1179860b2SJed Brown'''This module is meant to provide support for information and help systems based upon RDict.''' 25b6bfdb9SJed Brownfrom __future__ import print_function 35b6bfdb9SJed Brownfrom __future__ import absolute_import 4179860b2SJed Brownimport logger 5e44e973aSJacob Faibussowitschimport sys 6179860b2SJed Brown 7179860b2SJed Brownclass Info(logger.Logger): 8179860b2SJed Brown '''This basic class provides information independent of RDict''' 9179860b2SJed Brown def __init__(self, argDB = None): 10179860b2SJed Brown '''Creates a dictionary "sections" whose keys are section names, and values are a tuple of (ordinal, nameList)''' 11179860b2SJed Brown logger.Logger.__init__(self, None, argDB) 12179860b2SJed Brown self.sections = {} 13179860b2SJed Brown return 14179860b2SJed Brown 15179860b2SJed Brown def getTitle(self): 16179860b2SJed Brown return self._title 17179860b2SJed Brown 18179860b2SJed Brown def setTitle(self, title): 19179860b2SJed Brown self._title = str(title) 20179860b2SJed Brown title = property(getTitle, setTitle, None, 'Title of the Information Menu') 21179860b2SJed Brown 22179860b2SJed Brown def getDescription(self, section, name): 23179860b2SJed Brown return self._desc[(section, name)] 24179860b2SJed Brown 25179860b2SJed Brown def setDescription(self, section, name, desc): 26179860b2SJed Brown if not hasattr(self, '_desc'): 27179860b2SJed Brown self._desc = {} 28179860b2SJed Brown self._desc[(section, name)] = desc 29179860b2SJed Brown return 30179860b2SJed Brown 31179860b2SJed Brown def addArgument(self, section, name, desc): 32179860b2SJed Brown '''Add an argument with given name and string to an information section''' 33179860b2SJed Brown if not section in self.sections: 34179860b2SJed Brown self.sections[section] = (len(self.sections), []) 35179860b2SJed Brown if name in self.sections[section][1]: 36bb3dd2f6SJed Brown name += '@'+str(len([n for n in self.sections[section][1] if name == n.split('@')[0]])+1) 37179860b2SJed Brown self.sections[section][1].append(name) 38179860b2SJed Brown self.setDescription(section, name, desc) 39179860b2SJed Brown return 40179860b2SJed Brown 41179860b2SJed Brown def printBanner(self, f): 42179860b2SJed Brown '''Print a banner for the information screen''' 43e44e973aSJacob Faibussowitsch title = self.title 44e44e973aSJacob Faibussowitsch divider = '-' * logger.get_global_divider_length() 45e44e973aSJacob Faibussowitsch f.write('{}\n{}\n'.format(title, divider)) 46179860b2SJed Brown return 47179860b2SJed Brown 48179860b2SJed Brown def getTextSizes(self): 49179860b2SJed Brown '''Returns the maximum name and description lengths''' 50179860b2SJed Brown nameLen = 1 51179860b2SJed Brown descLen = 1 52179860b2SJed Brown for section in self.sections: 53179860b2SJed Brown nameLen = max([nameLen, max(map(lambda n: len(n.split('@')[0]), self.sections[section][1]))+1]) 54179860b2SJed Brown descLen = max([descLen, max(map(lambda name: len(self.getDescription(section, name)), self.sections[section][1]))+1]) 55179860b2SJed Brown return (nameLen, descLen) 56179860b2SJed Brown 57179860b2SJed Brown def output(self, f = None): 58179860b2SJed Brown '''Print a help screen with all the argument information.''' 59179860b2SJed Brown if f is None: 60179860b2SJed Brown f = sys.stdout 61179860b2SJed Brown self.printBanner(f) 62179860b2SJed Brown (nameLen, descLen) = self.getTextSizes() 63179860b2SJed Brown format = ' %-'+str(nameLen)+'s: %s\n' 64b8b3d021SJed Brown items = sorted(self.sections.items(), key=lambda a: a[1][0]) 65179860b2SJed Brown for section, names in items: 66179860b2SJed Brown f.write(section+':\n') 67179860b2SJed Brown for name in names[1]: 68179860b2SJed Brown f.write(format % (name.split('@')[0], self.getDescription(section, name))) 69179860b2SJed Brown return 70179860b2SJed Brown 71b93f8388SBarry Smith# I don't know how to not have this stupid global variable 72b93f8388SBarry Smith_outputDownloadDone = 0 73b93f8388SBarry Smith 74179860b2SJed Brownclass Help(Info): 75179860b2SJed Brown '''Help provides a simple help system for RDict''' 76179860b2SJed Brown def __init__(self, argDB): 77179860b2SJed Brown '''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.''' 78179860b2SJed Brown Info.__init__(self, argDB) 79179860b2SJed Brown self.title = 'Help' 80179860b2SJed Brown return 81179860b2SJed Brown 82179860b2SJed Brown def getDescription(self, section, name): 83179860b2SJed Brown return self.argDB.getType(self.getArgName(name)).help 84179860b2SJed Brown 85179860b2SJed Brown def setDescription(self, section, name, desc): 86179860b2SJed Brown return 87179860b2SJed Brown 88179860b2SJed Brown def getArgName(self, name): 89179860b2SJed Brown '''Return the RDict key corresponding to a more verbose help name. Right now, this means discard everything after "=".''' 90179860b2SJed Brown #return name.split('=')[0].strip('-') 91179860b2SJed Brown argName = name.split('=')[0] 92179860b2SJed Brown while argName[0] == '-': argName = argName[1:] 93179860b2SJed Brown return argName 94179860b2SJed Brown 95179860b2SJed Brown def addArgument(self, section, name, argType, ignoreDuplicates = 0): 96179860b2SJed Brown '''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.''' 97179860b2SJed Brown## super(Info, self).addArgument(section, name, None) 98179860b2SJed Brown if section in self.sections: 99179860b2SJed Brown if name in self.sections[section][1]: 100179860b2SJed Brown if ignoreDuplicates: 101179860b2SJed Brown return 102179860b2SJed Brown raise RuntimeError('Duplicate configure option '+name+' in section '+section) 103179860b2SJed Brown else: 104179860b2SJed Brown self.sections[section] = (len(self.sections), []) 105179860b2SJed Brown if not argType.deprecated: 106179860b2SJed Brown self.sections[section][1].append(name) 107179860b2SJed Brown 108179860b2SJed Brown self.argDB.setType(self.getArgName(name), argType, forceLocal = 1) 109179860b2SJed Brown return 110179860b2SJed Brown 11175f179b0SBarry Smith def addDownload(self,name,dlist): 11275f179b0SBarry Smith if not hasattr(self.argDB,'dlist'): 11375f179b0SBarry Smith self.argDB.dlist = {} 11475f179b0SBarry Smith else: 11575f179b0SBarry Smith self.argDB.dlist[name] = dlist 11675f179b0SBarry Smith 117179860b2SJed Brown def output(self, f = None, sections = None): 118179860b2SJed Brown '''Print a help screen with all the argument information.''' 119e44e973aSJacob Faibussowitsch def output_items(section_title, items): 120e44e973aSJacob Faibussowitsch f.write( 121e44e973aSJacob Faibussowitsch logger.build_multiline_message( 122e44e973aSJacob Faibussowitsch '***** {} *****'.format(section_title), '', divider_char='-' 123e44e973aSJacob Faibussowitsch ) + '\n' 124e44e973aSJacob Faibussowitsch ) 125e44e973aSJacob Faibussowitsch 126179860b2SJed Brown for section, names in items: 127e44e973aSJacob Faibussowitsch if sections and not section.casefold() in sections: 128e44e973aSJacob Faibussowitsch continue 129e44e973aSJacob Faibussowitsch 130179860b2SJed Brown f.write(section + ':\n') 131179860b2SJed Brown for name in names[1]: 132e44e973aSJacob Faibussowitsch arg_name = self.getArgName(name) 133e44e973aSJacob Faibussowitsch arg_type = self.argDB.getType(arg_name) 134e44e973aSJacob Faibussowitsch arg_help = arg_type.help 135e44e973aSJacob Faibussowitsch if arg_name in self.argDB: 136e44e973aSJacob Faibussowitsch f.write(' -{}\n {} current: {}\n'.format(name, arg_help, arg_type)) 137179860b2SJed Brown else: 138e44e973aSJacob Faibussowitsch f.write(' -{}\n {}\n'.format(name, arg_help)) 139e44e973aSJacob Faibussowitsch return 140e44e973aSJacob Faibussowitsch 141e44e973aSJacob Faibussowitsch if f is None: 142e44e973aSJacob Faibussowitsch f = sys.stdout 143e44e973aSJacob Faibussowitsch if sections: 144e44e973aSJacob Faibussowitsch sections = {s.casefold() for s in sections} 145e44e973aSJacob Faibussowitsch 146e44e973aSJacob Faibussowitsch packages = [] 147e44e973aSJacob Faibussowitsch modules = [] 148e44e973aSJacob Faibussowitsch for item in self.sections.items(): 149e44e973aSJacob Faibussowitsch # Packages all have -- for whatever reason -- an uppercase section name, so use this 150e44e973aSJacob Faibussowitsch # to distinguish them. This is a vile hack. 151e44e973aSJacob Faibussowitsch if item[0].isupper(): 152e44e973aSJacob Faibussowitsch packages.append(item) 153e44e973aSJacob Faibussowitsch else: 154e44e973aSJacob Faibussowitsch modules.append(item) 155e44e973aSJacob Faibussowitsch 156e44e973aSJacob Faibussowitsch self.printBanner(f) 157e44e973aSJacob Faibussowitsch # sort the primary modules by their ordering, this happens to be nice and logical 158e44e973aSJacob Faibussowitsch output_items('CORE OPTIONS', sorted(modules, key=lambda a: a[1][0])) 159e44e973aSJacob Faibussowitsch # self.printBanner() will automatically append a '----' so we don't have to print a 160e44e973aSJacob Faibussowitsch # divider above, but we do have to here 161e44e973aSJacob Faibussowitsch f.write('-' * logger.get_global_divider_length() + '\n') 162e44e973aSJacob Faibussowitsch # sort packages by name 163e44e973aSJacob Faibussowitsch output_items('PACKAGE OPTIONS', sorted(packages, key=lambda a: a[0])) 164179860b2SJed Brown return 16575f179b0SBarry Smith 16675f179b0SBarry Smith def outputDownload(self): 1670aa1f76dSSatish Balay ''' Looks for downloaded packages in --with-packages-download-dir 168b93f8388SBarry Smith For any it finds it updates the --download-xxx= argument to point to this local copy 169b93f8388SBarry Smith If it does not find some needed packages then prints the packages that need to be downloaded and exits''' 17075f179b0SBarry Smith import nargs 17175f179b0SBarry Smith import os 172b93f8388SBarry Smith global _outputDownloadDone 173b93f8388SBarry Smith if _outputDownloadDone: return 174b93f8388SBarry Smith _outputDownloadDone = 1 1750aa1f76dSSatish Balay pkgdir = os.path.abspath(os.path.expanduser(nargs.Arg.findArgument('with-packages-download-dir', self.clArgs))) 1765fd7084cSSatish Balay mesg = '' 177b93f8388SBarry Smith for i in self.argDB.dlist.keys(): 178b93f8388SBarry Smith if not nargs.Arg.findArgument('download-'+i, self.clArgs) == None and not nargs.Arg.findArgument('download-'+i, self.clArgs) == '0': 179b93f8388SBarry Smith dlist = self.argDB.dlist[i] 180b93f8388SBarry Smith found = 0 181b93f8388SBarry Smith for k in range(0,len(dlist)): 182*a2cf3c57SSatish Balay # github tarballs do not have pkg names, can cause namespace conflict, so also check for pkgname-FILENAME 183*a2cf3c57SSatish Balay # note: cannot check for pkgname/FILENAME - as there can be conflicts with git-URL [that gets checked before the tarball check] 184*a2cf3c57SSatish Balay fd = os.path.join(pkgdir,i + '-' + (os.path.basename(dlist[k]))) 185*a2cf3c57SSatish Balay if os.path.isfile(fd): 186*a2cf3c57SSatish Balay found = 1 187*a2cf3c57SSatish Balay break 188*a2cf3c57SSatish Balay # Now check for the unmodified FILENAME (tarball, git repo, or extracted folder) 189cadde5c7SSatish Balay fd = os.path.join(pkgdir,(os.path.basename(dlist[k]))) 190cadde5c7SSatish Balay if fd.endswith('.git'): 191cadde5c7SSatish Balay fd = fd[:-4] 192b93f8388SBarry Smith if os.path.isdir(fd) or os.path.isfile(fd): 193b93f8388SBarry Smith found = 1 194b93f8388SBarry Smith break 1955fd7084cSSatish Balay if found: 19675f179b0SBarry Smith for k in range(0,len(self.clArgs)): 19775f179b0SBarry Smith if self.clArgs[k].startswith('--download-'+i): 19875f179b0SBarry Smith self.clArgs[k] = 'download-'+i+'='+fd 19975f179b0SBarry Smith self.argDB.insertArgs([self.clArgs[k]]) 2005fd7084cSSatish Balay else: 2015fd7084cSSatish Balay mesg += i + ' ' + str(self.argDB.dlist[i]).replace("git://","git clone ")+'\n' 2025fd7084cSSatish Balay if mesg: 2035fd7084cSSatish Balay print('Download the following packages to '+pkgdir+' \n') 2045fd7084cSSatish Balay print(mesg) 2055fd7084cSSatish Balay print('Then run the script again\n') 206c524ecbbSBarry Smith sys.exit(10) 207