~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Jelmer Vernooij
  • Date: 2012-01-27 18:41:20 UTC
  • mto: This revision was merged to the branch mainline in revision 6449.
  • Revision ID: jelmer@samba.org-20120127184120-osvbbiwijy58hsah
remove unnecessary code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2014, 2016 Canonical Ltd
 
1
# Copyright (C) 2005-2012 Canonical Ltd
2
2
#   Authors: Robert Collins <robert.collins@canonical.com>
3
3
#            and others
4
4
#
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.
73
73
"""
74
74
 
75
75
from __future__ import absolute_import
76
 
from cStringIO import StringIO
 
76
 
77
77
import os
78
78
import sys
79
79
 
81
81
from bzrlib.decorators import needs_write_lock
82
82
from bzrlib.lazy_import import lazy_import
83
83
lazy_import(globals(), """
84
 
import base64
85
84
import fnmatch
86
85
import re
 
86
from cStringIO import StringIO
87
87
 
88
88
from bzrlib import (
89
89
    atomicfile,
90
90
    controldir,
91
91
    debug,
92
 
    directory_service,
93
92
    errors,
94
93
    lazy_regex,
95
94
    library_state,
96
95
    lockdir,
 
96
    mail_client,
97
97
    mergetools,
98
98
    osutils,
99
99
    symbol_versioning,
197
197
        return self[section][name]
198
198
 
199
199
 
 
200
# FIXME: Until we can guarantee that each config file is loaded once and
 
201
# only once for a given bzrlib session, we don't want to re-read the file every
 
202
# time we query for an option so we cache the value (bad ! watch out for tests
 
203
# needing to restore the proper value). -- vila 20110219
 
204
_expand_default_value = None
 
205
def _get_expand_default_value():
 
206
    global _expand_default_value
 
207
    if _expand_default_value is not None:
 
208
        return _expand_default_value
 
209
    conf = GlobalConfig()
 
210
    # Note that we must not use None for the expand value below or we'll run
 
211
    # into infinite recursion. Using False really would be quite silly ;)
 
212
    expand = conf.get_user_option_as_bool('bzr.config.expand', expand=True)
 
213
    if expand is None:
 
214
        # This is an opt-in feature, you *really* need to clearly say you want
 
215
        # to activate it !
 
216
        expand = False
 
217
    _expand_default_value = expand
 
218
    return expand
 
219
 
 
220
 
200
221
class Config(object):
201
222
    """A configuration policy - what username, editor, gpg needs etc."""
202
223
 
207
228
        """Returns a unique ID for the config."""
208
229
        raise NotImplementedError(self.config_id)
209
230
 
 
231
    @deprecated_method(deprecated_in((2, 4, 0)))
 
232
    def get_editor(self):
 
233
        """Get the users pop up editor."""
 
234
        raise NotImplementedError
 
235
 
210
236
    def get_change_editor(self, old_tree, new_tree):
211
237
        from bzrlib import diff
212
238
        cmd = self._get_change_editor()
215
241
        return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
216
242
                                             sys.stdout)
217
243
 
 
244
    def get_mail_client(self):
 
245
        """Get a mail client to use"""
 
246
        selected_client = self.get_user_option('mail_client')
 
247
        _registry = mail_client.mail_client_registry
 
248
        try:
 
249
            mail_client_class = _registry.get(selected_client)
 
250
        except KeyError:
 
251
            raise errors.UnknownMailClient(selected_client)
 
252
        return mail_client_class(self)
 
253
 
218
254
    def _get_signature_checking(self):
219
255
        """Template method to override signature checking policy."""
220
256
 
349
385
        """Template method to provide a user option."""
350
386
        return None
351
387
 
352
 
    def get_user_option(self, option_name, expand=True):
 
388
    def get_user_option(self, option_name, expand=None):
353
389
        """Get a generic option - no special process, no default.
354
390
 
355
391
        :param option_name: The queried option.
358
394
 
359
395
        :returns: The value of the option.
360
396
        """
 
397
        if expand is None:
 
398
            expand = _get_expand_default_value()
361
399
        value = self._get_user_option(option_name)
362
400
        if expand:
363
401
            if isinstance(value, list):
611
649
        for (oname, value, section, conf_id, parser) in self._get_options():
612
650
            if oname.startswith('bzr.mergetool.'):
613
651
                tool_name = oname[len('bzr.mergetool.'):]
614
 
                tools[tool_name] = self.get_user_option(oname, False)
 
652
                tools[tool_name] = self.get_user_option(oname)
615
653
        trace.mutter('loaded merge tools: %r' % tools)
616
654
        return tools
617
655
 
1053
1091
        conf._create_from_string(str_or_unicode, save)
1054
1092
        return conf
1055
1093
 
 
1094
    @deprecated_method(deprecated_in((2, 4, 0)))
 
1095
    def get_editor(self):
 
1096
        return self._get_user_option('editor')
 
1097
 
1056
1098
    @needs_write_lock
1057
1099
    def set_user_option(self, option, value):
1058
1100
        """Save option and its value in the configuration."""
1441
1483
        value = self._get_explicit_nickname()
1442
1484
        if value is not None:
1443
1485
            return value
1444
 
        if self.branch.name:
1445
 
            return self.branch.name
1446
1486
        return urlutils.unescape(self.branch.base.split('/')[-2])
1447
1487
 
1448
1488
    def has_explicit_nickname(self):
1485
1525
 
1486
1526
 
1487
1527
def config_dir():
1488
 
    """Return per-user configuration directory as unicode string
 
1528
    """Return per-user configuration directory.
1489
1529
 
1490
1530
    By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
1491
 
    and Linux.  On Mac OS X and Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
 
1531
    and Linux.  On Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
1492
1532
    that will be used instead.
1493
1533
 
1494
1534
    TODO: Global option --config-dir to override this.
