/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 bzrlib/option.py

  • Committer: Ian Clatworthy
  • Date: 2007-09-03 01:33:49 UTC
  • mto: (2779.1.1 ianc-integration)
  • mto: This revision was merged to the branch mainline in revision 2783.
  • Revision ID: ian.clatworthy@internode.on.net-20070903013349-o37wm1bxe04pctrm
Incorporate feedback from poolie

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2004, 2005, 2006, 2007 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
# TODO: For things like --diff-prefix, we want a way to customize the display
 
18
# of the option argument.
 
19
 
 
20
import re
 
21
 
 
22
from bzrlib.lazy_import import lazy_import
 
23
lazy_import(globals(), """
 
24
import optparse
 
25
 
 
26
from bzrlib import (
 
27
    errors,
 
28
    log,
 
29
    registry,
 
30
    revisionspec,
 
31
    symbol_versioning,
 
32
    )
 
33
""")
 
34
from bzrlib.trace import warning
 
35
 
 
36
 
 
37
def _parse_revision_str(revstr):
 
38
    """This handles a revision string -> revno.
 
39
 
 
40
    This always returns a list.  The list will have one element for
 
41
    each revision specifier supplied.
 
42
 
 
43
    >>> _parse_revision_str('234')
 
44
    [<RevisionSpec_revno 234>]
 
45
    >>> _parse_revision_str('234..567')
 
46
    [<RevisionSpec_revno 234>, <RevisionSpec_revno 567>]
 
47
    >>> _parse_revision_str('..')
 
48
    [<RevisionSpec None>, <RevisionSpec None>]
 
49
    >>> _parse_revision_str('..234')
 
50
    [<RevisionSpec None>, <RevisionSpec_revno 234>]
 
51
    >>> _parse_revision_str('234..')
 
52
    [<RevisionSpec_revno 234>, <RevisionSpec None>]
 
53
    >>> _parse_revision_str('234..456..789') # Maybe this should be an error
 
54
    [<RevisionSpec_revno 234>, <RevisionSpec_revno 456>, <RevisionSpec_revno 789>]
 
55
    >>> _parse_revision_str('234....789') #Error ?
 
56
    [<RevisionSpec_revno 234>, <RevisionSpec None>, <RevisionSpec_revno 789>]
 
57
    >>> _parse_revision_str('revid:test@other.com-234234')
 
58
    [<RevisionSpec_revid revid:test@other.com-234234>]
 
59
    >>> _parse_revision_str('revid:test@other.com-234234..revid:test@other.com-234235')
 
60
    [<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_revid revid:test@other.com-234235>]
 
61
    >>> _parse_revision_str('revid:test@other.com-234234..23')
 
62
    [<RevisionSpec_revid revid:test@other.com-234234>, <RevisionSpec_revno 23>]
 
63
    >>> _parse_revision_str('date:2005-04-12')
 
64
    [<RevisionSpec_date date:2005-04-12>]
 
65
    >>> _parse_revision_str('date:2005-04-12 12:24:33')
 
66
    [<RevisionSpec_date date:2005-04-12 12:24:33>]
 
67
    >>> _parse_revision_str('date:2005-04-12T12:24:33')
 
68
    [<RevisionSpec_date date:2005-04-12T12:24:33>]
 
69
    >>> _parse_revision_str('date:2005-04-12,12:24:33')
 
70
    [<RevisionSpec_date date:2005-04-12,12:24:33>]
 
71
    >>> _parse_revision_str('-5..23')
 
72
    [<RevisionSpec_revno -5>, <RevisionSpec_revno 23>]
 
73
    >>> _parse_revision_str('-5')
 
74
    [<RevisionSpec_revno -5>]
 
75
    >>> _parse_revision_str('123a')
 
76
    Traceback (most recent call last):
 
77
      ...
 
78
    NoSuchRevisionSpec: No namespace registered for string: '123a'
 
79
    >>> _parse_revision_str('abc')
 
80
    Traceback (most recent call last):
 
81
      ...
 
82
    NoSuchRevisionSpec: No namespace registered for string: 'abc'
 
83
    >>> _parse_revision_str('branch:../branch2')
 
84
    [<RevisionSpec_branch branch:../branch2>]
 
85
    >>> _parse_revision_str('branch:../../branch2')
 
86
    [<RevisionSpec_branch branch:../../branch2>]
 
87
    >>> _parse_revision_str('branch:../../branch2..23')
 
88
    [<RevisionSpec_branch branch:../../branch2>, <RevisionSpec_revno 23>]
 
89
    >>> _parse_revision_str('branch:..\\\\branch2')
 
90
    [<RevisionSpec_branch branch:..\\branch2>]
 
91
    >>> _parse_revision_str('branch:..\\\\..\\\\branch2..23')
 
92
    [<RevisionSpec_branch branch:..\\..\\branch2>, <RevisionSpec_revno 23>]
 
93
    """
 
