/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Florian Dorn
  • Date: 2012-04-03 14:49:22 UTC
  • mto: This revision was merged to the branch mainline in revision 6546.
  • Revision ID: florian.dorn@boku.ac.at-20120403144922-b8y59csy8l1rzs5u
updated developer docs

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
 
68
import base64
67
69
 
 
70
from bzrlib import commands
 
71
from bzrlib.decorators import needs_write_lock
68
72
from bzrlib.lazy_import import lazy_import
69
73
lazy_import(globals(), """
70
 
import errno
71
 
from fnmatch import fnmatch
 
74
import fnmatch
72
75
import re
73
76
from cStringIO import StringIO
74
77
 
75
78
import bzrlib
76
79
from bzrlib import (
 
80
    atomicfile,
 
81
    bzrdir,
77
82
    debug,
78
83
    errors,
 
84
    lockdir,
79
85
    mail_client,
 
86
    mergetools,
80
87
    osutils,
81
88
    registry,
82
89
    symbol_versioning,
83
90
    trace,
 
91
    transport,
84
92
    ui,
85
93
    urlutils,
86
94
    win32utils,
122
130
STORE_BRANCH = 3
123
131
STORE_GLOBAL = 4
124
132
 
125
 
_ConfigObj = None
126
 
def ConfigObj(*args, **kwargs):
127
 
    global _ConfigObj
128
 
    if _ConfigObj is None:
129
 
        class ConfigObj(configobj.ConfigObj):
130
 
 
131
 
            def get_bool(self, section, key):
132
 
                return self[section].as_bool(key)
133
 
 
134
 
            def get_value(self, section, name):
135
 
                # Try [] for the old DEFAULT section.
136
 
                if section == "DEFAULT":
137
 
                    try:
138
 
                        return self[name]
139
 
                    except KeyError:
140
 
                        pass
141
 
                return self[section][name]
142
 
        _ConfigObj = ConfigObj
143
 
    return _ConfigObj(*args, **kwargs)
 
133
 
 
134
class ConfigObj(configobj.ConfigObj):
 
135
 
 
136
    def __init__(self, infile=None, **kwargs):
 
137
        # We define our own interpolation mechanism calling it option expansion
 
138
        super(ConfigObj, self).__init__(infile=infile,
 
139
                                        interpolation=False,
 
140
                                        **kwargs)
 
141
 
 
142
 
 
143
    def get_bool(self, section, key):
 
144
        return self[section].as_bool(key)
 
145
 
 
146
    def get_value(self, section, name):
 
147
        # Try [] for the old DEFAULT section.
 
148
        if section == "DEFAULT":
 
149
            try:
 
150
                return self[name]
 
151
            except KeyError:
 
152
                pass
 
153
        return self[section][name]
 
154
 
 
155
 
 
156
# FIXME: Until we can guarantee that each config file is loaded once and and
 
157
# only once for a given bzrlib session, we don't want to re-read the file every
 
158
# time we query for an option so we cache the value (bad ! watch out for tests
 
159
# needing to restore the proper value).This shouldn't be part of 2.4.0 final,
 
160
# yell at mgz^W vila and the RM if this is still present at that time
 
161
# -- vila 20110219
 
162
_expand_default_value = None
 
163
def _get_expand_default_value():
 
164
    global _expand_default_value
 
165
    if _expand_default_value is not None:
 
166
        return _expand_default_value
 
167
    conf = GlobalConfig()
 
168
    # Note that we must not use None for the expand value below or we'll run
 
169
    # into infinite recursion. Using False really would be quite silly ;)
 
170
    expand = conf.get_user_option_as_bool('bzr.config.expand', expand=True)
 
171
    if expand is None:
 
172
        # This is an opt-in feature, you *really* need to clearly say you want
 
173
        # to activate it !
 
174
        expand = False
 
175
    _expand_default_value = expand
 
176
    return expand
144
177
 
145
178
 
146
179
class Config(object):
149
182
    def __init__(self):
150
183
        super(Config, self).__init__()
151
184
 
 
185
    def config_id(self):
 
186
        """Returns a unique ID for the config."""
 
187
        raise NotImplementedError(self.config_id)
 
188
 
152
189
    def get_editor(self):
153
190
        """Get the users pop up editor."""
154
191
        raise NotImplementedError
178
215
    def _get_signing_policy(self):
179
216
        """Template method to override signature creation policy."""
180
217
 
 
218
    option_ref_re = None
 
219
 
 
220
    def expand_options(self, string, env=None):
 
221
        """Expand option references in the string in the configuration context.
 
222
 
 
223
        :param string: The string containing option to expand.
 
224
 
 
225
        :param env: An option dict defining additional configuration options or
 
226
            overriding existing ones.
 
227
 
 
228
        :returns: The expanded string.
 
229
        """
 
230
        return self._expand_options_in_string(string, env)
 
231
 
 
232
    def _expand_options_in_list(self, slist, env=None, _ref_stack=None):
 
233
        """Expand options in  a list of strings in the configuration context.
 
234
 
 
235
        :param slist: A list of strings.
 
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
            expanded to detect loops.
 
242
 
 
243
        :returns: The flatten list of expanded strings.
 
244
        """
 
245
        # expand options in each value separately flattening lists
 
246
        result = []
 
247
        for s in slist:
 
248
            value = self._expand_options_in_string(s, env, _ref_stack)
 
249
            if isinstance(value, list):
 
250
                result.extend(value)
 
251
            else:
 
252
                result.append(value)
 
253
        return result
 
254
 
 
255
    def _expand_options_in_string(self, string, env=None, _ref_stack=None):
 
256
        """Expand options in the string in the configuration context.
 
257
 
 
258
        :param string: The string to be expanded.
 
259
 
 
260
        :param env: An option dict defining additional configuration options or
 
261
            overriding existing ones.
 
262
 
 
263
        :param _ref_stack: Private list containing the options being
 
264
            expanded to detect loops.
 
265
 
 
266
        :returns: The expanded string.
 
267
        """
 
268
        if string is None:
 
269
            # Not much to expand there
 
270
            return None
 
271
        if _ref_stack is None:
 
272
            # What references are currently resolved (to detect loops)
 
273
            _ref_stack = []
 
274
        if self.option_ref_re is None:
 
275
            # We want to match the most embedded reference first (i.e. for
 
276
            # '{{foo}}' we will get '{foo}',
 
277
            # for '{bar{baz}}' we will get '{baz}'
 
278
            self.option_ref_re = re.compile('({[^{}]+})')
 
279
        result = string
 
280
        # We need to iterate until no more refs appear ({{foo}} will need two
 
281
        # iterations for example).
 
282
        while True:
 
283
            raw_chunks = self.option_ref_re.split(result)
 
284
            if len(raw_chunks) == 1:
 
285
                # Shorcut the trivial case: no refs
 
286
                return result
 
287
            chunks = []
 
288
            list_value = False
 
289
            # Split will isolate refs so that every other chunk is a ref
 
290
            chunk_is_ref = False
 
291
            for chunk in raw_chunks:
 
292
                if not chunk_is_ref:
 
293
                    if chunk:
 
294
                        # Keep only non-empty strings (or we get bogus empty
 
295
                        # slots when a list value is involved).
 
296
                        chunks.append(chunk)
 
297
                    chunk_is_ref = True
 
298
                else:
 
299
                    name = chunk[1:-1]
 
300
                    if name in _ref_stack:
 
301
                        raise errors.OptionExpansionLoop(string, _ref_stack)
 
302
                    _ref_stack.append(name)
 
303
                    value = self._expand_option(name, env, _ref_stack)
 
304
                    if value is None:
 
305
                        raise errors.ExpandingUnknownOption(name, string)
 
306
                    if isinstance(value, list):
 
307
                        list_value = True
 
308
                        chunks.extend(value)
 
309
                    else:
 
310
                        chunks.append(value)
 
311
                    _ref_stack.pop()
 
312
                    chunk_is_ref = False
 
313
            if list_value:
 
314
                # Once a list appears as the result of an expansion, all
 
315
                # callers will get a list result. This allows a consistent
 
316
                # behavior even when some options in the expansion chain
 
317
                # defined as strings (no comma in their value) but their
 
318
                # expanded value is a list.
 
319
                return self._expand_options_in_list(chunks, env, _ref_stack)
 
320
            else:
 
321
                result = ''.join(chunks)
 
322
        return result
 
323
 
 
324
    def _expand_option(self, name, env, _ref_stack):
 
325
        if env is not None and name in env:
 
326
            # Special case, values provided in env takes precedence over
 
327
            # anything else
 
328
            value = env[name]
 
329
        else:
 
330
            # FIXME: This is a limited implementation, what we really need is a
 
331
            # way to query the bzr config for the value of an option,
 
332
            # respecting the scope rules (That is, once we implement fallback
 
333
            # configs, getting the option value should restart from the top
 
334
            # config, not the current one) -- vila 20101222
 
335
            value = self.get_user_option(name, expand=False)
 
336
            if isinstance(value, list):
 
337
                value = self._expand_options_in_list(value, env, _ref_stack)
 
338
            else:
 
339
                value = self._expand_options_in_string(value, env, _ref_stack)
 
340
        return value
 
341
 
181
342
    def _get_user_option(self, option_name):
182
343
        """Template method to provide a user option."""
183
344
        return None
184
345
 
185
 
    def get_user_option(self, option_name):
186
 
        """Get a generic option - no special process, no default."""
187
 
        return self._get_user_option(option_name)
188
 
 
189
 
    def get_user_option_as_bool(self, option_name):
 
346
    def get_user_option(self, option_name, expand=None):
 
347
        """Get a generic option - no special process, no default.
 
348
 
 
349
        :param option_name: The queried option.
 
350
 
 
351
        :param expand: Whether options references should be expanded.
 
352
 
 
353
        :returns: The value of the option.
 
354
        """
 
355
        if expand is None:
 
356
            expand = _get_expand_default_value()
 
357
        value = self._get_user_option(option_name)
 
358
        if expand:
 
359
            if isinstance(value, list):
 
360
                value = self._expand_options_in_list(value)
 
361
            elif isinstance(value, dict):
 
362
                trace.warning('Cannot expand "%s":'
 
363
                              ' Dicts do not support option expansion'
 
364
                              % (option_name,))
 
365
            else:
 
366
                value = self._expand_options_in_string(value)
 
367
        return value
 
368
 
 
369
    def get_user_option_as_bool(self, option_name, expand=None):
190
370
        """Get a generic option as a boolean - no special process, no default.
191
371
 
192
372
        :return None if the option doesn't exist or its value can't be
193
373
            interpreted as a boolean. Returns True or False otherwise.
194
374
        """
195
 
        s = self._get_user_option(option_name)
 
375
        s = self.get_user_option(option_name, expand=expand)
196
376
        if s is None:
197
377
            # The option doesn't exist
198
378
            return None
203
383
                          s, option_name)
204
384
        return val
205
385
 
206
 
    def get_user_option_as_list(self, option_name):
 
386
    def get_user_option_as_list(self, option_name, expand=None):
207
387
        """Get a generic option as a list - no special process, no default.
208
388
 
209
389
        :return None if the option doesn't exist. Returns the value as a list
210
390
            otherwise.
211
391
        """
212
 
        l = self._get_user_option(option_name)
 
392
        l = self.get_user_option(option_name, expand=expand)
213
393
        if isinstance(l, (str, unicode)):
214
 
            # A single value, most probably the user forgot the final ','
 
394
            # A single value, most probably the user forgot (or didn't care to
 
395
            # add) the final ','
215
396
            l = [l]
216
397
        return l
217
398
 
257
438
 
258
439
        Something similar to 'Martin Pool <mbp@sourcefrog.net>'
259
440
 
260
 
        $BZR_EMAIL can be set to override this (as well as the
261
 
        deprecated $BZREMAIL), then
 
441
        $BZR_EMAIL can be set to override this, then
262
442
        the concrete policy type is checked, and finally
263
443
        $EMAIL is examined.
264
 
        If none is found, a reasonable default is (hopefully)
265
 
        created.
266
 
 
267
 
        TODO: Check it's reasonably well-formed.
 
444
        If no username can be found, errors.NoWhoami exception is raised.
268
445
        """
269
446
        v = os.environ.get('BZR_EMAIL')
270
447
        if v:
271
448
            return v.decode(osutils.get_user_encoding())
272
 
 
273
449
        v = self._get_user_id()
274
450
        if v:
275
451
            return v
276
 
 
277
452
        v = os.environ.get('EMAIL')
278
453
        if v:
279
454
            return v.decode(osutils.get_user_encoding())
280
 
 
281
455
        name, email = _auto_user_id()
282
 
        if name:
 
456
        if name and email:
283
457
            return '%s <%s>' % (name, email)
284
 
        else:
 
458
        elif email:
285
459
            return email
 
460
        raise errors.NoWhoami()
 
461
 
 
462
    def ensure_username(self):
 
463
        """Raise errors.NoWhoami if username is not set.
 
464
 
 
465
        This method relies on the username() function raising the error.
 
466
        """
 
467
        self.username()
286
468
 
287
469
    def signature_checking(self):
288
470
        """What is the current policy for signature checking?."""
346
528
        else:
347
529
            return True
348
530
 
 
531
    def get_merge_tools(self):
 
532
        tools = {}
 
533
        for (oname, value, section, conf_id, parser) in self._get_options():
 
534
            if oname.startswith('bzr.mergetool.'):
 
535
                tool_name = oname[len('bzr.mergetool.'):]
 
536
                tools[tool_name] = value
 
537
        trace.mutter('loaded merge tools: %r' % tools)
 
538
        return tools
 
539
 
 
540
    def find_merge_tool(self, name):
 
541
        # We fake a defaults mechanism here by checking if the given name can 
 
542
        # be found in the known_merge_tools if it's not found in the config.
 
543
        # This should be done through the proposed config defaults mechanism
 
544
        # when it becomes available in the future.
 
545
        command_line = (self.get_user_option('bzr.mergetool.%s' % name,
 
546
                                             expand=False)
 
547
                        or mergetools.known_merge_tools.get(name, None))
 
548
        return command_line
 
549
 
349
550
 
350
551
class IniBasedConfig(Config):
351
552
    """A configuration policy that draws from ini files."""
352
553
 
353
 
    def __init__(self, get_filename):
 
554
    def __init__(self, get_filename=symbol_versioning.DEPRECATED_PARAMETER,
 
555
                 file_name=None):
 
556
        """Base class for configuration files using an ini-like syntax.
 
557
 
 
558
        :param file_name: The configuration file path.
 
559
        """
354
560
        super(IniBasedConfig, self).__init__()
355
 
        self._get_filename = get_filename
 
561
        self.file_name = file_name
 
562
        if symbol_versioning.deprecated_passed(get_filename):
 
563
            symbol_versioning.warn(
 
564
                'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
 
565
                ' Use file_name instead.',
 
566
                DeprecationWarning,
 
567
                stacklevel=2)
 
568
            if get_filename is not None:
 
569
                self.file_name = get_filename()
 
570
        else:
 
571
            self.file_name = file_name
 
572
        self._content = None
356
573
        self._parser = None
357
574
 
358
 
    def _get_parser(self, file=None):
 
575
    @classmethod
 
576
    def from_string(cls, str_or_unicode, file_name=None, save=False):
 
577
        """Create a config object from a string.
 
578
 
 
579
        :param str_or_unicode: A string representing the file content. This will
 
580
            be utf-8 encoded.
 
581
 
 
582
        :param file_name: The configuration file path.
 
583
 
 
584
        :param _save: Whether the file should be saved upon creation.
 
585
        """
 
586
        conf = cls(file_name=file_name)
 
587
        conf._create_from_string(str_or_unicode, save)
 
588
        return conf
 
589
 
 
590
    def _create_from_string(self, str_or_unicode, save):
 
591
        self._content = StringIO(str_or_unicode.encode('utf-8'))
 
592
        # Some tests use in-memory configs, some other always need the config
 
593
        # file to exist on disk.
 
594
        if save:
 
595
            self._write_config_file()
 
596
 
 
597
    def _get_parser(self, file=symbol_versioning.DEPRECATED_PARAMETER):
359
598
        if self._parser is not None:
360
599
            return self._parser
361
 
        if file is None:
362
 
            input = self._get_filename()
 
600
        if symbol_versioning.deprecated_passed(file):
 
601
            symbol_versioning.warn(
 
602
                'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
 
603
                ' Use IniBasedConfig(_content=xxx) instead.',
 
604
                DeprecationWarning,
 
605
                stacklevel=2)
 
606
        if self._content is not None:
 
607
            co_input = self._content
 
608
        elif self.file_name is None:
 
609
            raise AssertionError('We have no content to create the config')
363
610
        else:
364
 
            input = file
 
611
            co_input = self.file_name
365
612
        try:
366
 
            self._parser = ConfigObj(input, encoding='utf-8')
 
613
            self._parser = ConfigObj(co_input, encoding='utf-8')
367
614
        except configobj.ConfigObjError, e:
368
615
            raise errors.ParseConfigError(e.errors, e.config.filename)
 
616
        # Make sure self.reload() will use the right file name
 
617
        self._parser.filename = self.file_name
369
618
        return self._parser
370
619
 
 
620
    def reload(self):
 
621
        """Reload the config file from disk."""
 
622
        if self.file_name is None:
 
623
            raise AssertionError('We need a file name to reload the config')
 
624
        if self._parser is not None:
 
625
            self._parser.reload()
 
626
 
371
627
    def _get_matching_sections(self):
372
628
        """Return an ordered list of (section_name, extra_path) pairs.
373
629
 
384
640
        """Override this to define the section used by the config."""
385
641
        return "DEFAULT"
386
642
 
 
643
    def _get_sections(self, name=None):
 
644
        """Returns an iterator of the sections specified by ``name``.
 
645
 
 
646
        :param name: The section name. If None is supplied, the default
 
647
            configurations are yielded.
 
648
 
 
649
        :return: A tuple (name, section, config_id) for all sections that will
 
650
            be walked by user_get_option() in the 'right' order. The first one
 
651
            is where set_user_option() will update the value.
 
652
        """
 
653
        parser = self._get_parser()
 
654
        if name is not None:
 
655
            yield (name, parser[name], self.config_id())
 
656
        else:
 
657
            # No section name has been given so we fallback to the configobj
 
658
            # itself which holds the variables defined outside of any section.
 
659
            yield (None, parser, self.config_id())
 
660
 
 
661
    def _get_options(self, sections=None):
 
662
        """Return an ordered list of (name, value, section, config_id) tuples.
 
663
 
 
664
        All options are returned with their associated value and the section
 
665
        they appeared in. ``config_id`` is a unique identifier for the
 
666
        configuration file the option is defined in.
 
667
 
 
668
        :param sections: Default to ``_get_matching_sections`` if not
 
669
            specified. This gives a better control to daughter classes about
 
670
            which sections should be searched. This is a list of (name,
 
671
            configobj) tuples.
 
672
        """
 
673
        opts = []
 
674
        if sections is None:
 
675
            parser = self._get_parser()
 
676
            sections = []
 
677
            for (section_name, _) in self._get_matching_sections():
 
678
                try:
 
679
                    section = parser[section_name]
 
680
                except KeyError:
 
681
                    # This could happen for an empty file for which we define a
 
682
                    # DEFAULT section. FIXME: Force callers to provide sections
 
683
                    # instead ? -- vila 20100930
 
684
                    continue
 
685
                sections.append((section_name, section))
 
686
        config_id = self.config_id()
 
687
        for (section_name, section) in sections:
 
688
            for (name, value) in section.iteritems():
 
689
                yield (name, parser._quote(value), section_name,
 
690
                       config_id, parser)
 
691
 
387
692
    def _get_option_policy(self, section, option_name):
388
693
        """Return the policy for the given (section, option_name) pair."""
389
694
        return POLICY_NONE
476
781
    def _get_nickname(self):
477
782
        return self.get_user_option('nickname')
478
783
 
479
 
 
480
 
class GlobalConfig(IniBasedConfig):
 
784
    def remove_user_option(self, option_name, section_name=None):
 
785
        """Remove a user option and save the configuration file.
 
786
 
 
787
        :param option_name: The option to be removed.
 
788
 
 
789
        :param section_name: The section the option is defined in, default to
 
790
            the default section.
 
791
        """
 
792
        self.reload()
 
793
        parser = self._get_parser()
 
794
        if section_name is None:
 
795
            section = parser
 
796
        else:
 
797
            section = parser[section_name]
 
798
        try:
 
799
            del section[option_name]
 
800
        except KeyError:
 
801
            raise errors.NoSuchConfigOption(option_name)
 
802
        self._write_config_file()
 
803
 
 
804
    def _write_config_file(self):
 
805
        if self.file_name is None:
 
806
            raise AssertionError('We cannot save, self.file_name is None')
 
807
        conf_dir = os.path.dirname(self.file_name)
 
808
        ensure_config_dir_exists(conf_dir)
 
809
        atomic_file = atomicfile.AtomicFile(self.file_name)
 
810
        self._get_parser().write(atomic_file)
 
811
        atomic_file.commit()
 
812
        atomic_file.close()
 
813
        osutils.copy_ownership_from_path(self.file_name)
 
814
 
 
815
 
 
816
class LockableConfig(IniBasedConfig):
 
817
    """A configuration needing explicit locking for access.
 
818
 
 
819
    If several processes try to write the config file, the accesses need to be
 
820
    serialized.
 
821
 
 
822
    Daughter classes should decorate all methods that update a config with the
 
823
    ``@needs_write_lock`` decorator (they call, directly or indirectly, the
 
824
    ``_write_config_file()`` method. These methods (typically ``set_option()``
 
825
    and variants must reload the config file from disk before calling
 
826
    ``_write_config_file()``), this can be achieved by calling the
 
827
    ``self.reload()`` method. Note that the lock scope should cover both the
 
828
    reading and the writing of the config file which is why the decorator can't
 
829
    be applied to ``_write_config_file()`` only.
 
830
 
 
831
    This should be enough to implement the following logic:
 
832
    - lock for exclusive write access,
 
833
    - reload the config file from disk,
 
834
    - set the new value
 
835
    - unlock
 
836
 
 
837
    This logic guarantees that a writer can update a value without erasing an
 
838
    update made by another writer.
 
839
    """
 
840
 
 
841
    lock_name = 'lock'
 
842
 
 
843
    def __init__(self, file_name):
 
844
        super(LockableConfig, self).__init__(file_name=file_name)
 
845
        self.dir = osutils.dirname(osutils.safe_unicode(self.file_name))
 
846
        # FIXME: It doesn't matter that we don't provide possible_transports
 
847
        # below since this is currently used only for local config files ;
 
848
        # local transports are not shared. But if/when we start using
 
849
        # LockableConfig for other kind of transports, we will need to reuse
 
850
        # whatever connection is already established -- vila 20100929
 
851
        self.transport = transport.get_transport(self.dir)
 
852
        self._lock = lockdir.LockDir(self.transport, self.lock_name)
 
853
 
 
854
    def _create_from_string(self, unicode_bytes, save):
 
855
        super(LockableConfig, self)._create_from_string(unicode_bytes, False)
 
856
        if save:
 
857
            # We need to handle the saving here (as opposed to IniBasedConfig)
 
858
            # to be able to lock
 
859
            self.lock_write()
 
860
            self._write_config_file()
 
861
            self.unlock()
 
862
 
 
863
    def lock_write(self, token=None):
 
864
        """Takes a write lock in the directory containing the config file.
 
865
 
 
866
        If the directory doesn't exist it is created.
 
867
        """
 
868
        ensure_config_dir_exists(self.dir)
 
869
        return self._lock.lock_write(token)
 
870
 
 
871
    def unlock(self):
 
872
        self._lock.unlock()
 
873
 
 
874
    def break_lock(self):
 
875
        self._lock.break_lock()
 
876
 
 
877
    @needs_write_lock
 
878
    def remove_user_option(self, option_name, section_name=None):
 
879
        super(LockableConfig, self).remove_user_option(option_name,
 
880
                                                       section_name)
 
881
 
 
882
    def _write_config_file(self):
 
883
        if self._lock is None or not self._lock.is_held:
 
884
            # NB: if the following exception is raised it probably means a
 
885
            # missing @needs_write_lock decorator on one of the callers.
 
886
            raise errors.ObjectNotLocked(self)
 
887
        super(LockableConfig, self)._write_config_file()
 
888
 
 
889
 
 
890
class GlobalConfig(LockableConfig):
481
891
    """The configuration that should be used for a specific location."""
482
892
 
 
893
    def __init__(self):
 
894
        super(GlobalConfig, self).__init__(file_name=config_filename())
 
895
 
 
896
    def config_id(self):
 
897
        return 'bazaar'
 
898
 
 
899
    @classmethod
 
900
    def from_string(cls, str_or_unicode, save=False):
 
901
        """Create a config object from a string.
 
902
 
 
903
        :param str_or_unicode: A string representing the file content. This
 
904
            will be utf-8 encoded.
 
905
 
 
906
        :param save: Whether the file should be saved upon creation.
 
907
        """
 
908
        conf = cls()
 
909
        conf._create_from_string(str_or_unicode, save)
 
910
        return conf
 
911
 
483
912
    def get_editor(self):
484
913
        return self._get_user_option('editor')
485
914
 
486
 
    def __init__(self):
487
 
        super(GlobalConfig, self).__init__(config_filename)
488
 
 
 
915
    @needs_write_lock
489
916
    def set_user_option(self, option, value):
490
917
        """Save option and its value in the configuration."""
491
918
        self._set_option(option, value, 'DEFAULT')
497
924
        else:
498
925
            return {}
499
926
 
 
927
    @needs_write_lock
500
928
    def set_alias(self, alias_name, alias_command):
501
929
        """Save the alias in the configuration."""
502
930
        self._set_option(alias_name, alias_command, 'ALIASES')
503
931
 
 
932
    @needs_write_lock
504
933
    def unset_alias(self, alias_name):
505
934
        """Unset an existing alias."""
 
935
        self.reload()
506
936
        aliases = self._get_parser().get('ALIASES')
507
937
        if not aliases or alias_name not in aliases:
508
938
            raise errors.NoSuchAlias(alias_name)
510
940
        self._write_config_file()
511
941
 
512
942
    def _set_option(self, option, value, section):
513
 
        # FIXME: RBC 20051029 This should refresh the parser and also take a
514
 
        # file lock on bazaar.conf.
515
 
        conf_dir = os.path.dirname(self._get_filename())
516
 
        ensure_config_dir_exists(conf_dir)
 
943
        self.reload()
517
944
        self._get_parser().setdefault(section, {})[option] = value
518
945
        self._write_config_file()
519
946
 
520
 
    def _write_config_file(self):
521
 
        path = self._get_filename()
522
 
        f = open(path, 'wb')
523
 
        osutils.copy_ownership_from_path(path)
524
 
        self._get_parser().write(f)
525
 
        f.close()
526
 
 
527
 
 
528
 
class LocationConfig(IniBasedConfig):
 
947
 
 
948
    def _get_sections(self, name=None):
 
949
        """See IniBasedConfig._get_sections()."""
 
950
        parser = self._get_parser()
 
951
        # We don't give access to options defined outside of any section, we
 
952
        # used the DEFAULT section by... default.
 
953
        if name in (None, 'DEFAULT'):
 
954
            # This could happen for an empty file where the DEFAULT section
 
955
            # doesn't exist yet. So we force DEFAULT when yielding
 
956
            name = 'DEFAULT'
 
957
            if 'DEFAULT' not in parser:
 
958
               parser['DEFAULT']= {}
 
959
        yield (name, parser[name], self.config_id())
 
960
 
 
961
    @needs_write_lock
 
962
    def remove_user_option(self, option_name, section_name=None):
 
963
        if section_name is None:
 
964
            # We need to force the default section.
 
965
            section_name = 'DEFAULT'
 
966
        # We need to avoid the LockableConfig implementation or we'll lock
 
967
        # twice
 
968
        super(LockableConfig, self).remove_user_option(option_name,
 
969
                                                       section_name)
 
970
 
 
971
def _iter_for_location_by_parts(sections, location):
 
972
    """Keep only the sessions matching the specified location.
 
973
 
 
974
    :param sections: An iterable of section names.
 
975
 
 
976
    :param location: An url or a local path to match against.
 
977
 
 
978
    :returns: An iterator of (section, extra_path, nb_parts) where nb is the
 
979
        number of path components in the section name, section is the section
 
980
        name and extra_path is the difference between location and the section
 
981
        name.
 
982
 
 
983
    ``location`` will always be a local path and never a 'file://' url but the
 
984
    section names themselves can be in either form.
 
985
    """
 
986
    location_parts = location.rstrip('/').split('/')
 
987
 
 
988
    for section in sections:
 
989
        # location is a local path if possible, so we need to convert 'file://'
 
990
        # urls in section names to local paths if necessary.
 
991
 
 
992
        # This also avoids having file:///path be a more exact
 
993
        # match than '/path'.
 
994
 
 
995
        # FIXME: This still raises an issue if a user defines both file:///path
 
996
        # *and* /path. Should we raise an error in this case -- vila 20110505
 
997
 
 
998
        if section.startswith('file://'):
 
999
            section_path = urlutils.local_path_from_url(section)
 
1000
        else:
 
1001
            section_path = section
 
1002
        section_parts = section_path.rstrip('/').split('/')
 
1003
 
 
1004
        matched = True
 
1005
        if len(section_parts) > len(location_parts):
 
1006
            # More path components in the section, they can't match
 
1007
            matched = False
 
1008
        else:
 
1009
            # Rely on zip truncating in length to the length of the shortest
 
1010
            # argument sequence.
 
1011
            names = zip(location_parts, section_parts)
 
1012
            for name in names:
 
1013
                if not fnmatch.fnmatch(name[0], name[1]):
 
1014
                    matched = False
 
1015
                    break
 
1016
        if not matched:
 
1017
            continue
 
1018
        # build the path difference between the section and the location
 
1019
        extra_path = '/'.join(location_parts[len(section_parts):])
 
1020
        yield section, extra_path, len(section_parts)
 
1021
 
 
1022
 
 
1023
class LocationConfig(LockableConfig):
529
1024
    """A configuration object that gives the policy for a location."""
530
1025
 
531
1026
    def __init__(self, location):
532
 
        name_generator = locations_config_filename
533
 
        if (not os.path.exists(name_generator()) and
534
 
                os.path.exists(branches_config_filename())):
535
 
            if sys.platform == 'win32':
536
 
                trace.warning('Please rename %s to %s'
537
 
                              % (branches_config_filename(),
538
 
                                 locations_config_filename()))
539
 
            else:
540
 
                trace.warning('Please rename ~/.bazaar/branches.conf'
541
 
                              ' to ~/.bazaar/locations.conf')
542
 
            name_generator = branches_config_filename
543
 
        super(LocationConfig, self).__init__(name_generator)
 
1027
        super(LocationConfig, self).__init__(
 
1028
            file_name=locations_config_filename())
544
1029
        # local file locations are looked up by local path, rather than
545
1030
        # by file url. This is because the config file is a user
546
1031
        # file, and we would rather not expose the user to file urls.
548
1033
            location = urlutils.local_path_from_url(location)
549
1034
        self.location = location
550
1035
 
 
1036
    def config_id(self):
 
1037
        return 'locations'
 
1038
 
 
1039
    @classmethod
 
1040
    def from_string(cls, str_or_unicode, location, save=False):
 
1041
        """Create a config object from a string.
 
1042
 
 
1043
        :param str_or_unicode: A string representing the file content. This will
 
1044
            be utf-8 encoded.
 
1045
 
 
1046
        :param location: The location url to filter the configuration.
 
1047
 
 
1048
        :param save: Whether the file should be saved upon creation.
 
1049
        """
 
1050
        conf = cls(location)
 
1051
        conf._create_from_string(str_or_unicode, save)
 
1052
        return conf
 
1053
 
551
1054
    def _get_matching_sections(self):
552
1055
        """Return an ordered list of section names matching this location."""
553
 
        sections = self._get_parser()
554
 
        location_names = self.location.split('/')
555
 
        if self.location.endswith('/'):
556
 
            del location_names[-1]
557
 
        matches=[]
558
 
        for section in sections:
559
 
            # location is a local path if possible, so we need
560
 
            # to convert 'file://' urls to local paths if necessary.
561
 
            # This also avoids having file:///path be a more exact
562
 
            # match than '/path'.
563
 
            if section.startswith('file://'):
564
 
                section_path = urlutils.local_path_from_url(section)
565
 
            else:
566
 
                section_path = section
567
 
            section_names = section_path.split('/')
568
 
            if section.endswith('/'):
569
 
                del section_names[-1]
570
 
            names = zip(location_names, section_names)
571
 
            matched = True
572
 
            for name in names:
573
 
                if not fnmatch(name[0], name[1]):
574
 
                    matched = False
575
 
                    break
576
 
            if not matched:
577
 
                continue
578
 
            # so, for the common prefix they matched.
579
 
            # if section is longer, no match.
580
 
            if len(section_names) > len(location_names):
581
 
                continue
582
 
            matches.append((len(section_names), section,
583
 
                            '/'.join(location_names[len(section_names):])))
584
 
        matches.sort(reverse=True)
585
 
        sections = []
586
 
        for (length, section, extra_path) in matches:
587
 
            sections.append((section, extra_path))
 
1056
        matches = list(_iter_for_location_by_parts(self._get_parser(),
 
1057
                                                   self.location))
 
1058
        # put the longest (aka more specific) locations first
 
1059
        matches.sort(
 
1060
            key=lambda (section, extra_path, length): (length, section),
 
1061
            reverse=True)
 
1062
        for (section, extra_path, length) in matches:
 
1063
            yield section, extra_path
588
1064
            # should we stop looking for parent configs here?
589
1065
            try:
590
1066
                if self._get_parser()[section].as_bool('ignore_parents'):
591
1067
                    break
592
1068
            except KeyError:
593
1069
                pass
594
 
        return sections
 
1070
 
 
1071
    def _get_sections(self, name=None):
 
1072
        """See IniBasedConfig._get_sections()."""
 
1073
        # We ignore the name here as the only sections handled are named with
 
1074
        # the location path and we don't expose embedded sections either.
 
1075
        parser = self._get_parser()
 
1076
        for name, extra_path in self._get_matching_sections():
 
1077
            yield (name, parser[name], self.config_id())
595
1078
 
596
1079
    def _get_option_policy(self, section, option_name):
597
1080
        """Return the policy for the given (section, option_name) pair."""
641
1124
            if policy_key in self._get_parser()[section]:
642
1125
                del self._get_parser()[section][policy_key]
643
1126
 
 
1127
    @needs_write_lock
644
1128
    def set_user_option(self, option, value, store=STORE_LOCATION):
645
1129
        """Save option and its value in the configuration."""
646
1130
        if store not in [STORE_LOCATION,
648
1132
                         STORE_LOCATION_APPENDPATH]:
649
1133
            raise ValueError('bad storage policy %r for %r' %
650
1134
                (store, option))
651
 
        # FIXME: RBC 20051029 This should refresh the parser and also take a
652
 
        # file lock on locations.conf.
653
 
        conf_dir = os.path.dirname(self._get_filename())
654
 
        ensure_config_dir_exists(conf_dir)
 
1135
        self.reload()
655
1136
        location = self.location
656
1137
        if location.endswith('/'):
657
1138
            location = location[:-1]
658
 
        if (not location in self._get_parser() and
659
 
            not location + '/' in self._get_parser()):
660
 
            self._get_parser()[location]={}
661
 
        elif location + '/' in self._get_parser():
 
1139
        parser = self._get_parser()
 
1140
        if not location in parser and not location + '/' in parser:
 
1141
            parser[location] = {}
 
1142
        elif location + '/' in parser:
662
1143
            location = location + '/'
663
 
        self._get_parser()[location][option]=value
 
1144
        parser[location][option]=value
664
1145
        # the allowed values of store match the config policies
665
1146
        self._set_option_policy(location, option, store)
666
 
        self._get_parser().write(file(self._get_filename(), 'wb'))
 
1147
        self._write_config_file()
667
1148
 
668
1149
 
669
1150
class BranchConfig(Config):
670
1151
    """A configuration object giving the policy for a branch."""
671
1152
 
 
1153
    def __init__(self, branch):
 
1154
        super(BranchConfig, self).__init__()
 
1155
        self._location_config = None
 
1156
        self._branch_data_config = None
 
1157
        self._global_config = None
 
1158
        self.branch = branch
 
1159
        self.option_sources = (self._get_location_config,
 
1160
                               self._get_branch_data_config,
 
1161
                               self._get_global_config)
 
1162
 
 
1163
    def config_id(self):
 
1164
        return 'branch'
 
1165
 
672
1166
    def _get_branch_data_config(self):
673
1167
        if self._branch_data_config is None:
674
1168
            self._branch_data_config = TreeConfig(self.branch)
 
1169
            self._branch_data_config.config_id = self.config_id
675
1170
        return self._branch_data_config
676
1171
 
677
1172
    def _get_location_config(self):
745
1240
                return value
746
1241
        return None
747
1242
 
 
1243
    def _get_sections(self, name=None):
 
1244
        """See IniBasedConfig.get_sections()."""
 
1245
        for source in self.option_sources:
 
1246
            for section in source()._get_sections(name):
 
1247
                yield section
 
1248
 
 
1249
    def _get_options(self, sections=None):
 
1250
        opts = []
 
1251
        # First the locations options
 
1252
        for option in self._get_location_config()._get_options():
 
1253
            yield option
 
1254
        # Then the branch options
 
1255
        branch_config = self._get_branch_data_config()
 
1256
        if sections is None:
 
1257
            sections = [('DEFAULT', branch_config._get_parser())]
 
1258
        # FIXME: We shouldn't have to duplicate the code in IniBasedConfig but
 
1259
        # Config itself has no notion of sections :( -- vila 20101001
 
1260
        config_id = self.config_id()
 
1261
        for (section_name, section) in sections:
 
1262
            for (name, value) in section.iteritems():
 
1263
                yield (name, value, section_name,
 
1264
                       config_id, branch_config._get_parser())
 
1265
        # Then the global options
 
1266
        for option in self._get_global_config()._get_options():
 
1267
            yield option
 
1268
 
748
1269
    def set_user_option(self, name, value, store=STORE_BRANCH,
749
1270
        warn_masked=False):
750
1271
        if store == STORE_BRANCH:
768
1289
                        trace.warning('Value "%s" is masked by "%s" from'
769
1290
                                      ' branch.conf', value, mask_value)
770
1291
 
 
1292
    def remove_user_option(self, option_name, section_name=None):
 
1293
        self._get_branch_data_config().remove_option(option_name, section_name)
 
1294
 
771
1295
    def _gpg_signing_command(self):
772
1296
        """See Config.gpg_signing_command."""
773
1297
        return self._get_safe_value('_gpg_signing_command')
774
1298
 
775
 
    def __init__(self, branch):
776
 
        super(BranchConfig, self).__init__()
777
 
        self._location_config = None
778
 
        self._branch_data_config = None
779
 
        self._global_config = None
780
 
        self.branch = branch
781
 
        self.option_sources = (self._get_location_config,
782
 
                               self._get_branch_data_config,
783
 
                               self._get_global_config)
784
 
 
785
1299
    def _post_commit(self):
786
1300
        """See Config.post_commit."""
787
1301
        return self._get_safe_value('_post_commit')
817
1331
            parent_dir = os.path.dirname(path)
818
1332
            if not os.path.isdir(parent_dir):
819
1333
                trace.mutter('creating config parent directory: %r', parent_dir)
820
 
            os.mkdir(parent_dir)
 
1334
                os.mkdir(parent_dir)
821
1335
        trace.mutter('creating config directory: %r', path)
822
1336
        os.mkdir(path)
823
1337
        osutils.copy_ownership_from_path(path)
826
1340
def config_dir():
827
1341
    """Return per-user configuration directory.
828
1342
 
829
 
    By default this is ~/.bazaar/
 
1343
    By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
 
1344
    and Linux.  On Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
 
1345
    that will be used instead.
830
1346
 
831
1347
    TODO: Global option --config-dir to override this.
832
1348
    """
833
1349
    base = os.environ.get('BZR_HOME', None)
834
1350
    if sys.platform == 'win32':
 
1351
        # environ variables on Windows are in user encoding/mbcs. So decode
 
1352
        # before using one
 
1353
        if base is not None:
 
1354
            base = base.decode('mbcs')
835
1355
        if base is None:
836
1356
            base = win32utils.get_appdata_location_unicode()
837
1357
        if base is None:
838
1358
            base = os.environ.get('HOME', None)
 
1359
            if base is not None:
 
1360
                base = base.decode('mbcs')
839
1361
        if base is None:
840
1362
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
841
1363
                                  ' or HOME set')
842
1364
        return osutils.pathjoin(base, 'bazaar', '2.0')
 
1365
    elif sys.platform == 'darwin':
 
1366
        if base is None:
 
1367
            # this takes into account $HOME
 
1368
            base = os.path.expanduser("~")
 
1369
        return osutils.pathjoin(base, '.bazaar')
843
1370
    else:
844
 
        # cygwin, linux, and darwin all have a $HOME directory
845
1371
        if base is None:
 
1372
 
 
1373
            xdg_dir = os.environ.get('XDG_CONFIG_HOME', None)
 
1374
            if xdg_dir is None:
 
1375
                xdg_dir = osutils.pathjoin(os.path.expanduser("~"), ".config")
 
1376
            xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
 
1377
            if osutils.isdir(xdg_dir):
 
1378
                trace.mutter(
 
1379
                    "Using configuration in XDG directory %s." % xdg_dir)
 
1380
                return xdg_dir
 
1381
 
846
1382
            base = os.path.expanduser("~")
847
1383
        return osutils.pathjoin(base, ".bazaar")
848
1384
 
852
1388
    return osutils.pathjoin(config_dir(), 'bazaar.conf')
853
1389
 
854
1390
 
855
 
def branches_config_filename():
856
 
    """Return per-user configuration ini file filename."""
857
 
    return osutils.pathjoin(config_dir(), 'branches.conf')
858
 
 
859
 
 
860
1391
def locations_config_filename():
861
1392
    """Return per-user configuration ini file filename."""
862
1393
    return osutils.pathjoin(config_dir(), 'locations.conf')
899
1430
        return os.path.expanduser('~/.cache')
900
1431
 
901
1432
 
 
1433
def _get_default_mail_domain():
 
1434
    """If possible, return the assumed default email domain.
 
1435
 
 
1436
    :returns: string mail domain, or None.
 
1437
    """
 
1438
    if sys.platform == 'win32':
 
1439
        # No implementation yet; patches welcome
 
1440
        return None
 
1441
    try:
 
1442
        f = open('/etc/mailname')
 
1443
    except (IOError, OSError), e:
 
1444
        return None
 
1445
    try:
 
1446
        domain = f.read().strip()
 
1447
        return domain
 
1448
    finally:
 
1449
        f.close()
 
1450
 
 
1451
 
902
1452
def _auto_user_id():
903
1453
    """Calculate automatic user identification.
904
1454
 
905
 
    Returns (realname, email).
 
1455
    :returns: (realname, email), either of which may be None if they can't be
 
1456
    determined.
906
1457
 
907
1458
    Only used when none is set in the environment or the id file.
908
1459
 
909
 
    This previously used the FQDN as the default domain, but that can
910
 
    be very slow on machines where DNS is broken.  So now we simply
911
 
    use the hostname.
 
1460
    This only returns an email address if we can be fairly sure the 
 
1461
    address is reasonable, ie if /etc/mailname is set on unix.
 
1462
 
 
1463
    This doesn't use the FQDN as the default domain because that may be 
 
1464
    slow, and it doesn't use the hostname alone because that's not normally 
 
1465
    a reasonable address.
912
1466
    """
913
 
    import socket
914
 
 
915
1467
    if sys.platform == 'win32':
916
 
        name = win32utils.get_user_name_unicode()
917
 
        if name is None:
918
 
            raise errors.BzrError("Cannot autodetect user name.\n"
919
 
                                  "Please, set your name with command like:\n"
920
 
                                  'bzr whoami "Your Name <name@domain.com>"')
921
 
        host = win32utils.get_host_name_unicode()
922
 
        if host is None:
923
 
            host = socket.gethostname()
924
 
        return name, (name + '@' + host)
925
 
 
926
 
    try:
927
 
        import pwd
928
 
        uid = os.getuid()
929
 
        try:
930
 
            w = pwd.getpwuid(uid)
931
 
        except KeyError:
932
 
            raise errors.BzrCommandError('Unable to determine your name.  '
933
 
                'Please use "bzr whoami" to set it.')
934
 
 
935
 
        # we try utf-8 first, because on many variants (like Linux),
936
 
        # /etc/passwd "should" be in utf-8, and because it's unlikely to give
937
 
        # false positives.  (many users will have their user encoding set to
938
 
        # latin-1, which cannot raise UnicodeError.)
939
 
        try:
940
 
            gecos = w.pw_gecos.decode('utf-8')
941
 
            encoding = 'utf-8'
942
 
        except UnicodeError:
943
 
            try:
944
 
                encoding = osutils.get_user_encoding()
945
 
                gecos = w.pw_gecos.decode(encoding)
946
 
            except UnicodeError:
947
 
                raise errors.BzrCommandError('Unable to determine your name.  '
948
 
                   'Use "bzr whoami" to set it.')
949
 
        try:
950
 
            username = w.pw_name.decode(encoding)
951
 
        except UnicodeError:
952
 
            raise errors.BzrCommandError('Unable to determine your name.  '
953
 
                'Use "bzr whoami" to set it.')
954
 
 
955
 
        comma = gecos.find(',')
956
 
        if comma == -1:
957
 
            realname = gecos
958
 
        else:
959
 
            realname = gecos[:comma]
960
 
        if not realname:
961
 
            realname = username
962
 
 
963
 
    except ImportError:
964
 
        import getpass
965
 
        try:
966
 
            user_encoding = osutils.get_user_encoding()
967
 
            realname = username = getpass.getuser().decode(user_encoding)
968
 
        except UnicodeDecodeError:
969
 
            raise errors.BzrError("Can't decode username as %s." % \
970
 
                    user_encoding)
971
 
 
972
 
    return realname, (username + '@' + socket.gethostname())
 
1468
        # No implementation to reliably determine Windows default mail
 
1469
        # address; please add one.
 
1470
        return None, None
 
1471
 
 
1472
    default_mail_domain = _get_default_mail_domain()
 
1473
    if not default_mail_domain:
 
1474
        return None, None
 
1475
 
 
1476
    import pwd
 
1477
    uid = os.getuid()
 
1478
    try:
 
1479
        w = pwd.getpwuid(uid)
 
1480
    except KeyError:
 
1481
        mutter('no passwd entry for uid %d?' % uid)
 
1482
        return None, None
 
1483
 
 
1484
    # we try utf-8 first, because on many variants (like Linux),
 
1485
    # /etc/passwd "should" be in utf-8, and because it's unlikely to give
 
1486
    # false positives.  (many users will have their user encoding set to
 
1487
    # latin-1, which cannot raise UnicodeError.)
 
1488
    try:
 
1489
        gecos = w.pw_gecos.decode('utf-8')
 
1490
        encoding = 'utf-8'
 
1491
    except UnicodeError:
 
1492
        try:
 
1493
            encoding = osutils.get_user_encoding()
 
1494
            gecos = w.pw_gecos.decode(encoding)
 
1495
        except UnicodeError, e:
 
1496
            mutter("cannot decode passwd entry %s" % w)
 
1497
            return None, None
 
1498
    try:
 
1499
        username = w.pw_name.decode(encoding)
 
1500
    except UnicodeError, e:
 
1501
        mutter("cannot decode passwd entry %s" % w)
 
1502
        return None, None
 
1503
 
 
1504
    comma = gecos.find(',')
 
1505
    if comma == -1:
 
1506
        realname = gecos
 
1507
    else:
 
1508
        realname = gecos[:comma]
 
1509
 
 
1510
    return realname, (username + '@' + default_mail_domain)
973
1511
 
974
1512
 
975
1513
def parse_username(username):
1020
1558
 
1021
1559
    def set_option(self, value, name, section=None):
1022
1560
        """Set a per-branch configuration option"""
 
1561
        # FIXME: We shouldn't need to lock explicitly here but rather rely on
 
1562
        # higher levels providing the right lock -- vila 20101004
1023
1563
        self.branch.lock_write()
1024
1564
        try:
1025
1565
            self._config.set_option(value, name, section)
1026
1566
        finally:
1027
1567
            self.branch.unlock()
1028
1568
 
 
1569
    def remove_option(self, option_name, section_name=None):
 
1570
        # FIXME: We shouldn't need to lock explicitly here but rather rely on
 
1571
        # higher levels providing the right lock -- vila 20101004
 
1572
        self.branch.lock_write()
 
1573
        try:
 
1574
            self._config.remove_option(option_name, section_name)
 
1575
        finally:
 
1576
            self.branch.unlock()
 
1577
 
1029
1578
 
1030
1579
class AuthenticationConfig(object):
1031
1580
    """The authentication configuration file based on a ini file.
1063
1612
        """Save the config file, only tests should use it for now."""
1064
1613
        conf_dir = os.path.dirname(self._filename)
1065
1614
        ensure_config_dir_exists(conf_dir)
1066
 
        self._get_config().write(file(self._filename, 'wb'))
 
1615
        f = file(self._filename, 'wb')
 
1616
        try:
 
1617
            self._get_config().write(f)
 
1618
        finally:
 
1619
            f.close()
1067
1620
 
1068
1621
    def _set_option(self, section_name, option_name, value):
1069
1622
        """Set an authentication configuration option"""
1428
1981
                                   help=PlainTextCredentialStore.__doc__)
1429
1982
credential_store_registry.default_key = 'plain'
1430
1983
 
 
1984
class Base64CredentialStore(CredentialStore):
 
1985
    __doc__ = """Base64 credential store for the authentication.conf file"""
 
1986
    
 
1987
    def decode_password(self, credentials):
 
1988
        """See CredentialStore.decode_password."""
 
1989
        return base64.decodestring(credentials['password'])
 
1990
 
 
1991
credential_store_registry.register('base64', Base64CredentialStore,
 
1992
                                   help=Base64CredentialStore.__doc__)
1431
1993
 
1432
1994
class BzrDirConfig(object):
1433
1995
 
1470
2032
    """A Config that reads/writes a config file on a Transport.
1471
2033
 
1472
2034
    It is a low-level object that considers config data to be name/value pairs
1473
 
    that may be associated with a section.  Assigning meaning to the these
1474
 
    values is done at higher levels like TreeConfig.
 
2035
    that may be associated with a section.  Assigning meaning to these values
 
2036
    is done at higher levels like TreeConfig.
1475
2037
    """
1476
2038
 
1477
2039
    def __init__(self, transport, filename):
1510
2072
            configobj.setdefault(section, {})[name] = value
1511
2073
        self._set_configobj(configobj)
1512
2074
 
 
2075
    def remove_option(self, option_name, section_name=None):
 
2076
        configobj = self._get_configobj()
 
2077
        if section_name is None:
 
2078
            del configobj[option_name]
 
2079
        else:
 
2080
            del configobj[section_name][option_name]
 
2081
        self._set_configobj(configobj)
 
2082
 
1513
2083
    def _get_config_file(self):
1514
2084
        try:
1515
2085
            return StringIO(self._transport.get_bytes(self._filename))
1517
2087
            return StringIO()
1518
2088
 
1519
2089
    def _get_configobj(self):
1520
 
        return ConfigObj(self._get_config_file(), encoding='utf-8')
 
2090
        f = self._get_config_file()
 
2091
        try:
 
2092
            return ConfigObj(f, encoding='utf-8')
 
2093
        finally:
 
2094
            f.close()
1521
2095
 
1522
2096
    def _set_configobj(self, configobj):
1523
2097
        out_file = StringIO()
1524
2098
        configobj.write(out_file)
1525
2099
        out_file.seek(0)
1526
2100
        self._transport.put_file(self._filename, out_file)
 
2101
 
 
2102
 
 
2103
class Section(object):
 
2104
    """A section defines a dict of options.
 
2105
 
 
2106
    This is merely a read-only dict which can add some knowledge about the
 
2107
    options. It is *not* a python dict object though and doesn't try to mimic
 
2108
    its API.
 
2109
    """
 
2110
 
 
2111
    def __init__(self, section_id, options):
 
2112
        self.id = section_id
 
2113
        # We re-use the dict-like object received
 
2114
        self.options = options
 
2115
 
 
2116
    def get(self, name, default=None):
 
2117
        return self.options.get(name, default)
 
2118
 
 
2119
    def __repr__(self):
 
2120
        # Mostly for debugging use
 
2121
        return "<config.%s id=%s>" % (self.__class__.__name__, self.id)
 
2122
 
 
2123
 
 
2124
_NewlyCreatedOption = object()
 
2125
"""Was the option created during the MutableSection lifetime"""
 
2126
 
 
2127
 
 
2128
class MutableSection(Section):
 
2129
    """A section allowing changes and keeping track of the original values."""
 
2130
 
 
2131
    def __init__(self, section_id, options):
 
2132
        super(MutableSection, self).__init__(section_id, options)
 
2133
        self.orig = {}
 
2134
 
 
2135
    def set(self, name, value):
 
2136
        if name not in self.options:
 
2137
            # This is a new option
 
2138
            self.orig[name] = _NewlyCreatedOption
 
2139
        elif name not in self.orig:
 
2140
            self.orig[name] = self.get(name, None)
 
2141
        self.options[name] = value
 
2142
 
 
2143
    def remove(self, name):
 
2144
        if name not in self.orig:
 
2145
            self.orig[name] = self.get(name, None)
 
2146
        del self.options[name]
 
2147
 
 
2148
 
 
2149
class Store(object):
 
2150
    """Abstract interface to persistent storage for configuration options."""
 
2151
 
 
2152
    readonly_section_class = Section
 
2153
    mutable_section_class = MutableSection
 
2154
 
 
2155
    def is_loaded(self):
 
2156
        """Returns True if the Store has been loaded.
 
2157
 
 
2158
        This is used to implement lazy loading and ensure the persistent
 
2159
        storage is queried only when needed.
 
2160
        """
 
2161
        raise NotImplementedError(self.is_loaded)
 
2162
 
 
2163
    def load(self):
 
2164
        """Loads the Store from persistent storage."""
 
2165
        raise NotImplementedError(self.load)
 
2166
 
 
2167
    def _load_from_string(self, str_or_unicode):
 
2168
        """Create a store from a string in configobj syntax.
 
2169
 
 
2170
        :param str_or_unicode: A string representing the file content. This will
 
2171
            be encoded to suit store needs internally.
 
2172
 
 
2173
        This is for tests and should not be used in production unless a
 
2174
        convincing use case can be demonstrated :)
 
2175
        """
 
2176
        raise NotImplementedError(self._load_from_string)
 
2177
 
 
2178
    def save(self):
 
2179
        """Saves the Store to persistent storage."""
 
2180
        raise NotImplementedError(self.save)
 
2181
 
 
2182
    def external_url(self):
 
2183
        raise NotImplementedError(self.external_url)
 
2184
 
 
2185
    def get_sections(self):
 
2186
        """Returns an ordered iterable of existing sections.
 
2187
 
 
2188
        :returns: An iterable of (name, dict).
 
2189
        """
 
2190
        raise NotImplementedError(self.get_sections)
 
2191
 
 
2192
    def get_mutable_section(self, section_name=None):
 
2193
        """Returns the specified mutable section.
 
2194
 
 
2195
        :param section_name: The section identifier
 
2196
        """
 
2197
        raise NotImplementedError(self.get_mutable_section)
 
2198
 
 
2199
    def __repr__(self):
 
2200
        # Mostly for debugging use
 
2201
        return "<config.%s(%s)>" % (self.__class__.__name__,
 
2202
                                    self.external_url())
 
2203
 
 
2204
 
 
2205
class IniFileStore(Store):
 
2206
    """A config Store using ConfigObj for storage.
 
2207
 
 
2208
    :ivar transport: The transport object where the config file is located.
 
2209
 
 
2210
    :ivar file_name: The config file basename in the transport directory.
 
2211
 
 
2212
    :ivar _config_obj: Private member to hold the ConfigObj instance used to
 
2213
        serialize/deserialize the config file.
 
2214
    """
 
2215
 
 
2216
    def __init__(self, transport, file_name):
 
2217
        """A config Store using ConfigObj for storage.
 
2218
 
 
2219
        :param transport: The transport object where the config file is located.
 
2220
 
 
2221
        :param file_name: The config file basename in the transport directory.
 
2222
        """
 
2223
        super(IniFileStore, self).__init__()
 
2224
        self.transport = transport
 
2225
        self.file_name = file_name
 
2226
        self._config_obj = None
 
2227
 
 
2228
    def is_loaded(self):
 
2229
        return self._config_obj != None
 
2230
 
 
2231
    def load(self):
 
2232
        """Load the store from the associated file."""
 
2233
        if self.is_loaded():
 
2234
            return
 
2235
        content = self.transport.get_bytes(self.file_name)
 
2236
        self._load_from_string(content)
 
2237
 
 
2238
    def _load_from_string(self, str_or_unicode):
 
2239
        """Create a config store from a string.
 
2240
 
 
2241
        :param str_or_unicode: A string representing the file content. This will
 
2242
            be utf-8 encoded internally.
 
2243
 
 
2244
        This is for tests and should not be used in production unless a
 
2245
        convincing use case can be demonstrated :)
 
2246
        """
 
2247
        if self.is_loaded():
 
2248
            raise AssertionError('Already loaded: %r' % (self._config_obj,))
 
2249
        co_input = StringIO(str_or_unicode.encode('utf-8'))
 
2250
        try:
 
2251
            # The config files are always stored utf8-encoded
 
2252
            self._config_obj = ConfigObj(co_input, encoding='utf-8')
 
2253
        except configobj.ConfigObjError, e:
 
2254
            self._config_obj = None
 
2255
            raise errors.ParseConfigError(e.errors, self.external_url())
 
2256
 
 
2257
    def save(self):
 
2258
        if not self.is_loaded():
 
2259
            # Nothing to save
 
2260
            return
 
2261
        out = StringIO()
 
2262
        self._config_obj.write(out)
 
2263
        self.transport.put_bytes(self.file_name, out.getvalue())
 
2264
 
 
2265
    def external_url(self):
 
2266
        # FIXME: external_url should really accepts an optional relpath
 
2267
        # parameter (bug #750169) :-/ -- vila 2011-04-04
 
2268
        # The following will do in the interim but maybe we don't want to
 
2269
        # expose a path here but rather a config ID and its associated
 
2270
        # object </hand wawe>.
 
2271
        return urlutils.join(self.transport.external_url(), self.file_name)
 
2272
 
 
2273
    def get_sections(self):
 
2274
        """Get the configobj section in the file order.
 
2275
 
 
2276
        :returns: An iterable of (name, dict).
 
2277
        """
 
2278
        # We need a loaded store
 
2279
        try:
 
2280
            self.load()
 
2281
        except errors.NoSuchFile:
 
2282
            # If the file doesn't exist, there is no sections
 
2283
            return
 
2284
        cobj = self._config_obj
 
2285
        if cobj.scalars:
 
2286
            yield self.readonly_section_class(None, cobj)
 
2287
        for section_name in cobj.sections:
 
2288
            yield self.readonly_section_class(section_name, cobj[section_name])
 
2289
 
 
2290
    def get_mutable_section(self, section_name=None):
 
2291
        # We need a loaded store
 
2292
        try:
 
2293
            self.load()
 
2294
        except errors.NoSuchFile:
 
2295
            # The file doesn't exist, let's pretend it was empty
 
2296
            self._load_from_string('')
 
2297
        if section_name is None:
 
2298
            section = self._config_obj
 
2299
        else:
 
2300
            section = self._config_obj.setdefault(section_name, {})
 
2301
        return self.mutable_section_class(section_name, section)
 
2302
 
 
2303
 
 
2304
# Note that LockableConfigObjStore inherits from ConfigObjStore because we need
 
2305
# unlockable stores for use with objects that can already ensure the locking
 
2306
# (think branches). If different stores (not based on ConfigObj) are created,
 
2307
# they may face the same issue.
 
2308
 
 
2309
 
 
2310
class LockableIniFileStore(IniFileStore):
 
2311
    """A ConfigObjStore using locks on save to ensure store integrity."""
 
2312
 
 
2313
    def __init__(self, transport, file_name, lock_dir_name=None):
 
2314
        """A config Store using ConfigObj for storage.
 
2315
 
 
2316
        :param transport: The transport object where the config file is located.
 
2317
 
 
2318
        :param file_name: The config file basename in the transport directory.
 
2319
        """
 
2320
        if lock_dir_name is None:
 
2321
            lock_dir_name = 'lock'
 
2322
        self.lock_dir_name = lock_dir_name
 
2323
        super(LockableIniFileStore, self).__init__(transport, file_name)
 
2324
        self._lock = lockdir.LockDir(self.transport, self.lock_dir_name)
 
2325
 
 
2326
    def lock_write(self, token=None):
 
2327
        """Takes a write lock in the directory containing the config file.
 
2328
 
 
2329
        If the directory doesn't exist it is created.
 
2330
        """
 
2331
        # FIXME: This doesn't check the ownership of the created directories as
 
2332
        # ensure_config_dir_exists does. It should if the transport is local
 
2333
        # -- vila 2011-04-06
 
2334
        self.transport.create_prefix()
 
2335
        return self._lock.lock_write(token)
 
2336
 
 
2337
    def unlock(self):
 
2338
        self._lock.unlock()
 
2339
 
 
2340
    def break_lock(self):
 
2341
        self._lock.break_lock()
 
2342
 
 
2343
    @needs_write_lock
 
2344
    def save(self):
 
2345
        super(LockableIniFileStore, self).save()
 
2346
 
 
2347
 
 
2348
# FIXME: global, bazaar, shouldn't that be 'user' instead or even
 
2349
# 'user_defaults' as opposed to 'user_overrides', 'system_defaults'
 
2350
# (/etc/bzr/bazaar.conf) and 'system_overrides' ? -- vila 2011-04-05
 
2351
 
 
2352
# FIXME: Moreover, we shouldn't need classes for these stores either, factory
 
2353
# functions or a registry will make it easier and clearer for tests, focusing
 
2354
# on the relevant parts of the API that needs testing -- vila 20110503 (based
 
2355
# on a poolie's remark)
 
2356
class GlobalStore(LockableIniFileStore):
 
2357
 
 
2358
    def __init__(self, possible_transports=None):
 
2359
        t = transport.get_transport(config_dir(),
 
2360
                                    possible_transports=possible_transports)
 
2361
        super(GlobalStore, self).__init__(t, 'bazaar.conf')
 
2362
 
 
2363
 
 
2364
class LocationStore(LockableIniFileStore):
 
2365
 
 
2366
    def __init__(self, possible_transports=None):
 
2367
        t = transport.get_transport(config_dir(),
 
2368
                                    possible_transports=possible_transports)
 
2369
        super(LocationStore, self).__init__(t, 'locations.conf')
 
2370
 
 
2371
 
 
2372
class BranchStore(IniFileStore):
 
2373
 
 
2374
    def __init__(self, branch):
 
2375
        super(BranchStore, self).__init__(branch.control_transport,
 
2376
                                          'branch.conf')
 
2377
 
 
2378
class SectionMatcher(object):
 
2379
    """Select sections into a given Store.
 
2380
 
 
2381
    This intended to be used to postpone getting an iterable of sections from a
 
2382
    store.
 
2383
    """
 
2384
 
 
2385
    def __init__(self, store):
 
2386
        self.store = store
 
2387
 
 
2388
    def get_sections(self):
 
2389
        # This is where we require loading the store so we can see all defined
 
2390
        # sections.
 
2391
        sections = self.store.get_sections()
 
2392
        # Walk the revisions in the order provided
 
2393
        for s in sections:
 
2394
            if self.match(s):
 
2395
                yield s
 
2396
 
 
2397
    def match(self, secion):
 
2398
        raise NotImplementedError(self.match)
 
2399
 
 
2400
 
 
2401
class LocationSection(Section):
 
2402
 
 
2403
    def __init__(self, section, length, extra_path):
 
2404
        super(LocationSection, self).__init__(section.id, section.options)
 
2405
        self.length = length
 
2406
        self.extra_path = extra_path
 
2407
 
 
2408
    def get(self, name, default=None):
 
2409
        value = super(LocationSection, self).get(name, default)
 
2410
        if value is not None:
 
2411
            policy_name = self.get(name + ':policy', None)
 
2412
            policy = _policy_value.get(policy_name, POLICY_NONE)
 
2413
            if policy == POLICY_APPENDPATH:
 
2414
                value = urlutils.join(value, self.extra_path)
 
2415
        return value
 
2416
 
 
2417
 
 
2418
class LocationMatcher(SectionMatcher):
 
2419
 
 
2420
    def __init__(self, store, location):
 
2421
        super(LocationMatcher, self).__init__(store)
 
2422
        if location.startswith('file://'):
 
2423
            location = urlutils.local_path_from_url(location)
 
2424
        self.location = location
 
2425
 
 
2426
    def _get_matching_sections(self):
 
2427
        """Get all sections matching ``location``."""
 
2428
        # We slightly diverge from LocalConfig here by allowing the no-name
 
2429
        # section as the most generic one and the lower priority.
 
2430
        no_name_section = None
 
2431
        sections = []
 
2432
        # Filter out the no_name_section so _iter_for_location_by_parts can be
 
2433
        # used (it assumes all sections have a name).
 
2434
        for section in self.store.get_sections():
 
2435
            if section.id is None:
 
2436
                no_name_section = section
 
2437
            else:
 
2438
                sections.append(section)
 
2439
        # Unfortunately _iter_for_location_by_parts deals with section names so
 
2440
        # we have to resync.
 
2441
        filtered_sections = _iter_for_location_by_parts(
 
2442
            [s.id for s in sections], self.location)
 
2443
        iter_sections = iter(sections)
 
2444
        matching_sections = []
 
2445
        if no_name_section is not None:
 
2446
            matching_sections.append(
 
2447
                LocationSection(no_name_section, 0, self.location))
 
2448
        for section_id, extra_path, length in filtered_sections:
 
2449
            # a section id is unique for a given store so it's safe to iterate
 
2450
            # again
 
2451
            section = iter_sections.next()
 
2452
            if section_id == section.id:
 
2453
                matching_sections.append(
 
2454
                    LocationSection(section, length, extra_path))
 
2455
        return matching_sections
 
2456
 
 
2457
    def get_sections(self):
 
2458
        # Override the default implementation as we want to change the order
 
2459
        matching_sections = self._get_matching_sections()
 
2460
        # We want the longest (aka more specific) locations first
 
2461
        sections = sorted(matching_sections,
 
2462
                          key=lambda section: (section.length, section.id),
 
2463
                          reverse=True)
 
2464
        # Sections mentioning 'ignore_parents' restrict the selection
 
2465
        for section in sections:
 
2466
            # FIXME: We really want to use as_bool below -- vila 2011-04-07
 
2467
            ignore = section.get('ignore_parents', None)
 
2468
            if ignore is not None:
 
2469
                ignore = ui.bool_from_string(ignore)
 
2470
            if ignore:
 
2471
                break
 
2472
            # Finally, we have a valid section
 
2473
            yield section
 
2474
 
 
2475
 
 
2476
class Stack(object):
 
2477
    """A stack of configurations where an option can be defined"""
 
2478
 
 
2479
    def __init__(self, sections_def, store=None, mutable_section_name=None):
 
2480
        """Creates a stack of sections with an optional store for changes.
 
2481
 
 
2482
        :param sections_def: A list of Section or callables that returns an
 
2483
            iterable of Section. This defines the Sections for the Stack and
 
2484
            can be called repeatedly if needed.
 
2485
 
 
2486
        :param store: The optional Store where modifications will be
 
2487
            recorded. If none is specified, no modifications can be done.
 
2488
 
 
2489
        :param mutable_section_name: The name of the MutableSection where
 
2490
            changes are recorded. This requires the ``store`` parameter to be
 
2491
            specified.
 
2492
        """
 
2493
        self.sections_def = sections_def
 
2494
        self.store = store
 
2495
        self.mutable_section_name = mutable_section_name
 
2496
 
 
2497
    def get(self, name):
 
2498
        """Return the *first* option value found in the sections.
 
2499
 
 
2500
        This is where we guarantee that sections coming from Store are loaded
 
2501
        lazily: the loading is delayed until we need to either check that an
 
2502
        option exists or get its value, which in turn may require to discover
 
2503
        in which sections it can be defined. Both of these (section and option
 
2504
        existence) require loading the store (even partially).
 
2505
        """
 
2506
        # FIXME: No caching of options nor sections yet -- vila 20110503
 
2507
 
 
2508
        # Ensuring lazy loading is achieved by delaying section matching (which
 
2509
        # implies querying the persistent storage) until it can't be avoided
 
2510
        # anymore by using callables to describe (possibly empty) section
 
2511
        # lists.
 
2512
        for section_or_callable in self.sections_def:
 
2513
            # Each section can expand to multiple ones when a callable is used
 
2514
            if callable(section_or_callable):
 
2515
                sections = section_or_callable()
 
2516
            else:
 
2517
                sections = [section_or_callable]
 
2518
            for section in sections:
 
2519
                value = section.get(name)
 
2520
                if value is not None:
 
2521
                    return value
 
2522
        # No definition was found
 
2523
        return None
 
2524
 
 
2525
    def _get_mutable_section(self):
 
2526
        """Get the MutableSection for the Stack.
 
2527
 
 
2528
        This is where we guarantee that the mutable section is lazily loaded:
 
2529
        this means we won't load the corresponding store before setting a value
 
2530
        or deleting an option. In practice the store will often be loaded but
 
2531
        this allows helps catching some programming errors.
 
2532
        """
 
2533
        section = self.store.get_mutable_section(self.mutable_section_name)
 
2534
        return section
 
2535
 
 
2536
    def set(self, name, value):
 
2537
        """Set a new value for the option."""
 
2538
        section = self._get_mutable_section()
 
2539
        section.set(name, value)
 
2540
 
 
2541
    def remove(self, name):
 
2542
        """Remove an existing option."""
 
2543
        section = self._get_mutable_section()
 
2544
        section.remove(name)
 
2545
 
 
2546
    def __repr__(self):
 
2547
        # Mostly for debugging use
 
2548
        return "<config.%s(%s)>" % (self.__class__.__name__, id(self))
 
2549
 
 
2550
 
 
2551
class GlobalStack(Stack):
 
2552
 
 
2553
    def __init__(self):
 
2554
        # Get a GlobalStore
 
2555
        gstore = GlobalStore()
 
2556
        super(GlobalStack, self).__init__([gstore.get_sections], gstore)
 
2557
 
 
2558
 
 
2559
class LocationStack(Stack):
 
2560
 
 
2561
    def __init__(self, location):
 
2562
        lstore = LocationStore()
 
2563
        matcher = LocationMatcher(lstore, location)
 
2564
        gstore = GlobalStore()
 
2565
        super(LocationStack, self).__init__(
 
2566
            [matcher.get_sections, gstore.get_sections], lstore)
 
2567
 
 
2568
 
 
2569
class BranchStack(Stack):
 
2570
 
 
2571
    def __init__(self, branch):
 
2572
        bstore = BranchStore(branch)
 
2573
        lstore = LocationStore()
 
2574
        matcher = LocationMatcher(lstore, branch.base)
 
2575
        gstore = GlobalStore()
 
2576
        super(BranchStack, self).__init__(
 
2577
            [matcher.get_sections, bstore.get_sections, gstore.get_sections],
 
2578
            bstore)
 
2579
 
 
2580
 
 
2581
class cmd_config(commands.Command):
 
2582
    __doc__ = """Display, set or remove a configuration option.
 
2583
 
 
2584
    Display the active value for a given option.
 
2585
 
 
2586
    If --all is specified, NAME is interpreted as a regular expression and all
 
2587
    matching options are displayed mentioning their scope. The active value
 
2588
    that bzr will take into account is the first one displayed for each option.
 
2589
 
 
2590
    If no NAME is given, --all .* is implied.
 
2591
 
 
2592
    Setting a value is achieved by using name=value without spaces. The value
 
2593
    is set in the most relevant scope and can be checked by displaying the
 
2594
    option again.
 
2595
    """
 
2596
 
 
2597
    takes_args = ['name?']
 
2598
 
 
2599
    takes_options = [
 
2600
        'directory',
 
2601
        # FIXME: This should be a registry option so that plugins can register
 
2602
        # their own config files (or not) -- vila 20101002
 
2603
        commands.Option('scope', help='Reduce the scope to the specified'
 
2604
                        ' configuration file',
 
2605
                        type=unicode),
 
2606
        commands.Option('all',
 
2607
            help='Display all the defined values for the matching options.',
 
2608
            ),
 
2609
        commands.Option('remove', help='Remove the option from'
 
2610
                        ' the configuration file'),
 
2611
        ]
 
2612
 
 
2613
    @commands.display_command
 
2614
    def run(self, name=None, all=False, directory=None, scope=None,
 
2615
            remove=False):
 
2616
        if directory is None:
 
2617
            directory = '.'
 
2618
        directory = urlutils.normalize_url(directory)
 
2619
        if remove and all:
 
2620
            raise errors.BzrError(
 
2621
                '--all and --remove are mutually exclusive.')
 
2622
        elif remove:
 
2623
            # Delete the option in the given scope
 
2624
            self._remove_config_option(name, directory, scope)
 
2625
        elif name is None:
 
2626
            # Defaults to all options
 
2627
            self._show_matching_options('.*', directory, scope)
 
2628
        else:
 
2629
            try:
 
2630
                name, value = name.split('=', 1)
 
2631
            except ValueError:
 
2632
                # Display the option(s) value(s)
 
2633
                if all:
 
2634
                    self._show_matching_options(name, directory, scope)
 
2635
                else:
 
2636
                    self._show_value(name, directory, scope)
 
2637
            else:
 
2638
                if all:
 
2639
                    raise errors.BzrError(
 
2640
                        'Only one option can be set.')
 
2641
                # Set the option value
 
2642
                self._set_config_option(name, value, directory, scope)
 
2643
 
 
2644
    def _get_configs(self, directory, scope=None):
 
2645
        """Iterate the configurations specified by ``directory`` and ``scope``.
 
2646
 
 
2647
        :param directory: Where the configurations are derived from.
 
2648
 
 
2649
        :param scope: A specific config to start from.
 
2650
        """
 
2651
        if scope is not None:
 
2652
            if scope == 'bazaar':
 
2653
                yield GlobalConfig()
 
2654
            elif scope == 'locations':
 
2655
                yield LocationConfig(directory)
 
2656
            elif scope == 'branch':
 
2657
                (_, br, _) = bzrdir.BzrDir.open_containing_tree_or_branch(
 
2658
                    directory)
 
2659
                yield br.get_config()
 
2660
        else:
 
2661
            try:
 
2662
                (_, br, _) = bzrdir.BzrDir.open_containing_tree_or_branch(
 
2663
                    directory)
 
2664
                yield br.get_config()
 
2665
            except errors.NotBranchError:
 
2666
                yield LocationConfig(directory)
 
2667
                yield GlobalConfig()
 
2668
 
 
2669
    def _show_value(self, name, directory, scope):
 
2670
        displayed = False
 
2671
        for c in self._get_configs(directory, scope):
 
2672
            if displayed:
 
2673
                break
 
2674
            for (oname, value, section, conf_id, parser) in c._get_options():
 
2675
                if name == oname:
 
2676
                    # Display only the first value and exit
 
2677
 
 
2678
                    # FIXME: We need to use get_user_option to take policies
 
2679
                    # into account and we need to make sure the option exists
 
2680
                    # too (hence the two for loops), this needs a better API
 
2681
                    # -- vila 20101117
 
2682
                    value = c.get_user_option(name)
 
2683
                    # Quote the value appropriately
 
2684
                    value = parser._quote(value)
 
2685
                    self.outf.write('%s\n' % (value,))
 
2686
                    displayed = True
 
2687
                    break
 
2688
        if not displayed:
 
2689
            raise errors.NoSuchConfigOption(name)
 
2690
 
 
2691
    def _show_matching_options(self, name, directory, scope):
 
2692
        name = re.compile(name)
 
2693
        # We want any error in the regexp to be raised *now* so we need to
 
2694
        # avoid the delay introduced by the lazy regexp.
 
2695
        name._compile_and_collapse()
 
2696
        cur_conf_id = None
 
2697
        cur_section = None
 
2698
        for c in self._get_configs(directory, scope):
 
2699
            for (oname, value, section, conf_id, parser) in c._get_options():
 
2700
                if name.search(oname):
 
2701
                    if cur_conf_id != conf_id:
 
2702
                        # Explain where the options are defined
 
2703
                        self.outf.write('%s:\n' % (conf_id,))
 
2704
                        cur_conf_id = conf_id
 
2705
                        cur_section = None
 
2706
                    if (section not in (None, 'DEFAULT')
 
2707
                        and cur_section != section):
 
2708
                        # Display the section if it's not the default (or only)
 
2709
                        # one.
 
2710
                        self.outf.write('  [%s]\n' % (section,))
 
2711
                        cur_section = section
 
2712
                    self.outf.write('  %s = %s\n' % (oname, value))
 
2713
 
 
2714
    def _set_config_option(self, name, value, directory, scope):
 
2715
        for conf in self._get_configs(directory, scope):
 
2716
            conf.set_user_option(name, value)
 
2717
            break
 
2718
        else:
 
2719
            raise errors.NoSuchConfig(scope)
 
2720
 
 
2721
    def _remove_config_option(self, name, directory, scope):
 
2722
        if name is None:
 
2723
            raise errors.BzrCommandError(
 
2724
                '--remove expects an option to remove.')
 
2725
        removed = False
 
2726
        for conf in self._get_configs(directory, scope):
 
2727
            for (section_name, section, conf_id) in conf._get_sections():
 
2728
                if scope is not None and conf_id != scope:
 
2729
                    # Not the right configuration file
 
2730
                    continue
 
2731
                if name in section:
 
2732
                    if conf_id != conf.config_id():
 
2733
                        conf = self._get_configs(directory, conf_id).next()
 
2734
                    # We use the first section in the first config where the
 
2735
                    # option is defined to remove it
 
2736
                    conf.remove_user_option(name, section_name)
 
2737
                    removed = True
 
2738
                    break
 
2739
            break
 
2740
        else:
 
2741
            raise errors.NoSuchConfig(scope)
 
2742
        if not removed:
 
2743
            raise errors.NoSuchConfigOption(name)