1495
1535
    """
1496
 
    base = osutils.path_from_environ('BZR_HOME')
 
1536
    base = os.environ.get('BZR_HOME', None)
1497
1537
    if sys.platform == 'win32':
1498
 
        if base is None:
1499
 
            base = win32utils.get_appdata_location()
1500
 
        if base is None:
1501
 
            base = win32utils.get_home_location()
1502
 
        # GZ 2012-02-01: Really the two level subdirs only make sense inside
1503
 
        #                APPDATA, but hard to move. See bug 348640 for more.
 
1538
        # environ variables on Windows are in user encoding/mbcs. So decode
 
1539
        # before using one
 
1540
        if base is not None:
 
1541
            base = base.decode('mbcs')
 
1542
        if base is None:
 
1543
            base = win32utils.get_appdata_location_unicode()
 
1544
        if base is None:
 
1545
            base = os.environ.get('HOME', None)
 
1546
            if base is not None:
 
1547
                base = base.decode('mbcs')
 
1548
        if base is None:
 
1549
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
 
1550
                                  ' or HOME set')
1504
1551
        return osutils.pathjoin(base, 'bazaar', '2.0')
1505
 
    if base is None:
1506
 
        xdg_dir = osutils.path_from_environ('XDG_CONFIG_HOME')
1507
 
        if xdg_dir is None:
1508
 
            xdg_dir = osutils.pathjoin(osutils._get_home_dir(), ".config")
1509
 
        xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
1510
 
        if osutils.isdir(xdg_dir):
1511
 
            trace.mutter(
1512
 
                "Using configuration in XDG directory %s." % xdg_dir)
1513
 
            return xdg_dir
1514
 
        base = osutils._get_home_dir()
1515
 
    return osutils.pathjoin(base, ".bazaar")
 
1552
    else:
 
1553
        if base is not None:
 
1554
            base = base.decode(osutils._fs_enc)
 
1555
    if sys.platform == 'darwin':
 
1556
        if base is None:
 
1557
            # this takes into account $HOME
 
1558
            base = os.path.expanduser("~")
 
1559
        return osutils.pathjoin(base, '.bazaar')
 
1560
    else:
 
1561
        if base is None:
 
1562
            xdg_dir = os.environ.get('XDG_CONFIG_HOME', None)
 
1563
            if xdg_dir is None:
 
1564
                xdg_dir = osutils.pathjoin(os.path.expanduser("~"), ".config")
 
1565
            xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
 
1566
            if osutils.isdir(xdg_dir):
 
1567
                trace.mutter(
 
1568
                    "Using configuration in XDG directory %s." % xdg_dir)
 
1569
                return xdg_dir
 
1570
            base = os.path.expanduser("~")
 
1571
        return osutils.pathjoin(base, ".bazaar")
1516
1572
 
1517
1573
 
1518
1574
def config_filename():
1555
1611
def xdg_cache_dir():
1556
1612
    # See http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
1557
1613
    # Possibly this should be different on Windows?
1558
 
    e = os.environ.get('XDG_CACHE_HOME', None)
 
1614
    e = os.environ.get('XDG_CACHE_DIR', None)
1559
1615
    if e:
1560
1616
        return e
1561
1617
    else:
1562
1618
        return os.path.expanduser('~/.cache')
1563
1619
 
1564
1620
 
1565
 
def _get_default_mail_domain(mailname_file='/etc/mailname'):
 
1621
def _get_default_mail_domain():
1566
1622
    """If possible, return the assumed default email domain.
1567
1623
 
1568
1624
    :returns: string mail domain, or None.
1571
1627
        # No implementation yet; patches welcome
1572
1628
        return None
1573
1629
    try:
1574
 
        f = open(mailname_file)
 
1630
        f = open('/etc/mailname')
1575
1631
    except (IOError, OSError), e:
1576
1632
        return None
1577
1633
    try:
1578
 
        domain = f.readline().strip()
 
1634
        domain = f.read().strip()
1579
1635
        return domain
1580
1636
    finally:
1581
1637
        f.close()
2131
2187
credential_store_registry.default_key = 'plain'
2132
2188
 
2133
2189
 
2134
 
class Base64CredentialStore(CredentialStore):
2135
 
    __doc__ = """Base64 credential store for the authentication.conf file"""
2136
 
 
2137
 
    def decode_password(self, credentials):
2138
 
        """See CredentialStore.decode_password."""
2139
 
        # GZ 2012-07-28: Will raise binascii.Error if password is not base64,
2140
 
        #                should probably propogate as something more useful.
2141
 
        return base64.decodestring(credentials['password'])
2142
 
 
2143
 
credential_store_registry.register('base64', Base64CredentialStore,
2144
 
                                   help=Base64CredentialStore.__doc__)
2145
 
 
2146
 
 
2147
2190
class BzrDirConfig(object):
2148
2191
 
2149
2192
    def __init__(self, bzrdir):
2155
2198
 
2156
2199
        It may be set to a location, or None.
2157
2200
 
2158
 
        This policy affects all branches contained by this control dir, except
2159
 
        for those under repositories.
 
2201
        This policy affects all branches contained by this bzrdir, except for
 
2202
        those under repositories.
2160
2203
        """
2161
2204
        if self._config is None:
2162
 
            raise errors.BzrError("Cannot set configuration in %s"
2163
 
                                  % self._bzrdir)
 
2205
            raise errors.BzrError("Cannot set configuration in %s" % self._bzrdir)
2164
2206
        if value is None:
2165
2207
            self._config.set_option('', 'default_stack_on')
2166
2208
        else:
2171
2213
 
2172
2214
        This will either be a location, or None.
2173
2215
 
2174
 
        This policy affects all branches contained by this control dir, except
2175
 
        for those under repositories.
 
2216
        This policy affects all branches contained by this bzrdir, except for
 
2217
        those under repositories.
2176
2218
        """
2177
2219
        if self._config is None:
2178
2220
            return None