94
    # TODO: Maybe move this into revisionspec.py
 
95
    revs = []
 
96
    # split on .. that is not followed by a / or \
 
97
    sep = re.compile(r'\.\.(?![\\/])')
 
98
    for x in sep.split(revstr):
 
99
        revs.append(revisionspec.RevisionSpec.from_string(x or None))
 
100
    return revs
 
101
 
 
102
 
 
103
def _parse_merge_type(typestring):
 
104
    return get_merge_type(typestring)
 
105
 
 
106
def get_merge_type(typestring):
 
107
    """Attempt to find the merge class/factory associated with a string."""
 
108
    from merge import merge_types
 
109
    try:
 
110
        return merge_types[typestring][0]
 
111
    except KeyError:
 
112
        templ = '%s%%7s: %%s' % (' '*12)
 
113
        lines = [templ % (f[0], f[1][1]) for f in merge_types.iteritems()]
 
114
        type_list = '\n'.join(lines)
 
115
        msg = "No known merge type %s. Supported types are:\n%s" %\
 
116
            (typestring, type_list)
 
117
        raise errors.BzrCommandError(msg)
 
118
 
 
119
 
 
120
class Option(object):
 
121
    """Description of a command line option
 
122
    
 
123
    :ivar _short_name: If this option has a single-letter name, this is it.
 
124
    Otherwise None.
 
125
    """
 
126
 
 
127
    # The dictionary of standard options. These are always legal.
 
128
    STD_OPTIONS = {}
 
129
 
 
130
    # The dictionary of commonly used options. these are only legal
 
131
    # if a command explicitly references them by name in the list
 
132
    # of supported options.
 
133
    OPTIONS = {}
 
134
 
 
135
    def __init__(self, name, help='', type=None, argname=None,
 
136
                 short_name=None, custom_callback=None):
 
137
        """Make a new command option.
 
138
 
 
139
        :param name: regular name of the command, used in the double-dash
 
140
            form and also as the parameter to the command's run() 
 
141
            method.
 
142
 
 
143
        :param help: help message displayed in command help
 
144
 
 
145
        :param type: function called to parse the option argument, or 
 
146
            None (default) if this option doesn't take an argument.
 
147
 
 
148
        :param argname: name of option argument, if any
 
149
 
 
150
        :param short_name: short option code for use with a single -, e.g.
 
151
            short_name="v" to enable parsing of -v.
 
152
 
 
153
        :param custom_callback: a callback routine to be called after normal
 
154
            processing. The signature of the callback routine is
 
155
            (option, name, new_value, parser).
 
156
        """
 
157
        self.name = name
 
158
        self.help = help
 
159
        self.type = type
 
160
        self._short_name = short_name
 
161
        if type is None:
 
162
            assert argname is None
 
163
        elif argname is None:
 
164
            argname = 'ARG'
 
165
        self.argname = argname
 
166
        self.custom_callback = custom_callback
 
167
 
 
168
    def short_name(self):
 
169
        if self._short_name:
 
170
            return self._short_name
 
171
 
 
172
    def set_short_name(self, short_name):
 
173
        self._short_name = short_name
 
174
 
 
175
    def get_negation_name(self):
 
176
        if self.name.startswith('no-'):
 
177
            return self.name[3:]
 
178
        else:
 
179
            return 'no-' + self.name
 
180
 
 
181
    def add_option(self, parser, short_name):
 
182
        """Add this option to an Optparse parser"""
 
183
        option_strings = ['--%s' % self.name]
 
184
        if short_name is not None:
 
185
            option_strings.append('-%s' % short_name)
 
186
        optargfn = self.type
 
187
        if optargfn is None:
 
188
            parser.add_option(action='callback', 
 
189
                              callback=self._optparse_bool_callback, 
 
190
                              callback_args=(True,),
 
191
                              help=self.help,
 
192
                              *option_strings)
 
193
            negation_strings = ['--%s' % self.get_negation_name()]
 
194
            parser.add_option(action='callback', 
 
195
                              callback=self._optparse_bool_callback, 
 
196
                              callback_args=(False,),
 
197
                              help=optparse.SUPPRESS_HELP, *negation_strings)
 
198
        else:
 
199
            parser.add_option(action='callback', 
 
200
                              callback=self._optparse_callback, 
 
201
                              type='string', metavar=self.argname.upper(),
 
202
                              help=self.help,
 
203
                              default=OptionParser.DEFAULT_VALUE, 
 
204
                              *option_strings)
 
205
 
 
206
    def _optparse_bool_callback(self, option, opt_str, value, parser, bool_v):
 
207
        setattr(parser.values, self.name, bool_v)
 
208
        if self.custom_callback is not None:
 
209
            self.custom_callback(option, self.name, bool_v, parser)
 
210
 
 
211
    def _optparse_callback(self, option, opt, value, parser):
 
212
        v = self.type(value)
 
213
        setattr(parser.values, self.name, v)
 
214
        if self.custom_callback is not None:
 
215
            self.custom_callback(option, self.name, v, parser)
 
216
 
 
217
    def iter_switches(self):
 
218
        """Iterate through the list of switches provided by the option
 
219
        
 
220
        :return: an iterator of (name, short_name, argname, help)
 
221
        """
 
222
        argname =  self.argname
 
223
        if argname is not None:
 
224
            argname = argname.upper()
 
225
        yield self.name, self.short_name(), argname, self.help
 
226
 
 
227
    def is_hidden(self, name):
 
228
        return False
 
229
 
 
230
 
 
231
class ListOption(Option):
 
232
    """Option used to provide a list of values.
 
233
 
 
234
    On the command line, arguments are specified by a repeated use of the
 
235
    option. '-' is a special argument that resets the list. For example,
 
236
      --foo=a --foo=b
 
237
    sets the value of the 'foo' option to ['a', 'b'], and
 
238
      --foo=a --foo=b --foo=- --foo=c
 
239
    sets the value of the 'foo' option to ['c'].
 
240
    """
 
241
 
 
242
    def add_option(self, parser, short_name):
 
243
        """Add this option to an Optparse parser."""
 
244
        option_strings = ['--%s' % self.name]
 
245
        if short_name is not None:
 
246
            option_strings.append('-%s' % short_name)
 
247
        parser.add_option(action='callback',
 
248
                          callback=self._optparse_callback,
 
249
                          type='string', metavar=self.argname.upper(),
 
250
                          help=self.help, default=[],
 
251
                          *option_strings)
 
252
 
 
253
    def _optparse_callback(self, option, opt, value, parser):
 
254
        values = getattr(parser.values, self.name)
 
255
        if value == '-':
 
256
            del values[:]
 
257
        else:
 
258
            values.append(self.type(value))
 
259
        if self.custom_callback is not None:
 
260
            self.custom_callback(option, self.name, values, parser)
 
261
 
 
262
 
 
263
class RegistryOption(Option):
 
264
    """Option based on a registry
 
265
 
 
266
    The values for the options correspond to entries in the registry.  Input
 
267
    must be a registry key.  After validation, it is converted into an object
 
268
    using Registry.get or a caller-provided converter.
 
269
    """
 
270
 
 
271
    def validate_value(self, value):
 
272
        """Validate a value name"""
 
273
        if value not in self.registry:
 
274
            raise errors.BadOptionValue(self.name, value)
 
275
 
 
276
    def convert(self, value):
 
277
        """Convert a value name into an output type"""
 
278
        self.validate_value(value)
 
279
        if self.converter is None:
 
280
            return self.registry.get(value)
 
281
        else:
 
282
            return self.converter(value)
 
283
 
 
284
    def __init__(self, name, help, registry, converter=None,
 
285
        value_switches=False, title=None, enum_switch=True):
 
286
        """
 
287
        Constructor.
 
288
 
 
289
        :param name: The option name.
 
290
        :param help: Help for the option.
 
291
        :param registry: A Registry containing the values
 
292
        :param converter: Callable to invoke with the value name to produce
 
293
            the value.  If not supplied, self.registry.get is used.
 
294
        :param value_switches: If true, each possible value is assigned its
 
295
            own switch.  For example, instead of '--format knit',
 
296
            '--knit' can be used interchangeably.
 
297
        :param enum_switch: If true, a switch is provided with the option name,
 
298
            which takes a value.
 
299
        """
 
300
        Option.__init__(self, name, help, type=self.convert)
 
301
        self.registry = registry
 
302
        self.name = name
 
