/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/option.py

  • Committer: Jelmer Vernooij
  • Date: 2020-02-07 02:14:30 UTC
  • mto: This revision was merged to the branch mainline in revision 7492.
  • Revision ID: jelmer@jelmer.uk-20200207021430-m49iq3x4x8xlib6x
Drop python2 support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005-2010 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
# TODO: For things like --diff-prefix, we want a way to customize the display
 
18
# of the option argument.
 
19
 
 
20
from __future__ import absolute_import
 
21
 
 
22
import optparse
 
23
import re
 
24
 
 
25
from . import (
 
26
    errors,
 
27
    registry as _mod_registry,
 
28
    revisionspec,
 
29
    )
 
30
 
 
31
 
 
32
class BadOptionValue(errors.BzrError):
 
33
 
 
34
    _fmt = """Bad value "%(value)s" for option "%(name)s"."""
 
35
 
 
36
    def __init__(self, name, value):
 
37
        errors.BzrError.__init__(self, name=name, value=value)
 
38
 
 
39
 
 
40
def _parse_revision_str(revstr):
 
41
    """This handles a revision string -> revno.
 
42
 
 
43
    This always returns a list.  The list will have one element for
 
44
    each revision specifier supplied.
 
45
 
 
46
    >>> _parse_revision_str('234')
 
47
    [<RevisionSpec_dwim 234>]
 
48
    >>> _parse_revision_str('234..567')
 
49
    [<RevisionSpec_dwim 234>, <RevisionSpec_dwim 567>]
 
50
    >>> _parse_revision_str('..')
 
51
    [<RevisionSpec None>, <RevisionSpec None>]
 
52
    >>> _parse_revision_str('..234')
 
53
    [<RevisionSpec None>, <RevisionSpec_dwim 234>]
 
54
    >>> _parse_revision_str('234..')
 
55
    [<RevisionSpec_dwim 234>, <RevisionSpec None>]
 
56
    >>> _parse_revision_str('234..456..789') # Maybe this should be an error
 
57
    [<RevisionSpec_dwim 234>, <RevisionSpec_dwim 456>, <RevisionSpec_dwim 789>]
 
58
    >>> _parse_revision_str('234....789') #Error ?
 
59
    [<RevisionSpec_dwim 234>, <RevisionSpec None>, <RevisionSpec_dwim 789>]
 
60
    >>> _parse_revision_str('revid:test@other.com-234234')
 
61
    [<RevisionSpec_revid revid:test@other.com-234234>]
 
62
    >>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235')
 
63
    [<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_revid revid:test@other.com-234235>]
 
64
    >>> _parse_revision_str('revid:test@other.com-234234..23')
 
65
    [<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_dwim 23>]
 
66
    >>> _parse_revision_str('date:2005-04-12')
 
67
    [<RevisionSpec_date date:2005-04-12>]
 
68
    >>> _parse_revision_str('date:2005-04-12 12:24:33')
 
69
    [<RevisionSpec_date date:2005-04-12 12:24:33>]
 
70
    >>> _parse_revision_str('date:2005-04-12T12:24:33')
 
71
    [<RevisionSpec_date date:2005-04-12T12:24:33>]
 
72
    >>> _parse_revision_str('date:2005-04-12,12:24:33')
 
73
    [<RevisionSpec_date date:2005-04-12,12:24:33>]
 
74
    >>> _parse_revision_str('-5..23')
 
75
    [<RevisionSpec_dwim -5>, <RevisionSpec_dwim 23>]
 
76
    >>> _parse_revision_str('-5')
 
77
    [<RevisionSpec_dwim -5>]
 
78
    >>> _parse_revision_str('123a')
 
79
    [<RevisionSpec_dwim 123a>]
 
80
    >>> _parse_revision_str('abc')
 
81
    [<RevisionSpec_dwim abc>]
 
82
    >>> _parse_revision_str('branch:../branch2')
 
83
    [<RevisionSpec_branch branch:../branch2>]
 
84
    >>> _parse_revision_str('branch:../../branch2')
 
85
    [<RevisionSpec_branch branch:../../branch2>]
 
86
    >>> _parse_revision_str('branch:../../branch2..23')
 
87
    [<RevisionSpec_branch branch:../../branch2>, <RevisionSpec_dwim 23>]
 
88
    >>> _parse_revision_str('branch:..\\\\branch2')
 
89
    [<RevisionSpec_branch branch:..\\branch2>]
 
90
    >>> _parse_revision_str('branch:..\\\\..\\\\branch2..23')
 
91
    [<RevisionSpec_branch branch:..\\..\\branch2>, <RevisionSpec_dwim 23>]
 
92
    """
 
