xref: /petsc/config/BuildSystem/help.py (revision bb3dd2f65ef2449c5a5d945281d1be9b0cb6d0de)
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
5179860b2SJed Brown
6179860b2SJed Brownclass Info(logger.Logger):
7179860b2SJed Brown  '''This basic class provides information independent of RDict'''
8179860b2SJed Brown  def __init__(self, argDB = None):
9179860b2SJed Brown    '''Creates a dictionary "sections" whose keys are section names, and values are a tuple of (ordinal, nameList)'''
10179860b2SJed Brown    logger.Logger.__init__(self, None, argDB)
11179860b2SJed Brown    self.sections = {}
12179860b2SJed Brown    return
13179860b2SJed Brown
14179860b2SJed Brown  def getTitle(self):
15179860b2SJed Brown    return self._title
16179860b2SJed Brown
17179860b2SJed Brown  def setTitle(self, title):
18179860b2SJed Brown    self._title = str(title)
19179860b2SJed Brown  title = property(getTitle, setTitle, None, 'Title of the Information Menu')
20179860b2SJed Brown
21179860b2SJed Brown  def getDescription(self, section, name):
22179860b2SJed Brown    return self._desc[(section, name)]
23179860b2SJed Brown
24179860b2SJed Brown  def setDescription(self, section, name, desc):
25179860b2SJed Brown    if not hasattr(self, '_desc'):
26179860b2SJed Brown      self._desc = {}
27179860b2SJed Brown    self._desc[(section, name)] = desc
28179860b2SJed Brown    return
29179860b2SJed Brown
30179860b2SJed Brown  def addArgument(self, section, name, desc):
31179860b2SJed Brown    '''Add an argument with given name and string to an information section'''
32179860b2SJed Brown    if not section in self.sections:
33179860b2SJed Brown      self.sections[section] = (len(self.sections), [])
34179860b2SJed Brown    if name in self.sections[section][1]:
35*bb3dd2f6SJed Brown      name += '@'+str(len([n for n in self.sections[section][1] if name == n.split('@')[0]])+1)
36179860b2SJed Brown    self.sections[section][1].append(name)
37179860b2SJed Brown    self.setDescription(section, name, desc)
38179860b2SJed Brown    return
39179860b2SJed Brown
40179860b2SJed Brown  def printBanner(self, f):
41179860b2SJed Brown    '''Print a banner for the information screen'''
42179860b2SJed Brown    f.write(self.title+'\n')
43179860b2SJed Brown    for i in range(max(map(len, self.title.split('\n')))): f.write('-')
44179860b2SJed Brown    f.write('\n')
45179860b2SJed Brown    return
46179860b2SJed Brown
47179860b2SJed Brown  def getTextSizes(self):
48179860b2SJed Brown    '''Returns the maximum name and description lengths'''
49179860b2SJed Brown    nameLen = 1
50179860b2SJed Brown    descLen = 1
51179860b2SJed Brown    for section in self.sections:
52179860b2SJed Brown      nameLen = max([nameLen, max(map(lambda n: len(n.split('@')[0]), self.sections[section][1]))+1])
53179860b2SJed Brown      descLen = max([descLen, max(map(lambda name: len(self.getDescription(section, name)), self.sections[section][1]))+1])
54179860b2SJed Brown    return (nameLen, descLen)
55179860b2SJed Brown
56179860b2SJed Brown  def output(self, f = None):
57179860b2SJed Brown    '''Print a help screen with all the argument information.'''
58179860b2SJed Brown    if f is  None:
59179860b2SJed Brown      import sys
60179860b2SJed Brown      f = sys.stdout
61179860b2SJed Brown    self.printBanner(f)
62179860b2SJed Brown    (nameLen, descLen) = self.getTextSizes()
63179860b2SJed Brown    format = '  %-'+str(nameLen)+'s: %s\n'
64179860b2SJed Brown    items  = self.sections.items()
65f20c2d65SJed Brown    items.sort(key=lambda a: a[1][0])
66179860b2SJed Brown    for section, names in items:
67179860b2SJed Brown      f.write(section+':\n')
68179860b2SJed Brown      for name in names[1]:
69179860b2SJed Brown        f.write(format % (name.split('@')[0], self.getDescription(section, name)))
70179860b2SJed Brown    return
71179860b2SJed Brown
72b93f8388SBarry Smith# I don't know how to not have this stupid global variable
73b93f8388SBarry Smith_outputDownloadDone = 0
74b93f8388SBarry Smith
75179860b2SJed Brownclass Help(Info):
76179860b2SJed Brown  '''Help provides a simple help system for RDict'''
77179860b2SJed Brown  def __init__(self, argDB):
78179860b2SJed 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.'''
79179860b2SJed Brown    Info.__init__(self, argDB)
80179860b2SJed Brown    self.title = 'Help'
81179860b2SJed Brown    return
82179860b2SJed Brown
83179860b2SJed Brown  def getDescription(self, section, name):
84179860b2SJed Brown    return self.argDB.getType(self.getArgName(name)).help
85179860b2SJed Brown
86179860b2SJed Brown  def setDescription(self, section, name, desc):
87179860b2SJed Brown    return
88179860b2SJed Brown
89179860b2SJed Brown  def getArgName(self, name):
90179860b2SJed Brown    '''Return the RDict key corresponding to a more verbose help name. Right now, this means discard everything after "=".'''
91179860b2SJed Brown    #return name.split('=')[0].strip('-')
92179860b2SJed Brown    argName = name.split('=')[0]
93179860b2SJed Brown    while argName[0] == '-': argName = argName[1:]
94179860b2SJed Brown    return argName
95179860b2SJed Brown
96179860b2SJed Brown  def addArgument(self, section, name, argType, ignoreDuplicates = 0):
97179860b2SJed 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.'''
98179860b2SJed Brown##  super(Info, self).addArgument(section, name, None)
99179860b2SJed Brown    if section in self.sections:
100179860b2SJed Brown      if name in self.sections[section][1]:
101179860b2SJed Brown        if ignoreDuplicates:
102179860b2SJed Brown          return
103179860b2SJed Brown        raise RuntimeError('Duplicate configure option '+name+' in section '+section)
104179860b2SJed Brown    else:
105179860b2SJed Brown      self.sections[section] = (len(self.sections), [])
106179860b2SJed Brown    if not argType.deprecated:
107179860b2SJed Brown      self.sections[section][1].append(name)
108179860b2SJed Brown
109179860b2SJed Brown    self.argDB.setType(self.getArgName(name), argType, forceLocal = 1)
110179860b2SJed Brown    return
111179860b2SJed Brown
11275f179b0SBarry Smith  def addDownload(self,name,dlist):
11375f179b0SBarry Smith    if not hasattr(self.argDB,'dlist'):
11475f179b0SBarry Smith      self.argDB.dlist = {}
11575f179b0SBarry Smith    else:
11675f179b0SBarry Smith      self.argDB.dlist[name] = dlist
11775f179b0SBarry Smith
118179860b2SJed Brown  def output(self, f = None, sections = None):
119179860b2SJed Brown    '''Print a help screen with all the argument information.'''
120179860b2SJed Brown    if f is  None:
121179860b2SJed Brown      import sys
122179860b2SJed Brown      f = sys.stdout
123179860b2SJed Brown    if sections: sections = [s.lower() for s in sections]
124179860b2SJed Brown    self.printBanner(f)
125179860b2SJed Brown    (nameLen, descLen) = self.getTextSizes()
126179860b2SJed Brown#    format    = '  -%-'+str(nameLen)+'s: %s\n'
127179860b2SJed Brown#    formatDef = '  -%-'+str(nameLen)+'s: %-'+str(descLen)+'s  current: %s\n'
128179860b2SJed Brown    format    = '  -%s\n       %s\n'
129179860b2SJed Brown    formatDef = '  -%s\n       %s  current: %s\n'
130179860b2SJed Brown    items = self.sections.items()
131f20c2d65SJed Brown    items.sort(key=lambda a: a[1][0])
132179860b2SJed Brown    for section, names in items:
133179860b2SJed Brown      if sections and not section.lower() in sections: continue
134179860b2SJed Brown      f.write(section+':\n')
135179860b2SJed Brown      for name in names[1]:
136179860b2SJed Brown        argName = self.getArgName(name)
137179860b2SJed Brown        type    = self.argDB.getType(argName)
138179860b2SJed Brown        if argName in self.argDB:
139179860b2SJed Brown          f.write(formatDef % (name, type.help, str(self.argDB.getType(argName))))
140179860b2SJed Brown        else:
141179860b2SJed Brown          f.write(format % (name, type.help))
142179860b2SJed Brown    return
14375f179b0SBarry Smith
144b93f8388SBarry Smith
14575f179b0SBarry Smith  def outputDownload(self):
1460aa1f76dSSatish Balay    ''' Looks for downloaded packages in --with-packages-download-dir
147b93f8388SBarry Smith        For any it finds it updates the --download-xxx= argument to point to this local copy
148b93f8388SBarry Smith        If it does not find some needed packages then prints the packages that need to be downloaded and exits'''
14975f179b0SBarry Smith    import nargs
15075f179b0SBarry Smith    import os
15175f179b0SBarry Smith    import sys
152b93f8388SBarry Smith    global _outputDownloadDone
153b93f8388SBarry Smith    if _outputDownloadDone: return
154b93f8388SBarry Smith    _outputDownloadDone = 1
1550aa1f76dSSatish Balay    pkgdir = os.path.abspath(os.path.expanduser(nargs.Arg.findArgument('with-packages-download-dir', self.clArgs)))
15675f179b0SBarry Smith    missing = 0
157b93f8388SBarry Smith    for i in self.argDB.dlist.keys():
158b93f8388SBarry Smith      if not nargs.Arg.findArgument('download-'+i, self.clArgs) == None and not nargs.Arg.findArgument('download-'+i, self.clArgs) == '0':
159b93f8388SBarry Smith        dlist = self.argDB.dlist[i]
160b93f8388SBarry Smith        found = 0
161b93f8388SBarry Smith        for k in range(0,len(dlist)):
162b93f8388SBarry Smith          fd = os.path.join(pkgdir,os.path.basename(dlist[k]))
163b93f8388SBarry Smith          if os.path.isdir(fd) or os.path.isfile(fd):
164b93f8388SBarry Smith            found = 1
165b93f8388SBarry Smith            break
166b93f8388SBarry Smith        if not found:
167b93f8388SBarry Smith          missing = 1
168b93f8388SBarry Smith    if missing:
1695b6bfdb9SJed Brown      print('Download the following packages to '+pkgdir+' \n')
17075f179b0SBarry Smith    for i in self.argDB.dlist.keys():
17175f179b0SBarry Smith      if not nargs.Arg.findArgument('download-'+i, self.clArgs) == None and not nargs.Arg.findArgument('download-'+i, self.clArgs) == '0':
17275f179b0SBarry Smith        dlist = self.argDB.dlist[i]
17375f179b0SBarry Smith        found = 0
17475f179b0SBarry Smith        for k in range(0,len(dlist)):
17575f179b0SBarry Smith          fd = os.path.join(pkgdir,os.path.basename(dlist[k]))
17675f179b0SBarry Smith          if os.path.isdir(fd) or os.path.isfile(fd):
17775f179b0SBarry Smith            found = 1
17875f179b0SBarry Smith            for k in range(0,len(self.clArgs)):
17975f179b0SBarry Smith              if self.clArgs[k].startswith('--download-'+i):
18075f179b0SBarry Smith                self.clArgs[k] = 'download-'+i+'='+fd
18175f179b0SBarry Smith                self.argDB.insertArgs([self.clArgs[k]])
18275f179b0SBarry Smith            break
18375f179b0SBarry Smith        if not found:
1845b6bfdb9SJed Brown          print(i + ' ' + str(self.argDB.dlist[i]))
1859e6d21dfSBarry Smith    if missing:
1865b6bfdb9SJed Brown      print('\nThen run the script again\n')
187c524ecbbSBarry Smith      sys.exit(10)
18875f179b0SBarry Smith
189