14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
from __future__ import absolute_import
19
17
# TODO: Define arguments by objects, rather than just using names.
20
18
# Those objects can specify the expected type of the argument, which
21
19
# would help with validation and shell completion. They could also provide
24
22
# TODO: Specific "examples" property on commands for consistent formatting.
29
from bzrlib.lazy_import import lazy_import
34
from .lazy_import import lazy_import
30
35
lazy_import(globals(), """
49
from bzrlib.hooks import Hooks
50
from bzrlib.i18n import gettext
47
from .hooks import Hooks
48
from .i18n import gettext
51
49
# Compatibility - Option used to be in commands.
52
from bzrlib.option import Option
53
from bzrlib.plugin import disable_plugins, load_plugins
54
from bzrlib import registry
50
from .option import Option
51
from .plugin import disable_plugins, load_plugins, plugin_name
52
from . import errors, registry
55
class BzrOptionError(errors.CommandError):
57
_fmt = "Error in command line options"
60
class CommandAvailableInPlugin(Exception):
62
internal_error = False
64
def __init__(self, cmd_name, plugin_metadata, provider):
66
self.plugin_metadata = plugin_metadata
67
self.cmd_name = cmd_name
68
self.provider = provider
72
_fmt = ('"%s" is not a standard brz command. \n'
73
'However, the following official plugin provides this command: %s\n'
74
'You can install it by going to: %s'
75
% (self.cmd_name, self.plugin_metadata['name'],
76
self.plugin_metadata['url']))
57
81
class CommandInfo(object):
119
143
trace.warning('Two plugins defined the same command: %r' % k)
120
144
trace.warning('Not loading the one in %r' %
121
sys.modules[cmd.__module__])
145
sys.modules[cmd.__module__])
122
146
trace.warning('Previously this command was registered from %r' %
123
sys.modules[previous.__module__])
147
sys.modules[previous.__module__])
124
148
for a in cmd.aliases:
125
149
self._alias_dict[a] = k_unsquished
147
171
def register_command(cmd, decorate=False):
148
172
"""Register a plugin command.
150
Should generally be avoided in favor of lazy registration.
174
Should generally be avoided in favor of lazy registration.
152
176
global plugin_cmds
153
177
return plugin_cmds.register(cmd, decorate)
160
184
def _unsquish_command_name(cmd):
161
return cmd[4:].replace('_','-')
185
return cmd[4:].replace('_', '-')
164
188
def _register_builtin_commands():
165
189
if builtin_command_registry.keys():
168
import bzrlib.builtins
169
for cmd_class in _scan_module_for_commands(bzrlib.builtins).values():
192
import breezy.builtins
193
for cmd_class in _scan_module_for_commands(breezy.builtins):
170
194
builtin_command_registry.register(cmd_class)
171
bzrlib.builtins._register_lazy_builtins()
195
breezy.builtins._register_lazy_builtins()
174
198
def _scan_module_for_commands(module):
176
for name, obj in module.__dict__.iteritems():
199
module_dict = module.__dict__
200
for name in module_dict:
177
201
if name.startswith("cmd_"):
178
real_name = _unsquish_command_name(name)
202
yield module_dict[name]
183
205
def _list_bzr_commands(names):
184
206
"""Find commands from bzr's core and plugins.
186
This is not the public interface, just the default hook called by all_command_names.
208
This is not the public interface, just the default hook called by
188
211
# to eliminate duplicates
189
212
names.update(builtin_command_names())
217
240
return plugin_cmds.keys()
243
# Overrides for common mispellings that heuristics get wrong
245
'ic': {'ci': 0}, # heuristic finds nick
249
def guess_command(cmd_name):
250
"""Guess what command a user typoed.
252
:param cmd_name: Command to search for
253
:return: None if no command was found, name of a command otherwise
256
for name in all_command_names():
258
cmd = get_cmd_object(name)
259
names.update(cmd.aliases)
260
# candidate: modified levenshtein distance against cmd_name.
263
for name in sorted(names):
264
matcher = patiencediff.PatienceSequenceMatcher(None, cmd_name, name)
266
opcodes = matcher.get_opcodes()
267
for opcode, l1, l2, r1, r2 in opcodes:
268
if opcode == 'delete':
270
elif opcode == 'replace':
271
distance += max(l2 - l1, r2 - l1)
272
elif opcode == 'insert':
274
elif opcode == 'equal':
275
# Score equal ranges lower, making similar commands of equal
276
# length closer than arbitrary same length commands.
277
distance -= 0.1 * (l2 - l1)
278
costs[name] = distance
279
costs.update(_GUESS_OVERRIDES.get(cmd_name, {}))
280
costs = sorted((costs[key], key) for key in costs)
285
candidate = costs[0][1]
220
289
def get_cmd_object(cmd_name, plugins_override=True):
221
290
"""Return the command object for a command.
227
296
return _get_cmd_object(cmd_name, plugins_override)
229
raise errors.BzrCommandError(gettext('unknown command "%s"') % cmd_name)
298
# No command found, see if this was a typo
299
candidate = guess_command(cmd_name)
300
if candidate is not None:
301
raise errors.CommandError(
302
gettext('unknown command "%s". Perhaps you meant "%s"')
303
% (cmd_name, candidate))
304
raise errors.CommandError(gettext('unknown command "%s"')
232
308
def _get_cmd_object(cmd_name, plugins_override=True, check_missing=True):
346
class NoPluginAvailable(errors.BzrError):
270
350
def _try_plugin_provider(cmd_name):
271
351
"""Probe for a plugin provider having cmd_name."""
273
353
plugin_metadata, provider = probe_for_provider(cmd_name)
274
raise errors.CommandAvailableInPlugin(cmd_name,
275
plugin_metadata, provider)
276
except errors.NoPluginAvailable:
354
raise CommandAvailableInPlugin(cmd_name, plugin_metadata, provider)
355
except NoPluginAvailable:
288
367
for provider in command_providers_registry:
290
369
return provider.plugin_for_command(cmd_name), provider
291
except errors.NoPluginAvailable:
370
except NoPluginAvailable:
293
raise errors.NoPluginAvailable(cmd_name)
372
raise NoPluginAvailable(cmd_name)
296
375
def _get_bzr_command(cmd_or_None, cmd_name):
309
388
# Only do external command lookups when no command is found so far.
310
389
if cmd_or_None is not None:
311
390
return cmd_or_None
312
from bzrlib.externalcommand import ExternalCommand
391
from breezy.externalcommand import ExternalCommand
313
392
cmd_obj = ExternalCommand.find_command(cmd_name)
318
397
def _get_plugin_command(cmd_or_None, cmd_name):
319
"""Get a command from bzr's plugins."""
398
"""Get a command from brz's plugins."""
321
400
return plugin_cmds.get(cmd_name)()
331
410
class Command(object):
332
411
"""Base class for commands.
334
Commands are the heart of the command-line bzr interface.
413
Commands are the heart of the command-line brz interface.
336
415
The command object mostly handles the mapping of command-line
337
parameters into one or more bzrlib operations, and of the results
416
parameters into one or more breezy operations, and of the results
338
417
into textual output.
340
419
Commands normally don't have any state. All their arguments are
413
492
Functions will be called in LIFO order.
415
self._operation.add_cleanup(cleanup_func, *args, **kwargs)
494
self._exit_stack.callback(cleanup_func, *args, **kwargs)
417
496
def cleanup_now(self):
418
497
"""Execute and empty pending cleanup functions immediately.
427
506
as it releases all resources, this may release locks that the command
428
507
wants to hold, so use should be done with care.
430
self._operation.cleanup_now()
509
self._exit_stack.close()
511
def enter_context(self, cm):
512
return self._exit_stack.enter_context(cm)
432
514
def _usage(self):
433
515
"""Return single-line grammar for this command.
435
517
Only describes arguments, not options.
437
s = 'bzr ' + self.name() + ' '
519
s = 'brz ' + self.name() + ' '
438
520
for aname in self.takes_args:
439
521
aname = aname.upper()
440
522
if aname[-1] in ['$', '+']:
469
551
# Note: If self.gettext() translates ':Usage:\n', the section will
470
552
# be shown after "Description" section and we don't want to
471
553
# translate the usage string.
472
# Though, bzr export-pot don't exports :Usage: section and it must
554
# Though, brz export-pot don't exports :Usage: section and it must
473
555
# not be translated.
474
556
doc = self.gettext(doc)
476
558
doc = gettext("No help for this command.")
478
560
# Extract the summary (purpose) and sections out from the text
479
purpose,sections,order = self._get_help_parts(doc)
561
purpose, sections, order = self._get_help_parts(doc)
481
563
# If a custom usage section was provided, use it
482
if sections.has_key('Usage'):
564
if 'Usage' in sections:
483
565
usage = sections.pop('Usage')
485
567
usage = self._usage()
498
580
# XXX: optparse implicitly rewraps the help, and not always perfectly,
499
581
# so we get <https://bugs.launchpad.net/bzr/+bug/249908>. -- mbp
501
parser = option.get_optparser(self.options())
583
parser = option.get_optparser(
584
[v for k, v in sorted(self.options().items())])
502
585
options = parser.format_option_help()
503
586
# FIXME: According to the spec, ReST option lists actually don't
504
587
# support options like --1.14 so that causes syntax errors (in Sphinx
518
601
# Add the description, indenting it 2 spaces
519
602
# to match the indentation of the options
520
if sections.has_key(None):
521
604
text = sections.pop(None)
522
605
text = '\n '.join(text.splitlines())
523
606
result += gettext(':Description:\n %s\n\n') % (text,)
530
613
result += ':%s:\n%s\n' % (label, sections[label])
533
result += (gettext("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")
536
619
# Add the aliases, source (plug-in) and see also links, if any
553
636
# Use a Sphinx link for this entry
554
637
link_text = gettext(":doc:`{0} <{1}-help>`").format(
556
639
see_also_links.append(link_text)
557
640
see_also = see_also_links
558
641
result += gettext(':See also: %s') % ', '.join(see_also) + '\n'
560
643
# If this will be rendered as plain text, convert it
562
import bzrlib.help_topics
563
result = bzrlib.help_topics.help_as_plain_text(result)
645
import breezy.help_topics
646
result = breezy.help_topics.help_as_plain_text(result)
587
670
summary = lines.pop(0)
590
label,section = None,''
673
label, section = None, ''
591
674
for line in lines:
592
675
if line.startswith(':') and line.endswith(':') and len(line) > 2:
593
676
save_section(sections, order, label, section)
594
label,section = line[1:-1],''
595
elif (label is not None) and len(line) > 1 and not line[0].isspace():
677
label, section = line[1:-1], ''
678
elif (label is not None and len(line) > 1 and
679
not line[0].isspace()):
596
680
save_section(sections, order, label, section)
597
label,section = None,line
681
label, section = None, line
599
683
if len(section) > 0:
600
684
section += '\n' + line
645
729
self._setup_outf()
647
731
# Process the standard options
648
if 'help' in opts: # e.g. bzr add --help
732
if 'help' in opts: # e.g. brz add --help
649
733
self.outf.write(self.get_help_text())
651
if 'usage' in opts: # e.g. bzr add --usage
735
if 'usage' in opts: # e.g. brz add --usage
652
736
self.outf.write(self.get_help_text(verbose=False))
654
738
trace.set_verbosity_level(option._verbosity_level)
655
739
if 'verbose' in self.supported_std_options:
656
740
opts['verbose'] = trace.is_verbose()
657
elif opts.has_key('verbose'):
741
elif 'verbose' in opts:
658
742
del opts['verbose']
659
743
if 'quiet' in self.supported_std_options:
660
744
opts['quiet'] = trace.is_quiet()
661
elif opts.has_key('quiet'):
745
elif 'quiet' in opts:
662
746
del opts['quiet']
663
747
# mix arguments and options into one dictionary
664
748
cmdargs = _match_argform(self.name(), self.takes_args, args)
689
773
you can override this method.
691
775
class_run = self.run
692
777
def run(*args, **kwargs):
693
778
for hook in Command.hooks['pre_command']:
695
self._operation = cleanup.OperationWithCleanups(class_run)
697
return self._operation.run_simple(*args, **kwargs)
781
with contextlib.ExitStack() as self._exit_stack:
782
return class_run(*args, **kwargs)
700
784
for hook in Command.hooks['post_command']:
711
795
shell error code if not. It's OK for this method to allow
712
796
an exception to raise up.
714
This method is automatically wrapped by Command.__init__ with a
715
cleanup operation, stored as self._operation. This can be used
798
This method is automatically wrapped by Command.__init__ with a
799
ExitStack, stored as self._exit_stack. This can be used
716
800
via self.add_cleanup to perform automatic cleanups at the end of
768
848
These are all empty initially, because by default nothing should get
771
Hooks.__init__(self, "bzrlib.commands", "Command.hooks")
772
self.add_hook('extend_command',
851
Hooks.__init__(self, "breezy.commands", "Command.hooks")
773
854
"Called after creating a command object to allow modifications "
774
855
"such as adding or removing options, docs etc. Called with the "
775
"new bzrlib.commands.Command object.", (1, 13))
776
self.add_hook('get_command',
856
"new breezy.commands.Command object.", (1, 13))
777
859
"Called when creating a single command. Called with "
778
860
"(cmd_or_None, command_name). get_command should either return "
779
861
"the cmd_or_None parameter, or a replacement Command object that "
780
862
"should be used for the command. Note that the Command.hooks "
781
863
"hooks are core infrastructure. Many users will prefer to use "
782
"bzrlib.commands.register_command or plugin_cmds.register_lazy.",
864
"breezy.commands.register_command or plugin_cmds.register_lazy.",
784
self.add_hook('get_missing_command',
867
'get_missing_command',
785
868
"Called when creating a single command if no command could be "
786
869
"found. Called with (command_name). get_missing_command should "
787
870
"either return None, or a Command object to be used for the "
788
871
"command.", (1, 17))
789
self.add_hook('list_commands',
790
874
"Called when enumerating commands. Called with a set of "
791
875
"cmd_name strings for all the commands found so far. This set "
792
876
" is safe to mutate - e.g. to remove a command. "
793
877
"list_commands should return the updated set of command names.",
795
self.add_hook('pre_command',
796
881
"Called prior to executing a command. Called with the command "
797
882
"object.", (2, 6))
798
self.add_hook('post_command',
799
885
"Called after executing a command. Called with the command "
800
886
"object.", (2, 6))
802
889
Command.hooks = CommandHooks()
811
898
they take, and which commands will accept them.
813
900
# TODO: make it a method of the Command?
814
parser = option.get_optparser(command.options())
901
parser = option.get_optparser(
902
[v for k, v in sorted(command.options().items())])
815
903
if alias_argv is not None:
816
904
args = alias_argv + argv
820
# for python 2.5 and later, optparse raises this exception if a non-ascii
908
# python 2's optparse raises this exception if a non-ascii
821
909
# option name is given. See http://bugs.python.org/issue2931
823
911
options, args = parser.parse_args(args)
824
except UnicodeEncodeError,e:
825
raise errors.BzrCommandError(
912
except UnicodeEncodeError:
913
raise errors.CommandError(
826
914
gettext('Only ASCII permitted in option names'))
828
opts = dict([(k, v) for k, v in options.__dict__.iteritems() if
829
v is not option.OptionParser.DEFAULT_VALUE])
916
opts = dict((k, v) for k, v in options.__dict__.items() if
917
v is not option.OptionParser.DEFAULT_VALUE)
830
918
return args, opts
847
935
argdict[argname + '_list'] = None
848
936
elif ap[-1] == '+':
850
raise errors.BzrCommandError(gettext(
851
"command {0!r} needs one or more {1}").format(
852
cmd, argname.upper()))
938
raise errors.CommandError(gettext(
939
"command {0!r} needs one or more {1}").format(
940
cmd, argname.upper()))
854
942
argdict[argname + '_list'] = args[:]
856
elif ap[-1] == '$': # all but one
944
elif ap[-1] == '$': # all but one
857
945
if len(args) < 2:
858
raise errors.BzrCommandError(
859
gettext("command {0!r} needs one or more {1}").format(
860
cmd, argname.upper()))
946
raise errors.CommandError(
947
gettext("command {0!r} needs one or more {1}").format(
948
cmd, argname.upper()))
861
949
argdict[argname + '_list'] = args[:-1]
864
952
# just a plain arg
867
raise errors.BzrCommandError(
868
gettext("command {0!r} requires argument {1}").format(
869
cmd, argname.upper()))
955
raise errors.CommandError(
956
gettext("command {0!r} requires argument {1}").format(
957
cmd, argname.upper()))
871
959
argdict[argname] = args.pop(0)
874
raise errors.BzrCommandError( gettext(
875
"extra argument to command {0}: {1}").format(
962
raise errors.CommandError(gettext(
963
"extra argument to command {0}: {1}").format(
880
def apply_coveraged(dirname, the_callable, *args, **kwargs):
881
# Cannot use "import trace", as that would import bzrlib.trace instead of
882
# the standard library's trace.
883
trace = __import__('trace')
885
tracer = trace.Trace(count=1, trace=0)
886
sys.settrace(tracer.globaltrace)
887
threading.settrace(tracer.globaltrace)
969
def apply_coveraged(the_callable, *args, **kwargs):
971
cov = coverage.Coverage()
973
config_file = cov.config.config_file
974
except AttributeError: # older versions of coverage
975
config_file = cov.config_file
976
os.environ['COVERAGE_PROCESS_START'] = config_file
890
979
return exception_to_return_code(the_callable, *args, **kwargs)
893
results = tracer.results()
894
results.write_results(show_missing=1, summary=False,
898
985
def apply_profiled(the_callable, *args, **kwargs):
904
991
prof = hotshot.Profile(pfname)
906
993
ret = prof.runcall(exception_to_return_code, the_callable, *args,
910
997
stats = hotshot.stats.load(pfname)
911
998
stats.strip_dirs()
912
999
stats.sort_stats('cum') # 'time'
913
## XXX: Might like to write to stderr or the trace file instead but
914
## print_stats seems hardcoded to stdout
1000
# XXX: Might like to write to stderr or the trace file instead but
1001
# print_stats seems hardcoded to stdout
915
1002
stats.print_stats(20)
930
1017
return the_callable(*args, **kwargs)
931
except (KeyboardInterrupt, Exception), e:
1018
except (KeyboardInterrupt, Exception):
932
1019
# used to handle AssertionError and KeyboardInterrupt
933
1020
# specially here, but hopefully they're handled ok by the logger now
934
1021
exc_info = sys.exc_info()
935
1022
exitcode = trace.report_exception(exc_info, sys.stderr)
936
if os.environ.get('BZR_PDB'):
937
print '**** entering debugger'
1023
if os.environ.get('BRZ_PDB'):
1024
print('**** entering debugger')
939
1026
pdb.post_mortem(exc_info[2])
943
1030
def apply_lsprofiled(filename, the_callable, *args, **kwargs):
944
from bzrlib.lsprof import profile
1031
from breezy.lsprof import profile
945
1032
ret, stats = profile(exception_to_return_code, the_callable,
946
1033
*args, **kwargs)
1008
1095
Run under the Python lsprof profiler.
1011
Generate line coverage report in the specified directory.
1098
Generate code coverage report
1014
Specify the number of processes that can be run concurrently (selftest).
1101
Specify the number of processes that can be run concurrently
1016
trace.mutter("bazaar version: " + bzrlib.__version__)
1104
trace.mutter("breezy version: " + breezy.__version__)
1017
1105
argv = _specified_or_unicode_argv(argv)
1018
trace.mutter("bzr arguments: %r", argv)
1106
trace.mutter("brz arguments: %r", argv)
1020
1108
opt_lsprof = opt_profile = opt_no_plugins = opt_builtin = \
1021
opt_no_l10n = opt_no_aliases = False
1022
opt_lsprof_file = opt_coverage_dir = None
1109
opt_coverage = opt_no_l10n = opt_no_aliases = False
1110
opt_lsprof_file = None
1024
1112
# --no-plugins is handled specially at a very early stage. We need
1025
1113
# to load plugins before doing other command parsing so that they
1047
1135
elif a == '--builtin':
1048
1136
opt_builtin = True
1049
1137
elif a == '--concurrency':
1050
os.environ['BZR_CONCURRENCY'] = argv[i + 1]
1138
os.environ['BRZ_CONCURRENCY'] = argv[i + 1]
1052
1140
elif a == '--coverage':
1053
opt_coverage_dir = argv[i + 1]
1055
1142
elif a == '--profile-imports':
1056
pass # already handled in startup script Bug #588277
1143
pass # already handled in startup script Bug #588277
1057
1144
elif a.startswith('-D'):
1058
1145
debug.debug_flags.add(a[2:])
1059
1146
elif a.startswith('-O'):
1062
1149
argv_copy.append(a)
1065
if bzrlib.global_state is None:
1066
# FIXME: Workaround for users that imported bzrlib but didn't call
1067
# bzrlib.initialize -- vila 2012-01-19
1068
cmdline_overrides = config.CommandLineStore()
1070
cmdline_overrides = bzrlib.global_state.cmdline_overrides
1152
cmdline_overrides = breezy.get_global_state().cmdline_overrides
1071
1153
cmdline_overrides._from_cmdline(override_config)
1073
1155
debug.set_debug_flags_from_config()
1075
1157
if not opt_no_plugins:
1158
from breezy import config
1159
c = config.GlobalConfig()
1160
warn_load_problems = not c.suppress_warning('plugin_load_failure')
1161
load_plugins(warn_load_problems=warn_load_problems)
1078
1163
disable_plugins()
1106
1191
saved_verbosity_level = option._verbosity_level
1107
1192
option._verbosity_level = 0
1109
if opt_coverage_dir:
1111
1196
'--coverage ignored, because --lsprof is in use.')
1112
1197
ret = apply_lsprofiled(opt_lsprof_file, run, *run_argv)
1113
1198
elif opt_profile:
1114
if opt_coverage_dir:
1116
1201
'--coverage ignored, because --profile is in use.')
1117
1202
ret = apply_profiled(run, *run_argv)
1118
elif opt_coverage_dir:
1119
ret = apply_coveraged(opt_coverage_dir, run, *run_argv)
1204
ret = apply_coveraged(run, *run_argv)
1121
1206
ret = run(*run_argv)
1122
1207
return ret or 0
1156
1241
if _list_bzr_commands in Command.hooks["list_commands"]:
1158
1243
Command.hooks.install_named_hook("list_commands", _list_bzr_commands,
1160
1245
Command.hooks.install_named_hook("get_command", _get_bzr_command,
1162
1247
Command.hooks.install_named_hook("get_command", _get_plugin_command,
1163
"bzr plugin commands")
1248
"bzr plugin commands")
1164
1249
Command.hooks.install_named_hook("get_command", _get_external_command,
1165
"bzr external command lookup")
1250
"bzr external command lookup")
1166
1251
Command.hooks.install_named_hook("get_missing_command",
1167
1252
_try_plugin_provider,
1168
1253
"bzr plugin-provider-db check")
1172
1256
def _specified_or_unicode_argv(argv):
1173
1257
# For internal or testing use, argv can be passed. Otherwise, get it from
1174
# the process arguments in a unicode-safe way.
1258
# the process arguments.
1175
1259
if argv is None:
1176
return osutils.get_unicode_argv()
1180
# ensure all arguments are unicode strings
1182
if isinstance(a, unicode):
1185
new_argv.append(a.decode('ascii'))
1186
except UnicodeDecodeError:
1187
raise errors.BzrError("argv should be list of unicode strings.")
1263
# ensure all arguments are unicode strings
1265
if not isinstance(a, str):
1266
raise ValueError('not native str or unicode: %r' % (a,))
1268
except (ValueError, UnicodeDecodeError):
1269
raise errors.BzrError("argv should be list of unicode strings.")
1191
1273
def main(argv=None):
1192
1274
"""Main entry point of command-line interface.
1194
Typically `bzrlib.initialize` should be called first.
1276
Typically `breezy.initialize` should be called first.
1196
1278
:param argv: list of unicode command-line arguments similar to sys.argv.
1197
1279
argv[0] is script name usually, it will be ignored.
1198
1280
Don't pass here sys.argv because this list contains plain strings
1199
1281
and not unicode; pass None instead.
1201
:return: exit code of bzr command.
1283
:return: exit code of brz command.
1203
1285
if argv is not None:
1204
1286
argv = argv[1:]
1212
1294
"""Run a bzr command with parameters as described by argv.
1214
1296
This function assumed that that UI layer is setup, that symbol deprecations
1215
are already applied, and that unicode decoding has already been performed on argv.
1297
are already applied, and that unicode decoding has already been performed
1217
1300
# done here so that they're covered for every test run
1218
1301
install_bzr_command_hooks()
1222
1305
def run_bzr_catch_user_errors(argv):
1223
"""Run bzr and report user errors, but let internal errors propagate.
1306
"""Run brz and report user errors, but let internal errors propagate.
1225
1308
This is used for the test suite, and might be useful for other programs
1226
1309
that want to wrap the commandline interface.
1229
1312
install_bzr_command_hooks()
1231
1314
return run_bzr(argv)
1232
except Exception, e:
1315
except Exception as e:
1233
1316
if (isinstance(e, (OSError, IOError))
1234
or not getattr(e, 'internal_error', True)):
1317
or not getattr(e, 'internal_error', True)):
1235
1318
trace.report_exception(sys.exc_info(), sys.stderr)