1*179860b2SJed Brownimport args 2*179860b2SJed Brownimport sys 3*179860b2SJed Brownimport os 4*179860b2SJed Brown 5*179860b2SJed Brown# Ugly stuff to have curses called ONLY once, instead of for each 6*179860b2SJed Brown# new Configure object created (and flashing the screen) 7*179860b2SJed Brownglobal LineWidth 8*179860b2SJed Brownglobal RemoveDirectory 9*179860b2SJed Brownglobal backupRemoveDirectory 10*179860b2SJed BrownLineWidth = -1 11*179860b2SJed BrownRemoveDirectory = os.path.join(os.getcwd(),'') 12*179860b2SJed BrownbackupRemoveDirectory = '' 13*179860b2SJed Brown 14*179860b2SJed Brown# Compatibility fixes 15*179860b2SJed Browntry: 16*179860b2SJed Brown enumerate([0, 1]) 17*179860b2SJed Brownexcept NameError: 18*179860b2SJed Brown def enumerate(l): 19*179860b2SJed Brown return zip(range(len(l)), l) 20*179860b2SJed Browntry: 21*179860b2SJed Brown True, False 22*179860b2SJed Brownexcept NameError: 23*179860b2SJed Brown True, False = (0==0, 0!=0) 24*179860b2SJed Brown 25*179860b2SJed Brownclass Logger(args.ArgumentProcessor): 26*179860b2SJed Brown '''This class creates a shared log and provides methods for writing to it''' 27*179860b2SJed Brown defaultLog = None 28*179860b2SJed Brown defaultOut = sys.stdout 29*179860b2SJed Brown 30*179860b2SJed Brown def __init__(self, clArgs = None, argDB = None, log = None, out = defaultOut, debugLevel = None, debugSections = None, debugIndent = None): 31*179860b2SJed Brown args.ArgumentProcessor.__init__(self, clArgs, argDB) 32*179860b2SJed Brown self.logName = None 33*179860b2SJed Brown self.log = log 34*179860b2SJed Brown self.out = out 35*179860b2SJed Brown self.debugLevel = debugLevel 36*179860b2SJed Brown self.debugSections = debugSections 37*179860b2SJed Brown self.debugIndent = debugIndent 38*179860b2SJed Brown self.getRoot() 39*179860b2SJed Brown return 40*179860b2SJed Brown 41*179860b2SJed Brown def __getstate__(self): 42*179860b2SJed Brown '''We do not want to pickle the default log stream''' 43*179860b2SJed Brown d = args.ArgumentProcessor.__getstate__(self) 44*179860b2SJed Brown if 'log' in d: 45*179860b2SJed Brown if d['log'] is Logger.defaultLog: 46*179860b2SJed Brown del d['log'] 47*179860b2SJed Brown else: 48*179860b2SJed Brown d['log'] = None 49*179860b2SJed Brown if 'out' in d: 50*179860b2SJed Brown if d['out'] is Logger.defaultOut: 51*179860b2SJed Brown del d['out'] 52*179860b2SJed Brown else: 53*179860b2SJed Brown d['out'] = None 54*179860b2SJed Brown return d 55*179860b2SJed Brown 56*179860b2SJed Brown def __setstate__(self, d): 57*179860b2SJed Brown '''We must create the default log stream''' 58*179860b2SJed Brown args.ArgumentProcessor.__setstate__(self, d) 59*179860b2SJed Brown if not 'log' in d: 60*179860b2SJed Brown self.log = self.createLog(None) 61*179860b2SJed Brown if not 'out' in d: 62*179860b2SJed Brown self.out = Logger.defaultOut 63*179860b2SJed Brown self.__dict__.update(d) 64*179860b2SJed Brown return 65*179860b2SJed Brown 66*179860b2SJed Brown def setupArguments(self, argDB): 67*179860b2SJed Brown '''Setup types in the argument database''' 68*179860b2SJed Brown import nargs 69*179860b2SJed Brown 70*179860b2SJed Brown argDB = args.ArgumentProcessor.setupArguments(self, argDB) 71*179860b2SJed Brown argDB.setType('log', nargs.Arg(None, 'build.log', 'The filename for the log')) 72*179860b2SJed Brown argDB.setType('logAppend', nargs.ArgBool(None, 0, 'The flag determining whether we backup or append to the current log', isTemporary = 1)) 73*179860b2SJed Brown argDB.setType('debugLevel', nargs.ArgInt(None, 3, 'Integer 0 to 4, where a higher level means more detail', 0, 5)) 74*179860b2SJed Brown argDB.setType('debugSections', nargs.Arg(None, [], 'Message types to print, e.g. [compile,link,hg,install]')) 75*179860b2SJed Brown argDB.setType('debugIndent', nargs.Arg(None, ' ', 'The string used for log indentation')) 76*179860b2SJed Brown argDB.setType('scrollOutput', nargs.ArgBool(None, 0, 'Flag to allow output to scroll rather than overwriting a single line')) 77*179860b2SJed Brown argDB.setType('noOutput', nargs.ArgBool(None, 0, 'Flag to suppress output to the terminal')) 78*179860b2SJed Brown return argDB 79*179860b2SJed Brown 80*179860b2SJed Brown def setup(self): 81*179860b2SJed Brown '''Setup the terminal output and filtering flags''' 82*179860b2SJed Brown self.log = self.createLog(self.logName, self.log) 83*179860b2SJed Brown args.ArgumentProcessor.setup(self) 84*179860b2SJed Brown 85*179860b2SJed Brown if self.argDB['noOutput']: 86*179860b2SJed Brown self.out = None 87*179860b2SJed Brown if self.debugLevel is None: 88*179860b2SJed Brown self.debugLevel = self.argDB['debugLevel'] 89*179860b2SJed Brown if self.debugSections is None: 90*179860b2SJed Brown self.debugSections = self.argDB['debugSections'] 91*179860b2SJed Brown if self.debugIndent is None: 92*179860b2SJed Brown self.debugIndent = self.argDB['debugIndent'] 93*179860b2SJed Brown return 94*179860b2SJed Brown 95*179860b2SJed Brown def checkLog(self, logName): 96*179860b2SJed Brown import nargs 97*179860b2SJed Brown import os 98*179860b2SJed Brown 99*179860b2SJed Brown if logName is None: 100*179860b2SJed Brown logName = nargs.Arg.findArgument('log', self.clArgs) 101*179860b2SJed Brown if logName is None: 102*179860b2SJed Brown if not self.argDB is None and 'log' in self.argDB: 103*179860b2SJed Brown logName = self.argDB['log'] 104*179860b2SJed Brown else: 105*179860b2SJed Brown logName = 'default.log' 106*179860b2SJed Brown self.logName = logName 107*179860b2SJed Brown self.logExists = os.path.exists(self.logName) 108*179860b2SJed Brown return self.logExists 109*179860b2SJed Brown 110*179860b2SJed Brown def createLog(self, logName, initLog = None): 111*179860b2SJed Brown '''Create a default log stream, unless initLog is given''' 112*179860b2SJed Brown import nargs 113*179860b2SJed Brown 114*179860b2SJed Brown if not initLog is None: 115*179860b2SJed Brown log = initLog 116*179860b2SJed Brown else: 117*179860b2SJed Brown if Logger.defaultLog is None: 118*179860b2SJed Brown appendArg = nargs.Arg.findArgument('logAppend', self.clArgs) 119*179860b2SJed Brown if self.checkLog(logName): 120*179860b2SJed Brown if not self.argDB is None and ('logAppend' in self.argDB and self.argDB['logAppend']) or (not appendArg is None and bool(appendArg)): 121*179860b2SJed Brown Logger.defaultLog = file(self.logName, 'a') 122*179860b2SJed Brown else: 123*179860b2SJed Brown try: 124*179860b2SJed Brown import os 125*179860b2SJed Brown 126*179860b2SJed Brown os.rename(self.logName, self.logName+'.bkp') 127*179860b2SJed Brown Logger.defaultLog = file(self.logName, 'w') 128*179860b2SJed Brown except OSError: 129*179860b2SJed Brown print 'WARNING: Cannot backup log file, appending instead.' 130*179860b2SJed Brown Logger.defaultLog = file(self.logName, 'a') 131*179860b2SJed Brown else: 132*179860b2SJed Brown Logger.defaultLog = file(self.logName, 'w') 133*179860b2SJed Brown log = Logger.defaultLog 134*179860b2SJed Brown return log 135*179860b2SJed Brown 136*179860b2SJed Brown def closeLog(self): 137*179860b2SJed Brown '''Closes the log file''' 138*179860b2SJed Brown self.log.close() 139*179860b2SJed Brown 140*179860b2SJed Brown def getLinewidth(self): 141*179860b2SJed Brown global LineWidth 142*179860b2SJed Brown if not hasattr(self, '_linewidth'): 143*179860b2SJed Brown if self.out is None or not self.out.isatty() or self.argDB['scrollOutput']: 144*179860b2SJed Brown self._linewidth = -1 145*179860b2SJed Brown else: 146*179860b2SJed Brown if LineWidth == -1: 147*179860b2SJed Brown try: 148*179860b2SJed Brown import curses 149*179860b2SJed Brown 150*179860b2SJed Brown try: 151*179860b2SJed Brown curses.setupterm() 152*179860b2SJed Brown (y, self._linewidth) = curses.initscr().getmaxyx() 153*179860b2SJed Brown curses.endwin() 154*179860b2SJed Brown except curses.error: 155*179860b2SJed Brown self._linewidth = -1 156*179860b2SJed Brown except: 157*179860b2SJed Brown self._linewidth = -1 158*179860b2SJed Brown LineWidth = self._linewidth 159*179860b2SJed Brown else: 160*179860b2SJed Brown self._linewidth = LineWidth 161*179860b2SJed Brown return self._linewidth 162*179860b2SJed Brown def setLinewidth(self, linewidth): 163*179860b2SJed Brown self._linewidth = linewidth 164*179860b2SJed Brown return 165*179860b2SJed Brown linewidth = property(getLinewidth, setLinewidth, doc = 'The maximum number of characters per log line') 166*179860b2SJed Brown 167*179860b2SJed Brown def checkWrite(self, f, debugLevel, debugSection, writeAll = 0): 168*179860b2SJed Brown '''Check whether the log line should be written 169*179860b2SJed Brown - If writeAll is true, return true 170*179860b2SJed Brown - If debugLevel >= current level, and debugSection in current section or sections is empty, return true''' 171*179860b2SJed Brown if not isinstance(debugLevel, int): 172*179860b2SJed Brown raise RuntimeError('Debug level must be an integer: '+str(debugLevel)) 173*179860b2SJed Brown if f is None: 174*179860b2SJed Brown return False 175*179860b2SJed Brown if writeAll: 176*179860b2SJed Brown return True 177*179860b2SJed Brown if self.debugLevel >= debugLevel and (not len(self.debugSections) or debugSection in self.debugSections): 178*179860b2SJed Brown return True 179*179860b2SJed Brown return False 180*179860b2SJed Brown 181*179860b2SJed Brown def logIndent(self, debugLevel = -1, debugSection = None, comm = None): 182*179860b2SJed Brown '''Write the proper indentation to the log streams''' 183*179860b2SJed Brown import traceback 184*179860b2SJed Brown 185*179860b2SJed Brown indentLevel = len(traceback.extract_stack())-5 186*179860b2SJed Brown for writeAll, f in enumerate([self.out, self.log]): 187*179860b2SJed Brown if self.checkWrite(f, debugLevel, debugSection, writeAll): 188*179860b2SJed Brown if not comm is None: 189*179860b2SJed Brown f.write('[') 190*179860b2SJed Brown f.write(str(comm.rank())) 191*179860b2SJed Brown f.write(']') 192*179860b2SJed Brown for i in range(indentLevel): 193*179860b2SJed Brown f.write(self.debugIndent) 194*179860b2SJed Brown return 195*179860b2SJed Brown 196*179860b2SJed Brown def logBack(self): 197*179860b2SJed Brown '''Backup the current line if we are not scrolling output''' 198*179860b2SJed Brown if not self.out is None and self.linewidth > 0: 199*179860b2SJed Brown self.out.write('\r') 200*179860b2SJed Brown return 201*179860b2SJed Brown 202*179860b2SJed Brown def logClear(self): 203*179860b2SJed Brown '''Clear the current line if we are not scrolling output''' 204*179860b2SJed Brown if not self.out is None and self.linewidth > 0: 205*179860b2SJed Brown self.out.write('\r') 206*179860b2SJed Brown self.out.write(''.join([' '] * self.linewidth)) 207*179860b2SJed Brown self.out.write('\r') 208*179860b2SJed Brown return 209*179860b2SJed Brown 210*179860b2SJed Brown def logPrintDivider(self, debugLevel = -1, debugSection = None, single = 0): 211*179860b2SJed Brown if single: 212*179860b2SJed Brown self.logPrint('-------------------------------------------------------------------------------', debugLevel = debugLevel, debugSection = debugSection) 213*179860b2SJed Brown else: 214*179860b2SJed Brown self.logPrint('===============================================================================', debugLevel = debugLevel, debugSection = debugSection) 215*179860b2SJed Brown return 216*179860b2SJed Brown 217*179860b2SJed Brown def logPrintBox(self,msg, debugLevel = -1, debugSection = 'screen', indent = 1, comm = None): 218*179860b2SJed Brown self.logClear() 219*179860b2SJed Brown self.logPrintDivider(debugLevel = debugLevel, debugSection = debugSection) 220*179860b2SJed Brown [self.logPrint(' '+line, debugLevel = debugLevel, debugSection = debugSection) for line in msg.split('\n')] 221*179860b2SJed Brown self.logPrintDivider(debugLevel = debugLevel, debugSection = debugSection) 222*179860b2SJed Brown self.logPrint('', debugLevel = debugLevel, debugSection = debugSection) 223*179860b2SJed Brown return 224*179860b2SJed Brown 225*179860b2SJed Brown def logClearRemoveDirectory(self): 226*179860b2SJed Brown global RemoveDirectory 227*179860b2SJed Brown global backupRemoveDirectory 228*179860b2SJed Brown backupRemoveDirectory = RemoveDirectory 229*179860b2SJed Brown RemoveDirectory = '' 230*179860b2SJed Brown 231*179860b2SJed Brown def logResetRemoveDirectory(self): 232*179860b2SJed Brown global RemoveDirectory 233*179860b2SJed Brown global backupRemoveDirectory 234*179860b2SJed Brown RemoveDirectory = backupRemoveDirectory 235*179860b2SJed Brown 236*179860b2SJed Brown 237*179860b2SJed Brown def logWrite(self, msg, debugLevel = -1, debugSection = None, forceScroll = 0): 238*179860b2SJed Brown '''Write the message to the log streams''' 239*179860b2SJed Brown for writeAll, f in enumerate([self.out, self.log]): 240*179860b2SJed Brown if self.checkWrite(f, debugLevel, debugSection, writeAll): 241*179860b2SJed Brown if not forceScroll and not writeAll and self.linewidth > 0: 242*179860b2SJed Brown global RemoveDirectory 243*179860b2SJed Brown self.logBack() 244*179860b2SJed Brown msg = msg.replace(RemoveDirectory,'') 245*179860b2SJed Brown for ms in msg.split('\n'): 246*179860b2SJed Brown f.write(ms[0:self.linewidth]) 247*179860b2SJed Brown f.write(''.join([' '] * (self.linewidth - len(ms)))) 248*179860b2SJed Brown else: 249*179860b2SJed Brown if not debugSection is None and not debugSection == 'screen' and len(msg): 250*179860b2SJed Brown f.write(str(debugSection)) 251*179860b2SJed Brown f.write(': ') 252*179860b2SJed Brown f.write(msg) 253*179860b2SJed Brown if hasattr(f, 'flush'): 254*179860b2SJed Brown f.flush() 255*179860b2SJed Brown return 256*179860b2SJed Brown 257*179860b2SJed Brown def logPrint(self, msg, debugLevel = -1, debugSection = None, indent = 1, comm = None, forceScroll = 0): 258*179860b2SJed Brown '''Write the message to the log streams with proper indentation and a newline''' 259*179860b2SJed Brown if indent: 260*179860b2SJed Brown self.logIndent(debugLevel, debugSection, comm) 261*179860b2SJed Brown self.logWrite(msg, debugLevel, debugSection, forceScroll = forceScroll) 262*179860b2SJed Brown for writeAll, f in enumerate([self.out, self.log]): 263*179860b2SJed Brown if self.checkWrite(f, debugLevel, debugSection, writeAll): 264*179860b2SJed Brown if writeAll or self.linewidth < 0: 265*179860b2SJed Brown f.write('\n') 266*179860b2SJed Brown return 267*179860b2SJed Brown 268*179860b2SJed Brown 269*179860b2SJed Brown def getRoot(self): 270*179860b2SJed Brown '''Return the directory containing this module 271*179860b2SJed Brown - This has the problem that when we reload a module of the same name, this gets screwed up 272*179860b2SJed Brown Therefore, we call it in the initializer, and stash it''' 273*179860b2SJed Brown #print ' In getRoot' 274*179860b2SJed Brown #print hasattr(self, '__root') 275*179860b2SJed Brown #print ' done checking' 276*179860b2SJed Brown if not hasattr(self, '__root'): 277*179860b2SJed Brown import os 278*179860b2SJed Brown import sys 279*179860b2SJed Brown 280*179860b2SJed Brown # Work around a bug with pdb in 2.3 281*179860b2SJed Brown if hasattr(sys.modules[self.__module__], '__file__') and not os.path.basename(sys.modules[self.__module__].__file__) == 'pdb.py': 282*179860b2SJed Brown self.__root = os.path.abspath(os.path.dirname(sys.modules[self.__module__].__file__)) 283*179860b2SJed Brown else: 284*179860b2SJed Brown self.__root = os.getcwd() 285*179860b2SJed Brown #print ' Exiting getRoot' 286*179860b2SJed Brown return self.__root 287*179860b2SJed Brown def setRoot(self, root): 288*179860b2SJed Brown self.__root = root 289*179860b2SJed Brown return 290*179860b2SJed Brown root = property(getRoot, setRoot, doc = 'The directory containing this module') 291