~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Aaron Bentley
  • Date: 2012-07-19 16:57:16 UTC
  • mto: This revision was merged to the branch mainline in revision 6540.
  • Revision ID: aaron@aaronbentley.com-20120719165716-b4iupzkb17b9l9wx
Avoid branch write lock to preserve VFS call count.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 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.
72
72
up=pull
73
73
"""
74
74
 
 
75
from __future__ import absolute_import
 
76
from cStringIO import StringIO
75
77
import os
76
 
import string
77
78
import sys
78
79
 
79
 
 
 
80
import bzrlib
80
81
from bzrlib.decorators import needs_write_lock
81
82
from bzrlib.lazy_import import lazy_import
82
83
lazy_import(globals(), """
83
84
import fnmatch
84
85
import re
85
 
from cStringIO import StringIO
86
86
 
87
87
from bzrlib import (
88
88
    atomicfile,
89
 
    bzrdir,
 
89
    controldir,
90
90
    debug,
91
91
    errors,
92
92
    lazy_regex,
 
93
    library_state,
93
94
    lockdir,
94
 
    mail_client,
95
95
    mergetools,
96
96
    osutils,
97
97
    symbol_versioning,
101
101
    urlutils,
102
102
    win32utils,
103
103
    )
 
104
from bzrlib.i18n import gettext
104
105
from bzrlib.util.configobj import configobj
105
106
""")
106
107
from bzrlib import (
149
150
STORE_GLOBAL = 4
150
151
 
151
152
 
 
153
def signature_policy_from_unicode(signature_string):
 
154
    """Convert a string to a signing policy."""
 
155
    if signature_string.lower() == 'check-available':
 
156
        return CHECK_IF_POSSIBLE
 
157
    if signature_string.lower() == 'ignore':
 
158
        return CHECK_NEVER
 
159
    if signature_string.lower() == 'require':
 
160
        return CHECK_ALWAYS
 
161
    raise ValueError("Invalid signatures policy '%s'"
 
162
                     % signature_string)
 
163
 
 
164
 
 
165
def signing_policy_from_unicode(signature_string):
 
166
    """Convert a string to a signing policy."""
 
167
    if signature_string.lower() == 'when-required':
 
168
        return SIGN_WHEN_REQUIRED
 
169
    if signature_string.lower() == 'never':
 
170
        return SIGN_NEVER
 
171
    if signature_string.lower() == 'always':
 
172
        return SIGN_ALWAYS
 
173
    raise ValueError("Invalid signing policy '%s'"
 
174
                     % signature_string)
 
175
 
 
176
 
152
177
class ConfigObj(configobj.ConfigObj):
153
178
 
154
179
    def __init__(self, infile=None, **kwargs):
170
195
        return self[section][name]
171
196
 
172
197
 
173
 
# FIXME: Until we can guarantee that each config file is loaded once and
174
 
# only once for a given bzrlib session, we don't want to re-read the file every
175
 
# time we query for an option so we cache the value (bad ! watch out for tests
176
 
# needing to restore the proper value). -- vila 20110219
177
 
_expand_default_value = None
178
 
def _get_expand_default_value():
179
 
    global _expand_default_value
180
 
    if _expand_default_value is not None:
181
 
        return _expand_default_value
182
 
    conf = GlobalConfig()
183
 
    # Note that we must not use None for the expand value below or we'll run
184
 
    # into infinite recursion. Using False really would be quite silly ;)
185
 
    expand = conf.get_user_option_as_bool('bzr.config.expand', expand=True)
186
 
    if expand is None:
187
 
        # This is an opt-in feature, you *really* need to clearly say you want
188
 
        # to activate it !
189
 
        expand = False
190
 
    _expand_default_value = expand
191
 
    return expand
192
 
 
193
 
 
194
198
class Config(object):
195
199
    """A configuration policy - what username, editor, gpg needs etc."""
196
200
 
201
205
        """Returns a unique ID for the config."""
202
206
        raise NotImplementedError(self.config_id)
203
207
 
204
 
    @deprecated_method(deprecated_in((2, 4, 0)))
205
 
    def get_editor(self):
206
 
        """Get the users pop up editor."""
207
 
        raise NotImplementedError
208
 
 
209
208
    def get_change_editor(self, old_tree, new_tree):
210
209
        from bzrlib import diff
211
210
        cmd = self._get_change_editor()
214
213
        return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
215
214
                                             sys.stdout)
216
215
 
217
 
    def get_mail_client(self):
218
 
        """Get a mail client to use"""
219
 
        selected_client = self.get_user_option('mail_client')
220
 
        _registry = mail_client.mail_client_registry
221
 
        try:
222
 
            mail_client_class = _registry.get(selected_client)
223
 
        except KeyError:
224
 
            raise errors.UnknownMailClient(selected_client)
225
 
        return mail_client_class(self)
226
 
 
227
216
    def _get_signature_checking(self):
228
217
        """Template method to override signature checking policy."""
229
218
 
358
347
        """Template method to provide a user option."""
359
348
        return None
360
349
 
361
 
    def get_user_option(self, option_name, expand=None):
 
350
    def get_user_option(self, option_name, expand=True):
362
351
        """Get a generic option - no special process, no default.
363
352
 
364
353
        :param option_name: The queried option.
367
356
 
368
357
        :returns: The value of the option.
369
358
        """
370
 
        if expand is None:
371
 
            expand = _get_expand_default_value()
372
359
        value = self._get_user_option(option_name)
373
360
        if expand:
374
361
            if isinstance(value, list):
414
401
            # add) the final ','
415
402
            l = [l]
416
403
        return l
417
 
        
418
 
    def get_user_option_as_int_from_SI(self,  option_name,  default=None):
 
404
 
 
405
    @deprecated_method(deprecated_in((2, 5, 0)))
 
406
    def get_user_option_as_int_from_SI(self, option_name, default=None):
419
407
        """Get a generic option from a human readable size in SI units, e.g 10MB
420
 
        
 
408
 
421
409
        Accepted suffixes are K,M,G. It is case-insensitive and may be followed
422
410
        by a trailing b (i.e. Kb, MB). This is intended to be practical and not
423
411
        pedantic.
424
 
        
 
412
 
425
413
        :return Integer, expanded to its base-10 value if a proper SI unit is 
426
414
            found. If the option doesn't exist, or isn't a value in 
427
415
            SI units, return default (which defaults to None)
452
440
            except TypeError:
453
441
                val = default
454
442
        return val
455
 
        
456
443
 
 
444
    @deprecated_method(deprecated_in((2, 5, 0)))
457
445
    def gpg_signing_command(self):
458
446
        """What program should be used to sign signatures?"""
459
447
        result = self._gpg_signing_command()
465
453
        """See gpg_signing_command()."""
466
454
        return None
467
455
 
 
456
    @deprecated_method(deprecated_in((2, 5, 0)))
468
457
    def log_format(self):
469
458
        """What log format should be used"""
470
459
        result = self._log_format()
489
478
        """See validate_signatures_in_log()."""
490
479
        return None
491
480
 
 
481
    @deprecated_method(deprecated_in((2, 5, 0)))
492
482
    def acceptable_keys(self):
493
483
        """Comma separated list of key patterns acceptable to 
494
484
        verify-signatures command"""
499
489
        """See acceptable_keys()."""
500
490
        return None
501
491
 
 
492
    @deprecated_method(deprecated_in((2, 5, 0)))
502
493
    def post_commit(self):
503
494
        """An ordered list of python functions to call.
504
495
 
530
521
        v = self._get_user_id()
531
522
        if v:
532
523
            return v
533
 
        v = os.environ.get('EMAIL')
534
 
        if v:
535
 
            return v.decode(osutils.get_user_encoding())
536
 
        name, email = _auto_user_id()
537
 
        if name and email:
538
 
            return '%s <%s>' % (name, email)
539
 
        elif email:
540
 
            return email
541
 
        raise errors.NoWhoami()
 
524
        return default_email()
542
525
 
543
526
    def ensure_username(self):
544
527
        """Raise errors.NoWhoami if username is not set.
547
530
        """
548
531
        self.username()
549
532
 
 
533
    @deprecated_method(deprecated_in((2, 5, 0)))
550
534
    def signature_checking(self):
551
535
        """What is the current policy for signature checking?."""
552
536
        policy = self._get_signature_checking()
554
538
            return policy
555
539
        return CHECK_IF_POSSIBLE
556
540
 
 
541
    @deprecated_method(deprecated_in((2, 5, 0)))
557
542
    def signing_policy(self):
558
543
        """What is the current policy for signature checking?."""
559
544
        policy = self._get_signing_policy()
561
546
            return policy
562
547
        return SIGN_WHEN_REQUIRED
563
548
 
 
549
    @deprecated_method(deprecated_in((2, 5, 0)))
564
550
    def signature_needed(self):
565
551
        """Is a signature needed when committing ?."""
566
552
        policy = self._get_signing_policy()
575
561
            return True
576
562
        return False
577
563
 
 
564
    @deprecated_method(deprecated_in((2, 5, 0)))
578
565
    def gpg_signing_key(self):
579
566
        """GPG user-id to sign commits"""
580
567
        key = self.get_user_option('gpg_signing_key')
622
609
        for (oname, value, section, conf_id, parser) in self._get_options():
623
610
            if oname.startswith('bzr.mergetool.'):
624
611
                tool_name = oname[len('bzr.mergetool.'):]
625
 
                tools[tool_name] = self.get_user_option(oname)
 
612
                tools[tool_name] = self.get_user_option(oname, False)
626
613
        trace.mutter('loaded merge tools: %r' % tools)
627
614
        return tools
628
615
 
865
852
        """See Config._get_signature_checking."""
866
853
        policy = self._get_user_option('check_signatures')
867
854
        if policy:
868
 
            return self._string_to_signature_policy(policy)
 
855
            return signature_policy_from_unicode(policy)
869
856
 
870
857
    def _get_signing_policy(self):
871
858
        """See Config._get_signing_policy"""
872
859
        policy = self._get_user_option('create_signatures')
873
860
        if policy:
874
 
            return self._string_to_signing_policy(policy)
 
861
            return signing_policy_from_unicode(policy)
875
862
 
876
863
    def _get_user_id(self):
877
864
        """Get the user id from the 'email' key in the current section."""
922
909
        """See Config.post_commit."""
923
910
        return self._get_user_option('post_commit')
924
911
 
925
 
    def _string_to_signature_policy(self, signature_string):
926
 
        """Convert a string to a signing policy."""
927
 
        if signature_string.lower() == 'check-available':
928
 
            return CHECK_IF_POSSIBLE
929
 
        if signature_string.lower() == 'ignore':
930
 
            return CHECK_NEVER
931
 
        if signature_string.lower() == 'require':
932
 
            return CHECK_ALWAYS
933
 
        raise errors.BzrError("Invalid signatures policy '%s'"
934
 
                              % signature_string)
935
 
 
936
 
    def _string_to_signing_policy(self, signature_string):
937
 
        """Convert a string to a signing policy."""
938
 
        if signature_string.lower() == 'when-required':
939
 
            return SIGN_WHEN_REQUIRED
940
 
        if signature_string.lower() == 'never':
941
 
            return SIGN_NEVER
942
 
        if signature_string.lower() == 'always':
943
 
            return SIGN_ALWAYS
944
 
        raise errors.BzrError("Invalid signing policy '%s'"
945
 
                              % signature_string)
946
 
 
947
912
    def _get_alias(self, value):
948
913
        try:
949
914
            return self._get_parser().get_value("ALIASES",
1086
1051
        conf._create_from_string(str_or_unicode, save)
1087
1052
        return conf
1088
1053
 
1089
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1090
 
    def get_editor(self):
1091
 
        return self._get_user_option('editor')
1092
 
 
1093
1054
    @needs_write_lock
1094
1055
    def set_user_option(self, option, value):
1095
1056
        """Save option and its value in the configuration."""
1393
1354
        e.g. "John Hacker <jhacker@example.com>"
1394
1355
        This is looked up in the email controlfile for the branch.
1395
1356
        """
1396
 
        try:
1397
 
            return (self.branch._transport.get_bytes("email")
1398
 
                    .decode(osutils.get_user_encoding())
1399
 
                    .rstrip("\r\n"))
1400
 
        except (errors.NoSuchFile, errors.PermissionDenied), e:
1401
 
            pass
1402
 
 
1403
1357
        return self._get_best_value('_get_user_id')
1404
1358
 
1405
1359
    def _get_change_editor(self):
1485
1439
        value = self._get_explicit_nickname()
1486
1440
        if value is not None:
1487
1441
            return value
 
1442
        if self.branch.name:
 
1443
            return self.branch.name
1488
1444
        return urlutils.unescape(self.branch.base.split('/')[-2])
1489
1445
 
1490
1446
    def has_explicit_nickname(self):
1527
1483
 
1528
1484
 
1529
1485
def config_dir():
1530
 
    """Return per-user configuration directory.
 
1486
    """Return per-user configuration directory as unicode string
1531
1487
 
1532
1488
    By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
1533
1489
    and Linux.  On Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
1535
1491
 
1536
1492
    TODO: Global option --config-dir to override this.
1537
1493
    """
1538
 
    base = os.environ.get('BZR_HOME', None)
 
1494
    base = osutils.path_from_environ('BZR_HOME')
1539
1495
    if sys.platform == 'win32':
1540
 
        # environ variables on Windows are in user encoding/mbcs. So decode
1541
 
        # before using one
1542
 
        if base is not None:
1543
 
            base = base.decode('mbcs')
1544
 
        if base is None:
1545
 
            base = win32utils.get_appdata_location_unicode()
1546
 
        if base is None:
1547
 
            base = os.environ.get('HOME', None)
1548
 
            if base is not None:
1549
 
                base = base.decode('mbcs')
1550
 
        if base is None:
1551
 
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
1552
 
                                  ' 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.
1553
1502
        return osutils.pathjoin(base, 'bazaar', '2.0')
1554
 
    else:
1555
 
        if base is not None:
1556
 
            base = base.decode(osutils._fs_enc)
1557
 
    if sys.platform == 'darwin':
1558
 
        if base is None:
1559
 
            # this takes into account $HOME
1560
 
            base = os.path.expanduser("~")
1561
 
        return osutils.pathjoin(base, '.bazaar')
1562
 
    else:
1563
 
        if base is None:
1564
 
            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')
1565
1507
            if xdg_dir is None:
1566
 
                xdg_dir = osutils.pathjoin(os.path.expanduser("~"), ".config")
 
1508
                xdg_dir = osutils.pathjoin(osutils._get_home_dir(), ".config")
1567
1509
            xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
1568
1510
            if osutils.isdir(xdg_dir):
1569
1511
                trace.mutter(
1570
1512
                    "Using configuration in XDG directory %s." % xdg_dir)
1571
1513
                return xdg_dir
1572
 
            base = os.path.expanduser("~")
1573
 
        return osutils.pathjoin(base, ".bazaar")
 
1514
        base = osutils._get_home_dir()
 
1515
    return osutils.pathjoin(base, ".bazaar")
1574
1516
 
1575
1517
 
1576
1518
def config_filename():
1639
1581
        f.close()
1640
1582
 
1641
1583
 
 
1584
def default_email():
 
1585
    v = os.environ.get('BZR_EMAIL')
 
1586
    if v:
 
1587
        return v.decode(osutils.get_user_encoding())
 
1588
    v = os.environ.get('EMAIL')
 
1589
    if v:
 
1590
        return v.decode(osutils.get_user_encoding())
 
1591
    name, email = _auto_user_id()
 
1592
    if name and email:
 
1593
        return u'%s <%s>' % (name, email)
 
1594
    elif email:
 
1595
        return email
 
1596
    raise errors.NoWhoami()
 
1597
 
 
1598
 
1642
1599
def _auto_user_id():
1643
1600
    """Calculate automatic user identification.
1644
1601
 
1833
1790
        :param user: login (optional)
1834
1791
 
1835
1792
        :param path: the absolute path on the server (optional)
1836
 
        
 
1793
 
1837
1794
        :param realm: the http authentication realm (optional)
1838
1795
 
1839
1796
        :return: A dict containing the matching credentials or None.
2185
2142
 
2186
2143
        It may be set to a location, or None.
2187
2144
 
2188
 
        This policy affects all branches contained by this bzrdir, except for
2189
 
        those under repositories.
 
2145
        This policy affects all branches contained by this control dir, except
 
2146
        for those under repositories.
2190
2147
        """
2191
2148
        if self._config is None:
2192
2149
            raise errors.BzrError("Cannot set configuration in %s" % self._bzrdir)
2200
2157
 
2201
2158
        This will either be a location, or None.
2202
2159
 
2203
 
        This policy affects all branches contained by this bzrdir, except for
2204
 
        those under repositories.
 
2160
        This policy affects all branches contained by this control dir, except
 
2161
        for those under repositories.
2205
2162
        """
2206
2163
        if self._config is None:
2207
2164
            return None
2319
2276
    encoutered, in which config files it can be stored.
2320
2277
    """
2321
2278
 
2322
 
    def __init__(self, name, default=None, default_from_env=None,
2323
 
                 help=None,
2324
 
                 from_unicode=None, invalid=None):
 
2279
    def __init__(self, name, override_from_env=None,
 
2280
                 default=None, default_from_env=None,
 
2281
                 help=None, from_unicode=None, invalid=None, unquote=True):
2325
2282
        """Build an option definition.
2326
2283
 
2327
2284
        :param name: the name used to refer to the option.
2328
2285
 
 
2286
        :param override_from_env: A list of environment variables which can
 
2287
           provide override any configuration setting.
 
2288
 
2329
2289
        :param default: the default value to use when none exist in the config
2330
2290
            stores. This is either a string that ``from_unicode`` will convert
2331
 
            into the proper type or a python object that can be stringified (so
2332
 
            only the empty list is supported for example).
 
2291
            into the proper type, a callable returning a unicode string so that
 
2292
            ``from_unicode`` can be used on the return value, or a python
 
2293
            object that can be stringified (so only the empty list is supported
 
2294
            for example).
2333
2295
 
2334
2296
        :param default_from_env: A list of environment variables which can
2335
2297
           provide a default value. 'default' will be used only if none of the
2347
2309
            TypeError. Accepted values are: None (ignore invalid values),
2348
2310
            'warning' (emit a warning), 'error' (emit an error message and
2349
2311
            terminates).
 
2312
 
 
2313
        :param unquote: should the unicode value be unquoted before conversion.
 
2314
           This should be used only when the store providing the values cannot
 
