~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2011-08-09 12:34:00 UTC
  • mfrom: (6056.2.5 option-registry)
  • Revision ID: pqm@pqm.ubuntu.com-20110809123400-x521f2j9jkxx8ze2
(vila) Introduce OptionRegistry (Vincent Ladeuil)

Show diffs side-by-side

added added

removed removed

Lines of Context:
172
172
# FIXME: Until we can guarantee that each config file is loaded once and
173
173
# only once for a given bzrlib session, we don't want to re-read the file every
174
174
# time we query for an option so we cache the value (bad ! watch out for tests
175
 
# needing to restore the proper value). -- vila 20110219
 
175
# needing to restore the proper value).This shouldn't be part of 2.4.0 final,
 
176
# yell at mgz^W vila and the RM if this is still present at that time
 
177
# -- vila 20110219
176
178
_expand_default_value = None
177
179
def _get_expand_default_value():
178
180
    global _expand_default_value
1511
1513
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
1512
1514
                                  ' or HOME set')
1513
1515
        return osutils.pathjoin(base, 'bazaar', '2.0')
1514
 
    else:
1515
 
        if base is not None:
1516
 
            base = base.decode(osutils._fs_enc)
1517
 
    if sys.platform == 'darwin':
 
1516
    elif sys.platform == 'darwin':
1518
1517
        if base is None:
1519
1518
            # this takes into account $HOME
1520
1519
            base = os.path.expanduser("~")
1521
1520
        return osutils.pathjoin(base, '.bazaar')
1522
1521
    else:
1523
1522
        if base is None:
 
1523
 
1524
1524
            xdg_dir = os.environ.get('XDG_CONFIG_HOME', None)
1525
1525
            if xdg_dir is None:
1526
1526
                xdg_dir = osutils.pathjoin(os.path.expanduser("~"), ".config")
1529
1529
                trace.mutter(
1530
1530
                    "Using configuration in XDG directory %s." % xdg_dir)
1531
1531
                return xdg_dir
 
1532
 
1532
1533
            base = os.path.expanduser("~")
1533
1534
        return osutils.pathjoin(base, ".bazaar")
1534
1535
 
2270
2271
    The option *values* are stored in config files and found in sections.
2271
2272
 
2272
2273
    Here we define various properties about the option itself, its default
2273
 
    value, how to convert it from stores, what to do when invalid values are
2274
 
    encoutered, in which config files it can be stored.
 
2274
    value, in which config files it can be stored, etc (TBC).
2275
2275
    """
2276
2276
 
2277
 
    def __init__(self, name, default=None, help=None, from_unicode=None,
2278
 
                 invalid=None):
2279
 
        """Build an option definition.
2280
 
 
2281
 
        :param name: the name used to refer to the option.
2282
 
 
2283
 
        :param default: the default value to use when none exist in the config
2284
 
            stores.
2285
 
 
2286
 
        :param help: a doc string to explain the option to the user.
2287
 
 
2288
 
        :param from_unicode: a callable to convert the unicode string
2289
 
            representing the option value in a store. This is not called for
2290
 
            the default value.
2291
 
 
2292
 
        :param invalid: the action to be taken when an invalid value is
2293
 
            encountered in a store. This is called only when from_unicode is
2294
 
            invoked to convert a string and returns None or raise ValueError or
2295
 
            TypeError. Accepted values are: None (ignore invalid values),
2296
 
            'warning' (emit a warning), 'error' (emit an error message and
2297
 
            terminates).
