1
# Copyright (C) 2004, 2005 by Canonical Ltd
1
# Copyright (C) 2006 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
18
# TODO: probably should say which arguments are candidates for glob
19
19
# expansion on windows and do that at the command level.
21
# TODO: Help messages for options.
23
21
# TODO: Define arguments by objects, rather than just using names.
24
22
# Those objects can specify the expected type of the argument, which
25
# would help with validation and shell completion.
23
# would help with validation and shell completion. They could also provide
24
# help/explanation for that argument in a structured way.
26
# TODO: Specific "examples" property on commands for consistent formatting.
27
28
# TODO: "--profile=cum", to change sort order. Is there any value in leaving
28
29
# the profile output behind so it can be interactively examined?
34
from bzrlib.lazy_import import lazy_import
35
lazy_import(globals(), """
32
38
from warnings import warn
33
from inspect import getdoc
37
from bzrlib.trace import mutter, note, log_error, warning
38
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
39
from bzrlib.revisionspec import RevisionSpec
40
from bzrlib import BZRDIR
49
from bzrlib.symbol_versioning import (
41
56
from bzrlib.option import Option
46
def register_command(cmd):
47
"Utility function to help register a command"
62
def register_command(cmd, decorate=False):
63
"""Utility function to help register a command
65
:param cmd: Command subclass to register
66
:param decorate: If true, allow overriding an existing command
67
of the same name; the old command is returned by this function.
68
Otherwise it is an error to try to override an existing command.
50
72
if k.startswith("cmd_"):
51
73
k_unsquished = _unsquish_command_name(k)
54
if not plugin_cmds.has_key(k_unsquished):
55
plugin_cmds[k_unsquished] = cmd
56
mutter('registered plugin command %s', k_unsquished)
76
if k_unsquished not in plugin_cmds:
77
plugin_cmds[k_unsquished] = cmd
78
trace.mutter('registered plugin command %s', k_unsquished)
79
if decorate and k_unsquished in builtin_command_names():
80
return _builtin_commands()[k_unsquished]
82
result = plugin_cmds[k_unsquished]
83
plugin_cmds[k_unsquished] = cmd
58
log_error('Two plugins defined the same command: %r' % k)
59
log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
86
trace.log_error('Two plugins defined the same command: %r' % k)
87
trace.log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
62
90
def _squish_command_name(cmd):
183
232
Maps from long option name to option object."""
185
r['help'] = Option.OPTIONS['help']
234
r['help'] = option.Option.OPTIONS['help']
186
235
for o in self.takes_options:
187
if not isinstance(o, Option):
188
o = Option.OPTIONS[o]
236
if isinstance(o, basestring):
237
o = option.Option.OPTIONS[o]
241
def _setup_outf(self):
242
"""Return a file linked to stdout, which has proper encoding."""
243
assert self.encoding_type in ['strict', 'exact', 'replace']
245
# Originally I was using self.stdout, but that looks
246
# *way* too much like sys.stdout
247
if self.encoding_type == 'exact':
248
self.outf = sys.stdout
251
output_encoding = osutils.get_terminal_encoding()
253
# use 'replace' so that we don't abort if trying to write out
254
# in e.g. the default C locale.
255
self.outf = codecs.getwriter(output_encoding)(sys.stdout, errors=self.encoding_type)
256
# For whatever reason codecs.getwriter() does not advertise its encoding
257
# it just returns the encoding of the wrapped file, which is completely
258
# bogus. So set the attribute, so we can find the correct encoding later.
259
self.outf.encoding = output_encoding
261
@deprecated_method(zero_eight)
192
262
def run_argv(self, argv):
193
"""Parse command line and run."""
194
args, opts = parse_args(self, argv)
263
"""Parse command line and run.
265
See run_argv_aliases for the 0.8 and beyond api.
267
return self.run_argv_aliases(argv)
269
def run_argv_aliases(self, argv, alias_argv=None):
270
"""Parse the command line and run with extra aliases in alias_argv."""
272
warn("Passing None for [] is deprecated from bzrlib 0.10",
273
DeprecationWarning, stacklevel=2)
275
args, opts = parse_args(self, argv, alias_argv)
195
276
if 'help' in opts: # e.g. bzr add --help
196
277
from bzrlib.help import help_on_command
197
278
help_on_command(self.name())
199
# XXX: This should be handled by the parser
200
allowed_names = self.options().keys()
202
if oname not in allowed_names:
203
raise BzrCommandError("option '--%s' is not allowed for command %r"
204
% (oname, self.name()))
205
280
# mix arguments and options into one dictionary
206
281
cmdargs = _match_argform(self.name(), self.takes_args, args)
276
367
lookup table, something about the available options, what optargs
277
368
they take, and which commands will accept them.
279
# TODO: chop up this beast; make it a method of the Command
283
cmd_options = command.options()
291
# We've received a standalone -- No more flags
295
# option names must not be unicode
299
mutter(" got option %r" % a)
301
optname, optarg = a[2:].split('=', 1)
304
if optname not in cmd_options:
305
raise BzrCommandError('unknown long option %r for command %s'
309
if shortopt in Option.SHORT_OPTIONS:
310
# Multi-character options must have a space to delimit
312
# ^^^ what does this mean? mbp 20051014
313
optname = Option.SHORT_OPTIONS[shortopt].name
315
# Single character short options, can be chained,
316
# and have their value appended to their name
318
if shortopt not in Option.SHORT_OPTIONS:
319
# We didn't find the multi-character name, and we
320
# didn't find the single char name
321
raise BzrError('unknown short option %r' % a)
322
optname = Option.SHORT_OPTIONS[shortopt].name
325
# There are extra things on this option
326
# see if it is the value, or if it is another
328
optargfn = Option.OPTIONS[optname].type
330
# This option does not take an argument, so the
331
# next entry is another short option, pack it back
333
argv.insert(0, '-' + a[2:])
335
# This option takes an argument, so pack it
340
# XXX: Do we ever want to support this, e.g. for -r?
341
raise BzrError('repeated option %r' % a)
343
option_obj = cmd_options[optname]
344
optargfn = option_obj.type
348
raise BzrError('option %r needs an argument' % a)
351
opts[optname] = optargfn(optarg)
354
raise BzrError('option %r takes no argument' % optname)
370
# TODO: make it a method of the Command?
371
parser = option.get_optparser(command.options())
372
if alias_argv is not None:
373
args = alias_argv + argv
377
options, args = parser.parse_args(args)
378
opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
379
v is not option.OptionParser.DEFAULT_VALUE])
358
380
return args, opts
375
397
argdict[argname + '_list'] = None
376
398
elif ap[-1] == '+':
378
raise BzrCommandError("command %r needs one or more %s"
379
% (cmd, argname.upper()))
400
raise errors.BzrCommandError("command %r needs one or more %s"
401
% (cmd, argname.upper()))
381
403
argdict[argname + '_list'] = args[:]
383
405
elif ap[-1] == '$': # all but one
384
406
if len(args) < 2:
385
raise BzrCommandError("command %r needs one or more %s"
386
% (cmd, argname.upper()))
407
raise errors.BzrCommandError("command %r needs one or more %s"
408
% (cmd, argname.upper()))
387
409
argdict[argname + '_list'] = args[:-1]
390
412
# just a plain arg
393
raise BzrCommandError("command %r requires argument %s"
394
% (cmd, argname.upper()))
415
raise errors.BzrCommandError("command %r requires argument %s"
416
% (cmd, argname.upper()))
396
418
argdict[argname] = args.pop(0)
399
raise BzrCommandError("extra argument to command %s: %s"
421
raise errors.BzrCommandError("extra argument to command %s: %s"
444
491
Do not load plugin modules at all
447
497
Only use builtin commands. (Plugins are still allowed to change
448
498
other behaviour.)
451
Run under the Python profiler.
501
Run under the Python hotshot profiler.
504
Run under the Python lsprof profiler.
453
argv = [a.decode(bzrlib.user_encoding) for a in argv]
455
opt_profile = opt_no_plugins = opt_builtin = False
508
opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = \
509
opt_no_aliases = False
510
opt_lsprof_file = None
457
512
# --no-plugins is handled specially at a very early stage. We need
458
513
# to load plugins before doing other command parsing so that they
459
514
# can override commands, but this needs to happen first.
462
520
if a == '--profile':
463
521
opt_profile = True
522
elif a == '--lsprof':
524
elif a == '--lsprof-file':
526
opt_lsprof_file = argv[i + 1]
464
528
elif a == '--no-plugins':
465
529
opt_no_plugins = True
530
elif a == '--no-aliases':
531
opt_no_aliases = True
466
532
elif a == '--builtin':
467
533
opt_builtin = True
534
elif a in ('--quiet', '-q'):
472
if (not argv) or (argv[0] == '--help'):
473
from bzrlib.help import help
542
from bzrlib.builtins import cmd_help
543
cmd_help().run_argv_aliases([])
480
546
if argv[0] == '--version':
481
from bzrlib.builtins import show_version
547
from bzrlib.version import show_version
485
551
if not opt_no_plugins:
486
552
from bzrlib.plugin import load_plugins
489
cmd = str(argv.pop(0))
555
from bzrlib.plugin import disable_plugins
560
if not opt_no_aliases:
561
alias_argv = get_alias(argv[0])
563
alias_argv = [a.decode(bzrlib.user_encoding) for a in alias_argv]
564
argv[0] = alias_argv.pop(0)
567
# We want only 'ascii' command names, but the user may have typed
568
# in a Unicode name. In that case, they should just get a
569
# 'command not found' error later.
491
571
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
494
ret = apply_profiled(cmd_obj.run_argv, argv)
572
if not getattr(cmd_obj.run_argv, 'is_deprecated', False):
573
run = cmd_obj.run_argv
496
ret = cmd_obj.run_argv(argv)
576
run = cmd_obj.run_argv_aliases
577
run_argv = [argv, alias_argv]
581
ret = apply_lsprofiled(opt_lsprof_file, run, *run_argv)
583
ret = apply_profiled(run, *run_argv)
588
# reset, in case we may do other commands later within the same process
589
trace.be_quiet(False)
591
def display_command(func):
592
"""Decorator that suppresses pipe/interrupt errors."""
593
def ignore_pipe(*args, **kwargs):
595
result = func(*args, **kwargs)
599
if getattr(e, 'errno', None) is None:
601
if e.errno != errno.EPIPE:
602
# Win32 raises IOError with errno=0 on a broken pipe
603
if sys.platform != 'win32' or e.errno != 0:
606
except KeyboardInterrupt:
502
bzrlib.trace.log_startup(argv)
503
bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
505
return run_bzr_catch_errors(argv[1:])
613
from bzrlib.ui.text import TextUIFactory
614
bzrlib.ui.ui_factory = TextUIFactory()
615
argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
616
ret = run_bzr_catch_errors(argv)
617
trace.mutter("return code %d", ret)
508
621
def run_bzr_catch_errors(argv):
513
# do this here inside the exception wrappers to catch EPIPE
515
except BzrCommandError, e:
516
# command line syntax error, etc
520
bzrlib.trace.log_exception()
522
except AssertionError, e:
523
bzrlib.trace.log_exception('assertion failed: ' + str(e))
624
# do this here inside the exception wrappers to catch EPIPE
626
except (KeyboardInterrupt, Exception), e:
627
# used to handle AssertionError and KeyboardInterrupt
628
# specially here, but hopefully they're handled ok by the logger now
629
trace.report_exception(sys.exc_info(), sys.stderr)
630
if os.environ.get('BZR_PDB'):
631
print '**** entering debugger'
633
pdb.post_mortem(sys.exc_traceback)
525
except KeyboardInterrupt, e:
526
bzrlib.trace.log_exception('interrupted')
530
if (isinstance(e, IOError)
531
and hasattr(e, 'errno')
532
and e.errno == errno.EPIPE):
533
bzrlib.trace.note('broken pipe')
538
bzrlib.trace.log_exception()
541
636
if __name__ == '__main__':
542
637
sys.exit(main(sys.argv))