145 lines
4.5 KiB
Python
Executable File
145 lines
4.5 KiB
Python
Executable File
"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, 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, 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()
|