tiramisu/tiramisu/option/masterslaves.py

236 lines
9.9 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
"master slaves support"
2018-01-26 07:33:47 +01:00
# Copyright (C) 2014-2018 Team tiramisu (see AUTHORS for all contributors)
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# The original `Config` design model is unproudly borrowed from
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
import weakref
from itertools import chain
from ..i18n import _
2018-08-02 22:35:40 +02:00
from ..setting import groups, undefined, OptionBag
from .optiondescription import OptionDescription
from .syndynoptiondescription import SynDynMasterSlaves
from .option import Option
from ..error import SlaveError, PropertiesOptionError, RequirementError
from ..function import ParamOption
class MasterSlaves(OptionDescription):
__slots__ = ('master', 'slaves')
def __init__(self,
name,
doc,
children,
requires=None,
properties=None):
super(MasterSlaves, self).__init__(name,
doc,
children,
requires=requires,
properties=properties)
self._group_type = groups.master
slaves = []
2018-04-09 21:37:49 +02:00
if len(children) < 2:
2018-04-11 18:32:13 +02:00
raise ValueError(_('a master and a slave are mandatories in masterslaves "{}"').format(name))
master = children[0]
for idx, child in enumerate(children):
2018-09-29 21:58:41 +02:00
if child.impl_is_symlinkoption():
2018-04-11 18:32:13 +02:00
raise ValueError(_('masterslaves "{0}" shall not have '
2017-12-02 22:53:57 +01:00
"a symlinkoption").format(self.impl_get_display_name()))
2018-09-29 21:58:41 +02:00
if not isinstance(child, Option):
2018-04-11 18:32:13 +02:00
raise ValueError(_('masterslaves "{0}" shall not have '
2017-12-02 22:53:57 +01:00
'a subgroup').format(self.impl_get_display_name()))
2018-09-29 21:58:41 +02:00
if not child.impl_is_multi():
2018-04-11 18:32:13 +02:00
raise ValueError(_('only multi option allowed in masterslaves "{0}" but option '
2018-04-09 21:37:49 +02:00
'"{1}" is not a multi').format(self.impl_get_display_name(),
child.impl_get_display_name()))
if idx != 0 and child.impl_getdefault() != []:
raise ValueError(_('not allowed default value for option "{0}" '
2018-04-11 18:32:13 +02:00
'in masterslaves "{1}"'
2017-12-02 22:53:57 +01:00
'').format(child.impl_get_display_name(),
self.impl_get_display_name()))
# no empty property for save
if idx != 0:
child_properties = list(child._properties)
child_properties.remove('empty')
child._properties = frozenset(child_properties)
2017-12-02 22:53:57 +01:00
slaves.append(child)
child._add_dependency(self)
child._master_slaves = weakref.ref(self)
callback, callback_params = master.impl_get_callback()
if callback is not None and callback_params != None:
for callbk in chain(callback_params.args, callback_params.kwargs.values()):
if isinstance(callbk, ParamOption):
if callbk.option in slaves:
raise ValueError(_("callback of master's option shall "
"not refered a slave's ones"))
# master should not have requires, only MasterSlaves should have
# so move requires to MasterSlaves
# if MasterSlaves has requires to, cannot manage the move so raises
master_requires = getattr(master, '_requires', None)
if master_requires:
if self.impl_getrequires():
raise RequirementError(_('master {} have requirement, but MasterSlaves {} too'
'').format(master.impl_getname(),
self.impl_getname()))
master_calproperties = getattr(master, '_calc_properties', None)
if master_calproperties:
if properties is not None:
self.validate_properties(name, master_calproperties, frozenset(properties))
setattr(self, '_calc_properties', master_calproperties)
setattr(self, '_requires', master_requires)
delattr(master, '_requires')
all_requires = getattr(self, '_requires', None)
if all_requires:
for requires_ in all_requires:
for require in requires_:
for require_opt, values in require[0]:
if require_opt.impl_is_multi():
if require_opt.impl_is_master_slaves():
raise ValueError(_('malformed requirements option "{0}" '
'must not be in slave for "{1}"').format(
require_opt.impl_getname(), self.impl_getname()))
def is_master(self, opt):
master = self._children[0][0]
return opt.impl_getname() == master or (opt.impl_is_dynsymlinkoption() and
opt.opt.impl_getname() == master)
2017-12-02 22:53:57 +01:00
def getmaster(self):
return self._children[1][0]
2017-12-02 22:53:57 +01:00
def getslaves(self):
for slave in self._children[1][1:]:
yield slave
def in_same_group(self, opt):
if opt.impl_is_dynsymlinkoption():
c_opt = opt.opt
else:
c_opt = opt
return c_opt in self._children[1]
def reset(self,
values,
2018-08-01 08:37:58 +02:00
option_bag,
2017-12-19 23:11:45 +01:00
_commit=True):
2018-08-02 22:35:40 +02:00
config_bag = option_bag.config_bag.copy()
2018-08-17 23:11:25 +02:00
config_bag.remove_validation()
2017-12-02 22:53:57 +01:00
for slave in self.getslaves():
2018-09-06 23:16:17 +02:00
slave_path = slave.impl_getpath()
2018-08-01 08:37:58 +02:00
soption_bag = OptionBag()
soption_bag.set_option(slave,
slave_path,
None,
config_bag)
values.reset(soption_bag,
2017-12-19 23:11:45 +01:00
_commit=_commit)
def pop(self,
values,
index,
2018-08-01 08:37:58 +02:00
option_bag,
2017-12-02 22:53:57 +01:00
slaves=undefined):
2017-12-02 22:53:57 +01:00
if slaves is undefined:
slaves = self.getslaves()
2018-08-02 22:35:40 +02:00
config_bag = option_bag.config_bag.copy()
2018-08-17 23:11:25 +02:00
config_bag.remove_validation()
2017-12-02 22:53:57 +01:00
for slave in slaves:
2018-09-06 23:16:17 +02:00
slave_path = slave.impl_getpath()
slavelen = values._p_.get_max_length(slave_path)
2018-08-01 08:37:58 +02:00
soption_bag = OptionBag()
soption_bag.set_option(slave,
slave_path,
index,
config_bag)
# do not check force_default_on_freeze
2018-08-02 22:35:40 +02:00
soption_bag.properties = set()
2018-08-01 08:37:58 +02:00
if not values.is_default_owner(soption_bag,
2017-12-19 23:11:45 +01:00
validate_meta=False):
if slavelen > index:
values._p_.resetvalue_index(slave_path,
2018-10-31 16:08:22 +01:00
index,
True)
if slavelen > index + 1:
for idx in range(index + 1, slavelen):
2018-06-09 18:59:40 +02:00
if values._p_.hasvalue(slave_path, idx):
values._p_.reduce_index(slave_path,
idx)
def reset_cache(self,
path,
2018-04-03 21:15:58 +02:00
values,
settings,
resetted_opts):
2018-04-09 21:37:49 +02:00
master = self.getmaster()
slaves = self.getslaves()
self._reset_cache(path,
master,
2018-04-09 21:37:49 +02:00
slaves,
values,
settings,
resetted_opts)
def _reset_cache(self,
path,
2018-04-09 21:37:49 +02:00
master,
slaves,
values,
settings,
resetted_opts):
super().reset_cache(path,
values,
settings,
resetted_opts)
2018-09-06 23:16:17 +02:00
mpath = master.impl_getpath()
2018-04-09 21:37:49 +02:00
master.reset_cache(mpath,
values,
settings,
None)
for slave in slaves:
2018-09-06 23:16:17 +02:00
spath = slave.impl_getpath()
2018-04-09 21:37:49 +02:00
slave.reset_cache(spath,
2018-04-03 21:15:58 +02:00
values,
settings,
2018-04-09 21:37:49 +02:00
None)
resetted_opts.append(spath)
def impl_validate_value(self,
option,
value,
context):
if isinstance(value, list) and len(value) < context._impl_length:
raise SlaveError(_('cannot reduce length of the master "{}"'
'').format(option.impl_get_display_name()))
2017-12-02 22:53:57 +01:00
2018-03-24 22:37:48 +01:00
def impl_is_master_slaves(self, *args, **kwargs):
2017-12-02 22:53:57 +01:00
return True
def to_dynoption(self,
rootpath: str,
suffix: str) -> SynDynMasterSlaves:
return SynDynMasterSlaves(self,
rootpath,
suffix)