303
        self.converter = converter
 
304
        self.value_switches = value_switches
 
305
        self.enum_switch = enum_switch
 
306
        self.title = title
 
307
        if self.title is None:
 
308
            self.title = name
 
309
 
 
310
    @staticmethod
 
311
    def from_kwargs(name_, help=None, title=None, value_switches=False,
 
312
                    enum_switch=True, **kwargs):
 
313
        """Convenience method to generate string-map registry options
 
314
 
 
315
        name, help, value_switches and enum_switch are passed to the
 
316
        RegistryOption constructor.  Any other keyword arguments are treated
 
317
        as values for the option, and they value is treated as the help.
 
318
        """
 
319
        reg = registry.Registry()
 
320
        for name, switch_help in kwargs.iteritems():
 
321
            name = name.replace('_', '-')
 
322
            reg.register(name, name, help=switch_help)
 
323
        return RegistryOption(name_, help, reg, title=title,
 
324
            value_switches=value_switches, enum_switch=enum_switch)
 
325
 
 
326
    def add_option(self, parser, short_name):
 
327
        """Add this option to an Optparse parser"""
 
328
        if self.value_switches:
 
329
            parser = parser.add_option_group(self.title)
 
330
        if self.enum_switch:
 
331
            Option.add_option(self, parser, short_name)
 
332
        if self.value_switches:
 
333
            for key in self.registry.keys():
 
334
                option_strings = ['--%s' % key]
 
335
                if self.is_hidden(key):
 
336
                    help = optparse.SUPPRESS_HELP
 
337
                else:
 
338
                    help = self.registry.get_help(key)
 
339
                parser.add_option(action='callback',
 
340
                              callback=self._optparse_value_callback(key),
 
341
                                  help=help,
 
342
                                  *option_strings)
 
343
 
 
344
    def _optparse_value_callback(self, cb_value):
 
345
        def cb(option, opt, value, parser):
 
346
            v = self.type(cb_value)
 
347
            setattr(parser.values, self.name, v)
 
348
            if self.custom_callback is not None:
 
349
                self.custom_callback(option, self.name, v, parser)
 
350
        return cb
 
351
 
 
352
    def iter_switches(self):
 
353
        """Iterate through the list of switches provided by the option
 
354
 
 
355
        :return: an iterator of (name, short_name, argname, help)
 
356
        """
 
357
        for value in Option.iter_switches(self):
 
358
            yield value
 
359
        if self.value_switches:
 
360
            for key in sorted(self.registry.keys()):
 
361
                yield key, None, None, self.registry.get_help(key)
 
362
 
 
363
    def is_hidden(self, name):
 
364
        if name == self.name:
 
365
            return Option.is_hidden(self, name)
 
366
        return getattr(self.registry.get_info(name), 'hidden', False)
 
367
 
 
368
 
 
369
class OptionParser(optparse.OptionParser):
 
370
    """OptionParser that raises exceptions instead of exiting"""
 
371
 
 
372
    DEFAULT_VALUE = object()
 
373
 
 
374
    def error(self, message):
 
375
        raise errors.BzrCommandError(message)
 
376
 
 
377
 
 
378
def get_optparser(options):
 
379
    """Generate an optparse parser for bzrlib-style options"""
 
380
 
 
381
    parser = OptionParser()
 
382
    parser.remove_option('--help')
 
383
    for option in options.itervalues():
 
384
        option.add_option(parser, option.short_name())
 
385
    return parser
 
386
 
 
387
 
 
388
def custom_help(name, help):
 
389
    """Clone a common option overriding the help."""
 
390
    import copy
 
391
    o = copy.copy(Option.OPTIONS[name])
 
392
    o.help = help
 
393
    return o
 
394
 
 
395
 
 
396
def _standard_option(name, **kwargs):
 
397
    """Register a standard option."""
 
398
    # All standard options are implicitly 'global' ones
 
399
    Option.STD_OPTIONS[name] = Option(name, **kwargs)
 
400
    Option.OPTIONS[name] = Option.STD_OPTIONS[name]
 
401
 
 
402
 
 
403
def _global_option(name, **kwargs):
 
404
    """Register a global option."""
 
405
    Option.OPTIONS[name] = Option(name, **kwargs)
 
406
 
 
407
 
 
408
def _global_registry_option(name, help, registry, **kwargs):
 
409
    Option.OPTIONS[name] = RegistryOption(name, help, registry, **kwargs)
 
410
 
 
411
 
 
412
class MergeTypeRegistry(registry.Registry):
 
