~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Jelmer Vernooij
  • Date: 2012-04-16 11:08:11 UTC
  • mfrom: (6521 +trunk)
  • mto: This revision was merged to the branch mainline in revision 6522.
  • Revision ID: jelmer@samba.org-20120416110811-0y996ihqy9o2bb1t
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
55
55
                   turns on create_signatures.
56
56
create_signatures - this option controls whether bzr will always create
57
57
                    gpg signatures or not on commits.  There is an unused
58
 
                    option which in future is expected to work if               
 
58
                    option which in future is expected to work if
59
59
                    branch settings require signatures.
60
60
log_format - this option sets the default log format.  Possible values are
61
61
             long, short, line, or a plugin can register new formats.
92
92
    lazy_regex,
93
93
    library_state,
94
94
    lockdir,
95
 
    mail_client,
96
95
    mergetools,
97
96
    osutils,
98
97
    symbol_versioning,
196
195
        return self[section][name]
197
196
 
198
197
 
199
 
# FIXME: Until we can guarantee that each config file is loaded once and
200
 
# only once for a given bzrlib session, we don't want to re-read the file every
201
 
# time we query for an option so we cache the value (bad ! watch out for tests
202
 
# needing to restore the proper value). -- vila 20110219
203
 
_expand_default_value = None
204
 
def _get_expand_default_value():
205
 
    global _expand_default_value
206
 
    if _expand_default_value is not None:
207
 
        return _expand_default_value
208
 
    conf = GlobalConfig()
209
 
    # Note that we must not use None for the expand value below or we'll run
210
 
    # into infinite recursion. Using False really would be quite silly ;)
211
 
    expand = conf.get_user_option_as_bool('bzr.config.expand', expand=True)
212
 
    if expand is None:
213
 
        # This is an opt-in feature, you *really* need to clearly say you want
214
 
        # to activate it !
215
 
        expand = False
216
 
    _expand_default_value = expand
217
 
    return expand
218
 
 
219
 
 
220
198
class Config(object):
221
199
    """A configuration policy - what username, editor, gpg needs etc."""
222
200
 
227
205
        """Returns a unique ID for the config."""
228
206
        raise NotImplementedError(self.config_id)
229
207
 
230
 
    @deprecated_method(deprecated_in((2, 4, 0)))
231
 
    def get_editor(self):
232
 
        """Get the users pop up editor."""
233
 
        raise NotImplementedError
234
 
 
235
208
    def get_change_editor(self, old_tree, new_tree):
236
209
        from bzrlib import diff
237
210
        cmd = self._get_change_editor()
240
213
        return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
241
214
                                             sys.stdout)
242
215
 
243
 
    def get_mail_client(self):
244
 
        """Get a mail client to use"""
245
 
        selected_client = self.get_user_option('mail_client')
246
 
        _registry = mail_client.mail_client_registry
247
 
        try:
248
 
            mail_client_class = _registry.get(selected_client)
249
 
        except KeyError:
250
 
            raise errors.UnknownMailClient(selected_client)
251
 
        return mail_client_class(self)
252
 
 
253
216
    def _get_signature_checking(self):
254
217
        """Template method to override signature checking policy."""
255
218
 
384
347
        """Template method to provide a user option."""
385
348
        return None
386
349
 
387
 
    def get_user_option(self, option_name, expand=None):
 
350
    def get_user_option(self, option_name, expand=True):
388
351
        """Get a generic option - no special process, no default.
389
352
 
390
353
        :param option_name: The queried option.
393
356
 
394
357
        :returns: The value of the option.
395
358
        """
396
 
        if expand is None:
397
 
            expand = _get_expand_default_value()
398
359
        value = self._get_user_option(option_name)
399
360
        if expand:
400
361
            if isinstance(value, list):
648
609
        for (oname, value, section, conf_id, parser) in self._get_options():
649
610
            if oname.startswith('bzr.mergetool.'):
650
611
                tool_name = oname[len('bzr.mergetool.'):]
651
 
                tools[tool_name] = self.get_user_option(oname)
 
612
                tools[tool_name] = self.get_user_option(oname, False)
652
613
        trace.mutter('loaded merge tools: %r' % tools)
653
614
        return tools
654
615
 