2315
           safely unquote them (see http://pad.lv/906897). It is provided so
 
2316
           daughter classes can handle the quoting themselves.
2350
2317
        """
 
2318
        if override_from_env is None:
 
2319
            override_from_env = []
2351
2320
        if default_from_env is None:
2352
2321
            default_from_env = []
2353
2322
        self.name = name
 
2323
        self.override_from_env = override_from_env
2354
2324
        # Convert the default value to a unicode string so all values are
2355
2325
        # strings internally before conversion (via from_unicode) is attempted.
2356
2326
        if default is None:
2361
2331
                raise AssertionError(
2362
2332
                    'Only empty lists are supported as default values')
2363
2333
            self.default = u','
2364
 
        elif isinstance(default, (str, unicode, bool, int)):
 
2334
        elif isinstance(default, (str, unicode, bool, int, float)):
2365
2335
            # Rely on python to convert strings, booleans and integers
2366
2336
            self.default = u'%s' % (default,)
 
2337
        elif callable(default):
 
2338
            self.default = default
2367
2339
        else:
2368
2340
            # other python objects are not expected
2369
2341
            raise AssertionError('%r is not supported as a default value'
2370
2342
                                 % (default,))
2371
2343
        self.default_from_env = default_from_env
2372
 
        self.help = help
 
2344
        self._help = help
2373
2345
        self.from_unicode = from_unicode
 
2346
        self.unquote = unquote
2374
2347
        if invalid and invalid not in ('warning', 'error'):
2375
2348
            raise AssertionError("%s not supported for 'invalid'" % (invalid,))
2376
2349
        self.invalid = invalid
2377
2350
 
2378
 
    def convert_from_unicode(self, unicode_value):
 
2351
    @property
 
2352
    def help(self):
 
2353
        return self._help
 
2354
 
 
2355
    def convert_from_unicode(self, store, unicode_value):
 
2356
        if self.unquote and store is not None and unicode_value is not None:
 
2357
            unicode_value = store.unquote(unicode_value)
2379
2358
        if self.from_unicode is None or unicode_value is None:
2380
2359
            # Don't convert or nothing to convert
2381
2360
            return unicode_value
2393
2372
                raise errors.ConfigOptionValueError(self.name, unicode_value)
2394
2373
        return converted
2395
2374
 
 
2375
    def get_override(self):
 
2376
        value = None
 
2377
        for var in self.override_from_env:
 
2378
            try:
 
2379
                # If the env variable is defined, its value takes precedence
 
2380
                value = os.environ[var].decode(osutils.get_user_encoding())
 
2381
                break
 
2382
            except KeyError:
 
2383
                continue
 
2384
        return value
 
2385
 
2396
2386
    def get_default(self):
2397
2387
        value = None
2398
2388
        for var in self.default_from_env:
2399
2389
            try:
2400
2390
                # If the env variable is defined, its value is the default one
2401
 
                value = os.environ[var]
 
2391
                value = os.environ[var].decode(osutils.get_user_encoding())
2402
2392
                break
2403
2393
            except KeyError:
2404
2394
                continue
2405
2395
        if value is None:
2406
2396
            # Otherwise, fallback to the value defined at registration
2407
 
            value = self.default
 
2397
            if callable(self.default):
 
2398
                value = self.default()
 
2399
                if not isinstance(value, unicode):
 
2400
                    raise AssertionError(
 
2401
                        "Callable default value for '%s' should be unicode"
 
2402
                        % (self.name))
 
2403
            else:
 
2404
                value = self.default
2408
2405
        return value
2409
2406
 
 
2407
    def get_help_topic(self):
 
2408
        return self.name
 
2409
 
2410
2410
    def get_help_text(self, additional_see_also=None, plain=True):
2411
2411
        result = self.help
2412
2412
        from bzrlib import help_topics
2426
2426
    return int(unicode_str)
2427
2427
 
2428
2428
 
 
2429
_unit_suffixes = dict(K=10**3, M=10**6, G=10**9)
 
2430
 
 
2431
def int_SI_from_store(unicode_str):
 
2432
    """Convert a human readable size in SI units, e.g 10MB into an integer.
 
2433
 
 
2434
    Accepted suffixes are K,M,G. It is case-insensitive and may be followed
 
2435
    by a trailing b (i.e. Kb, MB). This is intended to be practical and not
 
2436
    pedantic.
 
2437
 
 
2438
    :return Integer, expanded to its base-10 value if a proper SI unit is 
 
2439
        found, None otherwise.
 
2440
    """
 
2441
    regexp = "^(\d+)(([" + ''.join(_unit_suffixes) + "])b?)?$"
 
2442
    p = re.compile(regexp, re.IGNORECASE)
 
2443
    m = p.match(unicode_str)
 
2444
    val = None
 
2445
    if m is not None:
 
2446
        val, _, unit = m.groups()
 
2447
        val = int(val)
 
2448
        if unit:
 
2449
            try:
 
2450
                coeff = _unit_suffixes[unit.upper()]
 
2451
            except KeyError:
 
2452
                raise ValueError(gettext('{0} is not an SI unit.').format(unit))
 
2453
            val *= coeff
 
2454
    return val
 
2455
 
 
2456
 
 
2457
def float_from_store(unicode_str):
 
2458
    return float(unicode_str)
 
2459
 
 
2460
 
2429
2461
# Use a an empty dict to initialize an empty configobj avoiding all
2430
2462
# parsing and encoding checks
2431
2463
_list_converter_config = configobj.ConfigObj(
2432
2464
    {}, encoding='utf-8', list_values=True, interpolation=False)
2433
2465
 
2434
2466
 
2435
 
def list_from_store(unicode_str):
2436
 
    if not isinstance(unicode_str, basestring):
2437
 
        raise TypeError
2438
 
    # Now inject our string directly as unicode. All callers got their value
2439
 
    # from configobj, so values that need to be quoted are already properly
2440
 
    # quoted.
2441
 
    _list_converter_config.reset()
2442
 
    _list_converter_config._parse([u"list=%s" % (unicode_str,)])
2443
 
    maybe_list = _list_converter_config['list']
2444
 
    # ConfigObj return '' instead of u''. Use 'str' below to catch all cases.
2445
 
    if isinstance(maybe_list, basestring):
2446
 
        if maybe_list:
2447
 
            # A single value, most probably the user forgot (or didn't care to
2448
 
            # add) the final ','
2449
 
            l = [maybe_list]
 
2467
class ListOption(Option):
 
2468
 
 
2469
    def __init__(self, name, default=None, default_from_env=None,
 
2470
                 help=None, invalid=None):
 
2471
        """A list Option definition.
 
2472
 
 
2473
        This overrides the base class so the conversion from a unicode string
 
2474
        can take quoting into account.
 
2475
        """
 
2476
        super(ListOption, self).__init__(
 
2477
            name, default=default, default_from_env=default_from_env,
 
2478
            from_unicode=self.from_unicode, help=help,
 
2479
            invalid=invalid, unquote=False)
 
2480
 
 
2481
    def from_unicode(self, unicode_str):
 
2482
        if not isinstance(unicode_str, basestring):
 
2483
            raise TypeError
 
2484
        # Now inject our string directly as unicode. All callers got their
 
2485
        # value from configobj, so values that need to be quoted are already
 
2486
        # properly quoted.
 
2487
        _list_converter_config.reset()
 
2488
        _list_converter_config._parse([u"list=%s" % (unicode_str,)])
 
2489
        maybe_list = _list_converter_config['list']
 
2490
        if isinstance(maybe_list, basestring):
 
2491
            if maybe_list:
 
2492
                # A single value, most probably the user forgot (or didn't care
 
2493
                # to add) the final ','
 
2494
                l = [maybe_list]
 
2495
            else:
 
2496
                # The empty string, convert to empty list
 
2497
                l = []
2450
2498
        else:
2451
 
            # The empty string, convert to empty list
2452
 
            l = []
2453
 
    else:
2454
 
        # We rely on ConfigObj providing us with a list already
2455
 
        l = maybe_list
2456
 
    return l
 
2499
            # We rely on ConfigObj providing us with a list already
 
2500
            l = maybe_list
 
2501
        return l
 
2502
 
 
2503
 
 
2504
class RegistryOption(Option):
 
2505
    """Option for a choice from a registry."""
 
2506
 
 
2507
    def __init__(self, name, registry, default_from_env=None,
 
2508
                 help=None, invalid=None):
 
2509
        """A registry based Option definition.
 
2510
 
 
2511
        This overrides the base class so the conversion from a unicode string
 
2512
        can take quoting into account.
 
2513
        """
 
2514
        super(RegistryOption, self).__init__(
 
2515
            name, default=lambda: unicode(registry.default_key),
 
2516
            default_from_env=default_from_env,
 
2517
            from_unicode=self.from_unicode, help=help,
 
2518
            invalid=invalid, unquote=False)
 
2519
        self.registry = registry
 
2520
 
 
2521
    def from_unicode(self, unicode_str):
 
2522
        if not isinstance(unicode_str, basestring):
 
2523
            raise TypeError
 
2524
        try:
 
2525
            return self.registry.get(unicode_str)
 
2526
        except KeyError:
 
2527
            raise ValueError(
 
2528
                "Invalid value %s for %s."
 
2529
                "See help for a list of possible values." % (unicode_str,
 
2530
                    self.name))
 
2531
 
 
2532
    @property
 
2533
    def help(self):
 
2534
        ret = [self._help, "\n\nThe following values are supported:\n"]
 
2535
        for key in self.registry.keys():
 
2536
            ret.append(" %s - %s\n" % (key, self.registry.get_help(key)))
 
2537
        return "".join(ret)
2457
2538
 
2458
2539
 
2459
2540
class OptionRegistry(registry.Registry):
2500
2581
# Registered options in lexicographical order
2501
2582
 
2502
2583
option_registry.register(
 
2584
    Option('append_revisions_only',
 
2585
           default=None, from_unicode=bool_from_store, invalid='warning',
 
2586
           help='''\
 
2587
Whether to only append revisions to the mainline.
 
2588
 
 
2589
If this is set to true, then it is not possible to change the
 
2590
existing mainline of the branch.
 
2591
'''))
 
2592
option_registry.register(
 
2593
    ListOption('acceptable_keys',
 
2594
           default=None,
 
2595
           help="""\
 
2596
List of GPG key patterns which are acceptable for verification.
 
2597
"""))
 
2598
option_registry.register(
 
2599
    Option('add.maximum_file_size',
 
2600
           default=u'20MB', from_unicode=int_SI_from_store,
 
2601
           help="""\
 
2602
Size above which files should be added manually.
 
2603
 
 
2604
Files below this size are added automatically when using ``bzr add`` without
 
2605
arguments.
 
2606
 
 
2607
A negative value means disable the size check.
 
2608
"""))
 
2609
option_registry.register(
 
2610
    Option('bound',
 
2611
           default=None, from_unicode=bool_from_store,
 
2612
           help="""\
 
2613
Is the branch bound to ``bound_location``.
 
2614
 
 
2615
If set to "True", the branch should act as a checkout, and push each commit to
 
2616
the bound_location.  This option is normally set by ``bind``/``unbind``.
 
2617
 
 
2618
See also: bound_location.
 
2619
"""))
 
2620
option_registry.register(
 
2621
    Option('bound_location',
 
2622
           default=None,
 
2623
           help="""\
 
2624
The location that commits should go to when acting as a checkout.
 
2625
 
 
2626
This option is normally set by ``bind``.
 
2627
 
 
2628
See also: bound.
 
2629
"""))
 
2630
option_registry.register(
 
2631
    Option('branch.fetch_tags', default=False,  from_unicode=bool_from_store,
 
2632
           help="""\
 
2633
Whether revisions associated with tags should be fetched.
 
2634
"""))
 
2635
option_registry.register_lazy(
 
2636
    'bzr.transform.orphan_policy', 'bzrlib.transform', 'opt_transform_orphan')
 
2637
option_registry.register(
2503
2638
    Option('bzr.workingtree.worth_saving_limit', default=10,
2504
2639
           from_unicode=int_from_store,  invalid='warning',
2505
2640
           help='''\
2512
2647
a file has been touched.
2513
2648
'''))
2514
2649
option_registry.register(
 
2650
    Option('bugtracker', default=None,
 
2651
           help='''\
 
2652
Default bug tracker to use.
 
2653
 
 
2654
This bug tracker will be used for example when marking bugs
 
2655
as fixed using ``bzr commit --fixes``, if no explicit
 
2656
bug tracker was specified.
 
2657
'''))
 
2658
option_registry.register(
 
2659
    Option('check_signatures', default=CHECK_IF_POSSIBLE,
 
2660
           from_unicode=signature_policy_from_unicode,
 
2661
           help='''\
 
2662
GPG checking policy.
 
2663
 
 
2664
Possible values: require, ignore, check-available (default)
 
2665
 
 
2666
this option will control whether bzr will require good gpg
 
2667
signatures, ignore them, or check them if they are
 
2668
present.
 
2669
'''))
 
2670
option_registry.register(
 
2671
    Option('child_submit_format',
 
2672
           help='''The preferred format of submissions to this branch.'''))
 
2673
option_registry.register(
 
2674
    Option('child_submit_to',
 
2675
           help='''Where submissions to this branch are mailed to.'''))
 
2676
option_registry.register(
 
2677
    Option('create_signatures', default=SIGN_WHEN_REQUIRED,
 
2678
           from_unicode=signing_policy_from_unicode,
 
2679
           help='''\
 
2680
GPG Signing policy.
 
2681
 
 
2682
Possible values: always, never, when-required (default)
 
2683
 
 
2684
This option controls whether bzr will always create
 
2685
gpg signatures or not on commits.
 
2686
'''))
 
2687
option_registry.register(
2515
2688
    Option('dirstate.fdatasync', default=True,
2516
2689
           from_unicode=bool_from_store,
2517
2690
           help='''\
2522
2695
should not be lost if the machine crashes.  See also repository.fdatasync.
2523
2696
'''))
2524
2697
option_registry.register(
2525
 
    Option('debug_flags', default=[], from_unicode=list_from_store,
 
2698
    ListOption('debug_flags', default=[],
2526
2699
           help='Debug flags to activate.'))
2527
2700
option_registry.register(
2528
2701
    Option('default_format', default='2a',
2541
2714
    Option('editor',
2542
2715
           help='The command called to launch an editor to enter a message.'))
2543
2716
option_registry.register(
 
2717
    Option('email', override_from_env=['BZR_EMAIL'], default=default_email,
 
2718
           help='The users identity'))
 
2719
option_registry.register(
 
2720
    Option('gpg_signing_command',
 
2721
           default='gpg',
 
2722
           help="""\
 
2723
Program to use use for creating signatures.
 
2724
 
 
2725
This should support at least the -u and --clearsign options.
 
2726
"""))
 
2727
option_registry.register(
 
2728
    Option('gpg_signing_key',
 
2729
           default=None,
 
2730
           help="""\
 
2731
GPG key to use for signing.
 
2732
 
 
2733
This defaults to the first key associated with the users email.
 
2734
"""))
 
2735
option_registry.register(
2544
2736
    Option('ignore_missing_extensions', default=False,
2545
2737
           from_unicode=bool_from_store,
2546
2738
           help='''\
2564
2756
Otherwise, bzr will prompt as normal to break the lock.
2565
2757
'''))
2566
2758
option_registry.register(
 
2759
    Option('log_format', default='long',
 
2760
           help= '''\
 
2761
Log format to use when displaying revisions.
 
2762
 
 
2763
Standard log formats are ``long``, ``short`` and ``line``. Additional formats
 
2764
may be provided by plugins.
 
2765
'''))
 
2766
option_registry.register_lazy('mail_client', 'bzrlib.mail_client',
 
2767
    'opt_mail_client')
 
2768
option_registry.register(
2567
2769
    Option('output_encoding',
2568
2770
           help= 'Unicode encoding for output'
2569
2771
           ' (terminal encoding if not specified).'))
2570
2772
option_registry.register(
 
2773
    Option('parent_location',
 
2774
           default=None,
 
2775
           help="""\
 
2776
The location of the default branch for pull or merge.
 
2777
 
 
2778
This option is normally set when creating a branch, the first ``pull`` or by
 
2779
``pull --remember``.
 
2780
"""))
 
2781
option_registry.register(
 
2782
    Option('post_commit', default=None,
 
2783
           help='''\
 
2784
Post commit functions.
 
2785
 
 
2786
An ordered list of python functions to call, separated by spaces.
 
2787
 
 
2788
Each function takes branch, rev_id as parameters.
 
2789
'''))
 
2790
option_registry.register(
 
2791
    Option('public_branch',
 
2792
           default=None,
 
2793
           help="""\
 
2794
A publically-accessible version of this branch.
 
2795
 
 
2796
This implies that the branch setting this option is not publically-accessible.
 
2797
Used and set by ``bzr send``.
 
2798
"""))
 
2799
option_registry.register(
 
2800
    Option('push_location',
 
2801
           default=None,
 
2802
           help="""\
 
2803
The location of the default branch for push.
 
2804
 
 
2805
This option is normally set by the first ``push`` or ``push --remember``.
 
2806
"""))
 
2807
option_registry.register(
2571
2808
    Option('push_strict', default=None,
2572
2809
           from_unicode=bool_from_store,
2573
2810
           help='''\
2586
2823
to physical disk.  This is somewhat slower, but means data should not be
2587
2824
lost if the machine crashes.  See also dirstate.fdatasync.
2588
2825
'''))
 
2826
option_registry.register_lazy('smtp_server',
 
2827
    'bzrlib.smtp_connection', 'smtp_server')
 
2828
option_registry.register_lazy('smtp_password',
 
2829
    'bzrlib.smtp_connection', 'smtp_password')
 
2830
option_registry.register_lazy('smtp_username',
 
2831
    'bzrlib.smtp_connection', 'smtp_username')
 
2832
option_registry.register(
 
2833
    Option('selftest.timeout',
 
2834
        default='600',
 
2835
        from_unicode=int_from_store,
 
2836
        help='Abort selftest if one test takes longer than this many seconds',
 
2837
        ))
 
2838
 
2589
2839
option_registry.register(
2590
2840
    Option('send_strict', default=None,
2591
2841
           from_unicode=bool_from_store,
2593
2843
The default value for ``send --strict``.
2594
2844
 
2595
2845
If present, defines the ``--strict`` option default value for checking
2596
 
uncommitted changes before pushing.
 
2846
uncommitted changes before sending a bundle.
2597
2847
'''))
2598
2848
 
 
2849
option_registry.register(
 
2850
    Option('serve.client_timeout',
 
2851
           default=300.0, from_unicode=float_from_store,
 
2852
           help="If we wait for a new request from a client for more than"
 
2853
                " X seconds, consider the client idle, and hangup."))
 
2854
option_registry.register(
 
2855
    Option('stacked_on_location',
 
2856
           default=None,
 
2857
           help="""The location where this branch is stacked on."""))
 
2858
option_registry.register(
 
2859
    Option('submit_branch',
 
2860
           default=None,
 
2861
           help="""\
 
2862
The branch you intend to submit your current work to.
 
2863
 
 
2864
This is automatically set by ``bzr send`` and ``bzr merge``, and is also used
 
2865
by the ``submit:`` revision spec.
 
2866
"""))
 
2867
option_registry.register(
 
2868
    Option('submit_to',
 
2869
           help='''Where submissions from this branch are mailed to.'''))
 
2870
option_registry.register(
 
2871
    ListOption('suppress_warnings',
 
2872
           default=[],
 
2873
           help="List of warning classes to suppress."))
 
2874
option_registry.register(
 
2875
    Option('validate_signatures_in_log', default=False,
 
2876
           from_unicode=bool_from_store, invalid='warning',
 
2877
           help='''Whether to validate signatures in bzr log.'''))
 
2878
option_registry.register_lazy('ssl.ca_certs',
 
2879
    'bzrlib.transport.http._urllib2_wrappers', 'opt_ssl_ca_certs')
 
2880
 
 
2881
option_registry.register_lazy('ssl.cert_reqs',
 
2882
    'bzrlib.transport.http._urllib2_wrappers', 'opt_ssl_cert_reqs')
 
2883
 
2599
2884
 
2600
2885
class Section(object):
2601
2886
    """A section defines a dict of option name => value.
2610
2895
        # We re-use the dict-like object received
2611
2896
        self.options = options
2612
2897
 
2613
 
    def get(self, name, default=None):
 
2898
    def get(self, name, default=None, expand=True):
2614
2899
        return self.options.get(name, default)
2615
2900
 
 
2901
    def iter_option_names(self):
 
2902
        for k in self.options.iterkeys():
 
2903
            yield k
 
2904
 
2616
2905
    def __repr__(self):
2617
2906
        # Mostly for debugging use
2618
2907
        return "<config.%s id=%s>" % (self.__class__.__name__, self.id)
2620
2909
 
2621
2910
_NewlyCreatedOption = object()
2622
2911
"""Was the option created during the MutableSection lifetime"""
 
2912
_DeletedOption = object()
 
2913
"""Was the option deleted during the MutableSection lifetime"""
2623
2914
 
2624
2915
 
2625
2916
class MutableSection(Section):
2627
2918
 
2628
2919
    def __init__(self, section_id, options):
2629
2920
        super(MutableSection, self).__init__(section_id, options)
2630
 
        self.orig = {}
 
2921
        self.reset_changes()
2631
2922
 
2632
2923
    def set(self, name, value):
2633
2924
        if name not in self.options:
2642
2933
            self.orig[name] = self.get(name, None)
2643
2934
        del self.options[name]
2644
2935
 
 
2936
    def reset_changes(self):
 
2937
        self.orig = {}
 
2938
 
 
2939
    def apply_changes(self, dirty, store):
 
2940
        """Apply option value changes.
 
2941
 
 
2942
        ``self`` has been reloaded from the persistent storage. ``dirty``
 
2943
        contains the changes made since the previous loading.
 
2944
 
 
2945
        :param dirty: the mutable section containing the changes.
 
2946
 
 
2947
        :param store: the store containing the section
 
2948
        """
 
2949
        for k, expected in dirty.orig.iteritems():
 
2950
            actual = dirty.get(k, _DeletedOption)
 
2951
            reloaded = self.get(k, _NewlyCreatedOption)
 
2952
            if actual is _DeletedOption:
 
2953
                if k in self.options:
 
2954
                    self.remove(k)
 
2955
            else:
 
2956
                self.set(k, actual)
 
2957
            # Report concurrent updates in an ad-hoc way. This should only
 
2958
            # occurs when different processes try to update the same option
 
2959
            # which is not supported (as in: the config framework is not meant
 
2960
            # to be used as a sharing mechanism).
 
2961
            if expected != reloaded:
 
2962
                if actual is _DeletedOption:
 
2963
                    actual = '<DELETED>'
 
2964
                if reloaded is _NewlyCreatedOption:
 
2965
                    reloaded = '<CREATED>'
 
2966
                if expected is _NewlyCreatedOption:
 
2967
                    expected = '<CREATED>'
 
2968
                # Someone changed the value since we get it from the persistent
 
2969
                # storage.
 
2970
                trace.warning(gettext(
 
2971
                        "Option {0} in section {1} of {2} was changed"
 
2972
                        " from {3} to {4}. The {5} value will be saved.".format(
 
2973
                            k, self.id, store.external_url(), expected,
 
2974
                            reloaded, actual)))
 
2975
        # No need to keep track of these changes
 
2976
        self.reset_changes()
 
2977
 
2645
2978
 
2646
2979
class Store(object):
2647
2980
    """Abstract interface to persistent storage for configuration options."""
2649
2982
    readonly_section_class = Section
2650
2983
    mutable_section_class = MutableSection
2651
2984
 
 
2985
    def __init__(self):
 
2986
        # Which sections need to be saved (by section id). We use a dict here
 
2987
        # so the dirty sections can be shared by multiple callers.
 
2988
        self.dirty_sections = {}
 
2989
 
2652
2990
    def is_loaded(self):
2653
2991
        """Returns True if the Store has been loaded.
2654
2992
 
2677
3015
        """
2678
3016
        raise NotImplementedError(self.unload)
2679
3017
 
 
3018
    def quote(self, value):
 
3019
        """Quote a configuration option value for storing purposes.
 
3020
 
 
3021
        This allows Stacks to present values as they will be stored.
 
3022
        """
 
3023
        return value
 
3024
 
 
3025
    def unquote(self, value):
 
3026
        """Unquote a configuration option value into unicode.
 
3027
 
 
3028
        The received value is quoted as stored.
 
3029
        """
 
3030
        return value
 
3031
 
2680
3032
    def save(self):
2681
3033
        """Saves the Store to persistent storage."""
2682
3034
        raise NotImplementedError(self.save)
2683
3035
 
 
3036
    def _need_saving(self):
 
3037
        for s in self.dirty_sections.values():
 
3038
            if s.orig:
 
3039
                # At least one dirty section contains a modification
 
3040
                return True
 
3041
        return False
 
3042
 
 
3043
    def apply_changes(self, dirty_sections):
 
3044
        """Apply changes from dirty sections while checking for coherency.
 
3045
 
 
3046
        The Store content is discarded and reloaded from persistent storage to
 
3047
        acquire up-to-date values.
 
3048
 
 
3049
        Dirty sections are MutableSection which kept track of the value they
 
3050
        are expected to update.
 
3051
        """
 
3052
        # We need an up-to-date version from the persistent storage, unload the
 
3053
        # store. The reload will occur when needed (triggered by the first
 
3054
        # get_mutable_section() call below.
 
3055
        self.unload()
 
3056
        # Apply the changes from the preserved dirty sections
 
3057
        for section_id, dirty in dirty_sections.iteritems():
 
3058
            clean = self.get_mutable_section(section_id)
 
3059
            clean.apply_changes(dirty, self)
 
3060
        # Everything is clean now
 
3061
        self.dirty_sections = {}
 
3062
 
 
3063
    def save_changes(self):
 
3064
        """Saves the Store to persistent storage if changes occurred.
 
3065
 
 
3066
        Apply the changes recorded in the mutable sections to a store content
 
3067
        refreshed from persistent storage.
 
3068
        """
 
3069
        raise NotImplementedError(self.save_changes)
 
3070
 
2684
3071
    def external_url(self):
2685
3072
        raise NotImplementedError(self.external_url)
2686
3073
 
2687
3074
    def get_sections(self):
2688
3075
        """Returns an ordered iterable of existing sections.
2689
3076
 
2690
 
        :returns: An iterable of (name, dict).
 
3077
        :returns: An iterable of (store, section).
2691
3078
        """
2692
3079
        raise NotImplementedError(self.get_sections)
2693
3080
 
2694
 
    def get_mutable_section(self, section_name=None):
 
3081
    def get_mutable_section(self, section_id=None):
2695
3082
        """Returns the specified mutable section.
2696
3083
 
2697
 
        :param section_name: The section identifier
 
3084
        :param section_id: The section identifier
2698
3085
        """
2699
3086
        raise NotImplementedError(self.get_mutable_section)
2700
3087
 
2704
3091
                                    self.external_url())
2705
3092
 
2706
3093
 
 
3094
class CommandLineStore(Store):
 
3095
    "A store to carry command line overrides for the config options."""
 
3096
 
 
3097
    def __init__(self, opts=None):
 
3098
        super(CommandLineStore, self).__init__()
 
3099
        if opts is None:
 
3100
            opts = {}
 
3101
        self.options = {}
 
3102
        self.id = 'cmdline'
 
3103
 
 
3104
    def _reset(self):
 
3105
        # The dict should be cleared but not replaced so it can be shared.
 
3106
        self.options.clear()
 
3107
 
 
3108
    def _from_cmdline(self, overrides):
 
3109
        # Reset before accepting new definitions
 
3110
        self._reset()
 
3111
        for over in overrides:
 
3112
            try:
 
3113
                name, value = over.split('=', 1)
 
3114
            except ValueError:
 
3115
                raise errors.BzrCommandError(
 
3116
                    gettext("Invalid '%s', should be of the form 'name=value'")
 
3117
                    % (over,))
 
3118
            self.options[name] = value
 
3119
 
 
3120
    def external_url(self):
 
3121
        # Not an url but it makes debugging easier and is never needed
 
3122
        # otherwise
 
3123
        return 'cmdline'
 
3124
 
 
3125
    def get_sections(self):
 
