1
# Copyright (C) 2006, 2008 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
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
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.
34
from bzrlib.lazy_import import lazy_import
35
lazy_import(globals(), """
38
38
from warnings import warn
39
from inspect import getdoc
51
from bzrlib import registry
53
from bzrlib.hooks import HookPoint, Hooks
54
from bzrlib.option import Option
57
class CommandInfo(object):
58
"""Information about a command."""
60
def __init__(self, aliases):
61
"""The list of aliases for the command."""
62
self.aliases = aliases
65
def from_command(klass, command):
66
"""Factory to construct a CommandInfo from a command."""
67
return klass(command.aliases)
70
class CommandRegistry(registry.Registry):
73
def _get_name(command_name):
74
if command_name.startswith("cmd_"):
75
return _unsquish_command_name(command_name)
79
def register(self, cmd, decorate=False):
80
"""Utility function to help register a command
82
:param cmd: Command subclass to register
83
:param decorate: If true, allow overriding an existing command
84
of the same name; the old command is returned by this function.
85
Otherwise it is an error to try to override an existing command.
88
k_unsquished = self._get_name(k)
90
previous = self.get(k_unsquished)
92
previous = _builtin_commands().get(k_unsquished)
93
info = CommandInfo.from_command(cmd)
95
registry.Registry.register(self, k_unsquished, cmd,
96
override_existing=decorate, info=info)
98
trace.log_error('Two plugins defined the same command: %r' % k)
99
trace.log_error('Not loading the one in %r' %
100
sys.modules[cmd.__module__])
101
trace.log_error('Previously this command was registered from %r' %
102
sys.modules[previous.__module__])
105
def register_lazy(self, command_name, aliases, module_name):
106
"""Register a command without loading its module.
108
:param command_name: The primary name of the command.
109
:param aliases: A list of aliases for the command.
110
:module_name: The module that the command lives in.
112
key = self._get_name(command_name)
113
registry.Registry.register_lazy(self, key, module_name, command_name,
114
info=CommandInfo(aliases))
117
plugin_cmds = CommandRegistry()
120
def register_command(cmd, decorate=False):
43
from bzrlib.trace import mutter, note, log_error, warning
44
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
45
from bzrlib.branch import find_branch
46
from bzrlib import BZRDIR
51
def register_command(cmd):
52
"Utility function to help register a command"
121
53
global plugin_cmds
122
return plugin_cmds.register(cmd, decorate)
55
if k.startswith("cmd_"):
56
k_unsquished = _unsquish_command_name(k)
59
if not plugin_cmds.has_key(k_unsquished):
60
plugin_cmds[k_unsquished] = cmd
61
mutter('registered plugin command %s', k_unsquished)
63
log_error('Two plugins defined the same command: %r' % k)
64
log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
125
67
def _squish_command_name(cmd):
129
71
def _unsquish_command_name(cmd):
72
assert cmd.startswith("cmd_")
130
73
return cmd[4:].replace('_','-')
76
def _parse_revision_str(revstr):
77
"""This handles a revision string -> revno.
79
This always returns a list. The list will have one element for
81
It supports integers directly, but everything else it
82
defers for passing to Branch.get_revision_info()
84
>>> _parse_revision_str('234')
86
>>> _parse_revision_str('234..567')
88
>>> _parse_revision_str('..')
90
>>> _parse_revision_str('..234')
92
>>> _parse_revision_str('234..')
94
>>> _parse_revision_str('234..456..789') # Maybe this should be an error
96
>>> _parse_revision_str('234....789') # Error?
98
>>> _parse_revision_str('revid:test@other.com-234234')
99
['revid:test@other.com-234234']
100
>>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235')
101
['revid:test@other.com-234234', 'revid:test@other.com-234235']
102
>>> _parse_revision_str('revid:test@other.com-234234..23')
103
['revid:test@other.com-234234', 23]
104
>>> _parse_revision_str('date:2005-04-12')
106
>>> _parse_revision_str('date:2005-04-12 12:24:33')
107
['date:2005-04-12 12:24:33']
108
>>> _parse_revision_str('date:2005-04-12T12:24:33')
109
['date:2005-04-12T12:24:33']
110
>>> _parse_revision_str('date:2005-04-12,12:24:33')
111
['date:2005-04-12,12:24:33']
112
>>> _parse_revision_str('-5..23')
114
>>> _parse_revision_str('-5')
116
>>> _parse_revision_str('123a')
118
>>> _parse_revision_str('abc')
122
old_format_re = re.compile('\d*:\d*')
123
m = old_format_re.match(revstr)
125
warning('Colon separator for revision numbers is deprecated.'
128
for rev in revstr.split(':'):
130
revs.append(int(rev))
135
for x in revstr.split('..'):
146
def get_merge_type(typestring):
147
"""Attempt to find the merge class/factory associated with a string."""
148
from merge import merge_types
150
return merge_types[typestring][0]
152
templ = '%s%%7s: %%s' % (' '*12)
153
lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
154
type_list = '\n'.join(lines)
155
msg = "No known merge type %s. Supported types are:\n%s" %\
156
(typestring, type_list)
157
raise BzrCommandError(msg)
133
160
def _builtin_commands():
134
161
import bzrlib.builtins
136
163
builtins = bzrlib.builtins.__dict__
137
164
for name in builtins:
138
165
if name.startswith("cmd_"):
139
real_name = _unsquish_command_name(name)
166
real_name = _unsquish_command_name(name)
140
167
r[real_name] = builtins[name]
144
172
def builtin_command_names():
145
173
"""Return list of builtin command names."""
146
174
return _builtin_commands().keys()
149
177
def plugin_command_names():
150
178
return plugin_cmds.keys()
251
246
List of argument forms, marked with whether they are optional,
256
['to_location', 'from_branch?', 'file*']
258
'to_location' is required
259
'from_branch' is optional
260
'file' can be specified 0 or more times
263
List of options that may be given for this command. These can
264
be either strings, referring to globally-defined options,
265
or option objects. Retrieve through options().
250
List of options that may be given for this command.
268
253
If true, this command isn't advertised. This is typically
269
254
for commands intended for expert users.
272
Command objects will get a 'outf' attribute, which has been
273
setup to properly handle encoding of unicode strings.
274
encoding_type determines what will happen when characters cannot
276
strict - abort if we cannot decode
277
replace - put in a bogus character (typically '?')
278
exact - do not encode sys.stdout
280
NOTE: by default on Windows, sys.stdout is opened as a text
281
stream, therefore LF line-endings are converted to CRLF.
282
When a command uses encoding_type = 'exact', then
283
sys.stdout is forced to be a binary stream, and line-endings
286
:cvar hooks: An instance of CommandHooks.
290
259
takes_options = []
291
encoding_type = 'strict'
295
263
def __init__(self):
296
264
"""Construct an instance of this command."""
297
265
if self.__doc__ == Command.__doc__:
298
266
warn("No help message set for %r" % self)
299
# List of standard options directly supported
300
self.supported_std_options = []
302
def _maybe_expand_globs(self, file_list):
303
"""Glob expand file_list if the platform does not do that itself.
305
:return: A possibly empty list of unicode paths.
307
Introduced in bzrlib 0.18.
311
if sys.platform == 'win32':
312
file_list = win32utils.glob_expand(file_list)
313
return list(file_list)
316
"""Return single-line grammar for this command.
318
Only describes arguments, not options.
320
s = 'bzr ' + self.name() + ' '
321
for aname in self.takes_args:
322
aname = aname.upper()
323
if aname[-1] in ['$', '+']:
324
aname = aname[:-1] + '...'
325
elif aname[-1] == '?':
326
aname = '[' + aname[:-1] + ']'
327
elif aname[-1] == '*':
328
aname = '[' + aname[:-1] + '...]'
330
s = s[:-1] # remove last space
333
def get_help_text(self, additional_see_also=None, plain=True,
334
see_also_as_links=False, verbose=True):
335
"""Return a text string with help for this command.
337
:param additional_see_also: Additional help topics to be
339
:param plain: if False, raw help (reStructuredText) is
340
returned instead of plain text.
341
:param see_also_as_links: if True, convert items in 'See also'
342
list to internal links (used by bzr_man rstx generator)
343
:param verbose: if True, display the full help, otherwise
344
leave out the descriptive sections and just display
345
usage help (e.g. Purpose, Usage, Options) with a
346
message explaining how to obtain full help.
350
raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
352
# Extract the summary (purpose) and sections out from the text
353
purpose,sections,order = self._get_help_parts(doc)
355
# If a custom usage section was provided, use it
356
if sections.has_key('Usage'):
357
usage = sections.pop('Usage')
359
usage = self._usage()
361
# The header is the purpose and usage
363
result += ':Purpose: %s\n' % purpose
364
if usage.find('\n') >= 0:
365
result += ':Usage:\n%s\n' % usage
367
result += ':Usage: %s\n' % usage
371
options = option.get_optparser(self.options()).format_option_help()
372
if options.startswith('Options:'):
373
result += ':' + options
374
elif options.startswith('options:'):
375
# Python 2.4 version of optparse
376
result += ':Options:' + options[len('options:'):]
382
# Add the description, indenting it 2 spaces
383
# to match the indentation of the options
384
if sections.has_key(None):
385
text = sections.pop(None)
386
text = '\n '.join(text.splitlines())
387
result += ':%s:\n %s\n\n' % ('Description',text)
389
# Add the custom sections (e.g. Examples). Note that there's no need
390
# to indent these as they must be indented already in the source.
393
if sections.has_key(label):
394
result += ':%s:\n%s\n' % (label,sections[label])
397
result += ("See bzr help %s for more details and examples.\n\n"
400
# Add the aliases, source (plug-in) and see also links, if any
402
result += ':Aliases: '
403
result += ', '.join(self.aliases) + '\n'
404
plugin_name = self.plugin_name()
405
if plugin_name is not None:
406
result += ':From: plugin "%s"\n' % plugin_name
407
see_also = self.get_see_also(additional_see_also)
409
if not plain and see_also_as_links:
411
for item in see_also:
413
# topics doesn't have an independent section
414
# so don't create a real link
415
see_also_links.append(item)
417
# Use a reST link for this entry
418
see_also_links.append("`%s`_" % (item,))
419
see_also = see_also_links
420
result += ':See also: '
421
result += ', '.join(see_also) + '\n'
423
# If this will be rendered as plain text, convert it
425
import bzrlib.help_topics
426
result = bzrlib.help_topics.help_as_plain_text(result)
430
def _get_help_parts(text):
431
"""Split help text into a summary and named sections.
433
:return: (summary,sections,order) where summary is the top line and
434
sections is a dictionary of the rest indexed by section name.
435
order is the order the section appear in the text.
436
A section starts with a heading line of the form ":xxx:".
437
Indented text on following lines is the section value.
438
All text found outside a named section is assigned to the
439
default section which is given the key of None.
441
def save_section(sections, order, label, section):
443
if sections.has_key(label):
444
sections[label] += '\n' + section
447
sections[label] = section
449
lines = text.rstrip().splitlines()
450
summary = lines.pop(0)
453
label,section = None,''
455
if line.startswith(':') and line.endswith(':') and len(line) > 2:
456
save_section(sections, order, label, section)
457
label,section = line[1:-1],''
458
elif (label is not None) and len(line) > 1 and not line[0].isspace():
459
save_section(sections, order, label, section)
460
label,section = None,line
463
section += '\n' + line
466
save_section(sections, order, label, section)
467
return summary, sections, order
469
def get_help_topic(self):
470
"""Return the commands help topic - its name."""
473
def get_see_also(self, additional_terms=None):
474
"""Return a list of help topics that are related to this command.
476
The list is derived from the content of the _see_also attribute. Any
477
duplicates are removed and the result is in lexical order.
478
:param additional_terms: Additional help topics to cross-reference.
479
:return: A list of help topics.
481
see_also = set(getattr(self, '_see_also', []))
483
see_also.update(additional_terms)
484
return sorted(see_also)
487
"""Return dict of valid options for this command.
489
Maps from long option name to option object."""
490
r = Option.STD_OPTIONS.copy()
492
for o in self.takes_options:
493
if isinstance(o, basestring):
494
o = option.Option.OPTIONS[o]
496
if o.name in std_names:
497
self.supported_std_options.append(o.name)
500
def _setup_outf(self):
501
"""Return a file linked to stdout, which has proper encoding."""
502
# Originally I was using self.stdout, but that looks
503
# *way* too much like sys.stdout
504
if self.encoding_type == 'exact':
505
# force sys.stdout to be binary stream on win32
506
if sys.platform == 'win32':
507
fileno = getattr(sys.stdout, 'fileno', None)
510
msvcrt.setmode(fileno(), os.O_BINARY)
511
self.outf = sys.stdout
514
output_encoding = osutils.get_terminal_encoding()
516
self.outf = codecs.getwriter(output_encoding)(sys.stdout,
517
errors=self.encoding_type)
518
# For whatever reason codecs.getwriter() does not advertise its encoding
519
# it just returns the encoding of the wrapped file, which is completely
520
# bogus. So set the attribute, so we can find the correct encoding later.
521
self.outf.encoding = output_encoding
523
def run_argv_aliases(self, argv, alias_argv=None):
524
"""Parse the command line and run with extra aliases in alias_argv."""
526
warn("Passing None for [] is deprecated from bzrlib 0.10",
527
DeprecationWarning, stacklevel=2)
529
args, opts = parse_args(self, argv, alias_argv)
531
# Process the standard options
269
def run_argv(self, argv):
270
"""Parse command line and run."""
271
args, opts = parse_args(argv)
532
273
if 'help' in opts: # e.g. bzr add --help
533
sys.stdout.write(self.get_help_text())
535
if 'usage' in opts: # e.g. bzr add --usage
536
sys.stdout.write(self.get_help_text(verbose=False))
538
trace.set_verbosity_level(option._verbosity_level)
539
if 'verbose' in self.supported_std_options:
540
opts['verbose'] = trace.is_verbose()
541
elif opts.has_key('verbose'):
543
if 'quiet' in self.supported_std_options:
544
opts['quiet'] = trace.is_quiet()
545
elif opts.has_key('quiet'):
274
from bzrlib.help import help_on_command
275
help_on_command(self.name())
278
# check options are reasonable
279
allowed = self.takes_options
281
if oname not in allowed:
282
raise BzrCommandError("option '--%s' is not allowed for command %r"
283
% (oname, self.name()))
548
285
# mix arguments and options into one dictionary
549
286
cmdargs = _match_argform(self.name(), self.takes_args, args)
582
317
return _unsquish_command_name(self.__class__.__name__)
584
def plugin_name(self):
585
"""Get the name of the plugin that provides this command.
587
:return: The name of the plugin or None if the command is builtin.
589
mod_parts = self.__module__.split('.')
590
if len(mod_parts) >= 3 and mod_parts[1] == 'plugins':
320
def parse_spec(spec):
326
>>> parse_spec("../@")
328
>>> parse_spec("../f/@35")
330
>>> parse_spec('./@revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67')
331
['.', 'revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67']
336
parsed = spec.split('/@')
337
assert len(parsed) == 2
596
class CommandHooks(Hooks):
597
"""Hooks related to Command object creation/enumeration."""
600
"""Create the default hooks.
602
These are all empty initially, because by default nothing should get
606
self.create_hook(HookPoint('extend_command',
607
"Called after creating a command object to allow modifications "
608
"such as adding or removing options, docs etc. Called with the "
609
"new bzrlib.commands.Command object.", (1, 13), None))
611
Command.hooks = CommandHooks()
614
def parse_args(command, argv, alias_argv=None):
342
parsed[1] = int(parsed[1])
344
pass # We can allow stuff like ./@revid:blahblahblah
348
parsed = [spec, None]
352
# list of all available options; the rhs can be either None for an
353
# option that takes no argument, or a constructor function that checks
366
'revision': _parse_revision_str,
378
'merge-type': get_merge_type,
392
def parse_args(argv):
615
393
"""Parse command line.
617
395
Arguments and options are parsed at this level before being passed
618
396
down to specific command handlers. This routine knows, from a
619
397
lookup table, something about the available options, what optargs
620
398
they take, and which commands will accept them.
400
>>> parse_args('--help'.split())
402
>>> parse_args('help -- --invalidcmd'.split())
403
(['help', '--invalidcmd'], {})
404
>>> parse_args('--version'.split())
405
([], {'version': True})
406
>>> parse_args('status --all'.split())
407
(['status'], {'all': True})
408
>>> parse_args('commit --message=biter'.split())
409
(['commit'], {'message': u'biter'})
410
>>> parse_args('log -r 500'.split())
411
(['log'], {'revision': [500]})
412
>>> parse_args('log -r500..600'.split())
413
(['log'], {'revision': [500, 600]})
414
>>> parse_args('log -vr500..600'.split())
415
(['log'], {'verbose': True, 'revision': [500, 600]})
416
>>> parse_args('log -rv500..600'.split()) #the r takes an argument
417
(['log'], {'revision': ['v500', 600]})
622
# TODO: make it a method of the Command?
623
parser = option.get_optparser(command.options())
624
if alias_argv is not None:
625
args = alias_argv + argv
629
options, args = parser.parse_args(args)
630
opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
631
v is not option.OptionParser.DEFAULT_VALUE])
425
if not argsover and a[0] == '-':
426
# option names must not be unicode
431
# We've received a standalone -- No more flags
434
mutter(" got option %r" % a)
436
optname, optarg = a[2:].split('=', 1)
439
if optname not in OPTIONS:
440
raise BzrError('unknown long option %r' % a)
443
if shortopt in SHORT_OPTIONS:
444
# Multi-character options must have a space to delimit
446
optname = SHORT_OPTIONS[shortopt]
448
# Single character short options, can be chained,
449
# and have their value appended to their name
451
if shortopt not in SHORT_OPTIONS:
452
# We didn't find the multi-character name, and we
453
# didn't find the single char name
454
raise BzrError('unknown short option %r' % a)
455
optname = SHORT_OPTIONS[shortopt]
458
# There are extra things on this option
459
# see if it is the value, or if it is another
461
optargfn = OPTIONS[optname]
463
# This option does not take an argument, so the
464
# next entry is another short option, pack it back
466
argv.insert(0, '-' + a[2:])
468
# This option takes an argument, so pack it
473
# XXX: Do we ever want to support this, e.g. for -r?
474
raise BzrError('repeated option %r' % a)
476
optargfn = OPTIONS[optname]
480
raise BzrError('option %r needs an argument' % a)
483
opts[optname] = optargfn(optarg)
486
raise BzrError('option %r takes no argument' % optname)
632
491
return args, opts
635
496
def _match_argform(cmd, takes_args, args):
649
510
argdict[argname + '_list'] = None
650
511
elif ap[-1] == '+':
652
raise errors.BzrCommandError("command %r needs one or more %s"
653
% (cmd, argname.upper()))
513
raise BzrCommandError("command %r needs one or more %s"
514
% (cmd, argname.upper()))
655
516
argdict[argname + '_list'] = args[:]
657
518
elif ap[-1] == '$': # all but one
658
519
if len(args) < 2:
659
raise errors.BzrCommandError("command %r needs one or more %s"
660
% (cmd, argname.upper()))
520
raise BzrCommandError("command %r needs one or more %s"
521
% (cmd, argname.upper()))
661
522
argdict[argname + '_list'] = args[:-1]
664
525
# just a plain arg
667
raise errors.BzrCommandError("command %r requires argument %s"
668
% (cmd, argname.upper()))
528
raise BzrCommandError("command %r requires argument %s"
529
% (cmd, argname.upper()))
670
531
argdict[argname] = args.pop(0)
673
raise errors.BzrCommandError("extra argument to command %s: %s"
534
raise BzrCommandError("extra argument to command %s: %s"
678
def apply_coveraged(dirname, the_callable, *args, **kwargs):
679
# Cannot use "import trace", as that would import bzrlib.trace instead of
680
# the standard library's trace.
681
trace = __import__('trace')
683
tracer = trace.Trace(count=1, trace=0)
684
sys.settrace(tracer.globaltrace)
687
return exception_to_return_code(the_callable, *args, **kwargs)
690
results = tracer.results()
691
results.write_results(show_missing=1, summary=False,
695
541
def apply_profiled(the_callable, *args, **kwargs):
699
544
pffileno, pfname = tempfile.mkstemp()
701
546
prof = hotshot.Profile(pfname)
703
ret = prof.runcall(exception_to_return_code, the_callable, *args,
548
ret = prof.runcall(the_callable, *args, **kwargs) or 0
707
553
stats = hotshot.stats.load(pfname)
709
stats.sort_stats('cum') # 'time'
555
stats.sort_stats('time')
710
556
## XXX: Might like to write to stderr or the trace file instead but
711
557
## print_stats seems hardcoded to stdout
712
558
stats.print_stats(20)
715
562
os.close(pffileno)
716
563
os.remove(pfname)
719
def exception_to_return_code(the_callable, *args, **kwargs):
720
"""UI level helper for profiling and coverage.
722
This transforms exceptions into a return value of 3. As such its only
723
relevant to the UI layer, and should never be called where catching
724
exceptions may be desirable.
727
return the_callable(*args, **kwargs)
728
except (KeyboardInterrupt, Exception), e:
729
# used to handle AssertionError and KeyboardInterrupt
730
# specially here, but hopefully they're handled ok by the logger now
731
exc_info = sys.exc_info()
732
exitcode = trace.report_exception(exc_info, sys.stderr)
733
if os.environ.get('BZR_PDB'):
734
print '**** entering debugger'
737
if sys.version_info[:2] < (2, 6):
739
# pdb.post_mortem(tb)
740
# but because pdb.post_mortem gives bad results for tracebacks
741
# from inside generators, we do it manually.
742
# (http://bugs.python.org/issue4150, fixed in Python 2.6)
744
# Setup pdb on the traceback
747
p.setup(tb.tb_frame, tb)
748
# Point the debugger at the deepest frame of the stack
749
p.curindex = len(p.stack) - 1
750
p.curframe = p.stack[p.curindex][0]
751
# Start the pdb prompt.
752
p.print_stack_entry(p.stack[p.curindex])
760
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
761
from bzrlib.lsprof import profile
762
ret, stats = profile(exception_to_return_code, the_callable, *args, **kwargs)
768
trace.note('Profile data written to "%s".', filename)
772
def shlex_split_unicode(unsplit):
774
return [u.decode('utf-8') for u in shlex.split(unsplit.encode('utf-8'))]
777
def get_alias(cmd, config=None):
778
"""Return an expanded alias, or None if no alias exists.
781
Command to be checked for an alias.
783
Used to specify an alternative config to use,
784
which is especially useful for testing.
785
If it is unspecified, the global config will be used.
789
config = bzrlib.config.GlobalConfig()
790
alias = config.get_alias(cmd)
792
return shlex_split_unicode(alias)
796
566
def run_bzr(argv):
797
567
"""Execute a command.
569
This is similar to main(), but without all the trappings for
570
logging and error handling.
800
573
The command-line arguments, without the program name from argv[0]
801
These should already be decoded. All library/test code calling
802
run_bzr should be passing valid strings (don't need decoding).
804
575
Returns a command status or raises an exception.
806
577
Special master options: these must come before the command because
810
581
Do not load plugin modules at all
816
584
Only use builtin commands. (Plugins are still allowed to change
817
585
other behaviour.)
820
Run under the Python hotshot profiler.
823
Run under the Python lsprof profiler.
826
Generate line coverage report in the specified directory.
588
Run under the Python profiler.
829
trace.mutter("bzr arguments: %r", argv)
590
# Load all of the transport methods
591
import bzrlib.transport.local, bzrlib.transport.http
593
argv = [a.decode(bzrlib.user_encoding) for a in argv]
831
opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = \
832
opt_no_aliases = False
833
opt_lsprof_file = opt_coverage_dir = None
595
opt_profile = opt_no_plugins = opt_builtin = False
835
597
# --no-plugins is handled specially at a very early stage. We need
836
598
# to load plugins before doing other command parsing so that they
837
599
# can override commands, but this needs to happen first.
843
602
if a == '--profile':
844
603
opt_profile = True
845
elif a == '--lsprof':
847
elif a == '--lsprof-file':
849
opt_lsprof_file = argv[i + 1]
851
604
elif a == '--no-plugins':
852
605
opt_no_plugins = True
853
elif a == '--no-aliases':
854
opt_no_aliases = True
855
606
elif a == '--builtin':
856
607
opt_builtin = True
857
elif a == '--coverage':
858
opt_coverage_dir = argv[i + 1]
860
elif a.startswith('-D'):
861
debug.debug_flags.add(a[2:])
866
debug.set_debug_flags_from_config()
870
from bzrlib.builtins import cmd_help
871
cmd_help().run_argv_aliases([])
612
if (not argv) or (argv[0] == '--help'):
613
from bzrlib.help import help
874
620
if argv[0] == '--version':
875
from bzrlib.builtins import cmd_version
876
cmd_version().run_argv_aliases([])
621
from bzrlib.builtins import show_version
879
625
if not opt_no_plugins:
880
626
from bzrlib.plugin import load_plugins
883
from bzrlib.plugin import disable_plugins
888
if not opt_no_aliases:
889
alias_argv = get_alias(argv[0])
891
user_encoding = osutils.get_user_encoding()
892
alias_argv = [a.decode(user_encoding) for a in alias_argv]
893
argv[0] = alias_argv.pop(0)
896
# We want only 'ascii' command names, but the user may have typed
897
# in a Unicode name. In that case, they should just get a
898
# 'command not found' error later.
629
cmd = str(argv.pop(0))
900
631
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
901
run = cmd_obj.run_argv_aliases
902
run_argv = [argv, alias_argv]
905
# We can be called recursively (tests for example), but we don't want
906
# the verbosity level to propagate.
907
saved_verbosity_level = option._verbosity_level
908
option._verbosity_level = 0
912
'--coverage ignored, because --lsprof is in use.')
913
ret = apply_lsprofiled(opt_lsprof_file, run, *run_argv)
917
'--coverage ignored, because --profile is in use.')
918
ret = apply_profiled(run, *run_argv)
919
elif opt_coverage_dir:
920
ret = apply_coveraged(opt_coverage_dir, run, *run_argv)
923
if 'memory' in debug.debug_flags:
924
trace.debug_memory('Process status after command:', short=False)
927
# reset, in case we may do other commands later within the same
928
# process. Commands that want to execute sub-commands must propagate
929
# --verbose in their own way.
930
option._verbosity_level = saved_verbosity_level
933
def display_command(func):
934
"""Decorator that suppresses pipe/interrupt errors."""
935
def ignore_pipe(*args, **kwargs):
937
result = func(*args, **kwargs)
941
if getattr(e, 'errno', None) is None:
943
if e.errno != errno.EPIPE:
944
# Win32 raises IOError with errno=0 on a broken pipe
945
if sys.platform != 'win32' or (e.errno not in (0, errno.EINVAL)):
948
except KeyboardInterrupt:
634
ret = apply_profiled(cmd_obj.run_argv, argv)
636
ret = cmd_obj.run_argv(argv)
955
bzrlib.ui.ui_factory = bzrlib.ui.make_ui_for_terminal(
956
sys.stdin, sys.stdout, sys.stderr)
958
# Is this a final release version? If so, we should suppress warnings
959
if bzrlib.version_info[3] == 'final':
960
from bzrlib import symbol_versioning
961
symbol_versioning.suppress_deprecation_warnings(override=False)
963
user_encoding = osutils.get_user_encoding()
964
argv = [a.decode(user_encoding) for a in argv[1:]]
965
except UnicodeDecodeError:
966
raise errors.BzrError(("Parameter '%r' is unsupported by the current "
968
ret = run_bzr_catch_errors(argv)
969
trace.mutter("return code %d", ret)
973
def run_bzr_catch_errors(argv):
974
"""Run a bzr command with parameters as described by argv.
976
This function assumed that that UI layer is setup, that symbol deprecations
977
are already applied, and that unicode decoding has already been performed on argv.
979
return exception_to_return_code(run_bzr, argv)
982
def run_bzr_catch_user_errors(argv):
983
"""Run bzr and report user errors, but let internal errors propagate.
985
This is used for the test suite, and might be useful for other programs
986
that want to wrap the commandline interface.
642
bzrlib.trace.log_startup(argv)
643
bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
648
return run_bzr(argv[1:])
650
# do this here inside the exception wrappers to catch EPIPE
652
#wrap common errors as CommandErrors.
653
except (NotBranchError,), e:
654
raise BzrCommandError(str(e))
655
except BzrCommandError, e:
656
# command line syntax error, etc
660
bzrlib.trace.log_exception()
662
except AssertionError, e:
663
bzrlib.trace.log_exception('assertion failed: ' + str(e))
665
except KeyboardInterrupt, e:
666
bzrlib.trace.note('interrupted')
990
668
except Exception, e:
991
if (isinstance(e, (OSError, IOError))
992
or not getattr(e, 'internal_error', True)):
993
trace.report_exception(sys.exc_info(), sys.stderr)
999
class HelpCommandIndex(object):
1000
"""A index for bzr help that returns commands."""
1003
self.prefix = 'commands/'
1005
def get_topics(self, topic):
1006
"""Search for topic amongst commands.
1008
:param topic: A topic to search for.
1009
:return: A list which is either empty or contains a single
1012
if topic and topic.startswith(self.prefix):
1013
topic = topic[len(self.prefix):]
1015
cmd = _get_cmd_object(topic)
1022
class Provider(object):
1023
'''Generic class to be overriden by plugins'''
1025
def plugin_for_command(self, cmd_name):
1026
'''Takes a command and returns the information for that plugin
1028
:return: A dictionary with all the available information
1029
for the requested plugin
1031
raise NotImplementedError
1034
class ProvidersRegistry(registry.Registry):
1035
'''This registry exists to allow other providers to exist'''
1038
for key, provider in self.iteritems():
1041
command_providers_registry = ProvidersRegistry()
670
if (isinstance(e, IOError)
671
and hasattr(e, 'errno')
672
and e.errno == errno.EPIPE):
673
bzrlib.trace.note('broken pipe')
676
bzrlib.trace.log_exception()
1044
679
if __name__ == '__main__':
1045
680
sys.exit(main(sys.argv))