1981
1453
configobj[name] = value
1983
1455
configobj.setdefault(section, {})[name] = value
1984
for hook in OldConfigHooks['set']:
1985
hook(self, name, value)
1986
self._set_configobj(configobj)
1988
def remove_option(self, option_name, section_name=None):
1989
configobj = self._get_configobj()
1990
if section_name is None:
1991
del configobj[option_name]
1993
del configobj[section_name][option_name]
1994
for hook in OldConfigHooks['remove']:
1995
hook(self, option_name)
1996
1456
self._set_configobj(configobj)
1998
1458
def _get_config_file(self):
2000
f = BytesIO(self._transport.get_bytes(self._filename))
2001
for hook in OldConfigHooks['load']:
1460
return self._transport.get(self._filename)
2004
1461
except errors.NoSuchFile:
2006
except errors.PermissionDenied:
2008
"Permission denied while trying to open "
2009
"configuration file %s.",
2010
urlutils.unescape_for_display(
2011
urlutils.join(self._transport.base, self._filename),
2015
def _external_url(self):
2016
return urlutils.join(self._transport.external_url(), self._filename)
2018
1464
def _get_configobj(self):
2019
f = self._get_config_file()
2022
conf = ConfigObj(f, encoding='utf-8')
2023
except configobj.ConfigObjError as e:
2024
raise ParseConfigError(e.errors, self._external_url())
2025
except UnicodeDecodeError:
2026
raise ConfigContentError(self._external_url())
1465
return ConfigObj(self._get_config_file(), encoding='utf-8')
2031
1467
def _set_configobj(self, configobj):
2032
out_file = BytesIO()
1468
out_file = StringIO()
2033
1469
configobj.write(out_file)
2034
1470
out_file.seek(0)
2035
1471
self._transport.put_file(self._filename, out_file)
2036
for hook in OldConfigHooks['save']:
2040
class Option(object):
2041
"""An option definition.
2043
The option *values* are stored in config files and found in sections.
2045
Here we define various properties about the option itself, its default
2046
value, how to convert it from stores, what to do when invalid values are
2047
encoutered, in which config files it can be stored.
2050
def __init__(self, name, override_from_env=None,
2051
default=None, default_from_env=None,
2052
help=None, from_unicode=None, invalid=None, unquote=True):
2053
"""Build an option definition.
2055
:param name: the name used to refer to the option.
2057
:param override_from_env: A list of environment variables which can
2058
provide override any configuration setting.
2060
:param default: the default value to use when none exist in the config
2061
stores. This is either a string that ``from_unicode`` will convert
2062
into the proper type, a callable returning a unicode string so that
2063
``from_unicode`` can be used on the return value, or a python
2064
object that can be stringified (so only the empty list is supported
2067
:param default_from_env: A list of environment variables which can
2068
provide a default value. 'default' will be used only if none of the
2069
variables specified here are set in the environment.
2071
:param help: a doc string to explain the option to the user.
2073
:param from_unicode: a callable to convert the unicode string
2074
representing the option value in a store or its default value.
2076
:param invalid: the action to be taken when an invalid value is
2077
encountered in a store. This is called only when from_unicode is
2078
invoked to convert a string and returns None or raise ValueError or
2079
TypeError. Accepted values are: None (ignore invalid values),
2080
'warning' (emit a warning), 'error' (emit an error message and
2083
:param unquote: should the unicode value be unquoted before conversion.
2084
This should be used only when the store providing the values cannot
2085
safely unquote them (see http://pad.lv/906897). It is provided so
2086
daughter classes can handle the quoting themselves.
2088
if override_from_env is None:
2089
override_from_env = []
2090
if default_from_env is None:
2091
default_from_env = []
2093
self.override_from_env = override_from_env
2094
# Convert the default value to a unicode string so all values are
2095
# strings internally before conversion (via from_unicode) is attempted.
2098
elif isinstance(default, list):
2099
# Only the empty list is supported
2101
raise AssertionError(
2102
'Only empty lists are supported as default values')
2104
elif isinstance(default, (bytes, str, bool, int, float)):
2105
# Rely on python to convert strings, booleans and integers
2106
self.default = u'%s' % (default,)
2107
elif callable(default):
2108
self.default = default
2110
# other python objects are not expected
2111
raise AssertionError('%r is not supported as a default value'
2113
self.default_from_env = default_from_env
2115
self.from_unicode = from_unicode
2116
self.unquote = unquote
2117
if invalid and invalid not in ('warning', 'error'):
2118
raise AssertionError("%s not supported for 'invalid'" % (invalid,))
2119
self.invalid = invalid
2125
def convert_from_unicode(self, store, unicode_value):
2126
if self.unquote and store is not None and unicode_value is not None:
2127
unicode_value = store.unquote(unicode_value)
2128
if self.from_unicode is None or unicode_value is None:
2129
# Don't convert or nothing to convert
2130
return unicode_value
2132
converted = self.from_unicode(unicode_value)
2133
except (ValueError, TypeError):
2134
# Invalid values are ignored
2136
if converted is None and self.invalid is not None:
2137
# The conversion failed
2138
if self.invalid == 'warning':
2139
trace.warning('Value "%s" is not valid for "%s"',
2140
unicode_value, self.name)
2141
elif self.invalid == 'error':
2142
raise ConfigOptionValueError(self.name, unicode_value)
2145
def get_override(self):
2147
for var in self.override_from_env:
2149
# If the env variable is defined, its value takes precedence
2150
value = os.environ[var]
2156
def get_default(self):
2158
for var in self.default_from_env:
2160
# If the env variable is defined, its value is the default one
2161
value = os.environ[var]
2166
# Otherwise, fallback to the value defined at registration
2167
if callable(self.default):
2168
value = self.default()
2169
if not isinstance(value, str):
2170
raise AssertionError(
2171
"Callable default value for '%s' should be unicode"
2174
value = self.default
2177
def get_help_topic(self):
2180
def get_help_text(self, additional_see_also=None, plain=True):
2182
from breezy import help_topics
2183
result += help_topics._format_see_also(additional_see_also)
2185
result = help_topics.help_as_plain_text(result)
2189
# Predefined converters to get proper values from store
2191
def bool_from_store(unicode_str):
2192
return ui.bool_from_string(unicode_str)
2195
def int_from_store(unicode_str):
2196
return int(unicode_str)
2199
_unit_suffixes = dict(K=10**3, M=10**6, G=10**9)
2202
def int_SI_from_store(unicode_str):
2203
"""Convert a human readable size in SI units, e.g 10MB into an integer.
2205
Accepted suffixes are K,M,G. It is case-insensitive and may be followed
2206
by a trailing b (i.e. Kb, MB). This is intended to be practical and not
2209
:return Integer, expanded to its base-10 value if a proper SI unit is
2210
found, None otherwise.
2212
regexp = "^(\\d+)(([" + ''.join(_unit_suffixes) + "])b?)?$"
2213
p = re.compile(regexp, re.IGNORECASE)
2214
m = p.match(unicode_str)
2217
val, _, unit = m.groups()
2221
coeff = _unit_suffixes[unit.upper()]
2224
gettext('{0} is not an SI unit.').format(unit))
2229
def float_from_store(unicode_str):
2230
return float(unicode_str)
2233
# Use an empty dict to initialize an empty configobj avoiding all parsing and
2235
_list_converter_config = configobj.ConfigObj(
2236
{}, encoding='utf-8', list_values=True, interpolation=False)
2239
class ListOption(Option):
2241
def __init__(self, name, default=None, default_from_env=None,
2242
help=None, invalid=None):
2243
"""A list Option definition.
2245
This overrides the base class so the conversion from a unicode string
2246
can take quoting into account.
2248
super(ListOption, self).__init__(
2249
name, default=default, default_from_env=default_from_env,
2250
from_unicode=self.from_unicode, help=help,
2251
invalid=invalid, unquote=False)
2253
def from_unicode(self, unicode_str):
2254
if not isinstance(unicode_str, str):
2256
# Now inject our string directly as unicode. All callers got their
2257
# value from configobj, so values that need to be quoted are already
2259
_list_converter_config.reset()
2260
_list_converter_config._parse([u"list=%s" % (unicode_str,)])
2261
maybe_list = _list_converter_config['list']
2262
if isinstance(maybe_list, str):
2264
# A single value, most probably the user forgot (or didn't care
2265
# to add) the final ','
2268
# The empty string, convert to empty list
2271
# We rely on ConfigObj providing us with a list already
2276
class RegistryOption(Option):
2277
"""Option for a choice from a registry."""
2279
def __init__(self, name, registry, default_from_env=None,
2280
help=None, invalid=None):
2281
"""A registry based Option definition.
2283
This overrides the base class so the conversion from a unicode string
2284
can take quoting into account.
2286
super(RegistryOption, self).__init__(
2287
name, default=lambda: registry.default_key,
2288
default_from_env=default_from_env,
2289
from_unicode=self.from_unicode, help=help,
2290
invalid=invalid, unquote=False)
2291
self.registry = registry
2293
def from_unicode(self, unicode_str):
2294
if not isinstance(unicode_str, str):
2297
return self.registry.get(unicode_str)
2300
"Invalid value %s for %s."
2301
"See help for a list of possible values." % (unicode_str,
2306
ret = [self._help, "\n\nThe following values are supported:\n"]
2307
for key in self.registry.keys():
2308
ret.append(" %s - %s\n" % (key, self.registry.get_help(key)))
2312
_option_ref_re = lazy_regex.lazy_compile('({[^\\d\\W](?:\\.\\w|-\\w|\\w)*})')
2313
"""Describes an expandable option reference.
2315
We want to match the most embedded reference first.
2317
I.e. for '{{foo}}' we will get '{foo}',
2318
for '{bar{baz}}' we will get '{baz}'
2322
def iter_option_refs(string):
2323
# Split isolate refs so every other chunk is a ref
2325
for chunk in _option_ref_re.split(string):
2330
class OptionRegistry(registry.Registry):
2331
"""Register config options by their name.
2333
This overrides ``registry.Registry`` to simplify registration by acquiring
2334
some information from the option object itself.
2337
def _check_option_name(self, option_name):
2338
"""Ensures an option name is valid.
2340
:param option_name: The name to validate.
2342
if _option_ref_re.match('{%s}' % option_name) is None:
2343
raise IllegalOptionName(option_name)
2345
def register(self, option):
2346
"""Register a new option to its name.
2348
:param option: The option to register. Its name is used as the key.
2350
self._check_option_name(option.name)
2351
super(OptionRegistry, self).register(option.name, option,
2354
def register_lazy(self, key, module_name, member_name):
2355
"""Register a new option to be loaded on request.
2357
:param key: the key to request the option later. Since the registration
2358
is lazy, it should be provided and match the option name.
2360
:param module_name: the python path to the module. Such as 'os.path'.
2362
:param member_name: the member of the module to return. If empty or
2363
None, get() will return the module itself.
2365
self._check_option_name(key)
2366
super(OptionRegistry, self).register_lazy(key,
2367
module_name, member_name)
2369
def get_help(self, key=None):
2370
"""Get the help text associated with the given key"""
2371
option = self.get(key)
2372
the_help = option.help
2373
if callable(the_help):
2374
return the_help(self, key)
2378
option_registry = OptionRegistry()
2381
# Registered options in lexicographical order
2383
option_registry.register(
2384
Option('append_revisions_only',
2385
default=None, from_unicode=bool_from_store, invalid='warning',
2387
Whether to only append revisions to the mainline.
2389
If this is set to true, then it is not possible to change the
2390
existing mainline of the branch.
2392
option_registry.register(
2393
ListOption('acceptable_keys',
2396
List of GPG key patterns which are acceptable for verification.
2398
option_registry.register(
2399
Option('add.maximum_file_size',
2400
default=u'20MB', from_unicode=int_SI_from_store,
2402
Size above which files should be added manually.
2404
Files below this size are added automatically when using ``bzr add`` without
2407
A negative value means disable the size check.
2409
option_registry.register(
2411
default=None, from_unicode=bool_from_store,
2413
Is the branch bound to ``bound_location``.
2415
If set to "True", the branch should act as a checkout, and push each commit to
2416
the bound_location. This option is normally set by ``bind``/``unbind``.
2418
See also: bound_location.
2420
option_registry.register(
2421
Option('bound_location',
2424
The location that commits should go to when acting as a checkout.
2426
This option is normally set by ``bind``.
2430
option_registry.register(
2431
Option('branch.fetch_tags', default=False, from_unicode=bool_from_store,
2433
Whether revisions associated with tags should be fetched.
2435
option_registry.register_lazy(
2436
'transform.orphan_policy', 'breezy.transform', 'opt_transform_orphan')
2437
option_registry.register(
2438
Option('bzr.workingtree.worth_saving_limit', default=10,
2439
from_unicode=int_from_store, invalid='warning',
2441
How many changes before saving the dirstate.
2443
-1 means that we will never rewrite the dirstate file for only
2444
stat-cache changes. Regardless of this setting, we will always rewrite
2445
the dirstate file if a file is added/removed/renamed/etc. This flag only
2446
affects the behavior of updating the dirstate file after we notice that
2447
a file has been touched.
2449
option_registry.register(
2450
Option('bugtracker', default=None,
2452
Default bug tracker to use.
2454
This bug tracker will be used for example when marking bugs
2455
as fixed using ``bzr commit --fixes``, if no explicit
2456
bug tracker was specified.
2458
option_registry.register(
2459
Option('calculate_revnos', default=True,
2460
from_unicode=bool_from_store,
2462
Calculate revision numbers if they are not known.
2464
Always show revision numbers, even for branch formats that don't store them
2465
natively (such as Git). Calculating the revision number requires traversing
2466
the left hand ancestry of the branch and can be slow on very large branches.
2468
option_registry.register(
2469
Option('check_signatures', default=CHECK_IF_POSSIBLE,
2470
from_unicode=signature_policy_from_unicode,
2472
GPG checking policy.
2474
Possible values: require, ignore, check-available (default)
2476
this option will control whether bzr will require good gpg
2477
signatures, ignore them, or check them if they are
2480
option_registry.register(
2481
Option('child_submit_format',
2482
help='''The preferred format of submissions to this branch.'''))
2483
option_registry.register(
2484
Option('child_submit_to',
2485
help='''Where submissions to this branch are mailed to.'''))
2486
option_registry.register(
2487
Option('create_signatures', default=SIGN_WHEN_REQUIRED,
2488
from_unicode=signing_policy_from_unicode,
2492
Possible values: always, never, when-required (default)
2494
This option controls whether bzr will always create
2495
gpg signatures or not on commits.
2497
option_registry.register(
2498
Option('dirstate.fdatasync', default=True,
2499
from_unicode=bool_from_store,
2501
Flush dirstate changes onto physical disk?
2503
If true (default), working tree metadata changes are flushed through the
2504
OS buffers to physical disk. This is somewhat slower, but means data
2505
should not be lost if the machine crashes. See also repository.fdatasync.
2507
option_registry.register(
2508
ListOption('debug_flags', default=[],
2509
help='Debug flags to activate.'))
2510
option_registry.register(
2511
Option('default_format', default='2a',
2512
help='Format used when creating branches.'))
2513
option_registry.register(
2515
help='The command called to launch an editor to enter a message.'))
2516
option_registry.register(
2517
Option('email', override_from_env=['BRZ_EMAIL', 'BZR_EMAIL'],
2518
default=bedding.default_email, help='The users identity'))
2519
option_registry.register(
2520
Option('gpg_signing_key',
2523
GPG key to use for signing.
2525
This defaults to the first key associated with the users email.
2527
option_registry.register(
2529
help='Language to translate messages into.'))
2530
option_registry.register(
2531
Option('locks.steal_dead', default=True, from_unicode=bool_from_store,
2533
Steal locks that appears to be dead.
2535
If set to True, bzr will check if a lock is supposed to be held by an
2536
active process from the same user on the same machine. If the user and
2537
machine match, but no process with the given PID is active, then bzr
2538
will automatically break the stale lock, and create a new lock for
2540
Otherwise, bzr will prompt as normal to break the lock.
2542
option_registry.register(
2543
Option('log_format', default='long',
2545
Log format to use when displaying revisions.
2547
Standard log formats are ``long``, ``short`` and ``line``. Additional formats
2548
may be provided by plugins.
2550
option_registry.register_lazy('mail_client', 'breezy.mail_client',
2552
option_registry.register(
2553
Option('output_encoding',
2554
help='Unicode encoding for output'
2555
' (terminal encoding if not specified).'))
2556
option_registry.register(
2557
Option('parent_location',
2560
The location of the default branch for pull or merge.
2562
This option is normally set when creating a branch, the first ``pull`` or by
2563
``pull --remember``.
2565
option_registry.register(
2566
Option('post_commit', default=None,
2568
Post commit functions.
2570
An ordered list of python functions to call, separated by spaces.
2572
Each function takes branch, rev_id as parameters.
2574
option_registry.register_lazy('progress_bar', 'breezy.ui.text',
2576
option_registry.register(
2577
Option('public_branch',
2580
A publically-accessible version of this branch.
2582
This implies that the branch setting this option is not publically-accessible.
2583
Used and set by ``bzr send``.
2585
option_registry.register(
2586
Option('push_location',
2589
The location of the default branch for push.
2591
This option is normally set by the first ``push`` or ``push --remember``.
2593
option_registry.register(
2594
Option('push_strict', default=None,
2595
from_unicode=bool_from_store,
2597
The default value for ``push --strict``.
2599
If present, defines the ``--strict`` option default value for checking
2600
uncommitted changes before sending a merge directive.
2602
option_registry.register(
2603
Option('repository.fdatasync', default=True,
2604
from_unicode=bool_from_store,
2606
Flush repository changes onto physical disk?
2608
If true (default), repository changes are flushed through the OS buffers
2609
to physical disk. This is somewhat slower, but means data should not be
2610
lost if the machine crashes. See also dirstate.fdatasync.
2612
option_registry.register_lazy('smtp_server',
2613
'breezy.smtp_connection', 'smtp_server')
2614
option_registry.register_lazy('smtp_password',
2615
'breezy.smtp_connection', 'smtp_password')
2616
option_registry.register_lazy('smtp_username',
2617
'breezy.smtp_connection', 'smtp_username')
2618
option_registry.register(
2619
Option('selftest.timeout',
2621
from_unicode=int_from_store,
2622
help='Abort selftest if one test takes longer than this many seconds',
2625
option_registry.register(
2626
Option('send_strict', default=None,
2627
from_unicode=bool_from_store,
2629
The default value for ``send --strict``.
2631
If present, defines the ``--strict`` option default value for checking
2632
uncommitted changes before sending a bundle.
2635
option_registry.register(
2636
Option('serve.client_timeout',
2637
default=300.0, from_unicode=float_from_store,
2638
help="If we wait for a new request from a client for more than"
2639
" X seconds, consider the client idle, and hangup."))
2640
option_registry.register(
2642
default=None, override_from_env=['BRZ_SSH'],
2643
help='SSH vendor to use.'))
2644
option_registry.register(
2645
Option('stacked_on_location',
2647
help="""The location where this branch is stacked on."""))
2648
option_registry.register(
2649
Option('submit_branch',
2652
The branch you intend to submit your current work to.
2654
This is automatically set by ``bzr send`` and ``bzr merge``, and is also used
2655
by the ``submit:`` revision spec.
2657
option_registry.register(
2659
help='''Where submissions from this branch are mailed to.'''))
2660
option_registry.register(
2661
ListOption('suppress_warnings',
2663
help="List of warning classes to suppress."))
2664
option_registry.register(
2665
Option('validate_signatures_in_log', default=False,
2666
from_unicode=bool_from_store, invalid='warning',
2667
help='''Whether to validate signatures in brz log.'''))
2668
option_registry.register_lazy('ssl.ca_certs',
2669
'breezy.transport.http', 'opt_ssl_ca_certs')
2671
option_registry.register_lazy('ssl.cert_reqs',
2672
'breezy.transport.http', 'opt_ssl_cert_reqs')
2675
class Section(object):
2676
"""A section defines a dict of option name => value.
2678
This is merely a read-only dict which can add some knowledge about the
2679
options. It is *not* a python dict object though and doesn't try to mimic
2683
def __init__(self, section_id, options):
2684
self.id = section_id
2685
# We re-use the dict-like object received
2686
self.options = options
2688
def get(self, name, default=None, expand=True):
2689
return self.options.get(name, default)
2691
def iter_option_names(self):
2692
for k in self.options.keys():
2696
# Mostly for debugging use
2697
return "<config.%s id=%s>" % (self.__class__.__name__, self.id)
2700
_NewlyCreatedOption = object()
2701
"""Was the option created during the MutableSection lifetime"""
2702
_DeletedOption = object()
2703
"""Was the option deleted during the MutableSection lifetime"""
2706
class MutableSection(Section):
2707
"""A section allowing changes and keeping track of the original values."""
2709
def __init__(self, section_id, options):
2710
super(MutableSection, self).__init__(section_id, options)
2711
self.reset_changes()
2713
def set(self, name, value):
2714
if name not in self.options:
2715
# This is a new option
2716
self.orig[name] = _NewlyCreatedOption
2717
elif name not in self.orig:
2718
self.orig[name] = self.get(name, None)
2719
self.options[name] = value
2721
def remove(self, name):
2722
if name not in self.orig and name in self.options:
2723
self.orig[name] = self.get(name, None)
2724
del self.options[name]
2726
def reset_changes(self):
2729
def apply_changes(self, dirty, store):
2730
"""Apply option value changes.
2732
``self`` has been reloaded from the persistent storage. ``dirty``
2733
contains the changes made since the previous loading.
2735
:param dirty: the mutable section containing the changes.
2737
:param store: the store containing the section
2739
for k, expected in dirty.orig.items():
2740
actual = dirty.get(k, _DeletedOption)
2741
reloaded = self.get(k, _NewlyCreatedOption)
2742
if actual is _DeletedOption:
2743
if k in self.options:
2747
# Report concurrent updates in an ad-hoc way. This should only
2748
# occurs when different processes try to update the same option
2749
# which is not supported (as in: the config framework is not meant
2750
# to be used as a sharing mechanism).
2751
if expected != reloaded:
2752
if actual is _DeletedOption:
2753
actual = '<DELETED>'
2754
if reloaded is _NewlyCreatedOption:
2755
reloaded = '<CREATED>'
2756
if expected is _NewlyCreatedOption:
2757
expected = '<CREATED>'
2758
# Someone changed the value since we get it from the persistent
2760
trace.warning(gettext(
2761
"Option {0} in section {1} of {2} was changed"
2762
" from {3} to {4}. The {5} value will be saved.".format(
2763
k, self.id, store.external_url(), expected,
2765
# No need to keep track of these changes
2766
self.reset_changes()
2769
class Store(object):
2770
"""Abstract interface to persistent storage for configuration options."""
2772
readonly_section_class = Section
2773
mutable_section_class = MutableSection
2776
# Which sections need to be saved (by section id). We use a dict here
2777
# so the dirty sections can be shared by multiple callers.
2778
self.dirty_sections = {}
2780
def is_loaded(self):
2781
"""Returns True if the Store has been loaded.
2783
This is used to implement lazy loading and ensure the persistent
2784
storage is queried only when needed.
2786
raise NotImplementedError(self.is_loaded)
2789
"""Loads the Store from persistent storage."""
2790
raise NotImplementedError(self.load)
2792
def _load_from_string(self, bytes):
2793
"""Create a store from a string in configobj syntax.
2795
:param bytes: A string representing the file content.
2797
raise NotImplementedError(self._load_from_string)
2800
"""Unloads the Store.
2802
This should make is_loaded() return False. This is used when the caller
2803
knows that the persistent storage has changed or may have change since
2806
raise NotImplementedError(self.unload)
2808
def quote(self, value):
2809
"""Quote a configuration option value for storing purposes.
2811
This allows Stacks to present values as they will be stored.
2815
def unquote(self, value):
2816
"""Unquote a configuration option value into unicode.
2818
The received value is quoted as stored.
2823
"""Saves the Store to persistent storage."""
2824
raise NotImplementedError(self.save)
2826
def _need_saving(self):
2827
for s in self.dirty_sections.values():
2829
# At least one dirty section contains a modification
2833
def apply_changes(self, dirty_sections):
2834
"""Apply changes from dirty sections while checking for coherency.
2836
The Store content is discarded and reloaded from persistent storage to
2837
acquire up-to-date values.
2839
Dirty sections are MutableSection which kept track of the value they
2840
are expected to update.
2842
# We need an up-to-date version from the persistent storage, unload the
2843
# store. The reload will occur when needed (triggered by the first
2844
# get_mutable_section() call below.
2846
# Apply the changes from the preserved dirty sections
2847
for section_id, dirty in dirty_sections.items():
2848
clean = self.get_mutable_section(section_id)
2849
clean.apply_changes(dirty, self)
2850
# Everything is clean now
2851
self.dirty_sections = {}
2853
def save_changes(self):
2854
"""Saves the Store to persistent storage if changes occurred.
2856
Apply the changes recorded in the mutable sections to a store content
2857
refreshed from persistent storage.
2859
raise NotImplementedError(self.save_changes)
2861
def external_url(self):
2862
raise NotImplementedError(self.external_url)
2864
def get_sections(self):
2865
"""Returns an ordered iterable of existing sections.
2867
:returns: An iterable of (store, section).
2869
raise NotImplementedError(self.get_sections)
2871
def get_mutable_section(self, section_id=None):
2872
"""Returns the specified mutable section.
2874
:param section_id: The section identifier
2876
raise NotImplementedError(self.get_mutable_section)
2879
# Mostly for debugging use
2880
return "<config.%s(%s)>" % (self.__class__.__name__,
2881
self.external_url())
2884
class CommandLineStore(Store):
2885
"A store to carry command line overrides for the config options."""
2887
def __init__(self, opts=None):
2888
super(CommandLineStore, self).__init__()
2895
# The dict should be cleared but not replaced so it can be shared.
2896
self.options.clear()
2898
def _from_cmdline(self, overrides):
2899
# Reset before accepting new definitions
2901
for over in overrides:
2903
name, value = over.split('=', 1)
2905
raise errors.CommandError(
2906
gettext("Invalid '%s', should be of the form 'name=value'")
2908
self.options[name] = value
2910
def external_url(self):
2911
# Not an url but it makes debugging easier and is never needed
2915
def get_sections(self):
2916
yield self, self.readonly_section_class(None, self.options)
2919
class IniFileStore(Store):
2920
"""A config Store using ConfigObj for storage.
2922
:ivar _config_obj: Private member to hold the ConfigObj instance used to
2923
serialize/deserialize the config file.
2927
"""A config Store using ConfigObj for storage.
2929
super(IniFileStore, self).__init__()
2930
self._config_obj = None
2932
def is_loaded(self):
2933
return self._config_obj is not None
2936
self._config_obj = None
2937
self.dirty_sections = {}
2939
def _load_content(self):
2940
"""Load the config file bytes.
2942
This should be provided by subclasses
2944
:return: Byte string
2946
raise NotImplementedError(self._load_content)
2948
def _save_content(self, content):
2949
"""Save the config file bytes.
2951
This should be provided by subclasses
2953
:param content: Config file bytes to write
2955
raise NotImplementedError(self._save_content)
2958
"""Load the store from the associated file."""
2959
if self.is_loaded():
2961
content = self._load_content()
2962
self._load_from_string(content)
2963
for hook in ConfigHooks['load']:
2966
def _load_from_string(self, bytes):
2967
"""Create a config store from a string.
2969
:param bytes: A string representing the file content.
2971
if self.is_loaded():
2972
raise AssertionError('Already loaded: %r' % (self._config_obj,))
2973
co_input = BytesIO(bytes)
2975
# The config files are always stored utf8-encoded
2976
self._config_obj = ConfigObj(co_input, encoding='utf-8',
2978
except configobj.ConfigObjError as e:
2979
self._config_obj = None
2980
raise ParseConfigError(e.errors, self.external_url())
2981
except UnicodeDecodeError:
2982
raise ConfigContentError(self.external_url())
2984
def save_changes(self):
2985
if not self.is_loaded():
2988
if not self._need_saving():
2990
# Preserve the current version
2991
dirty_sections = self.dirty_sections.copy()
2992
self.apply_changes(dirty_sections)
2993
# Save to the persistent storage
2997
if not self.is_loaded():
3001
self._config_obj.write(out)
3002
self._save_content(out.getvalue())
3003
for hook in ConfigHooks['save']:
3006
def get_sections(self):
3007
"""Get the configobj section in the file order.
3009
:returns: An iterable of (store, section).
3011
# We need a loaded store
3014
except (errors.NoSuchFile, errors.PermissionDenied):
3015
# If the file can't be read, there is no sections
3017
cobj = self._config_obj
3019
yield self, self.readonly_section_class(None, cobj)
3020
for section_name in cobj.sections:
3022
self.readonly_section_class(section_name,
3023
cobj[section_name]))
3025
def get_mutable_section(self, section_id=None):
3026
# We need a loaded store
3029
except errors.NoSuchFile:
3030
# The file doesn't exist, let's pretend it was empty
3031
self._load_from_string(b'')
3032
if section_id in self.dirty_sections:
3033
# We already created a mutable section for this id
3034
return self.dirty_sections[section_id]
3035
if section_id is None:
3036
section = self._config_obj
3038
section = self._config_obj.setdefault(section_id, {})
3039
mutable_section = self.mutable_section_class(section_id, section)
3040
# All mutable sections can become dirty
3041
self.dirty_sections[section_id] = mutable_section
3042
return mutable_section
3044
def quote(self, value):
3046
# configobj conflates automagical list values and quoting
3047
self._config_obj.list_values = True
3048
return self._config_obj._quote(value)
3050
self._config_obj.list_values = False
3052
def unquote(self, value):
3053
if value and isinstance(value, str):
3054
# _unquote doesn't handle None nor empty strings nor anything that
3055
# is not a string, really.
3056
value = self._config_obj._unquote(value)
3059
def external_url(self):
3060
# Since an IniFileStore can be used without a file (at least in tests),
3061
# it's better to provide something than raising a NotImplementedError.
3062
# All daughter classes are supposed to provide an implementation
3064
return 'In-Process Store, no URL'
3067
class TransportIniFileStore(IniFileStore):
3068
"""IniFileStore that loads files from a transport.
3070
:ivar transport: The transport object where the config file is located.
3072
:ivar file_name: The config file basename in the transport directory.
3075
def __init__(self, transport, file_name):
3076
"""A Store using a ini file on a Transport
3078
:param transport: The transport object where the config file is located.
3079
:param file_name: The config file basename in the transport directory.
3081
super(TransportIniFileStore, self).__init__()
3082
self.transport = transport
3083
self.file_name = file_name
3085
def _load_content(self):
3087
return self.transport.get_bytes(self.file_name)
3088
except errors.PermissionDenied:
3089
trace.warning("Permission denied while trying to load "
3090
"configuration store %s.", self.external_url())
3093
def _save_content(self, content):
3094
self.transport.put_bytes(self.file_name, content)
3096
def external_url(self):
3097
# FIXME: external_url should really accepts an optional relpath
3098
# parameter (bug #750169) :-/ -- vila 2011-04-04
3099
# The following will do in the interim but maybe we don't want to
3100
# expose a path here but rather a config ID and its associated
3101
# object </hand wawe>.
3102
return urlutils.join(
3103
self.transport.external_url(), urlutils.escape(self.file_name))
3106
# Note that LockableConfigObjStore inherits from ConfigObjStore because we need
3107
# unlockable stores for use with objects that can already ensure the locking
3108
# (think branches). If different stores (not based on ConfigObj) are created,
3109
# they may face the same issue.
3112
class LockableIniFileStore(TransportIniFileStore):
3113
"""A ConfigObjStore using locks on save to ensure store integrity."""
3115
def __init__(self, transport, file_name, lock_dir_name=None):
3116
"""A config Store using ConfigObj for storage.
3118
:param transport: The transport object where the config file is located.
3120
:param file_name: The config file basename in the transport directory.
3122
if lock_dir_name is None:
3123
lock_dir_name = 'lock'
3124
self.lock_dir_name = lock_dir_name
3125
super(LockableIniFileStore, self).__init__(transport, file_name)
3126
self._lock = lockdir.LockDir(self.transport, self.lock_dir_name)
3128
def lock_write(self, token=None):
3129
"""Takes a write lock in the directory containing the config file.
3131
If the directory doesn't exist it is created.
3133
# FIXME: This doesn't check the ownership of the created directories as
3134
# ensure_config_dir_exists does. It should if the transport is local
3135
# -- vila 2011-04-06
3136
self.transport.create_prefix()
3137
token = self._lock.lock_write(token)
3138
return lock.LogicalLockResult(self.unlock, token)
3143
def break_lock(self):
3144
self._lock.break_lock()
3147
with self.lock_write():
3148
# We need to be able to override the undecorated implementation
3149
self.save_without_locking()
3151
def save_without_locking(self):
3152
super(LockableIniFileStore, self).save()
3155
# FIXME: global, breezy, shouldn't that be 'user' instead or even
3156
# 'user_defaults' as opposed to 'user_overrides', 'system_defaults'
3157
# (/etc/bzr/bazaar.conf) and 'system_overrides' ? -- vila 2011-04-05
3159
# FIXME: Moreover, we shouldn't need classes for these stores either, factory
3160
# functions or a registry will make it easier and clearer for tests, focusing
3161
# on the relevant parts of the API that needs testing -- vila 20110503 (based
3162
# on a poolie's remark)
3163
class GlobalStore(LockableIniFileStore):
3164
"""A config store for global options.
3166
There is a single GlobalStore for a given process.
3169
def __init__(self, possible_transports=None):
3170
path, kind = bedding._config_dir()
3171
t = transport.get_transport_from_path(
3172
path, possible_transports=possible_transports)
3173
super(GlobalStore, self).__init__(t, kind + '.conf')
3177
class LocationStore(LockableIniFileStore):
3178
"""A config store for options specific to a location.
3180
There is a single LocationStore for a given process.
3183
def __init__(self, possible_transports=None):
3184
t = transport.get_transport_from_path(
3185
bedding.config_dir(), possible_transports=possible_transports)
3186
super(LocationStore, self).__init__(t, 'locations.conf')
3187
self.id = 'locations'
3190
class BranchStore(TransportIniFileStore):
3191
"""A config store for branch options.
3193
There is a single BranchStore for a given branch.
3196
def __init__(self, branch):
3197
super(BranchStore, self).__init__(branch.control_transport,
3199
self.branch = branch
3203
class ControlStore(LockableIniFileStore):
3205
def __init__(self, bzrdir):
3206
super(ControlStore, self).__init__(bzrdir.transport,
3208
lock_dir_name='branch_lock')
3212
class SectionMatcher(object):
3213
"""Select sections into a given Store.
3215
This is intended to be used to postpone getting an iterable of sections
3219
def __init__(self, store):
3222
def get_sections(self):
3223
# This is where we require loading the store so we can see all defined
3225
sections = self.store.get_sections()
3226
# Walk the revisions in the order provided
3227
for store, s in sections:
3231
def match(self, section):
3232
"""Does the proposed section match.
3234
:param section: A Section object.
3236
:returns: True if the section matches, False otherwise.
3238
raise NotImplementedError(self.match)
3241
class NameMatcher(SectionMatcher):
3243
def __init__(self, store, section_id):
3244
super(NameMatcher, self).__init__(store)
3245
self.section_id = section_id
3247
def match(self, section):
3248
return section.id == self.section_id
3251
class LocationSection(Section):
3253
def __init__(self, section, extra_path, branch_name=None):
3254
super(LocationSection, self).__init__(section.id, section.options)
3255
self.extra_path = extra_path
3256
if branch_name is None:
3258
self.locals = {'relpath': extra_path,
3259
'basename': urlutils.basename(extra_path),
3260
'branchname': branch_name}
3262
def get(self, name, default=None, expand=True):
3263
value = super(LocationSection, self).get(name, default)
3264
if value is not None and expand:
3265
policy_name = self.get(name + ':policy', None)
3266
policy = _policy_value.get(policy_name, POLICY_NONE)
3267
if policy == POLICY_APPENDPATH:
3268
value = urlutils.join(value, self.extra_path)
3269
# expand section local options right now (since POLICY_APPENDPATH
3270
# will never add options references, it's ok to expand after it).
3272
for is_ref, chunk in iter_option_refs(value):
3274
chunks.append(chunk)
3277
if ref in self.locals:
3278
chunks.append(self.locals[ref])
3280
chunks.append(chunk)
3281
value = ''.join(chunks)
3285
class StartingPathMatcher(SectionMatcher):
3286
"""Select sections for a given location respecting the Store order."""
3288
# FIXME: Both local paths and urls can be used for section names as well as
3289
# ``location`` to stay consistent with ``LocationMatcher`` which itself
3290
# inherited the fuzziness from the previous ``LocationConfig``
3291
# implementation. We probably need to revisit which encoding is allowed for
3292
# both ``location`` and section names and how we normalize
3293
# them. http://pad.lv/85479, http://pad.lv/437009 and http://359320 are
3294
# related too. -- vila 2012-01-04
3296
def __init__(self, store, location):
3297
super(StartingPathMatcher, self).__init__(store)
3298
if location.startswith('file://'):
3299
location = urlutils.local_path_from_url(location)
3300
self.location = location
3302
def get_sections(self):
3303
"""Get all sections matching ``location`` in the store.
3305
The most generic sections are described first in the store, then more
3306
specific ones can be provided for reduced scopes.
3308
The returned section are therefore returned in the reversed order so
3309
the most specific ones can be found first.
3311
location_parts = self.location.rstrip('/').split('/')
3313
# Later sections are more specific, they should be returned first
3314
for _, section in reversed(list(store.get_sections())):
3315
if section.id is None:
3316
# The no-name section is always included if present
3317
yield store, LocationSection(section, self.location)
3319
section_path = section.id
3320
if section_path.startswith('file://'):
3321
# the location is already a local path or URL, convert the
3322
# section id to the same format
3323
section_path = urlutils.local_path_from_url(section_path)
3324
if (self.location.startswith(section_path) or
3325
fnmatch.fnmatch(self.location, section_path)):
3326
section_parts = section_path.rstrip('/').split('/')
3327
extra_path = '/'.join(location_parts[len(section_parts):])
3328
yield store, LocationSection(section, extra_path)
3331
class LocationMatcher(SectionMatcher):
3333
def __init__(self, store, location):
3334
super(LocationMatcher, self).__init__(store)
3335
url, params = urlutils.split_segment_parameters(location)
3336
if location.startswith('file://'):
3337
location = urlutils.local_path_from_url(location)
3338
self.location = location
3339
branch_name = params.get('branch')
3340
if branch_name is None:
3341
self.branch_name = urlutils.basename(self.location)
3343
self.branch_name = urlutils.unescape(branch_name)
3345
def _get_matching_sections(self):
3346
"""Get all sections matching ``location``."""
3347
# We slightly diverge from LocalConfig here by allowing the no-name
3348
# section as the most generic one and the lower priority.
3349
no_name_section = None
3351
# Filter out the no_name_section so _iter_for_location_by_parts can be
3352
# used (it assumes all sections have a name).
3353
for _, section in self.store.get_sections():
3354
if section.id is None:
3355
no_name_section = section
3357
all_sections.append(section)
3358
# Unfortunately _iter_for_location_by_parts deals with section names so
3359
# we have to resync.
3360
filtered_sections = _iter_for_location_by_parts(
3361
[s.id for s in all_sections], self.location)
3362
iter_all_sections = iter(all_sections)
3363
matching_sections = []
3364
if no_name_section is not None:
3365
matching_sections.append(
3366
(0, LocationSection(no_name_section, self.location)))
3367
for section_id, extra_path, length in filtered_sections:
3368
# a section id is unique for a given store so it's safe to take the
3369
# first matching section while iterating. Also, all filtered
3370
# sections are part of 'all_sections' and will always be found
3373
section = next(iter_all_sections)
3374
if section_id == section.id:
3375
section = LocationSection(section, extra_path,
3377
matching_sections.append((length, section))
3379
return matching_sections
3381
def get_sections(self):
3382
# Override the default implementation as we want to change the order
3383
# We want the longest (aka more specific) locations first
3384
sections = sorted(self._get_matching_sections(),
3385
key=lambda match: (match[0], match[1].id),
3387
# Sections mentioning 'ignore_parents' restrict the selection
3388
for _, section in sections:
3389
# FIXME: We really want to use as_bool below -- vila 2011-04-07
3390
ignore = section.get('ignore_parents', None)
3391
if ignore is not None:
3392
ignore = ui.bool_from_string(ignore)
3395
# Finally, we have a valid section
3396
yield self.store, section
3399
# FIXME: _shared_stores should be an attribute of a library state once a
3400
# library_state object is always available.
3402
_shared_stores_at_exit_installed = False
3405
class Stack(object):
3406
"""A stack of configurations where an option can be defined"""
3408
def __init__(self, sections_def, store=None, mutable_section_id=None):
3409
"""Creates a stack of sections with an optional store for changes.
3411
:param sections_def: A list of Section or callables that returns an
3412
iterable of Section. This defines the Sections for the Stack and
3413
can be called repeatedly if needed.
3415
:param store: The optional Store where modifications will be
3416
recorded. If none is specified, no modifications can be done.
3418
:param mutable_section_id: The id of the MutableSection where changes
3419
are recorded. This requires the ``store`` parameter to be
3422
self.sections_def = sections_def
3424
self.mutable_section_id = mutable_section_id
3426
def iter_sections(self):
3427
"""Iterate all the defined sections."""
3428
# Ensuring lazy loading is achieved by delaying section matching (which
3429
# implies querying the persistent storage) until it can't be avoided
3430
# anymore by using callables to describe (possibly empty) section
3432
for sections in self.sections_def:
3433
for store, section in sections():
3434
yield store, section
3436
def get(self, name, expand=True, convert=True):
3437
"""Return the *first* option value found in the sections.
3439
This is where we guarantee that sections coming from Store are loaded
3440
lazily: the loading is delayed until we need to either check that an
3441
option exists or get its value, which in turn may require to discover
3442
in which sections it can be defined. Both of these (section and option
3443
existence) require loading the store (even partially).
3445
:param name: The queried option.
3447
:param expand: Whether options references should be expanded.
3449
:param convert: Whether the option value should be converted from
3450
unicode (do nothing for non-registered options).
3452
:returns: The value of the option.
3454
# FIXME: No caching of options nor sections yet -- vila 20110503
3456
found_store = None # Where the option value has been found
3457
# If the option is registered, it may provide additional info about
3460
opt = option_registry.get(name)
3465
def expand_and_convert(val):
3466
# This may need to be called in different contexts if the value is
3467
# None or ends up being None during expansion or conversion.
3470
if isinstance(val, str):
3471
val = self._expand_options_in_string(val)
3473
trace.warning('Cannot expand "%s":'
3474
' %s does not support option expansion'
3475
% (name, type(val)))
3477
val = found_store.unquote(val)
3479
val = opt.convert_from_unicode(found_store, val)
3482
# First of all, check if the environment can override the configuration
3484
if opt is not None and opt.override_from_env:
3485
value = opt.get_override()
3486
value = expand_and_convert(value)
3488
for store, section in self.iter_sections():
3489
value = section.get(name)
3490
if value is not None:
3493
value = expand_and_convert(value)
3494
if opt is not None and value is None:
3495
# If the option is registered, it may provide a default value
3496
value = opt.get_default()
3497
value = expand_and_convert(value)
3498
for hook in ConfigHooks['get']:
3499
hook(self, name, value)
3502
def expand_options(self, string, env=None):
3503
"""Expand option references in the string in the configuration context.
3505
:param string: The string containing option(s) to expand.
3507
:param env: An option dict defining additional configuration options or
3508
overriding existing ones.
3510
:returns: The expanded string.
3512
return self._expand_options_in_string(string, env)
3514
def _expand_options_in_string(self, string, env=None, _refs=None):
3515
"""Expand options in the string in the configuration context.
3517
:param string: The string to be expanded.
3519
:param env: An option dict defining additional configuration options or
3520
overriding existing ones.
3522
:param _refs: Private list (FIFO) containing the options being expanded
3525
:returns: The expanded string.
3528
# Not much to expand there
3531
# What references are currently resolved (to detect loops)
3534
# We need to iterate until no more refs appear ({{foo}} will need two
3535
# iterations for example).
3540
for is_ref, chunk in iter_option_refs(result):
3542
chunks.append(chunk)
3547
raise OptionExpansionLoop(string, _refs)
3549
value = self._expand_option(name, env, _refs)
3551
raise ExpandingUnknownOption(name, string)
3552
chunks.append(value)
3554
result = ''.join(chunks)
3557
def _expand_option(self, name, env, _refs):
3558
if env is not None and name in env:
3559
# Special case, values provided in env takes precedence over
3563
value = self.get(name, expand=False, convert=False)
3564
value = self._expand_options_in_string(value, env, _refs)
3567
def _get_mutable_section(self):
3568
"""Get the MutableSection for the Stack.
3570
This is where we guarantee that the mutable section is lazily loaded:
3571
this means we won't load the corresponding store before setting a value
3572
or deleting an option. In practice the store will often be loaded but
3573
this helps catching some programming errors.
3576
section = store.get_mutable_section(self.mutable_section_id)
3577
return store, section
3579
def set(self, name, value):
3580
"""Set a new value for the option."""
3581
store, section = self._get_mutable_section()
3582
section.set(name, store.quote(value))
3583
for hook in ConfigHooks['set']:
3584
hook(self, name, value)
3586
def remove(self, name):
3587
"""Remove an existing option."""
3588
_, section = self._get_mutable_section()
3589
section.remove(name)
3590
for hook in ConfigHooks['remove']:
3594
# Mostly for debugging use
3595
return "<config.%s(%s)>" % (self.__class__.__name__, id(self))
3597
def _get_overrides(self):
3598
if breezy._global_state is not None:
3599
# TODO(jelmer): Urgh, this is circular so we can't call breezy.get_global_state()
3600
return breezy._global_state.cmdline_overrides.get_sections()
3603
def get_shared_store(self, store, state=None):
3604
"""Get a known shared store.
3606
Store urls uniquely identify them and are used to ensure a single copy
3607
is shared across all users.
3609
:param store: The store known to the caller.
3611
:param state: The library state where the known stores are kept.
3613
:returns: The store received if it's not a known one, an already known
3617
# TODO(jelmer): Urgh, this is circular so we can't call breezy.get_global_state()
3618
state = breezy._global_state
3620
global _shared_stores_at_exit_installed
3621
stores = _shared_stores
3623
def save_config_changes():
3624
for k, store in stores.items():
3625
store.save_changes()
3626
if not _shared_stores_at_exit_installed:
3627
# FIXME: Ugly hack waiting for library_state to always be
3628
# available. -- vila 20120731
3630
atexit.register(save_config_changes)
3631
_shared_stores_at_exit_installed = True
3633
stores = state.config_stores
3634
url = store.external_url()
3642
class MemoryStack(Stack):
3643
"""A configuration stack defined from a string.
3645
This is mainly intended for tests and requires no disk resources.
3648
def __init__(self, content=None):
3649
"""Create an in-memory stack from a given content.
3651
It uses a single store based on configobj and support reading and
3654
:param content: The initial content of the store. If None, the store is
3655
not loaded and ``_load_from_string`` can and should be used if
3658
store = IniFileStore()
3659
if content is not None:
3660
store._load_from_string(content)
3661
super(MemoryStack, self).__init__(
3662
[store.get_sections], store)
3665
class _CompatibleStack(Stack):
3666
"""Place holder for compatibility with previous design.
3668
This is intended to ease the transition from the Config-based design to the
3669
Stack-based design and should not be used nor relied upon by plugins.
3671
One assumption made here is that the daughter classes will all use Stores
3672
derived from LockableIniFileStore).
3674
It implements set() and remove () by re-loading the store before applying
3675
the modification and saving it.
3677
The long term plan being to implement a single write by store to save
3678
all modifications, this class should not be used in the interim.
3681
def set(self, name, value):
3684
super(_CompatibleStack, self).set(name, value)
3685
# Force a write to persistent storage
3688
def remove(self, name):
3691
super(_CompatibleStack, self).remove(name)
3692
# Force a write to persistent storage
3696
class GlobalStack(Stack):
3697
"""Global options only stack.
3699
The following sections are queried:
3701
* command-line overrides,
3703
* the 'DEFAULT' section in bazaar.conf
3705
This stack will use the ``DEFAULT`` section in bazaar.conf as its
3710
gstore = self.get_shared_store(GlobalStore())
3711
super(GlobalStack, self).__init__(
3712
[self._get_overrides,
3713
NameMatcher(gstore, 'DEFAULT').get_sections],
3714
gstore, mutable_section_id='DEFAULT')
3717
class LocationStack(Stack):
3718
"""Per-location options falling back to global options stack.
3721
The following sections are queried:
3723
* command-line overrides,
3725
* the sections matching ``location`` in ``locations.conf``, the order being
3726
defined by the number of path components in the section glob, higher
3727
numbers first (from most specific section to most generic).
3729
* the 'DEFAULT' section in bazaar.conf
3731
This stack will use the ``location`` section in locations.conf as its
3735
def __init__(self, location):
3736
"""Make a new stack for a location and global configuration.
3738
:param location: A URL prefix to """
3739
lstore = self.get_shared_store(LocationStore())
3740
if location.startswith('file://'):
3741
location = urlutils.local_path_from_url(location)
3742
gstore = self.get_shared_store(GlobalStore())
3743
super(LocationStack, self).__init__(
3744
[self._get_overrides,
3745
LocationMatcher(lstore, location).get_sections,
3746
NameMatcher(gstore, 'DEFAULT').get_sections],
3747
lstore, mutable_section_id=location)
3750
class BranchStack(Stack):
3751
"""Per-location options falling back to branch then global options stack.
3753
The following sections are queried:
3755
* command-line overrides,
3757
* the sections matching ``location`` in ``locations.conf``, the order being
3758
defined by the number of path components in the section glob, higher
3759
numbers first (from most specific section to most generic),
3761
* the no-name section in branch.conf,
3763
* the ``DEFAULT`` section in ``bazaar.conf``.
3765
This stack will use the no-name section in ``branch.conf`` as its
3769
def __init__(self, branch):
3770
lstore = self.get_shared_store(LocationStore())
3771
bstore = branch._get_config_store()
3772
gstore = self.get_shared_store(GlobalStore())
3773
super(BranchStack, self).__init__(
3774
[self._get_overrides,
3775
LocationMatcher(lstore, branch.base).get_sections,
3776
NameMatcher(bstore, None).get_sections,
3777
NameMatcher(gstore, 'DEFAULT').get_sections],
3779
self.branch = branch
3781
def lock_write(self, token=None):
3782
return self.branch.lock_write(token)
3785
return self.branch.unlock()
3787
def set(self, name, value):
3788
with self.lock_write():
3789
super(BranchStack, self).set(name, value)
3790
# Unlocking the branch will trigger a store.save_changes() so the
3791
# last unlock saves all the changes.
3793
def remove(self, name):
3794
with self.lock_write():
3795
super(BranchStack, self).remove(name)
3796
# Unlocking the branch will trigger a store.save_changes() so the
3797
# last unlock saves all the changes.
3800
class RemoteControlStack(Stack):
3801
"""Remote control-only options stack."""
3803
# FIXME 2011-11-22 JRV This should probably be renamed to avoid confusion
3804
# with the stack used for remote bzr dirs. RemoteControlStack only uses
3805
# control.conf and is used only for stack options.
3807
def __init__(self, bzrdir):
3808
cstore = bzrdir._get_config_store()
3809
super(RemoteControlStack, self).__init__(
3810
[NameMatcher(cstore, None).get_sections],
3812
self.controldir = bzrdir
3815
class BranchOnlyStack(Stack):
3816
"""Branch-only options stack."""
3818
# FIXME: _BranchOnlyStack only uses branch.conf and is used only for the
3819
# stacked_on_location options waiting for http://pad.lv/832042 to be fixed.
3820
# -- vila 2011-12-16
3822
def __init__(self, branch):
3823
bstore = branch._get_config_store()
3824
super(BranchOnlyStack, self).__init__(
3825
[NameMatcher(bstore, None).get_sections],
3827
self.branch = branch
3829
def lock_write(self, token=None):
3830
return self.branch.lock_write(token)
3833
return self.branch.unlock()
3835
def set(self, name, value):
3836
with self.lock_write():
3837
super(BranchOnlyStack, self).set(name, value)
3838
# Force a write to persistent storage
3839
self.store.save_changes()
3841
def remove(self, name):
3842
with self.lock_write():
3843
super(BranchOnlyStack, self).remove(name)
3844
# Force a write to persistent storage
3845
self.store.save_changes()
3848
class cmd_config(commands.Command):
3849
__doc__ = """Display, set or remove a configuration option.
3851
Display the active value for option NAME.
3853
If --all is specified, NAME is interpreted as a regular expression and all
3854
matching options are displayed mentioning their scope and without resolving
3855
option references in the value). The active value that bzr will take into
3856
account is the first one displayed for each option.
3858
If NAME is not given, --all .* is implied (all options are displayed for the
3861
Setting a value is achieved by using NAME=value without spaces. The value
3862
is set in the most relevant scope and can be checked by displaying the
3865
Removing a value is achieved by using --remove NAME.
3868
takes_args = ['name?']
3872
# FIXME: This should be a registry option so that plugins can register
3873
# their own config files (or not) and will also address
3874
# http://pad.lv/788991 -- vila 20101115
3875
commands.Option('scope', help='Reduce the scope to the specified'
3876
' configuration file.',
3878
commands.Option('all',
3879
help='Display all the defined values for the matching options.',
3881
commands.Option('remove', help='Remove the option from'
3882
' the configuration file.'),
3885
_see_also = ['configuration']
3887
@commands.display_command
3888
def run(self, name=None, all=False, directory=None, scope=None,
3890
if directory is None:
3892
directory = directory_service.directories.dereference(directory)
3893
directory = urlutils.normalize_url(directory)
3895
raise errors.BzrError(
3896
'--all and --remove are mutually exclusive.')
3898
# Delete the option in the given scope
3899
self._remove_config_option(name, directory, scope)
3901
# Defaults to all options
3902
self._show_matching_options('.*', directory, scope)
3905
name, value = name.split('=', 1)
3907
# Display the option(s) value(s)
3909
self._show_matching_options(name, directory, scope)
3911
self._show_value(name, directory, scope)
3914
raise errors.BzrError(
3915
'Only one option can be set.')
3916
# Set the option value
3917
self._set_config_option(name, value, directory, scope)
3919
def _get_stack(self, directory, scope=None, write_access=False):
3920
"""Get the configuration stack specified by ``directory`` and ``scope``.
3922
:param directory: Where the configurations are derived from.
3924
:param scope: A specific config to start from.
3926
:param write_access: Whether a write access to the stack will be
3929
# FIXME: scope should allow access to plugin-specific stacks (even
3930
# reduced to the plugin-specific store), related to
3931
# http://pad.lv/788991 -- vila 2011-11-15
3932
if scope is not None:
3933
if scope == 'breezy':
3934
return GlobalStack()
3935
elif scope == 'locations':
3936
return LocationStack(directory)
3937
elif scope == 'branch':
3939
controldir.ControlDir.open_containing_tree_or_branch(
3942
self.add_cleanup(br.lock_write().unlock)
3943
return br.get_config_stack()
3944
raise NoSuchConfig(scope)
3948
controldir.ControlDir.open_containing_tree_or_branch(
3951
self.add_cleanup(br.lock_write().unlock)
3952
return br.get_config_stack()
3953
except errors.NotBranchError:
3954
return LocationStack(directory)
3956
def _quote_multiline(self, value):
3958
value = '"""' + value + '"""'
3961
def _show_value(self, name, directory, scope):
3962
conf = self._get_stack(directory, scope)
3963
value = conf.get(name, expand=True, convert=False)
3964
if value is not None:
3965
# Quote the value appropriately
3966
value = self._quote_multiline(value)
3967
self.outf.write('%s\n' % (value,))
3969
raise NoSuchConfigOption(name)
3971
def _show_matching_options(self, name, directory, scope):
3972
name = lazy_regex.lazy_compile(name)
3973
# We want any error in the regexp to be raised *now* so we need to
3974
# avoid the delay introduced by the lazy regexp. But, we still do
3975
# want the nicer errors raised by lazy_regex.
3976
name._compile_and_collapse()
3979
conf = self._get_stack(directory, scope)
3980
for store, section in conf.iter_sections():
3981
for oname in section.iter_option_names():
3982
if name.search(oname):
3983
if cur_store_id != store.id:
3984
# Explain where the options are defined
3985
self.outf.write('%s:\n' % (store.id,))
3986
cur_store_id = store.id
3988
if (section.id is not None and cur_section != section.id):
3989
# Display the section id as it appears in the store
3990
# (None doesn't appear by definition)
3991
self.outf.write(' [%s]\n' % (section.id,))
3992
cur_section = section.id
3993
value = section.get(oname, expand=False)
3994
# Quote the value appropriately
3995
value = self._quote_multiline(value)
3996
self.outf.write(' %s = %s\n' % (oname, value))
3998
def _set_config_option(self, name, value, directory, scope):
3999
conf = self._get_stack(directory, scope, write_access=True)
4000
conf.set(name, value)
4001
# Explicitly save the changes
4002
conf.store.save_changes()
4004
def _remove_config_option(self, name, directory, scope):
4006
raise errors.CommandError(
4007
'--remove expects an option to remove.')
4008
conf = self._get_stack(directory, scope, write_access=True)
4011
# Explicitly save the changes
4012
conf.store.save_changes()
4014
raise NoSuchConfigOption(name)
4019
# We need adapters that can build a Store or a Stack in a test context. Test
4020
# classes, based on TestCaseWithTransport, can use the registry to parametrize
4021
# themselves. The builder will receive a test instance and should return a
4022
# ready-to-use store or stack. Plugins that define new store/stacks can also
4023
# register themselves here to be tested against the tests defined in
4024
# breezy.tests.test_config. Note that the builder can be called multiple times
4025
# for the same test.
4027
# The registered object should be a callable receiving a test instance
4028
# parameter (inheriting from tests.TestCaseWithTransport) and returning a Store
4030
test_store_builder_registry = registry.Registry()
4032
# The registered object should be a callable receiving a test instance
4033
# parameter (inheriting from tests.TestCaseWithTransport) and returning a Stack
4035
test_stack_builder_registry = registry.Registry()