1'''This module is meant to provide support for information and help systems based upon RDict.''' 2import logger 3 4class Info(logger.Logger): 5 '''This basic class provides information independent of RDict''' 6 def __init__(self, argDB = None): 7 '''Creates a dictionary "sections" whose keys are section names, and values are a tuple of (ordinal, nameList)''' 8 logger.Logger.__init__(self, None, argDB) 9 self.sections = {} 10 return 11 12 def getTitle(self): 13 return self._title 14 15 def setTitle(self, title): 16 self._title = str(title) 17 title = property(getTitle, setTitle, None, 'Title of the Information Menu') 18 19 def getDescription(self, section, name): 20 return self._desc[(section, name)] 21 22 def setDescription(self, section, name, desc): 23 if not hasattr(self, '_desc'): 24 self._desc = {} 25 self._desc[(section, name)] = desc 26 return 27 28 def addArgument(self, section, name, desc): 29 '''Add an argument with given name and string to an information section''' 30 if not section in self.sections: 31 self.sections[section] = (len(self.sections), []) 32 if name in self.sections[section][1]: 33 name += '@'+str(len(filter(lambda n: name == n.split('@')[0], self.sections[section][1]))+1) 34 self.sections[section][1].append(name) 35 self.setDescription(section, name, desc) 36 return 37 38 def printBanner(self, f): 39 '''Print a banner for the information screen''' 40 f.write(self.title+'\n') 41 for i in range(max(map(len, self.title.split('\n')))): f.write('-') 42 f.write('\n') 43 return 44 45 def getTextSizes(self): 46 '''Returns the maximum name and description lengths''' 47 nameLen = 1 48 descLen = 1 49 for section in self.sections: 50 nameLen = max([nameLen, max(map(lambda n: len(n.split('@')[0]), self.sections[section][1]))+1]) 51 descLen = max([descLen, max(map(lambda name: len(self.getDescription(section, name)), self.sections[section][1]))+1]) 52 return (nameLen, descLen) 53 54 def output(self, f = None): 55 '''Print a help screen with all the argument information.''' 56 if f is None: 57 import sys 58 f = sys.stdout 59 self.printBanner(f) 60 (nameLen, descLen) = self.getTextSizes() 61 format = ' %-'+str(nameLen)+'s: %s\n' 62 items = self.sections.items() 63 items.sort(lambda a, b: a[1][0].__cmp__(b[1][0])) 64 for section, names in items: 65 f.write(section+':\n') 66 for name in names[1]: 67 f.write(format % (name.split('@')[0], self.getDescription(section, name))) 68 return 69 70# I don't know how to not have this stupid global variable 71_outputDownloadDone = 0 72 73class Help(Info): 74 '''Help provides a simple help system for RDict''' 75 def __init__(self, argDB): 76 '''Creates a dictionary "sections" whose keys are section names, and values are a tuple of (ordinal, nameList). Also provide the RDict upon which this will be based.''' 77 Info.__init__(self, argDB) 78 self.title = 'Help' 79 return 80 81 def getDescription(self, section, name): 82 return self.argDB.getType(self.getArgName(name)).help 83 84 def setDescription(self, section, name, desc): 85 return 86 87 def getArgName(self, name): 88 '''Return the RDict key corresponding to a more verbose help name. Right now, this means discard everything after "=".''' 89 #return name.split('=')[0].strip('-') 90 argName = name.split('=')[0] 91 while argName[0] == '-': argName = argName[1:] 92 return argName 93 94 def addArgument(self, section, name, argType, ignoreDuplicates = 0): 95 '''Add an argument with given name and type to a help section. The type, which can also have an initializer and help string, will be put into RDict.''' 96## super(Info, self).addArgument(section, name, None) 97 if section in self.sections: 98 if name in self.sections[section][1]: 99 if ignoreDuplicates: 100 return 101 raise RuntimeError('Duplicate configure option '+name+' in section '+section) 102 else: 103 self.sections[section] = (len(self.sections), []) 104 if not argType.deprecated: 105 self.sections[section][1].append(name) 106 107 self.argDB.setType(self.getArgName(name), argType, forceLocal = 1) 108 return 109 110 def addDownload(self,name,dlist): 111 if not hasattr(self.argDB,'dlist'): 112 self.argDB.dlist = {} 113 else: 114 self.argDB.dlist[name] = dlist 115 116 def output(self, f = None, sections = None): 117 '''Print a help screen with all the argument information.''' 118 if f is None: 119 import sys 120 f = sys.stdout 121 if sections: sections = [s.lower() for s in sections] 122 self.printBanner(f) 123 (nameLen, descLen) = self.getTextSizes() 124# format = ' -%-'+str(nameLen)+'s: %s\n' 125# formatDef = ' -%-'+str(nameLen)+'s: %-'+str(descLen)+'s current: %s\n' 126 format = ' -%s\n %s\n' 127 formatDef = ' -%s\n %s current: %s\n' 128 items = self.sections.items() 129 items.sort(lambda a, b: a[1][0].__cmp__(b[1][0])) 130 for section, names in items: 131 if sections and not section.lower() in sections: continue 132 f.write(section+':\n') 133 for name in names[1]: 134 argName = self.getArgName(name) 135 type = self.argDB.getType(argName) 136 if argName in self.argDB: 137 f.write(formatDef % (name, type.help, str(self.argDB.getType(argName)))) 138 else: 139 f.write(format % (name, type.help)) 140 return 141 142 143 def outputDownload(self): 144 ''' Looks for downloaded packages in --with-packages-dir 145 For any it finds it updates the --download-xxx= argument to point to this local copy 146 If it does not find some needed packages then prints the packages that need to be downloaded and exits''' 147 import nargs 148 import os 149 import sys 150 global _outputDownloadDone 151 if _outputDownloadDone: return 152 _outputDownloadDone = 1 153 pkgdir = os.path.abspath(os.path.expanduser(nargs.Arg.findArgument('with-packages-dir', self.clArgs))) 154 missing = 0 155 for i in self.argDB.dlist.keys(): 156 if not nargs.Arg.findArgument('download-'+i, self.clArgs) == None and not nargs.Arg.findArgument('download-'+i, self.clArgs) == '0': 157 dlist = self.argDB.dlist[i] 158 found = 0 159 for k in range(0,len(dlist)): 160 fd = os.path.join(pkgdir,os.path.basename(dlist[k])) 161 if os.path.isdir(fd) or os.path.isfile(fd): 162 found = 1 163 break 164 if not found: 165 missing = 1 166 if missing: 167 print 'Download the following packages to '+pkgdir+' \n' 168 for i in self.argDB.dlist.keys(): 169 if not nargs.Arg.findArgument('download-'+i, self.clArgs) == None and not nargs.Arg.findArgument('download-'+i, self.clArgs) == '0': 170 dlist = self.argDB.dlist[i] 171 found = 0 172 for k in range(0,len(dlist)): 173 fd = os.path.join(pkgdir,os.path.basename(dlist[k])) 174 if os.path.isdir(fd) or os.path.isfile(fd): 175 found = 1 176 for k in range(0,len(self.clArgs)): 177 if self.clArgs[k].startswith('--download-'+i): 178 self.clArgs[k] = 'download-'+i+'='+fd 179 self.argDB.insertArgs([self.clArgs[k]]) 180 break 181 if not found: 182 print i + ' ' + str(self.argDB.dlist[i]) 183 if missing: 184 print '\nThen run the script again\n' 185 sys.exit(10) 186 187