3126
        yield self,  self.readonly_section_class(None, self.options)
 
3127
 
 
3128
 
2707
3129
class IniFileStore(Store):
2708
3130
    """A config Store using ConfigObj for storage.
2709
3131
 
2710
 
    :ivar transport: The transport object where the config file is located.
2711
 
 
2712
 
    :ivar file_name: The config file basename in the transport directory.
2713
 
 
2714
3132
    :ivar _config_obj: Private member to hold the ConfigObj instance used to
2715
3133
        serialize/deserialize the config file.
2716
3134
    """
2717
3135
 
2718
 
    def __init__(self, transport, file_name):
 
3136
    def __init__(self):
2719
3137
        """A config Store using ConfigObj for storage.
2720
 
 
2721
 
        :param transport: The transport object where the config file is located.
2722
 
 
2723
 
        :param file_name: The config file basename in the transport directory.
2724
3138
        """
2725
3139
        super(IniFileStore, self).__init__()
2726
 
        self.transport = transport
2727
 
        self.file_name = file_name
2728
3140
        self._config_obj = None
2729
3141
 
2730
3142
    def is_loaded(self):
2732
3144
 
2733
3145
    def unload(self):
2734
3146
        self._config_obj = None
 
3147
        self.dirty_sections = {}
 
3148
 
 
3149
    def _load_content(self):
 
3150
        """Load the config file bytes.
 
3151
 
 
3152
        This should be provided by subclasses
 
3153
 
 
3154
        :return: Byte string
 
3155
        """
 
3156
        raise NotImplementedError(self._load_content)
 
3157
 
 
3158
    def _save_content(self, content):
 
3159
        """Save the config file bytes.
 
3160
 
 
3161
        This should be provided by subclasses
 
3162
 
 
3163
        :param content: Config file bytes to write
 
3164
        """
 
3165
        raise NotImplementedError(self._save_content)
2735
3166
 
2736
3167
    def load(self):
2737
3168
        """Load the store from the associated file."""
2738
3169
        if self.is_loaded():
2739
3170
            return
2740
 
        try:
2741
 
            content = self.transport.get_bytes(self.file_name)
2742
 
        except errors.PermissionDenied:
2743
 
            trace.warning("Permission denied while trying to load "
2744
 
                          "configuration store %s.", self.external_url())
2745
 
            raise
 
3171
        content = self._load_content()
2746
3172
        self._load_from_string(content)
2747
3173
        for hook in ConfigHooks['load']:
2748
3174
            hook(self)
2765
3191
        except UnicodeDecodeError:
2766
3192
            raise errors.ConfigContentError(self.external_url())
2767
3193
 
 
3194
    def save_changes(self):
 
3195
        if not self.is_loaded():
 
3196
            # Nothing to save
 
3197
            return
 
3198
        if not self._need_saving():
 
3199
            return
 
3200
        # Preserve the current version
 
3201
        dirty_sections = dict(self.dirty_sections.items())
 
3202
        self.apply_changes(dirty_sections)
 
3203
        # Save to the persistent storage
 
3204
        self.save()
 
3205
 
2768
3206
    def save(self):
2769
3207
        if not self.is_loaded():
2770
3208
            # Nothing to save
2771
3209
            return
2772
3210
        out = StringIO()
2773
3211
        self._config_obj.write(out)
2774
 
        self.transport.put_bytes(self.file_name, out.getvalue())
 
3212
        self._save_content(out.getvalue())
2775
3213
        for hook in ConfigHooks['save']:
2776
3214
            hook(self)
2777
3215
 
2778
 
    def external_url(self):
2779
 
        # FIXME: external_url should really accepts an optional relpath
2780
 
        # parameter (bug #750169) :-/ -- vila 2011-04-04
2781
 
        # The following will do in the interim but maybe we don't want to
2782
 
        # expose a path here but rather a config ID and its associated
2783
 
        # object </hand wawe>.
2784
 
        return urlutils.join(self.transport.external_url(), self.file_name)
2785
 
 
2786
3216
    def get_sections(self):
2787
3217
        """Get the configobj section in the file order.
2788
3218
 
2789
 
        :returns: An iterable of (name, dict).
 
3219
        :returns: An iterable of (store, section).
2790
3220
        """
2791
3221
        # We need a loaded store
2792
3222
        try:
2796
3226
            return
2797
3227
        cobj = self._config_obj
2798
3228
        if cobj.scalars:
2799
 
            yield self.readonly_section_class(None, cobj)
 
3229
            yield self, self.readonly_section_class(None, cobj)
2800
3230
        for section_name in cobj.sections:
2801
 
            yield self.readonly_section_class(section_name, cobj[section_name])
 
3231
            yield (self,
 
3232
                   self.readonly_section_class(section_name,
 
3233
                                               cobj[section_name]))
2802
3234
 
2803
 
    def get_mutable_section(self, section_name=None):
 
3235
    def get_mutable_section(self, section_id=None):
2804
3236
        # We need a loaded store
2805
3237
        try:
2806
3238
            self.load()
2807
3239
        except errors.NoSuchFile:
2808
3240
            # The file doesn't exist, let's pretend it was empty
2809
3241
            self._load_from_string('')
2810
 
        if section_name is None:
 
3242
        if section_id in self.dirty_sections:
 
3243
            # We already created a mutable section for this id
 
3244
            return self.dirty_sections[section_id]
 
3245
        if section_id is None:
2811
3246
            section = self._config_obj
2812
3247
        else:
2813
 
            section = self._config_obj.setdefault(section_name, {})
2814
 
        return self.mutable_section_class(section_name, section)
 
3248
            section = self._config_obj.setdefault(section_id, {})
 
3249
        mutable_section = self.mutable_section_class(section_id, section)
 
3250
        # All mutable sections can become dirty
 
3251
        self.dirty_sections[section_id] = mutable_section
 
3252
        return mutable_section
 
3253
 
 
3254
    def quote(self, value):
 
3255
        try:
 
3256
            # configobj conflates automagical list values and quoting
 
3257
            self._config_obj.list_values = True
 
3258
            return self._config_obj._quote(value)
 
3259
        finally:
 
3260
            self._config_obj.list_values = False
 
3261
 
 
3262
    def unquote(self, value):
 
3263
        if value and isinstance(value, basestring):
 
3264
            # _unquote doesn't handle None nor empty strings nor anything that
 
3265
            # is not a string, really.
 
3266
            value = self._config_obj._unquote(value)
 
3267
        return value
 
3268
 
 
3269
    def external_url(self):
 
3270
        # Since an IniFileStore can be used without a file (at least in tests),
 
3271
        # it's better to provide something than raising a NotImplementedError.
 
3272
        # All daughter classes are supposed to provide an implementation
 
3273
        # anyway.
 
3274
        return 'In-Process Store, no URL'
 
3275
 
 
3276
class TransportIniFileStore(IniFileStore):
 
3277
    """IniFileStore that loads files from a transport.
 
3278
 
 
3279
    :ivar transport: The transport object where the config file is located.
 
3280
 
 
3281
    :ivar file_name: The config file basename in the transport directory.
 
3282
    """
 
3283
 
 
3284
    def __init__(self, transport, file_name):
 
3285
        """A Store using a ini file on a Transport
 
3286
 
 
3287
        :param transport: The transport object where the config file is located.
 
3288
        :param file_name: The config file basename in the transport directory.
 
3289
        """
 
3290
        super(TransportIniFileStore, self).__init__()
 
3291
        self.transport = transport
 
3292
        self.file_name = file_name
 
3293
 
 
3294
    def _load_content(self):
 
3295
        try:
 
3296
            return self.transport.get_bytes(self.file_name)
 
3297
        except errors.PermissionDenied:
 
3298
            trace.warning("Permission denied while trying to load "
 
3299
                          "configuration store %s.", self.external_url())
 
3300
            raise
 
3301
 
 
3302
    def _save_content(self, content):
 
3303
        self.transport.put_bytes(self.file_name, content)
 
3304
 
 
3305
    def external_url(self):
 
3306
        # FIXME: external_url should really accepts an optional relpath
 
3307
        # parameter (bug #750169) :-/ -- vila 2011-04-04
 
3308
        # The following will do in the interim but maybe we don't want to
 
3309
        # expose a path here but rather a config ID and its associated
 
3310
        # object </hand wawe>.
 
3311
        return urlutils.join(self.transport.external_url(), self.file_name)
2815
3312
 
2816
3313
 
2817
3314
# Note that LockableConfigObjStore inherits from ConfigObjStore because we need
2820
3317
# they may face the same issue.
2821
3318
 
2822
3319
 
2823
 
class LockableIniFileStore(IniFileStore):
 
3320
class LockableIniFileStore(TransportIniFileStore):
2824
3321
    """A ConfigObjStore using locks on save to ensure store integrity."""
2825
3322
 
2826
3323
    def __init__(self, transport, file_name, lock_dir_name=None):
2876
3373
        t = transport.get_transport_from_path(
2877
3374
            config_dir(), possible_transports=possible_transports)
2878
3375
        super(GlobalStore, self).__init__(t, 'bazaar.conf')
 
3376
        self.id = 'bazaar'
2879
3377
 
2880
3378
 
2881
3379
class LocationStore(LockableIniFileStore):
2884
3382
        t = transport.get_transport_from_path(
2885
3383
            config_dir(), possible_transports=possible_transports)
2886
3384
        super(LocationStore, self).__init__(t, 'locations.conf')
2887
 
 
2888
 
 
2889
 
class BranchStore(IniFileStore):
 
3385
        self.id = 'locations'
 
3386
 
 
3387
 
 
3388
class BranchStore(TransportIniFileStore):
2890
3389
 
2891
3390
    def __init__(self, branch):
2892
3391
        super(BranchStore, self).__init__(branch.control_transport,
2893
3392
                                          'branch.conf')
2894
3393
        self.branch = branch
2895
 
 
2896
 
    def lock_write(self, token=None):
2897
 
        return self.branch.lock_write(token)
2898
 
 
2899
 
    def unlock(self):
2900
 
        return self.branch.unlock()
2901
 
 
2902
 
    @needs_write_lock
2903
 
    def save(self):
2904
 
        # We need to be able to override the undecorated implementation
2905
 
        self.save_without_locking()
2906
 
 
2907
 
    def save_without_locking(self):
2908
 
        super(BranchStore, self).save()
 
3394
        self.id = 'branch'
2909
3395
 
2910
3396
 
2911
3397
class ControlStore(LockableIniFileStore):
2914
3400
        super(ControlStore, self).__init__(bzrdir.transport,
2915
3401
                                          'control.conf',
2916
3402
                                           lock_dir_name='branch_lock')
 
3403
        self.id = 'control'
2917
3404
 
2918
3405
 
2919
3406
class SectionMatcher(object):
2931
3418
        # sections.
2932
3419
        sections = self.store.get_sections()
2933
3420
        # Walk the revisions in the order provided
2934
 
        for s in sections:
 
3421
        for store, s in sections:
2935
3422
            if self.match(s):
2936
 
                yield s
 
3423
                yield store, s
2937
3424
 
2938
3425
    def match(self, section):
2939
3426
        """Does the proposed section match.
2957
3444
 
2958
3445
class LocationSection(Section):
2959
3446
 
2960
 
    def __init__(self, section, length, extra_path):
 
3447
    def __init__(self, section, extra_path, branch_name=None):
2961
3448
        super(LocationSection, self).__init__(section.id, section.options)
2962
 
        self.length = length
2963
3449
        self.extra_path = extra_path
 
3450
        if branch_name is None:
 
3451
            branch_name = ''
 
3452
        self.locals = {'relpath': extra_path,
 
3453
                       'basename': urlutils.basename(extra_path),
 
3454
                       'branchname': branch_name}
2964
3455
 
2965
 
    def get(self, name, default=None):
 
3456
    def get(self, name, default=None, expand=True):
2966
3457
        value = super(LocationSection, self).get(name, default)
2967
 
        if value is not None:
 
3458
        if value is not None and expand:
2968
3459
            policy_name = self.get(name + ':policy', None)
2969
3460
            policy = _policy_value.get(policy_name, POLICY_NONE)
2970
3461
            if policy == POLICY_APPENDPATH:
2971
3462
                value = urlutils.join(value, self.extra_path)
 
3463
            # expand section local options right now (since POLICY_APPENDPATH
 
3464
            # will never add options references, it's ok to expand after it).
 
3465
            chunks = []
 
3466
            for is_ref, chunk in iter_option_refs(value):
 
3467
                if not is_ref:
 
3468
                    chunks.append(chunk)
 
3469
                else:
 
3470
                    ref = chunk[1:-1]
 
3471
                    if ref in self.locals:
 
3472
                        chunks.append(self.locals[ref])
 
3473
                    else:
 
3474
                        chunks.append(chunk)
 
3475
            value = ''.join(chunks)
2972
3476
        return value
2973
3477
 
2974
3478
 
 
3479
class StartingPathMatcher(SectionMatcher):
 
3480
    """Select sections for a given location respecting the Store order."""
 
3481
 
 
3482
    # FIXME: Both local paths and urls can be used for section names as well as
 
3483
    # ``location`` to stay consistent with ``LocationMatcher`` which itself
 
3484
    # inherited the fuzziness from the previous ``LocationConfig``
 
3485
    # implementation. We probably need to revisit which encoding is allowed for
 
3486
    # both ``location`` and section names and how we normalize
 
3487
    # them. http://pad.lv/85479, http://pad.lv/437009 and http://359320 are
 
3488
    # related too. -- vila 2012-01-04
 
3489
 
 
3490
    def __init__(self, store, location):
 
3491
        super(StartingPathMatcher, self).__init__(store)
 
3492
        if location.startswith('file://'):
 
3493
            location = urlutils.local_path_from_url(location)
 
3494
        self.location = location
 
3495
 
 
3496
    def get_sections(self):
 
3497
        """Get all sections matching ``location`` in the store.
 
3498
 
 
3499
        The most generic sections are described first in the store, then more
 
3500
        specific ones can be provided for reduced scopes.
 
3501
 
 
3502
        The returned section are therefore returned in the reversed order so
 
3503
        the most specific ones can be found first.
 
3504
        """
 
3505
        location_parts = self.location.rstrip('/').split('/')
 
3506
        store = self.store
 
3507
        sections = []
 
3508
        # Later sections are more specific, they should be returned first
 
3509
        for _, section in reversed(list(store.get_sections())):
 
3510
            if section.id is None:
 
3511
                # The no-name section is always included if present
 
3512
                yield store, LocationSection(section, self.location)
 
3513
                continue
 
3514
            section_path = section.id
 
3515
            if section_path.startswith('file://'):
 
3516
                # the location is already a local path or URL, convert the
 
3517
                # section id to the same format
 
3518
                section_path = urlutils.local_path_from_url(section_path)
 
3519
            if (self.location.startswith(section_path)
 
3520
                or fnmatch.fnmatch(self.location, section_path)):
 
3521
                section_parts = section_path.rstrip('/').split('/')
 
3522
                extra_path = '/'.join(location_parts[len(section_parts):])
 
3523
                yield store, LocationSection(section, extra_path)
 
3524
 
 
3525
 
2975
3526
class LocationMatcher(SectionMatcher):
2976
3527
 
2977
3528
    def __init__(self, store, location):
2978
3529
        super(LocationMatcher, self).__init__(store)
 
3530
        url, params = urlutils.split_segment_parameters(location)
2979
3531
        if location.startswith('file://'):
2980
3532
            location = urlutils.local_path_from_url(location)
2981
3533
        self.location = location
 
3534
        branch_name = params.get('branch')
 
3535
        if branch_name is None:
 
3536
            self.branch_name = urlutils.basename(self.location)
 
3537
        else:
 
3538
            self.branch_name = urlutils.unescape(branch_name)
2982
3539
 
2983
3540
    def _get_matching_sections(self):
2984
3541
        """Get all sections matching ``location``."""
2988
3545
        all_sections = []
2989
3546
        # Filter out the no_name_section so _iter_for_location_by_parts can be
2990
3547
        # used (it assumes all sections have a name).
2991
 
        for section in self.store.get_sections():
 
3548
        for _, section in self.store.get_sections():
2992
3549
            if section.id is None:
2993
3550
                no_name_section = section
2994
3551
            else:
3001
3558
        matching_sections = []
3002
3559
        if no_name_section is not None:
3003
3560
            matching_sections.append(
3004
 
                LocationSection(no_name_section, 0, self.location))
 
3561
                (0, LocationSection(no_name_section, self.location)))
3005
3562
        for section_id, extra_path, length in filtered_sections:
3006
3563
            # a section id is unique for a given store so it's safe to take the
3007
3564
            # first matching section while iterating. Also, all filtered
3010
3567
            while True:
3011
3568
                section = iter_all_sections.next()
3012
3569
                if section_id == section.id:
3013
 
                    matching_sections.append(
3014
 
                        LocationSection(section, length, extra_path))
 
3570
                    section = LocationSection(section, extra_path,
 
3571
                                              self.branch_name)
 
3572
                    matching_sections.append((length, section))
3015
3573
                    break
3016
3574
        return matching_sections
3017
3575
 
3020
3578
        matching_sections = self._get_matching_sections()
3021
3579
        # We want the longest (aka more specific) locations first
3022
3580
        sections = sorted(matching_sections,
3023
 
                          key=lambda section: (section.length, section.id),
 
3581
                          key=lambda (length, section): (length, section.id),
3024
3582
                          reverse=True)
3025
3583
        # Sections mentioning 'ignore_parents' restrict the selection
3026
 
        for section in sections:
 
3584
        for _, section in sections:
3027
3585
            # FIXME: We really want to use as_bool below -- vila 2011-04-07
3028
3586
            ignore = section.get('ignore_parents', None)
3029
3587
            if ignore is not None:
3031
3589
            if ignore:
3032
3590
                break
3033
3591
            # Finally, we have a valid section
3034
 
            yield section
 
3592
            yield self.store, section
 
3593
 
 
3594
 
 
3595
_option_ref_re = lazy_regex.lazy_compile('({[^{}\n]+})')
 
3596
"""Describes an expandable option reference.
 
3597
 
 
3598
We want to match the most embedded reference first.
 
3599
 
 
3600
I.e. for '{{foo}}' we will get '{foo}',
 
3601
for '{bar{baz}}' we will get '{baz}'
 
3602
"""
 
3603
 
 
3604
def iter_option_refs(string):
 
3605
    # Split isolate refs so every other chunk is a ref
 
3606
    is_ref = False
 
3607
    for chunk  in _option_ref_re.split(string):
 
3608
        yield is_ref, chunk
 
3609
        is_ref = not is_ref
3035
3610
 
3036
3611
 
3037
3612
class Stack(object):
3038
3613
    """A stack of configurations where an option can be defined"""
3039
3614
 
3040
 
    _option_ref_re = lazy_regex.lazy_compile('({[^{}]+})')
3041
 
    """Describes an exandable option reference.
3042
 
 
3043
 
    We want to match the most embedded reference first.
3044
 
 
3045
 
    I.e. for '{{foo}}' we will get '{foo}',
3046
 
    for '{bar{baz}}' we will get '{baz}'
3047
 
    """
3048
 
 
3049
 
    def __init__(self, sections_def, store=None, mutable_section_name=None):
 
3615
    def __init__(self, sections_def, store=None, mutable_section_id=None):
3050
3616
        """Creates a stack of sections with an optional store for changes.
3051
3617
 
3052
3618
        :param sections_def: A list of Section or callables that returns an
3056
3622
        :param store: The optional Store where modifications will be
3057
3623
            recorded. If none is specified, no modifications can be done.
3058
3624
 
3059
 
        :param mutable_section_name: The name of the MutableSection where
3060
 
            changes are recorded. This requires the ``store`` parameter to be
 
3625
        :param mutable_section_id: The id of the MutableSection where changes
 
3626
            are recorded. This requires the ``store`` parameter to be
3061
3627
            specified.
3062
3628
        """
3063
3629
        self.sections_def = sections_def
3064
3630
        self.store = store
3065
 
        self.mutable_section_name = mutable_section_name
3066
 
 
3067
 
    def get(self, name, expand=None):
 
3631
        self.mutable_section_id = mutable_section_id
 
3632
 
 
3633
    def iter_sections(self):
 
3634
        """Iterate all the defined sections."""
 
3635
        # Ensuring lazy loading is achieved by delaying section matching (which
 
3636
        # implies querying the persistent storage) until it can't be avoided
 
3637
        # anymore by using callables to describe (possibly empty) section
 
3638
        # lists.
 
3639
        for sections in self.sections_def:
 
3640
            for store, section in sections():
 
3641
                yield store, section
 
3642
 
 
3643
    def get(self, name, expand=True, convert=True):
3068
3644
        """Return the *first* option value found in the sections.
3069
3645
 
3070
3646
        This is where we guarantee that sections coming from Store are loaded
3077
3653
 
3078
3654
        :param expand: Whether options references should be expanded.
3079
3655
 
 
3656
        :param convert: Whether the option value should be converted from
 
3657
            unicode (do nothing for non-registered options).
 
3658
 
3080
3659
        :returns: The value of the option.
