[Cvsshell-devel] CVS: cvsshell/src app.py,1.4,1.5 basic_cmds.py,1.11,1.12 configurable_app.py,1.3,1.
Status: Beta
Brought to you by:
stefanheimann
From: Stefan H. <ste...@us...> - 2002-03-08 22:31:06
|
Update of /cvsroot/cvsshell/cvsshell/src In directory usw-pr-cvs1:/tmp/cvs-serv20462 Modified Files: app.py basic_cmds.py configurable_app.py cvs_shell.py plugable_app.py utils.py Log Message: * it's now possible to specify filenames for commit, add, remove * auto-aliases for checkout works now Index: app.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/app.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** app.py 7 Mar 2002 13:08:49 -0000 1.4 --- app.py 8 Mar 2002 22:31:00 -0000 1.5 *************** *** 20,233 **** ############################################################################### ! import sys, os, traceback, getopt ! AppError = 'AppError' ! ! _thisdir = os.path.join(os.getcwd(), sys.path[0]) ! ! class App: ! ! def __init__(self): ! # the directory this file is placed in ! self.THIS_DIR = _thisdir ! self.HOME = os.environ['HOME'] ! self.CONTEXT = {'APP':self} ! self.name = self.__class__.__name__ ! self.version = '0.1' ! self.copyright = None ! self.bugAddress = None ! self.args = sys.argv[1:] ! self.env = os.environ ! self.opts = None ! self.input = sys.stdin ! self.output = sys.stdout ! self.error = sys.stderr ! self.opt_to_doc = {} # opt_name -> doc ! ! def setName(self,name): ! self.name = name ! ! def setVersion(self,version): ! self.version = version ! ! def setCopyright(self, copyright): ! self.copyright = copyright ! ! def setBugAddress(self, address): ! self.bugAddress = address ! ! def closeApp(self): ! try: ! if self.input is not sys.stdin: self.input.close() ! except: pass ! try: ! if self.output is not sys.stdout: self.output.close() ! except: pass ! try: ! if self.error is not sys.stderr: self.error.close() ! except: pass ! ! def help(self): ! """Print the help message.""" ! print "%s, Version %s" % (self.name, self.version) ! print ! max = 0 ! for x in self.docs: ! l = len(x[0]) ! if l > max: max = l ! for x in self.docs: ! spaces = (max - len(x[0])) * ' ' ! print " %s%s %s" % (x[0],spaces,x[1]) ! print ! ! def initOptions(self, opts=[]): ! """ ! This method should be called once before getarg is called. ! opts is a list of key-value pairs. ! The keys are the name of the options that should be ! supported, without the leading `-'. If an ! option expects an argument, the name of the option should be ! followed by a colon. ! The values are the documentation of the option. ! """ ! str = '' ! self.docs = [] ! for x in opts: ! name = x[0] ! doc = x[1] ! str += name ! name = '-' + name ! if name[-1] == ':': name = name[:-1] + " <arg>" ! self.docs.append((name,doc)) ! try: ! self.opts = getopt.getopt(self.args,str) ! except getopt.GetoptError, msg: ! self.printErr("%s: %s" % (self.name, msg)) ! self.exit() ! ! ############################## ! # script environment services ! ############################## ! ! def getopt(self, tag): ! """test '-x' command arg""" ! if self.opts == None: ! raise AppError, "You have to call init_options before using getopt!" ! for x in self.opts[0]: ! if x[0] == tag: return 1 ! return 0 ! ! def getarg(self, tag, default=None): ! """get '-x val' command arg""" ! if self.opts == None: ! raise AppError, "You have to call init_options before using getarg!" ! for x in self.opts[0]: ! if x[0] == tag: return x[1] ! return default ! ! def restargs(self): ! """get the rest of the commandline arguments (after all options)""" ! if self.opts == None: ! raise AppError, "You have to call init_options before using restargs!" ! return self.opts[1] ! ! def getenv(self, name, default=''): ! """get '$x' environment var""" ! try: ! return self.env[name] ! except KeyError: ! return default ! ! def setenv(self, name, value): # convenient method ! """set '$x' environment var""" ! self.env[name] = value ! ! def isVerbose(self): ! return self.getopt('-v') or self.getopt('--verbose') ! ! def isHelpRequest(self): ! return self.getopt('-h') or self.getopt('--help') ! ! def printVMsg(self, text='', nonl=0): ! if self.isVerbose(): self.printMsg(text, nonl) ! ! def printMsg(self, text='', nonl=0): ! self.output.write(str(text)) ! if not nonl: self.output.write('\n') ! ! def printErr(self, text='', nonl=0): ! self.error.write(str(text)) ! if not nonl: self.error.write('\n') ! ! def exit(self, message='', status=1): ! if message: ! self.printMsg(message) ! sys.exit(status) ! ! def shell(self, command, fork=0, inp=''): ! if self.isVerbose(): ! self.printMsg(command) # how about ipc? ! if not fork: ! os.system(command) # run a shell cmd ! elif fork == 1: ! return os.popen(command, 'r').read() # get its output ! else: # readlines too? ! pipe = os.popen(command, 'w') ! pipe.write(inp) # send it input ! pipe.close() ! ! ################################################# ! # input/output-stream methods for the app itself; ! # redefine in subclasses if not using files, or ! # set self.input/output to file-like objects; ! ################################################# ! ! def read(self, *size): ! return apply(self.input.read, size) ! def readline(self): ! return self.input.readline() ! def readlines(self): ! return self.input.readlines() ! def write(self, text): ! self.output.write(text) ! def writelines(self, text): ! self.output.writelines(text) ! ! ! def main(self): ! """to run the app ! main() is the start/run/stop execution protocol""" ! if self.isHelpRequest(): ! self.help() ! return 0 ! res = None ! try: ! self.start() ! self.run() ! res = self.stop() # optional return val ! except SystemExit: # ignore if from exit() ! pass ! except: ! self.printMsg('========== Traceback starts here ==========') ! self.printMsg('uncaught: ' + `(sys.exc_type,sys.exc_value)`) ! traceback.print_exc() ! self.printMsg(""" ! Program Version: %s ! Platform: %s ! Python version: %s""" % (self.version, sys.platform, sys.version)) ! self.printMsg("========== Traceback ends here ==========\n" \ ! "You have discovered a bug in %s." % self.name) ! if self.bugAddress.find('@') > 0: ! self.printMsg("Please send a bug report to \n %s," % self.bugAddress) ! else: ! self.printMsg("Please fill out a bug report at \n %s," % self.bugAddress) ! self.printMsg("including the traceback above.") ! self.closeApp() ! return res ! ! def start(self): ! if self.isVerbose(): self.printMsg(self.name + ' started.') ! def stop(self): ! if self.isVerbose(): self.printMsg(self.name + ' done.') ! def run(self): ! raise AppError, 'run must be redefined!' ! --- 20,239 ---- ############################################################################### ! import sys, os, traceback, getopt ! AppError = 'AppError' ! ! _thisdir = os.path.join(os.getcwd(), sys.path[0]) ! ! class App: ! ! def __init__(self): ! # the directory this file is placed in ! self.THIS_DIR = _thisdir ! self.HOME = os.environ['HOME'] ! self.CONTEXT = {'APP':self} ! self.name = self.__class__.__name__ ! self.version = '0.1' ! self.copyright = None ! self.bugAddress = None ! self.args = sys.argv[1:] ! self.env = os.environ ! self.opts = None ! self.input = sys.stdin ! self.output = sys.stdout ! self.error = sys.stderr ! self.opt_to_doc = {} # opt_name -> doc ! ! def setName(self,name): ! self.name = name ! ! def setVersion(self,version): ! self.version = version ! ! def setCopyright(self, copyright): ! self.copyright = copyright ! ! def setBugAddress(self, address): ! self.bugAddress = address ! ! def closeApp(self): ! try: ! if self.input is not sys.stdin: self.input.close() ! except: pass ! try: ! if self.output is not sys.stdout: self.output.close() ! except: pass ! try: ! if self.error is not sys.stderr: self.error.close() ! except: pass ! ! def help(self): ! """Print the help message.""" ! print "%s, Version %s" % (self.name, self.version) ! print ! max = 0 ! for x in self.docs: ! l = len(x[0]) ! if l > max: max = l ! for x in self.docs: ! spaces = (max - len(x[0])) * ' ' ! print " %s%s %s" % (x[0],spaces,x[1]) ! print ! ! def initOptions(self, opts=[]): ! """ ! This method should be called once before getarg is called. ! opts is a list of key-value pairs. ! The keys are the name of the options that should be ! supported, without the leading `-'. If an ! option expects an argument, the name of the option should be ! followed by a colon. ! The values are the documentation of the option. ! """ ! str = '' ! self.docs = [] ! for x in opts: ! name = x[0] ! doc = x[1] ! str += name ! name = '-' + name ! if name[-1] == ':': name = name[:-1] + " <arg>" ! self.docs.append((name,doc)) ! try: ! self.opts = getopt.getopt(self.args,str) ! except getopt.GetoptError, msg: ! self.printErr("%s: %s" % (self.name, msg)) ! self.exit() ! ! ############################## ! # script environment services ! ############################## ! ! def getopt(self, tag): ! """test '-x' command arg""" ! if self.opts == None: ! raise AppError, "You have to call init_options before using getopt!" ! for x in self.opts[0]: ! if x[0] == tag: return 1 ! return 0 ! ! def getarg(self, tag, default=None): ! """get '-x val' command arg""" ! if self.opts == None: ! raise AppError, "You have to call init_options before using getarg!" ! for x in self.opts[0]: ! if x[0] == tag: return x[1] ! return default ! ! def restargs(self): ! """get the rest of the commandline arguments (after all options)""" ! if self.opts == None: ! raise AppError, "You have to call init_options before using restargs!" ! return self.opts[1] ! ! def getenv(self, name, default=''): ! """get '$x' environment var""" ! try: ! return self.env[name] ! except KeyError: ! return default ! ! def setenv(self, name, value): # convenient method ! """set '$x' environment var""" ! self.env[name] = value ! ! def isVerbose(self): ! return self.getopt('-v') or self.getopt('--verbose') ! ! def isHelpRequest(self): ! return self.getopt('-h') or self.getopt('--help') ! ! def printVMsg(self, text='', nonl=0): ! if self.isVerbose(): self.printMsg(text, nonl) ! ! def printMsg(self, text='', nonl=0): ! self.output.write(str(text)) ! if not nonl: self.output.write('\n') ! ! def printErr(self, text='', nonl=0): ! self.error.write(str(text)) ! if not nonl: self.error.write('\n') ! ! def exit(self, message='', status=1): ! if message: ! self.printMsg(message) ! sys.exit(status) ! ! def shell(self, command, fork=0, inp=''): ! if self.isVerbose(): ! self.printMsg(command) # how about ipc? ! if not fork: ! os.system(command) # run a shell cmd ! elif fork == 1: ! return os.popen(command, 'r').read() # get its output ! else: # readlines too? ! pipe = os.popen(command, 'w') ! pipe.write(inp) # send it input ! pipe.close() ! ! ################################################# ! # input/output-stream methods for the app itself; ! # redefine in subclasses if not using files, or ! # set self.input/output to file-like objects; ! ################################################# ! ! def read(self, *size): ! return apply(self.input.read, size) ! def readline(self): ! return self.input.readline() ! def readlines(self): ! return self.input.readlines() ! def write(self, text): ! self.output.write(text) ! def writelines(self, text): ! self.output.writelines(text) ! ! ! def main(self): ! """to run the app ! main() is the start/run/stop execution protocol""" ! if self.isHelpRequest(): ! self.help() ! return 0 ! res = None ! try: ! self.start() ! self.run() ! res = self.stop() # optional return val ! except SystemExit: # ignore if from exit() ! pass ! except: ! out = sys.stderr ! out.write('========== Traceback starts here ==========\n') ! out.write('uncaught: ' + `(sys.exc_type,sys.exc_value)` + '\n') ! traceback.print_exc() ! out.write(""" ! Program Version: %s ! Platform: %s ! Python version: %s ! """ % (self.version, sys.platform, sys.version)) ! out.write("========== Traceback ends here ==========\n" \ ! "You have discovered a bug in %s.\n" % self.name) ! if self.bugAddress.find('@') > 0: ! out.write("Please send a bug report to \n %s," ! % self.bugAddress) ! else: ! out.write("Please fill out a bug report at \n %s," ! % self.bugAddress) ! self.printMsg("\nincluding the traceback above.\n") ! self.closeApp() ! return res ! ! def start(self): ! self.printMsg("%s %s" % (self.name, self.version)) ! self.printMsg(self.copyright) ! self.printVMsg(self.name + ' started.') ! def stop(self): ! self.printVMsg(self.name + ' done.') ! def run(self): ! raise AppError, 'run must be redefined!' ! Index: basic_cmds.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/basic_cmds.py,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** basic_cmds.py 8 Mar 2002 11:32:16 -0000 1.11 --- basic_cmds.py 8 Mar 2002 22:31:01 -0000 1.12 *************** *** 182,185 **** --- 182,187 ---- return rest = rest.split() + if app.getCvsRoot() is None: + setCvsRoot('','',context) # FIXME do we really need the name arg? if len(rest) < 1: module = app.prompt('enter name of module: ') *************** *** 203,218 **** return if not rest: ! number = app.prompt('enter filenumber(s) to add: ') ! if numbers is None: return def __doIt(e,filename): e.status = utils.Entry.S_ADDED return filename ! (rootDir, filenames) = _applyOnEntryList(numbers, context, __doIt) if filenames: - if isBinary: opts += '-kb' try: _runCvsCmd(context, 'add', rootDir=rootDir, globOpts=globOpts, args=opts+' '+utils.list2string(filenames)) except CvsError: pass --- 205,226 ---- return if not rest: ! rest = app.prompt('enter filenumbers/filenames to add: ') ! if rest is None: return def __doIt(e,filename): e.status = utils.Entry.S_ADDED return filename ! (rootDir, filenames) = _applyOnEntryList(rest, context, __doIt) ! if isBinary: opts += '-kb' if filenames: try: _runCvsCmd(context, 'add', rootDir=rootDir, globOpts=globOpts, args=opts+' '+utils.list2string(filenames)) except CvsError: pass + else: # args do not spefiy ids in the current listing + try: + _runCvsCmd(context, 'add', globOpts=globOpts, + args=opts+' '+rest) + context['basic_cmds.dirty_listing'] = 0 + except CvsError: pass *************** *** 228,237 **** myOpts, rest) = _parseArgs(args, app.cmdToOpts.get(name, '')) - print "opts = %s" % opts - print "rest = %s" % rest except getopt.GetoptError, msg: app.printErr(msg) return ! if not rest: try: try: --- 236,243 ---- myOpts, rest) = _parseArgs(args, app.cmdToOpts.get(name, '')) except getopt.GetoptError, msg: app.printErr(msg) return ! if not rest: # commit without an argument try: try: *************** *** 257,260 **** --- 263,273 ---- args=opts+' '+utils.list2string(filenames), fork=1) except CvsError: pass + else: # args do not spefiy ids in the current listing + try: + _runCvsCmd(context, 'commit', globOpts=globOpts, + args=opts+' '+rest, fork=1) + context['basic_cmds.dirty_listing'] = 0 + except CvsError: pass + def remove(name, args, context): *************** *** 262,287 **** try: (globOpts, opts, ! myOpts, numbers) = _parseArgs(args, app.cmdToOpts.get(name, '')) except getopt.GetoptError, msg: app.printErr(msg) return ! if not numbers: ! numbers = app.prompt('enter filenumber(s) to remove: ') ! if numbers is None: return def __doIt(e,filename): return e ! (rootDir, toDelete) = _applyOnEntryList(numbers, context, __doIt) toDeleteList = utils.Listing(rootDir, toDelete) filenames = [] ! for e in toDeleteList.entries: ! name = os.path.join(toDeleteList.rootDir, e.dir, e.name) ! try: ! os.unlink(name) ! except OSError, msg: ! app.printErr(msg) ! else: filenames.append(os.path.join(e.dir, e.name)) e.status = utils.Entry.S_REMOVED if filenames: args = utils.list2string(filenames) --- 275,310 ---- try: (globOpts, opts, ! myOpts, rest) = _parseArgs(args, app.cmdToOpts.get(name, '')) except getopt.GetoptError, msg: app.printErr(msg) return ! if not rest: ! rest = app.prompt('enter filenumber(s) to remove: ') ! if rest is None: return def __doIt(e,filename): return e ! (rootDir, toDelete) = _applyOnEntryList(rest, context, __doIt) toDeleteList = utils.Listing(rootDir, toDelete) filenames = [] ! if toDelete: ! for e in toDeleteList.entries: ! name = os.path.join(toDeleteList.rootDir, e.dir, e.name) ! try: ! os.unlink(name) ! except OSError, msg: ! app.printErr(msg) ! # Hope that the file already has been removed filenames.append(os.path.join(e.dir, e.name)) e.status = utils.Entry.S_REMOVED + else: # args do not specify ids in the current listing + fs = utils.splitquoted(rest) + for name in fs: + try: + os.unlink(name) + except OSError, msg: + app.printErr(msg) + # Hope that the file already has been removed + filenames.append(name) if filenames: args = utils.list2string(filenames) *************** *** 318,321 **** --- 341,349 ---- if roots != None and roots.has_key(newRoot): newRoot = roots[newRoot] + if not roots.has_key(newRoot): + a = app.prompt("You can specify an alias for the cvsroot: ") + if a: + context.get('basic_cmds.CVSROOTS', {})[a] = newRoot + app.appendToSection('CVSROOT', ['%s = %s' % (a, newRoot)]) if newRoot is not None: app.setCvsRoot(newRoot) *************** *** 358,368 **** """fun must take 2 argument as the entry and its filename is passed to it. Returns a tuple ! (rootdir of listing, list with the return values from fun).""" app = context['APP'] ! defRet = (None, None) try: nums = utils.getNumbers(opts) except utils.ParseError, msg: - app.printErr(msg) return defRet if len(nums) == 0: --- 386,396 ---- """fun must take 2 argument as the entry and its filename is passed to it. Returns a tuple ! (rootdir of listing, list with the return values from fun). ! If an error occurs, (None, []) is returned.""" app = context['APP'] ! defRet = (None, []) try: nums = utils.getNumbers(opts) except utils.ParseError, msg: return defRet if len(nums) == 0: Index: configurable_app.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/configurable_app.py,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** configurable_app.py 7 Mar 2002 13:08:49 -0000 1.3 --- configurable_app.py 8 Mar 2002 22:31:01 -0000 1.4 *************** *** 55,74 **** def readConfigFile(self): - f = open(self.configFile,'r') try: ! sections = self._splitSections(f.readlines()) ! except SyntaxError, msg: ! self.printErr("Syntax error in config file: %s" % msg) ! return ! for x in sections.items(): ! name = x[0] ! content = x[1] ! if self._configsection_to_fun.has_key(name): ! self._configsection_to_fun[name](content, self.CONTEXT) else: ! self.printErr("Unknown section in configuration file: %s" ! % name) ! f.close() ######################################## # helper methods --- 55,107 ---- def readConfigFile(self): try: ! f = open(self.configFile,'r') ! try: ! sections = self._splitSections(f.readlines()) ! except SyntaxError, msg: ! self.printErr("Syntax error in config file: %s" % msg) ! return ! for x in sections.values(): ! try: ! self._configsection_to_fun[x.name](x.content, self.CONTEXT) ! except KeyError: ! self.printErr("Unknown section in configuration file: %s" ! % name) ! f.close() ! except IOError, msg: ! self.printErr(msg) ! ! ! def appendToSection(self, section, lines): ! """ Appends lines the the given section (a new section is ! created if not existing). lines is a list of lines without ! trailing \n""" ! try: ! f = open(self.configFile,'r') ! l = f.readlines() ! f.close() ! try: ! sections = self._splitSections(l) ! except SyntaxError, msg: ! self.printErr("Syntax error in config file: %s" % msg) ! return ! if sections.has_key(section): ! n = sections[section].end else: ! n = len(l) ! l.insert(n, '\n') ! n += 1 ! i = 0 ! for x in lines: ! print "inserting %s" % x ! l.insert(n+i-1, x + '\n') ! i += 1 ! f = open(self.configFile,'w') ! f.writelines(l) ! f.close() ! except IOError, msg: ! self.printErr(msg) + ######################################## # helper methods *************** *** 97,106 **** return fun def _splitSections(self,lines): ! """Returns a dictionary which maps every name of a section ! to the lines of the section. the values of the dictionary ! are tuples that consist of the line number and the content of ! the line. Comment lines are already removed. ! Leading and trailing whitespace are also removed. If a syntax exception is encountered, a SyntaxError is raised.""" comment_re= re.compile(r'^(\s*|\s*#.*)$') --- 130,145 ---- return fun + class Section: + def __init__(self, name, start): + self.name = name + self.start = start + self.end = None + self.content = [] + def _splitSections(self,lines): ! """Returns a dict which maps every name of a section to a ! ConfigurableApp.Section instance. ! Comment lines in a section are already removed. ! Leading and trailing whitespace is also removed from every line If a syntax exception is encountered, a SyntaxError is raised.""" comment_re= re.compile(r'^(\s*|\s*#.*)$') *************** *** 130,135 **** "section (line %d)." % n section_open = 1 ! section_name = start.group('name') ! section_content = [] continue end = section_end_re.match(l) --- 169,173 ---- "section (line %d)." % n section_open = 1 ! section = ConfigurableApp.Section(start.group('name'), n) continue end = section_end_re.match(l) *************** *** 139,143 **** "(line %d)." % n section_open = 0 ! sections[section_name] = section_content continue # the line must be the content of a section --- 177,182 ---- "(line %d)." % n section_open = 0 ! section.end = n ! sections[section.name] = section continue # the line must be the content of a section *************** *** 146,150 **** "section (line %d)." % n l = l.strip() ! section_content.append((n,l)) return sections --- 185,189 ---- "section (line %d)." % n l = l.strip() ! section.content.append((n,l)) return sections Index: cvs_shell.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/cvs_shell.py,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** cvs_shell.py 8 Mar 2002 11:12:29 -0000 1.9 --- cvs_shell.py 8 Mar 2002 22:31:01 -0000 1.10 *************** *** 34,38 **** self.setName('CvsShell') self.setVersion(VERSION) ! self.setCopyright('Copyright 2002 by Stefan Heimann. This software is released under the GPL.') self.setBugAddress('http://sourceforge.net/tracker/?group_id=48175&atid=452212') etcDir = os.path.join(self.THIS_DIR, '..', 'etc') --- 34,39 ---- self.setName('CvsShell') self.setVersion(VERSION) ! self.setCopyright('Copyright 2002 Stefan Heimann (ma...@st...).\n' \ ! 'This software is released under the GPL.') self.setBugAddress('http://sourceforge.net/tracker/?group_id=48175&atid=452212') etcDir = os.path.join(self.THIS_DIR, '..', 'etc') Index: plugable_app.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/plugable_app.py,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** plugable_app.py 8 Mar 2002 11:12:29 -0000 1.3 --- plugable_app.py 8 Mar 2002 22:31:01 -0000 1.4 *************** *** 46,49 **** --- 46,50 ---- cmds = sections.get('COMMANDS', []) + if cmds: cmds = cmds.content for x in cmds: n = x[0] *************** *** 57,60 **** --- 58,62 ---- opts = sections.get('COMMAND_OPTIONS', []) + if opts: opts = opts.content for x in opts: n = x[0] *************** *** 69,72 **** --- 71,75 ---- prs = sections.get('PARSERS', []) + if prs: prs = prs.content for x in prs: n = x[0] Index: utils.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/utils.py,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** utils.py 8 Mar 2002 11:32:16 -0000 1.5 --- utils.py 8 Mar 2002 22:31:01 -0000 1.6 *************** *** 51,54 **** --- 51,57 ---- def printEntries(self, output): + if not self.entries: + output.write('No entries available.\n') + return max = 0 for e in self.entries: *************** *** 57,62 **** formatStr = " %%%dd %%-%ds %%s\n" % (len(`len(self.entries)`), max) oldDir = None - if len(self.entries) == 0: - output.write('No entries available.\n') id = 0 for e in self.entries: --- 60,63 ---- |