2314
2356
        :param help: a doc string to explain the option to the user.
2315
2357
 
2316
2358
        :param from_unicode: a callable to convert the unicode string
2317
 
            representing the option value in a store or its default value.
 
2359
            representing the option value in a store. This is not called for
 
2360
            the default value.
2318
2361
 
2319
2362
        :param invalid: the action to be taken when an invalid value is
2320
2363
            encountered in a store. This is called only when from_unicode is
2354
2397
            raise AssertionError('%r is not supported as a default value'
2355
2398
                                 % (default,))
2356
2399
        self.default_from_env = default_from_env
2357
 
        self._help = help
 
2400
        self.help = help
2358
2401
        self.from_unicode = from_unicode
2359
2402
        self.unquote = unquote
2360
2403
        if invalid and invalid not in ('warning', 'error'):
2361
2404
            raise AssertionError("%s not supported for 'invalid'" % (invalid,))
2362
2405
        self.invalid = invalid
2363
2406
 
2364
 
    @property
2365
 
    def help(self):
2366
 
        return self._help
2367
 
 
2368
2407
    def convert_from_unicode(self, store, unicode_value):
2369
2408
        if self.unquote and store is not None and unicode_value is not None:
2370
2409
            unicode_value = store.unquote(unicode_value)
2411
2450
                value = self.default()
2412
2451
                if not isinstance(value, unicode):
2413
2452
                    raise AssertionError(
2414
 
                        "Callable default value for '%s' should be unicode"
2415
 
                        % (self.name))
 
2453
                    'Callable default values should be unicode')
2416
2454
            else:
2417
2455
                value = self.default
2418
2456
        return value
2419
2457
 
2420
 
    def get_help_topic(self):
2421
 
        return self.name
2422
 
 
2423
2458
    def get_help_text(self, additional_see_also=None, plain=True):
2424
2459
        result = self.help
2425
2460
        from bzrlib import help_topics
2471
2506
    return float(unicode_str)
2472
2507
 
2473
2508
 
2474
 
# Use an empty dict to initialize an empty configobj avoiding all parsing and
2475
 
# encoding checks
 
2509
# Use a an empty dict to initialize an empty configobj avoiding all
 
2510
# parsing and encoding checks
2476
2511
_list_converter_config = configobj.ConfigObj(
2477
2512
    {}, encoding='utf-8', list_values=True, interpolation=False)
2478
2513
 
2514
2549
        return l
2515
2550
 
2516
2551
 
2517
 
class RegistryOption(Option):
2518
 
    """Option for a choice from a registry."""
2519
 
 
2520
 
    def __init__(self, name, registry, default_from_env=None,
2521
 
                 help=None, invalid=None):
2522
 
        """A registry based Option definition.
2523
 
 
2524
 
        This overrides the base class so the conversion from a unicode string
2525
 
        can take quoting into account.
2526
 
        """
2527
 
        super(RegistryOption, self).__init__(
2528
 
            name, default=lambda: unicode(registry.default_key),
2529
 
            default_from_env=default_from_env,
2530
 
            from_unicode=self.from_unicode, help=help,
2531
 
            invalid=invalid, unquote=False)
2532
 
        self.registry = registry
2533
 
 
2534
 
    def from_unicode(self, unicode_str):
2535
 
        if not isinstance(unicode_str, basestring):
2536
 
            raise TypeError
2537
 
        try:
2538
 
            return self.registry.get(unicode_str)
2539
 
        except KeyError:
2540
 
            raise ValueError(
2541
 
                "Invalid value %s for %s."
2542
 
                "See help for a list of possible values." % (unicode_str,
2543
 
                    self.name))
2544
 
 
2545
 
    @property
2546
 
    def help(self):
2547
 
        ret = [self._help, "\n\nThe following values are supported:\n"]
2548
 
        for key in self.registry.keys():
2549
 
            ret.append(" %s - %s\n" % (key, self.registry.get_help(key)))
2550
 
        return "".join(ret)
2551
 
 
2552
 
 
2553
 
_option_ref_re = lazy_regex.lazy_compile('({[^\d\W](?:\.\w|-\w|\w)*})')
2554
 
"""Describes an expandable option reference.
2555
 
 
2556
 
We want to match the most embedded reference first.
2557
 
 
2558
 
I.e. for '{{foo}}' we will get '{foo}',
2559
 
for '{bar{baz}}' we will get '{baz}'
2560
 
"""
2561
 
 
2562
 
def iter_option_refs(string):
2563
 
    # Split isolate refs so every other chunk is a ref
2564
 
    is_ref = False
2565
 
    for chunk  in _option_ref_re.split(string):
2566
 
        yield is_ref, chunk
2567
 
        is_ref = not is_ref
2568
 
 
2569
 
 
2570
2552
class OptionRegistry(registry.Registry):
2571
2553
    """Register config options by their name.
2572
2554
 
2574
2556
    some information from the option object itself.
2575
2557
    """
2576
2558
 
2577
 
    def _check_option_name(self, option_name):
2578
 
        """Ensures an option name is valid.
2579
 
 
2580
 
        :param option_name: The name to validate.
2581
 
        """
2582
 
        if _option_ref_re.match('{%s}' % option_name) is None:
2583
 
            raise errors.IllegalOptionName(option_name)
2584
 
 
2585
2559
    def register(self, option):
2586
2560
        """Register a new option to its name.
2587
2561
 
2588
2562
        :param option: The option to register. Its name is used as the key.
2589
2563
        """
2590
 
        self._check_option_name(option.name)
2591
2564
        super(OptionRegistry, self).register(option.name, option,
2592
2565
                                             help=option.help)
2593
2566
 
2602
2575
        :param member_name: the member of the module to return.  If empty or 
2603
2576
                None, get() will return the module itself.
