2346
2346
def __init__(self, name, default=None, default_from_env=None,
2347
help=None, from_unicode=None, invalid=None):
2347
help=None, from_unicode=None, invalid=None,
2348
2349
"""Build an option definition.
2350
2351
:param name: the name used to refer to the option.
2372
2373
TypeError. Accepted values are: None (ignore invalid values),
2373
2374
'warning' (emit a warning), 'error' (emit an error message and
2377
:param unquote: should the unicode value be unquoted before conversion.
2378
This should be used only when the store providing the values cannot
2379
safely unquote them (see http://pad.lv/906897). It is provided so
2380
daughter classes can handle the quoting themselves.
2376
2382
if default_from_env is None:
2377
2383
default_from_env = []
2398
2404
self.default_from_env = default_from_env
2399
2405
self.help = help
2400
2406
self.from_unicode = from_unicode
2407
self.unquote = unquote
2401
2408
if invalid and invalid not in ('warning', 'error'):
2402
2409
raise AssertionError("%s not supported for 'invalid'" % (invalid,))
2403
2410
self.invalid = invalid
2405
def convert_from_unicode(self, unicode_value):
2412
def convert_from_unicode(self, store, unicode_value):
2413
if self.unquote and store is not None and unicode_value is not None:
2414
unicode_value = store.unquote(unicode_value)
2406
2415
if self.from_unicode is None or unicode_value is None:
2407
2416
# Don't convert or nothing to convert
2408
2417
return unicode_value
2459
2468
return int(unicode_str)
2462
_unit_sfxs = dict(K=10**3, M=10**6, G=10**9)
2471
_unit_suffixes = dict(K=10**3, M=10**6, G=10**9)
2464
2473
def int_SI_from_store(unicode_str):
2465
2474
"""Convert a human readable size in SI units, e.g 10MB into an integer.
2497
2506
{}, encoding='utf-8', list_values=True, interpolation=False)
2500
def list_from_store(unicode_str):
2501
if not isinstance(unicode_str, basestring):
2503
# Now inject our string directly as unicode. All callers got their value
2504
# from configobj, so values that need to be quoted are already properly
2506
_list_converter_config.reset()
2507
_list_converter_config._parse([u"list=%s" % (unicode_str,)])
2508
maybe_list = _list_converter_config['list']
2509
if isinstance(maybe_list, basestring):
2511
# A single value, most probably the user forgot (or didn't care to
2512
# add) the final ','
2509
class ListOption(Option):
2511
def __init__(self, name, default=None, default_from_env=None,
2512
help=None, invalid=None):
2513
"""A list Option definition.
2515
This overrides the base class so the conversion from a unicode string
2516
can take quoting into account.
2518
super(ListOption, self).__init__(
2519
name, default=default, default_from_env=default_from_env,
2520
from_unicode=self.from_unicode, help=help,
2521
invalid=invalid, unquote=False)
2523
def from_unicode(self, unicode_str):
2524
if not isinstance(unicode_str, basestring):
2526
# Now inject our string directly as unicode. All callers got their
2527
# value from configobj, so values that need to be quoted are already
2529
_list_converter_config.reset()
2530
_list_converter_config._parse([u"list=%s" % (unicode_str,)])
2531
maybe_list = _list_converter_config['list']
2532
if isinstance(maybe_list, basestring):
2534
# A single value, most probably the user forgot (or didn't care
2535
# to add) the final ','
2538
# The empty string, convert to empty list
2515
# The empty string, convert to empty list
2518
# We rely on ConfigObj providing us with a list already
2541
# We rely on ConfigObj providing us with a list already
2523
2546
class OptionRegistry(registry.Registry):
2573
2596
existing mainline of the branch.
2575
2598
option_registry.register(
2576
Option('acceptable_keys',
2577
default=None, from_unicode=list_from_store,
2599
ListOption('acceptable_keys',
2579
2602
List of GPG key patterns which are acceptable for verification.
2656
2679
should not be lost if the machine crashes. See also repository.fdatasync.
2658
2681
option_registry.register(
2659
Option('debug_flags', default=[], from_unicode=list_from_store,
2682
ListOption('debug_flags', default=[],
2660
2683
help='Debug flags to activate.'))
2661
2684
option_registry.register(
2662
2685
Option('default_format', default='2a',
2911
2934
raise NotImplementedError(self.unload)
2936
def quote(self, value):
2937
"""Quote a configuration option value for storing purposes.
2939
This allows Stacks to present values as they will be stored.
2943
def unquote(self, value):
2944
"""Unquote a configuration option value into unicode.
2946
The received value is quoted as stored.
2913
2950
def save(self):
2914
2951
"""Saves the Store to persistent storage."""
2915
2952
raise NotImplementedError(self.save)
3082
3119
section = self._config_obj.setdefault(section_id, {})
3083
3120
return self.mutable_section_class(section_id, section)
3122
def quote(self, value):
3124
# configobj conflates automagical list values and quoting
3125
self._config_obj.list_values = True
3126
return self._config_obj._quote(value)
3128
self._config_obj.list_values = False
3130
def unquote(self, value):
3132
# _unquote doesn't handle None nor empty strings
3133
value = self._config_obj._unquote(value)
3086
3137
class TransportIniFileStore(IniFileStore):
3087
3138
"""IniFileStore that loads files from a transport.
3416
3467
# implies querying the persistent storage) until it can't be avoided
3417
3468
# anymore by using callables to describe (possibly empty) section
3470
found_store = None # Where the option value has been found
3419
3471
for sections in self.sections_def:
3420
3472
for store, section in sections():
3421
3473
value = section.get(name)
3422
3474
if value is not None:
3424
3477
if value is not None:
3441
3494
trace.warning('Cannot expand "%s":'
3442
3495
' %s does not support option expansion'
3443
3496
% (name, type(val)))
3445
val = opt.convert_from_unicode(val)
3498
val = found_store.unquote(val)
3500
val = opt.convert_from_unicode(found_store, val)
3447
3502
value = expand_and_convert(value)
3448
3503
if opt is not None and value is None:
3526
3581
or deleting an option. In practice the store will often be loaded but
3527
3582
this helps catching some programming errors.
3529
section = self.store.get_mutable_section(self.mutable_section_id)
3585
section = store.get_mutable_section(self.mutable_section_id)
3586
return store, section
3532
3588
def set(self, name, value):
3533
3589
"""Set a new value for the option."""
3534
section = self._get_mutable_section()
3535
section.set(name, value)
3590
store, section = self._get_mutable_section()
3591
section.set(name, store.quote(value))
3536
3592
for hook in ConfigHooks['set']:
3537
3593
hook(self, name, value)
3539
3595
def remove(self, name):
3540
3596
"""Remove an existing option."""
3541
section = self._get_mutable_section()
3597
_, section = self._get_mutable_section()
3542
3598
section.remove(name)
3543
3599
for hook in ConfigHooks['remove']:
3544
3600
hook(self, name)
3727
3783
# Use a an empty dict to initialize an empty configobj avoiding all
3728
3784
# parsing and encoding checks
3729
3785
_quoting_config = configobj.ConfigObj(
3730
{}, encoding='utf-8', interpolation=False)
3786
{}, encoding='utf-8', interpolation=False, list_values=True)
3732
3788
class cmd_config(commands.Command):
3733
3789
__doc__ = """Display, set or remove a configuration option.
3860
3916
self.outf.write(' [%s]\n' % (section.id,))
3861
3917
cur_section = section.id
3862
3918
value = section.get(oname, expand=False)
3919
# Since we don't use the stack, we need to restore a
3922
opt = option_registry.get(oname)
3923
value = opt.convert_from_unicode(store, value)
3925
value = store.unquote(value)
3863
3926
value = _quoting_config._quote(value)
3864
3927
self.outf.write(' %s = %s\n' % (oname, value))