~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/option.py

Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
 
26
26
from bzrlib import (
27
27
    errors,
 
28
    log,
 
29
    registry,
28
30
    revisionspec,
 
31
    symbol_versioning,
29
32
    )
30
33
""")
31
34
from bzrlib.trace import warning
109
112
            (typestring, type_list)
110
113
        raise errors.BzrCommandError(msg)
111
114
 
 
115
 
112
116
class Option(object):
113
117
    """Description of a command line option
114
118
    
115
 
    :ivar short_name: If this option has a single-letter name, this is it.
 
119
    :ivar _short_name: If this option has a single-letter name, this is it.
116
120
    Otherwise None.
117
121
    """
118
122
 
138
142
        self.name = name
139
143
        self.help = help
140
144
        self.type = type
141
 
        self.short_name = short_name
 
145
        self._short_name = short_name
142
146
        if type is None:
143
147
            assert argname is None
144
148
        elif argname is None:
145
149
            argname = 'ARG'
146
150
        self.argname = argname
147
151
 
 
152
    def short_name(self):
 
153
        if self._short_name:
 
154
            return self._short_name
 
155
        else:
 
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):
 
160
                if v == self:
 
161
                    return k
 
162
 
 
163
    def set_short_name(self, short_name):
 
164
        self._short_name = short_name
 
165
 
148
166
    def get_negation_name(self):
149
167
        if self.name.startswith('no-'):
150
168
            return self.name[3:]
184
202
        argname =  self.argname
185
203
        if argname is not None:
186
204
            argname = argname.upper()
187
 
        yield self.name, self.short_name, argname, self.help
 
205
        yield self.name, self.short_name(), argname, self.help
 
206
 
 
207
 
 
208
class ListOption(Option):
 
209
    """Option used to provide a list of values.
 
210
 
 
211
    On the command line, arguments are specified by a repeated use of the
 
212
    option. '-' is a special argument that resets the list. For example,
 
213
      --foo=a --foo=b
 
214
    sets the value of the 'foo' option to ['a', 'b'], and
 
215
      --foo=a --foo=b --foo=- --foo=c
 
216
    sets the value of the 'foo' option to ['c'].
 
217
    """
 
218
 
 
219
    def add_option(self, parser, short_name):
 
220
        """Add this option to an Optparse parser."""
 
221
        option_strings = ['--%s' % self.name]
 
222
        if short_name is not None:
 
223
            option_strings.append('-%s' % short_name)
 
224
        parser.add_option(action='callback',
 
225
                          callback=self._optparse_callback,
 
226
                          type='string', metavar=self.argname.upper(),
 
227
                          help=self.help, default=[],
 
228
                          *option_strings)
 
229
 
 
230
    def _optparse_callback(self, option, opt, value, parser):
 
231
        values = getattr(parser.values, self.name)
 
232
        if value == '-':
 
233
            del values[:]
 
234
        else:
 
235
            values.append(self.type(value))
 
236
 
 
237
 
 
238
class RegistryOption(Option):
 
239
    """Option based on a registry
 
240
 
 
241
    The values for the options correspond to entries in the registry.  Input
 
242
    must be a registry key.  After validation, it is converted into an object
 
243
    using Registry.get or a caller-provided converter.
 
244
    """
 
245
 
 
246
    def validate_value(self, value):
 
247
        """Validate a value name"""
 
248
        if value not in self.registry:
 
249
            raise errors.BadOptionValue(self.name, value)
 
250
 
 
251
    def convert(self, value):
 
252
        """Convert a value name into an output type"""
 
253
        self.validate_value(value)
 
254
        if self.converter is None:
 
255
            return self.registry.get(value)
 
256
        else:
 
257
            return self.converter(value)
 
258
 
 
259
    def __init__(self, name, help, registry, converter=None,
 
260
        value_switches=False, title=None, enum_switch=True):
 
261
        """
 
262
        Constructor.
 
263
 
 
264
        :param name: The option name.
 
265
        :param help: Help for the option.
 
266
        :param registry: A Registry containing the values
 
267
        :param converter: Callable to invoke with the value name to produce
 
268
            the value.  If not supplied, self.registry.get is used.
 
269
        :param value_switches: If true, each possible value is assigned its
 
270
            own switch.  For example, instead of '--format knit',
 
271
            '--knit' can be used interchangeably.
 
272
        :param enum_switch: If true, a switch is provided with the option name,
 
273
            which takes a value.
 
274
        """
 
275
        Option.__init__(self, name, help, type=self.convert)
 
276
        self.registry = registry
 
277
        self.name = name
 
278
        self.converter = converter
 
279
        self.value_switches = value_switches
 
280
        self.enum_switch = enum_switch
 
281
        self.title = title
 
282
        if self.title is None:
 
283
            self.title = name
 
284
 
 
285
    @staticmethod
 
286
    def from_kwargs(name_, help=None, title=None, value_switches=False,
 
287
                    enum_switch=True, **kwargs):
 
288
        """Convenience method to generate string-map registry options
 
289
 
 
290
        name, help, value_switches and enum_switch are passed to the
 
291
        RegistryOption constructor.  Any other keyword arguments are treated
 
292
        as values for the option, and they value is treated as the help.
 
293
        """
 
294
        reg = registry.Registry()
 
295
        for name, help in kwargs.iteritems():
 
296
            name = name.replace('_', '-')
 
297
            reg.register(name, name, help=help)
 
298
        return RegistryOption(name_, help, reg, title=title,
 
299
            value_switches=value_switches, enum_switch=enum_switch)
 
300
 
 
301
    def add_option(self, parser, short_name):
 
302
        """Add this option to an Optparse parser"""
 
303
        if self.value_switches:
 
304
            parser = parser.add_option_group(self.title)
 
305
        if self.enum_switch:
 
306
            Option.add_option(self, parser, short_name)
 
307
        if self.value_switches:
 
308
            for key in self.registry.keys():
 
309
                option_strings = ['--%s' % key]
 
310
                if getattr(self.registry.get_info(key), 'hidden', False):
 
311
                    help = optparse.SUPPRESS_HELP
 
312
                else:
 
313
                    help = self.registry.get_help(key)
 
314
                parser.add_option(action='callback',
 
315
                              callback=self._optparse_value_callback(key),
 
316
                                  help=help,
 
317
                                  *option_strings)
 
318
 
 
319
    def _optparse_value_callback(self, cb_value):
 
320
        def cb(option, opt, value, parser):
 
321
            setattr(parser.values, self.name, self.type(cb_value))
 
322
        return cb
 
323
 
 
324
    def iter_switches(self):
 
325
        """Iterate through the list of switches provided by the option
 
326
 
 
327
        :return: an iterator of (name, short_name, argname, help)
 
328
        """
 
329
        for value in Option.iter_switches(self):
 
330
            yield value
 
331
        if self.value_switches:
 
332
            for key in sorted(self.registry.keys()):
 
333
                yield key, None, None, self.registry.get_help(key)
188
334
 
189
335
 
190
336
class OptionParser(optparse.OptionParser):
202
348
    parser = OptionParser()
203
349
    parser.remove_option('--help')
204
350
    for option in options.itervalues():
205
 
        option.add_option(parser, option.short_name)
 
351
        option.add_option(parser, option.short_name())
206
352
    return parser
207
353
 
208
354
 
210
356
    """Register o as a global option."""
211
357
    Option.OPTIONS[name] = Option(name, **kwargs)
212
358
 
 
359
 
 
360
def _global_registry_option(name, help, registry, **kwargs):
 
361
    Option.OPTIONS[name] = RegistryOption(name, help, registry, **kwargs)
 
362
 
 
363
 
 
364
class MergeTypeRegistry(registry.Registry):
 
365
 
 
366
    pass
 
367
 
 
368
 
 
369
_merge_type_registry = MergeTypeRegistry()
 
370
_merge_type_registry.register_lazy('merge3', 'bzrlib.merge', 'Merge3Merger',
 
371
                                   "Native diff3-style merge")
 
372
_merge_type_registry.register_lazy('diff3', 'bzrlib.merge', 'Diff3Merger',
 
373
                                   "Merge using external diff3")
 
374
_merge_type_registry.register_lazy('weave', 'bzrlib.merge', 'WeaveMerger',
 
375
                                   "Weave-based merge")
 
376
 
213
377
_global_option('all')
214
378
_global_option('overwrite', help='Ignore differences between branches and '
215
379
               'overwrite unconditionally')
244
408
_global_option('version')
245
409
_global_option('email')
246
410
_global_option('update')
247
 
_global_option('log-format', type=str, help="Use this log format")
 
411
_global_registry_option('log-format', "Use this log format",
 
412
                        log.log_formatter_registry, value_switches=True,
 
413
                        title='Log format')
248
414
_global_option('long', help='Use detailed log format. Same as --log-format long',
249
415
               short_name='l')
250
416
_global_option('short', help='Use moderately short log format. Same as --log-format short')
251
417
_global_option('line', help='Use log format with one line per revision. Same as --log-format line')
252
418
_global_option('root', type=str)
253
419
_global_option('no-backup')
254
 
_global_option('merge-type', type=_parse_merge_type, 
255
 
               help='Select a particular merge algorithm')
 
420
_global_registry_option('merge-type', 'Select a particular merge algorithm',
 
421
                        _merge_type_registry, value_switches=True,
 
422
                        title='Merge algorithm')
256
423
_global_option('pattern', type=str)
257
424
_global_option('quiet', short_name='q')
258
425
_global_option('remember', help='Remember the specified location as a'
262
429
_global_option('dry-run',
263
430
               help="show what would be done, but don't actually do anything")
264
431
_global_option('name-from-revision', help='The path name in the old tree.')
 
432
 
 
433
 
 
434
# prior to 0.14 these were always globally registered; the old dict is
 
435
# available for plugins that use it but it should not be used.
 
436
Option.SHORT_OPTIONS = symbol_versioning.DeprecatedDict(
 
437
    symbol_versioning.zero_fourteen,
 
438
    'SHORT_OPTIONS',
 
439
    {
 
440
        'F': Option.OPTIONS['file'],
 
441
        'h': Option.OPTIONS['help'],
 
442
        'm': Option.OPTIONS['message'],
 
443
        'r': Option.OPTIONS['revision'],
 
444
        'v': Option.OPTIONS['verbose'],
 
445
        'l': Option.OPTIONS['long'],
 
446
        'q': Option.OPTIONS['quiet'],
 
447
    },
 
448
    'Set the short option name when constructing the Option.',
 
449
    )