93
    # TODO: Maybe move this into revisionspec.py
 
94
    revs = []
 
95
    # split on .. that is not followed by a / or \
 
96
    sep = re.compile(r'\.\.(?![\\/])')
 
97
    for x in sep.split(revstr):
 
98
        revs.append(revisionspec.RevisionSpec.from_string(x or None))
 
99
    return revs
 
100
 
 
101
 
 
102
def _parse_change_str(revstr):
 
103
    """Parse the revision string and return a tuple with left-most
 
104
    parent of the revision.
 
105
 
 
106
    >>> _parse_change_str('123')
 
107
    (<RevisionSpec_before before:123>, <RevisionSpec_dwim 123>)
 
108
    >>> _parse_change_str('123..124')
 
109
    Traceback (most recent call last):
 
110
      ...
 
111
    breezy.errors.RangeInChangeOption: Option --change does not accept revision ranges
 
112
    """
 
113
    revs = _parse_revision_str(revstr)
 
114
    if len(revs) > 1:
 
115
        raise errors.RangeInChangeOption()
 
116
    return (revisionspec.RevisionSpec.from_string('before:' + revstr),
 
117
            revs[0])
 
118
 
 
119
 
 
120
def _parse_merge_type(typestring):
 
121
    return get_merge_type(typestring)
 
122
 
 
123
 
 
124
def get_merge_type(typestring):
 
125
    """Attempt to find the merge class/factory associated with a string."""
 
126
    from merge import merge_types
 
127
    try:
 
128
        return merge_types[typestring][0]
 
129
    except KeyError:
 
130
        templ = '%s%%7s: %%s' % (' ' * 12)
 
131
        lines = [templ % (f[0], f[1][1]) for f in merge_types.items()]
 
132
        type_list = '\n'.join(lines)
 
133
        msg = "No known merge type %s. Supported types are:\n%s" %\
 
134
            (typestring, type_list)
 
135
        raise errors.BzrCommandError(msg)
 
136
 
 
137
 
 
138
class Option(object):
 
139
    """Description of a command line option
 
140
 
 
141
    :ivar _short_name: If this option has a single-letter name, this is it.
 
142
    Otherwise None.
 
143
    """
 
144
 
 
145
    # The dictionary of standard options. These are always legal.
 
146
    STD_OPTIONS = {}
 
147
 
 
148
    # The dictionary of commonly used options. these are only legal
 
149
    # if a command explicitly references them by name in the list
 
150
    # of supported options.
 
151
    OPTIONS = {}
 
152
 
 
153
    def __init__(self, name, help='', type=None, argname=None,
 
154
                 short_name=None, param_name=None, custom_callback=None,
 
155
                 hidden=False):
 
156
        """Make a new command option.
 
157
 
 
158
        :param name: regular name of the command, used in the double-dash
 
159
            form and also as the parameter to the command's run()
 
160
            method (unless param_name is specified).
 
161
 
 
162
        :param help: help message displayed in command help
 
163
 
 
164
        :param type: function called to parse the option argument, or
 
165
            None (default) if this option doesn't take an argument.
 
166
 
 
167
        :param argname: name of option argument, if any
 
168
 
 
169
        :param short_name: short option code for use with a single -, e.g.
 
170
            short_name="v" to enable parsing of -v.
 
171
 
 
172
        :param param_name: name of the parameter which will be passed to
 
173
            the command's run() method.
 
174
 
 
175
        :param custom_callback: a callback routine to be called after normal
 
176
            processing. The signature of the callback routine is
 
177
            (option, name, new_value, parser).
 
178
        :param hidden: If True, the option should be hidden in help and
 
179
            documentation.
 
180
        """
 
181
        self.name = name
 
182
        self.help = help
 
183
        self.type = type
 
184
        self._short_name = short_name
 
185
        if type is None:
 
186
            if argname:
 
187
                raise ValueError('argname not valid for booleans')
 
188
        elif argname is None:
 
189
            argname = 'ARG'
 
190
        self.argname = argname
 
