1
# Copyright (C) 2006 by 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: Define arguments by objects, rather than just using names.
22
# 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.
28
# TODO: "--profile=cum", to change sort order. Is there any value in leaving
29
# the profile output behind so it can be interactively examined?
21
# TODO: Help messages for options.
23
# TODO: Define arguments by objects, rather than just using names.
24
# Those objects can specify the expected type of the argument, which
25
# would help with validation and shell completion.
28
# TODO: Help messages for options.
30
# TODO: Define arguments by objects, rather than just using names.
31
# Those objects can specify the expected type of the argument, which
32
# would help with validation and shell completion.
35
# TODO: Help messages for options.
37
# TODO: Define arguments by objects, rather than just using names.
38
# Those objects can specify the expected type of the argument, which
39
# would help with validation and shell completion.
34
45
from warnings import warn
46
from inspect import getdoc
38
import bzrlib.errors as errors
39
from bzrlib.errors import (BzrError,
43
from bzrlib import option
44
from bzrlib.option import Option
50
from bzrlib.trace import mutter, note, log_error, warning
51
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
46
52
from bzrlib.revisionspec import RevisionSpec
47
from bzrlib.symbol_versioning import (deprecated_method, zero_eight)
49
from bzrlib.trace import mutter, note, log_error, warning, be_quiet
53
from bzrlib import BZRDIR
54
def register_command(cmd, decorate=False):
55
"""Utility function to help register a command
57
:param cmd: Command subclass to register
58
:param decorate: If true, allow overriding an existing command
59
of the same name; the old command is returned by this function.
60
Otherwise it is an error to try to override an existing command.
58
def register_command(cmd):
59
"Utility function to help register a command"
64
62
if k.startswith("cmd_"):
88
80
return cmd[4:].replace('_','-')
83
def _parse_revision_str(revstr):
84
"""This handles a revision string -> revno.
86
This always returns a list. The list will have one element for
89
>>> _parse_revision_str('234')
90
[<RevisionSpec_int 234>]
91
>>> _parse_revision_str('234..567')
92
[<RevisionSpec_int 234>, <RevisionSpec_int 567>]
93
>>> _parse_revision_str('..')
94
[<RevisionSpec None>, <RevisionSpec None>]
95
>>> _parse_revision_str('..234')
96
[<RevisionSpec None>, <RevisionSpec_int 234>]
97
>>> _parse_revision_str('234..')
98
[<RevisionSpec_int 234>, <RevisionSpec None>]
99
>>> _parse_revision_str('234..456..789') # Maybe this should be an error
100
[<RevisionSpec_int 234>, <RevisionSpec_int 456>, <RevisionSpec_int 789>]
101
>>> _parse_revision_str('234....789') # Error?
102
[<RevisionSpec_int 234>, <RevisionSpec None>, <RevisionSpec_int 789>]
103
>>> _parse_revision_str('revid:test@other.com-234234')
104
[<RevisionSpec_revid revid:test@other.com-234234>]
105
>>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235')
106
[<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_revid revid:test@other.com-234235>]
107
>>> _parse_revision_str('revid:test@other.com-234234..23')
108
[<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_int 23>]
109
>>> _parse_revision_str('date:2005-04-12')
110
[<RevisionSpec_date date:2005-04-12>]
111
>>> _parse_revision_str('date:2005-04-12 12:24:33')
112
[<RevisionSpec_date date:2005-04-12 12:24:33>]
113
>>> _parse_revision_str('date:2005-04-12T12:24:33')
114
[<RevisionSpec_date date:2005-04-12T12:24:33>]
115
>>> _parse_revision_str('date:2005-04-12,12:24:33')
116
[<RevisionSpec_date date:2005-04-12,12:24:33>]
117
>>> _parse_revision_str('-5..23')
118
[<RevisionSpec_int -5>, <RevisionSpec_int 23>]
119
>>> _parse_revision_str('-5')
120
[<RevisionSpec_int -5>]
121
>>> _parse_revision_str('123a')
122
Traceback (most recent call last):
124
BzrError: No namespace registered for string: '123a'
125
>>> _parse_revision_str('abc')
126
Traceback (most recent call last):
128
BzrError: No namespace registered for string: 'abc'
131
old_format_re = re.compile('\d*:\d*')
132
m = old_format_re.match(revstr)
135
warning('Colon separator for revision numbers is deprecated.'
137
for rev in revstr.split(':'):
139
revs.append(RevisionSpec(int(rev)))
141
revs.append(RevisionSpec(None))
143
for x in revstr.split('..'):
145
revs.append(RevisionSpec(None))
147
revs.append(RevisionSpec(x))
91
151
def _builtin_commands():
92
152
import bzrlib.builtins
94
154
builtins = bzrlib.builtins.__dict__
95
155
for name in builtins:
96
156
if name.startswith("cmd_"):
97
real_name = _unsquish_command_name(name)
157
real_name = _unsquish_command_name(name)
98
158
r[real_name] = builtins[name]
102
163
def builtin_command_names():
176
237
List of argument forms, marked with whether they are optional,
181
['to_location', 'from_branch?', 'file*']
183
'to_location' is required
184
'from_branch' is optional
185
'file' can be specified 0 or more times
188
List of options that may be given for this command. These can
189
be either strings, referring to globally-defined options,
190
or option objects. Retrieve through options().
241
List of options that may be given for this command.
193
244
If true, this command isn't advertised. This is typically
194
245
for commands intended for expert users.
197
Command objects will get a 'outf' attribute, which has been
198
setup to properly handle encoding of unicode strings.
199
encoding_type determines what will happen when characters cannot
201
strict - abort if we cannot decode
202
replace - put in a bogus character (typically '?')
203
exact - do not encode sys.stdout
208
250
takes_options = []
209
encoding_type = 'strict'
215
256
if self.__doc__ == Command.__doc__:
216
257
warn("No help message set for %r" % self)
219
"""Return dict of valid options for this command.
221
Maps from long option name to option object."""
223
r['help'] = Option.OPTIONS['help']
224
for o in self.takes_options:
225
if isinstance(o, basestring):
226
o = Option.OPTIONS[o]
230
def _setup_outf(self):
231
"""Return a file linked to stdout, which has proper encoding."""
232
assert self.encoding_type in ['strict', 'exact', 'replace']
234
# Originally I was using self.stdout, but that looks
235
# *way* too much like sys.stdout
236
if self.encoding_type == 'exact':
237
self.outf = sys.stdout
240
output_encoding = bzrlib.osutils.get_terminal_encoding()
242
# use 'replace' so that we don't abort if trying to write out
243
# in e.g. the default C locale.
244
self.outf = codecs.getwriter(output_encoding)(sys.stdout, errors=self.encoding_type)
245
# For whatever reason codecs.getwriter() does not advertise its encoding
246
# it just returns the encoding of the wrapped file, which is completely
247
# bogus. So set the attribute, so we can find the correct encoding later.
248
self.outf.encoding = output_encoding
250
@deprecated_method(zero_eight)
251
260
def run_argv(self, argv):
252
"""Parse command line and run.
254
See run_argv_aliases for the 0.8 and beyond api.
256
return self.run_argv_aliases(argv)
261
"""Parse command line and run."""
262
args, opts = parse_args(argv)
258
def run_argv_aliases(self, argv, alias_argv=None):
259
"""Parse the command line and run with extra aliases in alias_argv."""
261
warn("Passing None for [] is deprecated from bzrlib 0.10",
262
DeprecationWarning, stacklevel=2)
264
args, opts = parse_args(self, argv, alias_argv)
265
264
if 'help' in opts: # e.g. bzr add --help
266
265
from bzrlib.help import help_on_command
267
266
help_on_command(self.name())
269
# check options are reasonable
270
allowed = self.takes_options
272
if oname not in allowed:
273
raise BzrCommandError("option '--%s' is not allowed for command %r"
274
% (oname, self.name()))
269
276
# mix arguments and options into one dictionary
270
277
cmdargs = _match_argform(self.name(), self.takes_args, args)
345
339
parsed = [spec, None]
348
def parse_args(command, argv, alias_argv=None):
343
# list of all available options; the rhs can be either None for an
344
# option that takes no argument, or a constructor function that checks
358
'revision': _parse_revision_str,
383
def parse_args(argv):
349
384
"""Parse command line.
351
386
Arguments and options are parsed at this level before being passed
352
387
down to specific command handlers. This routine knows, from a
353
388
lookup table, something about the available options, what optargs
354
389
they take, and which commands will accept them.
391
>>> parse_args('--help'.split())
393
>>> parse_args('help -- --invalidcmd'.split())
394
(['help', '--invalidcmd'], {})
395
>>> parse_args('--version'.split())
396
([], {'version': True})
397
>>> parse_args('status --all'.split())
398
(['status'], {'all': True})
399
>>> parse_args('commit --message=biter'.split())
400
(['commit'], {'message': u'biter'})
401
>>> parse_args('log -r 500'.split())
402
(['log'], {'revision': [<RevisionSpec_int 500>]})
403
>>> parse_args('log -r500..600'.split())
404
(['log'], {'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
405
>>> parse_args('log -vr500..600'.split())
406
(['log'], {'verbose': True, 'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
407
>>> parse_args('log -rrevno:500..600'.split()) #the r takes an argument
408
(['log'], {'revision': [<RevisionSpec_revno revno:500>, <RevisionSpec_int 600>]})
356
# TODO: make it a method of the Command?
357
parser = option.get_optparser(command.options())
358
if alias_argv is not None:
359
args = alias_argv + argv
363
options, args = parser.parse_args(args)
364
opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
365
v is not option.OptionParser.DEFAULT_VALUE])
416
if not argsover and a[0] == '-':
417
# option names must not be unicode
422
# We've received a standalone -- No more flags
425
mutter(" got option %r" % a)
427
optname, optarg = a[2:].split('=', 1)
430
if optname not in OPTIONS:
431
raise BzrError('unknown long option %r' % a)
434
if shortopt in SHORT_OPTIONS:
435
# Multi-character options must have a space to delimit
437
optname = SHORT_OPTIONS[shortopt]
439
# Single character short options, can be chained,
440
# and have their value appended to their name
442
if shortopt not in SHORT_OPTIONS:
443
# We didn't find the multi-character name, and we
444
# didn't find the single char name
445
raise BzrError('unknown short option %r' % a)
446
optname = SHORT_OPTIONS[shortopt]
449
# There are extra things on this option
450
# see if it is the value, or if it is another
452
optargfn = OPTIONS[optname]
454
# This option does not take an argument, so the
455
# next entry is another short option, pack it back
457
argv.insert(0, '-' + a[2:])
459
# This option takes an argument, so pack it
464
# XXX: Do we ever want to support this, e.g. for -r?
465
raise BzrError('repeated option %r' % a)
467
optargfn = OPTIONS[optname]
471
raise BzrError('option %r needs an argument' % a)
474
opts[optname] = optargfn(optarg)
477
raise BzrError('option %r takes no argument' % optname)
366
482
return args, opts
369
487
def _match_argform(cmd, takes_args, args):
422
539
ret = prof.runcall(the_callable, *args, **kwargs) or 0
425
544
stats = hotshot.stats.load(pfname)
427
stats.sort_stats('cum') # 'time'
546
stats.sort_stats('time')
428
547
## XXX: Might like to write to stderr or the trace file instead but
429
548
## print_stats seems hardcoded to stdout
430
549
stats.print_stats(20)
433
553
os.close(pffileno)
434
554
os.remove(pfname)
437
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
438
from bzrlib.lsprof import profile
440
ret, stats = profile(the_callable, *args, **kwargs)
446
cPickle.dump(stats, open(filename, 'w'), 2)
447
print 'Profile data written to %r.' % filename
452
"""Return an expanded alias, or None if no alias exists"""
454
alias = bzrlib.config.GlobalConfig().get_alias(cmd)
456
return alias.split(' ')
460
557
def run_bzr(argv):
461
558
"""Execute a command.
477
572
Do not load plugin modules at all
483
575
Only use builtin commands. (Plugins are still allowed to change
484
576
other behaviour.)
487
Run under the Python hotshot profiler.
490
Run under the Python lsprof profiler.
579
Run under the Python profiler.
581
# Load all of the transport methods
582
import bzrlib.transport.local, bzrlib.transport.http
584
argv = [a.decode(bzrlib.user_encoding) for a in argv]
494
opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = \
495
opt_no_aliases = False
496
opt_lsprof_file = None
586
opt_profile = opt_no_plugins = opt_builtin = False
498
588
# --no-plugins is handled specially at a very early stage. We need
499
589
# to load plugins before doing other command parsing so that they
500
590
# can override commands, but this needs to happen first.
506
593
if a == '--profile':
507
594
opt_profile = True
508
elif a == '--lsprof':
510
elif a == '--lsprof-file':
512
opt_lsprof_file = argv[i + 1]
514
595
elif a == '--no-plugins':
515
596
opt_no_plugins = True
516
elif a == '--no-aliases':
517
opt_no_aliases = True
518
597
elif a == '--builtin':
519
598
opt_builtin = True
520
elif a in ('--quiet', '-q'):
528
from bzrlib.builtins import cmd_help
529
cmd_help().run_argv_aliases([])
603
if (not argv) or (argv[0] == '--help'):
604
from bzrlib.help import help
532
611
if argv[0] == '--version':
533
from bzrlib.version import show_version
612
from bzrlib.builtins import show_version
537
616
if not opt_no_plugins:
538
617
from bzrlib.plugin import load_plugins
541
from bzrlib.plugin import disable_plugins
546
if not opt_no_aliases:
547
alias_argv = get_alias(argv[0])
549
alias_argv = [a.decode(bzrlib.user_encoding) for a in alias_argv]
550
argv[0] = alias_argv.pop(0)
552
620
cmd = str(argv.pop(0))
554
622
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
555
if not getattr(cmd_obj.run_argv, 'is_deprecated', False):
556
run = cmd_obj.run_argv
625
ret = apply_profiled(cmd_obj.run_argv, argv)
559
run = cmd_obj.run_argv_aliases
560
run_argv = [argv, alias_argv]
564
ret = apply_lsprofiled(opt_lsprof_file, run, *run_argv)
566
ret = apply_profiled(run, *run_argv)
571
# reset, in case we may do other commands later within the same process
574
def display_command(func):
575
"""Decorator that suppresses pipe/interrupt errors."""
576
def ignore_pipe(*args, **kwargs):
578
result = func(*args, **kwargs)
582
if not hasattr(e, 'errno'):
584
if e.errno != errno.EPIPE:
585
# Win32 raises IOError with errno=0 on a broken pipe
586
if sys.platform != 'win32' or e.errno != 0:
589
except KeyboardInterrupt:
627
ret = cmd_obj.run_argv(argv)
596
from bzrlib.ui.text import TextUIFactory
597
bzrlib.ui.ui_factory = TextUIFactory()
598
argv = [a.decode(bzrlib.user_encoding) for a in argv[1:]]
599
ret = run_bzr_catch_errors(argv)
600
mutter("return code %d", ret)
633
bzrlib.trace.log_startup(argv)
634
bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
636
return run_bzr_catch_errors(argv[1:])
604
639
def run_bzr_catch_errors(argv):
607
# do this here inside the exception wrappers to catch EPIPE
645
# do this here inside the exception wrappers to catch EPIPE
647
#wrap common errors as CommandErrors.
648
except (NotBranchError,), e:
649
raise BzrCommandError(str(e))
650
except BzrCommandError, e:
651
# command line syntax error, etc
655
bzrlib.trace.log_exception()
657
except AssertionError, e:
658
bzrlib.trace.log_exception('assertion failed: ' + str(e))
660
except KeyboardInterrupt, e:
661
bzrlib.trace.log_exception('interrupted')
609
663
except Exception, e:
610
# used to handle AssertionError and KeyboardInterrupt
611
# specially here, but hopefully they're handled ok by the logger now
612
bzrlib.trace.report_exception(sys.exc_info(), sys.stderr)
613
if os.environ.get('BZR_PDB'):
614
print '**** entering debugger'
616
pdb.post_mortem(sys.exc_traceback)
665
if (isinstance(e, IOError)
666
and hasattr(e, 'errno')
667
and e.errno == errno.EPIPE):
668
bzrlib.trace.note('broken pipe')
671
bzrlib.trace.log_exception()
619
674
if __name__ == '__main__':
620
675
sys.exit(main(sys.argv))