~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Andrew Bennetts
  • Date: 2011-02-25 08:45:27 UTC
  • mto: This revision was merged to the branch mainline in revision 5695.
  • Revision ID: andrew.bennetts@canonical.com-20110225084527-0ucp7p00d00hoqon
Add another test.

Show diffs side-by-side

added added

removed removed

Lines of Context:
129
129
STORE_BRANCH = 3
130
130
STORE_GLOBAL = 4
131
131
 
132
 
 
133
 
class ConfigObj(configobj.ConfigObj):
134
 
 
135
 
    def __init__(self, infile=None, **kwargs):
136
 
        # We define our own interpolation mechanism calling it option expansion
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
 
 
154
 
 
155
 
# FIXME: Until we can guarantee that each config file is loaded once and and
156
 
# only once for a given bzrlib session, we don't want to re-read the file every
157
 
# time we query for an option so we cache the value (bad ! watch out for tests
158
 
# needing to restore the proper value).This shouldn't be part of 2.4.0 final,
159
 
# yell at mgz^W vila and the RM if this is still present at that time
160
 
# -- vila 20110219
161
 
_expand_default_value = None
162
 
def _get_expand_default_value():
163
 
    global _expand_default_value
164
 
    if _expand_default_value is not None:
165
 
        return _expand_default_value
166
 
    conf = GlobalConfig()
167
 
    # Note that we must not use None for the expand value below or we'll run
168
 
    # into infinite recursion. Using False really would be quite silly ;)
169
 
    expand = conf.get_user_option_as_bool('bzr.config.expand', expand=True)
170
 
    if expand is None:
171
 
        # This is an opt-in feature, you *really* need to clearly say you want
172
 
        # to activate it !
173
 
        expand = False
174
 
    _expand_default_value = expand
175
 
    return expand
 
132
_ConfigObj = None
 
133
def ConfigObj(*args, **kwargs):
 
134
    global _ConfigObj
 
135
    if _ConfigObj is None:
 
136
        class ConfigObj(configobj.ConfigObj):
 
137
 
 
138
            def get_bool(self, section, key):
 
139
                return self[section].as_bool(key)
 
140
 
 
141
            def get_value(self, section, name):
 
142
                # Try [] for the old DEFAULT section.
 
143
                if section == "DEFAULT":
 
144
                    try:
 
145
                        return self[name]
 
146
                    except KeyError:
 
147
                        pass
 
148
                return self[section][name]
 
149
        _ConfigObj = ConfigObj
 
150
    return _ConfigObj(*args, **kwargs)
176
151
 
177
152
 
178
153
class Config(object):
214
189
    def _get_signing_policy(self):
215
190
        """Template method to override signature creation policy."""
216
191
 
217
 
    option_ref_re = None
218
 
 
219
 
    def expand_options(self, string, env=None):
220
 
        """Expand option references in the string in the configuration context.
221
 
 
222
 
        :param string: The string containing option to expand.
223
 
 
224
 
        :param env: An option dict defining additional configuration options or
225
 
            overriding existing ones.
226
 
 
227
 
        :returns: The expanded string.
228
 
        """
229
 
        return self._expand_options_in_string(string, env)
230
 
 
231
 
    def _expand_options_in_list(self, slist, env=None, _ref_stack=None):
232
 
        """Expand options in  a list of strings in the configuration context.
233
 
 
234
 
        :param slist: A list of strings.
235
 
 
236
 
        :param env: An option dict defining additional configuration options or
237
 
            overriding existing ones.
238
 
 
239
 
        :param _ref_stack: Private list containing the options being
240
 
            expanded to detect loops.
241
 
 
242
 
        :returns: The flatten list of expanded strings.
243
 
        """
244
 
        # expand options in each value separately flattening lists
245
 
        result = []
246
 
        for s in slist:
247
 
            value = self._expand_options_in_string(s, env, _ref_stack)
