[Cvsshell-devel] CVS: cvsshell/src app.py,1.10,1.11 basic_cmds.py,1.16,1.17 cvs_shell.py,1.19,1.20 p
Status: Beta
Brought to you by:
stefanheimann
From: Stefan H. <ste...@us...> - 2002-03-15 10:37:56
|
Update of /cvsroot/cvsshell/cvsshell/src In directory usw-pr-cvs1:/tmp/cvs-serv2767 Modified Files: app.py basic_cmds.py cvs_shell.py parsing.py Log Message: Added color support for listing. Index: app.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/app.py,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** app.py 15 Mar 2002 00:47:08 -0000 1.10 --- app.py 15 Mar 2002 10:37:53 -0000 1.11 *************** *** 1,268 **** ! ############################################################################### ! # This file is part of CvsShell ! # ! # CvsShell is free software; you can redistribute it and/or modify ! # it under the terms of the GNU General Public License as published by ! # the Free Software Foundation; either version 2 of the License, or ! # (at your option) any later version. ! # ! # CvsShell is distributed in the hope that it will be useful, ! # but WITHOUT ANY WARRANTY; without even the implied warranty of ! # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! # GNU General Public License for more details. ! # ! # You should have received a copy of the GNU General Public License ! # along with CvsShell; if not, write to the Free Software ! # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! # ! # Copyright 2002 by Stefan Heimann ! # Website: http://cvsshell.sourceforge.net/ ! ############################################################################### ! ! import sys, os, traceback, getopt, types ! 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.onWindows = sys.platform[:3] == 'win' ! self.THIS_DIR = _thisdir ! try: ! self.HOME = os.environ['HOME'] ! except KeyError: ! if self.onWindows: ! self.HOME = 'c:\\' ! else: ! self.printErr('$HOME is not set.') ! self.HOME = os.getcwd() ! self.name = self.__class__.__name__ ! self.version = '0.1' ! self.copyright = None ! self.bugAddress = None ! self.enableColor = 0 ! try: ! self.path = os.environ['PATH'].split(os.pathsep) ! except KeyError: ! self.path = [] ! 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.""" ! 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 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): ! 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): ! 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') ! ! colDict = { ! "black" : "30m", ! "red" : "31m", ! "green" : "32m", ! "brown" : "33m", ! "blue" : "34m", ! "purple" : "35m", ! "cyan" : "36m", ! "lgray" : "37m", ! "gray" : "1;30m", ! "lred" : "1;31m", ! "lgreen" : "1;32m", ! "yellow" : "1;33m", ! "lblue" : "1;34m", ! "pink" : "1;35m", ! "lcyan" : "1;36m", ! "white" : "1;37m", ! } ! def col(self, color, text): ! """Return colorized text; color can either be a string indicating a color ! or a tuple containing two strings - for color and background. ! Copyright (C) 2001 Andrei Kulakov <ak...@si...> GPL""" ! if not self.enableColor: return text ! bg = "0m" ! if type(color) is types.StringType: ! fg = App.colDict[color] ! else: ! f, b = color ! fg = App.colDict[f] ! bg = App.colDict[b] ! s = "\033[" ! clear = "0m" ! return "%s%s%s%s%s%s%s" % (s, bg, s, fg, text, s, clear) ! ! ! 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() ! return None ! ! 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.printErr('========== Traceback starts here ==========') ! self.printErr('uncaught: ' + `(sys.exc_type,sys.exc_value)`) ! traceback.print_exc() ! self.printErr(""" ! Program Version: %s ! Platform: %s ! Python version: %s""" % (self.version, sys.platform, sys.version)) ! self.printErr("========== Traceback ends here ==========\n" \ ! "You have discovered a bug in %s." % self.name) ! if self.bugAddress.find('@') > 0: ! self.printErr("Please send a bug report to \n %s," ! % self.bugAddress) ! else: ! self.printErr("Please fill out a bug report at \n %s," ! % self.bugAddress) ! self.printErr("including the traceback above.") ! 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!' ! --- 1,275 ---- ! ############################################################################### ! # This file is part of CvsShell ! # ! # CvsShell is free software; you can redistribute it and/or modify ! # it under the terms of the GNU General Public License as published by ! # the Free Software Foundation; either version 2 of the License, or ! # (at your option) any later version. ! # ! # CvsShell is distributed in the hope that it will be useful, ! # but WITHOUT ANY WARRANTY; without even the implied warranty of ! # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! # GNU General Public License for more details. ! # ! # You should have received a copy of the GNU General Public License ! # along with CvsShell; if not, write to the Free Software ! # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! # ! # Copyright 2002 by Stefan Heimann ! # Website: http://cvsshell.sourceforge.net/ ! ############################################################################### ! ! import sys, os, traceback, getopt, types ! 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.onWindows = sys.platform[:3] == 'win' ! self.THIS_DIR = _thisdir ! try: ! self.HOME = os.environ['HOME'] ! except KeyError: ! if self.onWindows: ! self.HOME = 'c:\\' ! else: ! self.printErr('$HOME is not set.') ! self.HOME = os.getcwd() ! self.name = self.__class__.__name__ ! self.version = '0.1' ! self.copyright = None ! self.bugAddress = None ! self.enableColor = 0 ! try: ! self.path = os.environ['PATH'].split(os.pathsep) ! except KeyError: ! self.path = [] ! 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.""" ! 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 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): ! 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): ! 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') ! ! colDict = { ! "black" : "30m", ! "red" : "31m", ! "green" : "32m", ! "brown" : "33m", ! "blue" : "34m", ! "purple" : "35m", ! "cyan" : "36m", ! "lgray" : "37m", ! "gray" : "1;30m", ! "lred" : "1;31m", ! "lgreen" : "1;32m", ! "yellow" : "1;33m", ! "lblue" : "1;34m", ! "pink" : "1;35m", ! "lcyan" : "1;36m", ! "white" : "1;37m", ! } ! def col(self, color, text): ! """Return colorized text; color can either be a string indicating a color ! or a string indicating two colors separated by whitespace or a tuple ! containing two colors. If two colors are given, the first is used as foreground ! the second as background. ! Copyright (C) 2001 Andrei Kulakov <ak...@si...> GPL""" ! if not self.enableColor or not color: return text ! bg = "0m" ! if type(color) is types.StringType: ! s = color.split() ! if len(s) < 2: ! fg = App.colDict[color] ! else: ! fg = App.colDict[s[0]] ! bg = App.colDict[s[1]] ! else: ! f, b = color ! fg = App.colDict[f] ! bg = App.colDict[b] ! s = "\033[" ! clear = "0m" ! return "%s%s%s%s%s%s%s" % (s, bg, s, fg, text, s, clear) ! ! ! 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() ! return None ! ! 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.printErr('========== Traceback starts here ==========') ! self.printErr('uncaught: ' + `(sys.exc_type,sys.exc_value)`) ! traceback.print_exc() ! self.printErr(""" ! Program Version: %s ! Platform: %s ! Python version: %s""" % (self.version, sys.platform, sys.version)) ! self.printErr("========== Traceback ends here ==========\n" \ ! "You have discovered a bug in %s." % self.name) ! if self.bugAddress.find('@') > 0: ! self.printErr("Please send a bug report to \n %s," ! % self.bugAddress) ! else: ! self.printErr("Please fill out a bug report at \n %s," ! % self.bugAddress) ! self.printErr("including the traceback above.") ! 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.16 retrieving revision 1.17 diff -C2 -d -r1.16 -r1.17 *** basic_cmds.py 15 Mar 2002 00:47:08 -0000 1.16 --- basic_cmds.py 15 Mar 2002 10:37:53 -0000 1.17 *************** *** 79,85 **** if root: app.setCvsRoot(root) ! def toggleFullStatusLine(app, name, args): ! """Toggle between full and abbreviated status line.""" ! app.showFullPrompt = app.toggle(app.showFullPrompt, args) --- 79,85 ---- if root: app.setCvsRoot(root) ! def toggleFullInfoLine(app, name, args): ! """Toggle between full and abbreviated info line.""" ! app.showFullPrompt = app.toggle(app.showFullInfo, args) Index: cvs_shell.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/cvs_shell.py,v retrieving revision 1.19 retrieving revision 1.20 diff -C2 -d -r1.19 -r1.20 *** cvs_shell.py 15 Mar 2002 09:43:51 -0000 1.19 --- cvs_shell.py 15 Mar 2002 10:37:53 -0000 1.20 *************** *** 1,416 **** ! ############################################################################### ! # This file is part of CvsShell ! # ! # CvsShell is free software; you can redistribute it and/or modify ! # it under the terms of the GNU General Public License as published by ! # the Free Software Foundation; either version 2 of the License, or ! # (at your option) any later version. ! # ! # CvsShell is distributed in the hope that it will be useful, ! # but WITHOUT ANY WARRANTY; without even the implied warranty of ! # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! # GNU General Public License for more details. ! # ! # You should have received a copy of the GNU General Public License ! # along with CvsShell; if not, write to the Free Software ! # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! # ! # Copyright 2002 by Stefan Heimann ! # Website: http://cvsshell.sourceforge.net/ ! ############################################################################### ! ! import os, sys, re, string, types, getopt, fnmatch, 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) ! self.initOptions([('v',"Print some extra information"), ! ('h',"Print this help message"), ! ('u',"Delete ~/.cvsshellrc and replace it with the default configuration file")]) ! etcDir = os.path.join(self.THIS_DIR, '..', 'etc') ! self.setConfigFile(os.path.join(self.HOME,'.cvsshellrc'), ! os.path.join(etcDir, 'default-cvsshellrc'), forceDefault=self.getopt('-u')) ! self.setCommandFile(os.path.join(etcDir, 'cvsshell.ini')) ! self.setHistoryFile(os.path.join(self.HOME,'.cvsshell_history')) ! self.CVS_ROOT_FILE = os.path.join('CVS', 'Root') ! 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 ! ( ! \s+ # delimits name and options ! (?P<opts>.*) # the options of the command ! )? # 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.aliasesMap = {} ! self.cmdToDefOpts = {} ! self.cmdToDefGlobOpts = {} ! self.defOpts = '' # options for all commands ! self.defGlobOpts = '' # global options for all commands ! self.readCommandFile() ! self.readConfigFile() ! self.listingFilter = utils.splitquoted(self.configMap.get('filter','')) ! self.enableColor = self.configMap.get('colors', 'off') == 'on' ! ! ! def readCvsRootFromFile(self): ! s = None ! if os.access(self.CVS_ROOT_FILE, os.R_OK): ! s = open(self.CVS_ROOT_FILE, 'r').readline().strip() ! return s ! ! ! def getPrompt(self): ! status = '' ! if self.cvsRootAutoUpdate: status += 'a' ! 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 the prompt match on one line ! extraChars = 6 ! maxLineWidth = 79 ! minLen = 15 ! ls = len(status) ! ld = len(dir) ! lr = len(root) ! width = ls + extraChars + ld + lr ! if width > maxLineWidth: ! w = max(minLen, (lr - (width - maxLineWidth + 3)) / 2) ! if lr > 2*w: root = root[:w] + '...' + root[-w:] ! lr = len(root) ! width = ls + extraChars + ld + lr ! if width > maxLineWidth: ! w = max(minLen, ld - (width - maxLineWidth + 3)) ! if ld > w: dir = '...' + dir[-w:] ! ld = len(dir) ! return self.col('cyan', "{%s} %s [%s]" % (status, ! dir, ! root)) + '\n$ ' ! ! ! def evalCommand(self, cmd): ! result = self.cmdRegex.match(cmd) ! if result is None: ! return None ! cmdName = result.group('name') ! cmdName = self.aliasesMap.get(cmdName, cmdName) ! cmdOpts = result.group('opts') ! if cmdOpts == None: ! cmdOpts = '' ! cmdOpts = cmdOpts.strip() ! fun = self.getCmdFun(cmdName, CvsShell.execShellCmd) ! return fun(self, cmdName, cmdOpts) ! ! ! def run(self): # FIXME: why must I redefine run here? ! InteractiveApp.run(self) ! ! ! 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) ! # on windows, cvs seems to output all information on stdout ! if getStderr and not self.onWindows: cmd += ' 2>&1' ! 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.sortOrder = ['dir', 'status', 'name'] ! filter = app.getListingFilter() ! if not filter: ! self.entries = entries ! else: ! self.entries = [] ! for e in entries: ! dontInclude = 0 ! for f in filter: ! if fnmatch.fnmatch(e.getName(), f): ! dontInclude = 1 ! break ! if not dontInclude: ! self.entries.append(e) ! ! 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%%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) ! if os.path.isdir(os.path.join(self.rootDir, e.dir, e.name)): ! isDir = "<dir> " ! else: ! isDir = '' ! lines.append(formatStr % (id, e.status, isDir, 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 ! ! ! def main(): ! app = CvsShell() ! res = app.main() ! app.exit(res) ! ! if __name__ == '__main__': ! main() --- 1,430 ---- ! ############################################################################### ! # This file is part of CvsShell ! # ! # CvsShell is free software; you can redistribute it and/or modify ! # it under the terms of the GNU General Public License as published by ! # the Free Software Foundation; either version 2 of the License, or ! # (at your option) any later version. ! # ! # CvsShell is distributed in the hope that it will be useful, ! # but WITHOUT ANY WARRANTY; without even the implied warranty of ! # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! # GNU General Public License for more details. ! # ! # You should have received a copy of the GNU General Public License ! # along with CvsShell; if not, write to the Free Software ! # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ! # ! # Copyright 2002 by Stefan Heimann ! # Website: http://cvsshell.sourceforge.net/ ! ############################################################################### ! ! import os, sys, re, string, types, getopt, fnmatch, 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) ! self.initOptions([('v',"Print some extra information"), ! ('h',"Print this help message"), ! ('u',"Delete ~/.cvsshellrc and replace it with the default configuration file")]) ! etcDir = os.path.join(self.THIS_DIR, '..', 'etc') ! self.setConfigFile(os.path.join(self.HOME,'.cvsshellrc'), ! os.path.join(etcDir, 'default-cvsshellrc'), forceDefault=self.getopt('-u')) ! self.setCommandFile(os.path.join(etcDir, 'cvsshell.ini')) ! self.setHistoryFile(os.path.join(self.HOME,'.cvsshell_history')) ! self.CVS_ROOT_FILE = os.path.join('CVS', 'Root') ! 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 ! ( ! \s+ # delimits name and options ! (?P<opts>.*) # the options of the command ! )? # 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.showFullInfo = 0 ! self.listing = None ! self.dirtyListing = 1 ! self.cvsRootAliases = {} ! self.configMap = {} ! self.aliasesMap = {} ! self.cmdToDefOpts = {} ! self.cmdToDefGlobOpts = {} ! self.defOpts = '' # options for all commands ! self.defGlobOpts = '' # global options for all commands ! self.readCommandFile() ! self.readConfigFile() ! self.listingFilter = utils.splitquoted(self.configMap.get('filter','')) ! self.enableColor = self.configMap.get('colors', 'off') == 'on' ! ! ! def readCvsRootFromFile(self): ! s = None ! if os.access(self.CVS_ROOT_FILE, os.R_OK): ! s = open(self.CVS_ROOT_FILE, 'r').readline().strip() ! return s ! ! ! def getPrompt(self): ! status = '' ! if self.cvsRootAutoUpdate: status += 'a' ! 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.showFullInfo: ! # make the prompt match on one line ! extraChars = 6 ! maxLineWidth = 79 ! minLen = 15 ! ls = len(status) ! ld = len(dir) ! lr = len(root) ! width = ls + extraChars + ld + lr ! if width > maxLineWidth: ! w = max(minLen, (lr - (width - maxLineWidth + 3)) / 2) ! if lr > 2*w: root = root[:w] + '...' + root[-w:] ! lr = len(root) ! width = ls + extraChars + ld + lr ! if width > maxLineWidth: ! w = max(minLen, ld - (width - maxLineWidth + 3)) ! if ld > w: dir = '...' + dir[-w:] ! ld = len(dir) ! return self.col('cyan', "{%s} %s [%s]" % (status, ! dir, ! root)) + '\n$ ' ! ! ! def evalCommand(self, cmd): ! result = self.cmdRegex.match(cmd) ! if result is None: ! return None ! cmdName = result.group('name') ! cmdName = self.aliasesMap.get(cmdName, cmdName) ! cmdOpts = result.group('opts') ! if cmdOpts == None: ! cmdOpts = '' ! cmdOpts = cmdOpts.strip() ! fun = self.getCmdFun(cmdName, CvsShell.execShellCmd) ! return fun(self, cmdName, cmdOpts) ! ! ! def run(self): # FIXME: why must I redefine run here? ! InteractiveApp.run(self) ! ! ! 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) ! # on windows, cvs seems to output all information on stdout ! if getStderr and not self.onWindows: cmd += ' 2>&1' ! 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.sortOrder = ['dir', 'status', 'name'] ! filter = app.getListingFilter() ! if not filter: ! self.entries = entries ! else: ! self.entries = [] ! for e in entries: ! dontInclude = 0 ! for f in filter: ! if fnmatch.fnmatch(e.getName(), f): ! dontInclude = 1 ! break ! if not dontInclude: ! self.entries.append(e) ! ! 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%%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) ! if os.path.isdir(os.path.join(self.rootDir, e.dir, e.name)): ! isDir = "<dir> " ! else: ! isDir = '' ! colorKey = e.getStatusAsColorKey() ! print "colorKey = ", colorKey ! color = self.app.getConfigMap().get(colorKey, '') ! print "color = ", color ! s = self.app.col(color, formatStr % (id, e.status, isDir, e.name)) ! lines.append(s) ! 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 ! statusToColorKey = None ! def __init__(self, dir, name, status): ! GetSetProvider.__init__(self) ! self.dir = dir ! self.name = name ! self.status = status ! if Entry.statusToColorKey is None: ! Entry.statusToColorKey = {} ! for x in Entry.__dict__.items(): ! key, value = x ! if key[:2] == 'S_': ! Entry.statusToColorKey[value] = 'color-' + key[2:].lower() ! ! def getStatusAsColorKey(self): ! return Entry.statusToColorKey.get(self.status, None) ! ! def main(): ! app = CvsShell() ! res = app.main() ! app.exit(res) ! ! if __name__ == '__main__': ! main() Index: parsing.py =================================================================== RCS file: /cvsroot/cvsshell/cvsshell/src/parsing.py,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** parsing.py 15 Mar 2002 09:43:51 -0000 1.2 --- parsing.py 15 Mar 2002 10:37:53 -0000 1.3 *************** *** 88,92 **** n = x[0] l = app.keyValSplitRE.split(x[1], 1) - print l if len(l) != 2: app.printErr("Syntax error in configuration file (line %d)." % n) --- 88,91 ---- |