1090
1051
        conf._create_from_string(str_or_unicode, save)
1091
1052
        return conf
1092
1053
 
1093
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1094
 
    def get_editor(self):
1095
 
        return self._get_user_option('editor')
1096
 
 
1097
1054
    @needs_write_lock
1098
1055
    def set_user_option(self, option, value):
1099
1056
        """Save option and its value in the configuration."""
1482
1439
        value = self._get_explicit_nickname()
1483
1440
        if value is not None:
1484
1441
            return value
 
1442
        if self.branch.name:
 
1443
            return self.branch.name
1485
1444
        return urlutils.unescape(self.branch.base.split('/')[-2])
1486
1445
 
1487
1446
    def has_explicit_nickname(self):
1524
1483
 
1525
1484
 
1526
1485
def config_dir():
1527
 
    """Return per-user configuration directory.
 
1486
    """Return per-user configuration directory as unicode string
1528
1487
 
1529
1488
    By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
1530
1489
    and Linux.  On Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
1532
1491
 
1533
1492
    TODO: Global option --config-dir to override this.
1534
1493
    """
1535
 
    base = os.environ.get('BZR_HOME', None)
 
1494
    base = osutils.path_from_environ('BZR_HOME')
1536
1495
    if sys.platform == 'win32':
1537
 
        # environ variables on Windows are in user encoding/mbcs. So decode
1538
 
        # before using one
1539
 
        if base is not None:
1540
 
            base = base.decode('mbcs')
1541
 
        if base is None:
1542
 
            base = win32utils.get_appdata_location_unicode()
1543
 
        if base is None:
1544
 
            base = os.environ.get('HOME', None)
1545
 
            if base is not None:
1546
 
                base = base.decode('mbcs')
1547
 
        if base is None:
1548
 
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
1549
 
                                  ' or HOME set')
 
1496
        if base is None:
 
1497
            base = win32utils.get_appdata_location()
 
1498
        if base is None:
 
1499
            base = win32utils.get_home_location()
 
1500
        # GZ 2012-02-01: Really the two level subdirs only make sense inside
 
1501
        #                APPDATA, but hard to move. See bug 348640 for more.
1550
1502
        return osutils.pathjoin(base, 'bazaar', '2.0')
1551
 
    else:
1552
 
        if base is not None:
1553
 
            base = base.decode(osutils._fs_enc)
1554
 
    if sys.platform == 'darwin':
1555
 
        if base is None:
1556
 
            # this takes into account $HOME
1557
 
            base = os.path.expanduser("~")
1558
 
        return osutils.pathjoin(base, '.bazaar')
1559
 
    else:
1560
 
        if base is None:
1561
 
            xdg_dir = os.environ.get('XDG_CONFIG_HOME', None)
 
1503
    if base is None:
 
1504
        # GZ 2012-02-01: What should OSX use instead of XDG if anything?
 
1505
        if sys.platform != 'darwin':
 
1506
            xdg_dir = osutils.path_from_environ('XDG_CONFIG_HOME')
1562
1507
            if xdg_dir is None:
1563
 
                xdg_dir = osutils.pathjoin(os.path.expanduser("~"), ".config")
 
1508
                xdg_dir = osutils.pathjoin(osutils._get_home_dir(), ".config")
1564
1509
            xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
1565
1510
            if osutils.isdir(xdg_dir):
1566
1511
                trace.mutter(
1567
1512
                    "Using configuration in XDG directory %s." % xdg_dir)
1568
1513
                return xdg_dir
1569
 
            base = os.path.expanduser("~")
1570
 
        return osutils.pathjoin(base, ".bazaar")
 
1514
        base = osutils._get_home_dir()
 
1515
    return osutils.pathjoin(base, ".bazaar")
1571
1516
 
1572
1517
 
1573
1518
def config_filename():
2197
2142
 
2198
2143
        It may be set to a location, or None.
2199
2144
 
2200
 
        This policy affects all branches contained by this bzrdir, except for
2201
 
        those under repositories.
 
2145
        This policy affects all branches contained by this control dir, except
 
2146
        for those under repositories.
2202
2147
        """
2203
2148
        if self._config is None:
2204
2149
            raise errors.BzrError("Cannot set configuration in %s" % self._bzrdir)
2212
2157
 