2298
 
        """
 
2277
    def __init__(self, name, default=None, help=None):
2299
2278
        self.name = name
2300
2279
        self.default = default
2301
2280
        self.help = help
2302
 
        self.from_unicode = from_unicode
2303
 
        if invalid and invalid not in ('warning', 'error'):
2304
 
            raise AssertionError("%s not supported for 'invalid'" % (invalid,))
2305
 
        self.invalid = invalid
2306
2281
 
2307
2282
    def get_default(self):
2308
2283
        return self.default
2309
2284
 
2310
 
    def get_help_text(self, additional_see_also=None, plain=True):
2311
 
        result = self.help
2312
 
        from bzrlib import help_topics
2313
 
        result += help_topics._format_see_also(additional_see_also)
2314
 
        if plain:
2315
 
            result = help_topics.help_as_plain_text(result)
2316
 
        return result
2317
 
 
2318
 
 
2319
 
# Predefined converters to get proper values from store
2320
 
 
2321
 
def bool_from_store(unicode_str):
2322
 
    return ui.bool_from_string(unicode_str)
2323
 
 
2324
 
 
2325
 
def int_from_store(unicode_str):
2326
 
    return int(unicode_str)
2327
 
 
2328
 
 
2329
 
def list_from_store(unicode_str):
2330
 
    # ConfigObj return '' instead of u''. Use 'str' below to catch all cases.
2331
 
    if isinstance(unicode_str, (str, unicode)):
2332
 
        if unicode_str:
2333
 
            # A single value, most probably the user forgot (or didn't care to
2334
 
            # add) the final ','
2335
 
            l = [unicode_str]
2336
 
        else:
2337
 
            # The empty string, convert to empty list
2338
 
            l = []
2339
 
    else:
2340
 
        # We rely on ConfigObj providing us with a list already
2341
 
        l = unicode_str
2342
 
    return l
2343
 
 
2344
2285
 
2345
2286
class OptionRegistry(registry.Registry):
2346
2287
    """Register config options by their name.
2360
2301
    def register_lazy(self, key, module_name, member_name):
2361
2302
        """Register a new option to be loaded on request.
2362
2303
 
2363
 
        :param key: the key to request the option later. Since the registration
2364
 
            is lazy, it should be provided and match the option name.
2365
 
 
2366
 
        :param module_name: the python path to the module. Such as 'os.path'.
2367
 
 
2368
 
        :param member_name: the member of the module to return.  If empty or 
 
2304
        :param key: This is the key to use to request the option later. Since
 
2305
            the registration is lazy, it should be provided and match the
 
2306
            option name.
 
2307
 
 
2308
        :param module_name: The python path to the module. Such as 'os.path'.
 
2309
 
 
2310
        :param member_name: The member of the module to return.  If empty or
2369
2311
                None, get() will return the module itself.
2370
2312
        """
