~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: 2010-11-08 13:45:51 UTC
  • mfrom: (5532.1.1 trunk)
  • Revision ID: pqm@pqm.ubuntu.com-20101108134551-sxvk77ehmegkrwmm
(vila) Fix news entry

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
3
#            and others
4
4
#
82
82
    errors,
83
83
    lockdir,
84
84
    mail_client,
85
 
    mergetools,
86
85
    osutils,
87
86
    registry,
88
87
    symbol_versioning,
129
128
STORE_BRANCH = 3
130
129
STORE_GLOBAL = 4
131
130
 
132
 
 
133
 
class ConfigObj(configobj.ConfigObj):
134
 
 
135
 
    def __init__(self, infile=None, **kwargs):
136
 
        # We define our own interpolation mechanism
137
 
        super(ConfigObj, self).__init__(infile=infile,
138
 
                                        interpolation=False,
139
 
                                        **kwargs)
140
 
 
141
 
 
142
 
    def get_bool(self, section, key):
143
 
        return self[section].as_bool(key)
144
 
 
145
 
    def get_value(self, section, name):
146
 
        # Try [] for the old DEFAULT section.
147
 
        if section == "DEFAULT":
148
 
            try:
149
 
                return self[name]
150
 
            except KeyError:
151
 
                pass
152
 
        return self[section][name]
153
 
 
 
131
_ConfigObj = None
 
132
def ConfigObj(*args, **kwargs):
 
133
    global _ConfigObj
 
134
    if _ConfigObj is None:
 
135
        class ConfigObj(configobj.ConfigObj):
 
136
 
 
137
            def get_bool(self, section, key):
 
138
                return self[section].as_bool(key)
 
139
 
 
140
            def get_value(self, section, name):
 
141
                # Try [] for the old DEFAULT section.
 
142
                if section == "DEFAULT":
 
143
                    try:
 
144
                        return self[name]
 
145
                    except KeyError:
 
146
                        pass
 
147
                return self[section][name]
 
148
        _ConfigObj = ConfigObj
 
149
    return _ConfigObj(*args, **kwargs)
154
150
 
155
151
 
156
152
class Config(object):
192
188
    def _get_signing_policy(self):
193
189
        """Template method to override signature creation policy."""
194
190
 
195
 
    option_ref_re = None
196
 
 
197
 
    def interpolate(self, string, env=None):
198
 
        """Interpolate the string in the configuration context.
199
 
 
200
 
        :param string: The string to interpolate
201
 
 
202
 
        :param env: An option dict defining additional configuration options or
203
 
            overriding existing ones.
204
 
 
205
 
        :returns: The interpolated string.
206
 
        """
207
 
        return self._interpolate_string(string, env)
208
 
 
209
 
    def _interpolate_list(self, slist, env=None, _ref_stack=None):
210
 
        """Interpolate a list of strings in the configuration context.
211
 
 
212
 
        :param slist: A list of strings.
213
 
 
214
 
        :param env: An option dict defining additional configuration options or
215
 
            overriding existing ones.
216
 
 
217
 
        :param _ref_stack: Private list containing the options being
218
 
            interpolated to detect loops.
219
 
 
220
 
        :returns: The flatten list of interpolated strings.
221
 
        """
222
 
        # interpolate each value separately flattening lists
223
 
        result = []
224
 
        for s in slist:
225
 
            value = self._interpolate_string(s, env, _ref_stack)
226
 
            if isinstance(value, list):
227
 
                result.extend(value)
228
 
            else:
229
 
                result.append(value)
230
 
        return result
231
 
 
232
 
    def _interpolate_string(self, string, env=None, _ref_stack=None):
233
 
        """Interpolate the string in the configuration context.
234
 
 
235
 
        :param string: The string to interpolate
236
 
 
237
 
        :param env: An option dict defining additional configuration options or
238
 
            overriding existing ones.
239
 
 
240
 
        :param _ref_stack: Private list containing the options being
241
 
            interpolated to detect loops.
242
 
 
243
 
        :returns: The interpolated string.
244
 
        """
245
 
        if string is None:
246
 
            # Not much to interpolate there
247
 
            return None
248
 
        if _ref_stack is None:
249
 
            # What references are currently resolved (to detect loops)
250
 
            _ref_stack = []
251
 
        if self.option_ref_re is None:
252
 
            # We want to match the most embedded reference first (i.e. for
253
 
            # '{{foo}}' we will get '{foo}',
254
 
            # for '{bar{baz}}' we will get '{baz}'
255
 
            self.option_ref_re = re.compile('({[^{}]+})')
256
 
        result = string
257
 
        # We need to iterate until no more refs appear ({{foo}} will need two
258
 
        # iterations for example).
259
 
        while True:
260
 
            try:
261
 
                raw_chunks = self.option_ref_re.split(result)
262
 
            except TypeError:
263
 
                import pdb; pdb.set_trace()
264
 
            if len(raw_chunks) == 1:
265
 
                # Shorcut the trivial case: no refs
266
 
                return result
267
 
            chunks = []
268
 
            list_value = False
269
 
            # Split will isolate refs so that every other chunk is a ref
