~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: John Arbash Meinel
  • Date: 2011-09-12 18:40:02 UTC
  • mfrom: (6132 +trunk)
  • mto: This revision was merged to the branch mainline in revision 6133.
  • Revision ID: john@arbash-meinel.com-20110912184002-o23eu21fdgp35h2q
Merge bzr.dev, resolve release-notes (aka NEWS) conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
75
75
import os
76
76
import string
77
77
import sys
78
 
import re
79
78
 
80
79
 
81
80
from bzrlib.decorators import needs_write_lock
107
106
from bzrlib import (
108
107
    commands,
109
108
    hooks,
 
109
    lazy_regex,
110
110
    registry,
111
111
    )
112
112
from bzrlib.symbol_versioning import (
622
622
        for (oname, value, section, conf_id, parser) in self._get_options():
623
623
            if oname.startswith('bzr.mergetool.'):
624
624
                tool_name = oname[len('bzr.mergetool.'):]
625
 
                tools[tool_name] = value
 
625
                tools[tool_name] = self.get_user_option(oname)
626
626
        trace.mutter('loaded merge tools: %r' % tools)
627
627
        return tools
628
628
 
2426
2426
    return int(unicode_str)
2427
2427
 
2428
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
 
2429
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']
2430
2444
    # ConfigObj return '' instead of u''. Use 'str' below to catch all cases.
2431
 
    if isinstance(unicode_str, (str, unicode)):
2432
 
        if unicode_str:
 
2445
    if isinstance(maybe_list, basestring):
 
2446
        if maybe_list:
2433
2447
            # A single value, most probably the user forgot (or didn't care to
2434
2448
            # add) the final ','
2435
 
            l = [unicode_str]
 
2449
            l = [maybe_list]
2436
2450
        else:
2437
2451
            # The empty string, convert to empty list
2438
2452
            l = []
2439
2453
    else:
2440
2454
        # We rely on ConfigObj providing us with a list already
2441
 
        l = unicode_str
 
2455
        l = maybe_list
2442
2456
    return l
2443
2457
 
2444
2458
 
2715
2729
        co_input = StringIO(bytes)
2716
2730
        try:
2717
2731
            # The config files are always stored utf8-encoded
2718
 
            self._config_obj = ConfigObj(co_input, encoding='utf-8')
 
2732
            self._config_obj = ConfigObj(co_input, encoding='utf-8',
 
2733
                                         list_values=False)
2719
2734
        except configobj.ConfigObjError, e:
2720
2735
            self._config_obj = None
2721
2736
            raise errors.ParseConfigError(e.errors, self.external_url())
2876
2891
class SectionMatcher(object):
2877
2892
    """Select sections into a given Store.
2878
2893
 
2879
 
    This intended to be used to postpone getting an iterable of sections from a
2880
 
    store.
 
2894
    This is intended to be used to postpone getting an iterable of sections
 
2895
    from a store.
2881
2896
    """
2882
2897
 
2883
2898
    def __init__(self, store):
2892
2907
            if self.match(s):
2893
2908
                yield s
2894
2909
 
2895
 
    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
        """
2896
2917
        raise NotImplementedError(self.match)
2897
2918
 
2898
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
 
2899
2930
class LocationSection(Section):
2900
2931
 
2901
2932
    def __init__(self, section, length, extra_path):
2978
3009
class Stack(object):
2979
3010
    """A stack of configurations where an option can be defined"""
2980
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
 
2981
3021
    def __init__(self, sections_def, store=None, mutable_section_name=None):
2982
3022
        """Creates a stack of sections with an optional store for changes.
2983
3023
 
2996
3036
        self.store = store
2997
3037
        self.mutable_section_name = mutable_section_name
2998
3038
 
2999
 
    def get(self, name):
 
3039
    def get(self, name, expand=None):
3000
3040
        """Return the *first* option value found in the sections.
3001
3041
 
3002
3042
        This is where we guarantee that sections coming from Store are loaded
3004
3044
        option exists or get its value, which in turn may require to discover
3005
3045
        in which sections it can be defined. Both of these (section and option
3006
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.
3007
3053
        """
3008
3054
        # FIXME: No caching of options nor sections yet -- vila 20110503
 
3055
        if expand is None:
 
3056
            expand = _get_expand_default_value()
3009
3057
        value = None
3010
3058
        # Ensuring lazy loading is achieved by delaying section matching (which
3011
3059
        # implies querying the persistent storage) until it can't be avoided
3030
3078
        except KeyError:
3031
3079
            # Not registered
3032
3080
            opt = None
3033
 
        if opt is not None:
3034
 
            value = opt.convert_from_unicode(value)
3035
 
            if value is None:
3036
 
                # The conversion failed or there was no value to convert,
3037
 
                # fallback to the default value
3038
 
                value = opt.convert_from_unicode(opt.get_default())
 
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:
 
3097
            # If the option is registered, it may provide a default value
 
3098
            value = opt.get_default()
 
3099
            value = expand_and_convert(value)
3039
3100
        for hook in ConfigHooks['get']:
3040
3101
            hook(self, name, value)
3041
3102
        return value
3042
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
 
3043
3179
    def _get_mutable_section(self):
3044
3180
        """Get the MutableSection for the Stack.
3045
3181