~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Jonathan Riddell
  • Date: 2011-09-16 11:13:47 UTC
  • mto: This revision was merged to the branch mainline in revision 6144.
  • Revision ID: jriddell@canonical.com-20110916111347-fyjk426bkl0jrbfu
gettext() show_warning usage

Show diffs side-by-side

added added

removed removed

Lines of Context:
106
106
from bzrlib import (
107
107
    commands,
108
108
    hooks,
 
109
    lazy_regex,
109
110
    registry,
110
111
    )
111
112
from bzrlib.symbol_versioning import (
413
414
            # add) the final ','
414
415
            l = [l]
415
416
        return l
 
417
        
 
418
    def get_user_option_as_int_from_SI(self,  option_name,  default=None):
 
419
        """Get a generic option from a human readable size in SI units, e.g 10MB
 
420
        
 
421
        Accepted suffixes are K,M,G. It is case-insensitive and may be followed
 
422
        by a trailing b (i.e. Kb, MB). This is intended to be practical and not
 
423
        pedantic.
 
424
        
 
425
        :return Integer, expanded to its base-10 value if a proper SI unit is 
 
426
            found. If the option doesn't exist, or isn't a value in 
 
427
            SI units, return default (which defaults to None)
 
428
        """
 
429
        val = self.get_user_option(option_name)
 
430
        if isinstance(val, list):
 
431
            val = val[0]
 
432
        if val is None:
 
433
            val = default
 
434
        else:
 
435
            p = re.compile("^(\d+)([kmg])*b*$", re.IGNORECASE)
 
436
            try:
 
437
                m = p.match(val)
 
438
                if m is not None:
 
439
                    val = int(m.group(1))
 
440
                    if m.group(2) is not None:
 
441
                        if m.group(2).lower() == 'k':
 
442
                            val *= 10**3
 
443
                        elif m.group(2).lower() == 'm':
 
444
                            val *= 10**6
 
445
                        elif m.group(2).lower() == 'g':
 
446
                            val *= 10**9
 
447
                else:
 
448
                    ui.ui_factory.show_warning(gettext('Invalid config value for "{0}" '
 
449
                                               ' value {1!r} is not an SI unit.').format(
 
450
                                                option_name, val))
 
451
                    val = default
 
452
            except TypeError:
 
453
                val = default
 
454
        return val
 
455
        
416
456
 
417
457
    def gpg_signing_command(self):
418
458
        """What program should be used to sign signatures?"""
582
622
        for (oname, value, section, conf_id, parser) in self._get_options():
583
623
            if oname.startswith('bzr.mergetool.'):
584
624
                tool_name = oname[len('bzr.mergetool.'):]
585
 
                tools[tool_name] = value
 
625
                tools[tool_name] = self.get_user_option(oname)
586
626
        trace.mutter('loaded merge tools: %r' % tools)
587
627
        return tools
588
628
 
985
1025
        # local transports are not shared. But if/when we start using
986
1026
        # LockableConfig for other kind of transports, we will need to reuse
987
1027
        # whatever connection is already established -- vila 20100929
988
 
        self.transport = transport.get_transport(self.dir)
 
1028
        self.transport = transport.get_transport_from_path(self.dir)
989
1029
        self._lock = lockdir.LockDir(self.transport, self.lock_name)
990
1030
 
991
1031
    def _create_from_string(self, unicode_bytes, save):
1357
1397
            return (self.branch._transport.get_bytes("email")
1358
1398
                    .decode(osutils.get_user_encoding())
1359
1399
                    .rstrip("\r\n"))
1360
 
        except errors.NoSuchFile, e:
 
1400
        except (errors.NoSuchFile, errors.PermissionDenied), e:
1361
1401
            pass
1362
1402
 
1363
1403
        return self._get_best_value('_get_user_id')
2238
2278
            return f
2239
2279
        except errors.NoSuchFile:
2240
2280
            return StringIO()
 
2281
        except errors.PermissionDenied, e:
 
2282
            trace.warning("Permission denied while trying to open "
 
2283
                "configuration file %s.", urlutils.unescape_for_display(
 
2284
                urlutils.join(self._transport.base, self._filename), "utf-8"))
 
2285
            return StringIO()
2241
2286
 
2242
2287
    def _external_url(self):
2243
2288
        return urlutils.join(self._transport.external_url(), self._filename)
2274
2319
    encoutered, in which config files it can be stored.
2275
2320
    """
2276
2321
 
2277
 
    def __init__(self, name, default=None, help=None, from_unicode=None,
2278
 
                 invalid=None):
 
2322
    def __init__(self, name, default=None, default_from_env=None,
 
2323
                 help=None,
 
2324
                 from_unicode=None, invalid=None):
2279
2325
        """Build an option definition.
2280
2326
 
2281
2327
        :param name: the name used to refer to the option.
2282
2328
 
2283
2329
        :param default: the default value to use when none exist in the config
2284
 
            stores.
 
2330
            stores. This is either a string that ``from_unicode`` will convert
 
2331
            into the proper type or a python object that can be stringified (so
 
2332
            only the empty list is supported for example).
 
2333
 
 
2334
        :param default_from_env: A list of environment variables which can
 
2335
           provide a default value. 'default' will be used only if none of the
 
2336
           variables specified here are set in the environment.
2285
2337
 
2286
2338
        :param help: a doc string to explain the option to the user.
2287
2339
 
2296
2348
            'warning' (emit a warning), 'error' (emit an error message and
2297
2349
            terminates).
2298
2350
        """
 
2351
        if default_from_env is None:
 
2352
            default_from_env = []
2299
2353
        self.name = name
2300
 
        self.default = default
 
2354
        # Convert the default value to a unicode string so all values are
 
2355
        # strings internally before conversion (via from_unicode) is attempted.
 
2356
        if default is None:
 
2357
            self.default = None
 
2358
        elif isinstance(default, list):
 
2359
            # Only the empty list is supported
 
2360
            if default:
 
2361
                raise AssertionError(
 
2362
                    'Only empty lists are supported as default values')
 
2363
            self.default = u','
 
2364
        elif isinstance(default, (str, unicode, bool, int)):
 
2365
            # Rely on python to convert strings, booleans and integers
 
2366
            self.default = u'%s' % (default,)
 
2367
        else:
 
2368
            # other python objects are not expected
 
2369
            raise AssertionError('%r is not supported as a default value'
 
2370
                                 % (default,))
 
2371
        self.default_from_env = default_from_env
2301
2372
        self.help = help
2302
2373
        self.from_unicode = from_unicode
2303
2374
        if invalid and invalid not in ('warning', 'error'):
2304
2375
            raise AssertionError("%s not supported for 'invalid'" % (invalid,))
2305
2376
        self.invalid = invalid
2306
2377
 
 
2378
    def convert_from_unicode(self, unicode_value):
 
2379
        if self.from_unicode is None or unicode_value is None:
 
2380
            # Don't convert or nothing to convert
 
2381
            return unicode_value
 
2382
        try:
 
2383
            converted = self.from_unicode(unicode_value)
 
2384
        except (ValueError, TypeError):
 
2385
            # Invalid values are ignored
 
2386
            converted = None
 
2387
        if converted is None and self.invalid is not None:
 
2388
            # The conversion failed
 
2389
            if self.invalid == 'warning':
 
2390
                trace.warning('Value "%s" is not valid for "%s"',
 
2391
                              unicode_value, self.name)
 
2392
            elif self.invalid == 'error':
 
2393
                raise errors.ConfigOptionValueError(self.name, unicode_value)
 
2394
        return converted
 
2395
 
2307
2396
    def get_default(self):
2308
 
        return self.default
 
2397
        value = None
 
2398
        for var in self.default_from_env:
 
2399
            try:
 
2400
                # If the env variable is defined, its value is the default one
 
2401
                value = os.environ[var]
 
2402
                break
 
2403
            except KeyError:
 
2404
                continue
 
2405
        if value is None:
 
2406
            # Otherwise, fallback to the value defined at registration
 
2407
            value = self.default
 
2408
        return value
2309
2409
 
2310
2410
    def get_help_text(self, additional_see_also=None, plain=True):
2311
2411
        result = self.help
2326
2426
    return int(unicode_str)
2327
2427
 
2328
2428
 
 
2429
# Use a an empty dict to initialize an empty configobj avoiding all
 
2430
# parsing and encoding checks
 
2431
_list_converter_config = configobj.ConfigObj(
 
2432
    {}, encoding='utf-8', list_values=True, interpolation=False)
 
2433
 
 
2434
 
2329
2435
def list_from_store(unicode_str):
 
2436
    if not isinstance(unicode_str, basestring):
 
2437
        raise TypeError
 
2438
    # Now inject our string directly as unicode. All callers got their value
 
2439
    # from configobj, so values that need to be quoted are already properly
 
2440
    # quoted.
 
2441
    _list_converter_config.reset()
 
2442
    _list_converter_config._parse([u"list=%s" % (unicode_str,)])
 
2443
    maybe_list = _list_converter_config['list']
2330
2444
    # ConfigObj return '' instead of u''. Use 'str' below to catch all cases.
2331
 
    if isinstance(unicode_str, (str, unicode)):
2332
 
        if unicode_str:
 
2445
    if isinstance(maybe_list, basestring):
 
2446
        if maybe_list:
2333
2447
            # A single value, most probably the user forgot (or didn't care to
2334
2448
            # add) the final ','
2335
 
            l = [unicode_str]
 
2449
            l = [maybe_list]
2336
2450
        else:
2337
2451
            # The empty string, convert to empty list
2338
2452
            l = []
2339
2453
    else:
2340
2454
        # We rely on ConfigObj providing us with a list already
2341
 
        l = unicode_str
 
2455
        l = maybe_list
2342
2456
    return l
2343
2457
 
2344
2458
 
2444
2558
           help= 'Unicode encoding for output'
2445
2559
           ' (terminal encoding if not specified).'))
2446
2560
option_registry.register(
2447
 
    Option('repository.fdatasync', default=True, from_unicode=bool_from_store,
 
2561
    Option('repository.fdatasync', default=True,
 
2562
           from_unicode=bool_from_store,
2448
2563
           help='''\
2449
2564
Flush repository changes onto physical disk?
2450
2565
 
2594
2709
        """Load the store from the associated file."""
2595
2710
        if self.is_loaded():
2596
2711
            return
2597
 
        content = self.transport.get_bytes(self.file_name)
 
2712
        try:
 
2713
            content = self.transport.get_bytes(self.file_name)
 
2714
        except errors.PermissionDenied:
 
2715
            trace.warning("Permission denied while trying to load "
 
2716
                          "configuration store %s.", self.external_url())
 
2717
            raise
2598
2718
        self._load_from_string(content)
2599
2719
        for hook in ConfigHooks['load']:
2600
2720
            hook(self)
2609
2729
        co_input = StringIO(bytes)
2610
2730
        try:
2611
2731
            # The config files are always stored utf8-encoded
2612
 
            self._config_obj = ConfigObj(co_input, encoding='utf-8')
 
2732
            self._config_obj = ConfigObj(co_input, encoding='utf-8',
 
2733
                                         list_values=False)
2613
2734
        except configobj.ConfigObjError, e:
2614
2735
            self._config_obj = None
2615
2736
            raise errors.ParseConfigError(e.errors, self.external_url())
2642
2763
        # We need a loaded store
2643
2764
        try:
2644
2765
            self.load()
2645
 
        except errors.NoSuchFile:
2646
 
            # If the file doesn't exist, there is no sections
 
2766
        except (errors.NoSuchFile, errors.PermissionDenied):
 
2767
            # If the file can't be read, there is no sections
2647
2768
            return
2648
2769
        cobj = self._config_obj
2649
2770
        if cobj.scalars:
2759
2880
        super(BranchStore, self).save()
2760
2881
 
2761
2882
 
 
2883
class ControlStore(LockableIniFileStore):
 
2884
 
 
2885
    def __init__(self, bzrdir):
 
2886
        super(ControlStore, self).__init__(bzrdir.transport,
 
2887
                                          'control.conf',
 
2888
                                           lock_dir_name='branch_lock')
 
2889
 
 
2890
 
2762
2891
class SectionMatcher(object):
2763
2892
    """Select sections into a given Store.
2764
2893
 
2765
 
    This intended to be used to postpone getting an iterable of sections from a
2766
 
    store.
 
2894
    This is intended to be used to postpone getting an iterable of sections
 
2895
    from a store.
2767
2896
    """
2768
2897
 
2769
2898
    def __init__(self, store):
2778
2907
            if self.match(s):
2779
2908
                yield s
2780
2909
 
2781
 
    def match(self, secion):
 
2910
    def match(self, section):
 
2911
        """Does the proposed section match.
 
2912
 
 
2913
        :param section: A Section object.
 
2914
 
 
2915
        :returns: True if the section matches, False otherwise.
 
2916
        """
2782
2917
        raise NotImplementedError(self.match)
2783
2918
 
2784
2919
 
 
2920
class NameMatcher(SectionMatcher):
 
2921
 
 
2922
    def __init__(self, store, section_id):
 
2923
        super(NameMatcher, self).__init__(store)
 
2924
        self.section_id = section_id
 
2925
 
 
2926
    def match(self, section):
 
2927
        return section.id == self.section_id
 
2928
 
 
2929
 
2785
2930
class LocationSection(Section):
2786
2931
 
2787
2932
    def __init__(self, section, length, extra_path):
2812
2957
        # We slightly diverge from LocalConfig here by allowing the no-name
2813
2958
        # section as the most generic one and the lower priority.
2814
2959
        no_name_section = None
2815
 
        sections = []
 
2960
        all_sections = []
2816
2961
        # Filter out the no_name_section so _iter_for_location_by_parts can be
2817
2962
        # used (it assumes all sections have a name).
2818
2963
        for section in self.store.get_sections():
2819
2964
            if section.id is None:
2820
2965
                no_name_section = section
2821
2966
            else:
2822
 
                sections.append(section)
 
2967
                all_sections.append(section)
2823
2968
        # Unfortunately _iter_for_location_by_parts deals with section names so
2824
2969
        # we have to resync.
2825
2970
        filtered_sections = _iter_for_location_by_parts(
2826
 
            [s.id for s in sections], self.location)
2827
 
        iter_sections = iter(sections)
 
2971
            [s.id for s in all_sections], self.location)
 
2972
        iter_all_sections = iter(all_sections)
2828
2973
        matching_sections = []
2829
2974
        if no_name_section is not None:
2830
2975
            matching_sections.append(
2831
2976
                LocationSection(no_name_section, 0, self.location))
2832
2977
        for section_id, extra_path, length in filtered_sections:
2833
 
            # a section id is unique for a given store so it's safe to iterate
2834
 
            # again
2835
 
            section = iter_sections.next()
2836
 
            if section_id == section.id:
2837
 
                matching_sections.append(
2838
 
                    LocationSection(section, length, extra_path))
 
2978
            # a section id is unique for a given store so it's safe to take the
 
2979
            # first matching section while iterating. Also, all filtered
 
2980
            # sections are part of 'all_sections' and will always be found
 
2981
            # there.
 
2982
            while True:
 
2983
                section = iter_all_sections.next()
 
2984
                if section_id == section.id:
 
2985
                    matching_sections.append(
 
2986
                        LocationSection(section, length, extra_path))
 
2987
                    break
2839
2988
        return matching_sections
2840
2989
 
2841
2990
    def get_sections(self):
2860
3009
class Stack(object):
2861
3010
    """A stack of configurations where an option can be defined"""
2862
3011
 
 
3012
    _option_ref_re = lazy_regex.lazy_compile('({[^{}]+})')
 
3013
    """Describes an exandable option reference.
 
3014
 
 
3015
    We want to match the most embedded reference first.
 
3016
 
 
3017
    I.e. for '{{foo}}' we will get '{foo}',
 
3018
    for '{bar{baz}}' we will get '{baz}'
 
3019
    """
 
3020
 
2863
3021
    def __init__(self, sections_def, store=None, mutable_section_name=None):
2864
3022
        """Creates a stack of sections with an optional store for changes.
2865
3023
 
2878
3036
        self.store = store
2879
3037
        self.mutable_section_name = mutable_section_name
2880
3038
 
2881
 
    def get(self, name):
 
3039
    def get(self, name, expand=None):
2882
3040
        """Return the *first* option value found in the sections.
2883
3041
 
2884
3042
        This is where we guarantee that sections coming from Store are loaded
2886
3044
        option exists or get its value, which in turn may require to discover
2887
3045
        in which sections it can be defined. Both of these (section and option
2888
3046
        existence) require loading the store (even partially).
 
3047
 
 
3048
        :param name: The queried option.
 
3049
 
 
3050
        :param expand: Whether options references should be expanded.
 
3051
 
 
3052
        :returns: The value of the option.
2889
3053
        """
2890
3054
        # FIXME: No caching of options nor sections yet -- vila 20110503
 
3055
        if expand is None:
 
3056
            expand = _get_expand_default_value()
2891
3057
        value = None
2892
3058
        # Ensuring lazy loading is achieved by delaying section matching (which
2893
3059
        # implies querying the persistent storage) until it can't be avoided
2912
3078
        except KeyError:
2913
3079
            # Not registered
2914
3080
            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
 
        if value is None:
 
3081
        def expand_and_convert(val):
 
3082
            # This may need to be called twice if the value is None or ends up
 
3083
            # being None during expansion or conversion.
 
3084
            if val is not None:
 
3085
                if expand:
 
3086
                    if isinstance(val, basestring):
 
3087
                        val = self._expand_options_in_string(val)
 
3088
                    else:
 
3089
                        trace.warning('Cannot expand "%s":'
 
3090
                                      ' %s does not support option expansion'
 
3091
                                      % (name, type(val)))
 
3092
                if opt is not None:
 
3093
                    val = opt.convert_from_unicode(val)
 
3094
            return val
 
3095
        value = expand_and_convert(value)
 
3096
        if opt is not None and value is None:
2932
3097
            # If the option is registered, it may provide a default value
2933
 
            if opt is not None:
2934
 
                value = opt.get_default()
 
3098
            value = opt.get_default()
 
3099
            value = expand_and_convert(value)
2935
3100
        for hook in ConfigHooks['get']:
2936
3101
            hook(self, name, value)
2937
3102
        return value
2938
3103
 
 
3104
    def expand_options(self, string, env=None):
 
3105
        """Expand option references in the string in the configuration context.
 
3106
 
 
3107
        :param string: The string containing option(s) to expand.
 
3108
 
 
3109
        :param env: An option dict defining additional configuration options or
 
3110
            overriding existing ones.
 
3111
 
 
3112
        :returns: The expanded string.
 
3113
        """
 
3114
        return self._expand_options_in_string(string, env)
 
3115
 
 
3116
    def _expand_options_in_string(self, string, env=None, _refs=None):
 
3117
        """Expand options in the string in the configuration context.
 
3118
 
 
3119
        :param string: The string to be expanded.
 
3120
 
 
3121
        :param env: An option dict defining additional configuration options or
 
3122
            overriding existing ones.
 
3123
 
 
3124
        :param _refs: Private list (FIFO) containing the options being expanded
 
3125
            to detect loops.
 
3126
 
 
3127
        :returns: The expanded string.
 
3128
        """
 
3129
        if string is None:
 
3130
            # Not much to expand there
 
3131
            return None
 
3132
        if _refs is None:
 
3133
            # What references are currently resolved (to detect loops)
 
3134
            _refs = []
 
3135
        result = string
 
3136
        # We need to iterate until no more refs appear ({{foo}} will need two
 
3137
        # iterations for example).
 
3138
        while True:
 
3139
            raw_chunks = Stack._option_ref_re.split(result)
 
3140
            if len(raw_chunks) == 1:
 
3141
                # Shorcut the trivial case: no refs
 
3142
                return result
 
3143
            chunks = []
 
3144
            # Split will isolate refs so that every other chunk is a ref
 
3145
            chunk_is_ref = False
 
3146
            for chunk in raw_chunks:
 
3147
                if not chunk_is_ref:
 
3148
                    chunks.append(chunk)
 
3149
                    chunk_is_ref = True
 
3150
                else:
 
3151
                    name = chunk[1:-1]
 
3152
                    if name in _refs:
 
3153
                        raise errors.OptionExpansionLoop(string, _refs)
 
3154
                    _refs.append(name)
 
3155
                    value = self._expand_option(name, env, _refs)
 
3156
                    if value is None:
 
3157
                        raise errors.ExpandingUnknownOption(name, string)
 
3158
                    chunks.append(value)
 
3159
                    _refs.pop()
 
3160
                    chunk_is_ref = False
 
3161
            result = ''.join(chunks)
 
3162
        return result
 
3163
 
 
3164
    def _expand_option(self, name, env, _refs):
 
3165
        if env is not None and name in env:
 
3166
            # Special case, values provided in env takes precedence over
 
3167
            # anything else
 
3168
            value = env[name]
 
3169
        else:
 
3170
            # FIXME: This is a limited implementation, what we really need is a
 
3171
            # way to query the bzr config for the value of an option,
 
3172
            # respecting the scope rules (That is, once we implement fallback
 
3173
            # configs, getting the option value should restart from the top
 
3174
            # config, not the current one) -- vila 20101222
 
3175
            value = self.get(name, expand=False)
 
3176
            value = self._expand_options_in_string(value, env, _refs)
 
3177
        return value
 
3178
 
2939
3179
    def _get_mutable_section(self):
2940
3180
        """Get the MutableSection for the Stack.
2941
3181
 
2991
3231
 
2992
3232
 
2993
3233
class GlobalStack(_CompatibleStack):
 
3234
    """Global options only stack."""
2994
3235
 
2995
3236
    def __init__(self):
2996
3237
        # Get a GlobalStore
2999
3240
 
3000
3241
 
3001
3242
class LocationStack(_CompatibleStack):
 
3243
    """Per-location options falling back to global options stack."""
3002
3244
 
3003
3245
    def __init__(self, location):
3004
3246
        """Make a new stack for a location and global configuration.
3010
3252
        super(LocationStack, self).__init__(
3011
3253
            [matcher.get_sections, gstore.get_sections], lstore)
3012
3254
 
 
3255
 
3013
3256
class BranchStack(_CompatibleStack):
 
3257
    """Per-location options falling back to branch then global options stack."""
3014
3258
 
3015
3259
    def __init__(self, branch):
3016
3260
        bstore = BranchStore(branch)
3023
3267
        self.branch = branch
3024
3268
 
3025
3269
 
 
3270
class RemoteControlStack(_CompatibleStack):
 
3271
    """Remote control-only options stack."""
 
3272
 
 
3273
    def __init__(self, bzrdir):
 
3274
        cstore = ControlStore(bzrdir)
 
3275
        super(RemoteControlStack, self).__init__(
 
3276
            [cstore.get_sections],
 
3277
            cstore)
 
3278
        self.bzrdir = bzrdir
 
3279
 
 
3280
 
 
3281
class RemoteBranchStack(_CompatibleStack):
 
3282
    """Remote branch-only options stack."""
 
3283
 
 
3284
    def __init__(self, branch):
 
3285
        bstore = BranchStore(branch)
 
3286
        super(RemoteBranchStack, self).__init__(
 
3287
            [bstore.get_sections],
 
3288
            bstore)
 
3289
        self.branch = branch
 
3290
 
 
3291
 
3026
3292
class cmd_config(commands.Command):
3027
3293
    __doc__ = """Display, set or remove a configuration option.
3028
3294