2604
2577
        """
2605
 
        self._check_option_name(key)
2606
2578
        super(OptionRegistry, self).register_lazy(key,
2607
2579
                                                  module_name, member_name)
2608
2580
 
2672
2644
           help="""\
2673
2645
Whether revisions associated with tags should be fetched.
2674
2646
"""))
2675
 
option_registry.register_lazy(
2676
 
    'bzr.transform.orphan_policy', 'bzrlib.transform', 'opt_transform_orphan')
2677
2647
option_registry.register(
2678
2648
    Option('bzr.workingtree.worth_saving_limit', default=10,
2679
2649
           from_unicode=int_from_store,  invalid='warning',
2687
2657
a file has been touched.
2688
2658
'''))
2689
2659
option_registry.register(
2690
 
    Option('bugtracker', default=None,
2691
 
           help='''\
2692
 
Default bug tracker to use.
2693
 
 
2694
 
This bug tracker will be used for example when marking bugs
2695
 
as fixed using ``bzr commit --fixes``, if no explicit
2696
 
bug tracker was specified.
2697
 
'''))
2698
 
option_registry.register(
2699
2660
    Option('check_signatures', default=CHECK_IF_POSSIBLE,
2700
2661
           from_unicode=signature_policy_from_unicode,
2701
2662
           help='''\
2803
2764
Standard log formats are ``long``, ``short`` and ``line``. Additional formats
2804
2765
may be provided by plugins.
2805
2766
'''))
2806
 
option_registry.register_lazy('mail_client', 'bzrlib.mail_client',
2807
 
    'opt_mail_client')
2808
2767
option_registry.register(
2809
2768
    Option('output_encoding',
2810
2769
           help= 'Unicode encoding for output'
2827
2786
 
2828
2787
Each function takes branch, rev_id as parameters.
2829
2788
'''))
2830
 
option_registry.register_lazy('progress_bar', 'bzrlib.ui.text',
2831
 
                              'opt_progress_bar')
2832
2789
option_registry.register(
2833
2790
    Option('public_branch',
2834
2791
           default=None,
2909
2866
option_registry.register(
2910
2867
    Option('submit_to',
2911
2868
           help='''Where submissions from this branch are mailed to.'''))
2912
 
option_registry.register(
2913
 
    ListOption('suppress_warnings',
2914
 
           default=[],
2915
 
           help="List of warning classes to suppress."))
2916
 
option_registry.register(
2917
 
    Option('validate_signatures_in_log', default=False,
2918
 
           from_unicode=bool_from_store, invalid='warning',
2919
 
           help='''Whether to validate signatures in bzr log.'''))
2920
 
option_registry.register_lazy('ssl.ca_certs',
2921
 
    'bzrlib.transport.http._urllib2_wrappers', 'opt_ssl_ca_certs')
2922
 
 
2923
 
option_registry.register_lazy('ssl.cert_reqs',
2924
 
    'bzrlib.transport.http._urllib2_wrappers', 'opt_ssl_cert_reqs')
2925
2869
 
2926
2870
 
2927
2871
class Section(object):
2971
2915
        self.options[name] = value
2972
2916
 
2973
2917
    def remove(self, name):
2974
 
        if name not in self.orig and name in self.options:
 
2918
        if name not in self.orig:
2975
2919
            self.orig[name] = self.get(name, None)
2976
2920
        del self.options[name]
2977
2921
 
2999
2943
            # Report concurrent updates in an ad-hoc way. This should only
3000
2944
            # occurs when different processes try to update the same option
3001
2945
            # which is not supported (as in: the config framework is not meant
3002
 
            # to be used as a sharing mechanism).
 
2946
            # to be used a sharing mechanism).
3003
2947
            if expected != reloaded:
3004
2948
                if actual is _DeletedOption:
3005
2949
                    actual = '<DELETED>'
3025
2969
    mutable_section_class = MutableSection
3026
2970
 
3027
2971
    def __init__(self):
3028
 
        # Which sections need to be saved (by section id). We use a dict here
3029
 
        # so the dirty sections can be shared by multiple callers.
3030
 
        self.dirty_sections = {}
 
2972
        # Which sections need to be saved
 
2973
        self.dirty_sections = []
3031
2974
 
3032
2975
    def is_loaded(self):
3033
2976
        """Returns True if the Store has been loaded.
3076
3019
        raise NotImplementedError(self.save)
3077
3020
 
3078
3021
    def _need_saving(self):
3079
 
        for s in self.dirty_sections.values():
 
3022
        for s in self.dirty_sections:
3080
3023
            if s.orig:
3081
3024
                # At least one dirty section contains a modification
3082
3025
                return True
3096
3039
        # get_mutable_section() call below.
3097
3040
        self.unload()
3098
3041
        # Apply the changes from the preserved dirty sections
3099
 
        for section_id, dirty in dirty_sections.iteritems():
3100
 
            clean = self.get_mutable_section(section_id)
 
3042
        for dirty in dirty_sections:
 
3043
            clean = self.get_mutable_section(dirty.id)
3101
3044
            clean.apply_changes(dirty, self)
3102
3045
        # Everything is clean now
3103
 
        self.dirty_sections = {}
 
3046
        self.dirty_sections = []
3104
3047
 
3105
3048
    def save_changes(self):
3106
3049
        """Saves the Store to persistent storage if changes occurred.
3186
3129
 
3187
3130
    def unload(self):
3188
3131
        self._config_obj = None
3189
 
        self.dirty_sections = {}
 
3132
        self.dirty_sections = []
3190
3133
 
3191
3134
    def _load_content(self):
3192
3135
        """Load the config file bytes.
3240
3183
        if not self._need_saving():
3241
3184
            return
3242
3185
        # Preserve the current version
3243
 
        dirty_sections = dict(self.dirty_sections.items())
 
3186
        current = self._config_obj
 
3187
        dirty_sections = list(self.dirty_sections)
3244
3188
        self.apply_changes(dirty_sections)
3245
3189
        # Save to the persistent storage
3246
3190
        self.save()
3281
3225
        except errors.NoSuchFile:
3282
3226
            # The file doesn't exist, let's pretend it was empty
3283
3227
            self._load_from_string('')
3284
 
        if section_id in self.dirty_sections:
3285
 
            # We already created a mutable section for this id
3286
 
            return self.dirty_sections[section_id]
3287
3228
        if section_id is None:
3288
3229
            section = self._config_obj
3289
3230
        else:
3290
3231
            section = self._config_obj.setdefault(section_id, {})
3291
3232
        mutable_section = self.mutable_section_class(section_id, section)
3292
3233
        # All mutable sections can become dirty
3293
 
        self.dirty_sections[section_id] = mutable_section
 
3234
        self.dirty_sections.append(mutable_section)
3294
3235
        return mutable_section
3295
3236
 
3296
3237
    def quote(self, value):
3315
3256
        # anyway.
3316
3257
        return 'In-Process Store, no URL'
3317
3258
 
3318
 
 
3319
3259
class TransportIniFileStore(IniFileStore):
3320
3260
    """IniFileStore that loads files from a transport.
3321
3261
 
3411
3351
# on the relevant parts of the API that needs testing -- vila 20110503 (based
3412
3352
# on a poolie's remark)
3413
3353
class GlobalStore(LockableIniFileStore):
3414
 
    """A config store for global options.
3415
 
 
3416
 
    There is a single GlobalStore for a given process.
3417
 
    """
3418
3354
 
3419
3355
    def __init__(self, possible_transports=None):
3420
3356
        t = transport.get_transport_from_path(
3424
3360
 
3425
3361
 
3426
3362
class LocationStore(LockableIniFileStore):
3427
 
    """A config store for options specific to a location.
3428
 
 
3429
 
    There is a single LocationStore for a given process.
3430
 
    """
3431
3363
 
3432
3364
    def __init__(self, possible_transports=None):
3433
3365
        t = transport.get_transport_from_path(
3437
3369
 
3438
3370
 
3439
3371
class BranchStore(TransportIniFileStore):
3440
 
    """A config store for branch options.
3441
 
 
3442
 
    There is a single BranchStore for a given branch.
3443
 
    """
3444
3372
 
3445
3373
    def __init__(self, branch):
3446
3374
        super(BranchStore, self).__init__(branch.control_transport,
3448
3376
        self.branch = branch
3449
3377
        self.id = 'branch'
3450
3378
 
 
3379
    def lock_write(self, token=None):
 
3380
        return self.branch.lock_write(token)
 
3381
 
 
3382
    def unlock(self):
 
3383
        return self.branch.unlock()
 
3384
 
 
3385
    @needs_write_lock
 
3386
    def save(self):
 
3387
        # We need to be able to override the undecorated implementation
 
3388
        self.save_without_locking()
 
3389
 
 
3390
    def save_without_locking(self):
 
3391
        super(BranchStore, self).save()
 
3392
 
3451
3393
 
3452
3394
class ControlStore(LockableIniFileStore):
3453
3395
 
3499
3441
 
3500
3442
class LocationSection(Section):
3501
3443
 
3502
 
    def __init__(self, section, extra_path, branch_name=None):
 
3444
    def __init__(self, section, extra_path):
3503
3445
        super(LocationSection, self).__init__(section.id, section.options)
3504
3446
        self.extra_path = extra_path
3505
 
        if branch_name is None:
3506
 
            branch_name = ''
3507
3447
        self.locals = {'relpath': extra_path,
3508
 
                       'basename': urlutils.basename(extra_path),
3509
 
                       'branchname': branch_name}
 
3448
                       'basename': urlutils.basename(extra_path)}
3510
3449
 
3511
3450
    def get(self, name, default=None, expand=True):
3512
3451
        value = super(LocationSection, self).get(name, default)
3559
3498
        """
3560
3499
        location_parts = self.location.rstrip('/').split('/')
3561
3500
        store = self.store
 
3501
        sections = []
3562
3502
        # Later sections are more specific, they should be returned first
3563
3503
        for _, section in reversed(list(store.get_sections())):
3564
3504
            if section.id is None:
3581
3521
 
3582
3522
    def __init__(self, store, location):
3583
3523
        super(LocationMatcher, self).__init__(store)
3584
 
        url, params = urlutils.split_segment_parameters(location)
3585
3524
        if location.startswith('file://'):
3586
3525
            location = urlutils.local_path_from_url(location)
3587
3526
        self.location = location
3588
 
        branch_name = params.get('branch')
3589
 
        if branch_name is None:
3590
 
            self.branch_name = urlutils.basename(self.location)
3591
 
        else:
3592
 
            self.branch_name = urlutils.unescape(branch_name)
3593
3527
 
3594
3528
    def _get_matching_sections(self):
3595
3529
        """Get all sections matching ``location``."""
3621
3555
            while True:
3622
3556
                section = iter_all_sections.next()
3623
3557
                if section_id == section.id:
3624
 
                    section = LocationSection(section, extra_path,
3625
 
                                              self.branch_name)
3626
 
                    matching_sections.append((length, section))
 
3558
                    matching_sections.append(
 
3559
                        (length, LocationSection(section, extra_path)))
3627
3560
                    break
3628
3561
        return matching_sections
3629
3562
 
3646
3579
            yield self.store, section
3647
3580
 
3648
3581
 
3649
 
# FIXME: _shared_stores should be an attribute of a library state once a
3650
 
# library_state object is always available.
3651
 
_shared_stores = {}
3652
 
_shared_stores_at_exit_installed = False
 
3582
_option_ref_re = lazy_regex.lazy_compile('({[^{}\n]+})')
 
3583
"""Describes an expandable option reference.
 
3584
 
 
3585
We want to match the most embedded reference first.
 
3586
 
 
3587
I.e. for '{{foo}}' we will get '{foo}',
 
3588
for '{bar{baz}}' we will get '{baz}'
 
3589
"""
 
