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 = sorted(self.sections.items(), key=lambda a: a[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-download-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-download-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 fd.endswith('.git'): 162 fd = fd[:-4] 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 fd.endswith('.git'): 177 fd = fd[:-4] 178 if os.path.isdir(fd) or os.path.isfile(fd): 179 found = 1 180 for k in range(0,len(self.clArgs)): 181 if self.clArgs[k].startswith('--download-'+i): 182 self.clArgs[k] = 'download-'+i+'='+fd 183 self.argDB.insertArgs([self.clArgs[k]]) 184 break 185 if not found: 186 print(i + ' ' + str(self.argDB.dlist[i])) 187 if missing: 188 print('\nThen run the script again\n') 189 sys.exit(10) 190 191