diff --git a/ChangeLog b/ChangeLog index e3c85ad..4f15433 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +Thu Sep 22 08:25:33 2016 +0200 Emmanuel Garette + * force_store_value is rebuild if needed + Mon Mar 7 16:10:30 2016 +0200 Emmanuel Garette * force_store_value is now used directly when configuration is loaded * add force_permissive to Values.is_default_owner diff --git a/test/test_config.py b/test/test_config.py index 8c7e332..9dfb809 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -376,3 +376,15 @@ def test_config_od_function(): except AttributeError as err: assert str(err) == _('unknown Option {0} in OptionDescription {1}' '').format('impl_get_opt_by_path', descr.impl_getname()) + + +def test_config_subconfig(): + i1 = IntOption('i1', '') + i2 = IntOption('i2', '', default=1) + i3 = IntOption('i3', '') + i4 = IntOption('i4', '', default=2) + od1 = OptionDescription('od1', '', [i1, i2, i3, i4]) + od2 = OptionDescription('od2', '', [od1]) + conf1 = Config(od2, name='conf1') + conf1 + raises(ConfigError, "conf2 = Config(od1, name='conf2')") diff --git a/test/test_duplicate_config.py b/test/test_duplicate_config.py index c6e9a6d..ce3dd3a 100644 --- a/test/test_duplicate_config.py +++ b/test/test_duplicate_config.py @@ -25,6 +25,7 @@ def make_description(): adresse_serveur_ntp = StrOption('serveur_ntp', "adresse serveur ntp", multi=True) time_zone = ChoiceOption('time_zone', 'fuseau horaire du serveur', ('Paris', 'Londres'), 'Paris') + wantref_option = BoolOption('wantref', 'Test requires', default=False, properties=('force_store_value',)) ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé") netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau") @@ -36,7 +37,7 @@ def make_description(): general = OptionDescription('general', '', [numero_etab, nom_machine, nombre_interfaces, activer_proxy_client, mode_conteneur_actif, mode_conteneur_actif2, - adresse_serveur_ntp, time_zone]) + adresse_serveur_ntp, time_zone, wantref_option]) general.impl_set_group_type(groups.family) new = OptionDescription('new', '', [], properties=('hidden',)) new.impl_set_group_type(groups.family) @@ -54,3 +55,14 @@ def test_duplicate(): raises(AssertionError, "_diff_conf(cfg, ncfg)") ncfg.creole.general.numero_etab = 'oui' _diff_conf(cfg, ncfg) + + +def test_duplicate_force_store_value(): + descr = make_description() + conf = Config(descr) + conf2 = Config(descr) + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'creole.general.wantref': ('forced', False)} + assert conf2.cfgimpl_get_values()._p_.get_modified_values() == {'creole.general.wantref': ('forced', False)} + conf.creole.general.wantref = True + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'creole.general.wantref': ('user', True)} + assert conf2.cfgimpl_get_values()._p_.get_modified_values() == {'creole.general.wantref': ('forced', False)} diff --git a/test/test_metaconfig.py b/test/test_metaconfig.py index e53b4dc..f14e4d1 100644 --- a/test/test_metaconfig.py +++ b/test/test_metaconfig.py @@ -231,10 +231,11 @@ def test_meta_unconsistent(): i4 = IntOption('i4', '', default=2) od1 = OptionDescription('od1', '', [i1, i2, i3, i4]) od2 = OptionDescription('od2', '', [od1]) + od3 = OptionDescription('od3', '', [od1]) conf1 = Config(od2, name='conf1') conf2 = Config(od2, name='conf2') conf3 = Config(od2, name='conf3') - conf4 = Config(od1, name='conf4') + conf4 = Config(od3, name='conf4') conf3, conf4 meta = MetaConfig([conf1, conf2]) meta.cfgimpl_get_settings().setowner(owners.meta) diff --git a/tiramisu/config.py b/tiramisu/config.py index 6cc8e4d..8cf061d 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -548,6 +548,7 @@ class _CommonConfig(SubConfig): if not descr.impl_already_build_caches(): descr.impl_build_cache_option() descr.impl_build_cache(self) + descr.impl_build_force_store_values(self) def read_only(self): "read only is a global config's setting, see `settings.py`" @@ -697,7 +698,8 @@ class Config(_CommonConfig): self._impl_meta = None #undocumented option used only in test script self._impl_test = False - self._impl_build_all_caches() + if force_settings is None or force_values is None: + self._impl_build_all_caches() self._impl_name = name def cfgimpl_reset_cache(self, diff --git a/tiramisu/option/optiondescription.py b/tiramisu/option/optiondescription.py index 1dda5b5..6edc458 100644 --- a/tiramisu/option/optiondescription.py +++ b/tiramisu/option/optiondescription.py @@ -102,6 +102,9 @@ class OptionDescription(BaseOption, StorageOptionDescription): """validate duplicate option and set option has readonly option """ if cache_option is None: + if self.impl_is_readonly(): + raise ConfigError(_('option description seems to be part of an other ' + 'config')) init = True _consistencies = {} cache_option = [] @@ -189,24 +192,29 @@ class OptionDescription(BaseOption, StorageOptionDescription): 'which is not in Config').format( opt.impl_getname())) self._cache_consistencies[opt] = tuple(cons) + self._cache_force_store_values = force_store_values self._set_readonly(False) - for subpath, option in force_store_values: - value = config.cfgimpl_get_values()._get_cached_value(option, - path=subpath, - validate=False, - trusted_cached_properties=False, - validate_properties=True) - if option.impl_is_master_slaves('slave'): - # problem with index - raise ConfigError(_('a slave ({0}) cannot have ' - 'force_store_value property').format(subpath)) - if option._is_subdyn(): - raise ConfigError(_('a dynoption ({0}) cannot have ' - 'force_store_value property').format(subpath)) - config._impl_values._p_.setvalue(subpath, value, - owners.forced, None, session) del(session) + + def impl_build_force_store_values(self, config): + session = config._impl_values._p_.getsession() + for subpath, option in self._cache_force_store_values: + value = config.cfgimpl_get_values()._get_cached_value(option, + path=subpath, + validate=False, + trusted_cached_properties=False, + validate_properties=True) + if option.impl_is_master_slaves('slave'): + # problem with index + raise ConfigError(_('a slave ({0}) cannot have ' + 'force_store_value property').format(subpath)) + if option._is_subdyn(): + raise ConfigError(_('a dynoption ({0}) cannot have ' + 'force_store_value property').format(subpath)) + config._impl_values._p_.setvalue(subpath, value, + owners.forced, None, session) + # ____________________________________________________________ def impl_set_group_type(self, group_type): """sets a given group object to an OptionDescription diff --git a/tiramisu/storage/dictionary/option.py b/tiramisu/storage/dictionary/option.py index 57c713c..481a1f4 100644 --- a/tiramisu/storage/dictionary/option.py +++ b/tiramisu/storage/dictionary/option.py @@ -363,7 +363,7 @@ class StorageBase(object): class StorageOptionDescription(StorageBase): __slots__ = ('_children', '_cache_paths', '_cache_consistencies', - '_group_type', '_state_group_type') + '_group_type', '_state_group_type', '_cache_force_store_values') def __init__(self, name, multi, warnings_only, doc, extra): super(StorageOptionDescription, self).__init__(name, multi,