248
 
            if isinstance(value, list):
249
 
                result.extend(value)
250
 
            else:
251
 
                result.append(value)
252
 
        return result
253
 
 
254
 
    def _expand_options_in_string(self, string, env=None, _ref_stack=None):
255
 
        """Expand options in the string in the configuration context.
256
 
 
257
 
        :param string: The string to be expanded.
258
 
 
259
 
        :param env: An option dict defining additional configuration options or
260
 
            overriding existing ones.
261
 
 
262
 
        :param _ref_stack: Private list containing the options being
263
 
            expanded to detect loops.
264
 
 
265
 
        :returns: The expanded string.
266
 
        """
267
 
        if string is None:
268
 
            # Not much to expand there
269
 
            return None
270
 
        if _ref_stack is None:
271
 
            # What references are currently resolved (to detect loops)
272
 
            _ref_stack = []
273
 
        if self.option_ref_re is None:
274
 
            # We want to match the most embedded reference first (i.e. for
275
 
            # '{{foo}}' we will get '{foo}',
276
 
            # for '{bar{baz}}' we will get '{baz}'
277
 
            self.option_ref_re = re.compile('({[^{}]+})')
278
 
        result = string
279
 
        # We need to iterate until no more refs appear ({{foo}} will need two
280
 
        # iterations for example).
281
 
        while True:
282
 
            try:
283
 
                raw_chunks = self.option_ref_re.split(result)
284
 
            except TypeError:
285
 
                import pdb; pdb.set_trace()
286
 
            if len(raw_chunks) == 1:
287
 
                # Shorcut the trivial case: no refs
288
 
                return result
289
 
            chunks = []
290
 
            list_value = False
291
 
            # Split will isolate refs so that every other chunk is a ref
292
 
            chunk_is_ref = False
293
 
            for chunk in raw_chunks:
294
 
                if not chunk_is_ref:
295
 
                    if chunk:
296
 
                        # Keep only non-empty strings (or we get bogus empty
297
 
                        # slots when a list value is involved).
298
 
                        chunks.append(chunk)
299
 
                    chunk_is_ref = True
300
 
                else:
301
 
                    name = chunk[1:-1]
302
 
                    if name in _ref_stack:
303
 
                        raise errors.OptionExpansionLoop(string, _ref_stack)
304
 
                    _ref_stack.append(name)
305
 
                    value = self._expand_option(name, env, _ref_stack)
306
 
                    if value is None:
307
 
                        raise errors.ExpandingUnknownOption(name, string)
308
 
                    if isinstance(value, list):
309
 
                        list_value = True
310
 
                        chunks.extend(value)
311
 
                    else:
312
 
                        chunks.append(value)
313
 
                    _ref_stack.pop()
314
 
                    chunk_is_ref = False
315
 
            if list_value:
316
 
                # Once a list appears as the result of an expansion, all
317
 
                # callers will get a list result. This allows a consistent
318
 
                # behavior even when some options in the expansion chain
319
 
                # defined as strings (no comma in their value) but their
320
 
                # expanded value is a list.
321
 
                return self._expand_options_in_list(chunks, env, _ref_stack)
322
 
            else:
323
 
                result = ''.join(chunks)
324
 
        return result
325
 
 
326
 
    def _expand_option(self, name, env, _ref_stack):
327
 
        if env is not None and name in env:
328
 
            # Special case, values provided in env takes precedence over
329
 
            # anything else
330
 
            value = env[name]
331
 
        else:
332
 
            # FIXME: This is a limited implementation, what we really need is a
333
 
            # way to query the bzr config for the value of an option,
334
 
            # respecting the scope rules (That is, once we implement fallback
335
 
            # configs, getting the option value should restart from the top
336
 
            # config, not the current one) -- vila 20101222
337
 
            value = self.get_user_option(name, expand=False)
338
 
            if isinstance(value, list):
339
 
                value = self._expand_options_in_list(value, env, _ref_stack)
340
 
            else:
341
 
                value = self._expand_options_in_string(value, env, _ref_stack)
342
 
        return value
343
 
 
344
192
    def _get_user_option(self, option_name):
345
193
        """Template method to provide a user option."""
346
194
        return None
347
195
 
348
 
    def get_user_option(self, option_name, expand=None):
349
 
        """Get a generic option - no special process, no default.
350
 
 
351
 
        :param option_name: The queried option.
352
 
 
353
 
        :param expand: Whether options references should be expanded.
354
 
 
355
 
        :returns: The value of the option.
356
 
        """
357
 
        if expand is None:
358
 
            expand = _get_expand_default_value()
359
 
        value = self._get_user_option(option_name)
360
 
        if expand:
361
 
            if isinstance(value, list):
362
 
                value = self._expand_options_in_list(value)
363
 
            elif isinstance(value, dict):
364
 
                trace.warning('Cannot expand "%s":'
365
 
                              ' Dicts do not support option expansion'
366
 
                              % (option_name,))
367
 
            else:
368
 
                value = self._expand_options_in_string(value)
369
 
        return value
370
 
 
371
 
    def get_user_option_as_bool(self, option_name, expand=None):
 
196
    def get_user_option(self, option_name):
 
197
        """Get a generic option - no special process, no default."""
 
198
        return self._get_user_option(option_name)
 
199
 
 
200
    def get_user_option_as_bool(self, option_name):
372
201
        """Get a generic option as a boolean - no special process, no default.
373
202
 
374
203
        :return None if the option doesn't exist or its value can't be
375
204
            interpreted as a boolean. Returns True or False otherwise.
376
205
        """
377
 
        s = self.get_user_option(option_name, expand=expand)
 
206
        s = self._get_user_option(option_name)
378
207
        if s is None:
379
208
            # The option doesn't exist
380
209
            return None
385
214
                          s, option_name)
386
215
        return val
387
216
 
388
 
    def get_user_option_as_list(self, option_name, expand=None):
 
217
    def get_user_option_as_list(self, option_name):
389
218
        """Get a generic option as a list - no special process, no default.
390
219
 
391
220
        :return None if the option doesn't exist. Returns the value as a list
392
221
            otherwise.
393
222
        """
394
 
        l = self.get_user_option(option_name, expand=expand)
 
223
        l = self._get_user_option(option_name)
395
224
        if isinstance(l, (str, unicode)):
396
 
            # A single value, most probably the user forgot (or didn't care to
397
 
            # add) the final ','
 
225
            # A single value, most probably the user forgot the final ','
398
226
            l = [l]
399
227
        return l
400
228
 
544
372
        # be found in the known_merge_tools if it's not found in the config.
545
373
        # This should be done through the proposed config defaults mechanism
546
374
        # when it becomes available in the future.
547
 
        command_line = (self.get_user_option('bzr.mergetool.%s' % name,
548
 
                                             expand=False)
549
 
                        or mergetools.known_merge_tools.get(name, None))
 
375
        command_line = (self.get_user_option('bzr.mergetool.%s' % name) or
 
376
                        mergetools.known_merge_tools.get(name, None))
550
377
        return command_line
551
378
 
552
379
 
845
672
    def __init__(self, file_name):
846
673
        super(LockableConfig, self).__init__(file_name=file_name)
847
674
        self.dir = osutils.dirname(osutils.safe_unicode(self.file_name))
848
 
        # FIXME: It doesn't matter that we don't provide possible_transports
849
 
        # below since this is currently used only for local config files ;
850
 
        # local transports are not shared. But if/when we start using
851
 
        # LockableConfig for other kind of transports, we will need to reuse
852
 
        # whatever connection is already established -- vila 20100929
853
675
        self.transport = transport.get_transport(self.dir)
854
676
        self._lock = lockdir.LockDir(self.transport, 'lock')
855
677