# simtree.py -- A library for parsing ini based decision trees # # # Michael Thomas # Center for Computation & Technology # Louisiana State University # import pyini import os, shutil import re import sys import libutil from libutil import dprint class DecisionTree: def __init__(self, env, tree, parentTree=None): self.SimEnvironment = env self.OptionsManager = self.SimEnvironment.OptionsManager self.ConfigurationDatabase = self.SimEnvironment.ConfigurationDatabase self.DefineDatabase = self.SimEnvironment.DefineDatabase self.SimLib = self.SimEnvironment.SimLib self.RestartLib = self.SimEnvironment.RestartLib self.IniTree = tree self.ParentTree = parentTree def setupTree(self, tree=None): if tree != None: self.IniTree = tree if self.IniTree == None: dprint("Error: no decision tree defined.") sys.exit(1) fullFile = self.SimLib.BuildPath([self.SimEnvironment.LIB_PATH, "dt", "%s.ini" % self.IniTree]) if not(os.path.exists(fullFile)): dprint("Error: could not open decision tree %s for reading." % fullFile) sys.exit(1) dprint("decision tree ini: %s" % fullFile) self.Parser = pyini.IniParser(fullFile) self.loadConfiguration() def loadConfiguration(self): if not(self.Parser.HasSection("decisiontree")): dprint("Error: invalid decision tree, missing [decisiontree] section") sys.exit(1) if not(self.Parser.HasSection("section")): dprint("Error: invalid decision tree, missing [section] section") sys.exit(1) self.TreeConfiguration = self.Parser.GetSectionAsDict("decisiontree") dest = self.TreeConfiguration['dest'] if dest == None: dprint("Error: invalid tree configuration, no destination defined") sys.exit(1) dest = dest.value (self.DestType, value) = dest.split(":") if self.DestType not in ['ini']: dprint("Error: invalid tree configuration, unknown destination type %s" % type) sys.exit(1) eval("self.%s_initializeDestination('%s')" % (self.DestType, value)) self.SectionConfiguration = self.Parser.GetSectionAsDict("section") if self.SectionConfiguration['fixed'].Value == 'yes': self.DefineDatabase.Set(self.extractValue(self.SectionConfiguration['dest'].Value, '@'), self.SectionConfiguration['value'].Value) dprint("Section: %s" % self.DefineDatabase.Get('section')) def finishTree(self): cmd = "self.%s_finish()" % self.DestType return eval(cmd) def updateValue(self, section, key, value): cmd = "self.%s_storeDestinationValue('%s', '%s', '%s')" % (self.DestType, section, key, value) eval(cmd) def extractValue(self, key, sep): if key.startswith(sep): m = re.match("\%s([^%s]+)\%s" % (sep, sep, sep), key) if m == None: dprint("Error: invalid key format: %s" % key) sys.exit(1) else: return m.group(1) def begin(self): dprint("\n") dprint(self.TreeConfiguration['prompt'].Value) c = 'yes' while c == 'yes': if self.TreeConfiguration['required'].Value == 'no': c = raw_input("Continue [yes/no]: ") if c == 'no': return dprint("\n") if self.SectionConfiguration['fixed'].Value == 'no': sv = raw_input("%s: " % self.SectionConfiguration['prompt'].Value) self.DefineDatabase.Set(self.extractValue(self.SectionConfiguration['dest'].Value, '@'), sv) sections = self.Parser.GetSections() ss = list() for s in sections: if s.count(":") > 0: (type, index) = s.split(":") index = int(index) ss.insert(index-1, s) sections = ss for i in range(0, len(sections)): section = sections[i] dd = self.Parser.GetSectionAsDict(section) if section.startswith("action"): self.action(dd) if section.startswith("keyvalue:"): self.keyvalue(dd) continue if self.TreeConfiguration.has_key('next'): next = self.TreeConfiguration['next'].value (type, nextTree) = next.split(":") if type not in ['decisiontree']: dprint("Error: unknown tree next destination %s" % type) sys.exit(1) tree = DecisionTree(self.SimEnvironment, nextTree, self) tree.setupTree() tree.begin() if self.TreeConfiguration['repeat'].Value == 'yes': dprint("\n") dprint(self.TreeConfiguration['prompt'].Value) c = raw_input("Continue [yes/no]: ") else: c = 'no' self.finishTree() def dictSortFunc(self, x, y): if x.count(":") == 0 or y.count(":") == 0: return 0 xi = int(x.split(":").pop()) yi = int(y.split(":").pop()) return xi - yi def action(self, adict): prompt = self.DefineDatabase.SubAll(adict['prompt'].Value) action = self.DefineDatabase.SubAll(self.extractValue(adict['action'].Value, '%')) if adict.has_key("check"): check = self.DefineDatabase.SubAll(self.extractValue(adict['check'].Value, '%')) results = eval("self.macro_%s" % check) if results == False: return results = eval("self.macro_%s" % action) if adict['printresults'].Value == 'yes': dprint("%s: %s" % (prompt, results)) else: dprint(prompt) if adict.has_key('dest'): dest = self.extractValue(adict['dest'].Value, '@') self.DefineDatabase.Set(dest, results) def keyvalue(self, vdict): c = 'yes' repeat = 'no' if vdict.has_key('repeat'): repeat = vdict['repeat'].Value while c == 'yes': dest = self.DefineDatabase.SubAll(vdict['dest'].Value) self.performOperation(vdict, 'key') key = self.DefineDatabase.Get('key') if len(key) == 0: dprint("length of key is 0") return self.performOperation(vdict, 'value') self.updateValue(dest, key, self.DefineDatabase.Get('value')) if repeat == 'no': c = 'no' def performOperation(self, vdict, type): default = str() if vdict.has_key("%sdefault" % type): default = vdict["%sdefault" % type].Value if default.startswith("option:"): option = results.split(":").pop() if self.OptionsManager.HasOption(option): default = self.OptionsManager.GetOption(option) else: default = str() if default.count("%") > 0: macro = self.DefineDatabase.SubAll(self.extractValue(default, '%')) default = eval("self.macro_%s" % macro) if default.count("@") > 0: default = self.DefineDatabase.SubAll(default) self.DefineDatabase.Set('default', default) if not(vdict.has_key('%sdest' % type)): dprint("Error: invalid keyvalue section, missing key %sdest" % type) sys.exit(1) vdest = self.extractValue(vdict['%sdest' % type].Value, '@') result = str() if not(vdict.has_key("%sprompt" % type)): results = vdict['%svalue' % type].Value if results.startswith("option:"): option = results.split(":").pop() if self.OptionsManager.HasOption(option): results = self.OptionsManager.GetOption(option) else: results = default else: prompt = self.DefineDatabase.SubAll(vdict['%sprompt' % type].Value) results = raw_input("%s: " % prompt).strip() if len(results) == 0: results = default self.DefineDatabase.Set(vdest, results) ############ INI ################# def ini_initializeDestination(self, value): fullPath = self.SimLib.BuildPath([self.SimEnvironment.BASE_PATH, value]) self.ini_FullPath = fullPath if self.ParentTree != None: if self.ParentTree.DestType == 'ini': if self.ParentTree.ini_FullPath == self.ini_FullPath: self.ini_DestParser = self.ParentTree.ini_DestParser return self.ini_DestParser = pyini.IniParser(self.ini_FullPath) def ini_storeDestinationValue(self, section, key, value): if section == 'None' or len(section) == 0: section = None if section != None: self.ini_DestParser.parser.InitSection(section) #IniOption(self,section, key, value, IsBlock): io = pyini.IniOption(section, key, value, False) self.ini_DestParser.parser.WriteKey(section, key, io) def ini_finish(self): dprint("\n--------------------SUMMARY--------------------:\n") dprint(self.ini_DestParser.GetIniAsString()) dprint("\n------------------END SUMMARY------------------:\n") if self.TreeConfiguration.has_key('save'): save = self.TreeConfiguration['save'].value if save == "noprompt": r = "yes" else: r = raw_input("Save contents [yes/no]: ") else: r = raw_input("Save contents [yes/no]: ") if r == "yes": self.SimLib.WriteContents(self.ini_FullPath, self.ini_DestParser.GetIniAsString()) dprint("Contents successfully written to %s" % self.ini_FullPath) # ini specific macro def ini_GET_KEY_DEFAULT(self, section, key): if section == 'None' or len(section) == 0: section = None default = str() vv = self.ini_DestParser.GetOption(section, key) if vv != None: default = vv.Value return default ############ MACROS ############## def macro_GET_KEY_DEFAULT(self, key): section = self.DefineDatabase.Get('section') cmd = "self.%s_GET_KEY_DEFAULT('%s', '%s')" % (self.DestType, section, key) return eval(cmd) def macro_GET_DEFAULT_USERNAME(self): if self.DestType == 'ini': vv = self.ini_GET_KEY_DEFAULT('default', 'user') if vv == None or len(vv) == 0: return os.environ['LOGNAME'] else: return vv def macro_GET_LOCAL_MACHINE_NAME(self): return self.SimLib.GetHostNameAlias() def macro_CHECK_CREATE_MACHINE(self): mm = self.DefineDatabase.Get('machine') if self.SimLib.MachineExists(mm): return False return True def macro_CREATE_MACHINE(self): mm = self.DefineDatabase.Get('machine') srcPath = self.SimLib.BuildPath([self.SimEnvironment.MDB_PATH, 'generic.ini']) dstPath = self.SimLib.BuildPath([self.SimEnvironment.MDB_PATH, '%s.ini' % mm]) shutil.copy(srcPath, dstPath) self.tParser = pyini.IniParser(dstPath) self.tParser.parser.RenameSection('generic', mm) options = ['name', 'hostname', 'nickname'] for oo in options: io = self.tParser.GetOption(mm, oo) io.Value = io.value = mm self.tParser.parser.WriteKey(mm, oo, io) io = self.tParser.GetOption(mm, "sourcebasedir") if self.OptionsManager.HasOption('setup-sourcebasedir'): sourcebasedir = self.OptionsManager.GetOption('setup-sourcebasedir') else: cpath = self.SimEnvironment.APP_PATH parts = cpath.split(os.sep) parts.pop() sourcebasedir = os.sep.join(parts) io.Value = sourcebasedir self.tParser.parser.WriteKey(mm, "sourcebasedir", io) self.SimLib.WriteContents(dstPath, self.tParser.GetIniAsString()) return "machine %s [%s] created successfully" % (mm, dstPath)