191
        if param_name is None:
 
192
            self._param_name = self.name.replace('-', '_')
 
193
        else:
 
194
            self._param_name = param_name
 
195
        self.custom_callback = custom_callback
 
196
        self.hidden = hidden
 
197
 
 
198
    def short_name(self):
 
199
        if self._short_name:
 
200
            return self._short_name
 
201
 
 
202
    def set_short_name(self, short_name):
 
203
        self._short_name = short_name
 
204
 
 
205
    def get_negation_name(self):
 
206
        if self.name.startswith('no-'):
 
207
            return self.name[3:]
 
208
        else:
 
209
            return 'no-' + self.name
 
210
 
 
211
    def add_option(self, parser, short_name):
 
212
        """Add this option to an Optparse parser"""
 
213
        option_strings = ['--%s' % self.name]
 
214
        if short_name is not None:
 
215
            option_strings.append('-%s' % short_name)
 
216
        if self.hidden:
 
217
            help = optparse.SUPPRESS_HELP
 
218
        else:
 
219
            help = self.help
 
220
        optargfn = self.type
 
221
        if optargfn is None:
 
222
            parser.add_option(action='callback',
 
223
                              callback=self._optparse_bool_callback,
 
224
                              callback_args=(True,),
 
225
                              help=help,
 
226
                              *option_strings)
 
227
            negation_strings = ['--%s' % self.get_negation_name()]
 
228
            parser.add_option(action='callback',
 
229
                              callback=self._optparse_bool_callback,
 
230
                              callback_args=(False,),
 
231
                              help=optparse.SUPPRESS_HELP, *negation_strings)
 
232
        else:
 
233
            parser.add_option(action='callback',
 
234
                              callback=self._optparse_callback,
 
235
                              type='string', metavar=self.argname.upper(),
 
236
                              help=help,
 
237
                              default=OptionParser.DEFAULT_VALUE,
 
238
                              *option_strings)
 
239
 
 
240
    def _optparse_bool_callback(self, option, opt_str, value, parser, bool_v):
 
241
        setattr(parser.values, self._param_name, bool_v)
 
242
        if self.custom_callback is not None:
 
243
            self.custom_callback(option, self._param_name, bool_v, parser)
 
244
 
 
245
    def _optparse_callback(self, option, opt, value, parser):
 
246
        try:
 
247
            v = self.type(value)
 
248
        except ValueError as e:
 
249
            raise optparse.OptionValueError(
 
250
                'invalid value for option %s: %s' % (option, value))
 
251
        setattr(parser.values, self._param_name, v)
 
252
        if self.custom_callback is not None:
 
253
            self.custom_callback(option, self.name, v, parser)
 
254
 
 
255
    def iter_switches(self):
 
256
        """Iterate through the list of switches provided by the option
 
257
 
 
258
        :return: an iterator of (name, short_name, argname, help)
 
259
        """
 
260
        argname = self.argname
 
261
        if argname is not None:
 
262
            argname = argname.upper()
 
263
        yield self.name, self.short_name(), argname, self.help
 
264
 
 
265
    def is_hidden(self, name):
 
266
        return self.hidden
 
267
 
 
268
 
 
269
class ListOption(Option):
 
270
    """Option used to provide a list of values.
 
271
 
 
272
    On the command line, arguments are specified by a repeated use of the
 
273
    option. '-' is a special argument that resets the list. For example,
 
274
      --foo=a --foo=b
 
275
    sets the value of the 'foo' option to ['a', 'b'], and
 
276
      --foo=a --foo=b --foo=- --foo=c
 
277
    sets the value of the 'foo' option to ['c'].
 
278
    """
 
279
 
 
280
    def add_option(self, parser, short_name):
 
281
        """Add this option to an Optparse parser."""
 
282
        option_strings = ['--%s' % self.name]
 
283
        if short_name is not None:
 
284
            option_strings.append('-%s' % short_name)
 
285
        parser.add_option(action='callback',
 
286
                          callback=self._optparse_callback,
 
287
                          type='string', metavar=self.argname.upper(),
 
288
                          help=self.help, dest=self._param_name, default=[],
 
289
                          *option_strings)
 
290
 
 
291
    def _optparse_callback(self, option, opt, value, parser):
 
292
        values = getattr(parser.values, self._param_name)
 