270
 
            chunk_is_ref = False
271
 
            for chunk in raw_chunks:
272
 
                if not chunk_is_ref:
273
 
                    if chunk:
274
 
                        # Keep only non-empty strings
275
 
                        chunks.append(chunk)
276
 
                    chunk_is_ref = True
277
 
                else:
278
 
                    name = chunk[1:-1]
279
 
                    if name in _ref_stack:
280
 
                        raise errors.InterpolationLoop(string, _ref_stack)
281
 
                    _ref_stack.append(name)
282
 
                    value = self._interpolate_option(name, env, _ref_stack)
283
 
                    if value is None:
284
 
                        raise errors.InterpolationUnknownOption(name, string)
285
 
                    if isinstance(value, list):
286
 
                        list_value = True
287
 
                        chunks.extend(value)
288
 
                    else:
289
 
                        chunks.append(value)
290
 
                    _ref_stack.pop()
291
 
                    chunk_is_ref = False
292
 
            if list_value:
293
 
                # Once a list appears as the result of an interpolation, all
294
 
                # callers will get a list result. This allows a consistent
295
 
                # behavior even when some options in the interpolation chain
296
 
                # may be seen defined as strings even if their interpolated
297
 
                # value is a list.
298
 
                return self._interpolate_list(chunks, env, _ref_stack)
299
 
            else:
300
 
                result = ''.join(chunks)
301
 
        return result
302
 
 
303
 
    def _interpolate_option(self, name, env, _ref_stack):
304
 
        if env is not None and name in env:
305
 
            # Special case, values provided in env takes precedence over
306
 
            # anything else
307
 
            value = env[name]
308
 
        else:
309
 
            # FIXME: This is a limited implementation, what we really need
310
 
            # is a way to query the bzr config for the value of an option,
311
 
            # respecting the scope rules -- vila 20101222
312
 
            value = self.get_user_option(name, interpolate=False)
313
 
            if isinstance(value, list):
314
 
                value = self._interpolate_list(value, env, _ref_stack)
315
 
            else:
316
 
                value = self._interpolate_string(value, env, _ref_stack)
317
 
        return value
318
 
 
319
191
    def _get_user_option(self, option_name):
320
192
        """Template method to provide a user option."""
321
193
        return None
322
194
 
323
 
    def get_user_option(self, option_name, interpolate=True):
 
195
    def get_user_option(self, option_name):
324
196
        """Get a generic option - no special process, no default."""
325
 
        value = self._get_user_option(option_name)
326
 
        if interpolate:
327
 
            if isinstance(value, list):
328
 
                value = self._interpolate_list(value)
329
 
            elif isinstance(value, dict):
330
 
                trace.warning('Cannot expand "%s":'
331
 
                              ' Dicts do not support option expansion'
332
 
                              % (option_name,))
333
 
            else:
334
 
                value = self._interpolate_string(value)
335
 
        return value
 
197
        return self._get_user_option(option_name)
336
198
 
337
199
    def get_user_option_as_bool(self, option_name):
338
200
        """Get a generic option as a boolean - no special process, no default.
359
221
        """
360
222
        l = self._get_user_option(option_name)
361
223
        if isinstance(l, (str, unicode)):
362
 
            # A single value, most probably the user forgot (or didn't care to
363
 
            # add) the final ','
 
224
            # A single value, most probably the user forgot the final ','
364
225
            l = [l]
365
226
        return l
366
227
 
496
357
        else:
497
358
            return True
498
359
 
499
 
    def get_merge_tools(self):
500
 
        tools = {}
501
 
        for (oname, value, section, conf_id, parser) in self._get_options():
502
 
            if oname.startswith('bzr.mergetool.'):
503
 
                tool_name = oname[len('bzr.mergetool.'):]
504
 
                tools[tool_name] = value
505
 
        trace.mutter('loaded merge tools: %r' % tools)
506
 
        return tools
507
 
 
508
 
    def find_merge_tool(self, name):
509
 
        # We fake a defaults mechanism here by checking if the given name can 
510
 
        # be found in the known_merge_tools if it's not found in the config.
511
 
        # This should be done through the proposed config defaults mechanism
512
 
        # when it becomes available in the future.
513
 
        command_line = (self.get_user_option('bzr.mergetool.%s' % name,
514
 
                                             interpolate=False)
515
 
                        or mergetools.known_merge_tools.get(name, None))
516
 
        return command_line
517
 
 
518
360
 
519
361
class IniBasedConfig(Config):
520
362
    """A configuration policy that draws from ini files."""
654
496
        config_id = self.config_id()
655
497
        for (section_name, section) in sections:
656
498
            for (name, value) in section.iteritems():
657
 
                yield (name, parser._quote(value), section_name,
658
 
                       config_id, parser)
 
499
                yield (name, value, section_name, config_id)
659
500
 
660
501
    def _get_option_policy(self, section, option_name):
661
502
        """Return the policy for the given (section, option_name) pair."""
811
652
    def __init__(self, file_name):
812
653
        super(LockableConfig, self).__init__(file_name=file_name)
