Changeset 216
- Timestamp:
- 01-05-07 10:53:10 (6 years ago)
- Location:
- trunk
- Files:
-
- 3 added
- 3 edited
- 1 copied
-
ChangeLog (modified) (1 diff)
-
moap/extern/Makefile.am (modified) (1 diff)
-
moap/extern/command (added)
-
moap/extern/command/__init__.py (added)
-
moap/extern/command/command.py (copied) (copied from trunk/moap/util/command.py) (1 diff)
-
moap/extern/command/test_command.py (added)
-
moap/util/command.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/ChangeLog
r215 r216 1 2007-05-01 Thomas Vander Stichele <thomas at apestaart dot org> 2 3 * moap/extern/Makefile.am: 4 * moap/extern/command/__init__.py: 5 * moap/extern/command/command.py: 6 * moap/extern/command/test_command.py: 7 * moap/util/command.py: 8 Move the command module into its own extern dir so other projects 9 can svn:externals include it. 10 1 11 2007-04-29 Thomas Vander Stichele <thomas at apestaart dot org> 2 12 -
trunk/moap/extern/Makefile.am
r202 r216 9 9 log/__init__.py \ 10 10 log/log.py 11 12 commanddir = $(PYTHONLIBDIR)/moap/extern/command 13 14 command_PYTHON = \ 15 command/__init__.py \ 16 command/command.py 17 18 EXTRA_DIST = log/test_log.py command/test_command.py -
trunk/moap/extern/command/command.py
r209 r216 1 # -*- Mode: Python; test-case-name: test suite.test_util_command -*-1 # -*- Mode: Python; test-case-name: test_command -*- 2 2 # vi:si:et:sw=4:sts=4:ts=4 3 4 # This file is released under the standard PSF license. 3 5 4 6 """ -
trunk/moap/util/command.py
r209 r216 6 6 """ 7 7 8 import optparse 9 import sys 10 11 class CommandHelpFormatter(optparse.IndentedHelpFormatter): 12 """ 13 I format the description as usual, but add an overview of commands 14 after it if there are any, formatted like the options. 15 """ 16 _commands = None 17 18 def addCommand(self, name, description): 19 if self._commands is None: 20 self._commands = {} 21 self._commands[name] = description 22 23 ### override parent method 24 def format_description(self, description): 25 # textwrap doesn't allow for a way to preserve double newlines 26 # to separate paragraphs, so we do it here. 27 blocks = description.split('\n\n') 28 rets = [] 29 30 for block in blocks: 31 rets.append(optparse.IndentedHelpFormatter.format_description(self, 32 block)) 33 ret = "\n".join(rets) 34 if self._commands: 35 commandDesc = [] 36 commandDesc.append("commands:") 37 keys = self._commands.keys() 38 keys.sort() 39 length = 0 40 for key in keys: 41 if len(key) > length: 42 length = len(key) 43 for name in keys: 44 format = " %-" + "%d" % length + "s %s" 45 commandDesc.append(format % (name, self._commands[name])) 46 ret += "\n" + "\n".join(commandDesc) + "\n" 47 return ret 48 49 class CommandOptionParser(optparse.OptionParser): 50 """ 51 I parse options as usual, but I explicitly allow setting stdout 52 so that our print_help() method (invoked by default with -h/--help) 53 defaults to writing there. 54 """ 55 _stdout = sys.stdout 56 57 def set_stdout(self, stdout): 58 self._stdout = stdout 59 60 # we're overriding the built-in file, but we need to since this is 61 # the signature from the base class 62 __pychecker__ = 'no-shadowbuiltin' 63 def print_help(self, file=None): 64 # we are overriding a parent method so we can't do anything about file 65 __pychecker__ = 'no-shadowbuiltin' 66 if file is None: 67 file = self._stdout 68 file.write(self.format_help()) 69 70 class Command: 71 """ 72 I am a class that handles a command for a program. 73 Commands can be nested underneath a command for further processing. 74 75 @cvar name: name of the command, lowercase 76 @cvar aliases: list of alternative lowercase names recognized 77 @type aliases: list of str 78 @cvar usage: short one-line usage string; 79 %command gets expanded to a sub-command or [commands] 80 as appropriate 81 @cvar summary: short one-line summary of the command 82 @cvar description: longer paragraph explaining the command 83 @cvar subCommands: dict of name -> commands below this command 84 @type subCommands: dict of str -> L{Command} 85 """ 86 name = None 87 aliases = None 88 usage = None 89 summary = None 90 description = None 91 parentCommand = None 92 subCommands = None 93 subCommandClasses = None 94 aliasedSubCommands = None 95 96 def __init__(self, parentCommand=None, stdout=sys.stdout, 97 stderr=sys.stderr): 98 """ 99 Create a new command instance, with the given parent. 100 Allows for redirecting stdout and stderr if needed. 101 This redirection will be passed on to child commands. 102 """ 103 if not self.name: 104 self.name = str(self.__class__).split('.')[-1].lower() 105 self.stdout = stdout 106 self.stderr = stderr 107 self.parentCommand = parentCommand 108 109 # create subcommands if we have them 110 self.subCommands = {} 111 self.aliasedSubCommands = {} 112 if self.subCommandClasses: 113 for C in self.subCommandClasses: 114 c = C(self, stdout=stdout, stderr=stderr) 115 self.subCommands[c.name] = c 116 if c.aliases: 117 for alias in c.aliases: 118 self.aliasedSubCommands[alias] = c 119 120 # create our formatter and add subcommands if we have them 121 formatter = CommandHelpFormatter() 122 if self.subCommands: 123 for name, command in self.subCommands.items(): 124 formatter.addCommand(name, command.summary or 125 command.description) 126 127 # expand %command for the bottom usage 128 usage = self.usage or self.name 129 if usage.find("%command") > -1: 130 usage = usage.split("%command")[0] + '[command]' 131 usages = [usage, ] 132 133 # walk the tree up for our usage 134 c = self.parentCommand 135 while c: 136 usage = c.usage or c.name 137 if usage.find(" %command") > -1: 138 usage = usage.split(" %command")[0] 139 usages.append(usage) 140 c = c.parentCommand 141 usages.reverse() 142 usage = " ".join(usages) 143 144 # create our parser 145 description = self.description or self.summary 146 self.parser = CommandOptionParser( 147 usage=usage, description=description, 148 formatter=formatter) 149 self.parser.set_stdout(self.stdout) 150 self.parser.disable_interspersed_args() 151 152 # allow subclasses to add options 153 self.addOptions() 154 155 def addOptions(self): 156 """ 157 Override me to add options to the parser. 158 """ 159 pass 160 161 def do(self, args): 162 """ 163 Override me to implement the functionality of the command. 164 """ 165 pass 166 167 def parse(self, argv): 168 """ 169 Parse the given arguments and act on them. 170 """ 171 options, args = self.parser.parse_args(argv) 172 173 ret = self.handleOptions(options) 174 if ret: 175 return ret 176 177 # if we don't have subcommands, defer to our do() method 178 if not self.subCommands: 179 return self.do(args) 180 181 # if we do have subcommands, defer to them 182 try: 183 command = args[0] 184 except IndexError: 185 self.parser.print_usage(file=self.stderr) 186 self.stderr.write( 187 "Use --help to get a list of commands.\n") 188 return 1 189 190 if command in self.subCommands.keys(): 191 return self.subCommands[command].parse(args[1:]) 192 193 if self.aliasedSubCommands: 194 if command in self.aliasedSubCommands.keys(): 195 return self.aliasedSubCommands[command].parse(args[1:]) 196 197 self.stderr.write("Unknown command '%s'.\n" % command) 198 return 1 199 200 def outputUsage(self): 201 """ 202 Output usage information. 203 Used when the options or arguments were missing or wrong. 204 """ 205 self.parser.print_usage(file=self.stderr) 206 207 def handleOptions(self, options): 208 """ 209 Handle the parsed options. 210 """ 211 pass 212 213 def getRootCommand(self): 214 """ 215 Return the top-level command, which is typically the program. 216 """ 217 c = self 218 while c.parentCommand: 219 c = c.parentCommand 220 return c 8 # FIXME: remove this compat import 9 from moap.extern.command.command import *
Note: See TracChangeset
for help on using the changeset viewer.