293
        if value == '-':
 
294
            del values[:]
 
295
        else:
 
296
            values.append(self.type(value))
 
297
        if self.custom_callback is not None:
 
298
            self.custom_callback(option, self._param_name, values, parser)
 
299
 
 
300
 
 
301
class RegistryOption(Option):
 
302
    """Option based on a registry
 
303
 
 
304
    The values for the options correspond to entries in the registry.  Input
 
305
    must be a registry key.  After validation, it is converted into an object
 
306
    using Registry.get or a caller-provided converter.
 
307
    """
 
308
 
 
309
    def validate_value(self, value):
 
310
        """Validate a value name"""
 
311
        if value not in self.registry:
 
312
            raise BadOptionValue(self.name, value)
 
313
 
 
314
    def convert(self, value):
 
315
        """Convert a value name into an output type"""
 
316
        self.validate_value(value)
 
317
        if self.converter is None:
 
318
            return self.registry.get(value)
 
319
        else:
 
320
            return self.converter(value)
 
321
 
 
322
    def __init__(self, name, help, registry=None, converter=None,
 
323
                 value_switches=False, title=None, enum_switch=True,
 
324
                 lazy_registry=None, short_name=None, short_value_switches=None):
 
325
        """
 
326
        Constructor.
 
327
 
 
328
        :param name: The option name.
 
329
        :param help: Help for the option.
 
330
        :param registry: A Registry containing the values
 
331
        :param converter: Callable to invoke with the value name to produce
 
332
            the value.  If not supplied, self.registry.get is used.
 
333
        :param value_switches: If true, each possible value is assigned its
 
334
            own switch.  For example, instead of '--format knit',
 
335
            '--knit' can be used interchangeably.
 
336
        :param enum_switch: If true, a switch is provided with the option name,
 
337
            which takes a value.
 
338
        :param lazy_registry: A tuple of (module name, attribute name) for a
 
339
            registry to be lazily loaded.
 
340
        :param short_name: The short name for the enum switch, if any
 
341
        :param short_value_switches: A dict mapping values to short names
 
342
        """
 
343
        Option.__init__(self, name, help, type=self.convert,
 
344
                        short_name=short_name)
 
345
        self._registry = registry
 
346
        if registry is None:
 
347
            if lazy_registry is None:
 
348
                raise AssertionError(
 
349
                    'One of registry or lazy_registry must be given.')
 
350
            self._lazy_registry = _mod_registry._LazyObjectGetter(
 
351
                *lazy_registry)
 
352
        if registry is not None and lazy_registry is not None:
 
353
            raise AssertionError(
 
354
                'registry and lazy_registry are mutually exclusive')
 
355
        self.name = name
 
356
        self.converter = converter
 
357
        self.value_switches = value_switches
 
358
        self.enum_switch = enum_switch
 
359
        self.short_value_switches = short_value_switches
 
360
        self.title = title
 
361
        if self.title is None:
 
362
            self.title = name
 
363
 
 
364
    @property
 
365
    def registry(self):
 
366
        if self._registry is None:
 
367
            self._registry = self._lazy_registry.get_obj()
 
368
        return self._registry
 
369
 
 
370
    @staticmethod
 
371
    def from_kwargs(name_, help=None, title=None, value_switches=False,
 
372
                    enum_switch=True, **kwargs):
 
373
        """Convenience method to generate string-map registry options
 
374
 
 
375
        name, help, value_switches and enum_switch are passed to the
 
376
        RegistryOption constructor.  Any other keyword arguments are treated
 
377
        as values for the option, and their value is treated as the help.
 
378
        """
 
379
        reg = _mod_registry.Registry()
 
380
        for name, switch_help in sorted(kwargs.items()):
 
381
            name = name.replace('_', '-')
 
382
            reg.register(name, name, help=switch_help)
 
383
            if not value_switches:
 
384
                help = help + '  "' + name + '": ' + switch_help
 
385
                if not help.endswith("."):
 
386
                    help = help + "."
 
387
        return RegistryOption(name_, help, reg, title=title,
 
388
                              value_switches=value_switches, enum_switch=enum_switch)
 
389
 
 
390
    def add_option(self, parser, short_name):
 
391
        """Add this option to an Optparse parser"""
 
392
        if self.value_switches:
 
393
            parser = parser.add_option_group(self.title)
 
