/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: Jonathan Riddell
  • Date: 2011-05-31 13:52:18 UTC
  • mto: This revision was merged to the branch mainline in revision 5954.
  • Revision ID: jriddell@canonical.com-20110531135218-v6fxs6pad89awidf
Make error message less specific (might not be a local disk issue) and pass through zlib error

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