413
 
 
414
    pass
 
415
 
 
416
 
 
417
# This is the verbosity level detected during command line parsing.
 
418
# Note that the final value is dependent on the order in which the
 
419
# various flags (verbose, quiet, no-verbose, no-quiet) are given.
 
420
# The final value will be one of the following:
 
421
#
 
422
# * -ve for quiet
 
423
# * 0 for normal
 
424
# * +ve for verbose
 
425
_verbosity_level = 0
 
426
 
 
427
 
 
428
def _verbosity_level_callback(option, opt_str, value, parser):
 
429
    global _verbosity_level
 
430
    if not value:
 
431
        # Either --no-verbose or --no-quiet was specified
 
432
        _verbosity_level = 0
 
433
    elif opt_str == "verbose":
 
434
        if _verbosity_level > 0:
 
435
            _verbosity_level += 1
 
436
        else:
 
437
            _verbosity_level = 1
 
438
    else:
 
439
        if _verbosity_level < 0:
 
440
            _verbosity_level -= 1
 
441
        else:
 
442
            _verbosity_level = -1
 
443
 
 
444
 
 
445
_merge_type_registry = MergeTypeRegistry()
 
446
_merge_type_registry.register_lazy('merge3', 'bzrlib.merge', 'Merge3Merger',
 
447
                                   "Native diff3-style merge")
 
448
_merge_type_registry.register_lazy('diff3', 'bzrlib.merge', 'Diff3Merger',
 
449
                                   "Merge using external diff3")
 
450
_merge_type_registry.register_lazy('weave', 'bzrlib.merge', 'WeaveMerger',
 
451
                                   "Weave-based merge")
 
452
 
 
453
# Declare the standard options
 
454
_standard_option('help', short_name='h',
 
455
                 help='Show help message.')
 
456
_standard_option('verbose', short_name='v',
 
457
                 help='Display more information.',
 
458
                 custom_callback=_verbosity_level_callback)
 
459
_standard_option('quiet', short_name='q',
 
460
                 help="Only display errors and warnings.",
 
461
                 custom_callback=_verbosity_level_callback)
 
462
 
 
463
# Declare commonly used options
 
464
_global_option('all')
 
465
_global_option('overwrite', help='Ignore differences between branches and '
 
466
               'overwrite unconditionally.')
 
467
_global_option('basis', type=str)
 
468
_global_option('bound')
 
469
_global_option('diff-options', type=str)
 
470
_global_option('file', type=unicode, short_name='F')
 
471
_global_option('force')
 
472
_global_option('format', type=unicode)
 
473
_global_option('forward')
 
474
_global_option('message', type=unicode,
 
475
               short_name='m',
 
476
               help='Message string.')
 
477
_global_option('no-recurse')
 
478
_global_option('profile',
 
479
               help='Show performance profiling information.')
 
480
_global_option('revision',
 
481
               type=_parse_revision_str,
 
482
               short_name='r',
 
483
               help='See \'help revisionspec\' for details.')
 
484
_global_option('show-ids',
 
485
               help='Show internal object ids.')
 
486
_global_option('timezone', 
 
487
               type=str,
 
488
               help='display timezone as local, original, or utc')
 
489
_global_option('unbound')
 
490
_global_option('version')
 
491
_global_option('email')
 
492
_global_option('update')
 
493
_global_registry_option('log-format', "Use specified log format.",
 
494
                        log.log_formatter_registry, value_switches=True,
 
495
                        title='Log format')
 
496
_global_option('long', help='Use detailed log format. Same as --log-format long',
 
497
               short_name='l')
 
498
_global_option('short', help='Use moderately short log format. Same as --log-format short')
 
499
_global_option('line', help='Use log format with one line per revision. Same as --log-format line')
 
500
_global_option('root', type=str)
 
501
_global_option('no-backup')
 
502
_global_registry_option('merge-type', 'Select a particular merge algorithm.',
 
503
                        _merge_type_registry, value_switches=True,
 
504
                        title='Merge algorithm')
 
505
_global_option('pattern', type=str)
 
506
_global_option('remember', help='Remember the specified location as a'
 
507
               ' default.')
 
508
_global_option('reprocess', help='Reprocess to reduce spurious conflicts.')
 
509
_global_option('kind', type=str)
 
510
_global_option('dry-run',
 
511
               help="Show what would be done, but don't actually do anything.")
 
512
_global_option('name-from-revision', help='The path name in the old tree.')