394
        if self.enum_switch:
 
395
            Option.add_option(self, parser, short_name)
 
396
        if self.value_switches:
 
397
            alias_map = self.registry.alias_map()
 
398
            for key in self.registry.keys():
 
399
                if key in self.registry.aliases():
 
400
                    continue
 
401
                option_strings = [
 
402
                    ('--%s' % name)
 
403
                    for name in [key] +
 
404
                    [alias for alias in alias_map.get(key, [])
 
405
                        if not self.is_hidden(alias)]]
 
406
                if self.is_hidden(key):
 
407
                    help = optparse.SUPPRESS_HELP
 
408
                else:
 
409
                    help = self.registry.get_help(key)
 
410
                if (self.short_value_switches and
 
411
                        key in self.short_value_switches):
 
412
                    option_strings.append('-%s' %
 
413
                                          self.short_value_switches[key])
 
414
                parser.add_option(action='callback',
 
415
                                  callback=self._optparse_value_callback(key),
 
416
                                  help=help,
 
417
                                  *option_strings)
 
418
 
 
419
    def _optparse_value_callback(self, cb_value):
 
420
        def cb(option, opt, value, parser):
 
421
            v = self.type(cb_value)
 
422
            setattr(parser.values, self._param_name, v)
 
423
            if self.custom_callback is not None:
 
424
                self.custom_callback(option, self._param_name, v, parser)
 
425
        return cb
 
426
 
 
427
    def iter_switches(self):
 
428
        """Iterate through the list of switches provided by the option
 
429
 
 
430
        :return: an iterator of (name, short_name, argname, help)
 
431
        """
 
432
        for value in Option.iter_switches(self):
 
433
            yield value
 
434
        if self.value_switches:
 
435
            for key in sorted(self.registry.keys()):
 
436
                yield key, None, None, self.registry.get_help(key)
 
437
 
 
438
    def is_alias(self, name):
 
439
        """Check whether a particular format is an alias."""
 
440
        if name == self.name:
 
441
            return False
 
442
        return name in self.registry.aliases()
 
443
 
 
444
    def is_hidden(self, name):
 
445
        if name == self.name:
 
446
            return Option.is_hidden(self, name)
 
447
        return getattr(self.registry.get_info(name), 'hidden', False)
 
448
 
 
449
 
 
450
class OptionParser(optparse.OptionParser):
 
451
    """OptionParser that raises exceptions instead of exiting"""
 
452
 
 
453
    DEFAULT_VALUE = object()
 
454
 
 
455
    def __init__(self):
 
456
        optparse.OptionParser.__init__(self)
 
457
        self.formatter = GettextIndentedHelpFormatter()
 
458
 
 
459
    def error(self, message):
 
460
        raise errors.BzrCommandError(message)
 
461
 
 
462
 
 
463
class GettextIndentedHelpFormatter(optparse.IndentedHelpFormatter):
 
464
    """Adds gettext() call to format_option()"""
 
465
 
 
466
    def __init__(self):
 
467
        optparse.IndentedHelpFormatter.__init__(self)
 
468
 
 
469
    def format_option(self, option):
 
470
        """code taken from Python's optparse.py"""
 
471
        if option.help:
 
472
            from .i18n import gettext
 
473
            option.help = gettext(option.help)
 
474
        return optparse.IndentedHelpFormatter.format_option(self, option)
 
475
 
 
476
 
 
477
def get_optparser(options):
 
478
    """Generate an optparse parser for breezy-style options"""
 
479
 
 
480
    parser = OptionParser()
 
481
    parser.remove_option('--help')
 
482
    for option in options:
 
483
        option.add_option(parser, option.short_name())
 
484
    return parser
 
485
 
 
486
 
 
487
def custom_help(name, help):
 
488
    """Clone a common option overriding the help."""
 
489
    import copy
 
490
    o = copy.copy(Option.OPTIONS[name])
 
491
    o.help = help
 
492
    return o
 
493
 
 
494
 
 
495
def _standard_option(name, **kwargs):
 
496
    """Register a standard option."""
 
497
    # All standard options are implicitly 'global' ones
 
498
    Option.STD_OPTIONS[name] = Option(name, **kwargs)
 
499
    Option.OPTIONS[name] = Option.STD_OPTIONS[name]
 
500
 
 
501
 
 
502
def _standard_list_option(name, **kwargs):
 
