1
# Copyright (C) 2004, 2005 by Canonical Ltd
1
# Copyright (C) 2005-2010 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.
23
21
# TODO: Define arguments by objects, rather than just using names.
24
22
# Those objects can specify the expected type of the argument, which
25
# would help with validation and shell completion.
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.
27
28
# TODO: "--profile=cum", to change sort order. Is there any value in leaving
28
29
# the profile output behind so it can be interactively examined?
34
from bzrlib.lazy_import import lazy_import
35
lazy_import(globals(), """
32
39
from warnings import warn
33
from inspect import getdoc
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
45
def register_command(cmd):
46
"Utility function to help register a command"
55
from bzrlib.hooks import HookPoint, Hooks
56
# Compatibility - Option used to be in commands.
57
from bzrlib.option import Option
58
from bzrlib.plugin import disable_plugins, load_plugins
59
from bzrlib import registry
60
from bzrlib.symbol_versioning import (
67
class CommandInfo(object):
68
"""Information about a command."""
70
def __init__(self, aliases):
71
"""The list of aliases for the command."""
72
self.aliases = aliases
75
def from_command(klass, command):
76
"""Factory to construct a CommandInfo from a command."""
77
return klass(command.aliases)
80
class CommandRegistry(registry.Registry):
83
def _get_name(command_name):
84
if command_name.startswith("cmd_"):
85
return _unsquish_command_name(command_name)
89
def register(self, cmd, decorate=False):
90
"""Utility function to help register a command
92
:param cmd: Command subclass to register
93
:param decorate: If true, allow overriding an existing command
94
of the same name; the old command is returned by this function.
95
Otherwise it is an error to try to override an existing command.
98
k_unsquished = self._get_name(k)
100
previous = self.get(k_unsquished)
102
previous = _builtin_commands().get(k_unsquished)
103
info = CommandInfo.from_command(cmd)
105
registry.Registry.register(self, k_unsquished, cmd,
106
override_existing=decorate, info=info)
108
trace.warning('Two plugins defined the same command: %r' % k)
109
trace.warning('Not loading the one in %r' %
110
sys.modules[cmd.__module__])
111
trace.warning('Previously this command was registered from %r' %
112
sys.modules[previous.__module__])
115
def register_lazy(self, command_name, aliases, module_name):
116
"""Register a command without loading its module.
118
:param command_name: The primary name of the command.
119
:param aliases: A list of aliases for the command.
120
:module_name: The module that the command lives in.
122
key = self._get_name(command_name)
123
registry.Registry.register_lazy(self, key, module_name, command_name,
124
info=CommandInfo(aliases))
127
plugin_cmds = CommandRegistry()
130
def register_command(cmd, decorate=False):
47
131
global plugin_cmds
49
if k.startswith("cmd_"):
50
k_unsquished = _unsquish_command_name(k)
53
if not plugin_cmds.has_key(k_unsquished):
54
plugin_cmds[k_unsquished] = cmd
55
mutter('registered plugin command %s', k_unsquished)
57
log_error('Two plugins defined the same command: %r' % k)
58
log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
132
return plugin_cmds.register(cmd, decorate)
61
135
def _squish_command_name(cmd):
65
139
def _unsquish_command_name(cmd):
66
assert cmd.startswith("cmd_")
67
140
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))
149
143
def _builtin_commands():
150
144
import bzrlib.builtins
145
return _scan_module_for_commands(bzrlib.builtins)
148
def _scan_module_for_commands(module):
152
builtins = bzrlib.builtins.__dict__
153
for name in builtins:
150
for name, obj in module.__dict__.iteritems():
154
151
if name.startswith("cmd_"):
155
real_name = _unsquish_command_name(name)
156
r[real_name] = builtins[name]
152
real_name = _unsquish_command_name(name)
157
def _list_bzr_commands(names):
158
"""Find commands from bzr's core and plugins."""
159
# to eliminate duplicates
160
names.update(builtin_command_names())
161
names.update(plugin_command_names())
165
def all_command_names():
166
"""Return a set of all command names."""
168
for hook in Command.hooks['list_commands']:
171
raise AssertionError(
172
'hook %s returned None' % Command.hooks.get_hook_name(hook))
161
176
def builtin_command_names():
162
"""Return list of builtin command names."""
177
"""Return list of builtin command names.
179
Use of all_command_names() is encouraged rather than builtin_command_names
180
and/or plugin_command_names.
163
182
return _builtin_commands().keys()
166
185
def plugin_command_names():
186
"""Returns command names from commands registered by plugins."""
167
187
return plugin_cmds.keys()
170
def _get_cmd_dict(plugins_override=True):
171
"""Return name->class mapping for all commands."""
172
d = _builtin_commands()
174
d.update(plugin_cmds)
178
def get_all_cmds(plugins_override=True):
179
"""Return canonical name and class for all registered commands."""
180
for k, v in _get_cmd_dict(plugins_override=plugins_override).iteritems():
184
190
def get_cmd_object(cmd_name, plugins_override=True):
185
"""Return the canonical name and command class for a command.
191
"""Return the command object for a command.
188
194
If true, plugin commands can override builtins.
190
from bzrlib.externalcommand import ExternalCommand
192
cmd_name = str(cmd_name) # not unicode
194
# first look up this command under the specified name
195
cmds = _get_cmd_dict(plugins_override=plugins_override)
197
return _get_cmd_object(cmd_name, plugins_override)
199
raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
202
def _get_cmd_object(cmd_name, plugins_override=True):
203
"""Get a command object.
205
:param cmd_name: The name of the command.
206
:param plugins_override: Allow plugins to override builtins.
207
:return: A Command object instance
208
:raises KeyError: If no command is found.
210
# We want only 'ascii' command names, but the user may have typed
211
# in a Unicode name. In that case, they should just get a
212
# 'command not found' error later.
213
# In the future, we may actually support Unicode command names.
216
for hook in Command.hooks['get_command']:
217
cmd = hook(cmd, cmd_name)
218
if cmd is not None and not plugins_override and not cmd.plugin_name():
219
# We've found a non-plugin command, don't permit it to be
223
for hook in Command.hooks['get_missing_command']:
230
# Allow plugins to extend commands
231
for hook in Command.hooks['extend_command']:
236
def _try_plugin_provider(cmd_name):
237
"""Probe for a plugin provider having cmd_name."""
239
plugin_metadata, provider = probe_for_provider(cmd_name)
240
raise errors.CommandAvailableInPlugin(cmd_name,
241
plugin_metadata, provider)
242
except errors.NoPluginAvailable:
246
def probe_for_provider(cmd_name):
247
"""Look for a provider for cmd_name.
249
:param cmd_name: The command name.
250
:return: plugin_metadata, provider for getting cmd_name.
251
:raises NoPluginAvailable: When no provider can supply the plugin.
253
# look for providers that provide this command but aren't installed
254
for provider in command_providers_registry:
256
return provider.plugin_for_command(cmd_name), provider
257
except errors.NoPluginAvailable:
259
raise errors.NoPluginAvailable(cmd_name)
262
def _get_bzr_command(cmd_or_None, cmd_name):
263
"""Get a command from bzr's core."""
264
cmds = _builtin_commands()
197
266
return cmds[cmd_name]()
201
269
# look for any command which claims this as an alias
202
270
for real_cmd_name, cmd_class in cmds.iteritems():
203
271
if cmd_name in cmd_class.aliases:
204
272
return cmd_class()
276
def _get_external_command(cmd_or_None, cmd_name):
277
"""Lookup a command that is a shell script."""
278
# Only do external command lookups when no command is found so far.
279
if cmd_or_None is not None:
281
from bzrlib.externalcommand import ExternalCommand
206
282
cmd_obj = ExternalCommand.find_command(cmd_name)
210
raise BzrCommandError("unknown command %r" % cmd_name)
287
def _get_plugin_command(cmd_or_None, cmd_name):
288
"""Get a command from bzr's plugins."""
290
return plugin_cmds.get(cmd_name)()
293
for key in plugin_cmds.keys():
294
info = plugin_cmds.get_info(key)
295
if cmd_name in info.aliases:
296
return plugin_cmds.get(key)()
213
300
class Command(object):
235
322
List of argument forms, marked with whether they are optional,
327
['to_location', 'from_branch?', 'file*']
329
'to_location' is required
330
'from_branch' is optional
331
'file' can be specified 0 or more times
239
List of options that may be given for this command.
334
List of options that may be given for this command. These can
335
be either strings, referring to globally-defined options,
336
or option objects. Retrieve through options().
242
339
If true, this command isn't advertised. This is typically
243
340
for commands intended for expert users.
343
Command objects will get a 'outf' attribute, which has been
344
setup to properly handle encoding of unicode strings.
345
encoding_type determines what will happen when characters cannot
347
strict - abort if we cannot decode
348
replace - put in a bogus character (typically '?')
349
exact - do not encode sys.stdout
351
NOTE: by default on Windows, sys.stdout is opened as a text
352
stream, therefore LF line-endings are converted to CRLF.
353
When a command uses encoding_type = 'exact', then
354
sys.stdout is forced to be a binary stream, and line-endings
357
:cvar hooks: An instance of CommandHooks.
248
361
takes_options = []
362
encoding_type = 'strict'
252
366
def __init__(self):
253
367
"""Construct an instance of this command."""
254
368
if self.__doc__ == Command.__doc__:
255
369
warn("No help message set for %r" % self)
258
def run_argv(self, argv):
259
"""Parse command line and run."""
260
args, opts = parse_args(argv)
370
# List of standard options directly supported
371
self.supported_std_options = []
372
self._operation = cleanup.OperationWithCleanups(self.run)
374
def add_cleanup(self, cleanup_func, *args, **kwargs):
375
"""Register a function to call after self.run returns or raises.
377
Functions will be called in LIFO order.
379
self._operation.add_cleanup(cleanup_func, *args, **kwargs)
381
def cleanup_now(self):
382
"""Execute and empty pending cleanup functions immediately.
384
After cleanup_now all registered cleanups are forgotten. add_cleanup
385
may be called again after cleanup_now; these cleanups will be called
386
after self.run returns or raises (or when cleanup_now is next called).
388
This is useful for releasing expensive or contentious resources (such
389
as write locks) before doing further work that does not require those
390
resources (such as writing results to self.outf).
392
self._operation.cleanup_now()
394
@deprecated_method(deprecated_in((2, 1, 0)))
395
def _maybe_expand_globs(self, file_list):
396
"""Glob expand file_list if the platform does not do that itself.
398
Not used anymore, now that the bzr command-line parser globs on
401
:return: A possibly empty list of unicode paths.
403
Introduced in bzrlib 0.18.
408
"""Return single-line grammar for this command.
410
Only describes arguments, not options.
412
s = 'bzr ' + self.name() + ' '
413
for aname in self.takes_args:
414
aname = aname.upper()
415
if aname[-1] in ['$', '+']:
416
aname = aname[:-1] + '...'
417
elif aname[-1] == '?':
418
aname = '[' + aname[:-1] + ']'
419
elif aname[-1] == '*':
420
aname = '[' + aname[:-1] + '...]'
422
s = s[:-1] # remove last space
425
def get_help_text(self, additional_see_also=None, plain=True,
426
see_also_as_links=False, verbose=True):
427
"""Return a text string with help for this command.
429
:param additional_see_also: Additional help topics to be
431
:param plain: if False, raw help (reStructuredText) is
432
returned instead of plain text.
433
:param see_also_as_links: if True, convert items in 'See also'
434
list to internal links (used by bzr_man rstx generator)
435
:param verbose: if True, display the full help, otherwise
436
leave out the descriptive sections and just display
437
usage help (e.g. Purpose, Usage, Options) with a
438
message explaining how to obtain full help.
442
raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
444
# Extract the summary (purpose) and sections out from the text
445
purpose,sections,order = self._get_help_parts(doc)
447
# If a custom usage section was provided, use it
448
if sections.has_key('Usage'):
449
usage = sections.pop('Usage')
451
usage = self._usage()
453
# The header is the purpose and usage
455
result += ':Purpose: %s\n' % purpose
456
if usage.find('\n') >= 0:
457
result += ':Usage:\n%s\n' % usage
459
result += ':Usage: %s\n' % usage
464
# XXX: optparse implicitly rewraps the help, and not always perfectly,
465
# so we get <https://bugs.launchpad.net/bzr/+bug/249908>. -- mbp
467
options = option.get_optparser(self.options()).format_option_help()
468
# XXX: According to the spec, ReST option lists actually don't support
469
# options like --1.9 so that causes syntax errors (in Sphinx at least).
470
# As that pattern always appears in the commands that break, we trap
471
# on that and then format that block of 'format' options as a literal
473
if not plain and options.find(' --1.9 ') != -1:
474
options = options.replace(' format:\n', ' format::\n\n', 1)
475
if options.startswith('Options:'):
476
result += ':' + options
477
elif options.startswith('options:'):
478
# Python 2.4 version of optparse
479
result += ':Options:' + options[len('options:'):]
485
# Add the description, indenting it 2 spaces
486
# to match the indentation of the options
487
if sections.has_key(None):
488
text = sections.pop(None)
489
text = '\n '.join(text.splitlines())
490
result += ':%s:\n %s\n\n' % ('Description',text)
492
# Add the custom sections (e.g. Examples). Note that there's no need
493
# to indent these as they must be indented already in the source.
496
if sections.has_key(label):
497
result += ':%s:\n%s\n' % (label,sections[label])
500
result += ("See bzr help %s for more details and examples.\n\n"
503
# Add the aliases, source (plug-in) and see also links, if any
505
result += ':Aliases: '
506
result += ', '.join(self.aliases) + '\n'
507
plugin_name = self.plugin_name()
508
if plugin_name is not None:
509
result += ':From: plugin "%s"\n' % plugin_name
510
see_also = self.get_see_also(additional_see_also)
512
if not plain and see_also_as_links:
514
for item in see_also:
516
# topics doesn't have an independent section
517
# so don't create a real link
518
see_also_links.append(item)
520
# Use a Sphinx link for this entry
521
link_text = ":doc:`%s <%s-help>`" % (item, item)
522
see_also_links.append(link_text)
523
see_also = see_also_links
524
result += ':See also: '
525
result += ', '.join(see_also) + '\n'
527
# If this will be rendered as plain text, convert it
529
import bzrlib.help_topics
530
result = bzrlib.help_topics.help_as_plain_text(result)
534
def _get_help_parts(text):
535
"""Split help text into a summary and named sections.
537
:return: (summary,sections,order) where summary is the top line and
538
sections is a dictionary of the rest indexed by section name.
539
order is the order the section appear in the text.
540
A section starts with a heading line of the form ":xxx:".
541
Indented text on following lines is the section value.
542
All text found outside a named section is assigned to the
543
default section which is given the key of None.
545
def save_section(sections, order, label, section):
547
if sections.has_key(label):
548
sections[label] += '\n' + section
551
sections[label] = section
553
lines = text.rstrip().splitlines()
554
summary = lines.pop(0)
557
label,section = None,''
559
if line.startswith(':') and line.endswith(':') and len(line) > 2:
560
save_section(sections, order, label, section)
561
label,section = line[1:-1],''
562
elif (label is not None) and len(line) > 1 and not line[0].isspace():
563
save_section(sections, order, label, section)
564
label,section = None,line
567
section += '\n' + line
570
save_section(sections, order, label, section)
571
return summary, sections, order
573
def get_help_topic(self):
574
"""Return the commands help topic - its name."""
577
def get_see_also(self, additional_terms=None):
578
"""Return a list of help topics that are related to this command.
580
The list is derived from the content of the _see_also attribute. Any
581
duplicates are removed and the result is in lexical order.
582
:param additional_terms: Additional help topics to cross-reference.
583
:return: A list of help topics.
585
see_also = set(getattr(self, '_see_also', []))
587
see_also.update(additional_terms)
588
return sorted(see_also)
591
"""Return dict of valid options for this command.
593
Maps from long option name to option object."""
594
r = Option.STD_OPTIONS.copy()
596
for o in self.takes_options:
597
if isinstance(o, basestring):
598
o = option.Option.OPTIONS[o]
600
if o.name in std_names:
601
self.supported_std_options.append(o.name)
604
def _setup_outf(self):
605
"""Return a file linked to stdout, which has proper encoding."""
606
self.outf = ui.ui_factory.make_output_stream(
607
encoding_type=self.encoding_type)
609
def run_argv_aliases(self, argv, alias_argv=None):
610
"""Parse the command line and run with extra aliases in alias_argv."""
611
args, opts = parse_args(self, argv, alias_argv)
613
# Process the standard options
262
614
if 'help' in opts: # e.g. bzr add --help
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()))
615
sys.stdout.write(self.get_help_text())
617
if 'usage' in opts: # e.g. bzr add --usage
618
sys.stdout.write(self.get_help_text(verbose=False))
620
trace.set_verbosity_level(option._verbosity_level)
621
if 'verbose' in self.supported_std_options:
622
opts['verbose'] = trace.is_verbose()
623
elif opts.has_key('verbose'):
625
if 'quiet' in self.supported_std_options:
626
opts['quiet'] = trace.is_quiet()
627
elif opts.has_key('quiet'):
274
630
# mix arguments and options into one dictionary
275
631
cmdargs = _match_argform(self.name(), self.takes_args, args)
306
668
return _unsquish_command_name(self.__class__.__name__)
670
def plugin_name(self):
671
"""Get the name of the plugin that provides this command.
309
def parse_spec(spec):
315
>>> parse_spec("../@")
317
>>> parse_spec("../f/@35")
319
>>> parse_spec('./@revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67')
320
['.', 'revid:john@arbash-meinel.com-20050711044610-3ca0327c6a222f67']
325
parsed = spec.split('/@')
326
assert len(parsed) == 2
673
:return: The name of the plugin or None if the command is builtin.
675
mod_parts = self.__module__.split('.')
676
if len(mod_parts) >= 3 and mod_parts[1] == 'plugins':
331
parsed[1] = int(parsed[1])
333
pass # We can allow stuff like ./@revid:blahblahblah
337
parsed = [spec, None]
341
# list of all available options; the rhs can be either None for an
342
# option that takes no argument, or a constructor function that checks
357
'revision': _parse_revision_str,
384
def parse_args(argv):
682
class CommandHooks(Hooks):
683
"""Hooks related to Command object creation/enumeration."""
686
"""Create the default hooks.
688
These are all empty initially, because by default nothing should get
692
self.create_hook(HookPoint('extend_command',
693
"Called after creating a command object to allow modifications "
694
"such as adding or removing options, docs etc. Called with the "
695
"new bzrlib.commands.Command object.", (1, 13), None))
696
self.create_hook(HookPoint('get_command',
697
"Called when creating a single command. Called with "
698
"(cmd_or_None, command_name). get_command should either return "
699
"the cmd_or_None parameter, or a replacement Command object that "
700
"should be used for the command. Note that the Command.hooks "
701
"hooks are core infrastructure. Many users will prefer to use "
702
"bzrlib.commands.register_command or plugin_cmds.register_lazy.",
704
self.create_hook(HookPoint('get_missing_command',
705
"Called when creating a single command if no command could be "
706
"found. Called with (command_name). get_missing_command should "
707
"either return None, or a Command object to be used for the "
708
"command.", (1, 17), None))
709
self.create_hook(HookPoint('list_commands',
710
"Called when enumerating commands. Called with a set of "
711
"cmd_name strings for all the commands found so far. This set "
712
" is safe to mutate - e.g. to remove a command. "
713
"list_commands should return the updated set of command names.",
716
Command.hooks = CommandHooks()
719
def parse_args(command, argv, alias_argv=None):
385
720
"""Parse command line.
387
722
Arguments and options are parsed at this level before being passed
388
723
down to specific command handlers. This routine knows, from a
389
724
lookup table, something about the available options, what optargs
390
725
they take, and which commands will accept them.
392
>>> parse_args('--help'.split())
394
>>> parse_args('help -- --invalidcmd'.split())
395
(['help', '--invalidcmd'], {})
396
>>> parse_args('--version'.split())
397
([], {'version': True})
398
>>> parse_args('status --all'.split())
399
(['status'], {'all': True})
400
>>> parse_args('commit --message=biter'.split())
401
(['commit'], {'message': u'biter'})
402
>>> parse_args('log -r 500'.split())
403
(['log'], {'revision': [<RevisionSpec_int 500>]})
404
>>> parse_args('log -r500..600'.split())
405
(['log'], {'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
406
>>> parse_args('log -vr500..600'.split())
407
(['log'], {'verbose': True, 'revision': [<RevisionSpec_int 500>, <RevisionSpec_int 600>]})
408
>>> parse_args('log -rrevno:500..600'.split()) #the r takes an argument
409
(['log'], {'revision': [<RevisionSpec_revno revno:500>, <RevisionSpec_int 600>]})
417
if not argsover and a[0] == '-':
418
# option names must not be unicode
423
# We've received a standalone -- No more flags
426
mutter(" got option %r" % a)
428
optname, optarg = a[2:].split('=', 1)
431
if optname not in OPTIONS:
432
raise BzrError('unknown long option %r' % a)
435
if shortopt in SHORT_OPTIONS:
436
# Multi-character options must have a space to delimit
438
optname = SHORT_OPTIONS[shortopt]
440
# Single character short options, can be chained,
441
# and have their value appended to their name
443
if shortopt not in SHORT_OPTIONS:
444
# We didn't find the multi-character name, and we
445
# didn't find the single char name
446
raise BzrError('unknown short option %r' % a)
447
optname = SHORT_OPTIONS[shortopt]
450
# There are extra things on this option
451
# see if it is the value, or if it is another
453
optargfn = OPTIONS[optname]
455
# This option does not take an argument, so the
456
# next entry is another short option, pack it back
458
argv.insert(0, '-' + a[2:])
460
# This option takes an argument, so pack it
465
# XXX: Do we ever want to support this, e.g. for -r?
466
raise BzrError('repeated option %r' % a)
468
optargfn = OPTIONS[optname]
472
raise BzrError('option %r needs an argument' % a)
475
opts[optname] = optargfn(optarg)
478
raise BzrError('option %r takes no argument' % optname)
727
# TODO: make it a method of the Command?
728
parser = option.get_optparser(command.options())
729
if alias_argv is not None:
730
args = alias_argv + argv
734
options, args = parser.parse_args(args)
735
opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
736
v is not option.OptionParser.DEFAULT_VALUE])
483
737
return args, opts
488
740
def _match_argform(cmd, takes_args, args):
553
822
os.remove(pfname)
825
def exception_to_return_code(the_callable, *args, **kwargs):
826
"""UI level helper for profiling and coverage.
828
This transforms exceptions into a return value of 3. As such its only
829
relevant to the UI layer, and should never be called where catching
830
exceptions may be desirable.
833
return the_callable(*args, **kwargs)
834
except (KeyboardInterrupt, Exception), e:
835
# used to handle AssertionError and KeyboardInterrupt
836
# specially here, but hopefully they're handled ok by the logger now
837
exc_info = sys.exc_info()
838
exitcode = trace.report_exception(exc_info, sys.stderr)
839
if os.environ.get('BZR_PDB'):
840
print '**** entering debugger'
843
if sys.version_info[:2] < (2, 6):
845
# pdb.post_mortem(tb)
846
# but because pdb.post_mortem gives bad results for tracebacks
847
# from inside generators, we do it manually.
848
# (http://bugs.python.org/issue4150, fixed in Python 2.6)
850
# Setup pdb on the traceback
853
p.setup(tb.tb_frame, tb)
854
# Point the debugger at the deepest frame of the stack
855
p.curindex = len(p.stack) - 1
856
p.curframe = p.stack[p.curindex][0]
857
# Start the pdb prompt.
858
p.print_stack_entry(p.stack[p.curindex])
866
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
867
from bzrlib.lsprof import profile
868
ret, stats = profile(exception_to_return_code, the_callable, *args, **kwargs)
874
trace.note('Profile data written to "%s".', filename)
878
def get_alias(cmd, config=None):
879
"""Return an expanded alias, or None if no alias exists.
882
Command to be checked for an alias.
884
Used to specify an alternative config to use,
885
which is especially useful for testing.
886
If it is unspecified, the global config will be used.
890
config = bzrlib.config.GlobalConfig()
891
alias = config.get_alias(cmd)
893
return cmdline.split(alias)
897
def run_bzr(argv, load_plugins=load_plugins, disable_plugins=disable_plugins):
557
898
"""Execute a command.
559
This is similar to main(), but without all the trappings for
560
logging and error handling.
563
The command-line arguments, without the program name from argv[0]
565
Returns a command status or raises an exception.
900
:param argv: The command-line arguments, without the program name from
901
argv[0] These should already be decoded. All library/test code calling
902
run_bzr should be passing valid strings (don't need decoding).
903
:param load_plugins: What function to call when triggering plugin loading.
904
This function should take no arguments and cause all plugins to be
906
:param disable_plugins: What function to call when disabling plugin
907
loading. This function should take no arguments and cause all plugin
908
loading to be prohibited (so that code paths in your application that
909
know about some plugins possibly being present will fail to import
910
those plugins even if they are installed.)
911
:return: Returns a command exit code or raises an exception.
567
913
Special master options: these must come before the command because
568
914
they control how the command is interpreted.
571
917
Do not load plugin modules at all
574
923
Only use builtin commands. (Plugins are still allowed to change
575
924
other behaviour.)
578
Run under the Python profiler.
927
Run under the Python hotshot profiler.
930
Run under the Python lsprof profiler.
933
Generate line coverage report in the specified directory.
936
Specify the number of processes that can be run concurrently (selftest).
580
# Load all of the transport methods
581
import bzrlib.transport.local, bzrlib.transport.http
583
argv = [a.decode(bzrlib.user_encoding) for a in argv]
938
trace.mutter("bazaar version: " + bzrlib.__version__)
940
trace.mutter("bzr arguments: %r", argv)
585
opt_profile = opt_no_plugins = opt_builtin = False
942
opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = \
943
opt_no_aliases = False
944
opt_lsprof_file = opt_coverage_dir = None
587
946
# --no-plugins is handled specially at a very early stage. We need
588
947
# to load plugins before doing other command parsing so that they
589
948
# can override commands, but this needs to happen first.
592
954
if a == '--profile':
593
955
opt_profile = True
956
elif a == '--lsprof':
958
elif a == '--lsprof-file':
960
opt_lsprof_file = argv[i + 1]
594
962
elif a == '--no-plugins':
595
963
opt_no_plugins = True
964
elif a == '--no-aliases':
965
opt_no_aliases = True
596
966
elif a == '--builtin':
597
967
opt_builtin = True
602
if (not argv) or (argv[0] == '--help'):
603
from bzrlib.help import help
610
if argv[0] == '--version':
611
from bzrlib.builtins import show_version
968
elif a == '--concurrency':
969
os.environ['BZR_CONCURRENCY'] = argv[i + 1]
971
elif a == '--coverage':
972
opt_coverage_dir = argv[i + 1]
974
elif a.startswith('-D'):
975
debug.debug_flags.add(a[2:])
980
debug.set_debug_flags_from_config()
615
982
if not opt_no_plugins:
616
from bzrlib.plugin import load_plugins
619
cmd = str(argv.pop(0))
989
get_cmd_object('help').run_argv_aliases([])
992
if argv[0] == '--version':
993
get_cmd_object('version').run_argv_aliases([])
998
if not opt_no_aliases:
999
alias_argv = get_alias(argv[0])
1001
user_encoding = osutils.get_user_encoding()
1002
alias_argv = [a.decode(user_encoding) for a in alias_argv]
1003
argv[0] = alias_argv.pop(0)
1006
# We want only 'ascii' command names, but the user may have typed
1007
# in a Unicode name. In that case, they should just get a
1008
# 'command not found' error later.
621
1010
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
624
ret = apply_profiled(cmd_obj.run_argv, argv)
1011
run = cmd_obj.run_argv_aliases
1012
run_argv = [argv, alias_argv]
1015
# We can be called recursively (tests for example), but we don't want
1016
# the verbosity level to propagate.
1017
saved_verbosity_level = option._verbosity_level
1018
option._verbosity_level = 0
1020
if opt_coverage_dir:
1022
'--coverage ignored, because --lsprof is in use.')
1023
ret = apply_lsprofiled(opt_lsprof_file, run, *run_argv)
1025
if opt_coverage_dir:
1027
'--coverage ignored, because --profile is in use.')
1028
ret = apply_profiled(run, *run_argv)
1029
elif opt_coverage_dir:
1030
ret = apply_coveraged(opt_coverage_dir, run, *run_argv)
1032
ret = run(*run_argv)
1035
# reset, in case we may do other commands later within the same
1036
# process. Commands that want to execute sub-commands must propagate
1037
# --verbose in their own way.
1038
if 'memory' in debug.debug_flags:
1039
trace.debug_memory('Process status after command:', short=False)
1040
option._verbosity_level = saved_verbosity_level
1043
def display_command(func):
1044
"""Decorator that suppresses pipe/interrupt errors."""
1045
def ignore_pipe(*args, **kwargs):
1047
result = func(*args, **kwargs)
1051
if getattr(e, 'errno', None) is None:
1053
if e.errno != errno.EPIPE:
1054
# Win32 raises IOError with errno=0 on a broken pipe
1055
if sys.platform != 'win32' or (e.errno not in (0, errno.EINVAL)):
1058
except KeyboardInterrupt:
1063
def install_bzr_command_hooks():
1064
"""Install the hooks to supply bzr's own commands."""
1065
if _list_bzr_commands in Command.hooks["list_commands"]:
1067
Command.hooks.install_named_hook("list_commands", _list_bzr_commands,
1069
Command.hooks.install_named_hook("get_command", _get_bzr_command,
1071
Command.hooks.install_named_hook("get_command", _get_plugin_command,
1072
"bzr plugin commands")
1073
Command.hooks.install_named_hook("get_command", _get_external_command,
1074
"bzr external command lookup")
1075
Command.hooks.install_named_hook("get_missing_command", _try_plugin_provider,
1076
"bzr plugin-provider-db check")
1080
def _specified_or_unicode_argv(argv):
1081
# For internal or testing use, argv can be passed. Otherwise, get it from
1082
# the process arguments in a unicode-safe way.
1084
return osutils.get_unicode_argv()
626
ret = cmd_obj.run_argv(argv)
632
bzrlib.trace.log_startup(argv)
633
bzrlib.ui.ui_factory = bzrlib.ui.TextUIFactory()
635
return run_bzr_catch_errors(argv[1:])
1088
# ensure all arguments are unicode strings
1090
if isinstance(a, unicode):
1093
new_argv.append(a.decode('ascii'))
1094
except UnicodeDecodeError:
1095
raise errors.BzrError("argv should be list of unicode strings.")
1099
def main(argv=None):
1100
"""Main entry point of command-line interface.
1102
Typically `bzrlib.initialize` should be called first.
1104
:param argv: list of unicode command-line arguments similar to sys.argv.
1105
argv[0] is script name usually, it will be ignored.
1106
Don't pass here sys.argv because this list contains plain strings
1107
and not unicode; pass None instead.
1109
:return: exit code of bzr command.
1111
argv = _specified_or_unicode_argv(argv)
1112
ret = run_bzr_catch_errors(argv)
1113
bzrlib.ui.ui_factory.log_transport_activity(
1114
display=('bytes' in debug.debug_flags))
1115
trace.mutter("return code %d", ret)
638
1119
def run_bzr_catch_errors(argv):
1120
"""Run a bzr command with parameters as described by argv.
1122
This function assumed that that UI layer is setup, that symbol deprecations
1123
are already applied, and that unicode decoding has already been performed on argv.
1125
# done here so that they're covered for every test run
1126
install_bzr_command_hooks()
1127
return exception_to_return_code(run_bzr, argv)
1130
def run_bzr_catch_user_errors(argv):
1131
"""Run bzr and report user errors, but let internal errors propagate.
1133
This is used for the test suite, and might be useful for other programs
1134
that want to wrap the commandline interface.
1136
# done here so that they're covered for every test run
1137
install_bzr_command_hooks()
643
# do this here inside the exception wrappers to catch EPIPE
645
except BzrCommandError, e:
646
# command line syntax error, etc
650
bzrlib.trace.log_exception()
652
except AssertionError, e:
653
bzrlib.trace.log_exception('assertion failed: ' + str(e))
655
except KeyboardInterrupt, e:
656
bzrlib.trace.log_exception('interrupted')
1139
return run_bzr(argv)
658
1140
except Exception, e:
660
if (isinstance(e, IOError)
661
and hasattr(e, 'errno')
662
and e.errno == errno.EPIPE):
663
bzrlib.trace.note('broken pipe')
668
bzrlib.trace.log_exception()
671
if __name__ == '__main__':
672
sys.exit(main(sys.argv))
1141
if (isinstance(e, (OSError, IOError))
1142
or not getattr(e, 'internal_error', True)):
1143
trace.report_exception(sys.exc_info(), sys.stderr)
1149
class HelpCommandIndex(object):
1150
"""A index for bzr help that returns commands."""
1153
self.prefix = 'commands/'
1155
def get_topics(self, topic):
1156
"""Search for topic amongst commands.
1158
:param topic: A topic to search for.
1159
:return: A list which is either empty or contains a single
1162
if topic and topic.startswith(self.prefix):
1163
topic = topic[len(self.prefix):]
1165
cmd = _get_cmd_object(topic)
1172
class Provider(object):
1173
'''Generic class to be overriden by plugins'''
1175
def plugin_for_command(self, cmd_name):
1176
'''Takes a command and returns the information for that plugin
1178
:return: A dictionary with all the available information
1179
for the requested plugin
1181
raise NotImplementedError
1184
class ProvidersRegistry(registry.Registry):
1185
'''This registry exists to allow other providers to exist'''
1188
for key, provider in self.iteritems():
1191
command_providers_registry = ProvidersRegistry()