2213
2158
        This will either be a location, or None.
2214
2159
 
2215
 
        This policy affects all branches contained by this bzrdir, except for
2216
 
        those under repositories.
 
2160
        This policy affects all branches contained by this control dir, except
 
2161
        for those under repositories.
2217
2162
        """
2218
2163
        if self._config is None:
2219
2164
            return None
2396
2341
            raise AssertionError('%r is not supported as a default value'
2397
2342
                                 % (default,))
2398
2343
        self.default_from_env = default_from_env
2399
 
        self.help = help
 
2344
        self._help = help
2400
2345
        self.from_unicode = from_unicode
2401
2346
        self.unquote = unquote
2402
2347
        if invalid and invalid not in ('warning', 'error'):
2403
2348
            raise AssertionError("%s not supported for 'invalid'" % (invalid,))
2404
2349
        self.invalid = invalid
2405
2350
 
 
2351
    @property
 
2352
    def help(self):
 
2353
        return self._help
 
2354
 
2406
2355
    def convert_from_unicode(self, store, unicode_value):
2407
2356
        if self.unquote and store is not None and unicode_value is not None:
2408
2357
            unicode_value = store.unquote(unicode_value)
2454
2403
                value = self.default
2455
2404
        return value
2456
2405
 
 
2406
    def get_help_topic(self):
 
2407
        return self.name
 
2408
 
2457
2409
    def get_help_text(self, additional_see_also=None, plain=True):
2458
2410
        result = self.help
2459
2411
        from bzrlib import help_topics
2548
2500
        return l
2549
2501
 
2550
2502
 
 
2503
class RegistryOption(Option):
 
2504
    """Option for a choice from a registry."""
 
2505
 
 
2506
    def __init__(self, name, registry, default_from_env=None,
 
2507
                 help=None, invalid=None):
 
2508
        """A registry based Option definition.
 
2509
 
 
2510
        This overrides the base class so the conversion from a unicode string
 
2511
        can take quoting into account.
 
2512
        """
 
2513
        super(RegistryOption, self).__init__(
 
2514
            name, default=lambda: unicode(registry.default_key),
 
2515
            default_from_env=default_from_env,
 
2516
            from_unicode=self.from_unicode, help=help,
 
2517
            invalid=invalid, unquote=False)
 
2518
        self.registry = registry
 
2519
 
 
2520
    def from_unicode(self, unicode_str):
 
2521
        if not isinstance(unicode_str, basestring):
 
2522
            raise TypeError
 
2523
        try:
 
2524
            return self.registry.get(unicode_str)
 
2525
        except KeyError:
 
2526
            raise ValueError(
 
2527
                "Invalid value %s for %s."
 
2528
                "See help for a list of possible values." % (unicode_str,
 
2529
                    self.name))
 
2530
 
 
2531
    @property
 
2532
    def help(self):
 
2533
        ret = [self._help, "\n\nThe following values are supported:\n"]
 
2534
        for key in self.registry.keys():
 
2535
            ret.append(" %s - %s\n" % (key, self.registry.get_help(key)))
 
2536
        return "".join(ret)
 
2537
 
 
2538
 
2551
2539
class OptionRegistry(registry.Registry):
2552
2540
    """Register config options by their name.
2553
2541
 
2643
2631
           help="""\
2644
2632
Whether revisions associated with tags should be fetched.
2645
2633
"""))
 
2634
option_registry.register_lazy(
 
2635
    'bzr.transform.orphan_policy', 'bzrlib.transform', 'opt_transform_orphan')
