1
# Copyright (C) 2006, 2008 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
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
18
# TODO: probably should say which arguments are candidates for glob
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?
34
from bzrlib.lazy_import import lazy_import
35
lazy_import(globals(), """
39
from warnings import warn
52
from bzrlib.hooks import HookPoint, Hooks
53
# Compatibility - Option used to be in commands.
54
from bzrlib.option import Option
55
from bzrlib import registry
56
from bzrlib.symbol_versioning import deprecated_function, deprecated_in
59
class CommandInfo(object):
60
"""Information about a command."""
62
def __init__(self, aliases):
63
"""The list of aliases for the command."""
64
self.aliases = aliases
67
def from_command(klass, command):
68
"""Factory to construct a CommandInfo from a command."""
69
return klass(command.aliases)
72
class CommandRegistry(registry.Registry):
75
def _get_name(command_name):
76
if command_name.startswith("cmd_"):
77
return _unsquish_command_name(command_name)
81
def register(self, cmd, decorate=False):
82
"""Utility function to help register a command
84
:param cmd: Command subclass to register
85
:param decorate: If true, allow overriding an existing command
86
of the same name; the old command is returned by this function.
87
Otherwise it is an error to try to override an existing command.
90
k_unsquished = self._get_name(k)
92
previous = self.get(k_unsquished)
94
previous = _builtin_commands().get(k_unsquished)
95
info = CommandInfo.from_command(cmd)
97
registry.Registry.register(self, k_unsquished, cmd,
98
override_existing=decorate, info=info)
100
trace.log_error('Two plugins defined the same command: %r' % k)
101
trace.log_error('Not loading the one in %r' %
102
sys.modules[cmd.__module__])
103
trace.log_error('Previously this command was registered from %r' %
104
sys.modules[previous.__module__])
107
def register_lazy(self, command_name, aliases, module_name):
108
"""Register a command without loading its module.
110
:param command_name: The primary name of the command.
111
:param aliases: A list of aliases for the command.
112
:module_name: The module that the command lives in.
114
key = self._get_name(command_name)
115
registry.Registry.register_lazy(self, key, module_name, command_name,
116
info=CommandInfo(aliases))
119
plugin_cmds = CommandRegistry()
122
def register_command(cmd, decorate=False):
124
return plugin_cmds.register(cmd, decorate)
127
def _squish_command_name(cmd):
128
return 'cmd_' + cmd.replace('-', '_')
131
def _unsquish_command_name(cmd):
132
return cmd[4:].replace('_','-')
135
def _builtin_commands():
136
import bzrlib.builtins
137
return _scan_module_for_commands(bzrlib.builtins)
140
def _scan_module_for_commands(module):
142
for name, obj in module.__dict__.iteritems():
143
if name.startswith("cmd_"):
144
real_name = _unsquish_command_name(name)
149
def _list_bzr_commands(names):
150
"""Return a list of all the registered commands.
152
This searches plugins and the core.
154
# to eliminate duplicates
155
names.update(builtin_command_names())
156
names.update(plugin_command_names())
160
def all_command_names():
161
"""Return a list of all command names."""
163
for hook in Command.hooks['list_commands']:
164
new_names = hook(names)
165
if new_names is None:
166
raise AssertionError(
167
'hook %s returned None' % Command.hooks.get_hook_name(hook))
172
def builtin_command_names():
173
"""Return list of builtin command names.
175
Use of all_command_names() is encouraged rather than builtin_command_names
176
and/or plugin_command_names.
178
return _builtin_commands().keys()
181
def plugin_command_names():
182
"""Returns command names from commands registered by plugins."""
183
return plugin_cmds.keys()
186
@deprecated_function(deprecated_in((1, 16, 0)))
188
"""Return canonical name and class for most commands.
190
NB: This does not return all commands since the introduction of
191
command hooks, and returning the class is not sufficient to
192
get correctly setup commands, which is why it is deprecated.
194
Use 'all_command_names' + 'get_cmd_object' instead.
196
d = _builtin_commands()
198
d.update(plugin_cmds.iteritems())
199
for k, v in d.iteritems():
203
def get_cmd_object(cmd_name, plugins_override=True):
204
"""Return the command object for a command.
207
If true, plugin commands can override builtins.
210
return _get_cmd_object(cmd_name, plugins_override)
212
raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
215
def _get_cmd_object(cmd_name, plugins_override=True):
216
"""Get a command object.
218
:param cmd_name: The name of the command.
219
:param plugins_override: Allow plugins to override builtins.
220
:return: A Command object instance
221
:raises: KeyError if no command is found.
223
# We want only 'ascii' command names, but the user may have typed
224
# in a Unicode name. In that case, they should just get a
225
# 'command not found' error later.
226
# In the future, we may actually support Unicode command names.
229
for hook in Command.hooks['get_command']:
230
cmd = hook(cmd, cmd_name)
231
if cmd is not None and not plugins_override:
232
# We've found a non-plugin command, don't permit it to be
234
if not cmd.plugin_name():
237
for hook in Command.hooks['get_missing_command']:
244
# Allow plugins to extend commands
245
for hook in Command.hooks['extend_command']:
250
def _try_plugin_provider(cmd_name):
251
"""Probe for a plugin provider having cmd_name."""
253
plugin_metadata, provider = probe_for_provider(cmd_name)
254
raise errors.CommandAvailableInPlugin(cmd_name,
255
plugin_metadata, provider)
256
except errors.NoPluginAvailable:
260
def probe_for_provider(cmd_name):
261
"""Look for a provider for cmd_name.
263
:param cmd_name: The command name.
264
:return: plugin_metadata, provider for getting cmd_name.
265
:raises NoPluginAvailable: When no provider can supply the plugin.
267
# look for providers that provide this command but aren't installed
268
for provider in command_providers_registry:
270
return provider.plugin_for_command(cmd_name), provider
271
except errors.NoPluginAvailable:
273
raise errors.NoPluginAvailable(cmd_name)
276
def _get_bzr_command(cmd_or_None, cmd_name):
277
"""Get a command from bzr's core."""
278
cmds = _builtin_commands()
280
return cmds[cmd_name]()
283
# look for any command which claims this as an alias
284
for real_cmd_name, cmd_class in cmds.iteritems():
285
if cmd_name in cmd_class.aliases:
290
def _get_external_command(cmd_or_None, cmd_name):
291
"""Lookup a command that is a shell script."""
292
# Only do external command lookups when no command is found so far.
293
if cmd_or_None is not None:
295
from bzrlib.externalcommand import ExternalCommand
296
cmd_obj = ExternalCommand.find_command(cmd_name)
301
def _get_plugin_command(cmd_or_None, cmd_name):
302
"""Get a command from bzr's plugins."""
304
return plugin_cmds.get(cmd_name)()
307
for key in plugin_cmds.keys():
308
info = plugin_cmds.get_info(key)
309
if cmd_name in info.aliases:
310
return plugin_cmds.get(key)()
314
class Command(object):
315
"""Base class for commands.
317
Commands are the heart of the command-line bzr interface.
319
The command object mostly handles the mapping of command-line
320
parameters into one or more bzrlib operations, and of the results
323
Commands normally don't have any state. All their arguments are
324
passed in to the run method. (Subclasses may take a different
325
policy if the behaviour of the instance needs to depend on e.g. a
326
shell plugin and not just its Python class.)
328
The docstring for an actual command should give a single-line
329
summary, then a complete description of the command. A grammar
330
description will be inserted.
333
Other accepted names for this command.
336
List of argument forms, marked with whether they are optional,
341
['to_location', 'from_branch?', 'file*']
343
'to_location' is required
344
'from_branch' is optional
345
'file' can be specified 0 or more times
348
List of options that may be given for this command. These can
349
be either strings, referring to globally-defined options,
350
or option objects. Retrieve through options().
353
If true, this command isn't advertised. This is typically
354
for commands intended for expert users.
357
Command objects will get a 'outf' attribute, which has been
358
setup to properly handle encoding of unicode strings.
359
encoding_type determines what will happen when characters cannot
361
strict - abort if we cannot decode
362
replace - put in a bogus character (typically '?')
363
exact - do not encode sys.stdout
365
NOTE: by default on Windows, sys.stdout is opened as a text
366
stream, therefore LF line-endings are converted to CRLF.
367
When a command uses encoding_type = 'exact', then
368
sys.stdout is forced to be a binary stream, and line-endings
371
:cvar hooks: An instance of CommandHooks.
376
encoding_type = 'strict'
381
"""Construct an instance of this command."""
382
if self.__doc__ == Command.__doc__:
383
warn("No help message set for %r" % self)
384
# List of standard options directly supported
385
self.supported_std_options = []
387
def _maybe_expand_globs(self, file_list):
388
"""Glob expand file_list if the platform does not do that itself.
390
:return: A possibly empty list of unicode paths.
392
Introduced in bzrlib 0.18.
396
if sys.platform == 'win32':
397
file_list = win32utils.glob_expand(file_list)
398
return list(file_list)
401
"""Return single-line grammar for this command.
403
Only describes arguments, not options.
405
s = 'bzr ' + self.name() + ' '
406
for aname in self.takes_args:
407
aname = aname.upper()
408
if aname[-1] in ['$', '+']:
409
aname = aname[:-1] + '...'
410
elif aname[-1] == '?':
411
aname = '[' + aname[:-1] + ']'
412
elif aname[-1] == '*':
413
aname = '[' + aname[:-1] + '...]'
415
s = s[:-1] # remove last space
418
def get_help_text(self, additional_see_also=None, plain=True,
419
see_also_as_links=False, verbose=True):
420
"""Return a text string with help for this command.
422
:param additional_see_also: Additional help topics to be
424
:param plain: if False, raw help (reStructuredText) is
425
returned instead of plain text.
426
:param see_also_as_links: if True, convert items in 'See also'
427
list to internal links (used by bzr_man rstx generator)
428
:param verbose: if True, display the full help, otherwise
429
leave out the descriptive sections and just display
430
usage help (e.g. Purpose, Usage, Options) with a
431
message explaining how to obtain full help.
435
raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
437
# Extract the summary (purpose) and sections out from the text
438
purpose,sections,order = self._get_help_parts(doc)
440
# If a custom usage section was provided, use it
441
if sections.has_key('Usage'):
442
usage = sections.pop('Usage')
444
usage = self._usage()
446
# The header is the purpose and usage
448
result += ':Purpose: %s\n' % purpose
449
if usage.find('\n') >= 0:
450
result += ':Usage:\n%s\n' % usage
452
result += ':Usage: %s\n' % usage
456
options = option.get_optparser(self.options()).format_option_help()
457
if options.startswith('Options:'):
458
result += ':' + options
459
elif options.startswith('options:'):
460
# Python 2.4 version of optparse
461
result += ':Options:' + options[len('options:'):]
467
# Add the description, indenting it 2 spaces
468
# to match the indentation of the options
469
if sections.has_key(None):
470
text = sections.pop(None)
471
text = '\n '.join(text.splitlines())
472
result += ':%s:\n %s\n\n' % ('Description',text)
474
# Add the custom sections (e.g. Examples). Note that there's no need
475
# to indent these as they must be indented already in the source.
478
if sections.has_key(label):
479
result += ':%s:\n%s\n' % (label,sections[label])
482
result += ("See bzr help %s for more details and examples.\n\n"
485
# Add the aliases, source (plug-in) and see also links, if any
487
result += ':Aliases: '
488
result += ', '.join(self.aliases) + '\n'
489
plugin_name = self.plugin_name()
490
if plugin_name is not None:
491
result += ':From: plugin "%s"\n' % plugin_name
492
see_also = self.get_see_also(additional_see_also)
494
if not plain and see_also_as_links:
496
for item in see_also:
498
# topics doesn't have an independent section
499
# so don't create a real link
500
see_also_links.append(item)
502
# Use a reST link for this entry
503
see_also_links.append("`%s`_" % (item,))
504
see_also = see_also_links
505
result += ':See also: '
506
result += ', '.join(see_also) + '\n'
508
# If this will be rendered as plain text, convert it
510
import bzrlib.help_topics
511
result = bzrlib.help_topics.help_as_plain_text(result)
515
def _get_help_parts(text):
516
"""Split help text into a summary and named sections.
518
:return: (summary,sections,order) where summary is the top line and
519
sections is a dictionary of the rest indexed by section name.
520
order is the order the section appear in the text.
521
A section starts with a heading line of the form ":xxx:".
522
Indented text on following lines is the section value.
523
All text found outside a named section is assigned to the
524
default section which is given the key of None.
526
def save_section(sections, order, label, section):
528
if sections.has_key(label):
529
sections[label] += '\n' + section
532
sections[label] = section
534
lines = text.rstrip().splitlines()
535
summary = lines.pop(0)
538
label,section = None,''
540
if line.startswith(':') and line.endswith(':') and len(line) > 2:
541
save_section(sections, order, label, section)
542
label,section = line[1:-1],''
543
elif (label is not None) and len(line) > 1 and not line[0].isspace():
544
save_section(sections, order, label, section)
545
label,section = None,line
548
section += '\n' + line
551
save_section(sections, order, label, section)
552
return summary, sections, order
554
def get_help_topic(self):
555
"""Return the commands help topic - its name."""
558
def get_see_also(self, additional_terms=None):
559
"""Return a list of help topics that are related to this command.
561
The list is derived from the content of the _see_also attribute. Any
562
duplicates are removed and the result is in lexical order.
563
:param additional_terms: Additional help topics to cross-reference.
564
:return: A list of help topics.
566
see_also = set(getattr(self, '_see_also', []))
568
see_also.update(additional_terms)
569
return sorted(see_also)
572
"""Return dict of valid options for this command.
574
Maps from long option name to option object."""
575
r = Option.STD_OPTIONS.copy()
577
for o in self.takes_options:
578
if isinstance(o, basestring):
579
o = option.Option.OPTIONS[o]
581
if o.name in std_names:
582
self.supported_std_options.append(o.name)
585
def _setup_outf(self):
586
"""Return a file linked to stdout, which has proper encoding."""
587
# Originally I was using self.stdout, but that looks
588
# *way* too much like sys.stdout
589
if self.encoding_type == 'exact':
590
# force sys.stdout to be binary stream on win32
591
if sys.platform == 'win32':
592
fileno = getattr(sys.stdout, 'fileno', None)
595
msvcrt.setmode(fileno(), os.O_BINARY)
596
self.outf = sys.stdout
599
output_encoding = osutils.get_terminal_encoding()
601
self.outf = codecs.getwriter(output_encoding)(sys.stdout,
602
errors=self.encoding_type)
603
# For whatever reason codecs.getwriter() does not advertise its encoding
604
# it just returns the encoding of the wrapped file, which is completely
605
# bogus. So set the attribute, so we can find the correct encoding later.
606
self.outf.encoding = output_encoding
608
def run_argv_aliases(self, argv, alias_argv=None):
609
"""Parse the command line and run with extra aliases in alias_argv."""
611
warn("Passing None for [] is deprecated from bzrlib 0.10",
612
DeprecationWarning, stacklevel=2)
614
args, opts = parse_args(self, argv, alias_argv)
616
# Process the standard options
617
if 'help' in opts: # e.g. bzr add --help
618
sys.stdout.write(self.get_help_text())
620
if 'usage' in opts: # e.g. bzr add --usage
621
sys.stdout.write(self.get_help_text(verbose=False))
623
trace.set_verbosity_level(option._verbosity_level)
624
if 'verbose' in self.supported_std_options:
625
opts['verbose'] = trace.is_verbose()
626
elif opts.has_key('verbose'):
628
if 'quiet' in self.supported_std_options:
629
opts['quiet'] = trace.is_quiet()
630
elif opts.has_key('quiet'):
633
# mix arguments and options into one dictionary
634
cmdargs = _match_argform(self.name(), self.takes_args, args)
636
for k, v in opts.items():
637
cmdopts[k.replace('-', '_')] = v
639
all_cmd_args = cmdargs.copy()
640
all_cmd_args.update(cmdopts)
644
return self.run(**all_cmd_args)
647
"""Actually run the command.
649
This is invoked with the options and arguments bound to
652
Return 0 or None if the command was successful, or a non-zero
653
shell error code if not. It's OK for this method to allow
654
an exception to raise up.
656
raise NotImplementedError('no implementation of command %r'
660
"""Return help message for this class."""
661
from inspect import getdoc
662
if self.__doc__ is Command.__doc__:
667
return _unsquish_command_name(self.__class__.__name__)
669
def plugin_name(self):
670
"""Get the name of the plugin that provides this command.
672
:return: The name of the plugin or None if the command is builtin.
674
mod_parts = self.__module__.split('.')
675
if len(mod_parts) >= 3 and mod_parts[1] == 'plugins':
681
class CommandHooks(Hooks):
682
"""Hooks related to Command object creation/enumeration."""
685
"""Create the default hooks.
687
These are all empty initially, because by default nothing should get
691
self.create_hook(HookPoint('extend_command',
692
"Called after creating a command object to allow modifications "
693
"such as adding or removing options, docs etc. Called with the "
694
"new bzrlib.commands.Command object.", (1, 13), None))
695
self.create_hook(HookPoint('get_command',
696
"Called when creating a single command. Called with "
697
"(cmd_or_None, command_name). get_command should either return "
698
"the cmd_or_None parameter, or a replacement Command object that "
699
"should be used for the command.", (1, 16), None))
700
self.create_hook(HookPoint('get_missing_command',
701
"Called when creating a single command if no command could be "
702
"found. Called with (command_name). get_missing_command should "
703
"either return None, or a Command object to be used for the "
704
"command.", (1, 16), None))
705
self.create_hook(HookPoint('list_commands',
706
"Called when enumerating commands. Called with a dict of "
707
"cmd_name: cmd_class tuples for all the commands found "
708
"so far. This dict is safe to mutate - to remove a command or "
709
"to replace it with another (eg plugin supplied) version. "
710
"list_commands should return the updated dict of commands.",
713
Command.hooks = CommandHooks()
716
def parse_args(command, argv, alias_argv=None):
717
"""Parse command line.
719
Arguments and options are parsed at this level before being passed
720
down to specific command handlers. This routine knows, from a
721
lookup table, something about the available options, what optargs
722
they take, and which commands will accept them.
724
# TODO: make it a method of the Command?
725
parser = option.get_optparser(command.options())
726
if alias_argv is not None:
727
args = alias_argv + argv
731
options, args = parser.parse_args(args)
732
opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
733
v is not option.OptionParser.DEFAULT_VALUE])
737
def _match_argform(cmd, takes_args, args):
740
# step through args and takes_args, allowing appropriate 0-many matches
741
for ap in takes_args:
745
argdict[argname] = args.pop(0)
746
elif ap[-1] == '*': # all remaining arguments
748
argdict[argname + '_list'] = args[:]
751
argdict[argname + '_list'] = None
754
raise errors.BzrCommandError("command %r needs one or more %s"
755
% (cmd, argname.upper()))
757
argdict[argname + '_list'] = args[:]
759
elif ap[-1] == '$': # all but one
761
raise errors.BzrCommandError("command %r needs one or more %s"
762
% (cmd, argname.upper()))
763
argdict[argname + '_list'] = args[:-1]
769
raise errors.BzrCommandError("command %r requires argument %s"
770
% (cmd, argname.upper()))
772
argdict[argname] = args.pop(0)
775
raise errors.BzrCommandError("extra argument to command %s: %s"
780
def apply_coveraged(dirname, the_callable, *args, **kwargs):
781
# Cannot use "import trace", as that would import bzrlib.trace instead of
782
# the standard library's trace.
783
trace = __import__('trace')
785
tracer = trace.Trace(count=1, trace=0)
786
sys.settrace(tracer.globaltrace)
787
threading.settrace(tracer.globaltrace)
790
return exception_to_return_code(the_callable, *args, **kwargs)
793
results = tracer.results()
794
results.write_results(show_missing=1, summary=False,
798
def apply_profiled(the_callable, *args, **kwargs):
802
pffileno, pfname = tempfile.mkstemp()
804
prof = hotshot.Profile(pfname)
806
ret = prof.runcall(exception_to_return_code, the_callable, *args,
810
stats = hotshot.stats.load(pfname)
812
stats.sort_stats('cum') # 'time'
813
## XXX: Might like to write to stderr or the trace file instead but
814
## print_stats seems hardcoded to stdout
815
stats.print_stats(20)
822
def exception_to_return_code(the_callable, *args, **kwargs):
823
"""UI level helper for profiling and coverage.
825
This transforms exceptions into a return value of 3. As such its only
826
relevant to the UI layer, and should never be called where catching
827
exceptions may be desirable.
830
return the_callable(*args, **kwargs)
831
except (KeyboardInterrupt, Exception), e:
832
# used to handle AssertionError and KeyboardInterrupt
833
# specially here, but hopefully they're handled ok by the logger now
834
exc_info = sys.exc_info()
835
exitcode = trace.report_exception(exc_info, sys.stderr)
836
if os.environ.get('BZR_PDB'):
837
print '**** entering debugger'
840
if sys.version_info[:2] < (2, 6):
842
# pdb.post_mortem(tb)
843
# but because pdb.post_mortem gives bad results for tracebacks
844
# from inside generators, we do it manually.
845
# (http://bugs.python.org/issue4150, fixed in Python 2.6)
847
# Setup pdb on the traceback
850
p.setup(tb.tb_frame, tb)
851
# Point the debugger at the deepest frame of the stack
852
p.curindex = len(p.stack) - 1
853
p.curframe = p.stack[p.curindex][0]
854
# Start the pdb prompt.
855
p.print_stack_entry(p.stack[p.curindex])
863
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
864
from bzrlib.lsprof import profile
865
ret, stats = profile(exception_to_return_code, the_callable, *args, **kwargs)
871
trace.note('Profile data written to "%s".', filename)
875
def shlex_split_unicode(unsplit):
877
return [u.decode('utf-8') for u in shlex.split(unsplit.encode('utf-8'))]
880
def get_alias(cmd, config=None):
881
"""Return an expanded alias, or None if no alias exists.
884
Command to be checked for an alias.
886
Used to specify an alternative config to use,
887
which is especially useful for testing.
888
If it is unspecified, the global config will be used.
892
config = bzrlib.config.GlobalConfig()
893
alias = config.get_alias(cmd)
895
return shlex_split_unicode(alias)
900
"""Execute a command.
903
The command-line arguments, without the program name from argv[0]
904
These should already be decoded. All library/test code calling
905
run_bzr should be passing valid strings (don't need decoding).
907
Returns a command status or raises an exception.
909
Special master options: these must come before the command because
910
they control how the command is interpreted.
913
Do not load plugin modules at all
919
Only use builtin commands. (Plugins are still allowed to change
923
Run under the Python hotshot profiler.
926
Run under the Python lsprof profiler.
929
Generate line coverage report in the specified directory.
932
trace.mutter("bzr arguments: %r", argv)
934
opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = \
935
opt_no_aliases = False
936
opt_lsprof_file = opt_coverage_dir = None
938
# --no-plugins is handled specially at a very early stage. We need
939
# to load plugins before doing other command parsing so that they
940
# can override commands, but this needs to happen first.
948
elif a == '--lsprof':
950
elif a == '--lsprof-file':
952
opt_lsprof_file = argv[i + 1]
954
elif a == '--no-plugins':
955
opt_no_plugins = True
956
elif a == '--no-aliases':
957
opt_no_aliases = True
958
elif a == '--builtin':
960
elif a == '--coverage':
961
opt_coverage_dir = argv[i + 1]
963
elif a.startswith('-D'):
964
debug.debug_flags.add(a[2:])
969
debug.set_debug_flags_from_config()
973
from bzrlib.builtins import cmd_help
974
cmd_help().run_argv_aliases([])
977
if argv[0] == '--version':
978
from bzrlib.builtins import cmd_version
979
cmd_version().run_argv_aliases([])
982
if not opt_no_plugins:
983
from bzrlib.plugin import load_plugins
986
from bzrlib.plugin import disable_plugins
991
if not opt_no_aliases:
992
alias_argv = get_alias(argv[0])
994
user_encoding = osutils.get_user_encoding()
995
alias_argv = [a.decode(user_encoding) for a in alias_argv]
996
argv[0] = alias_argv.pop(0)
999
# We want only 'ascii' command names, but the user may have typed
1000
# in a Unicode name. In that case, they should just get a
1001
# 'command not found' error later.
1003
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
1004
run = cmd_obj.run_argv_aliases
1005
run_argv = [argv, alias_argv]
1008
# We can be called recursively (tests for example), but we don't want
1009
# the verbosity level to propagate.
1010
saved_verbosity_level = option._verbosity_level
1011
option._verbosity_level = 0
1013
if opt_coverage_dir:
1015
'--coverage ignored, because --lsprof is in use.')
1016
ret = apply_lsprofiled(opt_lsprof_file, run, *run_argv)
1018
if opt_coverage_dir:
1020
'--coverage ignored, because --profile is in use.')
1021
ret = apply_profiled(run, *run_argv)
1022
elif opt_coverage_dir:
1023
ret = apply_coveraged(opt_coverage_dir, run, *run_argv)
1025
ret = run(*run_argv)
1026
if 'memory' in debug.debug_flags:
1027
trace.debug_memory('Process status after command:', short=False)
1030
# reset, in case we may do other commands later within the same
1031
# process. Commands that want to execute sub-commands must propagate
1032
# --verbose in their own way.
1033
option._verbosity_level = saved_verbosity_level
1036
def display_command(func):
1037
"""Decorator that suppresses pipe/interrupt errors."""
1038
def ignore_pipe(*args, **kwargs):
1040
result = func(*args, **kwargs)
1044
if getattr(e, 'errno', None) is None:
1046
if e.errno != errno.EPIPE:
1047
# Win32 raises IOError with errno=0 on a broken pipe
1048
if sys.platform != 'win32' or (e.errno not in (0, errno.EINVAL)):
1051
except KeyboardInterrupt:
1056
def install_bzr_command_hooks():
1057
"""Install the hooks to supply bzr's own commands."""
1058
Command.hooks.install_named_hook("list_commands", _list_bzr_commands,
1060
Command.hooks.install_named_hook("get_command", _get_bzr_command,
1062
Command.hooks.install_named_hook("get_command", _get_plugin_command,
1063
"bzr plugin commands")
1064
Command.hooks.install_named_hook("get_command", _get_external_command,
1065
"bzr external command lookup")
1066
Command.hooks.install_named_hook("get_missing_command", _try_plugin_provider,
1067
"bzr plugin-provider-db check")
1070
def main(argv=None):
1071
"""Main entry point of command-line interface.
1073
:param argv: list of unicode command-line arguments similar to sys.argv.
1074
argv[0] is script name usually, it will be ignored.
1075
Don't pass here sys.argv because this list contains plain strings
1076
and not unicode; pass None instead.
1078
:return: exit code of bzr command.
1081
bzrlib.ui.ui_factory = bzrlib.ui.make_ui_for_terminal(
1082
sys.stdin, sys.stdout, sys.stderr)
1084
# Is this a final release version? If so, we should suppress warnings
1085
if bzrlib.version_info[3] == 'final':
1086
symbol_versioning.suppress_deprecation_warnings(override=False)
1088
argv = osutils.get_unicode_argv()
1092
# ensure all arguments are unicode strings
1094
if isinstance(a, unicode):
1097
new_argv.append(a.decode('ascii'))
1098
except UnicodeDecodeError:
1099
raise errors.BzrError("argv should be list of unicode strings.")
1101
install_bzr_command_hooks()
1102
ret = run_bzr_catch_errors(argv)
1103
trace.mutter("return code %d", ret)
1107
def run_bzr_catch_errors(argv):
1108
"""Run a bzr command with parameters as described by argv.
1110
This function assumed that that UI layer is setup, that symbol deprecations
1111
are already applied, and that unicode decoding has already been performed on argv.
1113
return exception_to_return_code(run_bzr, argv)
1116
def run_bzr_catch_user_errors(argv):
1117
"""Run bzr and report user errors, but let internal errors propagate.
1119
This is used for the test suite, and might be useful for other programs
1120
that want to wrap the commandline interface.
1123
return run_bzr(argv)
1124
except Exception, e:
1125
if (isinstance(e, (OSError, IOError))
1126
or not getattr(e, 'internal_error', True)):
1127
trace.report_exception(sys.exc_info(), sys.stderr)
1133
class HelpCommandIndex(object):
1134
"""A index for bzr help that returns commands."""
1137
self.prefix = 'commands/'
1139
def get_topics(self, topic):
1140
"""Search for topic amongst commands.
1142
:param topic: A topic to search for.
1143
:return: A list which is either empty or contains a single
1146
if topic and topic.startswith(self.prefix):
1147
topic = topic[len(self.prefix):]
1149
cmd = _get_cmd_object(topic)
1156
class Provider(object):
1157
'''Generic class to be overriden by plugins'''
1159
def plugin_for_command(self, cmd_name):
1160
'''Takes a command and returns the information for that plugin
1162
:return: A dictionary with all the available information
1163
for the requested plugin
1165
raise NotImplementedError
1168
class ProvidersRegistry(registry.Registry):
1169
'''This registry exists to allow other providers to exist'''
1172
for key, provider in self.iteritems():
1175
command_providers_registry = ProvidersRegistry()
1178
if __name__ == '__main__':
1179
sys.exit(main(sys.argv))