#!/usr/bin/env python # -*- coding: utf-8 -*- # $Id: bacsource2configrules.py 11326 2010-10-25 07:56:12Z pstorz $ """Helper script to generate resource classes from bacula c definitions. Usage: c2py_resource.py BACULA_SRC_PATH """ #### # RESOURCE_TYPE has to be either 'dird', 'console', 'filed' or 'stored' # CONF_C_FILE is the corresponding c source e.g. 'dird/dird_conf.c' #""" C_CONFS = ( ("dird", "dird_conf.c"), ("console", "console_conf.c"), ("filed", "filed_conf.c"), ("stored", "stored_conf.c"), ("lib", "parse_conf.c"), ("inc" , "inc_conf.c"), ) import os import re from nosferatu.config_classes import * from resource import Resource from nosferatu import prettynames import pprint RXP_RESOURCE = re.compile(r''' ^(?:static\s+)?RES_ITEM(2)?\s+ (?P[^[]+)\[\]\s+=\s+\{\s*\n # First line with starting brace (?P.*?) # Non greedy search \n}\s*; ''', re.M|re.X|re.S) RXP_ITEM = re.compile(r''' ^\s+{"(?P[^"]+)"\s*, \s*(?P[^,]+)\s*, \s*(?P[^,]+)\s*, \s*(?P[^,]+)\s*, \s*(?P[^,]+)\s*, \s*(?P[^}]+)},?\s* ''', re.X) RXP_RESTABLE = re.compile(r''' ^(?:static\s+)?RES_TABLE\s+ (?P[^[]+)\[\]\s+=\s+\{\s*\n # First line with starting brace (?P.*?) # Non greedy search \n}\s*; ''', re.M|re.X|re.S) RXP_RESTABLE_ITEM = re.compile(r''' ^\s+{"(?P[^"]+)"\s*, \s*(?P[^,]+)\s*, \s*(?P[^}]+)},?\s* ''', re.X) RXP_STRUCT_TABLE = re.compile(r''' ^(?:static\s+?)?struct \ss_[a-zA-Z_]+\s(?P[^[^{]+)\[\]\s+=\s+\{\s*\n # First line with starting brace (?P.*?) # Non greedy search \n}\s*; ''', re.M|re.X|re.S) RXP_STRUCT_ITEM = re.compile(r''' ^\s+{"(?P[^"]+)"\s*, \s*(?P[^,]+)\s*(, \s*(?P[^}]+))?},?\s*(/\*.*\*/)? ''', re.X) # handler to python type wrapping CONF2TYPE = { 'store_bool' : bool, 'store_pint32' : int, 'store_str' : str, 'store_name' : str, #'store_dir' : Path, } CONF2VALUE = { 'INT32_MAX' : 0x7fffffffL, 'true' : True, 'false' : False, 'REPLACE_ALWAYS': 0 , #0 : '0' , #'0' : '0', 0 : None , '0' : None , '60*60*24*31*12*5' : '160704000', '60*60*24*60' : '5184000', '60*60*24*180': '15552000', '60*60*24*365': '31536000', '3 * 60' : '180', '30 * 60' : '1800', '60 * 30' : '1800', '5 * 60' : '300', } # Read in Commands Info RXP_COMMAND_ENTRY = re.compile(r''' ^\s+{\s+NT_\("(?P[^"]+)"\), \s*(?P[^"]+), \s*_\("(?P[^"]*)"\), \s+NT_\("(?P[^)]*)"\), \s*(?P\w+)} ''', re.X|re.M|re.S) RXP_DOT_COMMAND_ENTRY = re.compile(r''' ^\s+{\s+NT_\("(?P[^"]+)"\), \s*(?P[^"]+), \s*(?P\w*), \s*(?P\w+)} ''', re.X|re.M|re.S) BOOL_FILESET_OPTIONS = set([ 'portable' , 'ignorecase' , 'honornodumpflag', 'exclude' , 'enhancedwild' , 'hardlinks' , 'onefs' , 'xattrsupport' , 'hfsplussupport' , 'aclsupport' , 'checkfilechanges' , 'keepatime' , 'readfifo' , 'recurse' , 'sparse' , 'mtimeonly' , 'noatime' , ]) def defvalue(type, name, value): if type == 'store_opts': if name in BOOL_FILESET_OPTIONS: if value == 0: defval = False else: defval = True else: defval = value elif type == 'store_bool' or type == 'store_bit': if value == 0 or value == '0' or value == 'false' or value == None: defval = False else: defval = True else: defval = CONF2VALUE.get(value,value) return defval store_classes = [] def parse_conf_c(filename): """parse a bacula c file for resoure item definitions""" cfg = {} cf = open(filename).read() for block in RXP_RESOURCE.finditer(cf): bl = cfg[block.group("name")] = {} for line in block.group("items").split('\n'): m = RXP_ITEM.search(line) if not m: continue item = m.groupdict() bl[item.pop("name")] = item return cfg def parse_conf_c_for_res_table(filename): """parse a bacula c file for resoure table definitions""" cfg = {} cf = open(filename).read() for block in RXP_RESTABLE.finditer(cf): bl = cfg[block.group("name")] = {} for line in block.group("items").split('\n'): m = RXP_RESTABLE_ITEM.search(line) if not m: continue item = m.groupdict() bl[item.pop("name")] = item return cfg def directives(daemon, conf): res = conf.keys() res.sort() for r in res: s = "%s_%s = [\n" % (daemon, r) #s = ' ' keys = sorted(conf[r].iterkeys()) try: # put name first keys.remove('name') keys.insert(0,'name') except: pass for i in keys: #for i, v in conf[r].iteritems(): name = i v = conf[r][i] type = v["handler"] required = v["flags"] == "ITEM_REQUIRED" default = v["flags"] == "ITEM_DEFAULT" defaultvalue = defvalue(type, name, v["default_value"]) #defaultvalue = CONF2VALUE.get(v["default_value"],v["default_value"]) if default: value = defaultvalue else: value = defvalue(type, name, None) s += " %s,\n" % repr(Item(name, value, defaultvalue, default, type, required)) s += "]\n" print s def ressources(daemon, conf): res = conf.keys() res.sort() for r in res: s = "# This is the master resource definition. \n# It must have one item for each of the resources.\n" s += "%s_%s = [\n" % (daemon, r) for i, v in conf[r].iteritems(): name = i rcode = v["rcode"] resitem = v["resitem"] #print resitem if resitem == 'NULL': continue if resitem == 'msgs_items': # Message ressource is defined in lib file s += " [ \'%s\' , \'%s\', %s_%s ], \n" % (name, rcode, 'lib', resitem) else: s += " [ \'%s\' , \'%s\', %s_%s ], \n" % (name, rcode, daemon, resitem) s += "]\n" print s def parse_conf_c_for_structs(filename): """parse a bacula c file for resoure table definitions""" cfg = {} cf = open(filename).read() for block in RXP_STRUCT_TABLE.finditer(cf): if block.group("name") != "FS_options" and block.group("name") != "FS_option_kw": bl = cfg[block.group("name")] = {} for line in block.group("items").split('\n'): m = RXP_STRUCT_ITEM.search(line) if not m: continue item = m.groupdict() bl[item.pop("name")] = item elif block.group("name") == "FS_options": bl = cfg[block.group("name")] = {} # keywords for line in block.group("items").split('\n'): m = RXP_STRUCT_ITEM.search(line) if not m: continue item = m.groupdict() if not item["resitem"] in bl: #print "creating", item["resitem"], item bl[item["resitem"]] = [] #else: # print "not creating" , item["resitem"] #bl[item["resitem"]].append(item["name"]) #item.pop('rcode') bl[item["resitem"]].append(PrettyNames[item.pop('name')]) #print " appended to bl[" , item["resitem"] , "]" , item elif block.group("name") == "FS_option_kw": bl = cfg[block.group("name")] = {} # keywords for line in block.group("items").split('\n'): m = RXP_STRUCT_ITEM.search(line) if not m: continue item = m.groupdict() if not item["name"] in bl: #print "adding", item["resitem"], item["name"] bl[item["name"]] = [] #else: # print "not adding" , item["resitem"] #bl[item["resitem"]].append(item["name"]) bl[item["name"]] = item.pop('resitem') #print " appending to bl[" , item["resitem"] , "]" #print cfg return cfg #def structs(daemon, conf): if __name__ == "__main__": try: bacula_src = sys.argv[1] #bacula_src = '/home/pstorz/bacula_git/trunk/bacula/src/' except: raise(__doc__) rsc = [] print '''#!/usr/bin/env python # -*- coding: utf-8 -*- # # auto_types.py # # This file is autogenerated from the bacula sources. # from auto_types import * from command import * ''' # for parse_conf_c_for_structs(bacula_src + 'dird/dird_conf.c') conf = parse_conf_c_for_structs(bacula_src + 'lib/parse_conf.c') for r in conf.keys(): print r + ' = [' , #print r, conf[r] for i, v in conf[r].iteritems(): if str(i) != ' ': print "'" + i.lower() + "'" +', ', print ']' # for parse_conf_c_for_structs(bacula_src + 'dird/dird_conf.c') conf = parse_conf_c_for_structs(bacula_src + 'dird/dird_conf.c') for r in conf.keys(): print r + ' = [' , #print r, conf[r] for i, v in conf[r].iteritems(): if str(i) != ' ': print "'" + prettynames.prettyName(i.lower()) + "'" +', ', #print "'" + i.lower() + "'" +', ', print ']' #print 'READY1' conf = parse_conf_c_for_structs(bacula_src + 'dird/inc_conf.c') #print conf for r in conf.keys(): if r != 'FS_options' and r != 'FS_option_kw': #print 'R:' + r + ':R' print r + ' = [' , #print r,type( conf[r] ) #if type(conf[r]) == 'type ': for i, v in conf[r].iteritems(): if type(v) == 'type ': print "'" + i.lower() + "'" +', ', else: print '[' , i,'=',v, ']' #print "i,v:",i,v print ']\n' elif r == "FS_option_kw": print r + ' = {' , for i, v in conf[r].iteritems(): #if type(v) == 'type ': # print "'" + i.lower() + "'" +', ', #else: #print '[' , i,'=',v, ']' #print conf['FS_options'] try: options = conf['FS_options'][v] #print conf['FS_options'][v] except: options = ['Yes', 'No'] #print "excepting on " print "'" + i + "'" , ':', options, ',' #print "i,v:",i,v print '}\n' #else: # for i in conf[r]: # print i # print ']\n' #print 'READY2' commands = {} filename = bacula_src+"/dird/ua_cmds.c" cf = open(filename).read() for entry in RXP_COMMAND_ENTRY.finditer(cf): #print entry.groups() commands[entry.group("cmdtext")]= command( entry.group("cmdtext"), entry.group("cmd"), entry.group("usage"), entry.group("help").replace('"','').replace('\n',''), entry.group("inrunscript"), ) filename = bacula_src+"/dird/ua_dotcmds.c" cf = open(filename).read() for entry in RXP_DOT_COMMAND_ENTRY.finditer(cf): #print entry.groups() commands[entry.group("cmdtext")]= command(entry.group("cmdtext"), entry.group("cmd"), '', entry.group("help").replace('"','').replace('\n',''), entry.group("inrunscript"), ) print "commands = ", pprint.pprint(commands) print ''' #!/usr/bin/env python # -*- coding: utf-8 -*- # auto_configrules.py # # This file is autogenerated from the bacula sources. # from auto_types import * from config_classes import * ''' inc = False for daemon, conf in C_CONFS: if daemon == 'inc': inc = True daemon = 'dird' filename = os.path.join(bacula_src, daemon, conf) if inc: daemon = 'inc' directives(daemon, parse_conf_c(filename)) inc = False for daemon, conf in C_CONFS: if daemon == 'inc': inc = True daemon = 'dird' filename = os.path.join(bacula_src, daemon, conf) if inc: daemon = 'inc' ressources(daemon, parse_conf_c_for_res_table(filename)) print ''' # manual configurations dir_addresses_items = [ # no items, just a container ] cli_addresses_items = [ # no items, just a container ] store_addresses_items = [ # no items, just a container ] addresses_ip_items = [ Item('port', 9102, 9102, True, 'store_str', False), Item('addr', 0, 0, False, 'store_str', False), ] #fs_include_items = [ # Item('file', 0, 0, False, 'store_dir', False), #] fs_include_items = inc_newinc_items '''