~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/config.py

  • Committer: Martin Packman
  • Date: 2012-02-01 13:24:42 UTC
  • mto: (6437.23.4 2.5)
  • mto: This revision was merged to the branch mainline in revision 6462.
  • Revision ID: martin.packman@canonical.com-20120201132442-ela7jc4mxv4b058o
Treat path for .bzr.log as unicode

Show diffs side-by-side

added added

removed removed

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