/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: 2017-11-11 12:51:45 UTC
  • mto: This revision was merged to the branch mainline in revision 6804.
  • Revision ID: jelmer@jelmer.uk-20171111125145-zw639zp14j8b2cin
Bunch of developer docs changes:

 * Move plans to plans/
 * Move performance analysis & planning docs to plans/performance/
 * Change Bazaar references to Breezy
 * Add branding guidelines

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