3590
 
 
3591
def iter_option_refs(string):
 
3592
    # Split isolate refs so every other chunk is a ref
 
3593
    is_ref = False
 
3594
    for chunk  in _option_ref_re.split(string):
 
3595
        yield is_ref, chunk
 
3596
        is_ref = not is_ref
 
3597
 
3653
3598
 
3654
3599
class Stack(object):
3655
3600
    """A stack of configurations where an option can be defined"""
3672
3617
        self.store = store
3673
3618
        self.mutable_section_id = mutable_section_id
3674
3619
 
3675
 
    def iter_sections(self):
3676
 
        """Iterate all the defined sections."""
3677
 
        # Ensuring lazy loading is achieved by delaying section matching (which
3678
 
        # implies querying the persistent storage) until it can't be avoided
3679
 
        # anymore by using callables to describe (possibly empty) section
3680
 
        # lists.
3681
 
        for sections in self.sections_def:
3682
 
            for store, section in sections():
3683
 
                yield store, section
3684
 
 
3685
 
    def get(self, name, expand=True, convert=True):
 
3620
    def get(self, name, expand=None):
3686
3621
        """Return the *first* option value found in the sections.
3687
3622
 
3688
3623
        This is where we guarantee that sections coming from Store are loaded
3695
3630
 
3696
3631
        :param expand: Whether options references should be expanded.
3697
3632
 
3698
 
        :param convert: Whether the option value should be converted from
3699
 
            unicode (do nothing for non-registered options).
3700
 
 
3701
3633
        :returns: The value of the option.
3702
3634
        """
3703
3635
        # FIXME: No caching of options nor sections yet -- vila 20110503
 
3636
        if expand is None:
 
3637
            expand = _get_expand_default_value()
3704
3638
        value = None
3705
3639
        found_store = None # Where the option value has been found
3706
3640
        # If the option is registered, it may provide additional info about
3724
3658
                                      % (name, type(val)))
3725
3659
                if opt is None:
3726
3660
                    val = found_store.unquote(val)
3727
 
                elif convert:
 
3661
                else:
3728
3662
                    val = opt.convert_from_unicode(found_store, val)
3729
3663
            return val
3730
3664
 
3734
3668
            value = opt.get_override()
3735
3669
            value = expand_and_convert(value)
3736
3670
        if value is None:
3737
 
            for store, section in self.iter_sections():
3738
 
                value = section.get(name)
 
3671
            # Ensuring lazy loading is achieved by delaying section matching
 
3672
            # (which implies querying the persistent storage) until it can't be
 
3673
            # avoided anymore by using callables to describe (possibly empty)
 
3674
            # section lists.
 
3675
            for sections in self.sections_def:
 
3676
                for store, section in sections():
 
3677
                    value = section.get(name)
 
3678
                    if value is not None:
 
3679
                        found_store = store
 
3680
                        break
3739
3681
                if value is not None:
3740
 
                    found_store = store
3741
3682
                    break
3742
3683
            value = expand_and_convert(value)
3743
3684
            if opt is not None and value is None:
3809
3750
            # anything else
3810
3751
            value = env[name]
3811
3752
        else:
3812
 
            value = self.get(name, expand=False, convert=False)
 
3753
            value = self.get(name, expand=False)
3813
3754
            value = self._expand_options_in_string(value, env, _refs)
3814
3755
        return value
3815
3756
 
3844
3785
        return "<config.%s(%s)>" % (self.__class__.__name__, id(self))
3845
3786
 
3846
3787
    def _get_overrides(self):
3847
 
        # FIXME: Hack around library_state.initialize never called
 
3788
        # Hack around library_state.initialize never called
3848
3789
        if bzrlib.global_state is not None:
3849
3790
            return bzrlib.global_state.cmdline_overrides.get_sections()
3850
3791
        return []
3851
3792
 
3852
 
    def get_shared_store(self, store, state=None):
3853
 
        """Get a known shared store.
3854
 
 
3855
 
        Store urls uniquely identify them and are used to ensure a single copy
3856
 
        is shared across all users.
3857
 
 
3858
 
        :param store: The store known to the caller.
3859
 
 
3860
 
        :param state: The library state where the known stores are kept.
3861
 
 
3862
 
        :returns: The store received if it's not a known one, an already known
3863
 
            otherwise.
3864
 
        """
3865
 
        if state is None:
3866
 
            state = bzrlib.global_state
3867
 
        if state is None:
3868
 
            global _shared_stores_at_exit_installed
3869
 
            stores = _shared_stores
3870
 
            def save_config_changes():
3871
 
                for k, store in stores.iteritems():
3872
 
                    store.save_changes()
3873
 
            if not _shared_stores_at_exit_installed:
3874
 
                # FIXME: Ugly hack waiting for library_state to always be
3875
 
                # available. -- vila 20120731
3876
 
                import atexit
3877
 
                atexit.register(save_config_changes)
3878
 
                _shared_stores_at_exit_installed = True
3879
 
        else:
3880
 
            stores = state.config_stores
3881
 
        url = store.external_url()
3882
 
        try:
3883
 
            return stores[url]
3884
 
        except KeyError:
3885
 
            stores[url] = store
3886
 
            return store
3887
 
 
3888
3793
 
3889
3794
class MemoryStack(Stack):
3890
3795
    """A configuration stack defined from a string.
3940
3845
        self.store.save()
3941
3846
 
3942
3847
 
3943
 
class GlobalStack(Stack):
 
3848
class GlobalStack(_CompatibleStack):
3944
3849
    """Global options only stack.
3945
3850
 
3946
3851
    The following sections are queried:
