[Cvsshell-devel] CVS: cvsshell/src app.py,1.6,1.7 basic_cmds.py,1.13,1.14 configurable_app.py,1.5,1.
Status: Beta
Brought to you by:
stefanheimann
From: Stefan H. <ste...@us...> - 2002-03-10 23:14:02
|
Update of /cvsroot/cvsshell/cvsshell/src In directory usw-pr-cvs1:/tmp/cvs-serv25500/src Modified Files: app.py basic_cmds.py configurable_app.py cvs_shell.py interactive_app.py oo_tools.py plugable_app.py utils.py Log Message: * refactoring * many small improvements Index: app.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/app.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** app.py 8 Mar 2002 22:44:33 -0000 1.6 --- app.py 10 Mar 2002 23:13:59 -0000 1.7 *************** *** 21,70 **** 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.""" --- 21,60 ---- import sys, os, traceback, getopt ! from oo_tools import GetSetProvider ! _thisdir = os.path.join(os.getcwd(), sys.path[0]) + AppError = 'AppError' ! ! class App(GetSetProvider): def __init__(self): # the directory this file is placed in + GetSetProvider.__init__(self) self.THIS_DIR = _thisdir self.HOME = os.environ['HOME'] 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 + def closeApp(self): + for x, y in [(sys.stdin, sys.__stdin__), + (sys.stdout, sys.__stdout__), + (sys.stderr, sys.__stderr__)]: + try: + if x is not y: + x.close() + except: pass + sys.stdin = sys.__stdin__ + sys.stdout = sys.__stdout__ + sys.stderr = sys.__stderr__ + + def help(self): """Print the help message.""" *************** *** 72,82 **** 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=[]): --- 62,73 ---- 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=[]): *************** *** 91,95 **** """ str = '' ! self.docs = [] for x in opts: name = x[0] --- 82,86 ---- """ str = '' ! self._docs = [] for x in opts: name = x[0] *************** *** 98,107 **** 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() ############################## --- 89,99 ---- 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() + ############################## *************** *** 111,117 **** 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 --- 103,109 ---- 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 *************** *** 119,125 **** 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 --- 111,117 ---- 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 *************** *** 127,138 **** 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 --- 119,130 ---- 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 *************** *** 140,144 **** def setenv(self, name, value): # convenient method """set '$x' environment var""" ! self.env[name] = value def isVerbose(self): --- 132,144 ---- def setenv(self, name, value): # convenient method """set '$x' environment var""" ! self._env[name] = value ! ! def cd(self, dir): ! """Changes the current working directory. Returns the old directory.""" ! if not dir: return ! oldDir = os.getcwd() ! self.printVMsg('cd ' + dir) ! os.chdir(dir) ! return oldDir def isVerbose(self): *************** *** 152,161 **** 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): --- 152,161 ---- def printMsg(self, text='', nonl=0): ! sys.stdout.write(str(text)) ! if not nonl: sys.stdout.write('\n') def printErr(self, text='', nonl=0): ! sys.stderr.write(str(text)) ! if not nonl: sys.stderr.write('\n') def exit(self, message='', status=1): *************** *** 175,196 **** 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): --- 175,179 ---- pipe.write(inp) # send it input pipe.close() ! return None def main(self): Index: basic_cmds.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/basic_cmds.py,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** basic_cmds.py 9 Mar 2002 10:56:20 -0000 1.13 --- basic_cmds.py 10 Mar 2002 23:13:59 -0000 1.14 *************** *** 20,35 **** ############################################################################### ! import os, string, re, getopt ! import utils ! from app import AppError ! ! ############################## ! # Errors and error messages ! ############################## ! ! noListingErrMsg = "No listing found. \nYou must run `update', `refresh' " \ ! "or `status' before using this command." ! CvsError = 'CvsError' ! InternalCvsError = 'InternalCvsError' ###################################### --- 20,24 ---- ############################################################################### ! import os, string, re ###################################### *************** *** 37,45 **** ##################################### ! def cmdHelp(name, opts, context): """Prints this help message. If the name of a command is given as a option, a detailed help for this command is printed.""" - app = context['APP'] so = string.split(opts) if len(so) > 0: --- 26,33 ---- ##################################### ! def cmdHelp(app, name, opts): """Prints this help message. If the name of a command is given as a option, a detailed help for this command is printed.""" so = string.split(opts) if len(so) > 0: *************** *** 72,84 **** ! def exitProgram(name, opts, context): "Terminates the program." - app = context['APP'] return app.BREAK_REPL ! def changeDir(name, opts, context): "Changes the current working directory." - app = context['APP'] if len(opts) == 0: opts = app.HOME --- 60,70 ---- ! def exitProgram(app, name, opts): "Terminates the program." return app.BREAK_REPL ! def changeDir(app, name, opts): "Changes the current working directory." if len(opts) == 0: opts = app.HOME *************** *** 86,90 **** os.path.expanduser(opts) try: ! _cd(app,opts) except OSError, msg: app.printErr(msg) --- 72,76 ---- os.path.expanduser(opts) try: ! app.cd(opts) except OSError, msg: app.printErr(msg) *************** *** 93,627 **** if root: app.setCvsRoot(root) - - ############################## - # CVS commands - ############################## - - def status(name, args, context): - app = context['APP'] - entries = [] - regexHead = re.compile(r'File: (?P<name>\S+)\s+Status: (?P<status>.+)') - regexDir = re.compile(r'.*Examining (?P<dir>\S+)') - regexUnknown = re.compile(r'^\?\s+(?P<filename>\S+)') - try: - (globOpts, opts, - myOpts, rest) = _parseArgs(args, - app.cmdToOpts.get(name, '')) - except getopt.GetoptError, msg: - app.printErr(msg) - return - try: - lines = _runCvsCmd(context, 'status', globOpts=globOpts, - args=opts, getStderr=1) - except CvsError: return - entries = [] - dir = None - for line in lines: - unknownRes = regexUnknown.search(line) - if unknownRes: - name = os.path.basename(unknownRes.group('filename')) - dir = os.path.dirname(unknownRes.group('filename')) - entries.append(utils.Entry(dir, name, utils.Entry.S_UNKNOWN)) - continue - headRes = regexHead.search(line) - if headRes and dir is None: - raise InternalCvsError, "Parsing of status message failed: " \ - "`dir' is not set when get file information." - elif headRes: - name = headRes.group('name') - status = headRes.group('status').strip() - entries.append(utils.Entry(dir, name, status)) - continue - dirRes = regexDir.search(line) - if dirRes: - dir = dirRes.group('dir') - if dir == '.': dir = '' - l = context['basic_cmds.listing'] = utils.Listing(app, os.getcwd(), - entries) - context['basic_cmds.dirty_listing'] = 0 - l.sortEntries() - _printListing(context) - - def update(name, args, context, simulate=0): - app = context['APP'] - try: - (globOpts, opts, - myOpts, rest) = _parseArgs(args, - app.cmdToOpts.get(name, '')) - except getopt.GetoptError, msg: - app.printErr(msg) - return - if simulate: globOpts += '-n' - try: - lines = _runCvsCmd(context, 'update', globOpts=globOpts, args=opts) - except CvsError: return - entries = [] - for line in lines: - x = line.split() - status = x[0] - name = os.path.basename(x[1]) - dir = os.path.dirname(x[1]) - entries.append(utils.Entry(dir, name, status)) - l = context['basic_cmds.listing'] = utils.Listing(app, os.getcwd(), - entries) - context['basic_cmds.dirty_listing'] = 0 - l.sortEntries() - _printListing(context) - - def simulateUpdate(name, args, context): - update(name, args, context, simulate=1) - - def checkout(name, args, context): - app = context['APP'] - try: - (globOpts, opts, - myOpts, rest) = _parseArgs(args, - app.cmdToOpts.get(name, '')) - except getopt.GetoptError, msg: - app.printErr(msg) - 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: ') - if module is None: return - else: - module = args[0] - try: - _runCvsCmd(context, 'checkout', globOpts=globOpts, - args=opts+' '+module) - except CvsError: pass - - - def add(name, args, context, isBinary=0): - app = context['APP'] - 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 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 - - - def addBinary(name, args, context): - context['APP'].printMsg('The file will be added in binary mode.') - add(name, args, context, isBinary=1) - - - def commit(name, args, context): - app = context['APP'] - try: - (globOpts, opts, - 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: - listing = context['basic_cmds.listing'] - rootDir = listing.rootDir - except KeyError: - rootDir = '' - _runCvsCmd(context, 'commit', rootDir=rootDir, - globOpts=globOpts, args=opts, fork=1) - context['basic_cmds.dirty_listing'] = 1 - except CvsError: pass - return - def __doIt(e,filename): - if e.status == utils.Entry.S_REMOVED: - e.status = utils.Entry.S_DELETED - else: - e.status = utils.Entry.S_OK - return filename - (rootDir, filenames) = _applyOnEntryList(rest, context, __doIt) - if filenames: - try: - _runCvsCmd(context, 'commit', rootDir=rootDir, globOpts=globOpts, - 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): - app = context['APP'] - 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(app, 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) - try: - _runCvsCmd(context, 'remove', rootDir=rootDir, - globOpts=globOpts, args=opts+' '+args) - except CvsError: return - toDeleteList.printEntries(app.output) - answ = app.prompt("\nThe files have been scheduled for removal.\n" \ - "Should I run `commit' to remove the files " \ - "permanently (yes|no)? ") - if answ == 'yes': - for e in toDeleteList.entries: - e.status = utils.Entry.S_DELETED - _runCvsCmd(context, 'commit', rootDir=rootDir, fork=1, args=args) - - def printListing(name, args, context): - _printListing(context) - - def setCvsRoot(name, args, context): - "Sets the cvsroot variable manually." - app = context['APP'] - roots = context['basic_cmds.CVSROOTS'] - if len(args) != 0: - newRoot = args.split()[0] - else: - if roots == None: - app.printMsg("No aliases specified.") - else: - app.printMsg("Aliases:") - for x in roots.items(): - print " %s => %s" % (x[0], x[1]) - newRoot = app.prompt('enter new cvsroot: ') - 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) - - def readCvsRoot(name, args, context): - "Reads the cvsroot variable from ./CVS/Root." - app = context['APP'] - newRoot = app.readCvsRootFromFile() - if newRoot == None: - app.printErr('Could not read CVSROOT from file.') - else: - app.setCvsRoot(newRoot) - - def clearCvsRoot(name, args, context): - "Unsets the cvsroot variable." - app = context['APP'] - app.setCvsRoot(None) - - def toggleCvsRootAutoUpdate(name, args, context): - """Toggles the auto-update feature for the CVSROOT var. - If this option is set, the CVSROOT variable is automatically updated when a new - directory is entered. Without a argument the option is toggled. You can set the - option to a new value with `on' or `off' as argument.""" - app = context['APP'] - app.cvsRootAutoUpdate = _toggle(app, app.cvsRootAutoUpdate, args) - if app.cvsRootAutoUpdate: - newRoot = app.readCvsRootFromFile() - if newRoot is not None: app.setCvsRoot(newRoot) - - def toggleFullPrompt(name, args, context): - app = context['APP'] - app.showFullPrompt = _toggle(app, app.showFullPrompt, args) - - - ################################### - # Helper functions for CVS commands - ################################### - - def _applyOnEntryList(opts, context, fun): - """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: - app.printMsg('No files specified.') - return defRet - try: - listing = context['basic_cmds.listing'] - except KeyError: - app.printErr(noListingErrMsg) - return defRet - result = [] - for x in nums: - e = listing.entries[x] - name = os.path.join(e.dir, e.name) - result.append(fun(e,name)) - return listing.rootDir, result - - - def _runCvsCmd(context, cmd, rootDir=None, globOpts = '', - args='', fork=0, getStderr=0): - """ - * cmd is the command to execute - * rootDir is the directory the command should be executed in - * globOpts are global options. These options - override the default global options - * args are the arguments that should be passed to the cvs command - """ - app = context['APP'] - - oldDir = None - if rootDir is not None: - try: - oldDir = _cd(app,rootDir) - except OSError,msg: - app.printErr("Could not change to the root directory of the " \ - "current listing: %s" % str(msg)) - raise CvsError - - defGlobOpts,defOpts = _getOptions(context,cmd) - - cvsRoot = app.getCvsRoot() - if cvsRoot != None: cvsRootOpt = "-d %s" % cvsRoot - else: cvsRootOpt = '' - - globOpts = "%s %s %s" % (defGlobOpts, cvsRootOpt, globOpts) - args = "%s %s" % (defOpts, args) - - cmd = 'cvs %s %s %s' % (globOpts, cmd, args) - if getStderr: cmd += ' 2>&1' - app.printVMsg(cmd) - if not fork: - f = os.popen(cmd) - try: - lines = f.readlines() - except KeyboardInterrupt: - return [] - if f.close() is not None: # cvs command caused an error - raise CvsError - else: - return lines - else: - r = os.system(cmd) - if r != 0: - raise CvsError - - if oldDir is not None: - try: - _cd(app,oldDir) - except OSError,msg: - app.printErr(msg) - - - def _isDirtyListing(context): - try: - return context['basic_cmds.dirty_listing'] - except KeyError: - return 0 - - def _printListing(context): - app = context['APP'] - try: - listing = context['basic_cmds.listing'] - except KeyError: - app.printErr(noListingErrMsg) - else: - listing.printEntries() - if _isDirtyListing(context): - app.printMsg("Listing may be out-of-date. " \ - "Run `update', `refresh' or `status'.") - - - def _parseArgs(args, cvsCmdOpts='', cmdOpts=''): - """Parse args and separates it like that: - cvsCmdOpts are the options that are allowed for the cvs command - cmdOpts are additional options - global options are handled automatically - * global cvs options (as string) - * command specific cvs options (as string) - * other options (as dictionary) - * other args (as string) - These values are returned as a 4-tupel. - A GetoptError is raised if there are unknown options.""" - cvsGlobOpts = 'HQqrwlntvb:T:e:d:fz:as:' - s = cvsGlobOpts+cvsCmdOpts+cmdOpts - (opts, rest) = getopt.getopt(utils.splitquoted(args), s) - cvsGlobOptstr = cvsCmdOptstr = '' - cmdOptDict = {} - for x in opts: - name, value = x - if name[1] in cvsGlobOpts: - cvsGlobOptstr += ' %s %s' % (name, value) - elif name[1] in cvsCmdOpts: - cvsCmdOptstr += ' %s %s' % (name, value) - else: - cmdOptDict[name] = value - reststr = '' - for x in rest: - reststr += x + ' ' - if reststr: reststr = reststr[:-1] - return (cvsGlobOptstr, cvsCmdOptstr, cmdOptDict, reststr) - - - - def _getAllowedOptions(context, cmd): - """Returns the option string that is allowed for cmd.""" - return context['basic_cmds.allowedOptions'].get(cmd, '') - - - def _getOptions(context, cmd): - """Returns the options that should be used for cmd. The return value - is the tupel (globalOptions, options)""" - defGlobOpts = context['basic_cmds.ALL.defaultGlobalOptions'] - defOpts = context['basic_cmds.ALL.defaultOptions'] - defGlobOpts += context['basic_cmds.defaultGlobalOptions'].get(cmd,'') - defOpts += context['basic_cmds.defaultOptions'].get(cmd,'') - return defGlobOpts,defOpts - - - ############################## - # Parsing functions - ############################## - - def parseCvsRootSection(lines, context): - app = context['APP'] - splitRE = re.compile(r'\s*=\s*') - roots = {} - for x in lines: - n = x[0] - l = splitRE.split(x[1]) - if len(l) != 2: - app.printErr("Syntax error in configuration file (line %d)." % n) - else: - roots[l[0]] = l[1] - context['basic_cmds.CVSROOTS'] = roots - - - def parseInitCmdsSection(lines, context): - app = context['APP'] - for x in lines: - cmd = x[1] - app.evalCommand(cmd) - - - def parseDefaultOptions(lines, context): - app = context['APP'] - splitRE = re.compile(r'\s*[,=]\s*') - defOpts = {} - defGlobOpts = {} - for x in lines: - n = x[0] - l = splitRE.split(x[1]) - if len(l) < 2: - app.printErr("Syntax error in configuration file (line %d)." % n) - continue - value = l[-1] - for y in l[:-1]: - try: - if y != 'ALL': - (globOpt, opt, - du1, du2) = _parseArgs(value, app.cmdToOpts.get(y,'')) - defOpts[y] = opt - defGlobOpts[y] = globOpt - else: - (globOpt, opt, du1, du2) = _parseArgs(value) - context['basic_cmds.ALL.defaultOptions'] = opt - context['basic_cmds.ALL.defaultGlobalOptions'] = globOpt - except getopt.GetoptError, msg: - app.printErr("Bad format for default options for command "\ - "`%s': %s: %s" % (y, value, str(msg))) - app.printVMsg("Default global options:\n" \ - + `defGlobOpts` + \ - "\nDefault options:\n" \ - + `defOpts`) - context['basic_cmds.defaultOptions'] = defOpts - context['basic_cmds.defaultGlobalOptions'] = defGlobOpts - - - def parseConfigSection(lines, context): - app = context['APP'] - splitRE = re.compile(r'\s*=\s*') - for x in lines: - n = x[0] - l = splitRE.split(x[1]) - if len(l) != 2: - app.printErr("Syntax error in configuration file (line %d)." % n) - continue - key, value = l - app.configMap[key] = value - - - ############################## - # Helper functions - ############################## - - def _cd(app, dir): - """Changes the current working directory. Returns the old directory.""" - if not dir: return - oldDir = os.getcwd() - app.printVMsg('cd ' + dir) - os.chdir(dir) - return oldDir - - - def _toggle(app, oldVal, args): - if len(args) == 0: - return not oldVal - else: - if args == 'on': return 1 - elif args == 'off': return 0 - else: - app.printErr("argument must be `on' or `off'") - return oldVal --- 79,82 ---- Index: configurable_app.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/configurable_app.py,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** configurable_app.py 9 Mar 2002 10:56:20 -0000 1.5 --- configurable_app.py 10 Mar 2002 23:13:59 -0000 1.6 *************** *** 27,34 **** class ConfigurableApp(App): def __init__(self): App.__init__(self) ! self._configsection_to_fun = {} def setConfigFile(self, filename, default=None): """Set the name of the configfile. If the configfile --- 27,46 ---- class ConfigurableApp(App): + class Section: + def __init__(self, name, start): + self.name = name + self.start = start + self.end = None + self.content = [] + + def __init__(self): App.__init__(self) ! self._configsectionToFun = {} ! self.keyValSplitRE = re.compile(r'\s*=\s*') ! self.keysValSplitRE = re.compile(r'\s*[,=]\s*') ! self.commentRE = re.compile(r'^(\s*|\s*#.*)$') + def setConfigFile(self, filename, default=None): """Set the name of the configfile. If the configfile *************** *** 45,56 **** f.close() def registerConfigSectionParser(self, name, fun): """Registers `fun' for the section `name' in the config file. The function must accept 2 arguments: The 1st one is ! the lines of the section, the 2nd is the application context. `fun' is either a function or the name of a function.""" fun = self._getFun(fun) if fun != None: ! self._configsection_to_fun[name] = fun def readConfigFile(self): --- 57,70 ---- f.close() + def registerConfigSectionParser(self, name, fun): """Registers `fun' for the section `name' in the config file. The function must accept 2 arguments: The 1st one is ! the lines of the section, the 2nd is the application itself. `fun' is either a function or the name of a function.""" fun = self._getFun(fun) if fun != None: ! self._configsectionToFun[name] = fun ! def readConfigFile(self): *************** *** 64,71 **** 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: --- 78,85 ---- for x in sections.values(): try: ! self._configsectionToFun[x.name](x.content, self) except KeyError: self.printErr("Unknown section in configuration file: %s" ! % x.name) f.close() except IOError, msg: *************** *** 94,98 **** i = 0 for x in lines: - print "inserting %s" % x l.insert(n+i-1, x + '\n') i += 1 --- 108,111 ---- *************** *** 130,139 **** return fun - class Section: - def __init__(self, name, start): - self.name = name - self.start = start - self.end = None - self.content = [] def _splitSections(self,lines): --- 143,146 ---- *************** *** 143,147 **** 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*#.*)$') section_start_re = re.compile(r""" ^\s* # matches leading whitespace --- 150,153 ---- *************** *** 161,165 **** for l in lines: n += 1 ! if comment_re.match(l): continue start = section_start_re.match(l) --- 167,171 ---- for l in lines: n += 1 ! if self.commentRE.match(l): continue start = section_start_re.match(l) Index: cvs_shell.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/cvs_shell.py,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** cvs_shell.py 9 Mar 2002 10:56:20 -0000 1.11 --- cvs_shell.py 10 Mar 2002 23:13:59 -0000 1.12 *************** *** 20,40 **** ############################################################################### ! import os, sys, re, string, types ! from configurable_app import SyntaxError from interactive_app import InteractiveApp from plugable_app import PlugableApp VERSION = '0.1' ! class CvsShell(PlugableApp, InteractiveApp): def __init__(self): PlugableApp.__init__(self) InteractiveApp.__init__(self) ! 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') self.setConfigFile(os.path.join(self.HOME,'.cvsshellrc'), --- 20,48 ---- ############################################################################### ! import os, sys, re, string, types, getopt, utils ! from oo_tools import GetSetProvider ! from app import AppError from interactive_app import InteractiveApp from plugable_app import PlugableApp VERSION = '0.1' + NAME ='CvsShell' + COPYRIGHT = 'Copyright 2002 Stefan Heimann (ma...@st...).\n' \ + 'This software is released under the GPL.' + BUG_ADDRESS = 'http://sourceforge.net/tracker/?group_id=48175&atid=452212' + CvsError = 'CvsError' + InternalCvsError = 'InternalCvsError' ! class CvsShell(GetSetProvider, PlugableApp, InteractiveApp): def __init__(self): + GetSetProvider.__init__(self) PlugableApp.__init__(self) InteractiveApp.__init__(self) ! sys.stderr = sys.stdout ! self.setName(NAME) self.setVersion(VERSION) ! self.setCopyright(COPYRIGHT) ! self.setBugAddress(BUG_ADDRESS) etcDir = os.path.join(self.THIS_DIR, '..', 'etc') self.setConfigFile(os.path.join(self.HOME,'.cvsshellrc'), *************** *** 47,50 **** --- 55,59 ---- self.cmdRegex = re.compile(r""" ^\s* # matches leading whitespace + (?!\#) # line is not a comment (negative lookahead!) (?P<name>\S+) # matches the first word of the command ( *************** *** 53,69 **** )? # options are optional """, re.VERBOSE) self.cvsRoot = None self.cvsRootAutoUpdate = 0 self.showFullPrompt = 0 self.configMap = {} self.readCommandFile() self.readConfigFile() - - def setCvsRoot(self, root): - self.cvsRoot = root - - def getCvsRoot(self): - return self.cvsRoot def readCvsRootFromFile(self): s = None --- 62,85 ---- )? # options are optional """, re.VERBOSE) + self.cvsChangeCmdRE = re.compile(r"""\s+ + (ad(d)?|new|ci|com(mit)?|delete|remove) + \s+""", re.VERBOSE) + self.noListingErrMsg = """No listing found. + You must run `update', `refresh' or `status' before using this command.""" self.cvsRoot = None self.cvsRootAutoUpdate = 0 self.showFullPrompt = 0 + self.listing = None + self.dirtyListing = 1 + self.cvsRootAliases = {} self.configMap = {} + self.cmdToDefOpts = {} + self.cmdToDefGlobOpts = {} + self.defOpts = '' # options for all commands + self.defGlobOpts = '' # global options for all commands self.readCommandFile() self.readConfigFile() + def readCvsRootFromFile(self): s = None *************** *** 72,75 **** --- 88,92 ---- return s + def getPrompt(self): status = '' *************** *** 77,81 **** else: status += 'A' root = self.getCvsRoot() or '--' ! dir = os.getcwd().replace(self.HOME, '~') if not self.showFullPrompt: # make to prompt match on one line --- 94,102 ---- else: status += 'A' root = self.getCvsRoot() or '--' ! try: ! dir = os.getcwd().replace(self.HOME, '~') ! # if you delete the dir you are in, getcwd raise an error ! except OSError: ! dir = 'ERROR' if not self.showFullPrompt: # make to prompt match on one line *************** *** 100,103 **** --- 121,125 ---- root) + def evalCommand(self, cmd): result = self.cmdRegex.match(cmd) *************** *** 109,114 **** cmdOpts = '' cmdOpts = cmdOpts.strip() ! fun = self.getCmdFun(cmdName, self.execShellCmd) ! return fun(cmdName, cmdOpts, self.CONTEXT) --- 131,136 ---- cmdOpts = '' cmdOpts = cmdOpts.strip() ! fun = self.getCmdFun(cmdName, CvsShell.execShellCmd) ! return fun(self, cmdName, cmdOpts) *************** *** 117,149 **** ! _cvsChangeCmdRE = re.compile(r"""\s+ ! (ad(d)?|new|ci|com(mit)?|delete|remove) ! \s+""", re.VERBOSE) ! def execShellCmd(self, name, opts, context): ! app = context['APP'] ! if name == 'cvs' and CvsShell._cvsChangeCmdRE.search(opts): # command may change the status ! context['basic_cmds.dirty_listing'] = 1 ! app.shell('%s %s' % (name, opts)) ! def more(self, lines=None, str=None, numlines=24): if lines is not None: ! str = string.join(lines, '') ! elif str is not None: ! lines = str.split('\n') else: raise AppError, \ ! "Illegal argument: One of lines or str must be given" if len(lines) <= numlines or not self.configMap.has_key('pager'): ! self.printMsg(str) else: pager = self.configMap['pager'] try: ! os.popen(pager, 'w').write(str) ! except IOError: pass ! except OSError, msg: ! self.printMsg(str) ! self.printErr("Error invoking pager: %s" % str(msg)) --- 139,386 ---- ! def execShellCmd(self, name, opts): ! if name == 'cvs' and self.cvsChangeCmdRE.search(opts): # command may change the status ! self.setDirtyListing(1) ! self.shell('%s %s' % (name, opts)) ! def toggle(self, oldVal, args): ! if len(args) == 0: ! return not oldVal ! else: ! if args == 'on': return 1 ! elif args == 'off': return 0 ! else: ! self.printErr("argument must be `on' or `off'") ! return oldVal ! ! ! def more(self, lines=None, s=None, numlines=22): if lines is not None: ! s = string.join(lines, '') ! elif s is not None: ! lines = s.split('\n') else: raise AppError, \ ! "Illegal argument: One of lines or s must be given" if len(lines) <= numlines or not self.configMap.has_key('pager'): ! self.printMsg(s, nonl=1) else: + import tempfile pager = self.configMap['pager'] try: ! tmp = tempfile.mktemp() ! open(tmp,'w').write(s) ! self.shell(pager + ' ' + tmp) ! except (IOError,OSError), msg: ! self.printMsg(s, nonl=1) ! self.printErr("Error invoking pager `%s': %s" % (pager,str(msg))) ! ! ! ############################## ! # CVS helper methods ! ############################## ! ! def runCvsCmd(self, cmd, rootDir=None, cvsRoot=None, globOpts = '', ! args='', fork=1, getStderr=0): ! """ ! * cmd is the command to execute ! * rootDir is the directory the command should be executed in ! * globOpts are global options. These options ! override the default global options ! * args are the arguments that should be passed to the cvs command ! """ ! oldDir = None ! if rootDir is not None: ! try: ! oldDir = self.cd(rootDir) ! except OSError,msg: ! self.printErr("Could not change to the root directory of " \ ! "the current listing: %s" % str(msg)) ! raise CvsError ! # ! defGlobOpts,defOpts = self.getOptions(cmd) ! cvsRoot = cvsRoot or self.getCvsRoot() ! if cvsRoot != None: cvsRootOpt = "-d %s" % cvsRoot ! else: cvsRootOpt = '' ! # ! globOpts = "%s %s %s" % (defGlobOpts, cvsRootOpt, globOpts) ! args = "%s %s" % (defOpts, args) ! cmd = 'cvs %s %s %s' % (globOpts, cmd, args) ! if getStderr: cmd += ' 2>&1' # FIXME: does not work on win! ! self.printVMsg(cmd) ! if fork: ! f = os.popen(cmd) ! try: ! lines = f.readlines() ! except KeyboardInterrupt: ! return [] ! if f.close() is not None: # cvs command caused an error ! raise CvsError ! else: ! return lines ! else: ! r = os.system(cmd) ! if r != 0: ! raise CvsError ! if oldDir is not None: ! try: ! self.cd(oldDir) ! except OSError,msg: ! self.printErr(msg) ! return None ! ! ! def applyOnEntryList(self, opts, fun): ! """Applies fun to the entries of the current listing selected by opts. ! opts is a string that may specify some numbers ! which refers to entries in the listing. ! fun must take 2 argument as the entry and its ! filename is passed to it. Returns a ! list with the return values from fun. ! If a error occurs, an AppError is raised. If this error is ! encountered while parsing opts, a ParseError is raised.""" ! nums = utils.parseNumberStr(opts) ! if len(nums) == 0: ! raise AppError, 'No files specified.' ! if not self.listing: ! raise AppError, self.noListingErrMsg ! result = [] ! max = len(self.listing.entries) ! for x in nums: ! if x < 0 or x > max: continue ! e = self.listing.entries[x] ! name = os.path.join(e.dir, e.name) ! result.append(fun(e,name)) ! return result ! ! ! def printListing(self): ! if not self.listing: ! self.printErr(self.noListingErrMsg) ! else: ! self.listing.printEntries() ! if self.getDirtyListing(): ! self.printMsg("Listing may be out-of-date. " \ ! "Run `update', `refresh' or `status'.") ! ! ! def parseArgs(self, args, cvsCmdOpts='', cmdOpts=''): ! """Parse args and separates it like that: ! cvsCmdOpts are the options that are allowed for the cvs command ! cmdOpts are additional options (provided by cvsshell) ! global options are handled automatically ! * global cvs options (as string) ! * command specific cvs options (as string) ! * other options (as dictionary) ! * other args (as string) ! These values are returned as a 4-tupel. ! A GetoptError is raised if there are unknown options.""" ! cvsGlobOpts = 'HQqrwlntvb:T:e:d:fz:as:' ! s = cvsGlobOpts+cvsCmdOpts+cmdOpts ! (opts, rest) = getopt.getopt(utils.splitquoted(args), s) ! cvsGlobOptstr = cvsCmdOptstr = '' ! cmdOptDict = {} ! for x in opts: ! name, value = x ! # getopt prepends '-' to every option ! if name[1] in cvsGlobOpts: ! cvsGlobOptstr += ' ' + name ! if value: cvsGlobOptstr += ' ' + value ! elif name[1] in cvsCmdOpts: ! cvsCmdOptstr += ' ' + name ! if value: cvsCmdOptstr += ' ' + value ! else: ! cmdOptDict[name] = value ! if cvsGlobOptstr: cvsGlobOptstr = cvsGlobOptstr[1:] # remove trailing ' ' ! if cvsCmdOptstr: cvsCmdOptstr = cvsCmdOptstr[1:] # remove trailing ' ' ! reststr = '' ! for x in rest: ! reststr += x + ' ' ! if reststr: reststr = reststr[:-1] ! return (cvsGlobOptstr, cvsCmdOptstr, cmdOptDict, reststr) ! ! ! def getOptions(self, cmd): ! """Returns the options that should be used for cmd. The return value ! is the tupel (globalOptions, options)""" ! defGlobOpts = self.getDefGlobOpts() ! defOpts = self.getDefOpts() ! defGlobOpts += ' ' + self.getCmdToDefGlobOpts().get(cmd,'') ! defOpts += ' ' + self.getCmdToDefOpts().get(cmd,'') ! return defGlobOpts,defOpts ! ! ! ! ############################## ! # Listing ! ############################## ! ! class Listing(GetSetProvider): ! ! def __init__(self, app, rootDir, entries=[]): ! GetSetProvider.__init__(self) ! self.app = app ! self.rootDir = rootDir ! self.entries = entries ! self.sortOrder = ['dir', 'status', 'name'] ! ! def sortEntries(self): ! class __EntrySorter: ! def __init__(self, order): self.order = order ! def cmp(self,x,y): ! try: ! i = 0 ! for attr in self.order: ! i = eval("cmp(x.%s, y.%s)" % (attr,attr)) ! if i != 0: return i ! return i ! except AttributeError: ! return -1 ! self.entries.sort(__EntrySorter(self.sortOrder).cmp) ! ! def printEntries(self, verbose=1): ! if not self.entries: ! if verbose: self.app.printMsg('No entries available.') ! return ! max = 0 ! for e in self.entries: ! l = len(e.status) ! if l > max: max = l ! formatStr = " %%%dd %%-%ds %%s\n" % (len(`len(self.entries)`), max) ! oldDir = None ! id = 0 ! lines = [] ! for e in self.entries: ! newDir = e.dir ! if oldDir != newDir: ! lines.append("%s:\n" % newDir) ! lines.append(formatStr % (id, e.status, e.name)) ! id += 1 ! oldDir = newDir ! self.app.more(lines) ! ! ############################## ! # Entry ! ############################## ! ! class Entry(GetSetProvider): ! S_NEW = 'N' ! S_ADDED = 'A' ! S_CONFLICT = 'C' ! S_MODIFIED = 'M' ! S_PATCHED = 'P' ! S_REMOVED = 'R' ! S_UPDATED = 'U' ! S_UNKNOWN = '?' ! S_OK = 'OK' # file on the sandbox is in sync with repository ! S_DELETED = 'D' # file scheduled for removal has been commited ! def __init__(self, dir, name, status): ! GetSetProvider.__init__(self) ! self.dir = dir ! self.name = name ! self.status = status ! Index: interactive_app.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/interactive_app.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** interactive_app.py 7 Mar 2002 15:09:26 -0000 1.4 --- interactive_app.py 10 Mar 2002 23:13:59 -0000 1.5 *************** *** 57,61 **** if result is self.BREAK_REPL: break elif result is None: continue ! else: self.printMsg(`result`) def readCommand(self): # subclass hooks + App.start,stop --- 57,61 ---- if result is self.BREAK_REPL: break elif result is None: continue ! else: self.printMsg(result) def readCommand(self): # subclass hooks + App.start,stop *************** *** 67,78 **** def prompt(self, msg): """Displayes msg and prompts the user for input. ! If input is EOF, None is returned.""" ! try: a = raw_input(msg) ! except EOFError, KeyboardInterrupt: self.printMsg() return None a = os.path.expandvars(a) return a.strip() --- 67,78 ---- def prompt(self, msg): """Displayes msg and prompts the user for input. ! If input is EOF, None is returned.""" try: a = raw_input(msg) ! except (EOFError, KeyboardInterrupt): self.printMsg() return None a = os.path.expandvars(a) + a = os.path.expanduser(a) return a.strip() Index: oo_tools.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/oo_tools.py,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** oo_tools.py 9 Mar 2002 17:24:46 -0000 1.1 --- oo_tools.py 10 Mar 2002 23:13:59 -0000 1.2 *************** *** 32,36 **** # # To make it thread-safe, one must lock all access-points of the variable ! # GetSetProvider.__storage. AccessError = 'AccessError' --- 32,36 ---- # # To make it thread-safe, one must lock all access-points of the variable ! # _GetSetProvider__storage. AccessError = 'AccessError' *************** *** 40,43 **** --- 40,64 ---- get/set methods for all their variables. """ + _GetSetProvider__storage = None + + class Getter: + def __init__(self, dict, attrname, classname): + self.dict = dict + self.attrname = attrname + self.classname = classname + def __call__(self): + try: + return self.dict[self.attrname] + except KeyError: + raise AttributeError, "%s instance has no attribute '%s'" % \ + (self.classname, self.attrname) + + + class Setter: + def __init__(self, dict, name): + self.dict = dict + self.name = name + def __call__(self, val): + self.dict[self.name] = val def __init__(self): *************** *** 47,58 **** def __getattr__(self, name): if len(name) > 3: ! pre, attr = name[:3], name[3].lower() + name[4:] if attr[0] == '_': self.__raiseAccessError(attr, 'private') if pre == 'get': if attr in self.__private: self.__raiseAccessError(attr, 'private') ! GetSetProvider.__storage = eval('self.' + attr) ! return lambda : GetSetProvider.__storage if pre == 'set': if attr in self.__private: --- 68,81 ---- def __getattr__(self, name): if len(name) > 3: ! pre, attr = name[:3], name[3:] if attr[0] == '_': self.__raiseAccessError(attr, 'private') + if not self.__dict__.has_key(attr): + attr = attr[0].lower() + attr[1:] if pre == 'get': if attr in self.__private: self.__raiseAccessError(attr, 'private') ! return GetSetProvider.Getter(self.__dict__, attr, ! self.__class__.__name__) if pre == 'set': if attr in self.__private: *************** *** 60,69 **** elif attr in self.__readonly: self.__raiseAccessError(attr, 'readonly') ! GetSetProvider.__storage = (self.__dict__, attr) ! def __set(val): ! dict, name = GetSetProvider.__storage ! dict[name] = val ! return __set ! raise AttributeError, "class %s has no attribute '%s'" % \ (self.__class__.__name__, name) --- 83,88 ---- elif attr in self.__readonly: self.__raiseAccessError(attr, 'readonly') ! return GetSetProvider.Setter(self.__dict__, attr) ! raise AttributeError, "%s instance has no attribute '%s'" % \ (self.__class__.__name__, name) *************** *** 113,116 **** --- 132,137 ---- self.t.setAge(23) self.assertEqual(self.t.getAge(), 23) + self.t.QName = 'foo' + self.assertEqual(self.t.getQName(), 'foo') def testAccess(self): self.assertEqual(self.t.getReadonly(), 'readonly') *************** *** 127,131 **** fail('should raise exception here.') except AccessError: pass ! unittest.main() --- 148,155 ---- fail('should raise exception here.') except AccessError: pass ! def testDelayedInvocation(self): ! fun = self.t.getStreet ! self.t.setStreet('xy') ! self.assertEqual(fun(), 'xy') unittest.main() Index: plugable_app.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/plugable_app.py,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** plugable_app.py 8 Mar 2002 22:31:01 -0000 1.4 --- plugable_app.py 10 Mar 2002 23:13:59 -0000 1.5 *************** *** 27,35 **** def __init__(self): ConfigurableApp.__init__(self) ! self.cmdOpts = {} ! self.cmdToFun = {} self.cmdToDoc = {} self.cmdToCmds = {} ! self.cmdToOpts = {} def setCommandFile(self,filename): --- 27,34 ---- def __init__(self): ConfigurableApp.__init__(self) ! self._cmdToFun = {} self.cmdToDoc = {} self.cmdToCmds = {} ! self.cmdToAllowedOpts = {} # cmd -> options possible for this cmd def setCommandFile(self,filename): *************** *** 63,72 **** l = splitRE.split(x[1]) if len(l) < 2: ! app.printErr("Syntax error in configuration file (line %d)." % n) continue value = l[-1] for y in l[:-1]: ! self.cmdToOpts[y] = value prs = sections.get('PARSERS', []) --- 62,71 ---- l = splitRE.split(x[1]) if len(l) < 2: ! self.printErr("Syntax error in configuration file (line %d)." % n) continue value = l[-1] for y in l[:-1]: ! self.cmdToAllowedOpts[y] = value prs = sections.get('PARSERS', []) *************** *** 84,88 **** def getCmdFun(self, cmdName, default=None): ! return self.cmdToFun.get(cmdName, default) def registerCmdFun(self, cmdName, fun, doc=None): --- 83,87 ---- def getCmdFun(self, cmdName, default=None): ! return self._cmdToFun.get(cmdName, default) def registerCmdFun(self, cmdName, fun, doc=None): *************** *** 95,105 **** funtion by supplying a list of names in `cmdName'. `fun' is either a function or the name of a function in the ! currrent namespace. The function must take 3 arguments: the ! 1st argument is the name of the command, the 2nd argument is ! the option-string that was passed to the command and ! the 3rd argument is the application context. To avoid ! naming-conflicts in this dictionary, all commands should ! prepend the name of the module they are defined in ! followed by `.' to the keys.""" if type(cmdName) is types.ListType: l = cmdName --- 94,101 ---- funtion by supplying a list of names in `cmdName'. `fun' is either a function or the name of a function in the ! currrent namespace. The function must take 3 arguments: ! the 1st argument is the application itself, ths ! 2nd argument is the name of the command, the 3rd argument is ! the option-string that was passed to the command""" if type(cmdName) is types.ListType: l = cmdName *************** *** 113,117 **** cmds = '' for x in l: ! self.cmdToFun[x] = fun self.cmdToDoc[x] = doc cmds += "%s, " % x --- 109,113 ---- cmds = '' for x in l: ! self._cmdToFun[x] = fun self.cmdToDoc[x] = doc cmds += "%s, " % x Index: utils.py =================================================================== RC... [truncated message content] |