Viewing file: Command.py (9.61 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
######################################################################## # $Header: /var/local/cvsroot/4Suite/Ft/Lib/CommandLine/Command.py,v 1.13 2004/08/06 04:57:08 mbrown Exp $ """ Superclass for a command that can be invoked by a command-line script.
Copyright 2004 Fourthought, Inc. (USA). Detailed license and copyright information: http://4suite.org/COPYRIGHT Project home, documentation, distributions: http://4suite.org/ """
import string, sys
import Options import Arguments import CommandLineUtil import FancyGetOpt
from Ft.Lib.CommandLine import CONSOLE_WIDTH
class Command: """ Superclass for a command that can be invoked by a command-line script. Most commands won't need to subclass this.
A Command object encapsulates, for a particular command, a description, usage example, a set of valid options & arguments, methods for validating the actual options and arguments entered, a function for command invocation, and an association with subordinate Commands.
A tree of commands can be created by associating each Command instance with its subordinates. Typically, only the leaves of the tree will have functionality; the branches just provide ways of grouping the leaves and will not need to encapsulate the invocation functions themselves. """ # -- clear as mud. how about some examples def __init__(self, name, description, example, verbose_description, function = None, options=None, arguments = None, subCommands = None, authenticate = 0, heading = None, fileName = None, ):
self.name = name self.description = description self.function = function self.example = example self.verbose_description = verbose_description self.options = options or Options.Options() self.arguments = arguments or [] self.subCommands = subCommands or {} self.authenticate = authenticate self.heading = heading self._fileName = fileName
if type(self.subCommands) == type([]): cmds = {} for c in self.subCommands: cmds[c.name] = c self.subCommands = cmds
#Validate Options if not isinstance(self.options,Options.Options): raise Exception("Options not an instance of Options.Options")
for a in self.arguments: if not isinstance(a,Arguments.Argument): raise Exception("Argument is not an Argument: %s" % str(a))
def build_parent_relationship(self): for c in self.subCommands.values(): c.parent = self c.build_parent_relationship()
def break_parent_relationship(self): for c in self.subCommands.values(): if hasattr(c,'parent'): delattr(c,'parent') c.break_parent_relationship()
def flatten_command_tree(self,level,previousName=''): if previousName: fName = previousName + '.' + self.name else: fName = self.name
res = [(level,self,fName)] names = self.subCommands.keys() names.sort() for name in names: res.extend(self.subCommands[name].flatten_command_tree( level+1,previousName = fName)) return res
def run_command(self,auth): if self.authenticate: self.clOptions['AUTHENTICATION'] = auth( options=self.clOptions, level=self.authenticate) if self.heading: sys.stderr.write(self.heading) self.function(self.clOptions, self.clArguments) return
def validate_arguments(self,args): eatenArgs = {} uneatenArgs = filter(string.strip, args) for arg in self.arguments: eaten,uneatenArgs = arg.validate(self,uneatenArgs) if eaten is not None: eatenArgs[arg.name] = eaten
if len(uneatenArgs): raise CommandLineUtil.ArgumentError(self, "Unknown Argument %s" % uneatenArgs[0]) return eatenArgs
def validate_options(self,options): if options.get('help'): raise CommandLineUtil.ArgumentError(self,'') for opt in self.options: opt.apply_options(options) for opt in self.options: opt.validate() return 1
def _gen_usage(self,command_string): """ Generates the usage summary, example command line, and descriptions of options and subcommands or arguments """ lines = self.__gen_command_line_help(command_string)
# saved for use in the example command_size = len(command_string)
# generate the example, if available if self.example is not None: lines.append('\nExample:') text_width = CONSOLE_WIDTH - command_size text = CommandLineUtil.wrap_text(self.example, text_width) lines.append(command_string + text[0]) indent = ' ' * command_size lines.extend([ indent + s for s in text[1:] ])
# generate the option descriptions option_desc = self.options.generate_help() if option_desc: lines.append('\nOptions:') lines.extend(option_desc)
# generate the subcommand descriptions if self.subCommands: max_cmd = 0 for cmd in self.subCommands.keys(): if len(cmd) > max_cmd: max_cmd = len(cmd)
lines.append('\nSubcommands:') # column size = indent + longest command + gutter indent = ' ' * (2 + max_cmd + 2) + ' ' text_width = CONSOLE_WIDTH - len(indent) names = self.subCommands.keys() names.sort() for name in names: cmd = self.subCommands[name] text = CommandLineUtil.wrap_text(cmd.description, text_width) lines.append(' %-*s %s' % (max_cmd, name, text[0])) lines.extend([ indent + s for s in text[1:] ])
# generate the argument descriptions if self.arguments: max_arg = 0 for arg in self.arguments: if len(arg.name) > max_arg: max_arg = len(arg.name)
lines.append('\nArguments:') # column size = indent + longest command + gutter indent = ' ' * (2 + max_arg + 2) text_width = CONSOLE_WIDTH - len(indent) for arg in self.arguments: text = CommandLineUtil.wrap_text(arg.description, text_width) lines.append(' %-*s %s' % (max_arg, arg.name, text[0])) lines.extend([ indent + s for s in text[1:] ])
lines.append('') # add a blank line return lines
def _parse_command_opts(self, args): (options, args) = FancyGetOpt.FancyGetopt(self, self.options, args)
if not self.validate_options(options):return None self.clOptions = options
# Args can either be a subcommand, or the start of the argument # list. Subcommand takes precedence. if len(args) and self.subCommands.has_key(args[0]): #It is a subcommand cmd = self.subCommands[args[0]] finalCmd = cmd._parse_command_opts(args[1:],) else: #They are arguments finalCmd = self self.clArguments = self.validate_arguments(args) return finalCmd
def __gen_command_line_help(self, command_string): """ Generates the indented usage summary only. """ # command_string looks like this: ' 4ss create user ' # i.e., it is '4ss create user', indented and ready to # have the option & argument syntax appended like so: # ' 4ss create user (syntax line 1) # (syntax line 2) # (syntax line 3)'
# generate the option/arg syntax string, which looks like this: # '[--help] [[--username=<USER>] | [--anonymous]] # [--password=<PASSWORD>] [--port=<PORT>] [--host=<HOST>] # [--container=<PATH>] userName ' syntax_string = '' for opt in self.options: syntax_string += opt.gen_command_line() + ' ' if self.subCommands: if len(self.arguments): syntax_string += '[' syntax_string += '<subcommand> ' if len(self.arguments): syntax_string += '[' syntax_string += '<subcommand> ' if len(self.arguments): syntax_string += '] | [' if self.arguments: for arg in self.arguments: syntax_string += arg.gen_command_line() + ' ' if self.subCommands: syntax_string += ']'
# wrap the syntax line to a width that won't exceed the console # width when appended to command_string command_size = len(command_string) syntax_string_lines = CommandLineUtil.wrap_text( syntax_string, CONSOLE_WIDTH - command_size)
# append first line of wrapped syntax string to command_string # and indent the remaining lines appropriately lines = [command_string + syntax_string_lines[0]] indent = ' ' * command_size lines.extend([ indent + s for s in syntax_string_lines[1:] ])
return lines
|