2371
2313
        super(OptionRegistry, self).register_lazy(key,
2386
2328
# Registered options in lexicographical order
2387
2329
 
2388
2330
option_registry.register(
2389
 
    Option('bzr.workingtree.worth_saving_limit', default=10,
2390
 
           from_unicode=int_from_store,  invalid='warning',
2391
 
           help='''\
2392
 
How many changes before saving the dirstate.
2393
 
 
2394
 
-1 means that we will never rewrite the dirstate file for only
2395
 
stat-cache changes. Regardless of this setting, we will always rewrite
2396
 
the dirstate file if a file is added/removed/renamed/etc. This flag only
2397
 
affects the behavior of updating the dirstate file after we notice that
2398
 
a file has been touched.
2399
 
'''))
2400
 
option_registry.register(
2401
2331
    Option('dirstate.fdatasync', default=True,
2402
 
           from_unicode=bool_from_store,
2403
 
           help='''\
 
2332
           help='''
2404
2333
Flush dirstate changes onto physical disk?
2405
2334
 
2406
2335
If true (default), working tree metadata changes are flushed through the
2408
2337
should not be lost if the machine crashes.  See also repository.fdatasync.
2409
2338
'''))
2410
2339
option_registry.register(
2411
 
    Option('debug_flags', default=[], from_unicode=list_from_store,
2412
 
           help='Debug flags to activate.'))
2413
 
option_registry.register(
2414
2340
    Option('default_format', default='2a',
2415
2341
           help='Format used when creating branches.'))
2416
2342
option_registry.register(
2417
2343
    Option('editor',
2418
2344
           help='The command called to launch an editor to enter a message.'))
2419
2345
option_registry.register(
2420
 
    Option('ignore_missing_extensions', default=False,
2421
 
           from_unicode=bool_from_store,
2422
 
           help='''\
2423
 
Control the missing extensions warning display.
2424
 
 
2425
 
The warning will not be emitted if set to True.
2426
 
'''))
2427
 
option_registry.register(
2428
2346
    Option('language',
2429
2347
           help='Language to translate messages into.'))
2430
2348
option_registry.register(
2431
 
    Option('locks.steal_dead', default=False, from_unicode=bool_from_store,
2432
 
           help='''\
2433
 
Steal locks that appears to be dead.
2434
 
 
2435
 
If set to True, bzr will check if a lock is supposed to be held by an
2436
 
active process from the same user on the same machine. If the user and
2437
 
machine match, but no process with the given PID is active, then bzr
2438
 
will automatically break the stale lock, and create a new lock for
2439
 
this process.
2440
 
Otherwise, bzr will prompt as normal to break the lock.
2441
 
'''))
2442
 
option_registry.register(
2443
2349
    Option('output_encoding',
2444
2350
           help= 'Unicode encoding for output'
2445
2351
           ' (terminal encoding if not specified).'))
2446
2352
option_registry.register(
2447
 
    Option('repository.fdatasync', default=True, from_unicode=bool_from_store,
 
2353
    Option('repository.fdatasync', default=True,
2448
2354
           help='''\
2449
2355
Flush repository changes onto physical disk?
2450
2356
 
2724
2630
class GlobalStore(LockableIniFileStore):
2725
2631
 
2726
2632
    def __init__(self, possible_transports=None):
2727
 
        t = transport.get_transport_from_path(
2728
 
            config_dir(), possible_transports=possible_transports)
 
2633
        t = transport.get_transport_from_path(config_dir(),
 
2634
                                    possible_transports=possible_transports)
2729
2635
        super(GlobalStore, self).__init__(t, 'bazaar.conf')
2730
2636
 
2731
2637
 
2732
2638
class LocationStore(LockableIniFileStore):
2733
2639
 
2734
2640
    def __init__(self, possible_transports=None):
2735
 
        t = transport.get_transport_from_path(
2736
 
            config_dir(), possible_transports=possible_transports)
 
2641
        t = transport.get_transport_from_path(config_dir(),
 
2642
                                    possible_transports=possible_transports)
2737
2643
        super(LocationStore, self).__init__(t, 'locations.conf')
2738
2644
 
2739
2645
 
2905
2811
                    break
2906
2812
            if value is not None:
2907
2813
                break
2908
 
        # If the option is registered, it may provide additional info about
2909
 
        # value handling
2910
 
        try:
2911
 
            opt = option_registry.get(name)
2912
 
        except KeyError:
2913
 
            # Not registered
2914
 
            opt = None
2915
 
        if (opt is not None and opt.from_unicode is not None
2916
 
            and value is not None):
2917
 
            # If a value exists and the option provides a converter, use it
2918
 
            try:
2919
 
                converted = opt.from_unicode(value)
2920
 
            except (ValueError, TypeError):
2921
 
                # Invalid values are ignored
2922
 
                converted = None
2923
 
            if converted is None and opt.invalid is not None:
2924
 
                # The conversion failed
2925
 
                if opt.invalid == 'warning':
2926
 
                    trace.warning('Value "%s" is not valid for "%s"',
2927
 
                                  value, name)
2928
 
                elif opt.invalid == 'error':
2929
 
                    raise errors.ConfigOptionValueError(name, value)
2930
 
            value = converted
2931
2814
        if value is None:
2932
2815
            # If the option is registered, it may provide a default value
 
2816
            try:
 
2817
                opt = option_registry.get(name)
 
2818
            except KeyError:
 
2819
                # Not registered
 
2820
                opt = None
2933
2821
            if opt is not None:
2934
2822
                value = opt.get_default()
2935
2823
        for hook in ConfigHooks['get']: