41
41
each revision specifier supplied.
43
43
>>> _parse_revision_str('234')
44
[<RevisionSpec_revno 234>]
44
[<RevisionSpec_dwim 234>]
45
45
>>> _parse_revision_str('234..567')
46
[<RevisionSpec_revno 234>, <RevisionSpec_revno 567>]
46
[<RevisionSpec_dwim 234>, <RevisionSpec_dwim 567>]
47
47
>>> _parse_revision_str('..')
48
48
[<RevisionSpec None>, <RevisionSpec None>]
49
49
>>> _parse_revision_str('..234')
50
[<RevisionSpec None>, <RevisionSpec_revno 234>]
50
[<RevisionSpec None>, <RevisionSpec_dwim 234>]
51
51
>>> _parse_revision_str('234..')
52
[<RevisionSpec_revno 234>, <RevisionSpec None>]
52
[<RevisionSpec_dwim 234>, <RevisionSpec None>]
53
53
>>> _parse_revision_str('234..456..789') # Maybe this should be an error
54
[<RevisionSpec_revno 234>, <RevisionSpec_revno 456>, <RevisionSpec_revno 789>]
54
[<RevisionSpec_dwim 234>, <RevisionSpec_dwim 456>, <RevisionSpec_dwim 789>]
55
55
>>> _parse_revision_str('234....789') #Error ?
56
[<RevisionSpec_revno 234>, <RevisionSpec None>, <RevisionSpec_revno 789>]
56
[<RevisionSpec_dwim 234>, <RevisionSpec None>, <RevisionSpec_dwim 789>]
57
57
>>> _parse_revision_str('revid:test@other.com-234234')
58
58
[<RevisionSpec_revid revid:test@other.com-234234>]
59
59
>>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235')
60
60
[<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_revid revid:test@other.com-234235>]
61
61
>>> _parse_revision_str('revid:test@other.com-234234..23')
62
[<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_revno 23>]
62
[<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_dwim 23>]
63
63
>>> _parse_revision_str('date:2005-04-12')
64
64
[<RevisionSpec_date date:2005-04-12>]
65
65
>>> _parse_revision_str('date:2005-04-12 12:24:33')
69
69
>>> _parse_revision_str('date:2005-04-12,12:24:33')
70
70
[<RevisionSpec_date date:2005-04-12,12:24:33>]
71
71
>>> _parse_revision_str('-5..23')
72
[<RevisionSpec_revno -5>, <RevisionSpec_revno 23>]
72
[<RevisionSpec_dwim -5>, <RevisionSpec_dwim 23>]
73
73
>>> _parse_revision_str('-5')
74
[<RevisionSpec_revno -5>]
74
[<RevisionSpec_dwim -5>]
75
75
>>> _parse_revision_str('123a')
76
Traceback (most recent call last):
78
NoSuchRevisionSpec: No namespace registered for string: '123a'
76
[<RevisionSpec_dwim 123a>]
79
77
>>> _parse_revision_str('abc')
80
Traceback (most recent call last):
82
NoSuchRevisionSpec: No namespace registered for string: 'abc'
78
[<RevisionSpec_dwim abc>]
83
79
>>> _parse_revision_str('branch:../branch2')
84
80
[<RevisionSpec_branch branch:../branch2>]
85
81
>>> _parse_revision_str('branch:../../branch2')
86
82
[<RevisionSpec_branch branch:../../branch2>]
87
83
>>> _parse_revision_str('branch:../../branch2..23')
88
[<RevisionSpec_branch branch:../../branch2>, <RevisionSpec_revno 23>]
84
[<RevisionSpec_branch branch:../../branch2>, <RevisionSpec_dwim 23>]
85
>>> _parse_revision_str('branch:..\\\\branch2')
86
[<RevisionSpec_branch branch:..\\branch2>]
87
>>> _parse_revision_str('branch:..\\\\..\\\\branch2..23')
88
[<RevisionSpec_branch branch:..\\..\\branch2>, <RevisionSpec_dwim 23>]
90
90
# TODO: Maybe move this into revisionspec.py
92
# split on the first .. that is not followed by a / ?
93
sep = re.compile("\\.\\.(?!/)")
92
# split on .. that is not followed by a / or \
93
sep = re.compile(r'\.\.(?![\\/])')
94
94
for x in sep.split(revstr):
95
95
revs.append(revisionspec.RevisionSpec.from_string(x or None))
99
def _parse_change_str(revstr):
100
"""Parse the revision string and return a tuple with left-most
101
parent of the revision.
103
>>> _parse_change_str('123')
104
(<RevisionSpec_before before:123>, <RevisionSpec_dwim 123>)
105
>>> _parse_change_str('123..124')
106
Traceback (most recent call last):
108
RangeInChangeOption: Option --change does not accept revision ranges
110
revs = _parse_revision_str(revstr)
112
raise errors.RangeInChangeOption()
113
return (revisionspec.RevisionSpec.from_string('before:' + revstr),
99
117
def _parse_merge_type(typestring):
100
118
return get_merge_type(typestring)
116
134
class Option(object):
117
135
"""Description of a command line option
119
137
:ivar _short_name: If this option has a single-letter name, this is it.
123
# TODO: Some way to show in help a description of the option argument
141
# The dictionary of standard options. These are always legal.
144
# The dictionary of commonly used options. these are only legal
145
# if a command explicitly references them by name in the list
146
# of supported options.
127
149
def __init__(self, name, help='', type=None, argname=None,
150
short_name=None, param_name=None, custom_callback=None,
129
152
"""Make a new command option.
131
name -- regular name of the command, used in the double-dash
132
form and also as the parameter to the command's run()
135
help -- help message displayed in command help
137
type -- function called to parse the option argument, or
154
:param name: regular name of the command, used in the double-dash
155
form and also as the parameter to the command's run()
156
method (unless param_name is specified).
158
:param help: help message displayed in command help
160
:param type: function called to parse the option argument, or
138
161
None (default) if this option doesn't take an argument.
140
argname -- name of option argument, if any
163
:param argname: name of option argument, if any
165
:param short_name: short option code for use with a single -, e.g.
166
short_name="v" to enable parsing of -v.
168
:param param_name: name of the parameter which will be passed to
169
the command's run() method.
171
:param custom_callback: a callback routine to be called after normal
172
processing. The signature of the callback routine is
173
(option, name, new_value, parser).
174
:param hidden: If True, the option should be hidden in help and
145
180
self._short_name = short_name
147
assert argname is None
183
raise ValueError('argname not valid for booleans')
148
184
elif argname is None:
150
186
self.argname = argname
187
if param_name is None:
188
self._param_name = self.name.replace('-', '_')
190
self._param_name = param_name
191
self.custom_callback = custom_callback
152
194
def short_name(self):
153
195
if self._short_name:
154
196
return self._short_name
156
# remove this when SHORT_OPTIONS is removed
157
# XXX: This is accessing a DeprecatedDict, so we call the super
158
# method to avoid warnings
159
for (k, v) in dict.iteritems(Option.SHORT_OPTIONS):
163
198
def set_short_name(self, short_name):
164
199
self._short_name = short_name
174
209
option_strings = ['--%s' % self.name]
175
210
if short_name is not None:
176
211
option_strings.append('-%s' % short_name)
213
help = optparse.SUPPRESS_HELP
177
216
optargfn = self.type
178
217
if optargfn is None:
179
parser.add_option(action='store_true', dest=self.name,
181
default=OptionParser.DEFAULT_VALUE,
218
parser.add_option(action='callback',
219
callback=self._optparse_bool_callback,
220
callback_args=(True,),
183
223
negation_strings = ['--%s' % self.get_negation_name()]
184
parser.add_option(action='store_false', dest=self.name,
224
parser.add_option(action='callback',
225
callback=self._optparse_bool_callback,
226
callback_args=(False,),
185
227
help=optparse.SUPPRESS_HELP, *negation_strings)
187
parser.add_option(action='callback',
188
callback=self._optparse_callback,
229
parser.add_option(action='callback',
230
callback=self._optparse_callback,
189
231
type='string', metavar=self.argname.upper(),
191
default=OptionParser.DEFAULT_VALUE,
233
default=OptionParser.DEFAULT_VALUE,
236
def _optparse_bool_callback(self, option, opt_str, value, parser, bool_v):
237
setattr(parser.values, self._param_name, bool_v)
238
if self.custom_callback is not None:
239
self.custom_callback(option, self._param_name, bool_v, parser)
194
241
def _optparse_callback(self, option, opt, value, parser):
195
setattr(parser.values, self.name, self.type(value))
243
setattr(parser.values, self._param_name, v)
244
if self.custom_callback is not None:
245
self.custom_callback(option, self.name, v, parser)
197
247
def iter_switches(self):
198
248
"""Iterate through the list of switches provided by the option
200
250
:return: an iterator of (name, short_name, argname, help)
202
252
argname = self.argname
204
254
argname = argname.upper()
205
255
yield self.name, self.short_name(), argname, self.help
257
def is_hidden(self, name):
261
class ListOption(Option):
262
"""Option used to provide a list of values.
264
On the command line, arguments are specified by a repeated use of the
265
option. '-' is a special argument that resets the list. For example,
267
sets the value of the 'foo' option to ['a', 'b'], and
268
--foo=a --foo=b --foo=- --foo=c
269
sets the value of the 'foo' option to ['c'].
272
def add_option(self, parser, short_name):
273
"""Add this option to an Optparse parser."""
274
option_strings = ['--%s' % self.name]
275
if short_name is not None:
276
option_strings.append('-%s' % short_name)
277
parser.add_option(action='callback',
278
callback=self._optparse_callback,
279
type='string', metavar=self.argname.upper(),
280
help=self.help, dest=self._param_name, default=[],
283
def _optparse_callback(self, option, opt, value, parser):
284
values = getattr(parser.values, self._param_name)
288
values.append(self.type(value))
289
if self.custom_callback is not None:
290
self.custom_callback(option, self._param_name, values, parser)
208
293
class RegistryOption(Option):
209
294
"""Option based on a registry
241
327
'--knit' can be used interchangeably.
242
328
:param enum_switch: If true, a switch is provided with the option name,
243
329
which takes a value.
330
:param lazy_registry: A tuple of (module name, attribute name) for a
331
registry to be lazily loaded.
332
:param short_name: The short name for the enum switch, if any
333
:param short_value_switches: A dict mapping values to short names
245
Option.__init__(self, name, help, type=self.convert)
246
self.registry = registry
335
Option.__init__(self, name, help, type=self.convert, short_name=short_name)
336
self._registry = registry
338
if lazy_registry is None:
339
raise AssertionError(
340
'One of registry or lazy_registry must be given.')
341
self._lazy_registry = _mod_registry._LazyObjectGetter(
343
if registry is not None and lazy_registry is not None:
344
raise AssertionError(
345
'registry and lazy_registry are mutually exclusive')
248
347
self.converter = converter
249
348
self.value_switches = value_switches
250
349
self.enum_switch = enum_switch
350
self.short_value_switches = short_value_switches
251
351
self.title = title
252
352
if self.title is None:
253
353
self.title = name
357
if self._registry is None:
358
self._registry = self._lazy_registry.get_obj()
359
return self._registry
256
362
def from_kwargs(name_, help=None, title=None, value_switches=False,
257
363
enum_switch=True, **kwargs):
260
366
name, help, value_switches and enum_switch are passed to the
261
367
RegistryOption constructor. Any other keyword arguments are treated
262
as values for the option, and they value is treated as the help.
368
as values for the option, and their value is treated as the help.
264
reg = registry.Registry()
265
for name, help in kwargs.iteritems():
370
reg = _mod_registry.Registry()
371
for name, switch_help in sorted(kwargs.items()):
266
372
name = name.replace('_', '-')
267
reg.register(name, name, help=help)
373
reg.register(name, name, help=switch_help)
374
if not value_switches:
375
help = help + ' "' + name + '": ' + switch_help
376
if not help.endswith("."):
268
378
return RegistryOption(name_, help, reg, title=title,
269
379
value_switches=value_switches, enum_switch=enum_switch)
277
387
if self.value_switches:
278
388
for key in self.registry.keys():
279
389
option_strings = ['--%s' % key]
390
if self.is_hidden(key):
391
help = optparse.SUPPRESS_HELP
393
help = self.registry.get_help(key)
394
if (self.short_value_switches and
395
key in self.short_value_switches):
396
option_strings.append('-%s' %
397
self.short_value_switches[key])
280
398
parser.add_option(action='callback',
281
399
callback=self._optparse_value_callback(key),
282
help=self.registry.get_help(key),
285
403
def _optparse_value_callback(self, cb_value):
286
404
def cb(option, opt, value, parser):
287
setattr(parser.values, self.name, self.type(cb_value))
405
v = self.type(cb_value)
406
setattr(parser.values, self._param_name, v)
407
if self.custom_callback is not None:
408
self.custom_callback(option, self._param_name, v, parser)
290
411
def iter_switches(self):
298
419
for key in sorted(self.registry.keys()):
299
420
yield key, None, None, self.registry.get_help(key)
422
def is_hidden(self, name):
423
if name == self.name:
424
return Option.is_hidden(self, name)
425
return getattr(self.registry.get_info(name), 'hidden', False)
302
428
class OptionParser(optparse.OptionParser):
303
429
"""OptionParser that raises exceptions instead of exiting"""
305
431
DEFAULT_VALUE = object()
434
optparse.OptionParser.__init__(self)
435
self.formatter = GettextIndentedHelpFormatter()
307
437
def error(self, message):
308
438
raise errors.BzrCommandError(message)
440
class GettextIndentedHelpFormatter(optparse.IndentedHelpFormatter):
441
"""Adds gettext() call to format_option()"""
443
optparse.IndentedHelpFormatter.__init__(self)
445
def format_option(self, option):
446
"""code taken from Python's optparse.py"""
448
option.help = i18n.gettext(option.help)
449
return optparse.IndentedHelpFormatter.format_option(self, option)
311
451
def get_optparser(options):
312
452
"""Generate an optparse parser for bzrlib-style options"""
461
def custom_help(name, help):
462
"""Clone a common option overriding the help."""
464
o = copy.copy(Option.OPTIONS[name])
469
def _standard_option(name, **kwargs):
470
"""Register a standard option."""
471
# All standard options are implicitly 'global' ones
472
Option.STD_OPTIONS[name] = Option(name, **kwargs)
473
Option.OPTIONS[name] = Option.STD_OPTIONS[name]
321
476
def _global_option(name, **kwargs):
322
"""Register o as a global option."""
477
"""Register a global option."""
323
478
Option.OPTIONS[name] = Option(name, **kwargs)
326
def _global_registry_option(name, help, registry, **kwargs):
481
def _global_registry_option(name, help, registry=None, **kwargs):
327
482
Option.OPTIONS[name] = RegistryOption(name, help, registry, **kwargs)
330
class MergeTypeRegistry(registry.Registry):
485
# This is the verbosity level detected during command line parsing.
486
# Note that the final value is dependent on the order in which the
487
# various flags (verbose, quiet, no-verbose, no-quiet) are given.
488
# The final value will be one of the following:
496
def _verbosity_level_callback(option, opt_str, value, parser):
497
global _verbosity_level
499
# Either --no-verbose or --no-quiet was specified
501
elif opt_str == "verbose":
502
if _verbosity_level > 0:
503
_verbosity_level += 1
507
if _verbosity_level < 0:
508
_verbosity_level -= 1
510
_verbosity_level = -1
513
class MergeTypeRegistry(_mod_registry.Registry):
339
522
"Merge using external diff3")
340
523
_merge_type_registry.register_lazy('weave', 'bzrlib.merge', 'WeaveMerger',
341
524
"Weave-based merge")
525
_merge_type_registry.register_lazy('lca', 'bzrlib.merge', 'LCAMerger',
528
# Declare the standard options
529
_standard_option('help', short_name='h',
530
help='Show help message.')
531
_standard_option('usage',
532
help='Show usage message and options.')
533
_standard_option('verbose', short_name='v',
534
help='Display more information.',
535
custom_callback=_verbosity_level_callback)
536
_standard_option('quiet', short_name='q',
537
help="Only display errors and warnings.",
538
custom_callback=_verbosity_level_callback)
540
# Declare commonly used options
343
541
_global_option('all')
344
542
_global_option('overwrite', help='Ignore differences between branches and '
345
'overwrite unconditionally')
543
'overwrite unconditionally.')
346
544
_global_option('basis', type=str)
347
545
_global_option('bound')
348
546
_global_option('diff-options', type=str)
349
_global_option('help',
350
help='show help message',
352
547
_global_option('file', type=unicode, short_name='F')
353
548
_global_option('force')
354
549
_global_option('format', type=unicode)
355
550
_global_option('forward')
356
551
_global_option('message', type=unicode,
553
help='Message string.')
358
554
_global_option('no-recurse')
555
_global_option('null', short_name='0',
556
help='Use an ASCII NUL (\\0) separator rather than '
359
558
_global_option('profile',
360
help='show performance profiling information')
559
help='Show performance profiling information.')
361
560
_global_option('revision',
362
561
type=_parse_revision_str,
364
help='See \'help revisionspec\' for details')
365
_global_option('show-ids',
366
help='show internal object ids')
367
_global_option('timezone',
563
help='See "help revisionspec" for details.')
564
_global_option('change',
565
type=_parse_change_str,
567
param_name='revision',
568
help='Select changes introduced by the specified revision. See also "help revisionspec".')
569
_global_option('show-ids',
570
help='Show internal object ids.')
571
_global_option('timezone',
369
help='display timezone as local, original, or utc')
573
help='Display timezone as local, original, or utc.')
370
574
_global_option('unbound')
371
_global_option('verbose',
372
help='display more information',
374
575
_global_option('version')
375
576
_global_option('email')
376
577
_global_option('update')
377
_global_registry_option('log-format', "Use this log format",
378
log.log_formatter_registry, value_switches=True,
578
_global_registry_option('log-format', "Use specified log format.",
579
lazy_registry=('bzrlib.log', 'log_formatter_registry'),
580
value_switches=True, title='Log format',
581
short_value_switches={'short': 'S'})
380
582
_global_option('long', help='Use detailed log format. Same as --log-format long',
382
584
_global_option('short', help='Use moderately short log format. Same as --log-format short')
383
585
_global_option('line', help='Use log format with one line per revision. Same as --log-format line')
384
586
_global_option('root', type=str)
385
587
_global_option('no-backup')
386
_global_registry_option('merge-type', 'Select a particular merge algorithm',
588
_global_registry_option('merge-type', 'Select a particular merge algorithm.',
387
589
_merge_type_registry, value_switches=True,
388
590
title='Merge algorithm')
389
591
_global_option('pattern', type=str)
390
_global_option('quiet', short_name='q')
391
592
_global_option('remember', help='Remember the specified location as a'
393
_global_option('reprocess', help='Reprocess to reduce spurious conflicts')
594
_global_option('reprocess', help='Reprocess to reduce spurious conflicts.')
394
595
_global_option('kind', type=str)
395
596
_global_option('dry-run',
396
help="show what would be done, but don't actually do anything")
597
help="Show what would be done, but don't actually do anything.")
397
598
_global_option('name-from-revision', help='The path name in the old tree.')
400
# prior to 0.14 these were always globally registered; the old dict is
401
# available for plugins that use it but it should not be used.
402
Option.SHORT_OPTIONS = symbol_versioning.DeprecatedDict(
403
symbol_versioning.zero_fourteen,
406
'F': Option.OPTIONS['file'],
407
'h': Option.OPTIONS['help'],
408
'm': Option.OPTIONS['message'],
409
'r': Option.OPTIONS['revision'],
410
'v': Option.OPTIONS['verbose'],
411
'l': Option.OPTIONS['long'],
412
'q': Option.OPTIONS['quiet'],
414
'Set the short option name when constructing the Option.',
599
_global_option('directory', short_name='d', type=unicode,
600
help='Branch to operate on, instead of working directory')
602
diff_writer_registry = _mod_registry.Registry()
603
diff_writer_registry.register('plain', lambda x: x, 'Plaintext diff output.')
604
diff_writer_registry.default_key = 'plain'