3081
3660
        """
3082
3661
        # FIXME: No caching of options nor sections yet -- vila 20110503
3083
 
        if expand is None:
3084
 
            expand = _get_expand_default_value()
3085
3662
        value = None
3086
 
        # Ensuring lazy loading is achieved by delaying section matching (which
3087
 
        # implies querying the persistent storage) until it can't be avoided
3088
 
        # anymore by using callables to describe (possibly empty) section
3089
 
        # lists.
3090
 
        for section_or_callable in self.sections_def:
3091
 
            # Each section can expand to multiple ones when a callable is used
3092
 
            if callable(section_or_callable):
3093
 
                sections = section_or_callable()
3094
 
            else:
3095
 
                sections = [section_or_callable]
3096
 
            for section in sections:
3097
 
                value = section.get(name)
3098
 
                if value is not None:
3099
 
                    break
3100
 
            if value is not None:
3101
 
                break
 
3663
        found_store = None # Where the option value has been found
3102
3664
        # If the option is registered, it may provide additional info about
3103
3665
        # value handling
3104
3666
        try:
3106
3668
        except KeyError:
3107
3669
            # Not registered
3108
3670
            opt = None
 
3671
 
3109
3672
        def expand_and_convert(val):
3110
 
            # This may need to be called twice if the value is None or ends up
3111
 
            # being None during expansion or conversion.
 
3673
            # This may need to be called in different contexts if the value is
 
3674
            # None or ends up being None during expansion or conversion.
3112
3675
            if val is not None:
3113
3676
                if expand:
3114
3677
                    if isinstance(val, basestring):
3117
3680
                        trace.warning('Cannot expand "%s":'
3118
3681
                                      ' %s does not support option expansion'
3119
3682
                                      % (name, type(val)))
3120
 
                if opt is not None:
3121
 
                    val = opt.convert_from_unicode(val)
 
3683
                if opt is None:
 
3684
                    val = found_store.unquote(val)
 
3685
                elif convert:
 
3686
                    val = opt.convert_from_unicode(found_store, val)
3122
3687
            return val
3123
 
        value = expand_and_convert(value)
3124
 
        if opt is not None and value is None:
3125
 
            # If the option is registered, it may provide a default value
3126
 
            value = opt.get_default()
3127
 
            value = expand_and_convert(value)
 
3688
 
 
3689
        # First of all, check if the environment can override the configuration
 
3690
        # value
 
3691
        if opt is not None and opt.override_from_env:
 
3692
            value = opt.get_override()
 
3693
            value = expand_and_convert(value)
 
3694
        if value is None:
 
3695
            for store, section in self.iter_sections():
 
3696
                value = section.get(name)
 
3697
                if value is not None:
 
3698
                    found_store = store
 
3699
                    break
 
3700
            value = expand_and_convert(value)
 
3701
            if opt is not None and value is None:
 
3702
                # If the option is registered, it may provide a default value
 
3703
                value = opt.get_default()
 
3704
                value = expand_and_convert(value)
3128
3705
        for hook in ConfigHooks['get']:
3129
3706
            hook(self, name, value)
3130
3707
        return value
3163
3740
        result = string
3164
3741
        # We need to iterate until no more refs appear ({{foo}} will need two
3165
3742
        # iterations for example).
3166
 
        while True:
3167
 
            raw_chunks = Stack._option_ref_re.split(result)
3168
 
            if len(raw_chunks) == 1:
3169
 
                # Shorcut the trivial case: no refs
3170
 
                return result
 
3743
        expanded = True
 
3744
        while expanded:
 
3745
            expanded = False
3171
3746
            chunks = []
3172
 
            # Split will isolate refs so that every other chunk is a ref
3173
 
            chunk_is_ref = False
3174
 
            for chunk in raw_chunks:
3175
 
                if not chunk_is_ref:
 
3747
            for is_ref, chunk in iter_option_refs(result):
 
3748
                if not is_ref:
3176
3749
                    chunks.append(chunk)
3177
 
                    chunk_is_ref = True
3178
3750
                else:
 
3751
                    expanded = True
3179
3752
                    name = chunk[1:-1]
3180
3753
                    if name in _refs:
3181
3754
                        raise errors.OptionExpansionLoop(string, _refs)
3185
3758
                        raise errors.ExpandingUnknownOption(name, string)
3186
3759
                    chunks.append(value)
3187
3760
                    _refs.pop()
3188
 
                    chunk_is_ref = False
3189
3761
            result = ''.join(chunks)
3190
3762
        return result
3191
3763
 
3195
3767
            # anything else
3196
3768
            value = env[name]
3197
3769
        else:
3198
 
            # FIXME: This is a limited implementation, what we really need is a
3199
 
            # way to query the bzr config for the value of an option,
3200
 
            # respecting the scope rules (That is, once we implement fallback
3201
 
            # configs, getting the option value should restart from the top
3202
 
            # config, not the current one) -- vila 20101222
3203
 
            value = self.get(name, expand=False)
 
3770
            value = self.get(name, expand=False, convert=False)
3204
3771
            value = self._expand_options_in_string(value, env, _refs)
3205
3772
        return value
3206
3773
 
3210
3777
        This is where we guarantee that the mutable section is lazily loaded:
3211
3778
        this means we won't load the corresponding store before setting a value
3212
3779
        or deleting an option. In practice the store will often be loaded but
3213
 
        this allows helps catching some programming errors.
 
3780
        this helps catching some programming errors.
3214
3781
        """
3215
 
        section = self.store.get_mutable_section(self.mutable_section_name)
3216
 
        return section
 
3782
        store = self.store
 
3783
        section = store.get_mutable_section(self.mutable_section_id)
 
3784
        return store, section
3217
3785
 
3218
3786
    def set(self, name, value):
3219
3787
        """Set a new value for the option."""
3220
 
        section = self._get_mutable_section()
3221
 
        section.set(name, value)
 
3788
        store, section = self._get_mutable_section()
 
3789
        section.set(name, store.quote(value))
3222
3790
        for hook in ConfigHooks['set']:
3223
3791
            hook(self, name, value)
3224
3792
 
3225
3793
    def remove(self, name):
3226
3794
        """Remove an existing option."""
3227
 
        section = self._get_mutable_section()
 
3795
        _, section = self._get_mutable_section()
3228
3796
        section.remove(name)
3229
3797
        for hook in ConfigHooks['remove']:
3230
3798
            hook(self, name)
3233
3801
        # Mostly for debugging use
3234
3802
        return "<config.%s(%s)>" % (self.__class__.__name__, id(self))
3235
3803
 
 
3804
    def _get_overrides(self):
 
3805
        # Hack around library_state.initialize never called
 
3806
        if bzrlib.global_state is not None:
 
3807
            return bzrlib.global_state.cmdline_overrides.get_sections()
 
3808
        return []
 
3809
 
 
3810
 
 
3811
class MemoryStack(Stack):
 
3812
    """A configuration stack defined from a string.
 
3813
 
 
3814
    This is mainly intended for tests and requires no disk resources.
 
3815
    """
 
3816
 
 
3817
    def __init__(self, content=None):
 
3818
        """Create an in-memory stack from a given content.
 
3819
 
 
3820
        It uses a single store based on configobj and support reading and
 
3821
        writing options.
 
3822
 
 
3823
        :param content: The initial content of the store. If None, the store is
 
3824
            not loaded and ``_load_from_string`` can and should be used if
 
3825
            needed.
 
3826
        """
 
3827
        store = IniFileStore()
 
3828
        if content is not None:
 
3829
            store._load_from_string(content)
 
3830
        super(MemoryStack, self).__init__(
 
3831
            [store.get_sections], store)
 
3832
 
3236
3833
 
3237
3834
class _CompatibleStack(Stack):
3238
3835
    """Place holder for compatibility with previous design.
3243
3840
    One assumption made here is that the daughter classes will all use Stores
3244
3841
    derived from LockableIniFileStore).
3245
3842
 
3246
 
    It implements set() by re-loading the store before applying the
3247
 
    modification and saving it.
 
3843
    It implements set() and remove () by re-loading the store before applying
 
3844
    the modification and saving it.
3248
3845
 
3249
3846
    The long term plan being to implement a single write by store to save
3250
3847
    all modifications, this class should not be used in the interim.
3257
3854
        # Force a write to persistent storage
3258
3855
        self.store.save()
3259
3856
 
 
3857
    def remove(self, name):
 
3858
        # Force a reload
 
3859
        self.store.unload()
 
3860
        super(_CompatibleStack, self).remove(name)
 
3861
        # Force a write to persistent storage
 
3862
        self.store.save()
 
3863
 
3260
3864
 
3261
3865
class GlobalStack(_CompatibleStack):
3262
 
    """Global options only stack."""
 
3866
    """Global options only stack.
 
3867
 
 
3868
    The following sections are queried:
 
3869
 
 
3870
    * command-line overrides,
 
3871
 
 
3872
    * the 'DEFAULT' section in bazaar.conf
 
3873
 
 
3874
    This stack will use the ``DEFAULT`` section in bazaar.conf as its
 
3875
    MutableSection.
 
3876
    """
3263
3877
 
3264
3878
    def __init__(self):
3265
 
        # Get a GlobalStore
3266
3879
        gstore = GlobalStore()
3267
 
        super(GlobalStack, self).__init__([gstore.get_sections], gstore)
 
3880
        super(GlobalStack, self).__init__(
 
3881
            [self._get_overrides,
 
3882
             NameMatcher(gstore, 'DEFAULT').get_sections],
 
3883
            gstore, mutable_section_id='DEFAULT')
3268
3884
 
3269
3885
 
3270
3886
class LocationStack(_CompatibleStack):
3271
 
    """Per-location options falling back to global options stack."""
 
3887
    """Per-location options falling back to global options stack.
 
3888
 
 
3889
 
 
3890
    The following sections are queried:
 
3891
 
 
3892
    * command-line overrides,
 
3893
 
 
3894
    * the sections matching ``location`` in ``locations.conf``, the order being
 
3895
      defined by the number of path components in the section glob, higher
 
3896
      numbers first (from most specific section to most generic).
 
3897
 
 
3898
    * the 'DEFAULT' section in bazaar.conf
 
3899
 
 
3900
    This stack will use the ``location`` section in locations.conf as its
 
3901
    MutableSection.
 
3902
    """
3272
3903
 
3273
3904
    def __init__(self, location):
3274
3905
        """Make a new stack for a location and global configuration.
3275
 
        
 
3906
 
3276
3907
        :param location: A URL prefix to """
3277
3908
        lstore = LocationStore()
3278
 
        matcher = LocationMatcher(lstore, location)
 
3909
        if location.startswith('file://'):
 
3910
            location = urlutils.local_path_from_url(location)
3279
3911
        gstore = GlobalStore()
3280
3912
        super(LocationStack, self).__init__(
3281
 
            [matcher.get_sections, gstore.get_sections], lstore)
3282
 
 
3283
 
 
3284
 
class BranchStack(_CompatibleStack):
3285
 
    """Per-location options falling back to branch then global options stack."""
 
3913
            [self._get_overrides,
 
3914
             LocationMatcher(lstore, location).get_sections,
 
3915
             NameMatcher(gstore, 'DEFAULT').get_sections],
 
3916
            lstore, mutable_section_id=location)
 
3917
 
 
3918
 
 
3919
class BranchStack(Stack):
 
3920
    """Per-location options falling back to branch then global options stack.
 
3921
 
 
3922
    The following sections are queried:
 
3923
 
 
3924
    * command-line overrides,
 
3925
 
 
3926
    * the sections matching ``location`` in ``locations.conf``, the order being
 
3927
      defined by the number of path components in the section glob, higher
 
3928
      numbers first (from most specific section to most generic),
 
3929
 
 
3930
    * the no-name section in branch.conf,
 
3931
 
 
3932
    * the ``DEFAULT`` section in ``bazaar.conf``.
 
3933
 
 
3934
    This stack will use the no-name section in ``branch.conf`` as its
 
3935
    MutableSection.
 
