[Cvsshell-devel] CVS: cvsshell/src app.py,1.13,1.14 basic_cmds.py,1.20,1.21 cvs_cmds.py,1.13,1.14 cv
Status: Beta
Brought to you by:
stefanheimann
From: Stefan H. <ste...@us...> - 2002-07-29 17:29:13
|
Update of /cvsroot/cvsshell/cvsshell/src In directory usw-pr-cvs1:/tmp/cvs-serv14130/src Modified Files: app.py basic_cmds.py cvs_cmds.py cvs_shell.py interactive_app.py parsing.py plugable_app.py utils.py Log Message: improved refresh command added unit-tests Index: app.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/app.py,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** app.py 27 May 2002 07:32:29 -0000 1.13 --- app.py 29 Jul 2002 17:29:10 -0000 1.14 *************** *** 271,279 **** 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!' ! class ShellException(GetSetProvider): --- 271,282 ---- self.printMsg(self.copyright) self.printVMsg(self.name + ' started.') ! self.postStart() ! def stop(self): ! self.preStop() self.printVMsg(self.name + ' done.') def run(self): raise AppError, 'run must be redefined!' ! def postStart(self): pass ! def preStop(self): pass class ShellException(GetSetProvider): Index: basic_cmds.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/basic_cmds.py,v retrieving revision 1.20 retrieving revision 1.21 diff -C2 -d -r1.20 -r1.21 *** basic_cmds.py 26 Jul 2002 16:35:37 -0000 1.20 --- basic_cmds.py 29 Jul 2002 17:29:10 -0000 1.21 *************** *** 20,24 **** ############################################################################### ! import os, string, re from cvs_shell import Listing, Entry --- 20,25 ---- ############################################################################### ! from __future__ import nested_scopes ! import os, string, re, utils from cvs_shell import Listing, Entry *************** *** 102,127 **** """Enable or disable automatic refresh of the local listing. If this option is set to `on', the local listing is refreshed ! after a command changed some information on the CVS server but not in the local listing.""" app.autoRefresh = app.toggle(app.autoRefresh, args) ! def scan(app, name, args): ! """Scans the local filesystem starting at the given directory and creates a listing. ! The server is not contacted, so the status of all files will be `unknown'.""" ! def visit(entries, dirname, names): if dirname.find('CVS') >= 0: return ! for name in names: if name.find('CVS') < 0: ! entries.append(Entry(dirname, name, Entry.S_UNKNOWN)) ! dir = '.' entries = [] ! if args != '': dir = args try: ! os.path.walk(dir, visit, entries) ! except OSError, msg: app.printErr(msg) ! app.setListing(Listing(app, dir, entries)) ! app.setDirtyListing(0) ! app.getListing().sortEntries() ! app.printListing() --- 103,183 ---- """Enable or disable automatic refresh of the local listing. If this option is set to `on', the local listing is refreshed ! after a command that changed some information on the CVS server but not in the local listing.""" app.autoRefresh = app.toggle(app.autoRefresh, args) ! ! def refresh(app, name, args): ! """Refresh the current listing. ! The command scans the given directory and creates a listing based on the ! information contained in the file CVS/Entries. If no directory is given, ! the current working directory is assumed. You can use the `-r' option ! to apply the command recursivly to all subdirectories. ! ! The abbreviation `rd' means `repository date', `wd' means `working date'.""" ! from time import strftime, localtime ! def visit(myEntries, dirname, names): ! namesToProcess = [x for x in names] if dirname.find('CVS') >= 0: return ! if 'CVS' in names: # directory under CVS control ! cvsEntries = utils.parseCvsEntries(dirname) ! for name, (revision, rtstamp) in cvsEntries[0].items(): ! fullname = os.path.join(dirname, name) ! if not os.path.exists(fullname): ! myEntries.append(Entry(dirname, name, Entry.S_DELETED)) ! else: ! ltstamp = os.path.getmtime(fullname) ! info = '%s (rd: %s, wd: %s)' % (revision, strftime(app.dateFormat, localtime(rtstamp)), ! strftime(app.dateFormat, localtime(ltstamp))) ! if ltstamp == rtstamp: ! myEntries.append(Entry(dirname, name, Entry.S_OK, info)) ! else: ! myEntries.append(Entry(dirname, name, Entry.S_MODIFIED, info)) ! namesToProcess.remove(name) ! for name in cvsEntries[1].keys(): ! fullname = os.path.join(dirname, name) ! if not os.path.exists(fullname): ! myEntries.append(Entry(dirname, name, Entry.S_DELETED)) ! else: ! myEntries.append(Entry(dirname, name, Entry.S_OK)) ! namesToProcess.remove(name) ! # only files not under CVS control are contained in names. ! for name in namesToProcess: if name.find('CVS') < 0: ! myEntries.append(Entry(dirname, name, Entry.S_UNKNOWN)) ! # ! args = args.split() ! recursive = 0 ! wDir = None ! for x in args: ! if x == '-r': ! if recursive: ! app.printErr('invalid arguments') ! return ! recursive = 1 ! else: ! if wDir: ! app.printErr('invalid arguments') ! return ! wDir = x entries = [] ! wDir = wDir or '.' try: ! if not os.path.exists(os.path.join(wDir, 'CVS')): ! app.printErr('directory is not under CVS control.') ! return ! oldDir = os.getcwd() ! os.chdir(wDir) ! if recursive: ! os.path.walk('.', visit, entries) ! else: ! visit(entries, '.', os.listdir('.')) ! app.setListing(Listing(app, wDir, entries)) ! app.setDirtyListing(0) ! app.getListing().sortEntries() ! app.printListing() ! os.chdir(oldDir) ! except (IOError, OSError), msg: app.printErr(msg) ! return Index: cvs_cmds.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/cvs_cmds.py,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** cvs_cmds.py 27 Jul 2002 09:05:38 -0000 1.13 --- cvs_cmds.py 29 Jul 2002 17:29:10 -0000 1.14 *************** *** 33,37 **** This command creates a listing with all checked out files and their status. The abbreviation `rr' stands for `repository revision', ! `wr' means working revision. The listing can be filtered by setting the variable --- 33,37 ---- This command creates a listing with all checked out files and their status. The abbreviation `rr' stands for `repository revision', ! `wr' means `working revision'. The listing can be filtered by setting the variable *************** *** 83,87 **** i = i+1 try: ! time = strftime('%Y-%m-%d %H:%M', gmtime(os.stat(os.path.join(os.getcwd(), dir, name))[stat.ST_MTIME])) except OSError: time = '' info = 'rr: ' + repRev + ', wr: ' + workingRev + ', ' + time --- 83,88 ---- i = i+1 try: ! time = strftime(app.dateFormat, ! gmtime(os.stat(os.path.join(os.getcwd(), dir, name))[stat.ST_MTIME])) except OSError: time = '' info = 'rr: ' + repRev + ', wr: ' + workingRev + ', ' + time Index: cvs_shell.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/cvs_shell.py,v retrieving revision 1.28 retrieving revision 1.29 diff -C2 -d -r1.28 -r1.29 *** cvs_shell.py 27 Jul 2002 09:05:38 -0000 1.28 --- cvs_shell.py 29 Jul 2002 17:29:10 -0000 1.29 *************** *** 47,50 **** --- 47,51 ---- self.setCopyright(COPYRIGHT) self.setBugAddress(BUG_ADDRESS) + self.initCommands= [] self.initOptions([('v',"Print some extra information"), ('h',"Print this help message"), *************** *** 69,73 **** \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 --- 70,74 ---- \s+""", re.VERBOSE) self.noListingErrMsg = """No listing found. ! You must run `update', `sim-update', `refresh' or `status' before using this command.""" self.cvsRoot = None self.cvsRootAutoUpdate = 0 *************** *** 87,91 **** self.listingFilter = utils.splitquoted(self.configMap.get('filter','')) self.enableColor = self.configMap.get('colors', 'off') == 'on' ! def readCvsRootFromFile(self): --- 88,98 ---- self.listingFilter = utils.splitquoted(self.configMap.get('filter','')) self.enableColor = self.configMap.get('colors', 'off') == 'on' ! self.batchMode = 0 ! self.completeableCommands = self.getAvailableCommands() ! self.dateFormat = '%Y-%m-%d %H:%M' ! ! def postStart(self): ! for cmd in self.initCommands: ! self.evalCommand(cmd) def readCvsRootFromFile(self): *************** *** 221,225 **** 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: --- 228,232 ---- raise AppError, \ "Illegal argument: One of lines or s must be given" ! if len(lines) <= numlines or not self.configMap.has_key('pager') or self.batchMode: self.printMsg(s, nonl=1) else: *************** *** 382,385 **** --- 389,393 ---- ############################## + class Listing(GetSetProvider): *************** *** 412,416 **** i = eval("cmp(x.%s, y.%s)" % (attr,attr)) if i != 0: return i ! return i except AttributeError: return -1 --- 420,424 ---- i = eval("cmp(x.%s, y.%s)" % (attr,attr)) if i != 0: return i ! return i except AttributeError: return -1 Index: interactive_app.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/interactive_app.py,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -d -r1.12 -r1.13 *** interactive_app.py 27 Jul 2002 14:55:08 -0000 1.12 --- interactive_app.py 29 Jul 2002 17:29:10 -0000 1.13 *************** *** 29,32 **** --- 29,33 ---- self.BREAK_REPL = 'BREAK_REPL' self.DEF_PATTERN = '%%def%%' + self.completeableCommands = [] try: import readline *************** *** 36,40 **** else: readline.parse_and_bind("tab: complete") ! readline.set_completer_delims(' \t\n`~!@#$%^&*()-=+[{]}\\|;:\'",<>?') def setHistoryFile(self,filename): --- 37,42 ---- else: readline.parse_and_bind("tab: complete") ! readline.set_completer_delims(' \t\n`~!@$%^&*()=+[{]}\\|;:\'",<>?') ! readline.set_completer(self.complete) def setHistoryFile(self,filename): *************** *** 97,100 **** --- 99,142 ---- else: return a + # taken from http://mail.python.org/pipermail/python-list/2002-July/114824.html + def completenames(self, text, line, begidx, endidx): + l = [x for x in self.completeableCommands if x.startswith(text)] + path = os.environ['PATH'].split(':') + textlen = len(text) + for dir in path: + try: + files = os.listdir(dir) + except: + continue + for file in files: + if textlen > 0 and file[:textlen] != text: + continue + if os.access(dir+'/'+file, os.X_OK): + l += [file] + return l + + # taken from the cmd class (this method was introduced in python 2.2) + def complete(self, text, state): + """Return the next possible completion for 'text'. + + If a command has not been entered, then complete against command list. + Otherwise try to call complete_<command> to get list of completions. + """ + if state == 0: + import readline + origline = readline.get_line_buffer() + line = origline.lstrip() + stripped = len(origline) - len(line) + begidx = readline.get_begidx() - stripped + endidx = readline.get_endidx() - stripped + if begidx>0: + self.completion_matches = [] + else: + self.completion_matches = self.completenames(text, line, begidx, endidx) + try: + return self.completion_matches[state] + except IndexError: + return None + def evalCommand(self, command): """Subclasses should override this method. Index: parsing.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/parsing.py,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** parsing.py 15 Mar 2002 10:37:53 -0000 1.3 --- parsing.py 29 Jul 2002 17:29:10 -0000 1.4 *************** *** 41,45 **** for x in lines: cmd = x[1] ! app.evalCommand(cmd) --- 41,45 ---- for x in lines: cmd = x[1] ! app.initCommands.append(cmd) Index: plugable_app.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/plugable_app.py,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** plugable_app.py 15 Mar 2002 00:47:08 -0000 1.6 --- plugable_app.py 29 Jul 2002 17:29:10 -0000 1.7 *************** *** 117,120 **** --- 117,123 ---- self.printVMsg("registered command %s" % cmdName) + def getAvailableCommands(self): + """Returns a list of all command names that are currently registered""" + return self._cmdToFun.keys() Index: utils.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/utils.py,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** utils.py 26 Jul 2002 16:35:37 -0000 1.11 --- utils.py 29 Jul 2002 17:29:10 -0000 1.12 *************** *** 20,24 **** ############################################################################### ! import re from app import AppError --- 20,24 ---- ############################################################################### ! import sys, re, os, stat from app import AppError *************** *** 82,85 **** --- 82,114 ---- return result + lineRe = re.compile(r'(?P<isdir>D?)/(?P<name>[^/]*)/(?P<revision>[^/]*)/(?P<mtime>[^/]*)//') + + def parseCvsEntries(dir): + """Parses the CVS/Entries file contained in dir. + Returns a 2-tuple of dictionaries: + The first dict maps filenames to a 2-tuple containing the local revision number + as a string and the timestamp of this revision + The 2nd dict is a set (i.e. the values are None) and contains the directories. + Errors are propagated to the caller. + """ + from time import strptime + from calendar import timegm + p = os.path + filename = p.join(dir, 'CVS', 'Entries') + f = open(filename) + dirs = {} + files = {} + for line in f.readlines(): + result = lineRe.match(line) + if not result: continue + name = result.group('name') + if result.group('isdir'): + dirs[name] = None + else: + revision = result.group('revision') + repTime = timegm(strptime(result.group('mtime'))) + files[name] = (revision, repTime) + return files, dirs + doubleQ = r'"(?:[^"\\]+|\\.)*"' |