154
158
return self[section][name]
157
# FIXME: Until we can guarantee that each config file is loaded once and and
161
# FIXME: Until we can guarantee that each config file is loaded once and
158
162
# only once for a given bzrlib session, we don't want to re-read the file every
159
163
# time we query for an option so we cache the value (bad ! watch out for tests
160
164
# needing to restore the proper value).This shouldn't be part of 2.4.0 final,
365
369
% (option_name,))
367
371
value = self._expand_options_in_string(value)
372
for hook in OldConfigHooks['get']:
373
hook(self, option_name, value)
370
def get_user_option_as_bool(self, option_name, expand=None):
371
"""Get a generic option as a boolean - no special process, no default.
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
373
381
:return None if the option doesn't exist or its value can't be
374
382
interpreted as a boolean. Returns True or False otherwise.
376
384
s = self.get_user_option(option_name, expand=expand)
378
386
# The option doesn't exist
380
388
val = ui.bool_from_string(s)
382
390
# The value can't be interpreted as a boolean
487
495
if policy is None:
488
496
policy = self._get_signature_checking()
489
497
if policy is not None:
498
#this warning should go away once check_signatures is
499
#implemented (if not before)
490
500
trace.warning("Please use create_signatures,"
491
501
" not check_signatures to set signing policy.")
492
if policy == CHECK_ALWAYS:
494
502
elif policy == SIGN_ALWAYS:
541
549
def find_merge_tool(self, name):
542
# We fake a defaults mechanism here by checking if the given name can
550
# We fake a defaults mechanism here by checking if the given name can
543
551
# be found in the known_merge_tools if it's not found in the config.
544
552
# This should be done through the proposed config defaults mechanism
545
553
# when it becomes available in the future.
549
557
return command_line
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()
552
630
class IniBasedConfig(Config):
553
631
"""A configuration policy that draws from ini files."""
614
692
self._parser = ConfigObj(co_input, encoding='utf-8')
615
693
except configobj.ConfigObjError, e:
616
694
raise errors.ParseConfigError(e.errors, e.config.filename)
695
except UnicodeDecodeError:
696
raise errors.ConfigContentError(self.file_name)
617
697
# Make sure self.reload() will use the right file name
618
698
self._parser.filename = self.file_name
699
for hook in OldConfigHooks['load']:
619
701
return self._parser
621
703
def reload(self):
945
1034
self._get_parser().setdefault(section, {})[option] = value
946
1035
self._write_config_file()
1036
for hook in OldConfigHooks['set']:
1037
hook(self, option, value)
949
1039
def _get_sections(self, name=None):
950
1040
"""See IniBasedConfig._get_sections()."""
1146
1236
# the allowed values of store match the config policies
1147
1237
self._set_option_policy(location, option, store)
1148
1238
self._write_config_file()
1239
for hook in OldConfigHooks['set']:
1240
hook(self, option, value)
1151
1243
class BranchConfig(Config):
1629
1723
section[option_name] = value
1632
def get_credentials(self, scheme, host, port=None, user=None, path=None,
1726
def get_credentials(self, scheme, host, port=None, user=None, path=None,
1634
1728
"""Returns the matching credentials from authentication.conf file.
2048
2142
section_obj = configobj[section]
2049
2143
except KeyError:
2051
return section_obj.get(name, default)
2145
value = section_obj.get(name, default)
2146
for hook in OldConfigHooks['get']:
2147
hook(self, name, value)
2053
2150
def set_option(self, value, name, section=None):
2054
2151
"""Set the value associated with a named option.
2070
2169
del configobj[option_name]
2072
2171
del configobj[section_name][option_name]
2172
for hook in OldConfigHooks['remove']:
2173
hook(self, option_name)
2073
2174
self._set_configobj(configobj)
2075
2176
def _get_config_file(self):
2077
return StringIO(self._transport.get_bytes(self._filename))
2178
f = StringIO(self._transport.get_bytes(self._filename))
2179
for hook in OldConfigHooks['load']:
2078
2182
except errors.NoSuchFile:
2079
2183
return StringIO()
2185
def _external_url(self):
2186
return urlutils.join(self._transport.external_url(), self._filename)
2081
2188
def _get_configobj(self):
2082
2189
f = self._get_config_file()
2084
return ConfigObj(f, encoding='utf-8')
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())
2088
2201
def _set_configobj(self, configobj):
2089
2202
out_file = StringIO()
2090
2203
configobj.write(out_file)
2091
2204
out_file.seek(0)
2092
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.')
2095
2237
class Section(object):
2096
"""A section defines a dict of options.
2238
"""A section defines a dict of option name => value.
2098
2240
This is merely a read-only dict which can add some knowledge about the
2099
2241
options. It is *not* a python dict object though and doesn't try to mimic
2156
2298
"""Loads the Store from persistent storage."""
2157
2299
raise NotImplementedError(self.load)
2159
def _load_from_string(self, str_or_unicode):
2301
def _load_from_string(self, bytes):
2160
2302
"""Create a store from a string in configobj syntax.
2162
:param str_or_unicode: A string representing the file content. This will
2163
be encoded to suit store needs internally.
2165
This is for tests and should not be used in production unless a
2166
convincing use case can be demonstrated :)
2304
:param bytes: A string representing the file content.
2168
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)
2170
2317
def save(self):
2171
2318
"""Saves the Store to persistent storage."""
2172
2319
raise NotImplementedError(self.save)
2220
2367
def is_loaded(self):
2221
2368
return self._config_obj != None
2371
self._config_obj = None
2223
2373
def load(self):
2224
2374
"""Load the store from the associated file."""
2225
2375
if self.is_loaded():
2227
2377
content = self.transport.get_bytes(self.file_name)
2228
2378
self._load_from_string(content)
2379
for hook in ConfigHooks['load']:
2230
def _load_from_string(self, str_or_unicode):
2382
def _load_from_string(self, bytes):
2231
2383
"""Create a config store from a string.
2233
:param str_or_unicode: A string representing the file content. This will
2234
be utf-8 encoded internally.
2236
This is for tests and should not be used in production unless a
2237
convincing use case can be demonstrated :)
2385
:param bytes: A string representing the file content.
2239
2387
if self.is_loaded():
2240
2388
raise AssertionError('Already loaded: %r' % (self._config_obj,))
2241
co_input = StringIO(str_or_unicode.encode('utf-8'))
2389
co_input = StringIO(bytes)
2243
2391
# The config files are always stored utf8-encoded
2244
2392
self._config_obj = ConfigObj(co_input, encoding='utf-8')
2245
2393
except configobj.ConfigObjError, e:
2246
2394
self._config_obj = None
2247
2395
raise errors.ParseConfigError(e.errors, self.external_url())
2396
except UnicodeDecodeError:
2397
raise errors.ConfigContentError(self.external_url())
2249
2399
def save(self):
2250
2400
if not self.is_loaded():
2366
2522
def __init__(self, branch):
2367
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()
2370
2542
class SectionMatcher(object):
2371
2543
"""Select sections into a given Store.
2510
2682
for section in sections:
2511
2683
value = section.get(name)
2512
2684
if value is not None:
2514
# No definition was found
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)
2517
2701
def _get_mutable_section(self):
2518
2702
"""Get the MutableSection for the Stack.
2529
2713
"""Set a new value for the option."""
2530
2714
section = self._get_mutable_section()
2531
2715
section.set(name, value)
2716
for hook in ConfigHooks['set']:
2717
hook(self, name, value)
2533
2719
def remove(self, name):
2534
2720
"""Remove an existing option."""
2535
2721
section = self._get_mutable_section()
2536
2722
section.remove(name)
2723
for hook in ConfigHooks['remove']:
2538
2726
def __repr__(self):
2539
2727
# Mostly for debugging use
2540
2728
return "<config.%s(%s)>" % (self.__class__.__name__, id(self))
2543
class GlobalStack(Stack):
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):
2545
2757
def __init__(self):
2546
2758
# Get a GlobalStore
2557
2769
super(LocationStack, self).__init__(
2558
2770
[matcher.get_sections, gstore.get_sections], lstore)
2561
class BranchStack(Stack):
2772
class BranchStack(_CompatibleStack):
2563
2774
def __init__(self, branch):
2564
2775
bstore = BranchStore(branch)
2602
2814
' the configuration file'),
2817
_see_also = ['configuration']
2605
2819
@commands.display_command
2606
2820
def run(self, name=None, all=False, directory=None, scope=None,
2733
2947
raise errors.NoSuchConfig(scope)
2734
2948
if not removed:
2735
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()