2646
2636
option_registry.register(
2647
2637
    Option('bzr.workingtree.worth_saving_limit', default=10,
2648
2638
           from_unicode=int_from_store,  invalid='warning',
2656
2646
a file has been touched.
2657
2647
'''))
2658
2648
option_registry.register(
 
2649
    Option('bugtracker', default=None,
 
2650
           help='''\
 
2651
Default bug tracker to use.
 
2652
 
 
2653
This bug tracker will be used for example when marking bugs
 
2654
as fixed using ``bzr commit --fixes``, if no explicit
 
2655
bug tracker was specified.
 
2656
'''))
 
2657
option_registry.register(
2659
2658
    Option('check_signatures', default=CHECK_IF_POSSIBLE,
2660
2659
           from_unicode=signature_policy_from_unicode,
2661
2660
           help='''\
2763
2762
Standard log formats are ``long``, ``short`` and ``line``. Additional formats
2764
2763
may be provided by plugins.
2765
2764
'''))
 
2765
option_registry.register_lazy('mail_client', 'bzrlib.mail_client',
 
2766
    'opt_mail_client')
2766
2767
option_registry.register(
2767
2768
    Option('output_encoding',
2768
2769
           help= 'Unicode encoding for output'
2865
2866
option_registry.register(
2866
2867
    Option('submit_to',
2867
2868
           help='''Where submissions from this branch are mailed to.'''))
2868
 
 
 
2869
option_registry.register(
 
2870
    ListOption('suppress_warnings',
 
2871
           default=[],
 
2872
           help="List of warning classes to suppress."))
 
2873
option_registry.register(
 
2874
    Option('validate_signatures_in_log', default=False,
 
2875
           from_unicode=bool_from_store, invalid='warning',
 
2876
           help='''Whether to validate signatures in bzr log.'''))
2869
2877
option_registry.register_lazy('ssl.ca_certs',
2870
2878
    'bzrlib.transport.http._urllib2_wrappers', 'opt_ssl_ca_certs')
2871
2879
 
2873
2881
    'bzrlib.transport.http._urllib2_wrappers', 'opt_ssl_cert_reqs')
2874
2882
 
2875
2883
 
2876
 
 
2877
2884
class Section(object):
2878
2885
    """A section defines a dict of option name => value.
2879
2886
 
2949
2956
            # Report concurrent updates in an ad-hoc way. This should only
2950
2957
            # occurs when different processes try to update the same option
2951
2958
            # which is not supported (as in: the config framework is not meant
2952
 
            # to be used a sharing mechanism).
 
2959
            # to be used as a sharing mechanism).
2953
2960
            if expected != reloaded:
2954
2961
                if actual is _DeletedOption:
2955
2962
                    actual = '<DELETED>'
2975
2982
    mutable_section_class = MutableSection
2976
2983
 
2977
2984
    def __init__(self):
2978
 
        # Which sections need to be saved
2979
 
        self.dirty_sections = []
 
2985
        # Which sections need to be saved (by section id). We use a dict here
 
2986
        # so the dirty sections can be shared by multiple callers.
 
2987
        self.dirty_sections = {}
2980
2988
 
2981
2989
    def is_loaded(self):
2982
2990
        """Returns True if the Store has been loaded.
3025
3033
        raise NotImplementedError(self.save)
3026
3034
 
3027
3035
    def _need_saving(self):
3028
 
        for s in self.dirty_sections:
 
3036
        for s in self.dirty_sections.values():
3029
3037
            if s.orig:
3030
3038
                # At least one dirty section contains a modification
3031
3039
                return True
3045
3053
        # get_mutable_section() call below.
3046
3054
        self.unload()
3047
3055
        # Apply the changes from the preserved dirty sections
3048
 
        for dirty in dirty_sections:
3049
 
            clean = self.get_mutable_section(dirty.id)
 
3056
        for section_id, dirty in dirty_sections.iteritems():
 
3057
            clean = self.get_mutable_section(section_id)
3050
3058
            clean.apply_changes(dirty, self)
3051
3059
        # Everything is clean now
3052
 
        self.dirty_sections = []
 
3060
        self.dirty_sections = {}
3053
3061
 
3054
3062
    def save_changes(self):
3055
3063
        """Saves the Store to persistent storage if changes occurred.
3135
3143
 
3136
3144
    def unload(self):
3137
3145
        self._config_obj = None
3138
 
        self.dirty_sections = []
 
3146
        self.dirty_sections = {}
3139
3147
 
3140
3148
    def _load_content(self):
3141
3149
        """Load the config file bytes.
3189
3197
        if not self._need_saving():
3190
3198
            return
3191
3199
        # Preserve the current version
3192
 
        current = self._config_obj
3193
 
        dirty_sections = list(self.dirty_sections)
 
3200
        dirty_sections = dict(self.dirty_sections.items())
3194
3201
        self.apply_changes(dirty_sections)
3195
3202
        # Save to the persistent storage
3196
3203
        self.save()
3231
3238
        except errors.NoSuchFile:
3232
3239
            # The file doesn't exist, let's pretend it was empty
3233
3240
            self._load_from_string('')
 
3241
        if section_id in self.dirty_sections:
 
3242
            # We already created a mutable section for this id
 
3243
            return self.dirty_sections[section_id]
3234
3244
        if section_id is None:
3235
3245
            section = self._config_obj
3236
3246
        else:
3237
3247
            section = self._config_obj.setdefault(section_id, {})
3238
3248
        mutable_section = self.mutable_section_class(section_id, section)
3239
3249
        # All mutable sections can become dirty
3240
 
        self.dirty_sections.append(mutable_section)
 
3250
        self.dirty_sections[section_id] = mutable_section
3241
3251
        return mutable_section
3242
3252
 
3243
3253
    def quote(self, value):
3382
3392
        self.branch = branch
3383
3393
        self.id = 'branch'
3384
3394
 
3385
 
    def lock_write(self, token=None):
3386
 
        return self.branch.lock_write(token)
3387
 
 
3388
 
    def unlock(self):
3389
 
        return self.branch.unlock()
3390
 
 
3391
 
    @needs_write_lock
3392
 
    def save(self):
3393
 
        # We need to be able to override the undecorated implementation
3394
 
        self.save_without_locking()
3395
 
 
3396
 
    def save_without_locking(self):
3397
 
        super(BranchStore, self).save()
3398
 
 
3399
3395
 
3400
3396
class ControlStore(LockableIniFileStore):
3401
3397
 
3623
3619
        self.store = store
3624
3620
        self.mutable_section_id = mutable_section_id
3625
3621
 
3626
 
    def get(self, name, expand=None):
 
3622
    def iter_sections(self):
 
3623
        """Iterate all the defined sections."""
 
3624
        # Ensuring lazy loading is achieved by delaying section matching (which
 
3625
        # implies querying the persistent storage) until it can't be avoided
 
3626
        # anymore by using callables to describe (possibly empty) section
 
3627
        # lists.
 
3628
        for sections in self.sections_def:
 
3629
            for store, section in sections():
 
3630
                yield store, section
 
3631
 
 
3632
    def get(self, name, expand=True, convert=True):
3627
3633
        """Return the *first* option value found in the sections.
3628
3634
 
3629
3635
        This is where we guarantee that sections coming from Store are loaded
3636
3642
 
3637
3643
        :param expand: Whether options references should be expanded.
3638
3644
 
 
3645
        :param convert: Whether the option value should be converted from
 
3646
            unicode (do nothing for non-registered options).
 
3647
 
3639
3648
        :returns: The value of the option.
3640
3649
        """
3641
3650
        # FIXME: No caching of options nor sections yet -- vila 20110503
3642
 
        if expand is None:
3643
 
            expand = _get_expand_default_value()
3644
3651
        value = None
3645
3652
        found_store = None # Where the option value has been found
3646
3653
        # If the option is registered, it may provide additional info about
3664
3671
                                      % (name, type(val)))
3665
3672
                if opt is None:
3666
3673
                    val = found_store.unquote(val)
3667
 
                else:
 
3674
                elif convert:
3668
3675
                    val = opt.convert_from_unicode(found_store, val)
3669
3676
            return val
3670
3677
 
3674
3681
            value = opt.get_override()
3675
3682
            value = expand_and_convert(value)
3676
3683
        if value is None:
3677
 
            # Ensuring lazy loading is achieved by delaying section matching
3678
 
            # (which implies querying the persistent storage) until it can't be
3679
 
            # avoided anymore by using callables to describe (possibly empty)
3680
 
            # section lists.
3681
 
            for sections in self.sections_def:
3682
 
                for store, section in sections():
3683
 
                    value = section.get(name)
3684
 
                    if value is not None:
3685
 
                        found_store = store
3686
 
                        break
 
3684
            for store, section in self.iter_sections():
 
3685
                value = section.get(name)
3687
3686
                if value is not None:
 
3687
                    found_store = store
3688
3688
                    break
3689
3689
            value = expand_and_convert(value)
3690
3690
            if opt is not None and value is None:
3756
3756
            # anything else
3757
3757
            value = env[name]
3758
3758
        else:
3759
 
            value = self.get(name, expand=False)
 
3759
            value = self.get(name, expand=False, convert=False)
3760
3760
            value = self._expand_options_in_string(value, env, _refs)
3761
3761
        return value
3762
3762
 
3905
3905
            lstore, mutable_section_id=location)
3906
3906
 
3907
3907
 
3908
 
class BranchStack(_CompatibleStack):
 
3908
class BranchStack(Stack):
3909
3909
    """Per-location options falling back to branch then global options stack.
3910
3910
 
3911
3911
    The following sections are queried:
3936
3936
            bstore)
3937
3937
        self.branch = branch
3938
3938
 
 
3939
    def lock_write(self, token=None):
 
3940
        return self.branch.lock_write(token)
 
3941
 
 
3942
    def unlock(self):
 
3943
        return self.branch.unlock()
 
3944
 
 
3945
    @needs_write_lock
 
3946
    def set(self, name, value):
 
3947
        super(BranchStack, self).set(name, value)
 
3948
        # Unlocking the branch will trigger a store.save_changes() so the last
 
3949
        # unlock saves all the changes.
 
3950
 
 
3951
    @needs_write_lock
 
3952
    def remove(self, name):
 
3953
        super(BranchStack, self).remove(name)
 
3954
        # Unlocking the branch will trigger a store.save_changes() so the last
 
3955
        # unlock saves all the changes.
 
3956
 
3939
3957
 
3940
3958
class RemoteControlStack(_CompatibleStack):
3941
3959
    """Remote control-only options stack."""
3952
3970
        self.bzrdir = bzrdir
3953
3971
 
3954
3972
 
3955
 
class BranchOnlyStack(_CompatibleStack):
 
3973
class BranchOnlyStack(Stack):
3956
3974
    """Branch-only options stack."""
3957
3975
 
3958
3976
    # FIXME: _BranchOnlyStack only uses branch.conf and is used only for the
3966
3984
            bstore)
3967
3985
        self.branch = branch
3968
3986
 
3969
 
 
3970
 
# Use a an empty dict to initialize an empty configobj avoiding all
3971
 
# parsing and encoding checks
3972
 
_quoting_config = configobj.ConfigObj(
3973
 
    {}, encoding='utf-8', interpolation=False, list_values=True)
 
3987
    def lock_write(self, token=None):
 
3988
        return self.branch.lock_write(token)
 
3989
 
 
3990
    def unlock(self):
 
3991
        return self.branch.unlock()
 
3992
 
 
3993
    @needs_write_lock
 
3994
    def set(self, name, value):
 
3995
        super(BranchOnlyStack, self).set(name, value)
 
3996
        # Force a write to persistent storage
 
3997
        self.store.save_changes()
 
3998
 
 
3999
    @needs_write_lock
 
4000
    def remove(self, name):
 
4001
        super(BranchOnlyStack, self).remove(name)
 
4002
        # Force a write to persistent storage
 
4003
        self.store.save_changes()
 
4004
 
3974
4005
 
3975
4006
class cmd_config(commands.Command):
3976
4007
    __doc__ = """Display, set or remove a configuration option.
4038
4069
                # Set the option value
4039
4070
                self._set_config_option(name, value, directory, scope)
4040
4071
 
4041
 
    def _get_stack(self, directory, scope=None):
 
4072
    def _get_stack(self, directory, scope=None, write_access=False):
4042
4073
        """Get the configuration stack specified by ``directory`` and ``scope``.
4043
4074
 
4044
4075
        :param directory: Where the configurations are derived from.
4045
4076
 
4046
4077
        :param scope: A specific config to start from.
 
4078
 
 
4079
        :param write_access: Whether a write access to the stack will be
 
4080
            attempted.
4047
4081
        """
4048
4082
        # FIXME: scope should allow access to plugin-specific stacks (even
4049
4083
        # reduced to the plugin-specific store), related to
4057
4091
                (_, br, _) = (
4058
4092
                    controldir.ControlDir.open_containing_tree_or_branch(
4059
4093
                        directory))
 
4094
                if write_access:
 
4095
                    self.add_cleanup(br.lock_write().unlock)
4060
4096
                return br.get_config_stack()
4061
4097
            raise errors.NoSuchConfig(scope)
4062
4098
        else:
4064
4100
                (_, br, _) = (
4065
4101
                    controldir.ControlDir.open_containing_tree_or_branch(
4066
4102
                        directory))
 
4103
                if write_access:
 
4104
                    self.add_cleanup(br.lock_write().unlock)
4067
4105
                return br.get_config_stack()
4068
4106
            except errors.NotBranchError:
4069
4107
                return LocationStack(directory)
4070
4108
 
 
4109
    def _quote_multiline(self, value):
 
4110
        if '\n' in value:
 
4111
            value = '"""' + value + '"""'
 
4112
        return value
 
4113
 
4071
4114
    def _show_value(self, name, directory, scope):
4072
4115
        conf = self._get_stack(directory, scope)
4073
 
        value = conf.get(name, expand=True)
 
4116
        value = conf.get(name, expand=True, convert=False)
4074
4117
        if value is not None:
4075
4118
            # Quote the value appropriately
4076
 
            value = _quoting_config._quote(value)
 
4119
            value = self._quote_multiline(value)
4077
4120
            self.outf.write('%s\n' % (value,))
4078
4121
        else:
4079
4122
            raise errors.NoSuchConfigOption(name)
4087
4130
        cur_store_id = None
4088
4131
        cur_section = None
4089
4132
        conf = self._get_stack(directory, scope)
4090
 
        for sections in conf.sections_def:
4091
 
            for store, section in sections():
4092
 
                for oname in section.iter_option_names():
4093
 
                    if name.search(oname):
4094
 
                        if cur_store_id != store.id:
4095
 
                            # Explain where the options are defined
4096
 
                            self.outf.write('%s:\n' % (store.id,))
4097
 
                            cur_store_id = store.id
4098
 
                            cur_section = None
4099
 
                        if (section.id is not None
4100
 
                            and cur_section != section.id):
4101
 
                            # Display the section id as it appears in the store
4102
 
                            # (None doesn't appear by definition)
4103
 
                            self.outf.write('  [%s]\n' % (section.id,))
4104
 
                            cur_section = section.id
4105
 
                        value = section.get(oname, expand=False)
4106
 
                        # Since we don't use the stack, we need to restore a
4107
 
                        # proper quoting.
4108
 
                        try:
4109
 
                            opt = option_registry.get(oname)
4110
 
                            value = opt.convert_from_unicode(store, value)
4111
 
                        except KeyError:
4112
 
                            value = store.unquote(value)
4113
 
                        value = _quoting_config._quote(value)
4114
 
                        self.outf.write('  %s = %s\n' % (oname, value))
 
4133
        for store, section in conf.iter_sections():
 
4134
            for oname in section.iter_option_names():
 
4135
                if name.search(oname):
 
4136
                    if cur_store_id != store.id:
 
4137
                        # Explain where the options are defined
 
4138
                        self.outf.write('%s:\n' % (store.id,))
 
4139
                        cur_store_id = store.id
 
4140
                        cur_section = None
 
4141
                    if (section.id is not None and cur_section != section.id):
 
4142
                        # Display the section id as it appears in the store
 
4143
                        # (None doesn't appear by definition)
 
4144
                        self.outf.write('  [%s]\n' % (section.id,))
 
4145
                        cur_section = section.id
 
4146
                    value = section.get(oname, expand=False)
 
4147
                    # Quote the value appropriately
 
4148
                    value = self._quote_multiline(value)
 
4149
                    self.outf.write('  %s = %s\n' % (oname, value))
4115
4150
 
4116
4151
    def _set_config_option(self, name, value, directory, scope):
4117
 
        conf = self._get_stack(directory, scope)
 
4152
        conf = self._get_stack(directory, scope, write_access=True)
4118
4153
        conf.set(name, value)
4119
4154
 
4120
4155
    def _remove_config_option(self, name, directory, scope):
4121
4156
        if name is None:
4122
4157
            raise errors.BzrCommandError(
4123
4158
                '--remove expects an option to remove.')
4124
 
        conf = self._get_stack(directory, scope)
 
4159
        conf = self._get_stack(directory, scope, write_access=True)
4125
4160
        try:
4126
4161
            conf.remove(name)
4127
4162
        except KeyError: