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