3936
    """
3286
3937
 
3287
3938
    def __init__(self, branch):
3288
 
        bstore = BranchStore(branch)
3289
3939
        lstore = LocationStore()
3290
 
        matcher = LocationMatcher(lstore, branch.base)
 
3940
        bstore = branch._get_config_store()
3291
3941
        gstore = GlobalStore()
3292
3942
        super(BranchStack, self).__init__(
3293
 
            [matcher.get_sections, bstore.get_sections, gstore.get_sections],
 
3943
            [self._get_overrides,
 
3944
             LocationMatcher(lstore, branch.base).get_sections,
 
3945
             NameMatcher(bstore, None).get_sections,
 
3946
             NameMatcher(gstore, 'DEFAULT').get_sections],
3294
3947
            bstore)
3295
3948
        self.branch = branch
3296
3949
 
 
3950
    def lock_write(self, token=None):
 
3951
        return self.branch.lock_write(token)
 
3952
 
 
3953
    def unlock(self):
 
3954
        return self.branch.unlock()
 
3955
 
 
3956
    @needs_write_lock
 
3957
    def set(self, name, value):
 
3958
        super(BranchStack, self).set(name, value)
 
3959
        # Unlocking the branch will trigger a store.save_changes() so the last
 
3960
        # unlock saves all the changes.
 
3961
 
 
3962
    @needs_write_lock
 
3963
    def remove(self, name):
 
3964
        super(BranchStack, self).remove(name)
 
3965
        # Unlocking the branch will trigger a store.save_changes() so the last
 
3966
        # unlock saves all the changes.
 
3967
 
3297
3968
 
3298
3969
class RemoteControlStack(_CompatibleStack):
3299
3970
    """Remote control-only options stack."""
3300
3971
 
 
3972
    # FIXME 2011-11-22 JRV This should probably be renamed to avoid confusion
 
3973
    # with the stack used for remote bzr dirs. RemoteControlStack only uses
 
3974
    # control.conf and is used only for stack options.
 
3975
 
3301
3976
    def __init__(self, bzrdir):
3302
 
        cstore = ControlStore(bzrdir)
 
3977
        cstore = bzrdir._get_config_store()
3303
3978
        super(RemoteControlStack, self).__init__(
3304
 
            [cstore.get_sections],
 
3979
            [NameMatcher(cstore, None).get_sections],
3305
3980
            cstore)
3306
3981
        self.bzrdir = bzrdir
3307
3982
 
3308
3983
 
3309
 
class RemoteBranchStack(_CompatibleStack):
3310
 
    """Remote branch-only options stack."""
 
3984
class BranchOnlyStack(Stack):
 
3985
    """Branch-only options stack."""
 
3986
 
 
3987
    # FIXME: _BranchOnlyStack only uses branch.conf and is used only for the
 
3988
    # stacked_on_location options waiting for http://pad.lv/832042 to be fixed.
 
3989
    # -- vila 2011-12-16
3311
3990
 
3312
3991
    def __init__(self, branch):
3313
 
        bstore = BranchStore(branch)
3314
 
        super(RemoteBranchStack, self).__init__(
3315
 
            [bstore.get_sections],
 
3992
        bstore = branch._get_config_store()
 
3993
        super(BranchOnlyStack, self).__init__(
 
3994
            [NameMatcher(bstore, None).get_sections],
3316
3995
            bstore)
3317
3996
        self.branch = branch
3318
3997
 
 
3998
    def lock_write(self, token=None):
 
3999
        return self.branch.lock_write(token)
 
4000
 
 
4001
    def unlock(self):
 
4002
        return self.branch.unlock()
 
4003
 
 
4004
    @needs_write_lock
 
4005
    def set(self, name, value):
 
4006
        super(BranchOnlyStack, self).set(name, value)
 
4007
        # Force a write to persistent storage
 
4008
        self.store.save_changes()
 
4009
 
 
4010
    @needs_write_lock
 
4011
    def remove(self, name):
 
4012
        super(BranchOnlyStack, self).remove(name)
 
4013
        # Force a write to persistent storage
 
4014
        self.store.save_changes()
 
4015
 
3319
4016
 
3320
4017
class cmd_config(commands.Command):
3321
4018
    __doc__ = """Display, set or remove a configuration option.
3338
4035
    takes_options = [
3339
4036
        'directory',
3340
4037
        # FIXME: This should be a registry option so that plugins can register
3341
 
        # their own config files (or not) -- vila 20101002
 
4038
        # their own config files (or not) and will also address
 
4039
        # http://pad.lv/788991 -- vila 20101115
3342
4040
        commands.Option('scope', help='Reduce the scope to the specified'
3343
 
                        ' configuration file',
 
4041
                        ' configuration file.',
3344
4042
                        type=unicode),
3345
4043
        commands.Option('all',
3346
4044
            help='Display all the defined values for the matching options.',
3347
4045
            ),
3348
4046
        commands.Option('remove', help='Remove the option from'
3349
 
                        ' the configuration file'),
 
4047
                        ' the configuration file.'),
3350
4048
        ]
3351
4049
 
3352
4050
    _see_also = ['configuration']
3382
4080
                # Set the option value
3383
4081
                self._set_config_option(name, value, directory, scope)
3384
4082
 
3385
 
    def _get_configs(self, directory, scope=None):
3386
 
        """Iterate the configurations specified by ``directory`` and ``scope``.
 
4083
    def _get_stack(self, directory, scope=None, write_access=False):
 
4084
        """Get the configuration stack specified by ``directory`` and ``scope``.
3387
4085
 
3388
4086
        :param directory: Where the configurations are derived from.
3389
4087
 
3390
4088
        :param scope: A specific config to start from.
 
4089
 
 
4090
        :param write_access: Whether a write access to the stack will be
 
4091
            attempted.
3391
4092
        """
 
4093
        # FIXME: scope should allow access to plugin-specific stacks (even
 
4094
        # reduced to the plugin-specific store), related to
 
4095
        # http://pad.lv/788991 -- vila 2011-11-15
3392
4096
        if scope is not None:
3393
4097
            if scope == 'bazaar':
3394
 
                yield GlobalConfig()
 
4098
                return GlobalStack()
3395
4099
            elif scope == 'locations':
3396
 
                yield LocationConfig(directory)
 
4100
                return LocationStack(directory)
3397
4101
            elif scope == 'branch':
3398
 
                (_, br, _) = bzrdir.BzrDir.open_containing_tree_or_branch(
3399
 
                    directory)
3400
 
                yield br.get_config()
 
4102
                (_, br, _) = (
 
4103
                    controldir.ControlDir.open_containing_tree_or_branch(
 
4104
                        directory))
 
4105
                if write_access:
 
4106
                    self.add_cleanup(br.lock_write().unlock)
 
4107
                return br.get_config_stack()
 
4108
            raise errors.NoSuchConfig(scope)
3401
4109
        else:
3402
4110
            try:
3403
 
                (_, br, _) = bzrdir.BzrDir.open_containing_tree_or_branch(
3404
 
                    directory)
3405
 
                yield br.get_config()
 
4111
                (_, br, _) = (
 
4112
                    controldir.ControlDir.open_containing_tree_or_branch(
 
4113
                        directory))
 
4114
                if write_access:
 
4115
                    self.add_cleanup(br.lock_write().unlock)
 
4116
                return br.get_config_stack()
3406
4117
            except errors.NotBranchError:
3407
 
                yield LocationConfig(directory)
3408
 
                yield GlobalConfig()
 
4118
                return LocationStack(directory)
 
4119
 
 
4120
    def _quote_multiline(self, value):
 
4121
        if '\n' in value:
 
4122
            value = '"""' + value + '"""'
 
4123
        return value
3409
4124
 
3410
4125
    def _show_value(self, name, directory, scope):
3411
 
        displayed = False
3412
 
        for c in self._get_configs(directory, scope):
3413
 
            if displayed:
3414
 
                break
3415
 
            for (oname, value, section, conf_id, parser) in c._get_options():
3416
 
                if name == oname:
3417
 
                    # Display only the first value and exit
3418
 
 
3419
 
                    # FIXME: We need to use get_user_option to take policies
3420
 
                    # into account and we need to make sure the option exists
3421
 
                    # too (hence the two for loops), this needs a better API
3422
 
                    # -- vila 20101117
3423
 
                    value = c.get_user_option(name)
3424
 
                    # Quote the value appropriately
3425
 
                    value = parser._quote(value)
3426
 
                    self.outf.write('%s\n' % (value,))
3427
 
                    displayed = True
3428
 
                    break
3429
 
        if not displayed:
 
4126
        conf = self._get_stack(directory, scope)
 
4127
        value = conf.get(name, expand=True, convert=False)
 
4128
        if value is not None:
 
4129
            # Quote the value appropriately
 
4130
            value = self._quote_multiline(value)
 
4131
            self.outf.write('%s\n' % (value,))
 
4132
        else:
3430
4133
            raise errors.NoSuchConfigOption(name)
3431
4134
 
3432
4135
    def _show_matching_options(self, name, directory, scope):
3435
4138
        # avoid the delay introduced by the lazy regexp.  But, we still do
3436
4139
        # want the nicer errors raised by lazy_regex.
3437
4140
        name._compile_and_collapse()
3438
 
        cur_conf_id = None
 
4141
        cur_store_id = None
3439
4142
        cur_section = None
3440
 
        for c in self._get_configs(directory, scope):
3441
 
            for (oname, value, section, conf_id, parser) in c._get_options():
 
4143
        conf = self._get_stack(directory, scope)
 
4144
        for store, section in conf.iter_sections():
 
4145
            for oname in section.iter_option_names():
3442
4146
                if name.search(oname):
3443
 
                    if cur_conf_id != conf_id:
 
4147
                    if cur_store_id != store.id:
3444
4148
                        # Explain where the options are defined
3445
 
                        self.outf.write('%s:\n' % (conf_id,))
3446
 
                        cur_conf_id = conf_id
 
4149
                        self.outf.write('%s:\n' % (store.id,))
 
4150
                        cur_store_id = store.id
3447
4151
                        cur_section = None
3448
 
                    if (section not in (None, 'DEFAULT')
3449
 
                        and cur_section != section):
3450
 
                        # Display the section if it's not the default (or only)
3451
 
                        # one.
3452
 
                        self.outf.write('  [%s]\n' % (section,))
3453
 
                        cur_section = section
 
4152
                    if (section.id is not None and cur_section != section.id):
 
4153
                        # Display the section id as it appears in the store
 
4154
                        # (None doesn't appear by definition)
 
4155
                        self.outf.write('  [%s]\n' % (section.id,))
 
4156
                        cur_section = section.id
 
4157
                    value = section.get(oname, expand=False)
 
4158
                    # Quote the value appropriately
 
4159
                    value = self._quote_multiline(value)
3454
4160
                    self.outf.write('  %s = %s\n' % (oname, value))
3455
4161
 
3456
4162
    def _set_config_option(self, name, value, directory, scope):
3457
 
        for conf in self._get_configs(directory, scope):
3458
 
            conf.set_user_option(name, value)
3459
 
            break
3460
 
        else:
3461
 
            raise errors.NoSuchConfig(scope)
 
4163
        conf = self._get_stack(directory, scope, write_access=True)
 
4164
        conf.set(name, value)
3462
4165
 
3463
4166
    def _remove_config_option(self, name, directory, scope):
3464
4167
        if name is None:
3465
4168
            raise errors.BzrCommandError(
3466
4169
                '--remove expects an option to remove.')
3467
 
        removed = False
3468
 
        for conf in self._get_configs(directory, scope):
3469
 
            for (section_name, section, conf_id) in conf._get_sections():
3470
 
                if scope is not None and conf_id != scope:
3471
 
                    # Not the right configuration file
3472
 
                    continue
3473
 
                if name in section:
3474
 
                    if conf_id != conf.config_id():
3475
 
                        conf = self._get_configs(directory, conf_id).next()
3476
 
                    # We use the first section in the first config where the
3477
 
                    # option is defined to remove it
3478
 
                    conf.remove_user_option(name, section_name)
3479
 
                    removed = True
3480
 
                    break
3481
 
            break
3482
 
        else:
3483
 
            raise errors.NoSuchConfig(scope)
3484
 
        if not removed:
 
4170
        conf = self._get_stack(directory, scope, write_access=True)
 
4171
        try:
 
4172
            conf.remove(name)
 
4173
        except KeyError:
3485
4174
            raise errors.NoSuchConfigOption(name)
3486
4175
 
 
4176
 
3487
4177
# Test registries
3488
4178
#
3489
4179
# We need adapters that can build a Store or a Stack in a test context. Test
3492
4182
# ready-to-use store or stack.  Plugins that define new store/stacks can also
3493
4183
# register themselves here to be tested against the tests defined in
3494
4184
# bzrlib.tests.test_config. Note that the builder can be called multiple times
3495
 
# for the same tests.
 
4185
# for the same test.
3496
4186
 
3497
4187
# The registered object should be a callable receiving a test instance
3498
4188
# parameter (inheriting from tests.TestCaseWithTransport) and returning a Store