~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: John Arbash Meinel
  • Date: 2011-05-11 11:35:28 UTC
  • mto: This revision was merged to the branch mainline in revision 5851.
  • Revision ID: john@arbash-meinel.com-20110511113528-qepibuwxicjrbb2h
Break compatibility with python <2.6.

This includes auditing the code for places where we were doing
explicit 'sys.version' checks and removing them as appropriate.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2011 Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
3
#            and others
4
4
#
63
63
"""
64
64
 
65
65
import os
 
66
import string
66
67
import sys
67
68
 
 
69
from bzrlib import commands
68
70
from bzrlib.decorators import needs_write_lock
69
71
from bzrlib.lazy_import import lazy_import
70
72
lazy_import(globals(), """
71
 
import errno
72
 
from fnmatch import fnmatch
 
73
import fnmatch
73
74
import re
74
75
from cStringIO import StringIO
75
76
 
76
77
import bzrlib
77
78
from bzrlib import (
78
79
    atomicfile,
 
80
    bzrdir,
79
81
    debug,
80
82
    errors,
81
83
    lockdir,
82
84
    mail_client,
 
85
    mergetools,
83
86
    osutils,
84
87
    registry,
85
88
    symbol_versioning,
126
129
STORE_BRANCH = 3
127
130
STORE_GLOBAL = 4
128
131
 
129
 
_ConfigObj = None
130
 
def ConfigObj(*args, **kwargs):
131
 
    global _ConfigObj
132
 
    if _ConfigObj is None:
133
 
        class ConfigObj(configobj.ConfigObj):
134
 
 
135
 
            def get_bool(self, section, key):
136
 
                return self[section].as_bool(key)
137
 
 
138
 
            def get_value(self, section, name):
139
 
                # Try [] for the old DEFAULT section.
140
 
                if section == "DEFAULT":
141
 
                    try:
142
 
                        return self[name]
143
 
                    except KeyError:
144
 
                        pass
145
 
                return self[section][name]
146
 
        _ConfigObj = ConfigObj
147
 
    return _ConfigObj(*args, **kwargs)
 
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
148
176
 
149
177
 
150
178
class Config(object):
153
181
    def __init__(self):
154
182
        super(Config, self).__init__()
155
183
 
 
184
    def config_id(self):
 
185
        """Returns a unique ID for the config."""
 
186
        raise NotImplementedError(self.config_id)
 
187
 
156
188
    def get_editor(self):
157
189
        """Get the users pop up editor."""
158
190
        raise NotImplementedError
182
214
    def _get_signing_policy(self):
183
215
        """Template method to override signature creation policy."""
184
216
 
 
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
            raw_chunks = self.option_ref_re.split(result)
 
283
            if len(raw_chunks) == 1:
 
284
                # Shorcut the trivial case: no refs
 
285
                return result
 
286
            chunks = []
 
287
            list_value = False
 
288
            # Split will isolate refs so that every other chunk is a ref
 
289
            chunk_is_ref = False
 
290
            for chunk in raw_chunks:
 
291
                if not chunk_is_ref:
 
292
                    if chunk:
 
293
                        # Keep only non-empty strings (or we get bogus empty
 
294
                        # slots when a list value is involved).
 
295
                        chunks.append(chunk)
 
296
                    chunk_is_ref = True
 
297
                else:
 
298
                    name = chunk[1:-1]
 
299
                    if name in _ref_stack:
 
300
                        raise errors.OptionExpansionLoop(string, _ref_stack)
 
301
                    _ref_stack.append(name)
 
302
                    value = self._expand_option(name, env, _ref_stack)
 
303
                    if value is None:
 
304
                        raise errors.ExpandingUnknownOption(name, string)
 
305
                    if isinstance(value, list):
 
306
                        list_value = True
 
307
                        chunks.extend(value)
 
308
                    else:
 
309
                        chunks.append(value)
 
310
                    _ref_stack.pop()
 
311
                    chunk_is_ref = False
 
312
            if list_value:
 
313
                # Once a list appears as the result of an expansion, all
 
314
                # callers will get a list result. This allows a consistent
 
315
                # behavior even when some options in the expansion chain
 
316
                # defined as strings (no comma in their value) but their
 
317
                # expanded value is a list.
 
318
                return self._expand_options_in_list(chunks, env, _ref_stack)
 
319
            else:
 
320
                result = ''.join(chunks)
 
321
        return result
 
322
 
 
323
    def _expand_option(self, name, env, _ref_stack):
 
324
        if env is not None and name in env:
 
325
            # Special case, values provided in env takes precedence over
 
326
            # anything else
 
327
            value = env[name]
 
328
        else:
 
329
            # FIXME: This is a limited implementation, what we really need is a
 
330
            # way to query the bzr config for the value of an option,
 
331
            # respecting the scope rules (That is, once we implement fallback
 
332
            # configs, getting the option value should restart from the top
 
333
            # config, not the current one) -- vila 20101222
 
334
            value = self.get_user_option(name, expand=False)
 
335
            if isinstance(value, list):
 
336
                value = self._expand_options_in_list(value, env, _ref_stack)
 
337
            else:
 
338
                value = self._expand_options_in_string(value, env, _ref_stack)
 
339
        return value
 
340
 
185
341
    def _get_user_option(self, option_name):
186
342
        """Template method to provide a user option."""
187
343
        return None
188
344
 
189
 
    def get_user_option(self, option_name):
190
 
        """Get a generic option - no special process, no default."""
191
 
        return self._get_user_option(option_name)
192
 
 
193
 
    def get_user_option_as_bool(self, option_name):
 
345
    def get_user_option(self, option_name, expand=None):
 
346
        """Get a generic option - no special process, no default.
 
347
 
 
348
        :param option_name: The queried option.
 
349
 
 
350
        :param expand: Whether options references should be expanded.
 
351
 
 
352
        :returns: The value of the option.
 
353
        """
 
354
        if expand is None:
 
355
            expand = _get_expand_default_value()
 
356
        value = self._get_user_option(option_name)
 
357
        if expand:
 
358
            if isinstance(value, list):
 
359
                value = self._expand_options_in_list(value)
 
360
            elif isinstance(value, dict):
 
361
                trace.warning('Cannot expand "%s":'
 
362
                              ' Dicts do not support option expansion'
 
363
                              % (option_name,))
 
364
            else:
 
365
                value = self._expand_options_in_string(value)
 
366
        return value
 
367
 
 
368
    def get_user_option_as_bool(self, option_name, expand=None):
194
369
        """Get a generic option as a boolean - no special process, no default.
195
370
 
196
371
        :return None if the option doesn't exist or its value can't be
197
372
            interpreted as a boolean. Returns True or False otherwise.
198
373
        """
199
 
        s = self._get_user_option(option_name)
 
374
        s = self.get_user_option(option_name, expand=expand)
200
375
        if s is None:
201
376
            # The option doesn't exist
202
377
            return None
207
382
                          s, option_name)
208
383
        return val
209
384
 
210
 
    def get_user_option_as_list(self, option_name):
 
385
    def get_user_option_as_list(self, option_name, expand=None):
