Changeset 216


Ignore:
Timestamp:
01-05-07 10:53:10 (6 years ago)
Author:
thomas
Message:
  • moap/extern/Makefile.am:
  • moap/extern/command/init.py:
  • moap/extern/command/command.py:
  • moap/extern/command/test_command.py:
  • moap/util/command.py: Move the command module into its own extern dir so other projects can svn:externals include it.
Location:
trunk
Files:
3 added
3 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/ChangeLog

    r215 r216  
     12007-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 
    1112007-04-29  Thomas Vander Stichele  <thomas at apestaart dot org> 
    212 
  • trunk/moap/extern/Makefile.am

    r202 r216  
    99        log/__init__.py \ 
    1010        log/log.py 
     11 
     12commanddir = $(PYTHONLIBDIR)/moap/extern/command 
     13 
     14command_PYTHON = \ 
     15        command/__init__.py \ 
     16        command/command.py 
     17 
     18EXTRA_DIST = log/test_log.py command/test_command.py 
  • trunk/moap/extern/command/command.py

    r209 r216  
    1 # -*- Mode: Python; test-case-name: testsuite.test_util_command -*- 
     1# -*- Mode: Python; test-case-name: test_command -*- 
    22# vi:si:et:sw=4:sts=4:ts=4 
     3 
     4# This file is released under the standard PSF license. 
    35 
    46""" 
  • trunk/moap/util/command.py

    r209 r216  
    66""" 
    77 
    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 
     9from moap.extern.command.command import * 
Note: See TracChangeset for help on using the changeset viewer.