| "Framework for command line interfaces like CVS. See class CmdFrameWork." |
| |
| |
| class CommandFrameWork: |
| |
| """Framework class for command line interfaces like CVS. |
| |
| The general command line structure is |
| |
| command [flags] subcommand [subflags] [argument] ... |
| |
| There's a class variable GlobalFlags which specifies the |
| global flags options. Subcommands are defined by defining |
| methods named do_<subcommand>. Flags for the subcommand are |
| defined by defining class or instance variables named |
| flags_<subcommand>. If there's no command, method default() |
| is called. The __doc__ strings for the do_ methods are used |
| for the usage message, printed after the general usage message |
| which is the class variable UsageMessage. The class variable |
| PostUsageMessage is printed after all the do_ methods' __doc__ |
| strings. The method's return value can be a suggested exit |
| status. [XXX Need to rewrite this to clarify it.] |
| |
| Common usage is to derive a class, instantiate it, and then call its |
| run() method; by default this takes its arguments from sys.argv[1:]. |
| """ |
| |
| UsageMessage = \ |
| "usage: (name)s [flags] subcommand [subflags] [argument] ..." |
| |
| PostUsageMessage = None |
| |
| GlobalFlags = '' |
| |
| def __init__(self): |
| """Constructor, present for completeness.""" |
| pass |
| |
| def run(self, args = None): |
| """Process flags, subcommand and options, then run it.""" |
| import getopt, sys |
| if args is None: args = sys.argv[1:] |
| try: |
| opts, args = getopt.getopt(args, self.GlobalFlags) |
| except getopt.error as msg: |
| return self.usage(msg) |
| self.options(opts) |
| if not args: |
| self.ready() |
| return self.default() |
| else: |
| cmd = args[0] |
| mname = 'do_' + cmd |
| fname = 'flags_' + cmd |
| try: |
| method = getattr(self, mname) |
| except AttributeError: |
| return self.usage("command %r unknown" % (cmd,)) |
| try: |
| flags = getattr(self, fname) |
| except AttributeError: |
| flags = '' |
| try: |
| opts, args = getopt.getopt(args[1:], flags) |
| except getopt.error as msg: |
| return self.usage( |
| "subcommand %s: " % cmd + str(msg)) |
| self.ready() |
| return method(opts, args) |
| |
| def options(self, opts): |
| """Process the options retrieved by getopt. |
| Override this if you have any options.""" |
| if opts: |
| print "-"*40 |
| print "Options:" |
| for o, a in opts: |
| print 'option', o, 'value', repr(a) |
| print "-"*40 |
| |
| def ready(self): |
| """Called just before calling the subcommand.""" |
| pass |
| |
| def usage(self, msg = None): |
| """Print usage message. Return suitable exit code (2).""" |
| if msg: print msg |
| print self.UsageMessage % {'name': self.__class__.__name__} |
| docstrings = {} |
| c = self.__class__ |
| while 1: |
| for name in dir(c): |
| if name[:3] == 'do_': |
| if docstrings.has_key(name): |
| continue |
| try: |
| doc = getattr(c, name).__doc__ |
| except: |
| doc = None |
| if doc: |
| docstrings[name] = doc |
| if not c.__bases__: |
| break |
| c = c.__bases__[0] |
| if docstrings: |
| print "where subcommand can be:" |
| names = docstrings.keys() |
| names.sort() |
| for name in names: |
| print docstrings[name] |
| if self.PostUsageMessage: |
| print self.PostUsageMessage |
| return 2 |
| |
| def default(self): |
| """Default method, called when no subcommand is given. |
| You should always override this.""" |
| print "Nobody expects the Spanish Inquisition!" |
| |
| |
| def test(): |
| """Test script -- called when this module is run as a script.""" |
| import sys |
| class Hello(CommandFrameWork): |
| def do_hello(self, opts, args): |
| "hello -- print 'hello world', needs no arguments" |
| print "Hello, world" |
| x = Hello() |
| tests = [ |
| [], |
| ['hello'], |
| ['spam'], |
| ['-x'], |
| ['hello', '-x'], |
| None, |
| ] |
| for t in tests: |
| print '-'*10, t, '-'*10 |
| sts = x.run(t) |
| print "Exit status:", repr(sts) |
| |
| |
| if __name__ == '__main__': |
| test() |