1
# Copyright (C) 2006 Canonical Ltd
1
# Copyright (C) 2004, 2005 by 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.
21
23
# TODO: Define arguments by objects, rather than just using names.
22
24
# Those objects can specify the expected type of the argument, which
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.
25
# would help with validation and shell completion.
28
27
# TODO: "--profile=cum", to change sort order. Is there any value in leaving
29
28
# the profile output behind so it can be interactively examined?
34
from bzrlib.lazy_import import lazy_import
35
lazy_import(globals(), """
38
32
from warnings import warn
33
from inspect import getdoc
50
from bzrlib.symbol_versioning import (
57
from bzrlib.option import Option
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
63
def register_command(cmd, decorate=False):
64
"""Utility function to help register a command
66
:param cmd: Command subclass to register
67
:param decorate: If true, allow overriding an existing command
68
of the same name; the old command is returned by this function.
69
Otherwise it is an error to try to override an existing command.
45
def register_command(cmd):
46
"Utility function to help register a command"
73
49
if k.startswith("cmd_"):
74
50
k_unsquished = _unsquish_command_name(k)
77
if k_unsquished not in plugin_cmds:
78
plugin_cmds[k_unsquished] = cmd
79
trace.mutter('registered plugin command %s', k_unsquished)
80
if decorate and k_unsquished in builtin_command_names():
81
return _builtin_commands()[k_unsquished]
83
result = plugin_cmds[k_unsquished]
84
plugin_cmds[k_unsquished] = cmd
53
if not plugin_cmds.has_key(k_unsquished):
54
plugin_cmds[k_unsquished] = cmd
55
mutter('registered plugin command %s', k_unsquished)
87
trace.log_error('Two plugins defined the same command: %r' % k)
88
trace.log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
57
log_error('Two plugins defined the same command: %r' % k)
58
log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
91
61
def _squish_command_name(cmd):
97
67
return cmd[4:].replace('_','-')
70
def _parse_revision_str(revstr):
71
"""This handles a revision string -> revno.
73
This always returns a list. The list will have one element for
74
each revision specifier supplied.
76
>>> _parse_revision_str('234')
77
[<RevisionSpec_int 234>]
78
>>> _parse_revision_str('234..567')
79
[<RevisionSpec_int 234>, <RevisionSpec_int 567>]
80
>>> _parse_revision_str('..')
81
[<RevisionSpec None>, <RevisionSpec None>]
82
>>> _parse_revision_str('..234')
83
[<RevisionSpec None>, <RevisionSpec_int 234>]
84
>>> _parse_revision_str('234..')
85
[<RevisionSpec_int 234>, <RevisionSpec None>]
86
>>> _parse_revision_str('234..456..789') # Maybe this should be an error
87
[<RevisionSpec_int 234>, <RevisionSpec_int 456>, <RevisionSpec_int 789>]
88
>>> _parse_revision_str('234....789') #Error ?
89
[<RevisionSpec_int 234>, <RevisionSpec None>, <RevisionSpec_int 789>]
90
>>> _parse_revision_str('revid:test@other.com-234234')
91
[<RevisionSpec_revid revid:test@other.com-234234>]
92
>>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235')
93
[<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_revid revid:test@other.com-234235>]
94
>>> _parse_revision_str('revid:test@other.com-234234..23')
95
[<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_int 23>]
96
>>> _parse_revision_str('date:2005-04-12')
97
[<RevisionSpec_date date:2005-04-12>]
98
>>> _parse_revision_str('date:2005-04-12 12:24:33')
99
[<RevisionSpec_date date:2005-04-12 12:24:33>]
100
>>> _parse_revision_str('date:2005-04-12T12:24:33')
101
[<RevisionSpec_date date:2005-04-12T12:24:33>]
102
>>> _parse_revision_str('date:2005-04-12,12:24:33')
103
[<RevisionSpec_date date:2005-04-12,12:24:33>]
104
>>> _parse_revision_str('-5..23')
105
[<RevisionSpec_int -5>, <RevisionSpec_int 23>]
106
>>> _parse_revision_str('-5')
107
[<RevisionSpec_int -5>]
108
>>> _parse_revision_str('123a')
109
Traceback (most recent call last):
111
BzrError: No namespace registered for string: '123a'
112
>>> _parse_revision_str('abc')
113
Traceback (most recent call last):
115
BzrError: No namespace registered for string: 'abc'
116
>>> _parse_revision_str('branch:../branch2')
117
[<RevisionSpec_branch branch:../branch2>]
120
old_format_re = re.compile('\d*:\d*')
121
m = old_format_re.match(revstr)
124
warning('Colon separator for revision numbers is deprecated.'
126
for rev in revstr.split(':'):
128
revs.append(RevisionSpec(int(rev)))
130
revs.append(RevisionSpec(None))
133
for x in revstr.split('..'):
135
revs.append(RevisionSpec(None))
137
# looks like a namespace:.. has happened
138
next_prefix = x + '..'
140
if next_prefix is not None:
142
revs.append(RevisionSpec(x))
144
if next_prefix is not None:
145
revs.append(RevisionSpec(next_prefix))
100
149
def _builtin_commands():
101
150
import bzrlib.builtins
103
152
builtins = bzrlib.builtins.__dict__
104
153
for name in builtins:
105
154
if name.startswith("cmd_"):
106
real_name = _unsquish_command_name(name)
155
real_name = _unsquish_command_name(name)
107
156
r[real_name] = builtins[name]
111
161
def builtin_command_names():
188
235
List of argument forms, marked with whether they are optional,
193
['to_location', 'from_branch?', 'file*']
195
'to_location' is required
196
'from_branch' is optional
197
'file' can be specified 0 or more times
200
List of options that may be given for this command. These can
201
be either strings, referring to globally-defined options,
202
or option objects. Retrieve through options().
239
List of options that may be given for this command.
205
242
If true, this command isn't advertised. This is typically
206
243
for commands intended for expert users.
209
Command objects will get a 'outf' attribute, which has been
210
setup to properly handle encoding of unicode strings.
211
encoding_type determines what will happen when characters cannot
213
strict - abort if we cannot decode
214
replace - put in a bogus character (typically '?')
215
exact - do not encode sys.stdout
220
248
takes_options = []
221
encoding_type = 'strict'
227
254
if self.__doc__ == Command.__doc__:
228
255
warn("No help message set for %r" % self)
231
"""Return dict of valid options for this command.
233
Maps from long option name to option object."""
235
r['help'] = option.Option.OPTIONS['help']
236
for o in self.takes_options:
237
if isinstance(o, basestring):
238
o = option.Option.OPTIONS[o]
242
def _setup_outf(self):
243
"""Return a file linked to stdout, which has proper encoding."""
244
assert self.encoding_type in ['strict', 'exact', 'replace']
246
# Originally I was using self.stdout, but that looks
247
# *way* too much like sys.stdout
248
if self.encoding_type == 'exact':
249
self.outf = sys.stdout
252
output_encoding = osutils.get_terminal_encoding()
254
# use 'replace' so that we don't abort if trying to write out
255
# in e.g. the default C locale.
256
self.outf = codecs.getwriter(output_encoding)(sys.stdout, errors=self.encoding_type)
257
# For whatever reason codecs.getwriter() does not advertise its encoding
258
# it just returns the encoding of the wrapped file, which is completely
259
# bogus. So set the attribute, so we can find the correct encoding later.
260
self.outf.encoding = output_encoding
262
@deprecated_method(zero_eight)
263
258
def run_argv(self, argv):
264
"""Parse command line and run.
266
See run_argv_aliases for the 0.8 and beyond api.
268
return self.run_argv_aliases(argv)
259
"""Parse command line and run."""
260
args, opts = parse_args(argv)
270
def run_argv_aliases(self, argv, alias_argv=None):
271
"""Parse the command line and run with extra aliases in alias_argv."""
273
warn("Passing None for [] is deprecated from bzrlib 0.10",
274
DeprecationWarning, stacklevel=2)
276
args, opts = parse_args(self, argv, alias_argv)
277
262
if 'help' in opts: # e.g. bzr add --help
278
263
from bzrlib.help import help_on_command
279
264
help_on_command(self.name())
267
# check options are reasonable
268
allowed = self.takes_options
270
if oname not in allowed:
271
raise BzrCommandError("option '--%s' is not allowed for command %r"
272
% (oname, self.name()))
281
274
# mix arguments and options into one dictionary
282
275
cmdargs = _match_argform(self.name(), self.takes_args, args)
360
337
parsed = [spec, None]
363
def parse_args(command, argv, alias_argv=None):
341
# list of all available options; the rhs can be either None for an
342
# option that takes no argument, or a constructor function that checks
357
'revision': _parse_revision_str,
384
def parse_args(argv):
364
385
"""Parse command line.
366
387
Arguments and options are parsed at this level before being passed
367
388
down to specific command handlers. This routine knows, from a
368
389
lookup table, something about the available options, what optargs
369
390
they take, and which commands will accept them.
392
>>> parse_args('--help'.split())
394
>>> parse_args('help -- --invalidcmd'.split())
395
(['help', '--invalidcmd'], {})
396
>>> parse_args('--version'.split())
397
([], {'version': True})
398
>>> parse_args('status --all'.split())
399
(['status'], {'all': True})
400
>>> parse_args('commit --message=biter'.split())
401
(['commit'], {'message': u'biter'})
402
>>> parse_args('log -r 500'.split())
403
(['log'], {'revision': [<RevisionSpec_int 500>]})
404
>>> parse_args('log -r500..600'.split())
405
(['log'], {'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
406
>>> parse_args('log -vr500..600'.split())
407
(['log'], {'verbose': True, 'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
408
>>> parse_args('log -rrevno:500..600'.split()) #the r takes an argument
409
(['log'], {'revision': [<RevisionSpec_revno revno:500>, <RevisionSpec_int 600>]})
371
# TODO: make it a method of the Command?
372
parser = option.get_optparser(command.options())
373
if alias_argv is not None:
374
args = alias_argv + argv
378
options, args = parser.parse_args(args)
379
opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
380
v is not option.OptionParser.DEFAULT_VALUE])
417
if not argsover and a[0] == '-':
418
# option names must not be unicode
423
# We've received a standalone -- No more flags
426
mutter(" got option %r" % a)
428
optname, optarg = a[2:].split('=', 1)
431
if optname not in OPTIONS:
432
raise BzrError('unknown long option %r' % a)
435
if shortopt in SHORT_OPTIONS:
436
# Multi-character options must have a space to delimit
438
optname = SHORT_OPTIONS[shortopt]
440
# Single character short options, can be chained,
441
# and have their value appended to their name
443
if shortopt not in SHORT_OPTIONS:
444
# We didn't find the multi-character name, and we
445
# didn't find the single char name
446
raise BzrError('unknown short option %r' % a)
447
optname = SHORT_OPTIONS[shortopt]
450
# There are extra things on this option
451
# see if it is the value, or if it is another
453
optargfn = OPTIONS[optname]
455
# This option does not take an argument, so the
456
# next entry is another short option, pack it back
458
argv.insert(0, '-' + a[2:])
460
# This option takes an argument, so pack it
465
# XXX: Do we ever want to support this, e.g. for -r?
466
raise BzrError('repeated option %r' % a)
468
optargfn = OPTIONS[optname]
472
raise BzrError('option %r needs an argument' % a)
475
opts[optname] = optargfn(optarg)
478
raise BzrError('option %r takes no argument' % optname)
381
483
return args, opts
384
488
def _match_argform(cmd, takes_args, args):
398
502
argdict[argname + '_list'] = None
399
503
elif ap[-1] == '+':
401
raise errors.BzrCommandError("command %r needs one or more %s"
402
% (cmd, argname.upper()))
505
raise BzrCommandError("command %r needs one or more %s"
506
% (cmd, argname.upper()))
404
508
argdict[argname + '_list'] = args[:]
406
510
elif ap[-1] == '$': # all but one
407
511
if len(args) < 2:
408
raise errors.BzrCommandError("command %r needs one or more %s"
409
% (cmd, argname.upper()))
512
raise BzrCommandError("command %r needs one or more %s"
513
% (cmd, argname.upper()))
410
514
argdict[argname + '_list'] = args[:-1]
413
517
# just a plain arg
416
raise errors.BzrCommandError("command %r requires argument %s"
417
% (cmd, argname.upper()))
520
raise BzrCommandError("command %r requires argument %s"
521
% (cmd, argname.upper()))
419
523
argdict[argname] = args.pop(0)
422
raise errors.BzrCommandError("extra argument to command %s: %s"
526
raise BzrCommandError("extra argument to command %s: %s"
492
571
Do not load plugin modules at all
498
574
Only use builtin commands. (Plugins are still allowed to change
499
575
other behaviour.)
502
Run under the Python hotshot profiler.
505
Run under the Python lsprof profiler.
578
Run under the Python profiler.
580
# Load all of the transport methods
581
import bzrlib.transport.local, bzrlib.transport.http
583
argv = [a.decode(bzrlib.user_encoding) for a in argv]
509
opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = \
510
opt_no_aliases = False
511
opt_lsprof_file = None
585
opt_profile = opt_no_plugins = opt_builtin = False
513
587
# --no-plugins is handled specially at a very early stage. We need
514
588
# to load plugins before doing other command parsing so that they
515
589
# can override commands, but this needs to happen first.
521
592
if a == '--profile':
522
593
opt_profile = True
523
elif a == '--lsprof':
525
elif a == '--lsprof-file':
527
opt_lsprof_file = argv[i + 1]
529
594
elif a == '--no-plugins':
530
595
opt_no_plugins = True
531
elif a == '--no-aliases':
532
opt_no_aliases = True
533
596
elif a == '--builtin':
534
597
opt_builtin = True
535
elif a in ('--quiet', '-q'):
537
elif a.startswith('-D'):
538
debug.debug_flags.add(a[2:])
545
from bzrlib.builtins import cmd_help
546
cmd_help().run_argv_aliases([])
602
if (not argv) or (argv[0] == '--help'):
603
from bzrlib.help import help
549
610
if argv[0] == '--version':
550
from bzrlib.version import show_version
611
from bzrlib.builtins import show_version
554
615
if not opt_no_plugins:
555
616
from bzrlib.plugin import load_plugins
558
from bzrlib.plugin import disable_plugins
563
if not opt_no_aliases:
564
alias_argv = get_alias(argv[0])
566
alias_argv = [a.decode(bzrlib.user_encoding) for a in alias_argv]
567
argv[0] = alias_argv.pop(0)
570
# We want only 'ascii' command names, but the user may have typed
571
# in a Unicode name. In that case, they should just get a
572
# 'command not found' error later.
619
cmd = str(argv.pop(0))
574
621
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
575
if not getattr(cmd_obj.run_argv, 'is_deprecated', False):
576
run = cmd_obj.run_argv
624
ret = apply_profiled(cmd_obj.run_argv, argv)
579
run = cmd_obj.run_argv_aliases
580
run_argv = [argv, alias_argv]
584
ret = apply_lsprofiled(opt_lsprof_file, run, *run_argv)
586
ret = apply_profiled(run, *run_argv)
591
# reset, in case we may do other commands later within the same process
592
trace.be_quiet(False)
594
def display_command(func):
595
"""Decorator that suppresses pipe/interrupt errors."""
596
def ignore_pipe(*args, **kwargs):
598
result = func(*args, **kwargs)
602
if getattr(e, 'errno', None) is None:
604
if e.errno != errno.EPIPE:
605
# Win32 raises IOError with errno=0 on a broken pipe
606
if sys.platform != 'win32' or e.errno != 0:
609
except KeyboardInterrupt:
626
ret = cmd_obj.run_argv(argv)
616
from bzrlib.ui.text import TextUIFactory
617
bzrlib.ui.ui_factory = TextUIFactory()
618
argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
619
ret = run_bzr_catch_errors(argv)
620
trace.mutter("return code %d", ret)
632
bzrlib.trace.log_startup(argv)
633
bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
635
return run_bzr_catch_errors(argv[1:])
624
638
def run_bzr_catch_errors(argv):
627
# do this here inside the exception wrappers to catch EPIPE
629
except (KeyboardInterrupt, Exception), e:
630
# used to handle AssertionError and KeyboardInterrupt
631
# specially here, but hopefully they're handled ok by the logger now
632
trace.report_exception(sys.exc_info(), sys.stderr)
633
if os.environ.get('BZR_PDB'):
634
print '**** entering debugger'
636
pdb.post_mortem(sys.exc_traceback)
643
# do this here inside the exception wrappers to catch EPIPE
645
except BzrCommandError, e:
646
# command line syntax error, etc
650
bzrlib.trace.log_exception()
652
except AssertionError, e:
653
bzrlib.trace.log_exception('assertion failed: ' + str(e))
655
except KeyboardInterrupt, e:
656
bzrlib.trace.log_exception('interrupted')
660
if (isinstance(e, IOError)
661
and hasattr(e, 'errno')
662
and e.errno == errno.EPIPE):
663
bzrlib.trace.note('broken pipe')
668
bzrlib.trace.log_exception()
639
671
if __name__ == '__main__':
640
672
sys.exit(main(sys.argv))