160
163
msg = "No known merge type %s. Supported types are:\n%s" %\
161
164
(typestring, type_list)
162
165
raise BzrCommandError(msg)
166
def _get_cmd_dict(plugins_override=True):
168
def _builtin_commands():
167
169
import bzrlib.builtins
170
171
builtins = bzrlib.builtins.__dict__
171
172
for name in builtins:
172
173
if name.startswith("cmd_"):
173
d[_unsquish_command_name(name)] = builtins[name]
174
# If we didn't load plugins, the plugin_cmds dict will be empty
174
real_name = _unsquish_command_name(name)
175
r[real_name] = builtins[name]
180
def builtin_command_names():
181
"""Return list of builtin command names."""
182
return _builtin_commands().keys()
185
def plugin_command_names():
186
return plugin_cmds.keys()
189
def _get_cmd_dict(plugins_override=True):
190
"""Return name->class mapping for all commands."""
191
d = _builtin_commands()
175
192
if plugins_override:
176
193
d.update(plugin_cmds)
178
d2 = plugin_cmds.copy()
190
def get_cmd_class(cmd, plugins_override=True):
203
def get_cmd_object(cmd_name, plugins_override=True):
191
204
"""Return the canonical name and command class for a command.
207
If true, plugin commands can override builtins.
193
cmd = str(cmd) # not unicode
209
cmd_name = str(cmd_name) # not unicode
195
211
# first look up this command under the specified name
196
212
cmds = _get_cmd_dict(plugins_override=plugins_override)
197
mutter("all commands: %r", cmds.keys())
199
return cmd, cmds[cmd]
214
return cmds[cmd_name]()
203
218
# look for any command which claims this as an alias
204
for cmdname, cmdclass in cmds.iteritems():
205
if cmd in cmdclass.aliases:
206
return cmdname, cmdclass
208
cmdclass = ExternalCommand.find_command(cmd)
212
raise BzrCommandError("unknown command %r" % cmd)
219
for real_cmd_name, cmd_class in cmds.iteritems():
220
if cmd_name in cmd_class.aliases:
223
cmd_obj = ExternalCommand.find_command(cmd_name)
227
raise BzrCommandError("unknown command %r" % cmd_name)
215
230
class Command(object):
216
231
"""Base class for commands.
233
Commands are the heart of the command-line bzr interface.
235
The command object mostly handles the mapping of command-line
236
parameters into one or more bzrlib operations, and of the results
239
Commands normally don't have any state. All their arguments are
240
passed in to the run method. (Subclasses may take a different
241
policy if the behaviour of the instance needs to depend on e.g. a
242
shell plugin and not just its Python class.)
218
244
The docstring for an actual command should give a single-line
219
245
summary, then a complete description of the command. A grammar
220
246
description will be inserted.
249
Other accepted names for this command.
223
252
List of argument forms, marked with whether they are optional,
227
256
List of options that may be given for this command.
230
If true, this command isn't advertised.
259
If true, this command isn't advertised. This is typically
260
for commands intended for expert users.
239
def __init__(self, options, arguments):
240
"""Construct and run the command.
242
Sets self.status to the return value of run()."""
243
assert isinstance(options, dict)
244
assert isinstance(arguments, dict)
245
cmdargs = options.copy()
246
cmdargs.update(arguments)
270
"""Construct an instance of this command."""
247
271
if self.__doc__ == Command.__doc__:
248
from warnings import warn
249
272
warn("No help message set for %r" % self)
250
self.status = self.run(**cmdargs)
251
if self.status is None:
255
def run(self, *args, **kwargs):
256
"""Override this in sub-classes.
276
"""Actually run the command.
258
278
This is invoked with the options and arguments bound to
259
279
keyword parameters.
261
Return 0 or None if the command was successful, or a shell
281
Return 0 or None if the command was successful, or a non-zero
282
shell error code if not. It's OK for this method to allow
283
an exception to raise up.
264
285
raise NotImplementedError()
289
"""Return help message for this class."""
290
if self.__doc__ is Command.__doc__:
295
return _unsquish_command_name(self.__class__.__name__)
267
298
class ExternalCommand(Command):
268
299
"""Class to wrap external commands.
609
def apply_profiled(the_callable, *args, **kwargs):
612
pffileno, pfname = tempfile.mkstemp()
614
prof = hotshot.Profile(pfname)
616
ret = prof.runcall(the_callable, *args, **kwargs) or 0
621
stats = hotshot.stats.load(pfname)
623
stats.sort_stats('time')
624
## XXX: Might like to write to stderr or the trace file instead but
625
## print_stats seems hardcoded to stdout
626
stats.print_stats(20)
573
634
def run_bzr(argv):
574
635
"""Execute a command.
641
702
cmd = str(args.pop(0))
643
canonical_cmd, cmd_class = \
644
get_cmd_class(cmd, plugins_override=not opt_builtin)
704
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
646
706
# check options are reasonable
647
allowed = cmd_class.takes_options
707
allowed = cmd_obj.takes_options
648
708
for oname in opts:
649
709
if oname not in allowed:
650
710
raise BzrCommandError("option '--%s' is not allowed for command %r"
653
713
# mix arguments and options into one dictionary
654
cmdargs = _match_argform(cmd, cmd_class.takes_args, args)
714
cmdargs = _match_argform(cmd, cmd_obj.takes_args, args)
656
716
for k, v in opts.items():
657
717
cmdopts[k.replace('-', '_')] = v
719
all_cmd_args = cmdargs.copy()
720
all_cmd_args.update(cmdopts)
660
import hotshot, tempfile
661
pffileno, pfname = tempfile.mkstemp()
663
prof = hotshot.Profile(pfname)
664
ret = prof.runcall(cmd_class, cmdopts, cmdargs) or 0
668
stats = hotshot.stats.load(pfname)
670
stats.sort_stats('time')
671
## XXX: Might like to write to stderr or the trace file instead but
672
## print_stats seems hardcoded to stdout
673
stats.print_stats(20)
723
ret = apply_profiled(cmd_obj.run, **all_cmd_args)
681
return cmd_class(cmdopts, cmdargs).status
725
ret = cmd_obj.run(**all_cmd_args)