3954
3859
    """
3955
3860
 
3956
3861
    def __init__(self):
3957
 
        gstore = self.get_shared_store(GlobalStore())
 
3862
        gstore = GlobalStore()
3958
3863
        super(GlobalStack, self).__init__(
3959
3864
            [self._get_overrides,
3960
3865
             NameMatcher(gstore, 'DEFAULT').get_sections],
3961
3866
            gstore, mutable_section_id='DEFAULT')
3962
3867
 
3963
3868
 
3964
 
class LocationStack(Stack):
 
3869
class LocationStack(_CompatibleStack):
3965
3870
    """Per-location options falling back to global options stack.
3966
3871
 
3967
3872
 
3983
3888
        """Make a new stack for a location and global configuration.
3984
3889
 
3985
3890
        :param location: A URL prefix to """
3986
 
        lstore = self.get_shared_store(LocationStore())
 
3891
        lstore = LocationStore()
3987
3892
        if location.startswith('file://'):
3988
3893
            location = urlutils.local_path_from_url(location)
3989
 
        gstore = self.get_shared_store(GlobalStore())
 
3894
        gstore = GlobalStore()
3990
3895
        super(LocationStack, self).__init__(
3991
3896
            [self._get_overrides,
3992
3897
             LocationMatcher(lstore, location).get_sections,
3994
3899
            lstore, mutable_section_id=location)
3995
3900
 
3996
3901
 
3997
 
class BranchStack(Stack):
 
3902
class BranchStack(_CompatibleStack):
3998
3903
    """Per-location options falling back to branch then global options stack.
3999
3904
 
4000
3905
    The following sections are queried:
4014
3919
    """
4015
3920
 
4016
3921
    def __init__(self, branch):
4017
 
        lstore = self.get_shared_store(LocationStore())
 
3922
        lstore = LocationStore()
4018
3923
        bstore = branch._get_config_store()
4019
 
        gstore = self.get_shared_store(GlobalStore())
 
3924
        gstore = GlobalStore()
4020
3925
        super(BranchStack, self).__init__(
4021
3926
            [self._get_overrides,
4022
3927
             LocationMatcher(lstore, branch.base).get_sections,
4025
3930
            bstore)
4026
3931
        self.branch = branch
4027
3932
 
4028
 
    def lock_write(self, token=None):
4029
 
        return self.branch.lock_write(token)
4030
 
 
4031
 
    def unlock(self):
4032
 
        return self.branch.unlock()
4033
 
 
4034
 
    @needs_write_lock
4035
 
    def set(self, name, value):
4036
 
        super(BranchStack, self).set(name, value)
4037
 
        # Unlocking the branch will trigger a store.save_changes() so the last
4038
 
        # unlock saves all the changes.
4039
 
 
4040
 
    @needs_write_lock
4041
 
    def remove(self, name):
4042
 
        super(BranchStack, self).remove(name)
4043
 
        # Unlocking the branch will trigger a store.save_changes() so the last
4044
 
        # unlock saves all the changes.
4045
 
 
4046
 
 
4047
 
class RemoteControlStack(Stack):
 
3933
 
 
3934
class RemoteControlStack(_CompatibleStack):
4048
3935
    """Remote control-only options stack."""
4049
3936
 
4050
3937
    # FIXME 2011-11-22 JRV This should probably be renamed to avoid confusion
4059
3946
        self.bzrdir = bzrdir
4060
3947
 
4061
3948
 
4062
 
class BranchOnlyStack(Stack):
 
3949
class BranchOnlyStack(_CompatibleStack):
4063
3950
    """Branch-only options stack."""
4064
3951
 
4065
3952
    # FIXME: _BranchOnlyStack only uses branch.conf and is used only for the
4073
3960
            bstore)
4074
3961
        self.branch = branch
4075
3962
 
4076
 
    def lock_write(self, token=None):
4077
 
        return self.branch.lock_write(token)
4078
 
 
4079
 
    def unlock(self):
4080
 
        return self.branch.unlock()
4081
 
 
4082
 
    @needs_write_lock
4083
 
    def set(self, name, value):
4084
 
        super(BranchOnlyStack, self).set(name, value)
4085
 
        # Force a write to persistent storage
4086
 
        self.store.save_changes()
4087
 
 
4088
 
    @needs_write_lock
4089
 
    def remove(self, name):
4090
 
        super(BranchOnlyStack, self).remove(name)
4091
 
        # Force a write to persistent storage
4092
 
        self.store.save_changes()
4093
 
 
 
3963
 
 
3964
# Use a an empty dict to initialize an empty configobj avoiding all
 
3965
# parsing and encoding checks
 
3966
_quoting_config = configobj.ConfigObj(
 
3967
    {}, encoding='utf-8', interpolation=False, list_values=True)
4094
3968
 
4095
3969
class cmd_config(commands.Command):
4096
3970
    __doc__ = """Display, set or remove a configuration option.
4097
3971
 
4098
 
    Display the active value for option NAME.
 
3972
    Display the active value for a given option.
4099
3973
 
4100
3974
    If --all is specified, NAME is interpreted as a regular expression and all
4101
 
    matching options are displayed mentioning their scope and without resolving
4102
 
    option references in the value). The active value that bzr will take into
4103
 
    account is the first one displayed for each option.
4104
 
 
4105
 
    If NAME is not given, --all .* is implied (all options are displayed for the
4106
 
    current scope).
4107
 
 
4108
 
    Setting a value is achieved by using NAME=value without spaces. The value
 
3975
    matching options are displayed mentioning their scope. The active value
 
3976
    that bzr will take into account is the first one displayed for each option.
 
3977
 
 
3978
    If no NAME is given, --all .* is implied.
 
3979
 
 
3980
    Setting a value is achieved by using name=value without spaces. The value
4109
3981
    is set in the most relevant scope and can be checked by displaying the
4110
3982
    option again.
4111
 
 
4112
 
    Removing a value is achieved by using --remove NAME.
4113
3983
    """
4114
3984
 
4115
3985
    takes_args = ['name?']
4136
4006
            remove=False):