211
386
        """Get a generic option as a list - no special process, no default.
212
387
 
213
388
        :return None if the option doesn't exist. Returns the value as a list
214
389
            otherwise.
215
390
        """
216
 
        l = self._get_user_option(option_name)
 
391
        l = self.get_user_option(option_name, expand=expand)
217
392
        if isinstance(l, (str, unicode)):
218
 
            # A single value, most probably the user forgot the final ','
 
393
            # A single value, most probably the user forgot (or didn't care to
 
394
            # add) the final ','
219
395
            l = [l]
220
396
        return l
221
397
 
265
441
        the concrete policy type is checked, and finally
266
442
        $EMAIL is examined.
267
443
        If no username can be found, errors.NoWhoami exception is raised.
268
 
 
269
 
        TODO: Check it's reasonably well-formed.
270
444
        """
271
445
        v = os.environ.get('BZR_EMAIL')
272
446
        if v:
273
447
            return v.decode(osutils.get_user_encoding())
274
 
 
275
448
        v = self._get_user_id()
276
449
        if v:
277
450
            return v
278
 
 
279
451
        v = os.environ.get('EMAIL')
280
452
        if v:
281
453
            return v.decode(osutils.get_user_encoding())
282
 
 
 
454
        name, email = _auto_user_id()
 
455
        if name and email:
 
456
            return '%s <%s>' % (name, email)
 
457
        elif email:
 
458
            return email
283
459
        raise errors.NoWhoami()
284
460
 
285
461
    def ensure_username(self):
351
527
        else:
352
528
            return True
353
529
 
 
530
    def get_merge_tools(self):
 
531
        tools = {}
 
532
        for (oname, value, section, conf_id, parser) in self._get_options():
 
533
            if oname.startswith('bzr.mergetool.'):
 
534
                tool_name = oname[len('bzr.mergetool.'):]
 
535
                tools[tool_name] = value
 
536
        trace.mutter('loaded merge tools: %r' % tools)
 
537
        return tools
 
538
 
 
539
    def find_merge_tool(self, name):
 
540
        # We fake a defaults mechanism here by checking if the given name can 
 
541
        # be found in the known_merge_tools if it's not found in the config.
 
542
        # This should be done through the proposed config defaults mechanism
 
543
        # when it becomes available in the future.
 
544
        command_line = (self.get_user_option('bzr.mergetool.%s' % name,
 
545
                                             expand=False)
 
546
                        or mergetools.known_merge_tools.get(name, None))
 
547
        return command_line
 
548
 
354
549
 
355
550
class IniBasedConfig(Config):
356
551
    """A configuration policy that draws from ini files."""
444
639
        """Override this to define the section used by the config."""
445
640
        return "DEFAULT"
446
641
 
 
642
    def _get_sections(self, name=None):
 
643
        """Returns an iterator of the sections specified by ``name``.
 
644
 
 
645
        :param name: The section name. If None is supplied, the default
 
646
            configurations are yielded.
 
647
 
 
648
        :return: A tuple (name, section, config_id) for all sections that will
 
649
            be walked by user_get_option() in the 'right' order. The first one
 
650
            is where set_user_option() will update the value.
 
651
        """
 
652
        parser = self._get_parser()
 
653
        if name is not None:
 
654
            yield (name, parser[name], self.config_id())
 
655
        else:
 
656
            # No section name has been given so we fallback to the configobj
 
657
            # itself which holds the variables defined outside of any section.
 
658
            yield (None, parser, self.config_id())
 
659
 
 
660
    def _get_options(self, sections=None):
 
661
        """Return an ordered list of (name, value, section, config_id) tuples.
 
662
 
 
663
        All options are returned with their associated value and the section
 
664
        they appeared in. ``config_id`` is a unique identifier for the
 
665
        configuration file the option is defined in.
 
666
 
 
667
        :param sections: Default to ``_get_matching_sections`` if not
 
668
            specified. This gives a better control to daughter classes about
 
669
            which sections should be searched. This is a list of (name,
 
670
            configobj) tuples.
 
671
        """
 
672
        opts = []
 
673
        if sections is None:
 
674
            parser = self._get_parser()
 
675
            sections = []
 
676
            for (section_name, _) in self._get_matching_sections():
 
677
                try:
 
678
                    section = parser[section_name]
 
679
                except KeyError:
 
680
                    # This could happen for an empty file for which we define a
 
681
                    # DEFAULT section. FIXME: Force callers to provide sections
 
682
                    # instead ? -- vila 20100930
 
683
                    continue
 
684
                sections.append((section_name, section))
 
685
        config_id = self.config_id()
 
686
        for (section_name, section) in sections:
 
687
            for (name, value) in section.iteritems():
 
688
                yield (name, parser._quote(value), section_name,
 
689
                       config_id, parser)
 
690
 
447
691
    def _get_option_policy(self, section, option_name):
448
692
        """Return the policy for the given (section, option_name) pair."""
449
693
        return POLICY_NONE
536
780
    def _get_nickname(self):
537
781
        return self.get_user_option('nickname')
538
782
 
 
783
    def remove_user_option(self, option_name, section_name=None):
 
784
        """Remove a user option and save the configuration file.
 
785
 
 
786
        :param option_name: The option to be removed.
 
787
 
 
788
        :param section_name: The section the option is defined in, default to
 
789
            the default section.
 
790
        """
 
791
        self.reload()
 
792
        parser = self._get_parser()
 
793
        if section_name is None:
 
794
            section = parser
 
795
        else:
 
796
            section = parser[section_name]
 
797
        try:
 
798
            del section[option_name]
 
799
        except KeyError:
 
800
            raise errors.NoSuchConfigOption(option_name)
 
801
        self._write_config_file()
 
802
 
539
803
    def _write_config_file(self):
540
804
        if self.file_name is None:
541
805
            raise AssertionError('We cannot save, self.file_name is None')
578
842
    def __init__(self, file_name):
579
843
        super(LockableConfig, self).__init__(file_name=file_name)
580
844
        self.dir = osutils.dirname(osutils.safe_unicode(self.file_name))
 
845
        # FIXME: It doesn't matter that we don't provide possible_transports
 
846
        # below since this is currently used only for local config files ;
 
847
        # local transports are not shared. But if/when we start using
 
848
        # LockableConfig for other kind of transports, we will need to reuse
 
849
        # whatever connection is already established -- vila 20100929
581
850
        self.transport = transport.get_transport(self.dir)
582
 
        self._lock = lockdir.LockDir(self.transport, 'lock')
 
851
        self._lock = lockdir.LockDir(self.transport, self.lock_name)
583
852
 
584
853
    def _create_from_string(self, unicode_bytes, save):
585
854
        super(LockableConfig, self)._create_from_string(unicode_bytes, False)
604
873
    def break_lock(self):
605
874
        self._lock.break_lock()
606
875
 
 
876
    @needs_write_lock
 
877
    def remove_user_option(self, option_name, section_name=None):
 
878
        super(LockableConfig, self).remove_user_option(option_name,
 
879
                                                       section_name)
 
880
 
607
881
    def _write_config_file(self):
608
882
        if self._lock is None or not self._lock.is_held:
609
883
            # NB: if the following exception is raised it probably means a
618
892
    def __init__(self):
619
893
        super(GlobalConfig, self).__init__(file_name=config_filename())
620
894
 
 
895
    def config_id(self):
 
896
        return 'bazaar'
 
897
 
621
898
    @classmethod
622
899
    def from_string(cls, str_or_unicode, save=False):
623
900
        """Create a config object from a string.
667
944
        self._write_config_file()
668
945
 
669
946
 
 
947
    def _get_sections(self, name=None):
 
948
        """See IniBasedConfig._get_sections()."""
 
949
        parser = self._get_parser()
 
950
        # We don't give access to options defined outside of any section, we
 
951
        # used the DEFAULT section by... default.
 
952
        if name in (None, 'DEFAULT'):
 
953
            # This could happen for an empty file where the DEFAULT section
 
954
            # doesn't exist yet. So we force DEFAULT when yielding
 
955
            name = 'DEFAULT'
 
956
            if 'DEFAULT' not in parser:
 
957
               parser['DEFAULT']= {}
 
958
        yield (name, parser[name], self.config_id())
 
959
 
 
960
    @needs_write_lock
 
961
    def remove_user_option(self, option_name, section_name=None):
 
962
        if section_name is None:
 
963
            # We need to force the default section.
 
964
            section_name = 'DEFAULT'
 
965
        # We need to avoid the LockableConfig implementation or we'll lock
 
966
        # twice
 
967
        super(LockableConfig, self).remove_user_option(option_name,
 
968
                                                       section_name)
 
969
 
 
970
def _iter_for_location_by_parts(sections, location):
 
971
    """Keep only the sessions matching the specified location.
 
972
 
 
973
    :param sections: An iterable of section names.
 
974
 
 
975
    :param location: An url or a local path to match against.
 
976
 
 
977
    :returns: An iterator of (section, extra_path, nb_parts) where nb is the
 
978
        number of path components in the section name, section is the section
 
979
        name and extra_path is the difference between location and the section
 
980
        name.
 
981
    """
 
982
    location_parts = location.rstrip('/').split('/')
 
983
 
 
984
    for section in sections:
 
985
        # location is a local path if possible, so we need
 
986
        # to convert 'file://' urls to local paths if necessary.
 
987
 
 
988
        # FIXME: I don't think the above comment is still up to date,
 
989
        # LocationConfig is always instantiated with an url -- vila 2011-04-07
 
990
 
 
991
        # This also avoids having file:///path be a more exact
 
992
        # match than '/path'.
 
993
 
 
994
        # FIXME: Not sure about the above either, but since the path components
 
995
        # are compared in sync, adding two empty components (//) is likely to
 
996
        # trick the comparison and also trick the check on the number of
 
997
        # components, so we *should* take only the relevant part of the url. On
 
998
        # the other hand, this means 'file://' urls *can't* be used in sections
 
999
        # so more work is probably needed -- vila 2011-04-07
 
1000
 
 
1001
        if section.startswith('file://'):
 
1002
            section_path = urlutils.local_path_from_url(section)
 
1003
        else:
 
1004
            section_path = section
 
1005
        section_parts = section_path.rstrip('/').split('/')
 
1006
 
 
1007
        matched = True
 
1008
        if len(section_parts) > len(location_parts):
 
1009
            # More path components in the section, they can't match
 
1010
            matched = False
 
1011
        else:
 
1012
            # Rely on zip truncating in length to the length of the shortest
 
1013
            # argument sequence.
 
1014
            names = zip(location_parts, section_parts)
 
1015
            for name in names:
 
1016
                if not fnmatch.fnmatch(name[0], name[1]):
 
1017
                    matched = False
 
1018
                    break
 
1019
        if not matched:
 
1020
            continue
 
1021
        # build the path difference between the section and the location
 
1022
        extra_path = '/'.join(location_parts[len(section_parts):])
 
1023
        yield section, extra_path, len(section_parts)
 
1024
 
 
1025
 
670
1026
class LocationConfig(LockableConfig):
671
1027
    """A configuration object that gives the policy for a location."""
672
1028
 
680
1036
            location = urlutils.local_path_from_url(location)
681
1037
        self.location = location
682
1038
 
 
1039
    def config_id(self):
 
1040
        return 'locations'
 
1041
 
683
1042
    @classmethod
684
1043
    def from_string(cls, str_or_unicode, location, save=False):
685
1044
        """Create a config object from a string.
697
1056
 
698
1057
    def _get_matching_sections(self):
699
1058
        """Return an ordered list of section names matching this location."""
700
 
        sections = self._get_parser()
701
 
        location_names = self.location.split('/')
702
 
        if self.location.endswith('/'):
703
 
            del location_names[-1]
704
 
        matches=[]
705
 
        for section in sections:
706
 
            # location is a local path if possible, so we need
707
 
            # to convert 'file://' urls to local paths if necessary.
708
 
            # This also avoids having file:///path be a more exact
709
 
            # match than '/path'.
710
 
            if section.startswith('file://'):
711
 
                section_path = urlutils.local_path_from_url(section)
712
 
            else:
713
 
                section_path = section
714
 
            section_names = section_path.split('/')
715
 
            if section.endswith('/'):
716
 
                del section_names[-1]
717
 
            names = zip(location_names, section_names)
718
 
            matched = True
719
 
            for name in names:
720
 
                if not fnmatch(name[0], name[1]):
721
 
                    matched = False
722
 
                    break
723
 
            if not matched:
724
 
                continue
725
 
            # so, for the common prefix they matched.
726
 
            # if section is longer, no match.
727
 
            if len(section_names) > len(location_names):
728
 
                continue
729
 
            matches.append((len(section_names), section,
730
 
                            '/'.join(location_names[len(section_names):])))
731
 
        matches.sort(reverse=True)
732
 
        sections = []
733
 
        for (length, section, extra_path) in matches:
734
 
            sections.append((section, extra_path))
 
1059
        matches = list(_iter_for_location_by_parts(self._get_parser(),
 
1060
                                                   self.location))
 
1061
        # put the longest (aka more specific) locations first
 
1062
        matches.sort(
 
1063
            key=lambda (section, extra_path, length): (length, section),
 
1064
            reverse=True)
 
1065
        for (section, extra_path, length) in matches:
 
1066
            yield section, extra_path
735
1067
            # should we stop looking for parent configs here?
736
1068
            try:
737
1069
                if self._get_parser()[section].as_bool('ignore_parents'):
738
1070
                    break
739
1071
            except KeyError:
740
1072
                pass
741
 
        return sections
 
1073
 
 
1074
    def _get_sections(self, name=None):
 
1075
        """See IniBasedConfig._get_sections()."""
 
1076
        # We ignore the name here as the only sections handled are named with
 
1077
        # the location path and we don't expose embedded sections either.
 
1078
        parser = self._get_parser()
 
1079
        for name, extra_path in self._get_matching_sections():
 
1080
            yield (name, parser[name], self.config_id())
742
1081
 
743
1082
    def _get_option_policy(self, section, option_name):
744
1083
        """Return the policy for the given (section, option_name) pair."""
824
1163
                               self._get_branch_data_config,
825
1164
                               self._get_global_config)
826
1165
 
 
1166
    def config_id(self):
 
1167
        return 'branch'
 
1168
 
827
1169
    def _get_branch_data_config(self):
828
1170
        if self._branch_data_config is None:
829
1171
            self._branch_data_config = TreeConfig(self.branch)
 
1172
            self._branch_data_config.config_id = self.config_id
830
1173
        return self._branch_data_config
831
1174
 
832
1175
    def _get_location_config(self):
900
1243
                return value
901
1244
        return None
902
1245
 
 
1246
    def _get_sections(self, name=None):
 
1247
        """See IniBasedConfig.get_sections()."""
 
1248
        for source in self.option_sources:
 
1249
            for section in source()._get_sections(name):
 
1250
                yield section
 
1251
 
 
1252
    def _get_options(self, sections=None):
 
1253
        opts = []
 
1254
        # First the locations options
 
1255
        for option in self._get_location_config()._get_options():
 
1256
            yield option
 
1257
        # Then the branch options
 
1258
        branch_config = self._get_branch_data_config()
 
1259
        if sections is None:
 
1260
            sections = [('DEFAULT', branch_config._get_parser())]
 
1261
        # FIXME: We shouldn't have to duplicate the code in IniBasedConfig but
 
1262
        # Config itself has no notion of sections :( -- vila 20101001
 
1263
        config_id = self.config_id()
 
1264
        for (section_name, section) in sections:
 
1265
            for (name, value) in section.iteritems():
 
1266
                yield (name, value, section_name,
 
1267
                       config_id, branch_config._get_parser())
 
1268
        # Then the global options
 
1269
        for option in self._get_global_config()._get_options():
 
1270
            yield option
 
1271
 
903
1272
    def set_user_option(self, name, value, store=STORE_BRANCH,
904
1273
        warn_masked=False):
905
1274
        if store == STORE_BRANCH:
923
1292
                        trace.warning('Value "%s" is masked by "%s" from'
924
1293
                                      ' branch.conf', value, mask_value)
925
1294
 
 
1295
    def remove_user_option(self, option_name, section_name=None):
 
1296
        self._get_branch_data_config().remove_option(option_name, section_name)
 
1297
 
926
1298
    def _gpg_signing_command(self):
927
1299
        """See Config.gpg_signing_command."""
928
1300
        return self._get_safe_value('_gpg_signing_command')
962
1334
            parent_dir = os.path.dirname(path)
963
1335
            if not os.path.isdir(parent_dir):
964
1336
                trace.mutter('creating config parent directory: %r', parent_dir)
965
 
            os.mkdir(parent_dir)
 
1337
                os.mkdir(parent_dir)
966
1338
        trace.mutter('creating config directory: %r', path)
967
1339
        os.mkdir(path)
968
1340
        osutils.copy_ownership_from_path(path)
971
1343
def config_dir():
972
1344
    """Return per-user configuration directory.
973
1345
 
974
 
    By default this is ~/.bazaar/
 
1346
    By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
 
1347
    and Linux.  On Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
 
1348
    that will be used instead.
975
1349
 
976
1350
    TODO: Global option --config-dir to override this.
977
1351
    """
978
1352
    base = os.environ.get('BZR_HOME', None)
979
1353
    if sys.platform == 'win32':
 
1354
        # environ variables on Windows are in user encoding/mbcs. So decode
 
1355
        # before using one
 
1356
        if base is not None:
 
1357
            base = base.decode('mbcs')
980
1358
        if base is None:
981
1359
            base = win32utils.get_appdata_location_unicode()
982
1360
        if base is None:
983
1361
            base = os.environ.get('HOME', None)
 
1362
            if base is not None:
 
1363
                base = base.decode('mbcs')
984
1364
        if base is None:
985
1365
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
986
1366
                                  ' or HOME set')
987
1367
        return osutils.pathjoin(base, 'bazaar', '2.0')
 
1368
    elif sys.platform == 'darwin':
 
1369
        if base is None:
 
1370
            # this takes into account $HOME
 
1371
            base = os.path.expanduser("~")
 
1372
        return osutils.pathjoin(base, '.bazaar')
988
1373
    else:
989
1374
        if base is None:
 
1375
 
 
1376
            xdg_dir = os.environ.get('XDG_CONFIG_HOME', None)
 
1377
            if xdg_dir is None:
 
1378
                xdg_dir = osutils.pathjoin(os.path.expanduser("~"), ".config")
 
1379
            xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
 
1380
            if osutils.isdir(xdg_dir):
 
1381
                trace.mutter(
 
1382
                    "Using configuration in XDG directory %s." % xdg_dir)
 
1383
                return xdg_dir
 
1384
 
990
1385
            base = os.path.expanduser("~")
991
1386
        return osutils.pathjoin(base, ".bazaar")
992
1387
 
1038
1433
        return os.path.expanduser('~/.cache')
1039
1434
 
1040
1435
 
 
1436
def _get_default_mail_domain():
 
1437
    """If possible, return the assumed default email domain.
 
1438
 
 
1439
    :returns: string mail domain, or None.
 
1440
    """
 
1441
    if sys.platform == 'win32':
 
1442
        # No implementation yet; patches welcome
 
1443
        return None
 
1444
    try:
 
1445
        f = open('/etc/mailname')
 
1446
    except (IOError, OSError), e:
 
1447
        return None
 
1448
    try:
 
1449
        domain = f.read().strip()
 
1450
        return domain
 
1451
    finally:
 
1452
        f.close()
 
1453
 
 
1454
 
 
1455
def _auto_user_id():
 
1456
    """Calculate automatic user identification.
 
1457
 
 
1458
    :returns: (realname, email), either of which may be None if they can't be
 
1459
    determined.
 
1460
 
 
1461
    Only used when none is set in the environment or the id file.
 
1462
 
 
1463
    This only returns an email address if we can be fairly sure the 
 
1464
    address is reasonable, ie if /etc/mailname is set on unix.
 
1465
 
 
1466
    This doesn't use the FQDN as the default domain because that may be 
 
1467
    slow, and it doesn't use the hostname alone because that's not normally 
 
1468
    a reasonable address.
 
1469
    """
 
1470
    if sys.platform == 'win32':
 
1471
        # No implementation to reliably determine Windows default mail
 
1472
        # address; please add one.
 
1473
        return None, None
 
1474
 
 
1475
    default_mail_domain = _get_default_mail_domain()
 
1476
    if not default_mail_domain:
 
1477
        return None, None
 
1478
 
 
1479
    import pwd
 
1480
    uid = os.getuid()
 
1481
    try:
 
1482
        w = pwd.getpwuid(uid)
 
1483
    except KeyError:
 
1484
        mutter('no passwd entry for uid %d?' % uid)
 
1485
        return None, None
 
1486
 
 
1487
    # we try utf-8 first, because on many variants (like Linux),
 
1488
    # /etc/passwd "should" be in utf-8, and because it's unlikely to give
 
1489
    # false positives.  (many users will have their user encoding set to
 
1490
    # latin-1, which cannot raise UnicodeError.)
 
1491
    try:
 
1492
        gecos = w.pw_gecos.decode('utf-8')
 
1493
        encoding = 'utf-8'
 
1494
    except UnicodeError:
 
1495
        try:
 
1496
            encoding = osutils.get_user_encoding()
 
1497
            gecos = w.pw_gecos.decode(encoding)
 
1498
        except UnicodeError, e:
 
1499
            mutter("cannot decode passwd entry %s" % w)
 
1500
            return None, None
 
1501
    try:
 
1502
        username = w.pw_name.decode(encoding)
 
1503
    except UnicodeError, e:
 
1504
        mutter("cannot decode passwd entry %s" % w)
 
1505
        return None, None
 
1506
 
 
1507
    comma = gecos.find(',')
 
1508
    if comma == -1:
 
1509
        realname = gecos
 
1510
    else:
 
1511
        realname = gecos[:comma]
 
1512
 
 
1513
    return realname, (username + '@' + default_mail_domain)
 
1514
 
 
1515
 
1041
1516
def parse_username(username):
1042
1517
    """Parse e-mail username and return a (name, address) tuple."""
1043
1518
    match = re.match(r'(.*?)\s*<?([\w+.-]+@[\w+.-]+)>?', username)
1086
1561
 
1087
1562
    def set_option(self, value, name, section=None):
1088
1563
        """Set a per-branch configuration option"""
 
1564
        # FIXME: We shouldn't need to lock explicitly here but rather rely on
 
1565
        # higher levels providing the right lock -- vila 20101004
1089
1566
        self.branch.lock_write()
1090
1567
        try:
1091
1568
            self._config.set_option(value, name, section)
1092
1569
        finally:
1093
1570
            self.branch.unlock()
1094
1571
 
 
1572
    def remove_option(self, option_name, section_name=None):
 
1573
        # FIXME: We shouldn't need to lock explicitly here but rather rely on
 
1574
        # higher levels providing the right lock -- vila 20101004
 
1575
        self.branch.lock_write()
 
1576
        try:
 
1577
            self._config.remove_option(option_name, section_name)
 
1578
        finally:
 
1579
            self.branch.unlock()
 
1580
 
1095
1581
 
1096
1582
class AuthenticationConfig(object):
1097
1583
    """The authentication configuration file based on a ini file.
1540
2026
    """A Config that reads/writes a config file on a Transport.
1541
2027
 
1542
2028
    It is a low-level object that considers config data to be name/value pairs
1543
 
    that may be associated with a section.  Assigning meaning to the these
1544
 
    values is done at higher levels like TreeConfig.
 
2029
    that may be associated with a section.  Assigning meaning to these values
 
2030
    is done at higher levels like TreeConfig.
1545
2031
    """
1546
2032
 
1547
2033
    def __init__(self, transport, filename):
1580
2066
            configobj.setdefault(section, {})[name] = value
1581
2067
        self._set_configobj(configobj)
1582
2068
 
 
2069
    def remove_option(self, option_name, section_name=None):
 
2070
        configobj = self._get_configobj()
 
2071
        if section_name is None:
 
2072
            del configobj[option_name]
 
2073
        else:
 
2074
            del configobj[section_name][option_name]
 
2075
        self._set_configobj(configobj)
 
2076
 
1583
2077
    def _get_config_file(self):
1584
2078
        try:
1585
2079
            return StringIO(self._transport.get_bytes(self._filename))
1598
2092
        configobj.write(out_file)
1599
2093
        out_file.seek(0)
1600
2094
        self._transport.put_file(self._filename, out_file)
 
2095
 
 
2096
 
 
2097
class Section(object):
 
2098
    """A section defines a dict of options.
 
2099
 
 
2100
    This is merely a read-only dict which can add some knowledge about the
 
2101
    options. It is *not* a python dict object though and doesn't try to mimic
 
2102
    its API.
 
2103
    """
 
2104
 
 
2105
    def __init__(self, section_id, options):
 
2106
        self.id = section_id
 
2107
        # We re-use the dict-like object received
 
2108
        self.options = options
 
2109
 
 
2110
    def get(self, name, default=None):
 
2111
        return self.options.get(name, default)
 
2112
 
 
2113
    def __repr__(self):
 
2114
        # Mostly for debugging use
 
2115
        return "<config.%s id=%s>" % (self.__class__.__name__, self.id)
 
2116
 
 
2117
 
 
2118
_NewlyCreatedOption = object()
 
2119
"""Was the option created during the MutableSection lifetime"""
 
2120
 
 
2121
 
 
2122
class MutableSection(Section):
 
2123
    """A section allowing changes and keeping track of the original values."""
 
2124
 
 
2125
    def __init__(self, section_id, options):
 
2126
        super(MutableSection, self).__init__(section_id, options)
 
2127
        self.orig = {}
 
2128
 
 
2129
    def set(self, name, value):
 
2130
        if name not in self.options:
 
2131
            # This is a new option
 
2132
            self.orig[name] = _NewlyCreatedOption
 
2133
        elif name not in self.orig:
 
2134
            self.orig[name] = self.get(name, None)
 
2135
        self.options[name] = value
 
2136
 
 
2137
    def remove(self, name):
 
2138
        if name not in self.orig:
 
2139
            self.orig[name] = self.get(name, None)
 
2140
        del self.options[name]
 
2141
 
 
2142
 
 
2143
class Store(object):
 
2144
    """Abstract interface to persistent storage for configuration options."""
 
2145
 
 
2146
    readonly_section_class = Section
 
2147
    mutable_section_class = MutableSection
 
2148
 
 
2149
    def is_loaded(self):
 
2150
        """Returns True if the Store has been loaded.
 
2151
 
 
2152
        This is used to implement lazy loading and ensure the persistent
 
2153
        storage is queried only when needed.
 
2154
        """
 
2155
        raise NotImplementedError(self.is_loaded)
 
2156
 
 
2157
    def load(self):
 
2158
        """Loads the Store from persistent storage."""
 
2159
        raise NotImplementedError(self.load)
 
2160
 
 
2161
    def _load_from_string(self, str_or_unicode):
 
2162
        """Create a store from a string in configobj syntax.
 
2163
 
 
2164
        :param str_or_unicode: A string representing the file content. This will
 
2165
            be encoded to suit store needs internally.
 
2166
 
 
2167
        This is for tests and should not be used in production unless a
 
2168
        convincing use case can be demonstrated :)
 
2169
        """
 
2170
        raise NotImplementedError(self._load_from_string)
 
2171
 
 
2172
    def save(self):
 
2173
        """Saves the Store to persistent storage."""
 
2174
        raise NotImplementedError(self.save)
 
2175
 
 
2176
    def external_url(self):
 
2177
        raise NotImplementedError(self.external_url)
 
2178
 
 
2179
    def get_sections(self):
 
2180
        """Returns an ordered iterable of existing sections.
 
2181
 
 
2182
        :returns: An iterable of (name, dict).
 
2183
        """
 
2184
        raise NotImplementedError(self.get_sections)
 
2185
 
 
2186
    def get_mutable_section(self, section_name=None):
 
2187
        """Returns the specified mutable section.
 
2188
 
 
2189
        :param section_name: The section identifier
 
2190
        """
 
2191
        raise NotImplementedError(self.get_mutable_section)
 
2192
 
 
2193
    def __repr__(self):
 
2194
        # Mostly for debugging use
 
2195
        return "<config.%s(%s)>" % (self.__class__.__name__,
 
2196
                                    self.external_url())
 
2197
 
 
2198
 
 
2199
class IniFileStore(Store):
 
2200
    """A config Store using ConfigObj for storage.
 
2201
 
 
2202
    :ivar transport: The transport object where the config file is located.
 
2203
 
 
2204
    :ivar file_name: The config file basename in the transport directory.
 
2205
 
 
2206
    :ivar _config_obj: Private member to hold the ConfigObj instance used to
 
2207
        serialize/deserialize the config file.
 
2208
    """
 
2209
 
 
2210
    def __init__(self, transport, file_name):
 
2211
        """A config Store using ConfigObj for storage.
 
2212
 
 
2213
        :param transport: The transport object where the config file is located.
 
2214
 
 
2215
        :param file_name: The config file basename in the transport directory.
 
2216
        """
 
2217
        super(IniFileStore, self).__init__()
 
2218
        self.transport = transport
 
2219
        self.file_name = file_name
 
2220
        self._config_obj = None
 
2221
 
 
2222
    def is_loaded(self):
 
2223
        return self._config_obj != None
 
2224
 
 
2225
    def load(self):
 
2226
        """Load the store from the associated file."""
 
2227
        if self.is_loaded():
 
2228
            return
 
2229
        content = self.transport.get_bytes(self.file_name)
 
2230
        self._load_from_string(content)
 
2231
 
 
2232
    def _load_from_string(self, str_or_unicode):
 
2233
        """Create a config store from a string.
 
2234
 
 
2235
        :param str_or_unicode: A string representing the file content. This will
 
2236
            be utf-8 encoded internally.
 
2237
 
 
2238
        This is for tests and should not be used in production unless a
 
2239
        convincing use case can be demonstrated :)
 
2240
        """
 
2241
        if self.is_loaded():
 
2242
            raise AssertionError('Already loaded: %r' % (self._config_obj,))
 
2243
        co_input = StringIO(str_or_unicode.encode('utf-8'))
 
2244
        try:
 
2245
            # The config files are always stored utf8-encoded
 
2246
            self._config_obj = ConfigObj(co_input, encoding='utf-8')
 
2247
        except configobj.ConfigObjError, e:
 
2248
            self._config_obj = None
 
2249
            raise errors.ParseConfigError(e.errors, self.external_url())
 
2250
 
 
2251
    def save(self):
 
2252
        if not self.is_loaded():
 
2253
            # Nothing to save
 
2254
            return
 
2255
        out = StringIO()
 
2256
        self._config_obj.write(out)
 
2257
        self.transport.put_bytes(self.file_name, out.getvalue())
 
2258
 
 
2259
    def external_url(self):
 
2260
        # FIXME: external_url should really accepts an optional relpath
 
2261
        # parameter (bug #750169) :-/ -- vila 2011-04-04
 
2262
        # The following will do in the interim but maybe we don't want to
 
2263
        # expose a path here but rather a config ID and its associated
 
2264
        # object </hand wawe>.
 
2265
        return urlutils.join(self.transport.external_url(), self.file_name)
 
2266
 
 
2267
    def get_sections(self):
 
2268
        """Get the configobj section in the file order.
 
2269
 
 
2270
        :returns: An iterable of (name, dict).
 
2271
        """
 
2272
        # We need a loaded store
 
2273
        self.load()
 
2274
        cobj = self._config_obj
 
2275
        if cobj.scalars:
 
2276
            yield self.readonly_section_class(None, cobj)
 
2277
        for section_name in cobj.sections:
 
2278
            yield self.readonly_section_class(section_name, cobj[section_name])
 
2279
 
 
2280
    def get_mutable_section(self, section_name=None):
 
2281
        # We need a loaded store
 
2282
        try:
 
2283
            self.load()
 
2284
        except errors.NoSuchFile:
 
2285
            # The file doesn't exist, let's pretend it was empty
 
2286
            self._load_from_string('')
 
2287
        if section_name is None:
 
2288
            section = self._config_obj
 
2289
        else:
 
2290
            section = self._config_obj.setdefault(section_name, {})
 
2291
        return self.mutable_section_class(section_name, section)
 
2292
 
 
2293
 
 
2294
# Note that LockableConfigObjStore inherits from ConfigObjStore because we need
 
2295
# unlockable stores for use with objects that can already ensure the locking
 
2296
# (think branches). If different stores (not based on ConfigObj) are created,
 
2297
# they may face the same issue.
 
2298
 
 
2299
 
 
2300
class LockableIniFileStore(IniFileStore):
 
2301
    """A ConfigObjStore using locks on save to ensure store integrity."""
 
2302
 
 
2303
    def __init__(self, transport, file_name, lock_dir_name=None):
 
2304
        """A config Store using ConfigObj for storage.
 
2305
 
 
2306
        :param transport: The transport object where the config file is located.
 
2307
 
 
2308
        :param file_name: The config file basename in the transport directory.
 
2309
        """
 
2310
        if lock_dir_name is None:
 
2311
            lock_dir_name = 'lock'
 
2312
        self.lock_dir_name = lock_dir_name
 
2313
        super(LockableIniFileStore, self).__init__(transport, file_name)
 
2314
        self._lock = lockdir.LockDir(self.transport, self.lock_dir_name)
 
2315
 
 
2316
    def lock_write(self, token=None):
 
2317
        """Takes a write lock in the directory containing the config file.
 
2318
 
 
2319
        If the directory doesn't exist it is created.
 
2320
        """
 
2321
        # FIXME: This doesn't check the ownership of the created directories as
 
2322
        # ensure_config_dir_exists does. It should if the transport is local
 
2323
        # -- vila 2011-04-06
 
2324
        self.transport.create_prefix()
 
2325
        return self._lock.lock_write(token)
 
2326
 
 
2327
    def unlock(self):
 
2328
        self._lock.unlock()
 
2329
 
 
2330
    def break_lock(self):
 
2331
        self._lock.break_lock()
 
2332
 
 
2333
    @needs_write_lock
 
2334
    def save(self):
 
2335
        super(LockableIniFileStore, self).save()
 
2336
 
 
2337
 
 
2338
# FIXME: global, bazaar, shouldn't that be 'user' instead or even
 
2339
# 'user_defaults' as opposed to 'user_overrides', 'system_defaults'
 
2340
# (/etc/bzr/bazaar.conf) and 'system_overrides' ? -- vila 2011-04-05
 
2341
 
 
2342
# FIXME: Moreover, we shouldn't need classes for these stores either, factory
 
2343
# functions or a registry will make it easier and clearer for tests, focusing
 
2344
# on the relevant parts of the API that needs testing -- vila 20110503 (based
 
2345
# on a poolie's remark)
 
2346
class GlobalStore(LockableIniFileStore):
 
2347
 
 
2348
    def __init__(self, possible_transports=None):
 
2349
        t = transport.get_transport(config_dir(),
 
2350
                                    possible_transports=possible_transports)
 
2351
        super(GlobalStore, self).__init__(t, 'bazaar.conf')
 
2352
 
 
2353
 
 
2354
class LocationStore(LockableIniFileStore):
 
2355
 
 
2356
    def __init__(self, possible_transports=None):
 
2357
        t = transport.get_transport(config_dir(),
 
2358
                                    possible_transports=possible_transports)
 
2359
        super(LocationStore, self).__init__(t, 'locations.conf')
 
2360
 
 
2361
 
 
2362
class BranchStore(IniFileStore):
 
2363
 
 
2364
    def __init__(self, branch):
 
2365
        super(BranchStore, self).__init__(branch.control_transport,
 
2366
                                          'branch.conf')
 
2367
 
 
2368
class SectionMatcher(object):
 
2369
    """Select sections into a given Store.
 
2370
 
 
2371
    This intended to be used to postpone getting an iterable of sections from a
 
2372
    store.
 
2373
    """
 
2374
 
 
2375
    def __init__(self, store):
 
2376
        self.store = store
 
2377
 
 
2378
    def get_sections(self):
 
2379
        # This is where we require loading the store so we can see all defined
 
2380
        # sections.
 
2381
        sections = self.store.get_sections()
 
2382
        # Walk the revisions in the order provided
 
2383
        for s in sections:
 
2384
            if self.match(s):
 
2385
                yield s
 
2386
 
 
2387
    def match(self, secion):
 
2388
        raise NotImplementedError(self.match)
 
2389
 
 
2390
 
 
2391
class LocationSection(Section):
 
2392
 
 
2393
    def __init__(self, section, length, extra_path):
 
2394
        super(LocationSection, self).__init__(section.id, section.options)
 
2395
        self.length = length
 
2396
        self.extra_path = extra_path
 
2397
 
 
2398
    def get(self, name, default=None):
 
2399
        value = super(LocationSection, self).get(name, default)
 
2400
        if value is not None:
 
2401
            policy_name = self.get(name + ':policy', None)
 
2402
            policy = _policy_value.get(policy_name, POLICY_NONE)
 
2403
            if policy == POLICY_APPENDPATH:
 
2404
                value = urlutils.join(value, self.extra_path)
 
2405
        return value
 
2406
 
 
2407
 
 
2408
class LocationMatcher(SectionMatcher):
 
2409
 
 
2410
    def __init__(self, store, location):
 
2411
        super(LocationMatcher, self).__init__(store)
 
2412
        self.location = location
 
2413
 
 
2414
    def get_sections(self):
 
2415
        # Override the default implementation as we want to change the order
 
2416
 
 
2417
        # The following is a bit hackish but ensures compatibility with
 
2418
        # LocationConfig by reusing the same code
 
2419
        sections = list(self.store.get_sections())
 
2420
        filtered_sections = _iter_for_location_by_parts(
 
2421
            [s.id for s in sections], self.location)
 
2422
        iter_sections = iter(sections)
 
2423
        matching_sections = []
 
2424
        for section_id, extra_path, length in filtered_sections:
 
2425
            # a section id is unique for a given store so it's safe to iterate
 
2426
            # again
 
2427
            section = iter_sections.next()
 
2428
            if section_id == section.id:
 
2429
                matching_sections.append(
 
2430
                    LocationSection(section, length, extra_path))
 
2431
        # We want the longest (aka more specific) locations first
 
2432
        sections = sorted(matching_sections,
 
2433
                          key=lambda section: (section.length, section.id),
 
2434
                          reverse=True)
 
2435
        # Sections mentioning 'ignore_parents' restrict the selection
 
2436
        for section in sections:
 
2437
            # FIXME: We really want to use as_bool below -- vila 2011-04-07
 
2438
            ignore = section.get('ignore_parents', None)
 
2439
            if ignore is not None:
 
2440
                ignore = ui.bool_from_string(ignore)
 
2441
            if ignore:
 
2442
                break
 
2443
            # Finally, we have a valid section
 
2444
            yield section
 
2445
 
 
2446
 
 
2447
class Stack(object):
 
2448
    """A stack of configurations where an option can be defined"""
 
2449
 
 
2450
    def __init__(self, sections_def, store=None, mutable_section_name=None):
 
2451
        """Creates a stack of sections with an optional store for changes.
 
2452
 
 
2453
        :param sections_def: A list of Section or callables that returns an
 
2454
            iterable of Section. This defines the Sections for the Stack and
 
2455
            can be called repeatedly if needed.
 
2456
 
 
2457
        :param store: The optional Store where modifications will be
 
2458
            recorded. If none is specified, no modifications can be done.
 
2459
 
 
2460
        :param mutable_section_name: The name of the MutableSection where
 
2461
            changes are recorded. This requires the ``store`` parameter to be
 
2462
            specified.
 
2463
        """
 
2464
        self.sections_def = sections_def
 
2465
        self.store = store
 
2466
        self.mutable_section_name = mutable_section_name
 
2467
 
 
2468
    def get(self, name):
 
2469
        """Return the *first* option value found in the sections.
 
2470
 
 
2471
        This is where we guarantee that sections coming from Store are loaded
 
2472
        lazily: the loading is delayed until we need to either check that an
 
2473
        option exists or get its value, which in turn may require to discover
 
2474
        in which sections it can be defined. Both of these (section and option
 
2475
        existence) require loading the store (even partially).
 
2476
        """
 
2477
        # FIXME: No caching of options nor sections yet -- vila 20110503
 
2478
 
 
2479
        # Ensuring lazy loading is achieved by delaying section matching until
 
2480
        # it can be avoided anymore by using callables to describe (possibly
 
2481
        # empty) section lists.
 
2482
        for section_or_callable in self.sections_def:
 
2483
            # Each section can expand to multiple ones when a callable is used
 
2484
            if callable(section_or_callable):
 
2485
                sections = section_or_callable()
 
2486
            else:
 
2487
                sections = [section_or_callable]
 
2488
            for section in sections:
 
2489
                value = section.get(name)
 
2490
                if value is not None:
 
2491
                    return value
 
2492
        # No definition was found
 
2493
        return None
 
2494
 
 
2495
    def _get_mutable_section(self):
 
2496
        """Get the MutableSection for the Stack.
 
2497
 
 
2498
        This is where we guarantee that the mutable section is lazily loaded:
 
2499
        this means we won't load the corresponding store before setting a value
 
2500
        or deleting an option. In practice the store will often be loaded but
 
2501
        this allows catching some programming errors.
 
2502
        """
 
2503
        section = self.store.get_mutable_section(self.mutable_section_name)
 
2504
        return section
 
2505
 
 
2506
    def set(self, name, value):
 
2507
        """Set a new value for the option."""
 
2508
        section = self._get_mutable_section()
 
2509
        section.set(name, value)
 
2510
 
 
2511
    def remove(self, name):
 
2512
        """Remove an existing option."""
 
2513
        section = self._get_mutable_section()
 
2514
        section.remove(name)
 
2515
 
 
2516
    def __repr__(self):
 
2517
        # Mostly for debugging use
 
2518
        return "<config.%s(%s)>" % (self.__class__.__name__, id(self))
 
