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
51
from bzrlib.symbol_versioning import (
58
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
64
def register_command(cmd, decorate=False):
65
"""Utility function to help register a command
67
:param cmd: Command subclass to register
68
:param decorate: If true, allow overriding an existing command
69
of the same name; the old command is returned by this function.
70
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"
74
49
if k.startswith("cmd_"):
75
50
k_unsquished = _unsquish_command_name(k)
78
if k_unsquished not in plugin_cmds:
79
plugin_cmds[k_unsquished] = cmd
80
## trace.mutter('registered plugin command %s', k_unsquished)
81
if decorate and k_unsquished in builtin_command_names():
82
return _builtin_commands()[k_unsquished]
84
result = plugin_cmds[k_unsquished]
85
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)
88
trace.log_error('Two plugins defined the same command: %r' % k)
89
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__])
92
61
def _squish_command_name(cmd):
98
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))
101
149
def _builtin_commands():
102
150
import bzrlib.builtins
104
152
builtins = bzrlib.builtins.__dict__
105
153
for name in builtins:
106
154
if name.startswith("cmd_"):
107
real_name = _unsquish_command_name(name)
155
real_name = _unsquish_command_name(name)
108
156
r[real_name] = builtins[name]
112
161
def builtin_command_names():
196
235
List of argument forms, marked with whether they are optional,
201
['to_location', 'from_branch?', 'file*']
203
'to_location' is required
204
'from_branch' is optional
205
'file' can be specified 0 or more times
208
List of options that may be given for this command. These can
209
be either strings, referring to globally-defined options,
210
or option objects. Retrieve through options().
239
List of options that may be given for this command.
213
242
If true, this command isn't advertised. This is typically
214
243
for commands intended for expert users.
217
Command objects will get a 'outf' attribute, which has been
218
setup to properly handle encoding of unicode strings.
219
encoding_type determines what will happen when characters cannot
221
strict - abort if we cannot decode
222
replace - put in a bogus character (typically '?')
223
exact - do not encode sys.stdout
225
NOTE: by default on Windows, sys.stdout is opened as a text
226
stream, therefore LF line-endings are converted to CRLF.
227
When a command uses encoding_type = 'exact', then
228
sys.stdout is forced to be a binary stream, and line-endings
234
248
takes_options = []
235
encoding_type = 'strict'
241
254
if self.__doc__ == Command.__doc__:
242
255
warn("No help message set for %r" % self)
244
def _maybe_expand_globs(self, file_list):
245
"""Glob expand file_list if the platform does not do that itself.
247
:return: A possibly empty list of unicode paths.
249
Introduced in bzrlib 0.18.
253
if sys.platform == 'win32':
254
file_list = win32utils.glob_expand(file_list)
255
return list(file_list)
258
"""Return single-line grammar for this command.
260
Only describes arguments, not options.
262
s = 'bzr ' + self.name() + ' '
263
for aname in self.takes_args:
264
aname = aname.upper()
265
if aname[-1] in ['$', '+']:
266
aname = aname[:-1] + '...'
267
elif aname[-1] == '?':
268
aname = '[' + aname[:-1] + ']'
269
elif aname[-1] == '*':
270
aname = '[' + aname[:-1] + '...]'
277
def get_help_text(self, additional_see_also=None):
278
"""Return a text string with help for this command.
280
:param additional_see_also: Additional help topics to be
285
raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
288
result += 'usage: %s\n' % self._usage()
291
result += 'aliases: '
292
result += ', '.join(self.aliases) + '\n'
296
plugin_name = self.plugin_name()
297
if plugin_name is not None:
298
result += '(From plugin "%s")' % plugin_name
302
if result[-1] != '\n':
305
result += option.get_optparser(self.options()).format_option_help()
306
see_also = self.get_see_also(additional_see_also)
308
result += '\nSee also: '
309
result += ', '.join(see_also)
313
def get_help_topic(self):
314
"""Return the commands help topic - its name."""
317
def get_see_also(self, additional_terms=None):
318
"""Return a list of help topics that are related to this ommand.
320
The list is derived from the content of the _see_also attribute. Any
321
duplicates are removed and the result is in lexical order.
322
:param additional_terms: Additional help topics to cross-reference.
323
:return: A list of help topics.
325
see_also = set(getattr(self, '_see_also', []))
327
see_also.update(additional_terms)
328
return sorted(see_also)
331
"""Return dict of valid options for this command.
333
Maps from long option name to option object."""
335
r['help'] = option._help_option
336
for o in self.takes_options:
337
if isinstance(o, basestring):
338
o = option.Option.OPTIONS[o]
342
def _setup_outf(self):
343
"""Return a file linked to stdout, which has proper encoding."""
344
assert self.encoding_type in ['strict', 'exact', 'replace']
346
# Originally I was using self.stdout, but that looks
347
# *way* too much like sys.stdout
348
if self.encoding_type == 'exact':
349
# force sys.stdout to be binary stream on win32
350
if sys.platform == 'win32':
351
fileno = getattr(sys.stdout, 'fileno', None)
354
msvcrt.setmode(fileno(), os.O_BINARY)
355
self.outf = sys.stdout
358
output_encoding = osutils.get_terminal_encoding()
360
# use 'replace' so that we don't abort if trying to write out
361
# in e.g. the default C locale.
362
self.outf = codecs.getwriter(output_encoding)(sys.stdout, errors=self.encoding_type)
363
# For whatever reason codecs.getwriter() does not advertise its encoding
364
# it just returns the encoding of the wrapped file, which is completely
365
# bogus. So set the attribute, so we can find the correct encoding later.
366
self.outf.encoding = output_encoding
368
def run_argv_aliases(self, argv, alias_argv=None):
369
"""Parse the command line and run with extra aliases in alias_argv."""
371
warn("Passing None for [] is deprecated from bzrlib 0.10",
372
DeprecationWarning, stacklevel=2)
374
args, opts = parse_args(self, argv, alias_argv)
258
def run_argv(self, argv):
259
"""Parse command line and run."""
260
args, opts = parse_args(argv)
375
262
if 'help' in opts: # e.g. bzr add --help
376
sys.stdout.write(self.get_help_text())
263
from bzrlib.help import help_on_command
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()))
378
274
# mix arguments and options into one dictionary
379
275
cmdargs = _match_argform(self.name(), self.takes_args, args)
457
337
parsed = [spec, None]
460
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
356
'revision': _parse_revision_str,
382
def parse_args(argv):
461
383
"""Parse command line.
463
385
Arguments and options are parsed at this level before being passed
464
386
down to specific command handlers. This routine knows, from a
465
387
lookup table, something about the available options, what optargs
466
388
they take, and which commands will accept them.
390
>>> parse_args('--help'.split())
392
>>> parse_args('help -- --invalidcmd'.split())
393
(['help', '--invalidcmd'], {})
394
>>> parse_args('--version'.split())
395
([], {'version': True})
396
>>> parse_args('status --all'.split())
397
(['status'], {'all': True})
398
>>> parse_args('commit --message=biter'.split())
399
(['commit'], {'message': u'biter'})
400
>>> parse_args('log -r 500'.split())
401
(['log'], {'revision': [<RevisionSpec_int 500>]})
402
>>> parse_args('log -r500..600'.split())
403
(['log'], {'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
404
>>> parse_args('log -vr500..600'.split())
405
(['log'], {'verbose': True, 'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
406
>>> parse_args('log -rrevno:500..600'.split()) #the r takes an argument
407
(['log'], {'revision': [<RevisionSpec_revno revno:500>, <RevisionSpec_int 600>]})
468
# TODO: make it a method of the Command?
469
parser = option.get_optparser(command.options())
470
if alias_argv is not None:
471
args = alias_argv + argv
475
options, args = parser.parse_args(args)
476
opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
477
v is not option.OptionParser.DEFAULT_VALUE])
415
if not argsover and a[0] == '-':
416
# option names must not be unicode
421
# We've received a standalone -- No more flags
424
mutter(" got option %r" % a)
426
optname, optarg = a[2:].split('=', 1)
429
if optname not in OPTIONS:
430
raise BzrError('unknown long option %r' % a)
433
if shortopt in SHORT_OPTIONS:
434
# Multi-character options must have a space to delimit
436
optname = SHORT_OPTIONS[shortopt]
438
# Single character short options, can be chained,
439
# and have their value appended to their name
441
if shortopt not in SHORT_OPTIONS:
442
# We didn't find the multi-character name, and we
443
# didn't find the single char name
444
raise BzrError('unknown short option %r' % a)
445
optname = SHORT_OPTIONS[shortopt]
448
# There are extra things on this option
449
# see if it is the value, or if it is another
451
optargfn = OPTIONS[optname]
453
# This option does not take an argument, so the
454
# next entry is another short option, pack it back
456
argv.insert(0, '-' + a[2:])
458
# This option takes an argument, so pack it
463
# XXX: Do we ever want to support this, e.g. for -r?
464
raise BzrError('repeated option %r' % a)
466
optargfn = OPTIONS[optname]
470
raise BzrError('option %r needs an argument' % a)
473
opts[optname] = optargfn(optarg)
476
raise BzrError('option %r takes no argument' % optname)
478
481
return args, opts
481
486
def _match_argform(cmd, takes_args, args):
495
500
argdict[argname + '_list'] = None
496
501
elif ap[-1] == '+':
498
raise errors.BzrCommandError("command %r needs one or more %s"
499
% (cmd, argname.upper()))
503
raise BzrCommandError("command %r needs one or more %s"
504
% (cmd, argname.upper()))
501
506
argdict[argname + '_list'] = args[:]
503
508
elif ap[-1] == '$': # all but one
504
509
if len(args) < 2:
505
raise errors.BzrCommandError("command %r needs one or more %s"
506
% (cmd, argname.upper()))
510
raise BzrCommandError("command %r needs one or more %s"
511
% (cmd, argname.upper()))
507
512
argdict[argname + '_list'] = args[:-1]
510
515
# just a plain arg
513
raise errors.BzrCommandError("command %r requires argument %s"
514
% (cmd, argname.upper()))
518
raise BzrCommandError("command %r requires argument %s"
519
% (cmd, argname.upper()))
516
521
argdict[argname] = args.pop(0)
519
raise errors.BzrCommandError("extra argument to command %s: %s"
524
raise BzrCommandError("extra argument to command %s: %s"
546
551
os.remove(pfname)
549
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
550
from bzrlib.lsprof import profile
551
ret, stats = profile(the_callable, *args, **kwargs)
557
trace.note('Profile data written to "%s".', filename)
561
def get_alias(cmd, config=None):
562
"""Return an expanded alias, or None if no alias exists.
565
Command to be checked for an alias.
567
Used to specify an alternative config to use,
568
which is especially useful for testing.
569
If it is unspecified, the global config will be used.
573
config = bzrlib.config.GlobalConfig()
574
alias = config.get_alias(cmd)
577
return [a.decode('utf-8') for a in shlex.split(alias.encode('utf-8'))]
581
554
def run_bzr(argv):
582
555
"""Execute a command.
598
569
Do not load plugin modules at all
604
572
Only use builtin commands. (Plugins are still allowed to change
605
573
other behaviour.)
608
Run under the Python hotshot profiler.
611
Run under the Python lsprof profiler.
576
Run under the Python profiler.
614
trace.mutter("bzr arguments: %r", argv)
578
# Load all of the transport methods
579
import bzrlib.transport.local, bzrlib.transport.http
581
argv = [a.decode(bzrlib.user_encoding) for a in argv]
616
opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = \
617
opt_no_aliases = False
618
opt_lsprof_file = None
583
opt_profile = opt_no_plugins = opt_builtin = False
620
585
# --no-plugins is handled specially at a very early stage. We need
621
586
# to load plugins before doing other command parsing so that they
622
587
# can override commands, but this needs to happen first.
628
590
if a == '--profile':
629
591
opt_profile = True
630
elif a == '--lsprof':
632
elif a == '--lsprof-file':
634
opt_lsprof_file = argv[i + 1]
636
592
elif a == '--no-plugins':
637
593
opt_no_plugins = True
638
elif a == '--no-aliases':
639
opt_no_aliases = True
640
594
elif a == '--builtin':
641
595
opt_builtin = True
642
elif a in ('--quiet', '-q'):
644
elif a.startswith('-D'):
645
debug.debug_flags.add(a[2:])
652
from bzrlib.builtins import cmd_help
653
cmd_help().run_argv_aliases([])
600
if (not argv) or (argv[0] == '--help'):
601
from bzrlib.help import help
656
608
if argv[0] == '--version':
657
from bzrlib.version import show_version
609
from bzrlib.builtins import show_version
661
613
if not opt_no_plugins:
662
614
from bzrlib.plugin import load_plugins
665
from bzrlib.plugin import disable_plugins
670
if not opt_no_aliases:
671
alias_argv = get_alias(argv[0])
673
alias_argv = [a.decode(bzrlib.user_encoding) for a in alias_argv]
674
argv[0] = alias_argv.pop(0)
677
# We want only 'ascii' command names, but the user may have typed
678
# in a Unicode name. In that case, they should just get a
679
# 'command not found' error later.
617
cmd = str(argv.pop(0))
681
619
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
682
run = cmd_obj.run_argv_aliases
683
run_argv = [argv, alias_argv]
687
ret = apply_lsprofiled(opt_lsprof_file, run, *run_argv)
689
ret = apply_profiled(run, *run_argv)
694
# reset, in case we may do other commands later within the same process
695
trace.be_quiet(False)
697
def display_command(func):
698
"""Decorator that suppresses pipe/interrupt errors."""
699
def ignore_pipe(*args, **kwargs):
701
result = func(*args, **kwargs)
705
if getattr(e, 'errno', None) is None:
707
if e.errno != errno.EPIPE:
708
# Win32 raises IOError with errno=0 on a broken pipe
709
if sys.platform != 'win32' or (e.errno not in (0, errno.EINVAL)):
712
except KeyboardInterrupt:
622
ret = apply_profiled(cmd_obj.run_argv, argv)
624
ret = cmd_obj.run_argv(argv)
719
from bzrlib.ui.text import TextUIFactory
720
bzrlib.ui.ui_factory = TextUIFactory()
721
argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
722
ret = run_bzr_catch_errors(argv)
723
trace.mutter("return code %d", ret)
630
bzrlib.trace.log_startup(argv)
631
bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
633
return run_bzr_catch_errors(argv[1:])
727
636
def run_bzr_catch_errors(argv):
730
except (KeyboardInterrupt, Exception), e:
731
# used to handle AssertionError and KeyboardInterrupt
732
# specially here, but hopefully they're handled ok by the logger now
733
trace.report_exception(sys.exc_info(), sys.stderr)
734
if os.environ.get('BZR_PDB'):
735
print '**** entering debugger'
737
pdb.post_mortem(sys.exc_traceback)
641
# do this here inside the exception wrappers to catch EPIPE
643
except BzrCommandError, e:
644
# command line syntax error, etc
648
bzrlib.trace.log_exception()
650
except AssertionError, e:
651
bzrlib.trace.log_exception('assertion failed: ' + str(e))
741
class HelpCommandIndex(object):
742
"""A index for bzr help that returns commands."""
745
self.prefix = 'commands/'
747
def get_topics(self, topic):
748
"""Search for topic amongst commands.
750
:param topic: A topic to search for.
751
:return: A list which is either empty or contains a single
754
if topic and topic.startswith(self.prefix):
755
topic = topic[len(self.prefix):]
757
cmd = _get_cmd_object(topic)
653
except KeyboardInterrupt, e:
654
bzrlib.trace.log_exception('interrupted')
658
if (isinstance(e, IOError)
659
and hasattr(e, 'errno')
660
and e.errno == errno.EPIPE):
661
bzrlib.trace.note('broken pipe')
666
bzrlib.trace.log_exception()
764
669
if __name__ == '__main__':
765
670
sys.exit(main(sys.argv))