503
    """Register a standard option."""
 
504
    # All standard options are implicitly 'global' ones
 
505
    Option.STD_OPTIONS[name] = ListOption(name, **kwargs)
 
506
    Option.OPTIONS[name] = Option.STD_OPTIONS[name]
 
507
 
 
508
 
 
509
def _global_option(name, **kwargs):
 
510
    """Register a global option."""
 
511
    Option.OPTIONS[name] = Option(name, **kwargs)
 
512
 
 
513
 
 
514
def _global_registry_option(name, help, registry=None, **kwargs):
 
515
    Option.OPTIONS[name] = RegistryOption(name, help, registry, **kwargs)
 
516
 
 
517
 
 
518
# This is the verbosity level detected during command line parsing.
 
519
# Note that the final value is dependent on the order in which the
 
520
# various flags (verbose, quiet, no-verbose, no-quiet) are given.
 
521
# The final value will be one of the following:
 
522
#
 
523
# * -ve for quiet
 
524
# * 0 for normal
 
525
# * +ve for verbose
 
526
_verbosity_level = 0
 
527
 
 
528
 
 
529
def _verbosity_level_callback(option, opt_str, value, parser):
 
530
    global _verbosity_level
 
531
    if not value:
 
532
        # Either --no-verbose or --no-quiet was specified
 
533
        _verbosity_level = 0
 
534
    elif opt_str == "verbose":
 
535
        if _verbosity_level > 0:
 
536
            _verbosity_level += 1
 
537
        else:
 
538
            _verbosity_level = 1
 
539
    else:
 
540
        if _verbosity_level < 0:
 
541
            _verbosity_level -= 1
 
542
        else:
 
543
            _verbosity_level = -1
 
544
 
 
545
 
 
546
# Declare the standard options
 
547
_standard_option('help', short_name='h',
 
548
                 help='Show help message.')
 
549
_standard_option('quiet', short_name='q',
 
550
                 help="Only display errors and warnings.",
 
551
                 custom_callback=_verbosity_level_callback)
 
552
_standard_option('usage',
 
553
                 help='Show usage message and options.')
 
554
_standard_option('verbose', short_name='v',
 
555
                 help='Display more information.',
 
556
                 custom_callback=_verbosity_level_callback)
 
557
 
 
558
# Declare commonly used options
 
559
_global_option('change',
 
560
               type=_parse_change_str,
 
561
               short_name='c',
 
562
               param_name='revision',
 
563
               help='Select changes introduced by the specified revision. See also "help revisionspec".')
 
564
_global_option('directory', short_name='d', type=str,
 
565
               help='Branch to operate on, instead of working directory.')
 
566
_global_option('file', type=str, short_name='F')
 
567
_global_registry_option('log-format', "Use specified log format.",
 
568
                        lazy_registry=('breezy.log', 'log_formatter_registry'),
 
569
                        value_switches=True, title='Log format',
 
570
                        short_value_switches={'short': 'S'})
 
571
_global_registry_option('merge-type', 'Select a particular merge algorithm.',
 
572
                        lazy_registry=('breezy.merge', 'merge_type_registry'),
 
573
                        value_switches=True, title='Merge algorithm')
 
574
_global_option('message', type=str,
 
575
               short_name='m',
 
576
               help='Message string.')
 
577
_global_option('null', short_name='0',
 
578
               help='Use an ASCII NUL (\\0) separator rather than '
 
579
               'a newline.')
 
580
_global_option('overwrite', help='Ignore differences between branches and '
 
581
               'overwrite unconditionally.')
 
582
_global_option('remember', help='Remember the specified location as a'
 
583
               ' default.')
 
584
_global_option('reprocess', help='Reprocess to reduce spurious conflicts.')
 
585
_global_option('revision',
 
586
               type=_parse_revision_str,
 
587
               short_name='r',
 
588
               help='See "help revisionspec" for details.')
 
589
_global_option('show-ids',
 
590
               help='Show internal object ids.')
 
591
_global_option('timezone',
 
592
               type=str,
 
593
               help='Display timezone as local, original, or utc.')
 
594
 
 
595
diff_writer_registry = _mod_registry.Registry()
 
596
diff_writer_registry.register('plain', lambda x: x, 'Plaintext diff output.')
 
597
diff_writer_registry.default_key = 'plain'