4137
4007
        if directory is None:
4138
4008
            directory = '.'
4139
 
        directory = directory_service.directories.dereference(directory)
4140
4009
        directory = urlutils.normalize_url(directory)
4141
4010
        if remove and all:
4142
4011
            raise errors.BzrError(
4163
4032
                # Set the option value
4164
4033
                self._set_config_option(name, value, directory, scope)
4165
4034
 
4166
 
    def _get_stack(self, directory, scope=None, write_access=False):
 
4035
    def _get_stack(self, directory, scope=None):
4167
4036
        """Get the configuration stack specified by ``directory`` and ``scope``.
4168
4037
 
4169
4038
        :param directory: Where the configurations are derived from.
4170
4039
 
4171
4040
        :param scope: A specific config to start from.
4172
 
 
4173
 
        :param write_access: Whether a write access to the stack will be
4174
 
            attempted.
4175
4041
        """
4176
4042
        # FIXME: scope should allow access to plugin-specific stacks (even
4177
4043
        # reduced to the plugin-specific store), related to
4185
4051
                (_, br, _) = (
4186
4052
                    controldir.ControlDir.open_containing_tree_or_branch(
4187
4053
                        directory))
4188
 
                if write_access:
4189
 
                    self.add_cleanup(br.lock_write().unlock)
4190
4054
                return br.get_config_stack()
4191
4055
            raise errors.NoSuchConfig(scope)
4192
4056
        else:
4194
4058
                (_, br, _) = (
4195
4059
                    controldir.ControlDir.open_containing_tree_or_branch(
4196
4060
                        directory))
4197
 
                if write_access:
4198
 
                    self.add_cleanup(br.lock_write().unlock)
4199
4061
                return br.get_config_stack()
4200
4062
            except errors.NotBranchError:
4201
4063
                return LocationStack(directory)
4202
4064
 
4203
 
    def _quote_multiline(self, value):
4204
 
        if '\n' in value:
4205
 
            value = '"""' + value + '"""'
4206
 
        return value
4207
 
 
4208
4065
    def _show_value(self, name, directory, scope):
4209
4066
        conf = self._get_stack(directory, scope)
4210
 
        value = conf.get(name, expand=True, convert=False)
 
4067
        value = conf.get(name, expand=True)
4211
4068
        if value is not None:
4212
4069
            # Quote the value appropriately
4213
 
            value = self._quote_multiline(value)
 
4070
            value = _quoting_config._quote(value)
4214
4071
            self.outf.write('%s\n' % (value,))
4215
4072
        else:
4216
4073
            raise errors.NoSuchConfigOption(name)
4224
4081
        cur_store_id = None
4225
4082
        cur_section = None
4226
4083
        conf = self._get_stack(directory, scope)
4227
 
        for store, section in conf.iter_sections():
4228
 
            for oname in section.iter_option_names():
4229
 
                if name.search(oname):
4230
 
                    if cur_store_id != store.id:
4231
 
                        # Explain where the options are defined
4232
 
                        self.outf.write('%s:\n' % (store.id,))
4233
 
                        cur_store_id = store.id
4234
 
                        cur_section = None
4235
 
                    if (section.id is not None and cur_section != section.id):
4236
 
                        # Display the section id as it appears in the store
4237
 
                        # (None doesn't appear by definition)
4238
 
                        self.outf.write('  [%s]\n' % (section.id,))
4239
 
                        cur_section = section.id
4240
 
                    value = section.get(oname, expand=False)
4241
 
                    # Quote the value appropriately
4242
 
                    value = self._quote_multiline(value)
4243
 
                    self.outf.write('  %s = %s\n' % (oname, value))
 
4084
        for sections in conf.sections_def:
 
4085
            for store, section in sections():
 
4086
                for oname in section.iter_option_names():
 
4087
                    if name.search(oname):
 
4088
                        if cur_store_id != store.id:
 
4089
                            # Explain where the options are defined
 
4090
                            self.outf.write('%s:\n' % (store.id,))
 
4091
                            cur_store_id = store.id
 
4092
                            cur_section = None
 
4093
                        if (section.id is not None
 
4094
                            and cur_section != section.id):
 
4095
                            # Display the section id as it appears in the store
 
4096
                            # (None doesn't appear by definition)
 
4097
                            self.outf.write('  [%s]\n' % (section.id,))
 
4098
                            cur_section = section.id
 
4099
                        value = section.get(oname, expand=False)
 
4100
                        # Since we don't use the stack, we need to restore a
 
4101
                        # proper quoting.
 
4102
                        try:
 
4103
                            opt = option_registry.get(oname)
 
4104
                            value = opt.convert_from_unicode(store, value)
 
4105
                        except KeyError:
 
4106
                            value = store.unquote(value)
 
4107
                        value = _quoting_config._quote(value)
 
4108
                        self.outf.write('  %s = %s\n' % (oname, value))
4244
4109
 
4245
4110
    def _set_config_option(self, name, value, directory, scope):
4246
 
        conf = self._get_stack(directory, scope, write_access=True)
 
4111
        conf = self._get_stack(directory, scope)
4247
4112
        conf.set(name, value)
4248
 
        # Explicitly save the changes
4249
 
        conf.store.save_changes()
4250
4113
 
4251
4114
    def _remove_config_option(self, name, directory, scope):
4252
4115
        if name is None:
4253
4116
            raise errors.BzrCommandError(
4254
4117
                '--remove expects an option to remove.')
4255
 
        conf = self._get_stack(directory, scope, write_access=True)
 
4118
        conf = self._get_stack(directory, scope)
4256
4119
        try:
4257
4120
            conf.remove(name)
4258
 
            # Explicitly save the changes
4259
 
            conf.store.save_changes()
4260
4121
        except KeyError:
4261
4122
            raise errors.NoSuchConfigOption(name)
4262
4123