summaryrefslogtreecommitdiffstats
path: root/Demo/pdist/cmdfw.py
blob: 25584b78f84c6a311594240ca82b373f74b5488e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
"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()