1*5b6bfdb9SJed Brownfrom __future__ import absolute_import 2179860b2SJed Brownimport args 3179860b2SJed Brownimport sys 4179860b2SJed Brownimport os 5179860b2SJed Brown 6179860b2SJed Brown# Ugly stuff to have curses called ONLY once, instead of for each 7179860b2SJed Brown# new Configure object created (and flashing the screen) 8179860b2SJed Brownglobal LineWidth 9179860b2SJed Brownglobal RemoveDirectory 10179860b2SJed Brownglobal backupRemoveDirectory 11179860b2SJed BrownLineWidth = -1 12179860b2SJed BrownRemoveDirectory = os.path.join(os.getcwd(),'') 13179860b2SJed BrownbackupRemoveDirectory = '' 14179860b2SJed Brown 15179860b2SJed Brown# Compatibility fixes 16179860b2SJed Browntry: 17179860b2SJed Brown enumerate([0, 1]) 18179860b2SJed Brownexcept NameError: 19179860b2SJed Brown def enumerate(l): 20179860b2SJed Brown return zip(range(len(l)), l) 21179860b2SJed Browntry: 22179860b2SJed Brown True, False 23179860b2SJed Brownexcept NameError: 24179860b2SJed Brown True, False = (0==0, 0!=0) 25179860b2SJed Brown 26179860b2SJed Brownclass Logger(args.ArgumentProcessor): 27179860b2SJed Brown '''This class creates a shared log and provides methods for writing to it''' 28179860b2SJed Brown defaultLog = None 29179860b2SJed Brown defaultOut = sys.stdout 30179860b2SJed Brown 31179860b2SJed Brown def __init__(self, clArgs = None, argDB = None, log = None, out = defaultOut, debugLevel = None, debugSections = None, debugIndent = None): 32179860b2SJed Brown args.ArgumentProcessor.__init__(self, clArgs, argDB) 33179860b2SJed Brown self.logName = None 34179860b2SJed Brown self.log = log 35179860b2SJed Brown self.out = out 36179860b2SJed Brown self.debugLevel = debugLevel 37179860b2SJed Brown self.debugSections = debugSections 38179860b2SJed Brown self.debugIndent = debugIndent 39179860b2SJed Brown self.getRoot() 40179860b2SJed Brown return 41179860b2SJed Brown 42179860b2SJed Brown def __getstate__(self): 43179860b2SJed Brown '''We do not want to pickle the default log stream''' 44179860b2SJed Brown d = args.ArgumentProcessor.__getstate__(self) 45b59d1e59SMatthew G. Knepley if 'logBkp' in d: 46b59d1e59SMatthew G. Knepley del d['logBkp'] 47179860b2SJed Brown if 'log' in d: 48179860b2SJed Brown if d['log'] is Logger.defaultLog: 49179860b2SJed Brown del d['log'] 50179860b2SJed Brown else: 51179860b2SJed Brown d['log'] = None 52179860b2SJed Brown if 'out' in d: 53179860b2SJed Brown if d['out'] is Logger.defaultOut: 54179860b2SJed Brown del d['out'] 55179860b2SJed Brown else: 56179860b2SJed Brown d['out'] = None 57179860b2SJed Brown return d 58179860b2SJed Brown 59179860b2SJed Brown def __setstate__(self, d): 60179860b2SJed Brown '''We must create the default log stream''' 61179860b2SJed Brown args.ArgumentProcessor.__setstate__(self, d) 62179860b2SJed Brown if not 'log' in d: 63179860b2SJed Brown self.log = self.createLog(None) 64179860b2SJed Brown if not 'out' in d: 65179860b2SJed Brown self.out = Logger.defaultOut 66179860b2SJed Brown self.__dict__.update(d) 67179860b2SJed Brown return 68179860b2SJed Brown 69179860b2SJed Brown def setupArguments(self, argDB): 70179860b2SJed Brown '''Setup types in the argument database''' 71179860b2SJed Brown import nargs 72179860b2SJed Brown 73179860b2SJed Brown argDB = args.ArgumentProcessor.setupArguments(self, argDB) 7403e6d329SSatish Balay argDB.setType('log', nargs.Arg(None, 'buildsystem.log', 'The filename for the log')) 75179860b2SJed Brown argDB.setType('logAppend', nargs.ArgBool(None, 0, 'The flag determining whether we backup or append to the current log', isTemporary = 1)) 76179860b2SJed Brown argDB.setType('debugLevel', nargs.ArgInt(None, 3, 'Integer 0 to 4, where a higher level means more detail', 0, 5)) 77179860b2SJed Brown argDB.setType('debugSections', nargs.Arg(None, [], 'Message types to print, e.g. [compile,link,hg,install]')) 78179860b2SJed Brown argDB.setType('debugIndent', nargs.Arg(None, ' ', 'The string used for log indentation')) 79179860b2SJed Brown argDB.setType('scrollOutput', nargs.ArgBool(None, 0, 'Flag to allow output to scroll rather than overwriting a single line')) 80179860b2SJed Brown argDB.setType('noOutput', nargs.ArgBool(None, 0, 'Flag to suppress output to the terminal')) 81179860b2SJed Brown return argDB 82179860b2SJed Brown 83179860b2SJed Brown def setup(self): 84179860b2SJed Brown '''Setup the terminal output and filtering flags''' 85179860b2SJed Brown self.log = self.createLog(self.logName, self.log) 86179860b2SJed Brown args.ArgumentProcessor.setup(self) 87179860b2SJed Brown 88179860b2SJed Brown if self.argDB['noOutput']: 89179860b2SJed Brown self.out = None 90179860b2SJed Brown if self.debugLevel is None: 91179860b2SJed Brown self.debugLevel = self.argDB['debugLevel'] 92179860b2SJed Brown if self.debugSections is None: 93179860b2SJed Brown self.debugSections = self.argDB['debugSections'] 94179860b2SJed Brown if self.debugIndent is None: 95179860b2SJed Brown self.debugIndent = self.argDB['debugIndent'] 96179860b2SJed Brown return 97179860b2SJed Brown 98179860b2SJed Brown def checkLog(self, logName): 99179860b2SJed Brown import nargs 100179860b2SJed Brown import os 101179860b2SJed Brown 102179860b2SJed Brown if logName is None: 103179860b2SJed Brown logName = nargs.Arg.findArgument('log', self.clArgs) 104179860b2SJed Brown if logName is None: 105179860b2SJed Brown if not self.argDB is None and 'log' in self.argDB: 106179860b2SJed Brown logName = self.argDB['log'] 107179860b2SJed Brown else: 108179860b2SJed Brown logName = 'default.log' 109179860b2SJed Brown self.logName = logName 110179860b2SJed Brown self.logExists = os.path.exists(self.logName) 111179860b2SJed Brown return self.logExists 112179860b2SJed Brown 113179860b2SJed Brown def createLog(self, logName, initLog = None): 114179860b2SJed Brown '''Create a default log stream, unless initLog is given''' 115179860b2SJed Brown import nargs 116179860b2SJed Brown 117179860b2SJed Brown if not initLog is None: 118179860b2SJed Brown log = initLog 119179860b2SJed Brown else: 120179860b2SJed Brown if Logger.defaultLog is None: 121179860b2SJed Brown appendArg = nargs.Arg.findArgument('logAppend', self.clArgs) 122179860b2SJed Brown if self.checkLog(logName): 123179860b2SJed Brown if not self.argDB is None and ('logAppend' in self.argDB and self.argDB['logAppend']) or (not appendArg is None and bool(appendArg)): 124179860b2SJed Brown Logger.defaultLog = file(self.logName, 'a') 125179860b2SJed Brown else: 126179860b2SJed Brown try: 127179860b2SJed Brown import os 128179860b2SJed Brown 129179860b2SJed Brown os.rename(self.logName, self.logName+'.bkp') 130179860b2SJed Brown Logger.defaultLog = file(self.logName, 'w') 131179860b2SJed Brown except OSError: 13215ac2963SJed Brown sys.stdout.write('WARNING: Cannot backup log file, appending instead.\n') 133179860b2SJed Brown Logger.defaultLog = file(self.logName, 'a') 134179860b2SJed Brown else: 135179860b2SJed Brown Logger.defaultLog = file(self.logName, 'w') 136179860b2SJed Brown log = Logger.defaultLog 137179860b2SJed Brown return log 138179860b2SJed Brown 139179860b2SJed Brown def closeLog(self): 140179860b2SJed Brown '''Closes the log file''' 141179860b2SJed Brown self.log.close() 142179860b2SJed Brown 143a75b4e77SMatthew G. Knepley def saveLog(self): 144a75b4e77SMatthew G. Knepley import StringIO 145a75b4e77SMatthew G. Knepley self.logBkp = self.log 146a75b4e77SMatthew G. Knepley self.log = StringIO.StringIO() 147a75b4e77SMatthew G. Knepley 148a75b4e77SMatthew G. Knepley def restoreLog(self): 149a75b4e77SMatthew G. Knepley s = self.log.getvalue() 150a75b4e77SMatthew G. Knepley self.log.close() 151a75b4e77SMatthew G. Knepley self.log = self.logBkp 152a75b4e77SMatthew G. Knepley del(self.logBkp) 153a75b4e77SMatthew G. Knepley return s 154a75b4e77SMatthew G. Knepley 155179860b2SJed Brown def getLinewidth(self): 156179860b2SJed Brown global LineWidth 157179860b2SJed Brown if not hasattr(self, '_linewidth'): 158179860b2SJed Brown if self.out is None or not self.out.isatty() or self.argDB['scrollOutput']: 159179860b2SJed Brown self._linewidth = -1 160179860b2SJed Brown else: 161179860b2SJed Brown if LineWidth == -1: 162179860b2SJed Brown try: 163179860b2SJed Brown import curses 164179860b2SJed Brown 165179860b2SJed Brown try: 166179860b2SJed Brown curses.setupterm() 167179860b2SJed Brown (y, self._linewidth) = curses.initscr().getmaxyx() 168179860b2SJed Brown curses.endwin() 169179860b2SJed Brown except curses.error: 170179860b2SJed Brown self._linewidth = -1 171179860b2SJed Brown except: 172179860b2SJed Brown self._linewidth = -1 173179860b2SJed Brown LineWidth = self._linewidth 174179860b2SJed Brown else: 175179860b2SJed Brown self._linewidth = LineWidth 176179860b2SJed Brown return self._linewidth 177179860b2SJed Brown def setLinewidth(self, linewidth): 178179860b2SJed Brown self._linewidth = linewidth 179179860b2SJed Brown return 180179860b2SJed Brown linewidth = property(getLinewidth, setLinewidth, doc = 'The maximum number of characters per log line') 181179860b2SJed Brown 182179860b2SJed Brown def checkWrite(self, f, debugLevel, debugSection, writeAll = 0): 183179860b2SJed Brown '''Check whether the log line should be written 184179860b2SJed Brown - If writeAll is true, return true 185179860b2SJed Brown - If debugLevel >= current level, and debugSection in current section or sections is empty, return true''' 186179860b2SJed Brown if not isinstance(debugLevel, int): 187179860b2SJed Brown raise RuntimeError('Debug level must be an integer: '+str(debugLevel)) 188179860b2SJed Brown if f is None: 189179860b2SJed Brown return False 190179860b2SJed Brown if writeAll: 191179860b2SJed Brown return True 192179860b2SJed Brown if self.debugLevel >= debugLevel and (not len(self.debugSections) or debugSection in self.debugSections): 193179860b2SJed Brown return True 194179860b2SJed Brown return False 195179860b2SJed Brown 196179860b2SJed Brown def logIndent(self, debugLevel = -1, debugSection = None, comm = None): 197179860b2SJed Brown '''Write the proper indentation to the log streams''' 198179860b2SJed Brown import traceback 199179860b2SJed Brown 200179860b2SJed Brown indentLevel = len(traceback.extract_stack())-5 201179860b2SJed Brown for writeAll, f in enumerate([self.out, self.log]): 202179860b2SJed Brown if self.checkWrite(f, debugLevel, debugSection, writeAll): 203179860b2SJed Brown if not comm is None: 204179860b2SJed Brown f.write('[') 205179860b2SJed Brown f.write(str(comm.rank())) 206179860b2SJed Brown f.write(']') 207179860b2SJed Brown for i in range(indentLevel): 208179860b2SJed Brown f.write(self.debugIndent) 209179860b2SJed Brown return 210179860b2SJed Brown 211179860b2SJed Brown def logBack(self): 212179860b2SJed Brown '''Backup the current line if we are not scrolling output''' 213179860b2SJed Brown if not self.out is None and self.linewidth > 0: 214179860b2SJed Brown self.out.write('\r') 215179860b2SJed Brown return 216179860b2SJed Brown 217179860b2SJed Brown def logClear(self): 218179860b2SJed Brown '''Clear the current line if we are not scrolling output''' 219179860b2SJed Brown if not self.out is None and self.linewidth > 0: 220179860b2SJed Brown self.out.write('\r') 221179860b2SJed Brown self.out.write(''.join([' '] * self.linewidth)) 222179860b2SJed Brown self.out.write('\r') 223179860b2SJed Brown return 224179860b2SJed Brown 225179860b2SJed Brown def logPrintDivider(self, debugLevel = -1, debugSection = None, single = 0): 226179860b2SJed Brown if single: 227179860b2SJed Brown self.logPrint('-------------------------------------------------------------------------------', debugLevel = debugLevel, debugSection = debugSection) 228179860b2SJed Brown else: 229179860b2SJed Brown self.logPrint('===============================================================================', debugLevel = debugLevel, debugSection = debugSection) 230179860b2SJed Brown return 231179860b2SJed Brown 232179860b2SJed Brown def logPrintBox(self,msg, debugLevel = -1, debugSection = 'screen', indent = 1, comm = None): 233179860b2SJed Brown self.logClear() 234179860b2SJed Brown self.logPrintDivider(debugLevel = debugLevel, debugSection = debugSection) 235179860b2SJed Brown [self.logPrint(' '+line, debugLevel = debugLevel, debugSection = debugSection) for line in msg.split('\n')] 236179860b2SJed Brown self.logPrintDivider(debugLevel = debugLevel, debugSection = debugSection) 237179860b2SJed Brown self.logPrint('', debugLevel = debugLevel, debugSection = debugSection) 238179860b2SJed Brown return 239179860b2SJed Brown 240179860b2SJed Brown def logClearRemoveDirectory(self): 241179860b2SJed Brown global RemoveDirectory 242179860b2SJed Brown global backupRemoveDirectory 243179860b2SJed Brown backupRemoveDirectory = RemoveDirectory 244179860b2SJed Brown RemoveDirectory = '' 245179860b2SJed Brown 246179860b2SJed Brown def logResetRemoveDirectory(self): 247179860b2SJed Brown global RemoveDirectory 248179860b2SJed Brown global backupRemoveDirectory 249179860b2SJed Brown RemoveDirectory = backupRemoveDirectory 250179860b2SJed Brown 251179860b2SJed Brown 252179860b2SJed Brown def logWrite(self, msg, debugLevel = -1, debugSection = None, forceScroll = 0): 253179860b2SJed Brown '''Write the message to the log streams''' 254179860b2SJed Brown for writeAll, f in enumerate([self.out, self.log]): 255179860b2SJed Brown if self.checkWrite(f, debugLevel, debugSection, writeAll): 256179860b2SJed Brown if not forceScroll and not writeAll and self.linewidth > 0: 257179860b2SJed Brown global RemoveDirectory 258179860b2SJed Brown self.logBack() 259179860b2SJed Brown msg = msg.replace(RemoveDirectory,'') 260179860b2SJed Brown for ms in msg.split('\n'): 261179860b2SJed Brown f.write(ms[0:self.linewidth]) 262179860b2SJed Brown f.write(''.join([' '] * (self.linewidth - len(ms)))) 263179860b2SJed Brown else: 264179860b2SJed Brown if not debugSection is None and not debugSection == 'screen' and len(msg): 265179860b2SJed Brown f.write(str(debugSection)) 266179860b2SJed Brown f.write(': ') 267179860b2SJed Brown f.write(msg) 268179860b2SJed Brown if hasattr(f, 'flush'): 269179860b2SJed Brown f.flush() 270179860b2SJed Brown return 271179860b2SJed Brown 272179860b2SJed Brown def logPrint(self, msg, debugLevel = -1, debugSection = None, indent = 1, comm = None, forceScroll = 0): 273179860b2SJed Brown '''Write the message to the log streams with proper indentation and a newline''' 274179860b2SJed Brown if indent: 275179860b2SJed Brown self.logIndent(debugLevel, debugSection, comm) 276179860b2SJed Brown self.logWrite(msg, debugLevel, debugSection, forceScroll = forceScroll) 277179860b2SJed Brown for writeAll, f in enumerate([self.out, self.log]): 278179860b2SJed Brown if self.checkWrite(f, debugLevel, debugSection, writeAll): 279179860b2SJed Brown if writeAll or self.linewidth < 0: 280179860b2SJed Brown f.write('\n') 281179860b2SJed Brown return 282179860b2SJed Brown 283179860b2SJed Brown 284179860b2SJed Brown def getRoot(self): 285179860b2SJed Brown '''Return the directory containing this module 286179860b2SJed Brown - This has the problem that when we reload a module of the same name, this gets screwed up 287179860b2SJed Brown Therefore, we call it in the initializer, and stash it''' 288179860b2SJed Brown #print ' In getRoot' 289179860b2SJed Brown #print hasattr(self, '__root') 290179860b2SJed Brown #print ' done checking' 291179860b2SJed Brown if not hasattr(self, '__root'): 292179860b2SJed Brown import os 293179860b2SJed Brown import sys 294179860b2SJed Brown 295179860b2SJed Brown # Work around a bug with pdb in 2.3 296179860b2SJed Brown if hasattr(sys.modules[self.__module__], '__file__') and not os.path.basename(sys.modules[self.__module__].__file__) == 'pdb.py': 297179860b2SJed Brown self.__root = os.path.abspath(os.path.dirname(sys.modules[self.__module__].__file__)) 298179860b2SJed Brown else: 299179860b2SJed Brown self.__root = os.getcwd() 300179860b2SJed Brown #print ' Exiting getRoot' 301179860b2SJed Brown return self.__root 302179860b2SJed Brown def setRoot(self, root): 303179860b2SJed Brown self.__root = root 304179860b2SJed Brown return 305179860b2SJed Brown root = property(getRoot, setRoot, doc = 'The directory containing this module') 306