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([n for n in self.sections[section][1] if name == n.split('@')[0]])+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 = sorted(self.sections.items(), key=lambda a: a[1][0]) 65 for section, names in items: 66 f.write(section+':\n') 67 for name in names[1]: 68 f.write(format % (name.split('@')[0], self.getDescription(section, name))) 69 return 70 71# I don't know how to not have this stupid global variable 72_outputDownloadDone = 0 73 74class Help(Info): 75 '''Help provides a simple help system for RDict''' 76 def __init__(self, argDB): 77 '''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.''' 78 Info.__init__(self, argDB) 79 self.title = 'Help' 80 return 81 82 def getDescription(self, section, name): 83 return self.argDB.getType(self.getArgName(name)).help 84 85 def setDescription(self, section, name, desc): 86 return 87 88 def getArgName(self, name): 89 '''Return the RDict key corresponding to a more verbose help name. Right now, this means discard everything after "=".''' 90 #return name.split('=')[0].strip('-') 91 argName = name.split('=')[0] 92 while argName[0] == '-': argName = argName[1:] 93 return argName 94 95 def addArgument(self, section, name, argType, ignoreDuplicates = 0): 96 '''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.''' 97## super(Info, self).addArgument(section, name, None) 98 if section in self.sections: 99 if name in self.sections[section][1]: 100 if ignoreDuplicates: 101 return 102 raise RuntimeError('Duplicate configure option '+name+' in section '+section) 103 else: 104 self.sections[section] = (len(self.sections), []) 105 if not argType.deprecated: 106 self.sections[section][1].append(name) 107 108 self.argDB.setType(self.getArgName(name), argType, forceLocal = 1) 109 return 110 111 def addDownload(self,name,dlist): 112 if not hasattr(self.argDB,'dlist'): 113 self.argDB.dlist = {} 114 else: 115 self.argDB.dlist[name] = dlist 116 117 def output(self, f = None, sections = None): 118 '''Print a help screen with all the argument information.''' 119 if f is None: 120 import sys 121 f = sys.stdout 122 if sections: sections = [s.lower() for s in sections] 123 self.printBanner(f) 124 (nameLen, descLen) = self.getTextSizes() 125# format = ' -%-'+str(nameLen)+'s: %s\n' 126# formatDef = ' -%-'+str(nameLen)+'s: %-'+str(descLen)+'s current: %s\n' 127 format = ' -%s\n %s\n' 128 formatDef = ' -%s\n %s current: %s\n' 129 items = self.sections.items() 130 items.sort(key=lambda a: a[1][0]) 131 for section, names in items: 132 if sections and not section.lower() in sections: continue 133 f.write(section+':\n') 134 for name in names[1]: 135 argName = self.getArgName(name) 136 type = self.argDB.getType(argName) 137 if argName in self.argDB: 138 f.write(formatDef % (name, type.help, str(self.argDB.getType(argName)))) 139 else: 140 f.write(format % (name, type.help)) 141 return 142 143 144 def outputDownload(self): 145 ''' Looks for downloaded packages in --with-packages-download-dir 146 For any it finds it updates the --download-xxx= argument to point to this local copy 147 If it does not find some needed packages then prints the packages that need to be downloaded and exits''' 148 import nargs 149 import os 150 import sys 151 global _outputDownloadDone 152 if _outputDownloadDone: return 153 _outputDownloadDone = 1 154 pkgdir = os.path.abspath(os.path.expanduser(nargs.Arg.findArgument('with-packages-download-dir', self.clArgs))) 155 missing = 0 156 for i in self.argDB.dlist.keys(): 157 if not nargs.Arg.findArgument('download-'+i, self.clArgs) == None and not nargs.Arg.findArgument('download-'+i, self.clArgs) == '0': 158 dlist = self.argDB.dlist[i] 159 found = 0 160 for k in range(0,len(dlist)): 161 fd = os.path.join(pkgdir,os.path.basename(dlist[k])) 162 if os.path.isdir(fd) or os.path.isfile(fd): 163 found = 1 164 break 165 if not found: 166 missing = 1 167 if missing: 168 print('Download the following packages to '+pkgdir+' \n') 169 for i in self.argDB.dlist.keys(): 170 if not nargs.Arg.findArgument('download-'+i, self.clArgs) == None and not nargs.Arg.findArgument('download-'+i, self.clArgs) == '0': 171 dlist = self.argDB.dlist[i] 172 found = 0 173 for k in range(0,len(dlist)): 174 fd = os.path.join(pkgdir,os.path.basename(dlist[k])) 175 if os.path.isdir(fd) or os.path.isfile(fd): 176 found = 1 177 for k in range(0,len(self.clArgs)): 178 if self.clArgs[k].startswith('--download-'+i): 179 self.clArgs[k] = 'download-'+i+'='+fd 180 self.argDB.insertArgs([self.clArgs[k]]) 181 break 182 if not found: 183 print(i + ' ' + str(self.argDB.dlist[i])) 184 if missing: 185 print('\nThen run the script again\n') 186 sys.exit(10) 187 188