28
from bzrlib.lazy_import import lazy_import
29
from .lazy_import import lazy_import
29
30
lazy_import(globals(), """
33
from warnings import warn
49
from bzrlib.hooks import HookPoint, Hooks
48
from .hooks import Hooks
49
from .i18n import gettext
50
50
# Compatibility - Option used to be in commands.
51
from bzrlib.option import Option
52
from bzrlib.plugin import disable_plugins, load_plugins
53
from bzrlib import registry
54
from bzrlib.symbol_versioning import (
51
from .option import Option
52
from .plugin import disable_plugins, load_plugins, plugin_name
53
from . import errors, registry
60
class BzrOptionError(errors.BzrCommandError):
62
_fmt = "Error in command line options"
65
class CommandAvailableInPlugin(Exception):
67
internal_error = False
69
def __init__(self, cmd_name, plugin_metadata, provider):
71
self.plugin_metadata = plugin_metadata
72
self.cmd_name = cmd_name
73
self.provider = provider
77
_fmt = ('"%s" is not a standard brz command. \n'
78
'However, the following official plugin provides this command: %s\n'
79
'You can install it by going to: %s'
80
% (self.cmd_name, self.plugin_metadata['name'],
81
self.plugin_metadata['url']))
61
86
class CommandInfo(object):
62
87
"""Information about a command."""
164
189
def _unsquish_command_name(cmd):
165
return cmd[4:].replace('_','-')
168
@deprecated_function(deprecated_in((2, 2, 0)))
169
def _builtin_commands():
170
"""Return a dict of {name: cmd_class} for builtin commands.
172
:deprecated: Use the builtin_command_registry registry instead
174
# return dict(name: cmd_class)
175
return dict(builtin_command_registry.items())
190
return cmd[4:].replace('_', '-')
178
193
def _register_builtin_commands():
179
194
if builtin_command_registry.keys():
182
import bzrlib.builtins
183
for cmd_class in _scan_module_for_commands(bzrlib.builtins).values():
197
import breezy.builtins
198
for cmd_class in _scan_module_for_commands(breezy.builtins):
184
199
builtin_command_registry.register(cmd_class)
185
bzrlib.builtins._register_lazy_builtins()
200
breezy.builtins._register_lazy_builtins()
188
203
def _scan_module_for_commands(module):
190
for name, obj in module.__dict__.iteritems():
204
module_dict = module.__dict__
205
for name in module_dict:
191
206
if name.startswith("cmd_"):
192
real_name = _unsquish_command_name(name)
207
yield module_dict[name]
197
210
def _list_bzr_commands(names):
230
244
return plugin_cmds.keys()
247
# Overrides for common mispellings that heuristics get wrong
249
'ic': {'ci': 0}, # heuristic finds nick
253
def guess_command(cmd_name):
254
"""Guess what command a user typoed.
256
:param cmd_name: Command to search for
257
:return: None if no command was found, name of a command otherwise
260
for name in all_command_names():
262
cmd = get_cmd_object(name)
263
names.update(cmd.aliases)
264
# candidate: modified levenshtein distance against cmd_name.
266
from . import patiencediff
267
for name in sorted(names):
268
matcher = patiencediff.PatienceSequenceMatcher(None, cmd_name, name)
270
opcodes = matcher.get_opcodes()
271
for opcode, l1, l2, r1, r2 in opcodes:
272
if opcode == 'delete':
274
elif opcode == 'replace':
275
distance += max(l2-l1, r2-l1)
276
elif opcode == 'insert':
278
elif opcode == 'equal':
279
# Score equal ranges lower, making similar commands of equal
280
# length closer than arbitrary same length commands.
281
distance -= 0.1 * (l2-l1)
282
costs[name] = distance
283
costs.update(_GUESS_OVERRIDES.get(cmd_name, {}))
284
costs = sorted((costs[key], key) for key in costs)
289
candidate = costs[0][1]
233
293
def get_cmd_object(cmd_name, plugins_override=True):
234
294
"""Return the command object for a command.
240
300
return _get_cmd_object(cmd_name, plugins_override)
242
raise errors.BzrCommandError('unknown command "%s"' % cmd_name)
302
# No command found, see if this was a typo
303
candidate = guess_command(cmd_name)
304
if candidate is not None:
305
raise errors.BzrCommandError(
306
gettext('unknown command "%s". Perhaps you meant "%s"')
307
% (cmd_name, candidate))
308
raise errors.BzrCommandError(gettext('unknown command "%s"')
245
312
def _get_cmd_object(cmd_name, plugins_override=True, check_missing=True):
275
342
# Allow plugins to extend commands
276
343
for hook in Command.hooks['extend_command']:
345
if getattr(cmd, 'invoked_as', None) is None:
346
cmd.invoked_as = cmd_name
350
class NoPluginAvailable(errors.BzrError):
281
354
def _try_plugin_provider(cmd_name):
282
355
"""Probe for a plugin provider having cmd_name."""
284
357
plugin_metadata, provider = probe_for_provider(cmd_name)
285
raise errors.CommandAvailableInPlugin(cmd_name,
286
plugin_metadata, provider)
287
except errors.NoPluginAvailable:
358
raise CommandAvailableInPlugin(cmd_name, plugin_metadata, provider)
359
except NoPluginAvailable:
357
429
summary, then a complete description of the command. A grammar
358
430
description will be inserted.
361
Other accepted names for this command.
364
List of argument forms, marked with whether they are optional,
369
['to_location', 'from_branch?', 'file*']
371
'to_location' is required
372
'from_branch' is optional
373
'file' can be specified 0 or more times
376
List of options that may be given for this command. These can
377
be either strings, referring to globally-defined options,
378
or option objects. Retrieve through options().
381
If true, this command isn't advertised. This is typically
432
:cvar aliases: Other accepted names for this command.
434
:cvar takes_args: List of argument forms, marked with whether they are
435
optional, repeated, etc. Examples::
437
['to_location', 'from_branch?', 'file*']
439
* 'to_location' is required
440
* 'from_branch' is optional
441
* 'file' can be specified 0 or more times
443
:cvar takes_options: List of options that may be given for this command.
444
These can be either strings, referring to globally-defined options, or
445
option objects. Retrieve through options().
447
:cvar hidden: If true, this command isn't advertised. This is typically
382
448
for commands intended for expert users.
385
Command objects will get a 'outf' attribute, which has been
386
setup to properly handle encoding of unicode strings.
387
encoding_type determines what will happen when characters cannot
389
strict - abort if we cannot decode
390
replace - put in a bogus character (typically '?')
391
exact - do not encode sys.stdout
393
NOTE: by default on Windows, sys.stdout is opened as a text
394
stream, therefore LF line-endings are converted to CRLF.
395
When a command uses encoding_type = 'exact', then
396
sys.stdout is forced to be a binary stream, and line-endings
450
:cvar encoding_type: Command objects will get a 'outf' attribute, which has
451
been setup to properly handle encoding of unicode strings.
452
encoding_type determines what will happen when characters cannot be
455
* strict - abort if we cannot decode
456
* replace - put in a bogus character (typically '?')
457
* exact - do not encode sys.stdout
459
NOTE: by default on Windows, sys.stdout is opened as a text stream,
460
therefore LF line-endings are converted to CRLF. When a command uses
461
encoding_type = 'exact', then sys.stdout is forced to be a binary
462
stream, and line-endings will not mangled.
465
A string indicating the real name under which this command was
466
invoked, before expansion of aliases.
467
(This may be None if the command was constructed and run in-process.)
399
469
:cvar hooks: An instance of CommandHooks.
471
:cvar __doc__: The help shown by 'brz help command' for this command.
472
This is set by assigning explicitly to __doc__ so that -OO can
476
__doc__ = "My help goes here"
403
480
takes_options = []
404
481
encoding_type = 'strict'
408
487
def __init__(self):
409
488
"""Construct an instance of this command."""
410
if self.__doc__ == Command.__doc__:
411
warn("No help message set for %r" % self)
412
489
# List of standard options directly supported
413
490
self.supported_std_options = []
414
491
self._setup_run()
436
513
self._operation.cleanup_now()
438
@deprecated_method(deprecated_in((2, 1, 0)))
439
def _maybe_expand_globs(self, file_list):
440
"""Glob expand file_list if the platform does not do that itself.
442
Not used anymore, now that the bzr command-line parser globs on
445
:return: A possibly empty list of unicode paths.
447
Introduced in bzrlib 0.18.
451
515
def _usage(self):
452
516
"""Return single-line grammar for this command.
454
518
Only describes arguments, not options.
456
s = 'bzr ' + self.name() + ' '
520
s = 'brz ' + self.name() + ' '
457
521
for aname in self.takes_args:
458
522
aname = aname.upper()
459
523
if aname[-1] in ['$', '+']:
481
545
usage help (e.g. Purpose, Usage, Options) with a
482
546
message explaining how to obtain full help.
549
i18n.install() # Install i18n only for get_help_text for now.
484
550
doc = self.help()
486
raise NotImplementedError("sorry, no detailed help yet for %r" % self.name())
552
# Note: If self.gettext() translates ':Usage:\n', the section will
553
# be shown after "Description" section and we don't want to
554
# translate the usage string.
555
# Though, brz export-pot don't exports :Usage: section and it must
557
doc = self.gettext(doc)
559
doc = gettext("No help for this command.")
488
561
# Extract the summary (purpose) and sections out from the text
489
purpose,sections,order = self._get_help_parts(doc)
562
purpose, sections, order = self._get_help_parts(doc)
491
564
# If a custom usage section was provided, use it
492
if sections.has_key('Usage'):
565
if 'Usage' in sections:
493
566
usage = sections.pop('Usage')
495
568
usage = self._usage()
497
570
# The header is the purpose and usage
499
result += ':Purpose: %s\n' % purpose
572
result += gettext(':Purpose: %s\n') % (purpose,)
500
573
if usage.find('\n') >= 0:
501
result += ':Usage:\n%s\n' % usage
574
result += gettext(':Usage:\n%s\n') % (usage,)
503
result += ':Usage: %s\n' % usage
576
result += gettext(':Usage: %s\n') % (usage,)
506
579
# Add the options
508
581
# XXX: optparse implicitly rewraps the help, and not always perfectly,
509
582
# so we get <https://bugs.launchpad.net/bzr/+bug/249908>. -- mbp
511
options = option.get_optparser(self.options()).format_option_help()
512
# XXX: According to the spec, ReST option lists actually don't support
513
# options like --1.9 so that causes syntax errors (in Sphinx at least).
514
# As that pattern always appears in the commands that break, we trap
515
# on that and then format that block of 'format' options as a literal
517
if not plain and options.find(' --1.9 ') != -1:
584
parser = option.get_optparser(self.options())
585
options = parser.format_option_help()
586
# FIXME: According to the spec, ReST option lists actually don't
587
# support options like --1.14 so that causes syntax errors (in Sphinx
588
# at least). As that pattern always appears in the commands that
589
# break, we trap on that and then format that block of 'format' options
590
# as a literal block. We use the most recent format still listed so we
591
# don't have to do that too often -- vila 20110514
592
if not plain and options.find(' --1.14 ') != -1:
518
593
options = options.replace(' format:\n', ' format::\n\n', 1)
519
594
if options.startswith('Options:'):
520
result += ':' + options
521
elif options.startswith('options:'):
522
# Python 2.4 version of optparse
523
result += ':Options:' + options[len('options:'):]
595
result += gettext(':Options:%s') % (options[len('options:'):],)
525
597
result += options
529
601
# Add the description, indenting it 2 spaces
530
602
# to match the indentation of the options
531
if sections.has_key(None):
532
604
text = sections.pop(None)
533
605
text = '\n '.join(text.splitlines())
534
result += ':%s:\n %s\n\n' % ('Description',text)
606
result += gettext(':Description:\n %s\n\n') % (text,)
536
608
# Add the custom sections (e.g. Examples). Note that there's no need
537
609
# to indent these as they must be indented already in the source.
539
611
for label in order:
540
if sections.has_key(label):
541
result += ':%s:\n%s\n' % (label,sections[label])
612
if label in sections:
613
result += ':%s:\n%s\n' % (label, sections[label])
544
result += ("See bzr help %s for more details and examples.\n\n"
616
result += (gettext("See brz help %s for more details and examples.\n\n")
547
619
# Add the aliases, source (plug-in) and see also links, if any
549
result += ':Aliases: '
621
result += gettext(':Aliases: ')
550
622
result += ', '.join(self.aliases) + '\n'
551
623
plugin_name = self.plugin_name()
552
624
if plugin_name is not None:
553
result += ':From: plugin "%s"\n' % plugin_name
625
result += gettext(':From: plugin "%s"\n') % plugin_name
554
626
see_also = self.get_see_also(additional_see_also)
556
628
if not plain and see_also_as_links:
562
634
see_also_links.append(item)
564
636
# Use a Sphinx link for this entry
565
link_text = ":doc:`%s <%s-help>`" % (item, item)
637
link_text = gettext(":doc:`{0} <{1}-help>`").format(
566
639
see_also_links.append(link_text)
567
640
see_also = see_also_links
568
result += ':See also: '
569
result += ', '.join(see_also) + '\n'
641
result += gettext(':See also: %s') % ', '.join(see_also) + '\n'
571
643
# If this will be rendered as plain text, convert it
573
import bzrlib.help_topics
574
result = bzrlib.help_topics.help_as_plain_text(result)
645
import breezy.help_topics
646
result = breezy.help_topics.help_as_plain_text(result)
598
670
summary = lines.pop(0)
601
label,section = None,''
673
label, section = None, ''
602
674
for line in lines:
603
675
if line.startswith(':') and line.endswith(':') and len(line) > 2:
604
676
save_section(sections, order, label, section)
605
label,section = line[1:-1],''
677
label, section = line[1:-1], ''
606
678
elif (label is not None) and len(line) > 1 and not line[0].isspace():
607
679
save_section(sections, order, label, section)
608
label,section = None,line
680
label, section = None, line
610
682
if len(section) > 0:
611
683
section += '\n' + line
653
725
def run_argv_aliases(self, argv, alias_argv=None):
654
726
"""Parse the command line and run with extra aliases in alias_argv."""
655
727
args, opts = parse_args(self, argv, alias_argv)
657
730
# Process the standard options
658
if 'help' in opts: # e.g. bzr add --help
659
sys.stdout.write(self.get_help_text())
731
if 'help' in opts: # e.g. brz add --help
732
self.outf.write(self.get_help_text())
661
if 'usage' in opts: # e.g. bzr add --usage
662
sys.stdout.write(self.get_help_text(verbose=False))
734
if 'usage' in opts: # e.g. brz add --usage
735
self.outf.write(self.get_help_text(verbose=False))
664
737
trace.set_verbosity_level(option._verbosity_level)
665
738
if 'verbose' in self.supported_std_options:
666
739
opts['verbose'] = trace.is_verbose()
667
elif opts.has_key('verbose'):
740
elif 'verbose' in opts:
668
741
del opts['verbose']
669
742
if 'quiet' in self.supported_std_options:
670
743
opts['quiet'] = trace.is_quiet()
671
elif opts.has_key('quiet'):
744
elif 'quiet' in opts:
672
745
del opts['quiet']
674
746
# mix arguments and options into one dictionary
675
747
cmdargs = _match_argform(self.name(), self.takes_args, args)
680
752
all_cmd_args = cmdargs.copy()
681
753
all_cmd_args.update(cmdopts)
685
return self.run(**all_cmd_args)
756
return self.run(**all_cmd_args)
758
# reset it, so that other commands run in the same process won't
759
# inherit state. Before we reset it, log any activity, so that it
760
# gets properly tracked.
761
ui.ui_factory.log_transport_activity(
762
display=('bytes' in debug.debug_flags))
763
trace.set_verbosity_level(0)
687
765
def _setup_run(self):
688
766
"""Wrap the defined run method on self with a cleanup.
696
774
class_run = self.run
697
775
def run(*args, **kwargs):
776
for hook in Command.hooks['pre_command']:
698
778
self._operation = cleanup.OperationWithCleanups(class_run)
700
780
return self._operation.run_simple(*args, **kwargs)
702
782
del self._operation
783
for hook in Command.hooks['post_command']:
705
@deprecated_method(deprecated_in((2, 2, 0)))
706
def run_direct(self, *args, **kwargs):
707
"""Deprecated thunk from bzrlib 2.1."""
708
return self.run(*args, **kwargs)
711
788
"""Actually run the command.
762
847
These are all empty initially, because by default nothing should get
766
self.create_hook(HookPoint('extend_command',
850
Hooks.__init__(self, "breezy.commands", "Command.hooks")
851
self.add_hook('extend_command',
767
852
"Called after creating a command object to allow modifications "
768
853
"such as adding or removing options, docs etc. Called with the "
769
"new bzrlib.commands.Command object.", (1, 13), None))
770
self.create_hook(HookPoint('get_command',
854
"new breezy.commands.Command object.", (1, 13))
855
self.add_hook('get_command',
771
856
"Called when creating a single command. Called with "
772
857
"(cmd_or_None, command_name). get_command should either return "
773
858
"the cmd_or_None parameter, or a replacement Command object that "
774
859
"should be used for the command. Note that the Command.hooks "
775
860
"hooks are core infrastructure. Many users will prefer to use "
776
"bzrlib.commands.register_command or plugin_cmds.register_lazy.",
778
self.create_hook(HookPoint('get_missing_command',
861
"breezy.commands.register_command or plugin_cmds.register_lazy.",
863
self.add_hook('get_missing_command',
779
864
"Called when creating a single command if no command could be "
780
865
"found. Called with (command_name). get_missing_command should "
781
866
"either return None, or a Command object to be used for the "
782
"command.", (1, 17), None))
783
self.create_hook(HookPoint('list_commands',
868
self.add_hook('list_commands',
784
869
"Called when enumerating commands. Called with a set of "
785
870
"cmd_name strings for all the commands found so far. This set "
786
871
" is safe to mutate - e.g. to remove a command. "
787
872
"list_commands should return the updated set of command names.",
874
self.add_hook('pre_command',
875
"Called prior to executing a command. Called with the command "
877
self.add_hook('post_command',
878
"Called after executing a command. Called with the command "
790
881
Command.hooks = CommandHooks()
808
options, args = parser.parse_args(args)
809
opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
810
v is not option.OptionParser.DEFAULT_VALUE])
899
# for python 2.5 and later, optparse raises this exception if a non-ascii
900
# option name is given. See http://bugs.python.org/issue2931
902
options, args = parser.parse_args(args)
903
except UnicodeEncodeError as e:
904
raise errors.BzrCommandError(
905
gettext('Only ASCII permitted in option names'))
907
opts = dict((k, v) for k, v in options.__dict__.items() if
908
v is not option.OptionParser.DEFAULT_VALUE)
811
909
return args, opts
828
926
argdict[argname + '_list'] = None
829
927
elif ap[-1] == '+':
831
raise errors.BzrCommandError("command %r needs one or more %s"
832
% (cmd, argname.upper()))
929
raise errors.BzrCommandError(gettext(
930
"command {0!r} needs one or more {1}").format(
931
cmd, argname.upper()))
834
933
argdict[argname + '_list'] = args[:]
836
935
elif ap[-1] == '$': # all but one
837
936
if len(args) < 2:
838
raise errors.BzrCommandError("command %r needs one or more %s"
839
% (cmd, argname.upper()))
937
raise errors.BzrCommandError(
938
gettext("command {0!r} needs one or more {1}").format(
939
cmd, argname.upper()))
840
940
argdict[argname + '_list'] = args[:-1]
843
943
# just a plain arg
846
raise errors.BzrCommandError("command %r requires argument %s"
847
% (cmd, argname.upper()))
946
raise errors.BzrCommandError(
947
gettext("command {0!r} requires argument {1}").format(
948
cmd, argname.upper()))
849
950
argdict[argname] = args.pop(0)
852
raise errors.BzrCommandError("extra argument to command %s: %s"
953
raise errors.BzrCommandError( gettext(
954
"extra argument to command {0}: {1}").format(
857
960
def apply_coveraged(dirname, the_callable, *args, **kwargs):
858
# Cannot use "import trace", as that would import bzrlib.trace instead of
859
# the standard library's trace.
860
trace = __import__('trace')
862
962
tracer = trace.Trace(count=1, trace=0)
863
963
sys.settrace(tracer.globaltrace)
864
964
threading.settrace(tracer.globaltrace)
907
1007
return the_callable(*args, **kwargs)
908
except (KeyboardInterrupt, Exception), e:
1008
except (KeyboardInterrupt, Exception) as e:
909
1009
# used to handle AssertionError and KeyboardInterrupt
910
1010
# specially here, but hopefully they're handled ok by the logger now
911
1011
exc_info = sys.exc_info()
912
1012
exitcode = trace.report_exception(exc_info, sys.stderr)
913
if os.environ.get('BZR_PDB'):
914
print '**** entering debugger'
1013
if os.environ.get('BRZ_PDB'):
1014
print('**** entering debugger')
917
if sys.version_info[:2] < (2, 6):
919
# pdb.post_mortem(tb)
920
# but because pdb.post_mortem gives bad results for tracebacks
921
# from inside generators, we do it manually.
922
# (http://bugs.python.org/issue4150, fixed in Python 2.6)
924
# Setup pdb on the traceback
927
p.setup(tb.tb_frame, tb)
928
# Point the debugger at the deepest frame of the stack
929
p.curindex = len(p.stack) - 1
930
p.curframe = p.stack[p.curindex][0]
931
# Start the pdb prompt.
932
p.print_stack_entry(p.stack[p.curindex])
1016
pdb.post_mortem(exc_info[2])
940
1020
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
941
from bzrlib.lsprof import profile
942
ret, stats = profile(exception_to_return_code, the_callable, *args, **kwargs)
1021
from breezy.lsprof import profile
1022
ret, stats = profile(exception_to_return_code, the_callable,
944
1025
if filename is None:
947
1028
stats.save(filename)
948
trace.note('Profile data written to "%s".', filename)
1029
trace.note(gettext('Profile data written to "%s".'), filename)
952
@deprecated_function(deprecated_in((2, 2, 0)))
953
def shlex_split_unicode(unsplit):
954
return cmdline.split(unsplit)
957
1033
def get_alias(cmd, config=None):
958
1034
"""Return an expanded alias, or None if no alias exists.
1015
1091
Specify the number of processes that can be run concurrently (selftest).
1017
trace.mutter("bazaar version: " + bzrlib.__version__)
1019
trace.mutter("bzr arguments: %r", argv)
1093
trace.mutter("breezy version: " + breezy.__version__)
1094
argv = _specified_or_unicode_argv(argv)
1095
trace.mutter("brz arguments: %r", argv)
1021
opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = \
1022
opt_no_aliases = False
1097
opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = \
1098
opt_no_l10n = opt_no_aliases = False
1023
1099
opt_lsprof_file = opt_coverage_dir = None
1025
1101
# --no-plugins is handled specially at a very early stage. We need
1042
1119
opt_no_plugins = True
1043
1120
elif a == '--no-aliases':
1044
1121
opt_no_aliases = True
1122
elif a == '--no-l10n':
1045
1124
elif a == '--builtin':
1046
1125
opt_builtin = True
1047
1126
elif a == '--concurrency':
1048
os.environ['BZR_CONCURRENCY'] = argv[i + 1]
1127
os.environ['BRZ_CONCURRENCY'] = argv[i + 1]
1050
1129
elif a == '--coverage':
1051
1130
opt_coverage_dir = argv[i + 1]
1132
elif a == '--profile-imports':
1133
pass # already handled in startup script Bug #588277
1053
1134
elif a.startswith('-D'):
1054
1135
debug.debug_flags.add(a[2:])
1136
elif a.startswith('-O'):
1137
override_config.append(a[2:])
1056
1139
argv_copy.append(a)
1142
cmdline_overrides = breezy.get_global_state().cmdline_overrides
1143
cmdline_overrides._from_cmdline(override_config)
1059
1145
debug.set_debug_flags_from_config()
1061
1147
if not opt_no_plugins:
1077
1163
if not opt_no_aliases:
1078
1164
alias_argv = get_alias(argv[0])
1080
user_encoding = osutils.get_user_encoding()
1081
alias_argv = [a.decode(user_encoding) for a in alias_argv]
1082
1166
argv[0] = alias_argv.pop(0)
1084
1168
cmd = argv.pop(0)
1085
# We want only 'ascii' command names, but the user may have typed
1086
# in a Unicode name. In that case, they should just get a
1087
# 'command not found' error later.
1089
1169
cmd_obj = get_cmd_object(cmd, plugins_override=not opt_builtin)
1171
cmd_obj.l10n = False
1090
1172
run = cmd_obj.run_argv_aliases
1091
1173
run_argv = [argv, alias_argv]
1161
1246
# the process arguments in a unicode-safe way.
1162
1247
if argv is None:
1163
1248
return osutils.get_unicode_argv()
1167
# ensure all arguments are unicode strings
1169
if isinstance(a, unicode):
1172
new_argv.append(a.decode('ascii'))
1173
except UnicodeDecodeError:
1174
raise errors.BzrError("argv should be list of unicode strings.")
1251
# ensure all arguments are unicode strings
1253
if not isinstance(a, string_types):
1254
raise ValueError('not native str or unicode: %r' % (a,))
1255
if isinstance(a, bytes):
1256
# For Python 2 only allow ascii native strings
1257
a = a.decode('ascii')
1259
except (ValueError, UnicodeDecodeError):
1260
raise errors.BzrError("argv should be list of unicode strings.")
1178
1264
def main(argv=None):
1179
1265
"""Main entry point of command-line interface.
1181
Typically `bzrlib.initialize` should be called first.
1267
Typically `breezy.initialize` should be called first.
1183
1269
:param argv: list of unicode command-line arguments similar to sys.argv.
1184
1270
argv[0] is script name usually, it will be ignored.
1185
1271
Don't pass here sys.argv because this list contains plain strings
1186
1272
and not unicode; pass None instead.
1188
:return: exit code of bzr command.
1274
:return: exit code of brz command.
1190
argv = _specified_or_unicode_argv(argv)
1276
if argv is not None:
1191
1278
_register_builtin_commands()
1192
1279
ret = run_bzr_catch_errors(argv)
1193
bzrlib.ui.ui_factory.log_transport_activity(
1194
display=('bytes' in debug.debug_flags))
1195
1280
trace.mutter("return code %d", ret)
1252
1337
class Provider(object):
1253
'''Generic class to be overriden by plugins'''
1338
"""Generic class to be overriden by plugins"""
1255
1340
def plugin_for_command(self, cmd_name):
1256
'''Takes a command and returns the information for that plugin
1341
"""Takes a command and returns the information for that plugin
1258
1343
:return: A dictionary with all the available information
1259
for the requested plugin
1344
for the requested plugin
1261
1346
raise NotImplementedError
1264
1349
class ProvidersRegistry(registry.Registry):
1265
'''This registry exists to allow other providers to exist'''
1350
"""This registry exists to allow other providers to exist"""
1267
1352
def __iter__(self):
1268
for key, provider in self.iteritems():
1353
for key, provider in self.items():
1271
1356
command_providers_registry = ProvidersRegistry()