178
220
def _get_signing_policy(self):
179
221
"""Template method to override signature creation policy."""
225
def expand_options(self, string, env=None):
226
"""Expand option references in the string in the configuration context.
228
:param string: The string containing option to expand.
230
:param env: An option dict defining additional configuration options or
231
overriding existing ones.
233
:returns: The expanded string.
235
return self._expand_options_in_string(string, env)
237
def _expand_options_in_list(self, slist, env=None, _ref_stack=None):
238
"""Expand options in a list of strings in the configuration context.
240
:param slist: A list of strings.
242
:param env: An option dict defining additional configuration options or
243
overriding existing ones.
245
:param _ref_stack: Private list containing the options being
246
expanded to detect loops.
248
:returns: The flatten list of expanded strings.
250
# expand options in each value separately flattening lists
253
value = self._expand_options_in_string(s, env, _ref_stack)
254
if isinstance(value, list):
260
def _expand_options_in_string(self, string, env=None, _ref_stack=None):
261
"""Expand options in the string in the configuration context.
263
:param string: The string to be expanded.
265
:param env: An option dict defining additional configuration options or
266
overriding existing ones.
268
:param _ref_stack: Private list containing the options being
269
expanded to detect loops.
271
:returns: The expanded string.
274
# Not much to expand there
276
if _ref_stack is None:
277
# What references are currently resolved (to detect loops)
279
if self.option_ref_re is None:
280
# We want to match the most embedded reference first (i.e. for
281
# '{{foo}}' we will get '{foo}',
282
# for '{bar{baz}}' we will get '{baz}'
283
self.option_ref_re = re.compile('({[^{}]+})')
285
# We need to iterate until no more refs appear ({{foo}} will need two
286
# iterations for example).
288
raw_chunks = self.option_ref_re.split(result)
289
if len(raw_chunks) == 1:
290
# Shorcut the trivial case: no refs
294
# Split will isolate refs so that every other chunk is a ref
296
for chunk in raw_chunks:
299
# Keep only non-empty strings (or we get bogus empty
300
# slots when a list value is involved).
305
if name in _ref_stack:
306
raise errors.OptionExpansionLoop(string, _ref_stack)
307
_ref_stack.append(name)
308
value = self._expand_option(name, env, _ref_stack)
310
raise errors.ExpandingUnknownOption(name, string)
311
if isinstance(value, list):
319
# Once a list appears as the result of an expansion, all
320
# callers will get a list result. This allows a consistent
321
# behavior even when some options in the expansion chain
322
# defined as strings (no comma in their value) but their
323
# expanded value is a list.
324
return self._expand_options_in_list(chunks, env, _ref_stack)
326
result = ''.join(chunks)
329
def _expand_option(self, name, env, _ref_stack):
330
if env is not None and name in env:
331
# Special case, values provided in env takes precedence over
335
# FIXME: This is a limited implementation, what we really need is a
336
# way to query the bzr config for the value of an option,
337
# respecting the scope rules (That is, once we implement fallback
338
# configs, getting the option value should restart from the top
339
# config, not the current one) -- vila 20101222
340
value = self.get_user_option(name, expand=False)
341
if isinstance(value, list):
342
value = self._expand_options_in_list(value, env, _ref_stack)
344
value = self._expand_options_in_string(value, env, _ref_stack)
181
347
def _get_user_option(self, option_name):
182
348
"""Template method to provide a user option."""
185
def get_user_option(self, option_name):
186
"""Get a generic option - no special process, no default."""
187
return self._get_user_option(option_name)
189
def get_user_option_as_bool(self, option_name):
190
"""Get a generic option as a boolean - no special process, no default.
351
def get_user_option(self, option_name, expand=None):
352
"""Get a generic option - no special process, no default.
354
:param option_name: The queried option.
356
:param expand: Whether options references should be expanded.
358
:returns: The value of the option.
361
expand = _get_expand_default_value()
362
value = self._get_user_option(option_name)
364
if isinstance(value, list):
365
value = self._expand_options_in_list(value)
366
elif isinstance(value, dict):
367
trace.warning('Cannot expand "%s":'
368
' Dicts do not support option expansion'
371
value = self._expand_options_in_string(value)
372
for hook in OldConfigHooks['get']:
373
hook(self, option_name, value)
376
def get_user_option_as_bool(self, option_name, expand=None, default=None):
377
"""Get a generic option as a boolean.
379
:param expand: Allow expanding references to other config values.
380
:param default: Default value if nothing is configured
192
381
:return None if the option doesn't exist or its value can't be
193
382
interpreted as a boolean. Returns True or False otherwise.
195
s = self._get_user_option(option_name)
384
s = self.get_user_option(option_name, expand=expand)
197
386
# The option doesn't exist
199
388
val = ui.bool_from_string(s)
201
390
# The value can't be interpreted as a boolean
540
def get_merge_tools(self):
542
for (oname, value, section, conf_id, parser) in self._get_options():
543
if oname.startswith('bzr.mergetool.'):
544
tool_name = oname[len('bzr.mergetool.'):]
545
tools[tool_name] = value
546
trace.mutter('loaded merge tools: %r' % tools)
549
def find_merge_tool(self, name):
550
# We fake a defaults mechanism here by checking if the given name can
551
# be found in the known_merge_tools if it's not found in the config.
552
# This should be done through the proposed config defaults mechanism
553
# when it becomes available in the future.
554
command_line = (self.get_user_option('bzr.mergetool.%s' % name,
556
or mergetools.known_merge_tools.get(name, None))
560
class _ConfigHooks(hooks.Hooks):
561
"""A dict mapping hook names and a list of callables for configs.
565
"""Create the default hooks.
567
These are all empty initially, because by default nothing should get
570
super(_ConfigHooks, self).__init__('bzrlib.config', 'ConfigHooks')
571
self.add_hook('load',
572
'Invoked when a config store is loaded.'
573
' The signature is (store).',
575
self.add_hook('save',
576
'Invoked when a config store is saved.'
577
' The signature is (store).',
579
# The hooks for config options
581
'Invoked when a config option is read.'
582
' The signature is (stack, name, value).',
585
'Invoked when a config option is set.'
586
' The signature is (stack, name, value).',
588
self.add_hook('remove',
589
'Invoked when a config option is removed.'
590
' The signature is (stack, name).',
592
ConfigHooks = _ConfigHooks()
595
class _OldConfigHooks(hooks.Hooks):
596
"""A dict mapping hook names and a list of callables for configs.
600
"""Create the default hooks.
602
These are all empty initially, because by default nothing should get
605
super(_OldConfigHooks, self).__init__('bzrlib.config', 'OldConfigHooks')
606
self.add_hook('load',
607
'Invoked when a config store is loaded.'
608
' The signature is (config).',
610
self.add_hook('save',
611
'Invoked when a config store is saved.'
612
' The signature is (config).',
614
# The hooks for config options
616
'Invoked when a config option is read.'
617
' The signature is (config, name, value).',
620
'Invoked when a config option is set.'
621
' The signature is (config, name, value).',
623
self.add_hook('remove',
624
'Invoked when a config option is removed.'
625
' The signature is (config, name).',
627
OldConfigHooks = _OldConfigHooks()
350
630
class IniBasedConfig(Config):
351
631
"""A configuration policy that draws from ini files."""
353
def __init__(self, get_filename):
633
def __init__(self, get_filename=symbol_versioning.DEPRECATED_PARAMETER,
635
"""Base class for configuration files using an ini-like syntax.
637
:param file_name: The configuration file path.
354
639
super(IniBasedConfig, self).__init__()
355
self._get_filename = get_filename
640
self.file_name = file_name
641
if symbol_versioning.deprecated_passed(get_filename):
642
symbol_versioning.warn(
643
'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
644
' Use file_name instead.',
647
if get_filename is not None:
648
self.file_name = get_filename()
650
self.file_name = file_name
356
652
self._parser = None
358
def _get_parser(self, file=None):
655
def from_string(cls, str_or_unicode, file_name=None, save=False):
656
"""Create a config object from a string.
658
:param str_or_unicode: A string representing the file content. This will
661
:param file_name: The configuration file path.
663
:param _save: Whether the file should be saved upon creation.
665
conf = cls(file_name=file_name)
666
conf._create_from_string(str_or_unicode, save)
669
def _create_from_string(self, str_or_unicode, save):
670
self._content = StringIO(str_or_unicode.encode('utf-8'))
671
# Some tests use in-memory configs, some other always need the config
672
# file to exist on disk.
674
self._write_config_file()
676
def _get_parser(self, file=symbol_versioning.DEPRECATED_PARAMETER):
359
677
if self._parser is not None:
360
678
return self._parser
362
input = self._get_filename()
679
if symbol_versioning.deprecated_passed(file):
680
symbol_versioning.warn(
681
'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
682
' Use IniBasedConfig(_content=xxx) instead.',
685
if self._content is not None:
686
co_input = self._content
687
elif self.file_name is None:
688
raise AssertionError('We have no content to create the config')
690
co_input = self.file_name
366
self._parser = ConfigObj(input, encoding='utf-8')
692
self._parser = ConfigObj(co_input, encoding='utf-8')
367
693
except configobj.ConfigObjError, e:
368
694
raise errors.ParseConfigError(e.errors, e.config.filename)
695
except UnicodeDecodeError:
696
raise errors.ConfigContentError(self.file_name)
697
# Make sure self.reload() will use the right file name
698
self._parser.filename = self.file_name
699
for hook in OldConfigHooks['load']:
369
701
return self._parser
704
"""Reload the config file from disk."""
705
if self.file_name is None:
706
raise AssertionError('We need a file name to reload the config')
707
if self._parser is not None:
708
self._parser.reload()
709
for hook in ConfigHooks['load']:
371
712
def _get_matching_sections(self):
372
713
"""Return an ordered list of (section_name, extra_path) pairs.
1508
2159
configobj[name] = value
1510
2161
configobj.setdefault(section, {})[name] = value
2162
for hook in OldConfigHooks['set']:
2163
hook(self, name, value)
2164
self._set_configobj(configobj)
2166
def remove_option(self, option_name, section_name=None):
2167
configobj = self._get_configobj()
2168
if section_name is None:
2169
del configobj[option_name]
2171
del configobj[section_name][option_name]
2172
for hook in OldConfigHooks['remove']:
2173
hook(self, option_name)
1511
2174
self._set_configobj(configobj)
1513
2176
def _get_config_file(self):
1515
return StringIO(self._transport.get_bytes(self._filename))
2178
f = StringIO(self._transport.get_bytes(self._filename))
2179
for hook in OldConfigHooks['load']:
1516
2182
except errors.NoSuchFile:
1517
2183
return StringIO()
2185
def _external_url(self):
2186
return urlutils.join(self._transport.external_url(), self._filename)
1519
2188
def _get_configobj(self):
1520
return ConfigObj(self._get_config_file(), encoding='utf-8')
2189
f = self._get_config_file()
2192
conf = ConfigObj(f, encoding='utf-8')
2193
except configobj.ConfigObjError, e:
2194
raise errors.ParseConfigError(e.errors, self._external_url())
2195
except UnicodeDecodeError:
2196
raise errors.ConfigContentError(self._external_url())
1522
2201
def _set_configobj(self, configobj):
1523
2202
out_file = StringIO()
1524
2203
configobj.write(out_file)
1525
2204
out_file.seek(0)
1526
2205
self._transport.put_file(self._filename, out_file)
2206
for hook in OldConfigHooks['save']:
2210
class Option(object):
2211
"""An option definition.
2213
The option *values* are stored in config files and found in sections.
2215
Here we define various properties about the option itself, its default
2216
value, in which config files it can be stored, etc (TBC).
2219
def __init__(self, name, default=None):
2221
self.default = default
2223
def get_default(self):
2229
option_registry = registry.Registry()
2232
option_registry.register(
2233
'editor', Option('editor'),
2234
help='The command called to launch an editor to enter a message.')
2237
class Section(object):
2238
"""A section defines a dict of option name => value.
2240
This is merely a read-only dict which can add some knowledge about the
2241
options. It is *not* a python dict object though and doesn't try to mimic
2245
def __init__(self, section_id, options):
2246
self.id = section_id
2247
# We re-use the dict-like object received
2248
self.options = options
2250
def get(self, name, default=None):
2251
return self.options.get(name, default)
2254
# Mostly for debugging use
2255
return "<config.%s id=%s>" % (self.__class__.__name__, self.id)
2258
_NewlyCreatedOption = object()
2259
"""Was the option created during the MutableSection lifetime"""
2262
class MutableSection(Section):
2263
"""A section allowing changes and keeping track of the original values."""
2265
def __init__(self, section_id, options):
2266
super(MutableSection, self).__init__(section_id, options)
2269
def set(self, name, value):
2270
if name not in self.options:
2271
# This is a new option
2272
self.orig[name] = _NewlyCreatedOption
2273
elif name not in self.orig:
2274
self.orig[name] = self.get(name, None)
2275
self.options[name] = value
2277
def remove(self, name):
2278
if name not in self.orig:
2279
self.orig[name] = self.get(name, None)
2280
del self.options[name]
2283
class Store(object):
2284
"""Abstract interface to persistent storage for configuration options."""
2286
readonly_section_class = Section
2287
mutable_section_class = MutableSection
2289
def is_loaded(self):
2290
"""Returns True if the Store has been loaded.
2292
This is used to implement lazy loading and ensure the persistent
2293
storage is queried only when needed.
2295
raise NotImplementedError(self.is_loaded)
2298
"""Loads the Store from persistent storage."""
2299
raise NotImplementedError(self.load)
2301
def _load_from_string(self, bytes):
2302
"""Create a store from a string in configobj syntax.
2304
:param bytes: A string representing the file content.
2306
raise NotImplementedError(self._load_from_string)
2309
"""Unloads the Store.
2311
This should make is_loaded() return False. This is used when the caller
2312
knows that the persistent storage has changed or may have change since
2315
raise NotImplementedError(self.unload)
2318
"""Saves the Store to persistent storage."""
2319
raise NotImplementedError(self.save)
2321
def external_url(self):
2322
raise NotImplementedError(self.external_url)
2324
def get_sections(self):
2325
"""Returns an ordered iterable of existing sections.
2327
:returns: An iterable of (name, dict).
2329
raise NotImplementedError(self.get_sections)
2331
def get_mutable_section(self, section_name=None):
2332
"""Returns the specified mutable section.
2334
:param section_name: The section identifier
2336
raise NotImplementedError(self.get_mutable_section)
2339
# Mostly for debugging use
2340
return "<config.%s(%s)>" % (self.__class__.__name__,
2341
self.external_url())
2344
class IniFileStore(Store):
2345
"""A config Store using ConfigObj for storage.
2347
:ivar transport: The transport object where the config file is located.
2349
:ivar file_name: The config file basename in the transport directory.
2351
:ivar _config_obj: Private member to hold the ConfigObj instance used to
2352
serialize/deserialize the config file.
2355
def __init__(self, transport, file_name):
2356
"""A config Store using ConfigObj for storage.
2358
:param transport: The transport object where the config file is located.
2360
:param file_name: The config file basename in the transport directory.
2362
super(IniFileStore, self).__init__()
2363
self.transport = transport
2364
self.file_name = file_name
2365
self._config_obj = None
2367
def is_loaded(self):
2368
return self._config_obj != None
2371
self._config_obj = None
2374
"""Load the store from the associated file."""
2375
if self.is_loaded():
2377
content = self.transport.get_bytes(self.file_name)
2378
self._load_from_string(content)
2379
for hook in ConfigHooks['load']:
2382
def _load_from_string(self, bytes):
2383
"""Create a config store from a string.
2385
:param bytes: A string representing the file content.
2387
if self.is_loaded():
2388
raise AssertionError('Already loaded: %r' % (self._config_obj,))
2389
co_input = StringIO(bytes)
2391
# The config files are always stored utf8-encoded
2392
self._config_obj = ConfigObj(co_input, encoding='utf-8')
2393
except configobj.ConfigObjError, e:
2394
self._config_obj = None
2395
raise errors.ParseConfigError(e.errors, self.external_url())
2396
except UnicodeDecodeError:
2397
raise errors.ConfigContentError(self.external_url())
2400
if not self.is_loaded():
2404
self._config_obj.write(out)
2405
self.transport.put_bytes(self.file_name, out.getvalue())
2406
for hook in ConfigHooks['save']:
2409
def external_url(self):
2410
# FIXME: external_url should really accepts an optional relpath
2411
# parameter (bug #750169) :-/ -- vila 2011-04-04
2412
# The following will do in the interim but maybe we don't want to
2413
# expose a path here but rather a config ID and its associated
2414
# object </hand wawe>.
2415
return urlutils.join(self.transport.external_url(), self.file_name)
2417
def get_sections(self):
2418
"""Get the configobj section in the file order.
2420
:returns: An iterable of (name, dict).
2422
# We need a loaded store
2425
except errors.NoSuchFile:
2426
# If the file doesn't exist, there is no sections
2428
cobj = self._config_obj
2430
yield self.readonly_section_class(None, cobj)
2431
for section_name in cobj.sections:
2432
yield self.readonly_section_class(section_name, cobj[section_name])
2434
def get_mutable_section(self, section_name=None):
2435
# We need a loaded store
2438
except errors.NoSuchFile:
2439
# The file doesn't exist, let's pretend it was empty
2440
self._load_from_string('')
2441
if section_name is None:
2442
section = self._config_obj
2444
section = self._config_obj.setdefault(section_name, {})
2445
return self.mutable_section_class(section_name, section)
2448
# Note that LockableConfigObjStore inherits from ConfigObjStore because we need
2449
# unlockable stores for use with objects that can already ensure the locking
2450
# (think branches). If different stores (not based on ConfigObj) are created,
2451
# they may face the same issue.
2454
class LockableIniFileStore(IniFileStore):
2455
"""A ConfigObjStore using locks on save to ensure store integrity."""
2457
def __init__(self, transport, file_name, lock_dir_name=None):
2458
"""A config Store using ConfigObj for storage.
2460
:param transport: The transport object where the config file is located.
2462
:param file_name: The config file basename in the transport directory.
2464
if lock_dir_name is None:
2465
lock_dir_name = 'lock'
2466
self.lock_dir_name = lock_dir_name
2467
super(LockableIniFileStore, self).__init__(transport, file_name)
2468
self._lock = lockdir.LockDir(self.transport, self.lock_dir_name)
2470
def lock_write(self, token=None):
2471
"""Takes a write lock in the directory containing the config file.
2473
If the directory doesn't exist it is created.
2475
# FIXME: This doesn't check the ownership of the created directories as
2476
# ensure_config_dir_exists does. It should if the transport is local
2477
# -- vila 2011-04-06
2478
self.transport.create_prefix()
2479
return self._lock.lock_write(token)
2484
def break_lock(self):
2485
self._lock.break_lock()
2489
# We need to be able to override the undecorated implementation
2490
self.save_without_locking()
2492
def save_without_locking(self):
2493
super(LockableIniFileStore, self).save()
2496
# FIXME: global, bazaar, shouldn't that be 'user' instead or even
2497
# 'user_defaults' as opposed to 'user_overrides', 'system_defaults'
2498
# (/etc/bzr/bazaar.conf) and 'system_overrides' ? -- vila 2011-04-05
2500
# FIXME: Moreover, we shouldn't need classes for these stores either, factory
2501
# functions or a registry will make it easier and clearer for tests, focusing
2502
# on the relevant parts of the API that needs testing -- vila 20110503 (based
2503
# on a poolie's remark)
2504
class GlobalStore(LockableIniFileStore):
2506
def __init__(self, possible_transports=None):
2507
t = transport.get_transport(config_dir(),
2508
possible_transports=possible_transports)
2509
super(GlobalStore, self).__init__(t, 'bazaar.conf')
2512
class LocationStore(LockableIniFileStore):
2514
def __init__(self, possible_transports=None):
2515
t = transport.get_transport(config_dir(),
2516
possible_transports=possible_transports)
2517
super(LocationStore, self).__init__(t, 'locations.conf')
2520
class BranchStore(IniFileStore):
2522
def __init__(self, branch):
2523
super(BranchStore, self).__init__(branch.control_transport,
2525
self.branch = branch
2527
def lock_write(self, token=None):
2528
return self.branch.lock_write(token)
2531
return self.branch.unlock()
2535
# We need to be able to override the undecorated implementation
2536
self.save_without_locking()
2538
def save_without_locking(self):
2539
super(BranchStore, self).save()
2542
class SectionMatcher(object):
2543
"""Select sections into a given Store.
2545
This intended to be used to postpone getting an iterable of sections from a
2549
def __init__(self, store):
2552
def get_sections(self):
2553
# This is where we require loading the store so we can see all defined
2555
sections = self.store.get_sections()
2556
# Walk the revisions in the order provided
2561
def match(self, secion):
2562
raise NotImplementedError(self.match)
2565
class LocationSection(Section):
2567
def __init__(self, section, length, extra_path):
2568
super(LocationSection, self).__init__(section.id, section.options)
2569
self.length = length
2570
self.extra_path = extra_path
2572
def get(self, name, default=None):
2573
value = super(LocationSection, self).get(name, default)
2574
if value is not None:
2575
policy_name = self.get(name + ':policy', None)
2576
policy = _policy_value.get(policy_name, POLICY_NONE)
2577
if policy == POLICY_APPENDPATH:
2578
value = urlutils.join(value, self.extra_path)
2582
class LocationMatcher(SectionMatcher):
2584
def __init__(self, store, location):
2585
super(LocationMatcher, self).__init__(store)
2586
if location.startswith('file://'):
2587
location = urlutils.local_path_from_url(location)
2588
self.location = location
2590
def _get_matching_sections(self):
2591
"""Get all sections matching ``location``."""
2592
# We slightly diverge from LocalConfig here by allowing the no-name
2593
# section as the most generic one and the lower priority.
2594
no_name_section = None
2596
# Filter out the no_name_section so _iter_for_location_by_parts can be
2597
# used (it assumes all sections have a name).
2598
for section in self.store.get_sections():
2599
if section.id is None:
2600
no_name_section = section
2602
sections.append(section)
2603
# Unfortunately _iter_for_location_by_parts deals with section names so
2604
# we have to resync.
2605
filtered_sections = _iter_for_location_by_parts(
2606
[s.id for s in sections], self.location)
2607
iter_sections = iter(sections)
2608
matching_sections = []
2609
if no_name_section is not None:
2610
matching_sections.append(
2611
LocationSection(no_name_section, 0, self.location))
2612
for section_id, extra_path, length in filtered_sections:
2613
# a section id is unique for a given store so it's safe to iterate
2615
section = iter_sections.next()
2616
if section_id == section.id:
2617
matching_sections.append(
2618
LocationSection(section, length, extra_path))
2619
return matching_sections
2621
def get_sections(self):
2622
# Override the default implementation as we want to change the order
2623
matching_sections = self._get_matching_sections()
2624
# We want the longest (aka more specific) locations first
2625
sections = sorted(matching_sections,
2626
key=lambda section: (section.length, section.id),
2628
# Sections mentioning 'ignore_parents' restrict the selection
2629
for section in sections:
2630
# FIXME: We really want to use as_bool below -- vila 2011-04-07
2631
ignore = section.get('ignore_parents', None)
2632
if ignore is not None:
2633
ignore = ui.bool_from_string(ignore)
2636
# Finally, we have a valid section
2640
class Stack(object):
2641
"""A stack of configurations where an option can be defined"""
2643
def __init__(self, sections_def, store=None, mutable_section_name=None):
2644
"""Creates a stack of sections with an optional store for changes.
2646
:param sections_def: A list of Section or callables that returns an
2647
iterable of Section. This defines the Sections for the Stack and
2648
can be called repeatedly if needed.
2650
:param store: The optional Store where modifications will be
2651
recorded. If none is specified, no modifications can be done.
2653
:param mutable_section_name: The name of the MutableSection where
2654
changes are recorded. This requires the ``store`` parameter to be
2657
self.sections_def = sections_def
2659
self.mutable_section_name = mutable_section_name
2661
def get(self, name):
2662
"""Return the *first* option value found in the sections.
2664
This is where we guarantee that sections coming from Store are loaded
2665
lazily: the loading is delayed until we need to either check that an
2666
option exists or get its value, which in turn may require to discover
2667
in which sections it can be defined. Both of these (section and option
2668
existence) require loading the store (even partially).
2670
# FIXME: No caching of options nor sections yet -- vila 20110503
2672
# Ensuring lazy loading is achieved by delaying section matching (which
2673
# implies querying the persistent storage) until it can't be avoided
2674
# anymore by using callables to describe (possibly empty) section
2676
for section_or_callable in self.sections_def:
2677
# Each section can expand to multiple ones when a callable is used
2678
if callable(section_or_callable):
2679
sections = section_or_callable()
2681
sections = [section_or_callable]
2682
for section in sections:
2683
value = section.get(name)
2684
if value is not None:
2686
if value is not None:
2689
# If the option is registered, it may provide a default value
2691
opt = option_registry.get(name)
2696
value = opt.get_default()
2697
for hook in ConfigHooks['get']:
2698
hook(self, name, value)
2701
def _get_mutable_section(self):
2702
"""Get the MutableSection for the Stack.
2704
This is where we guarantee that the mutable section is lazily loaded:
2705
this means we won't load the corresponding store before setting a value
2706
or deleting an option. In practice the store will often be loaded but
2707
this allows helps catching some programming errors.
2709
section = self.store.get_mutable_section(self.mutable_section_name)
2712
def set(self, name, value):
2713
"""Set a new value for the option."""
2714
section = self._get_mutable_section()
2715
section.set(name, value)
2716
for hook in ConfigHooks['set']:
2717
hook(self, name, value)
2719
def remove(self, name):
2720
"""Remove an existing option."""
2721
section = self._get_mutable_section()
2722
section.remove(name)
2723
for hook in ConfigHooks['remove']:
2727
# Mostly for debugging use
2728
return "<config.%s(%s)>" % (self.__class__.__name__, id(self))
2731
class _CompatibleStack(Stack):
2732
"""Place holder for compatibility with previous design.
2734
This is intended to ease the transition from the Config-based design to the
2735
Stack-based design and should not be used nor relied upon by plugins.
2737
One assumption made here is that the daughter classes will all use Stores
2738
derived from LockableIniFileStore).
2740
It implements set() by re-loading the store before applying the
2741
modification and saving it.
2743
The long term plan being to implement a single write by store to save
2744
all modifications, this class should not be used in the interim.
2747
def set(self, name, value):
2750
super(_CompatibleStack, self).set(name, value)
2751
# Force a write to persistent storage
2755
class GlobalStack(_CompatibleStack):
2759
gstore = GlobalStore()
2760
super(GlobalStack, self).__init__([gstore.get_sections], gstore)
2763
class LocationStack(_CompatibleStack):
2765
def __init__(self, location):
2766
lstore = LocationStore()
2767
matcher = LocationMatcher(lstore, location)
2768
gstore = GlobalStore()
2769
super(LocationStack, self).__init__(
2770
[matcher.get_sections, gstore.get_sections], lstore)
2772
class BranchStack(_CompatibleStack):
2774
def __init__(self, branch):
2775
bstore = BranchStore(branch)
2776
lstore = LocationStore()
2777
matcher = LocationMatcher(lstore, branch.base)
2778
gstore = GlobalStore()
2779
super(BranchStack, self).__init__(
2780
[matcher.get_sections, bstore.get_sections, gstore.get_sections],
2782
self.branch = branch
2785
class cmd_config(commands.Command):
2786
__doc__ = """Display, set or remove a configuration option.
2788
Display the active value for a given option.
2790
If --all is specified, NAME is interpreted as a regular expression and all
2791
matching options are displayed mentioning their scope. The active value
2792
that bzr will take into account is the first one displayed for each option.
2794
If no NAME is given, --all .* is implied.
2796
Setting a value is achieved by using name=value without spaces. The value
2797
is set in the most relevant scope and can be checked by displaying the
2801
takes_args = ['name?']
2805
# FIXME: This should be a registry option so that plugins can register
2806
# their own config files (or not) -- vila 20101002
2807
commands.Option('scope', help='Reduce the scope to the specified'
2808
' configuration file',
2810
commands.Option('all',
2811
help='Display all the defined values for the matching options.',
2813
commands.Option('remove', help='Remove the option from'
2814
' the configuration file'),
2817
_see_also = ['configuration']
2819
@commands.display_command
2820
def run(self, name=None, all=False, directory=None, scope=None,
2822
if directory is None:
2824
directory = urlutils.normalize_url(directory)
2826
raise errors.BzrError(
2827
'--all and --remove are mutually exclusive.')
2829
# Delete the option in the given scope
2830
self._remove_config_option(name, directory, scope)
2832
# Defaults to all options
2833
self._show_matching_options('.*', directory, scope)
2836
name, value = name.split('=', 1)
2838
# Display the option(s) value(s)
2840
self._show_matching_options(name, directory, scope)
2842
self._show_value(name, directory, scope)
2845
raise errors.BzrError(
2846
'Only one option can be set.')
2847
# Set the option value
2848
self._set_config_option(name, value, directory, scope)
2850
def _get_configs(self, directory, scope=None):
2851
"""Iterate the configurations specified by ``directory`` and ``scope``.
2853
:param directory: Where the configurations are derived from.
2855
:param scope: A specific config to start from.
2857
if scope is not None:
2858
if scope == 'bazaar':
2859
yield GlobalConfig()
2860
elif scope == 'locations':
2861
yield LocationConfig(directory)
2862
elif scope == 'branch':
2863
(_, br, _) = bzrdir.BzrDir.open_containing_tree_or_branch(
2865
yield br.get_config()
2868
(_, br, _) = bzrdir.BzrDir.open_containing_tree_or_branch(
2870
yield br.get_config()
2871
except errors.NotBranchError:
2872
yield LocationConfig(directory)
2873
yield GlobalConfig()
2875
def _show_value(self, name, directory, scope):
2877
for c in self._get_configs(directory, scope):
2880
for (oname, value, section, conf_id, parser) in c._get_options():
2882
# Display only the first value and exit
2884
# FIXME: We need to use get_user_option to take policies
2885
# into account and we need to make sure the option exists
2886
# too (hence the two for loops), this needs a better API
2888
value = c.get_user_option(name)
2889
# Quote the value appropriately
2890
value = parser._quote(value)
2891
self.outf.write('%s\n' % (value,))
2895
raise errors.NoSuchConfigOption(name)
2897
def _show_matching_options(self, name, directory, scope):
2898
name = re.compile(name)
2899
# We want any error in the regexp to be raised *now* so we need to
2900
# avoid the delay introduced by the lazy regexp.
2901
name._compile_and_collapse()
2904
for c in self._get_configs(directory, scope):
2905
for (oname, value, section, conf_id, parser) in c._get_options():
2906
if name.search(oname):
2907
if cur_conf_id != conf_id:
2908
# Explain where the options are defined
2909
self.outf.write('%s:\n' % (conf_id,))
2910
cur_conf_id = conf_id
2912
if (section not in (None, 'DEFAULT')
2913
and cur_section != section):
2914
# Display the section if it's not the default (or only)
2916
self.outf.write(' [%s]\n' % (section,))
2917
cur_section = section
2918
self.outf.write(' %s = %s\n' % (oname, value))
2920
def _set_config_option(self, name, value, directory, scope):
2921
for conf in self._get_configs(directory, scope):
2922
conf.set_user_option(name, value)
2925
raise errors.NoSuchConfig(scope)
2927
def _remove_config_option(self, name, directory, scope):
2929
raise errors.BzrCommandError(
2930
'--remove expects an option to remove.')
2932
for conf in self._get_configs(directory, scope):
2933
for (section_name, section, conf_id) in conf._get_sections():
2934
if scope is not None and conf_id != scope:
2935
# Not the right configuration file
2938
if conf_id != conf.config_id():
2939
conf = self._get_configs(directory, conf_id).next()
2940
# We use the first section in the first config where the
2941
# option is defined to remove it
2942
conf.remove_user_option(name, section_name)
2947
raise errors.NoSuchConfig(scope)
2949
raise errors.NoSuchConfigOption(name)
2953
# We need adapters that can build a Store or a Stack in a test context. Test
2954
# classes, based on TestCaseWithTransport, can use the registry to parametrize
2955
# themselves. The builder will receive a test instance and should return a
2956
# ready-to-use store or stack. Plugins that define new store/stacks can also
2957
# register themselves here to be tested against the tests defined in
2958
# bzrlib.tests.test_config. Note that the builder can be called multiple times
2959
# for the same tests.
2961
# The registered object should be a callable receiving a test instance
2962
# parameter (inheriting from tests.TestCaseWithTransport) and returning a Store
2964
test_store_builder_registry = registry.Registry()
2966
# The registered object should be a callable receiving a test instance
2967
# parameter (inheriting from tests.TestCaseWithTransport) and returning a Stack
2969
test_stack_builder_registry = registry.Registry()