2519
 
 
2520
 
 
2521
class cmd_config(commands.Command):
 
2522
    __doc__ = """Display, set or remove a configuration option.
 
2523
 
 
2524
    Display the active value for a given option.
 
2525
 
 
2526
    If --all is specified, NAME is interpreted as a regular expression and all
 
2527
    matching options are displayed mentioning their scope. The active value
 
2528
    that bzr will take into account is the first one displayed for each option.
 
2529
 
 
2530
    If no NAME is given, --all .* is implied.
 
2531
 
 
2532
    Setting a value is achieved by using name=value without spaces. The value
 
2533
    is set in the most relevant scope and can be checked by displaying the
 
2534
    option again.
 
2535
    """
 
2536
 
 
2537
    takes_args = ['name?']
 
2538
 
 
2539
    takes_options = [
 
2540
        'directory',
 
2541
        # FIXME: This should be a registry option so that plugins can register
 
2542
        # their own config files (or not) -- vila 20101002
 
2543
        commands.Option('scope', help='Reduce the scope to the specified'
 
2544
                        ' configuration file',
 
2545
                        type=unicode),
 
2546
        commands.Option('all',
 
2547
            help='Display all the defined values for the matching options.',
 
2548
            ),
 
2549
        commands.Option('remove', help='Remove the option from'
 
2550
                        ' the configuration file'),
 
2551
        ]
 
2552
 
 
2553
    @commands.display_command
 
2554
    def run(self, name=None, all=False, directory=None, scope=None,
 
2555
            remove=False):
 
2556
        if directory is None:
 
2557
            directory = '.'
 
2558
        directory = urlutils.normalize_url(directory)
 
2559
        if remove and all:
 
2560
            raise errors.BzrError(
 
2561
                '--all and --remove are mutually exclusive.')
 
2562
        elif remove:
 
2563
            # Delete the option in the given scope
 
2564
            self._remove_config_option(name, directory, scope)
 
2565
        elif name is None:
 
2566
            # Defaults to all options
 
2567
            self._show_matching_options('.*', directory, scope)
 
2568
        else:
 
2569
            try:
 
2570
                name, value = name.split('=', 1)
 
2571
            except ValueError:
 
2572
                # Display the option(s) value(s)
 
2573
                if all:
 
2574
                    self._show_matching_options(name, directory, scope)
 
2575
                else:
 
2576
                    self._show_value(name, directory, scope)
 
2577
            else:
 
2578
                if all:
 
2579
                    raise errors.BzrError(
 
2580
                        'Only one option can be set.')
 
2581
                # Set the option value
 
2582
                self._set_config_option(name, value, directory, scope)
 
2583
 
 
2584
    def _get_configs(self, directory, scope=None):
 
2585
        """Iterate the configurations specified by ``directory`` and ``scope``.
 
2586
 
 
2587
        :param directory: Where the configurations are derived from.
 
2588
 
 
2589
        :param scope: A specific config to start from.
 
2590
        """
 
2591
        if scope is not None:
 
2592
            if scope == 'bazaar':
 
2593
                yield GlobalConfig()
 
2594
            elif scope == 'locations':
 
2595
                yield LocationConfig(directory)
 
2596
            elif scope == 'branch':
 
2597
                (_, br, _) = bzrdir.BzrDir.open_containing_tree_or_branch(
 
2598
                    directory)
 
2599
                yield br.get_config()
 
2600
        else:
 
2601
            try:
 
2602
                (_, br, _) = bzrdir.BzrDir.open_containing_tree_or_branch(
 
2603
                    directory)
 
2604
                yield br.get_config()
 
2605
            except errors.NotBranchError:
 
2606
                yield LocationConfig(directory)
 
2607
                yield GlobalConfig()
 
2608
 
 
2609
    def _show_value(self, name, directory, scope):
 
2610
        displayed = False
 
2611
        for c in self._get_configs(directory, scope):
 
2612
            if displayed:
 
2613
                break
 
2614
            for (oname, value, section, conf_id, parser) in c._get_options():
 
2615
                if name == oname:
 
2616
                    # Display only the first value and exit
 
2617
 
 
2618
                    # FIXME: We need to use get_user_option to take policies
 
2619
                    # into account and we need to make sure the option exists
 
2620
                    # too (hence the two for loops), this needs a better API
 
2621
                    # -- vila 20101117
 
2622
                    value = c.get_user_option(name)
 
2623
                    # Quote the value appropriately
 
2624
                    value = parser._quote(value)
 
2625
                    self.outf.write('%s\n' % (value,))
 
2626
                    displayed = True
 
2627
                    break
 
2628
        if not displayed:
 
2629
            raise errors.NoSuchConfigOption(name)
 
2630
 
 
2631
    def _show_matching_options(self, name, directory, scope):
 
2632
        name = re.compile(name)
 
2633
        # We want any error in the regexp to be raised *now* so we need to
 
2634
        # avoid the delay introduced by the lazy regexp.
 
2635
        name._compile_and_collapse()
 
2636
        cur_conf_id = None
 
2637
        cur_section = None
 
2638
        for c in self._get_configs(directory, scope):
 
2639
            for (oname, value, section, conf_id, parser) in c._get_options():
 
2640
                if name.search(oname):
 
2641
                    if cur_conf_id != conf_id:
 
2642
                        # Explain where the options are defined
 
2643
                        self.outf.write('%s:\n' % (conf_id,))
 
2644
                        cur_conf_id = conf_id
 
2645
                        cur_section = None
 
2646
                    if (section not in (None, 'DEFAULT')
 
2647
                        and cur_section != section):
 
2648
                        # Display the section if it's not the default (or only)
 
2649
                        # one.
 
2650
                        self.outf.write('  [%s]\n' % (section,))
 
2651
                        cur_section = section
 
2652
                    self.outf.write('  %s = %s\n' % (oname, value))
 
2653
 
 
2654
    def _set_config_option(self, name, value, directory, scope):
 
2655
        for conf in self._get_configs(directory, scope):
 
2656
            conf.set_user_option(name, value)
 
2657
            break
 
2658
        else:
 
2659
            raise errors.NoSuchConfig(scope)
 
2660
 
 
2661
    def _remove_config_option(self, name, directory, scope):
 
2662
        if name is None:
 
2663
            raise errors.BzrCommandError(
 
2664
                '--remove expects an option to remove.')
 
2665
        removed = False
 
2666
        for conf in self._get_configs(directory, scope):
 
2667
            for (section_name, section, conf_id) in conf._get_sections():
 
2668
                if scope is not None and conf_id != scope:
 
2669
                    # Not the right configuration file
 
2670
                    continue
 
2671
                if name in section:
 
2672
                    if conf_id != conf.config_id():
 
2673
                        conf = self._get_configs(directory, conf_id).next()
 
2674
                    # We use the first section in the first config where the
 
2675
                    # option is defined to remove it
 
2676
                    conf.remove_user_option(name, section_name)
 
2677
                    removed = True
 
2678
                    break
 
2679
            break
 
2680
        else:
 
2681
            raise errors.NoSuchConfig(scope)
 
2682
        if not removed:
 
2683
            raise errors.NoSuchConfigOption(name)