813
654
        self.dir = osutils.dirname(osutils.safe_unicode(self.file_name))
814
 
        # FIXME: It doesn't matter that we don't provide possible_transports
815
 
        # below since this is currently used only for local config files ;
816
 
        # local transports are not shared. But if/when we start using
817
 
        # LockableConfig for other kind of transports, we will need to reuse
818
 
        # whatever connection is already established -- vila 20100929
819
655
        self.transport = transport.get_transport(self.dir)
820
656
        self._lock = lockdir.LockDir(self.transport, 'lock')
821
657
 
1206
1042
        config_id = self.config_id()
1207
1043
        for (section_name, section) in sections:
1208
1044
            for (name, value) in section.iteritems():
1209
 
                yield (name, value, section_name,
1210
 
                       config_id, branch_config._get_parser())
 
1045
                yield (name, value, section_name, config_id)
1211
1046
        # Then the global options
1212
1047
        for option in self._get_global_config()._get_options():
1213
1048
            yield option
1286
1121
def config_dir():
1287
1122
    """Return per-user configuration directory.
1288
1123
 
1289
 
    By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
1290
 
    and Linux.  On Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
1291
 
    that will be used instead.
 
1124
    By default this is ~/.bazaar/
1292
1125
 
1293
1126
    TODO: Global option --config-dir to override this.
1294
1127
    """
1295
1128
    base = os.environ.get('BZR_HOME', None)
1296
1129
    if sys.platform == 'win32':
1297
 
        # environ variables on Windows are in user encoding/mbcs. So decode
1298
 
        # before using one
1299
 
        if base is not None:
1300
 
            base = base.decode('mbcs')
1301
1130
        if base is None:
1302
1131
            base = win32utils.get_appdata_location_unicode()
1303
1132
        if base is None:
1304
1133
            base = os.environ.get('HOME', None)
1305
 
            if base is not None:
1306
 
                base = base.decode('mbcs')
1307
1134
        if base is None:
1308
1135
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
1309
1136
                                  ' or HOME set')
1310
1137
        return osutils.pathjoin(base, 'bazaar', '2.0')
1311
 
    elif sys.platform == 'darwin':
1312
 
        if base is None:
1313
 
            # this takes into account $HOME
1314
 
            base = os.path.expanduser("~")
1315
 
        return osutils.pathjoin(base, '.bazaar')
1316
1138
    else:
1317
1139
        if base is None:
1318
 
 
1319
 
            xdg_dir = os.environ.get('XDG_CONFIG_HOME', None)
1320
 
            if xdg_dir is None:
1321
 
                xdg_dir = osutils.pathjoin(os.path.expanduser("~"), ".config")
1322
 
            xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
1323
 
            if osutils.isdir(xdg_dir):
1324
 
                trace.mutter(
1325
 
                    "Using configuration in XDG directory %s." % xdg_dir)
1326
 
                return xdg_dir
1327
 
 
1328
1140
            base = os.path.expanduser("~")
1329
1141
        return osutils.pathjoin(base, ".bazaar")
1330
1142
 
2050
1862
        for c in self._get_configs(directory, scope):
2051
1863
            if displayed:
2052
1864
                break
2053
 
            for (oname, value, section, conf_id, parser) in c._get_options():
 
1865
            for (oname, value, section, conf_id) in c._get_options():
2054
1866
                if name == oname:
2055
1867
                    # Display only the first value and exit
2056
 
 
2057
 
                    # FIXME: We need to use get_user_option to take policies
2058
 
                    # into account and we need to make sure the option exists
2059
 
                    # too (hence the two for loops), this needs a better API
2060
 
                    # -- vila 20101117
2061
 
                    value = c.get_user_option(name)
2062
 
                    # Quote the value appropriately
2063
 
                    value = parser._quote(value)
2064
 
                    self.outf.write('%s\n' % (value,))
 
1868
                    self.outf.write('%s\n' % (value))
2065
1869
                    displayed = True
2066
1870
                    break
2067
1871
        if not displayed:
2073
1877
        # avoid the delay introduced by the lazy regexp.
2074
1878
        name._compile_and_collapse()
2075
1879
        cur_conf_id = None
2076
 
        cur_section = None
2077
1880
        for c in self._get_configs(directory, scope):
2078
 
            for (oname, value, section, conf_id, parser) in c._get_options():
 
1881
            for (oname, value, section, conf_id) in c._get_options():
2079
1882
                if name.search(oname):
2080
1883
                    if cur_conf_id != conf_id:
2081
1884
                        # Explain where the options are defined
2082
1885
                        self.outf.write('%s:\n' % (conf_id,))
2083
1886
                        cur_conf_id = conf_id
2084
 
                        cur_section = None
2085
 
                    if (section not in (None, 'DEFAULT')
2086
 
                        and cur_section != section):
2087
 
                        # Display the section if it's not the default (or only)
2088
 
                        # one.
2089
 
                        self.outf.write('  [%s]\n' % (section,))
2090
 
                        cur_section = section
2091
1887
                    self.outf.write('  %s = %s\n' % (oname, value))
2092
1888
 
2093
1889
    def _set_config_option(self, name, value, directory, scope):