~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Patch Queue Manager
  • Date: 2012-09-05 20:52:26 UTC
  • mfrom: (6549.3.1 dev_2.5_integration)
  • Revision ID: pqm@pqm.ubuntu.com-20120905205226-8s3bzolvduug3ifj
(gz) Merge 2.5 (Martin Packman)

Show diffs side-by-side

added added

removed removed

Lines of Context:
55
55
                   turns on create_signatures.
56
56
create_signatures - this option controls whether bzr will always create
57
57
                    gpg signatures or not on commits.  There is an unused
58
 
                    option which in future is expected to work if               
 
58
                    option which in future is expected to work if
59
59
                    branch settings require signatures.
60
60
log_format - this option sets the default log format.  Possible values are
61
61
             long, short, line, or a plugin can register new formats.
81
81
from bzrlib.decorators import needs_write_lock
82
82
from bzrlib.lazy_import import lazy_import
83
83
lazy_import(globals(), """
 
84
import base64
84
85
import fnmatch
85
86
import re
86
87
 
88
89
    atomicfile,
89
90
    controldir,
90
91
    debug,
 
92
    directory_service,
91
93
    errors,
92
94
    lazy_regex,
93
95
    library_state,
94
96
    lockdir,
95
 
    mail_client,
96
97
    mergetools,
97
98
    osutils,
98
99
    symbol_versioning,
196
197
        return self[section][name]
197
198
 
198
199
 
199
 
# FIXME: Until we can guarantee that each config file is loaded once and
200
 
# only once for a given bzrlib session, we don't want to re-read the file every
201
 
# time we query for an option so we cache the value (bad ! watch out for tests
202
 
# needing to restore the proper value). -- vila 20110219
203
 
_expand_default_value = None
204
 
def _get_expand_default_value():
205
 
    global _expand_default_value
206
 
    if _expand_default_value is not None:
207
 
        return _expand_default_value
208
 
    conf = GlobalConfig()
209
 
    # Note that we must not use None for the expand value below or we'll run
210
 
    # into infinite recursion. Using False really would be quite silly ;)
211
 
    expand = conf.get_user_option_as_bool('bzr.config.expand', expand=True)
212
 
    if expand is None:
213
 
        # This is an opt-in feature, you *really* need to clearly say you want
214
 
        # to activate it !
215
 
        expand = False
216
 
    _expand_default_value = expand
217
 
    return expand
218
 
 
219
 
 
220
200
class Config(object):
221
201
    """A configuration policy - what username, editor, gpg needs etc."""
222
202
 
227
207
        """Returns a unique ID for the config."""
228
208
        raise NotImplementedError(self.config_id)
229
209
 
230
 
    @deprecated_method(deprecated_in((2, 4, 0)))
231
 
    def get_editor(self):
232
 
        """Get the users pop up editor."""
233
 
        raise NotImplementedError
234
 
 
235
210
    def get_change_editor(self, old_tree, new_tree):
236
211
        from bzrlib import diff
237
212
        cmd = self._get_change_editor()
240
215
        return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
241
216
                                             sys.stdout)
242
217
 
243
 
    def get_mail_client(self):
244
 
        """Get a mail client to use"""
245
 
        selected_client = self.get_user_option('mail_client')
246
 
        _registry = mail_client.mail_client_registry
247
 
        try:
248
 
            mail_client_class = _registry.get(selected_client)
249
 
        except KeyError:
250
 
            raise errors.UnknownMailClient(selected_client)
251
 
        return mail_client_class(self)
252
 
 
253
218
    def _get_signature_checking(self):
254
219
        """Template method to override signature checking policy."""
255
220
 
384
349
        """Template method to provide a user option."""
385
350
        return None
386
351
 
387
 
    def get_user_option(self, option_name, expand=None):
 
352
    def get_user_option(self, option_name, expand=True):
388
353
        """Get a generic option - no special process, no default.
389
354
 
390
355
        :param option_name: The queried option.
393
358
 
394
359
        :returns: The value of the option.
395
360
        """
396
 
        if expand is None:
397
 
            expand = _get_expand_default_value()
398
361
        value = self._get_user_option(option_name)
399
362
        if expand:
400
363
            if isinstance(value, list):
648
611
        for (oname, value, section, conf_id, parser) in self._get_options():
649
612
            if oname.startswith('bzr.mergetool.'):
650
613
                tool_name = oname[len('bzr.mergetool.'):]
651
 
                tools[tool_name] = self.get_user_option(oname)
 
614
                tools[tool_name] = self.get_user_option(oname, False)
652
615
        trace.mutter('loaded merge tools: %r' % tools)
653
616
        return tools
654
617
 
1090
1053
        conf._create_from_string(str_or_unicode, save)
1091
1054
        return conf
1092
1055
 
1093
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1094
 
    def get_editor(self):
1095
 
        return self._get_user_option('editor')
1096
 
 
1097
1056
    @needs_write_lock
1098
1057
    def set_user_option(self, option, value):
1099
1058
        """Save option and its value in the configuration."""
1482
1441
        value = self._get_explicit_nickname()
1483
1442
        if value is not None:
1484
1443
            return value
 
1444
        if self.branch.name:
 
1445
            return self.branch.name
1485
1446
        return urlutils.unescape(self.branch.base.split('/')[-2])
1486
1447
 
1487
1448
    def has_explicit_nickname(self):
1524
1485
 
1525
1486
 
1526
1487
def config_dir():
1527
 
    """Return per-user configuration directory.
 
1488
    """Return per-user configuration directory as unicode string
1528
1489
 
1529
1490
    By default this is %APPDATA%/bazaar/2.0 on Windows, ~/.bazaar on Mac OS X
1530
1491
    and Linux.  On Linux, if there is a $XDG_CONFIG_HOME/bazaar directory,
1532
1493
 
1533
1494
    TODO: Global option --config-dir to override this.
1534
1495
    """
1535
 
    base = os.environ.get('BZR_HOME', None)
 
1496
    base = osutils.path_from_environ('BZR_HOME')
1536
1497
    if sys.platform == 'win32':
1537
 
        # environ variables on Windows are in user encoding/mbcs. So decode
1538
 
        # before using one
1539
 
        if base is not None:
1540
 
            base = base.decode('mbcs')
1541
 
        if base is None:
1542
 
            base = win32utils.get_appdata_location_unicode()
1543
 
        if base is None:
1544
 
            base = os.environ.get('HOME', None)
1545
 
            if base is not None:
1546
 
                base = base.decode('mbcs')
1547
 
        if base is None:
1548
 
            raise errors.BzrError('You must have one of BZR_HOME, APPDATA,'
1549
 
                                  ' or HOME set')
 
1498
        if base is None:
 
1499
            base = win32utils.get_appdata_location()
 
1500
        if base is None:
 
1501
            base = win32utils.get_home_location()
 
1502
        # GZ 2012-02-01: Really the two level subdirs only make sense inside
 
1503
        #                APPDATA, but hard to move. See bug 348640 for more.
1550
1504
        return osutils.pathjoin(base, 'bazaar', '2.0')
1551
 
    else:
1552
 
        if base is not None:
1553
 
            base = base.decode(osutils._fs_enc)
1554
 
    if sys.platform == 'darwin':
1555
 
        if base is None:
1556
 
            # this takes into account $HOME
1557
 
            base = os.path.expanduser("~")
1558
 
        return osutils.pathjoin(base, '.bazaar')
1559
 
    else:
1560
 
        if base is None:
1561
 
            xdg_dir = os.environ.get('XDG_CONFIG_HOME', None)
 
1505
    if base is None:
 
1506
        # GZ 2012-02-01: What should OSX use instead of XDG if anything?
 
1507
        if sys.platform != 'darwin':
 
1508
            xdg_dir = osutils.path_from_environ('XDG_CONFIG_HOME')
1562
1509
            if xdg_dir is None:
1563
 
                xdg_dir = osutils.pathjoin(os.path.expanduser("~"), ".config")
 
1510
                xdg_dir = osutils.pathjoin(osutils._get_home_dir(), ".config")
1564
1511
            xdg_dir = osutils.pathjoin(xdg_dir, 'bazaar')
1565
1512
            if osutils.isdir(xdg_dir):
1566
1513
                trace.mutter(
1567
1514
                    "Using configuration in XDG directory %s." % xdg_dir)
1568
1515
                return xdg_dir
1569
 
            base = os.path.expanduser("~")
1570
 
        return osutils.pathjoin(base, ".bazaar")
 
1516
        base = osutils._get_home_dir()
 
1517
    return osutils.pathjoin(base, ".bazaar")
1571
1518
 
1572
1519
 
1573
1520
def config_filename():
1617
1564
        return os.path.expanduser('~/.cache')
1618
1565
 
1619
1566
 
1620
 
def _get_default_mail_domain():
 
1567
def _get_default_mail_domain(mailname_file='/etc/mailname'):
1621
1568
    """If possible, return the assumed default email domain.
1622
1569
 
1623
1570
    :returns: string mail domain, or None.
1626
1573
        # No implementation yet; patches welcome
1627
1574
        return None
1628
1575
    try:
1629
 
        f = open('/etc/mailname')
 
1576
        f = open(mailname_file)
1630
1577
    except (IOError, OSError), e:
1631
1578
        return None
1632
1579
    try:
1633
 
        domain = f.read().strip()
 
1580
        domain = f.readline().strip()
1634
1581
        return domain
1635
1582
    finally:
1636
1583
        f.close()
2186
2133
credential_store_registry.default_key = 'plain'
2187
2134
 
2188
2135
 
 
2136
class Base64CredentialStore(CredentialStore):
 
2137
    __doc__ = """Base64 credential store for the authentication.conf file"""
 
2138
    
 
2139
    def decode_password(self, credentials):
 
2140
        """See CredentialStore.decode_password."""
 
2141
        # GZ 2012-07-28: Will raise binascii.Error if password is not base64,
 
2142
        #                should probably propogate as something more useful.
 
2143
        return base64.decodestring(credentials['password'])
 
2144
 
 
2145
credential_store_registry.register('base64', Base64CredentialStore,
 
2146
                                   help=Base64CredentialStore.__doc__)
 
2147
 
 
2148
 
2189
2149
class BzrDirConfig(object):
2190
2150
 
2191
2151
    def __init__(self, bzrdir):
2197
2157
 
2198
2158
        It may be set to a location, or None.
2199
2159
 
2200
 
        This policy affects all branches contained by this bzrdir, except for
2201
 
        those under repositories.
 
2160
        This policy affects all branches contained by this control dir, except
 
2161
        for those under repositories.
2202
2162
        """
2203
2163
        if self._config is None:
2204
2164
            raise errors.BzrError("Cannot set configuration in %s" % self._bzrdir)
2212
2172
 
2213
2173
        This will either be a location, or None.
2214
2174
 
2215
 
        This policy affects all branches contained by this bzrdir, except for
2216
 
        those under repositories.
 
2175
        This policy affects all branches contained by this control dir, except
 
2176
        for those under repositories.
2217
2177
        """
2218
2178
        if self._config is None:
2219
2179
            return None
2453
2413
                value = self.default()
2454
2414
                if not isinstance(value, unicode):
2455
2415
                    raise AssertionError(
2456
 
                    'Callable default values should be unicode')
 
2416
                        "Callable default value for '%s' should be unicode"
 
2417
                        % (self.name))
2457
2418
            else:
2458
2419
                value = self.default
2459
2420
        return value
2460
2421
 
 
2422
    def get_help_topic(self):
 
2423
        return self.name
 
2424
 
2461
2425
    def get_help_text(self, additional_see_also=None, plain=True):
2462
2426
        result = self.help
2463
2427
        from bzrlib import help_topics
2683
2647
           help="""\
2684
2648
Whether revisions associated with tags should be fetched.
2685
2649
"""))
 
2650
option_registry.register_lazy(
 
2651
    'bzr.transform.orphan_policy', 'bzrlib.transform', 'opt_transform_orphan')
2686
2652
option_registry.register(
2687
2653
    Option('bzr.workingtree.worth_saving_limit', default=10,
2688
2654
           from_unicode=int_from_store,  invalid='warning',
2696
2662
a file has been touched.
2697
2663
'''))
2698
2664
option_registry.register(
 
2665
    Option('bugtracker', default=None,
 
2666
           help='''\
 
2667
Default bug tracker to use.
 
2668
 
 
2669
This bug tracker will be used for example when marking bugs
 
2670
as fixed using ``bzr commit --fixes``, if no explicit
 
2671
bug tracker was specified.
 
2672
'''))
 
2673
option_registry.register(
2699
2674
    Option('check_signatures', default=CHECK_IF_POSSIBLE,
2700
2675
           from_unicode=signature_policy_from_unicode,
2701
2676
           help='''\
2922
2897
    'bzrlib.transport.http._urllib2_wrappers', 'opt_ssl_cert_reqs')
2923
2898
 
2924
2899
 
2925
 
 
2926
2900
class Section(object):
2927
2901
    """A section defines a dict of option name => value.
2928
2902
 
2998
2972
            # Report concurrent updates in an ad-hoc way. This should only
2999
2973
            # occurs when different processes try to update the same option
3000
2974
            # which is not supported (as in: the config framework is not meant
3001
 
            # to be used a sharing mechanism).
 
2975
            # to be used as a sharing mechanism).
3002
2976
            if expected != reloaded:
3003
2977
                if actual is _DeletedOption:
3004
2978
                    actual = '<DELETED>'
3024
2998
    mutable_section_class = MutableSection
3025
2999
 
3026
3000
    def __init__(self):
3027
 
        # Which sections need to be saved
3028
 
        self.dirty_sections = []
 
3001
        # Which sections need to be saved (by section id). We use a dict here
 
3002
        # so the dirty sections can be shared by multiple callers.
 
3003
        self.dirty_sections = {}
3029
3004
 
3030
3005
    def is_loaded(self):
3031
3006
        """Returns True if the Store has been loaded.
3074
3049
        raise NotImplementedError(self.save)
3075
3050
 
3076
3051
    def _need_saving(self):
3077
 
        for s in self.dirty_sections:
 
3052
        for s in self.dirty_sections.values():
3078
3053
            if s.orig:
3079
3054
                # At least one dirty section contains a modification
3080
3055
                return True
3094
3069
        # get_mutable_section() call below.
3095
3070
        self.unload()
3096
3071
        # Apply the changes from the preserved dirty sections
3097
 
        for dirty in dirty_sections:
3098
 
            clean = self.get_mutable_section(dirty.id)
 
3072
        for section_id, dirty in dirty_sections.iteritems():
 
3073
            clean = self.get_mutable_section(section_id)
3099
3074
            clean.apply_changes(dirty, self)
3100
3075
        # Everything is clean now
3101
 
        self.dirty_sections = []
 
3076
        self.dirty_sections = {}
3102
3077
 
3103
3078
    def save_changes(self):
3104
3079
        """Saves the Store to persistent storage if changes occurred.
3184
3159
 
3185
3160
    def unload(self):
3186
3161
        self._config_obj = None
3187
 
        self.dirty_sections = []
 
3162
        self.dirty_sections = {}
3188
3163
 
3189
3164
    def _load_content(self):
3190
3165
        """Load the config file bytes.
3238
3213
        if not self._need_saving():
3239
3214
            return
3240
3215
        # Preserve the current version
3241
 
        current = self._config_obj
3242
 
        dirty_sections = list(self.dirty_sections)
 
3216
        dirty_sections = dict(self.dirty_sections.items())
3243
3217
        self.apply_changes(dirty_sections)
3244
3218
        # Save to the persistent storage
3245
3219
        self.save()
3280
3254
        except errors.NoSuchFile:
3281
3255
            # The file doesn't exist, let's pretend it was empty
3282
3256
            self._load_from_string('')
 
3257
        if section_id in self.dirty_sections:
 
3258
            # We already created a mutable section for this id
 
3259
            return self.dirty_sections[section_id]
3283
3260
        if section_id is None:
3284
3261
            section = self._config_obj
3285
3262
        else:
3286
3263
            section = self._config_obj.setdefault(section_id, {})
3287
3264
        mutable_section = self.mutable_section_class(section_id, section)
3288
3265
        # All mutable sections can become dirty
3289
 
        self.dirty_sections.append(mutable_section)
 
3266
        self.dirty_sections[section_id] = mutable_section
3290
3267
        return mutable_section
3291
3268
 
3292
3269
    def quote(self, value):
3311
3288
        # anyway.
3312
3289
        return 'In-Process Store, no URL'
3313
3290
 
 
3291
 
3314
3292
class TransportIniFileStore(IniFileStore):
3315
3293
    """IniFileStore that loads files from a transport.
3316
3294
 
3406
3384
# on the relevant parts of the API that needs testing -- vila 20110503 (based
3407
3385
# on a poolie's remark)
3408
3386
class GlobalStore(LockableIniFileStore):
 
3387
    """A config store for global options.
 
3388
 
 
3389
    There is a single GlobalStore for a given process.
 
3390
    """
3409
3391
 
3410
3392
    def __init__(self, possible_transports=None):
3411
3393
        t = transport.get_transport_from_path(
3415
3397
 
3416
3398
 
3417
3399
class LocationStore(LockableIniFileStore):
 
3400
    """A config store for global options.
 
3401
 
 
3402
    There is a single GlobalStore for a given process.
 
3403
    """
3418
3404
 
3419
3405
    def __init__(self, possible_transports=None):
3420
3406
        t = transport.get_transport_from_path(
3424
3410
 
3425
3411
 
3426
3412
class BranchStore(TransportIniFileStore):
 
3413
    """A config store for branch options.
 
3414
 
 
3415
    There is a single BranchStore for a given branch.
 
3416
    """
3427
3417
 
3428
3418
    def __init__(self, branch):
3429
3419
        super(BranchStore, self).__init__(branch.control_transport,
3431
3421
        self.branch = branch
3432
3422
        self.id = 'branch'
3433
3423
 
3434
 
    def lock_write(self, token=None):
3435
 
        return self.branch.lock_write(token)
3436
 
 
3437
 
    def unlock(self):
3438
 
        return self.branch.unlock()
3439
 
 
3440
 
    @needs_write_lock
3441
 
    def save(self):
3442
 
        # We need to be able to override the undecorated implementation
3443
 
        self.save_without_locking()
3444
 
 
3445
 
    def save_without_locking(self):
3446
 
        super(BranchStore, self).save()
3447
 
 
3448
3424
 
3449
3425
class ControlStore(LockableIniFileStore):
3450
3426
 
3496
3472
 
3497
3473
class LocationSection(Section):
3498
3474
 
3499
 
    def __init__(self, section, extra_path):
 
3475
    def __init__(self, section, extra_path, branch_name=None):
3500
3476
        super(LocationSection, self).__init__(section.id, section.options)
3501
3477
        self.extra_path = extra_path
 
3478
        if branch_name is None:
 
3479
            branch_name = ''
3502
3480
        self.locals = {'relpath': extra_path,
3503
 
                       'basename': urlutils.basename(extra_path)}
 
3481
                       'basename': urlutils.basename(extra_path),
 
3482
                       'branchname': branch_name}
3504
3483
 
3505
3484
    def get(self, name, default=None, expand=True):
3506
3485
        value = super(LocationSection, self).get(name, default)
3576
3555
 
3577
3556
    def __init__(self, store, location):
3578
3557
        super(LocationMatcher, self).__init__(store)
 
3558
        url, params = urlutils.split_segment_parameters(location)
3579
3559
        if location.startswith('file://'):
3580
3560
            location = urlutils.local_path_from_url(location)
3581
3561
        self.location = location
 
3562
        branch_name = params.get('branch')
 
3563
        if branch_name is None:
 
3564
            self.branch_name = urlutils.basename(self.location)
 
3565
        else:
 
3566
            self.branch_name = urlutils.unescape(branch_name)
3582
3567
 
3583
3568
    def _get_matching_sections(self):
3584
3569
        """Get all sections matching ``location``."""
3610
3595
            while True:
3611
3596
                section = iter_all_sections.next()
3612
3597
                if section_id == section.id:
3613
 
                    matching_sections.append(
3614
 
                        (length, LocationSection(section, extra_path)))
 
3598
                    section = LocationSection(section, extra_path,
 
3599
                                              self.branch_name)
 
3600
                    matching_sections.append((length, section))
3615
3601
                    break
3616
3602
        return matching_sections
3617
3603
 
3650
3636
        yield is_ref, chunk
3651
3637
        is_ref = not is_ref
3652
3638
 
 
3639
# FIXME: _shared_stores should be an attribute of a library state once a
 
3640
# library_state object is always available.
 
3641
_shared_stores = {}
 
3642
_shared_stores_at_exit_installed = False
3653
3643
 
3654
3644
class Stack(object):
3655
3645
    """A stack of configurations where an option can be defined"""
3672
3662
        self.store = store
3673
3663
        self.mutable_section_id = mutable_section_id
3674
3664
 
3675
 
    def get(self, name, expand=None):
 
3665
    def iter_sections(self):
 
3666
        """Iterate all the defined sections."""
 
3667
        # Ensuring lazy loading is achieved by delaying section matching (which
 
3668
        # implies querying the persistent storage) until it can't be avoided
 
3669
        # anymore by using callables to describe (possibly empty) section
 
3670
        # lists.
 
3671
        for sections in self.sections_def:
 
3672
            for store, section in sections():
 
3673
                yield store, section
 
3674
 
 
3675
    def get(self, name, expand=True, convert=True):
3676
3676
        """Return the *first* option value found in the sections.
3677
3677
 
3678
3678
        This is where we guarantee that sections coming from Store are loaded
3685
3685
 
3686
3686
        :param expand: Whether options references should be expanded.
3687
3687
 
 
3688
        :param convert: Whether the option value should be converted from
 
3689
            unicode (do nothing for non-registered options).
 
3690
 
3688
3691
        :returns: The value of the option.
3689
3692
        """
3690
3693
        # FIXME: No caching of options nor sections yet -- vila 20110503
3691
 
        if expand is None:
3692
 
            expand = _get_expand_default_value()
3693
3694
        value = None
3694
3695
        found_store = None # Where the option value has been found
3695
3696
        # If the option is registered, it may provide additional info about
3713
3714
                                      % (name, type(val)))
3714
3715
                if opt is None:
3715
3716
                    val = found_store.unquote(val)
3716
 
                else:
 
3717
                elif convert:
3717
3718
                    val = opt.convert_from_unicode(found_store, val)
3718
3719
            return val
3719
3720
 
3723
3724
            value = opt.get_override()
3724
3725
            value = expand_and_convert(value)
3725
3726
        if value is None:
3726
 
            # Ensuring lazy loading is achieved by delaying section matching
3727
 
            # (which implies querying the persistent storage) until it can't be
3728
 
            # avoided anymore by using callables to describe (possibly empty)
3729
 
            # section lists.
3730
 
            for sections in self.sections_def:
3731
 
                for store, section in sections():
3732
 
                    value = section.get(name)
3733
 
                    if value is not None:
3734
 
                        found_store = store
3735
 
                        break
 
3727
            for store, section in self.iter_sections():
 
3728
                value = section.get(name)
3736
3729
                if value is not None:
 
3730
                    found_store = store
3737
3731
                    break
3738
3732
            value = expand_and_convert(value)
3739
3733
            if opt is not None and value is None:
3805
3799
            # anything else
3806
3800
            value = env[name]
3807
3801
        else:
3808
 
            value = self.get(name, expand=False)
 
3802
            value = self.get(name, expand=False, convert=False)
3809
3803
            value = self._expand_options_in_string(value, env, _refs)
3810
3804
        return value
3811
3805
 
3840
3834
        return "<config.%s(%s)>" % (self.__class__.__name__, id(self))
3841
3835
 
3842
3836
    def _get_overrides(self):
3843
 
        # Hack around library_state.initialize never called
 
3837
        # FIXME: Hack around library_state.initialize never called
3844
3838
        if bzrlib.global_state is not None:
3845
3839
            return bzrlib.global_state.cmdline_overrides.get_sections()
3846
3840
        return []
3847
3841
 
 
3842
    def get_shared_store(self, store, state=None):
 
3843
        """Get a known shared store.
 
3844
 
 
3845
        Store urls uniquely identify them and are used to ensure a single copy
 
3846
        is shared across all users.
 
3847
 
 
3848
        :param store: The store known to the caller.
 
3849
 
 
3850
        :param state: The library state where the known stores are kept.
 
3851
 
 
3852
        :returns: The store received if it's not a known one, an already known
 
3853
            otherwise.
 
3854
        """
 
3855
        if state is None:
 
3856
            state = bzrlib.global_state
 
3857
        if state is None:
 
3858
            global _shared_stores_at_exit_installed
 
3859
            stores = _shared_stores
 
3860
            def save_config_changes():
 
3861
                for k, store in stores.iteritems():
 
3862
                    store.save_changes()
 
3863
            if not _shared_stores_at_exit_installed:
 
3864
                # FIXME: Ugly hack waiting for library_state to always be
 
3865
                # available. -- vila 20120731
 
3866
                import atexit
 
3867
                atexit.register(save_config_changes)
 
3868
                _shared_stores_at_exit_installed = True
 
3869
        else:
 
3870
            stores = state.config_stores
 
3871
        url = store.external_url()
 
3872
        try:
 
3873
            return stores[url]
 
3874
        except KeyError:
 
3875
            stores[url] = store
 
3876
            return store
 
3877
 
3848
3878
 
3849
3879
class MemoryStack(Stack):
3850
3880
    """A configuration stack defined from a string.
3900
3930
        self.store.save()
3901
3931
 
3902
3932
 
3903
 
class GlobalStack(_CompatibleStack):
 
3933
class GlobalStack(Stack):
3904
3934
    """Global options only stack.
3905
3935
 
3906
3936
    The following sections are queried:
3914
3944
    """
3915
3945
 
3916
3946
    def __init__(self):
3917
 
        gstore = GlobalStore()
 
3947
        gstore = self.get_shared_store(GlobalStore())
3918
3948
        super(GlobalStack, self).__init__(
3919
3949
            [self._get_overrides,
3920
3950
             NameMatcher(gstore, 'DEFAULT').get_sections],
3921
3951
            gstore, mutable_section_id='DEFAULT')
3922
3952
 
3923
3953
 
3924
 
class LocationStack(_CompatibleStack):
 
3954
class LocationStack(Stack):
3925
3955
    """Per-location options falling back to global options stack.
3926
3956
 
3927
3957
 
3943
3973
        """Make a new stack for a location and global configuration.
3944
3974
 
3945
3975
        :param location: A URL prefix to """
3946
 
        lstore = LocationStore()
 
3976
        lstore = self.get_shared_store(LocationStore())
3947
3977
        if location.startswith('file://'):
3948
3978
            location = urlutils.local_path_from_url(location)
3949
 
        gstore = GlobalStore()
 
3979
        gstore = self.get_shared_store(GlobalStore())
3950
3980
        super(LocationStack, self).__init__(
3951
3981
            [self._get_overrides,
3952
3982
             LocationMatcher(lstore, location).get_sections,
3954
3984
            lstore, mutable_section_id=location)
3955
3985
 
3956
3986
 
3957
 
class BranchStack(_CompatibleStack):
 
3987
class BranchStack(Stack):
3958
3988
    """Per-location options falling back to branch then global options stack.
3959
3989
 
3960
3990
    The following sections are queried:
3974
4004
    """
3975
4005
 
3976
4006
    def __init__(self, branch):
3977
 
        lstore = LocationStore()
 
4007
        lstore = self.get_shared_store(LocationStore())
3978
4008
        bstore = branch._get_config_store()
3979
 
        gstore = GlobalStore()
 
4009
        gstore = self.get_shared_store(GlobalStore())
3980
4010
        super(BranchStack, self).__init__(
3981
4011
            [self._get_overrides,
3982
4012
             LocationMatcher(lstore, branch.base).get_sections,
3985
4015
            bstore)
3986
4016
        self.branch = branch
3987
4017
 
3988
 
 
3989
 
class RemoteControlStack(_CompatibleStack):
 
4018
    def lock_write(self, token=None):
 
4019
        return self.branch.lock_write(token)
 
4020
 
 
4021
    def unlock(self):
 
4022
        return self.branch.unlock()
 
4023
 
 
4024
    @needs_write_lock
 
4025
    def set(self, name, value):
 
4026
        super(BranchStack, self).set(name, value)
 
4027
        # Unlocking the branch will trigger a store.save_changes() so the last
 
4028
        # unlock saves all the changes.
 
4029
 
 
4030
    @needs_write_lock
 
4031
    def remove(self, name):
 
4032
        super(BranchStack, self).remove(name)
 
4033
        # Unlocking the branch will trigger a store.save_changes() so the last
 
4034
        # unlock saves all the changes.
 
4035
 
 
4036
 
 
4037
class RemoteControlStack(Stack):
3990
4038
    """Remote control-only options stack."""
3991
4039
 
3992
4040
    # FIXME 2011-11-22 JRV This should probably be renamed to avoid confusion
4001
4049
        self.bzrdir = bzrdir
4002
4050
 
4003
4051
 
4004
 
class BranchOnlyStack(_CompatibleStack):
 
4052
class BranchOnlyStack(Stack):
4005
4053
    """Branch-only options stack."""
4006
4054
 
4007
4055
    # FIXME: _BranchOnlyStack only uses branch.conf and is used only for the
4015
4063
            bstore)
4016
4064
        self.branch = branch
4017
4065
 
4018
 
 
4019
 
# Use a an empty dict to initialize an empty configobj avoiding all
4020
 
# parsing and encoding checks
4021
 
_quoting_config = configobj.ConfigObj(
4022
 
    {}, encoding='utf-8', interpolation=False, list_values=True)
 
4066
    def lock_write(self, token=None):
 
4067
        return self.branch.lock_write(token)
 
4068
 
 
4069
    def unlock(self):
 
4070
        return self.branch.unlock()
 
4071
 
 
4072
    @needs_write_lock
 
4073
    def set(self, name, value):
 
4074
        super(BranchOnlyStack, self).set(name, value)
 
4075
        # Force a write to persistent storage
 
4076
        self.store.save_changes()
 
4077
 
 
4078
    @needs_write_lock
 
4079
    def remove(self, name):
 
4080
        super(BranchOnlyStack, self).remove(name)
 
4081
        # Force a write to persistent storage
 
4082
        self.store.save_changes()
 
4083
 
4023
4084
 
4024
4085
class cmd_config(commands.Command):
4025
4086
    __doc__ = """Display, set or remove a configuration option.
4061
4122
            remove=False):
4062
4123
        if directory is None:
4063
4124
            directory = '.'
 
4125
        directory = directory_service.directories.dereference(directory)
4064
4126
        directory = urlutils.normalize_url(directory)
4065
4127
        if remove and all:
4066
4128
            raise errors.BzrError(
4087
4149
                # Set the option value
4088
4150
                self._set_config_option(name, value, directory, scope)
4089
4151
 
4090
 
    def _get_stack(self, directory, scope=None):
 
4152
    def _get_stack(self, directory, scope=None, write_access=False):
4091
4153
        """Get the configuration stack specified by ``directory`` and ``scope``.
4092
4154
 
4093
4155
        :param directory: Where the configurations are derived from.
4094
4156
 
4095
4157
        :param scope: A specific config to start from.
 
4158
 
 
4159
        :param write_access: Whether a write access to the stack will be
 
4160
            attempted.
4096
4161
        """
4097
4162
        # FIXME: scope should allow access to plugin-specific stacks (even
4098
4163
        # reduced to the plugin-specific store), related to
4106
4171
                (_, br, _) = (
4107
4172
                    controldir.ControlDir.open_containing_tree_or_branch(
4108
4173
                        directory))
 
4174
                if write_access:
 
4175
                    self.add_cleanup(br.lock_write().unlock)
4109
4176
                return br.get_config_stack()
4110
4177
            raise errors.NoSuchConfig(scope)
4111
4178
        else:
4113
4180
                (_, br, _) = (
4114
4181
                    controldir.ControlDir.open_containing_tree_or_branch(
4115
4182
                        directory))
 
4183
                if write_access:
 
4184
                    self.add_cleanup(br.lock_write().unlock)
4116
4185
                return br.get_config_stack()
4117
4186
            except errors.NotBranchError:
4118
4187
                return LocationStack(directory)
4119
4188
 
 
4189
    def _quote_multiline(self, value):
 
4190
        if '\n' in value:
 
4191
            value = '"""' + value + '"""'
 
4192
        return value
 
4193
 
4120
4194
    def _show_value(self, name, directory, scope):
4121
4195
        conf = self._get_stack(directory, scope)
4122
 
        value = conf.get(name, expand=True)
 
4196
        value = conf.get(name, expand=True, convert=False)
4123
4197
        if value is not None:
4124
4198
            # Quote the value appropriately
4125
 
            value = _quoting_config._quote(value)
 
4199
            value = self._quote_multiline(value)
4126
4200
            self.outf.write('%s\n' % (value,))
4127
4201
        else:
4128
4202
            raise errors.NoSuchConfigOption(name)
4136
4210
        cur_store_id = None
4137
4211
        cur_section = None
4138
4212
        conf = self._get_stack(directory, scope)
4139
 
        for sections in conf.sections_def:
4140
 
            for store, section in sections():
4141
 
                for oname in section.iter_option_names():
4142
 
                    if name.search(oname):
4143
 
                        if cur_store_id != store.id:
4144
 
                            # Explain where the options are defined
4145
 
                            self.outf.write('%s:\n' % (store.id,))
4146
 
                            cur_store_id = store.id
4147
 
                            cur_section = None
4148
 
                        if (section.id is not None
4149
 
                            and cur_section != section.id):
4150
 
                            # Display the section id as it appears in the store
4151
 
                            # (None doesn't appear by definition)
4152
 
                            self.outf.write('  [%s]\n' % (section.id,))
4153
 
                            cur_section = section.id
4154
 
                        value = section.get(oname, expand=False)
4155
 
                        # Since we don't use the stack, we need to restore a
4156
 
                        # proper quoting.
4157
 
                        try:
4158
 
                            opt = option_registry.get(oname)
4159
 
                            value = opt.convert_from_unicode(store, value)
4160
 
                        except KeyError:
4161
 
                            value = store.unquote(value)
4162
 
                        value = _quoting_config._quote(value)
4163
 
                        self.outf.write('  %s = %s\n' % (oname, value))
 
4213
        for store, section in conf.iter_sections():
 
4214
            for oname in section.iter_option_names():
 
4215
                if name.search(oname):
 
4216
                    if cur_store_id != store.id:
 
4217
                        # Explain where the options are defined
 
4218
                        self.outf.write('%s:\n' % (store.id,))
 
4219
                        cur_store_id = store.id
 
4220
                        cur_section = None
 
4221
                    if (section.id is not None and cur_section != section.id):
 
4222
                        # Display the section id as it appears in the store
 
4223
                        # (None doesn't appear by definition)
 
4224
                        self.outf.write('  [%s]\n' % (section.id,))
 
4225
                        cur_section = section.id
 
4226
                    value = section.get(oname, expand=False)
 
4227
                    # Quote the value appropriately
 
4228
                    value = self._quote_multiline(value)
 
4229
                    self.outf.write('  %s = %s\n' % (oname, value))
4164
4230
 
4165
4231
    def _set_config_option(self, name, value, directory, scope):
4166
 
        conf = self._get_stack(directory, scope)
 
4232
        conf = self._get_stack(directory, scope, write_access=True)
4167
4233
        conf.set(name, value)
4168
4234
 
4169
4235
    def _remove_config_option(self, name, directory, scope):
4170
4236
        if name is None:
4171
4237
            raise errors.BzrCommandError(
4172
4238
                '--remove expects an option to remove.')
4173
 
        conf = self._get_stack(directory, scope)
 
4239
        conf = self._get_stack(directory, scope, write_access=True)
4174
4240
        try:
4175
4241
            conf.remove(name)
4176
4242
        except KeyError: