|
|
|
@ -20,6 +20,7 @@ from ..utils.files import join_paths, check_directory_link, check_command,\
|
|
|
|
|
from calculate.variables.datavars import HashType, NamespaceNode,\
|
|
|
|
|
VariableNode, IniType, IntegerType,\
|
|
|
|
|
FloatType, ListType
|
|
|
|
|
from calculate.variables.loader import Datavars
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Типы шаблона: директория или файл.
|
|
|
|
@ -51,40 +52,45 @@ class Variables(MutableMapping):
|
|
|
|
|
iterator = iter(self.__attrs)
|
|
|
|
|
return next(iterator)
|
|
|
|
|
|
|
|
|
|
def __getattribute__(self, name):
|
|
|
|
|
def __getattribute__(self, name: str):
|
|
|
|
|
if name == '_Variables__attrs':
|
|
|
|
|
return super().__getattribute__(name)
|
|
|
|
|
if name == 'available_packages':
|
|
|
|
|
return super().__getattribute__(name)
|
|
|
|
|
if name == 'variables':
|
|
|
|
|
return self.__attrs
|
|
|
|
|
try:
|
|
|
|
|
return self.__attrs[name]
|
|
|
|
|
except KeyError:
|
|
|
|
|
raise AttributeError(name)
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def available_packages(self):
|
|
|
|
|
def available_packages(self) -> set:
|
|
|
|
|
packages = set(self.__attrs.keys())
|
|
|
|
|
packages.update({'custom'})
|
|
|
|
|
return packages
|
|
|
|
|
|
|
|
|
|
def __getitem__(self, name):
|
|
|
|
|
def __getitem__(self, name: str):
|
|
|
|
|
return self.__attrs[name]
|
|
|
|
|
|
|
|
|
|
def __setitem__(self, name, value):
|
|
|
|
|
def __setitem__(self, name: str, value) -> None:
|
|
|
|
|
self.__attrs[name] = value
|
|
|
|
|
|
|
|
|
|
def __delitem__(self, name):
|
|
|
|
|
def __delitem__(self, name: str) -> None:
|
|
|
|
|
del self.__attrs[name]
|
|
|
|
|
|
|
|
|
|
def __iter__(self):
|
|
|
|
|
return iter(self.__attrs)
|
|
|
|
|
|
|
|
|
|
def __len__(self):
|
|
|
|
|
def __len__(self) -> int:
|
|
|
|
|
return len(self.__attrs)
|
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
|
|
return '<Variables {}>'.format(self.__attrs)
|
|
|
|
|
|
|
|
|
|
def __contains__(self, name: str) -> bool:
|
|
|
|
|
return name in self.__attrs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ParametersProcessor:
|
|
|
|
|
'''Класс для проверки и разбора параметров шаблона.'''
|
|
|
|
@ -93,10 +99,10 @@ class ParametersProcessor:
|
|
|
|
|
'unbound', 'mirror', 'run', 'exec', 'env',
|
|
|
|
|
'package', 'merge', 'postmerge', 'action',
|
|
|
|
|
'rebuild', 'restart', 'stop', 'start', 'handler',
|
|
|
|
|
'notify'}
|
|
|
|
|
'notify', 'group'}
|
|
|
|
|
|
|
|
|
|
inheritable_parameters = {'chmod', 'chown', 'autoupdate', 'env',
|
|
|
|
|
'package', 'action', 'handler'}
|
|
|
|
|
'package', 'action', 'handler', 'group'}
|
|
|
|
|
|
|
|
|
|
# Параметры по умолчанию для файлов --
|
|
|
|
|
# будут заполняться из __datavars__
|
|
|
|
@ -129,6 +135,20 @@ class ParametersProcessor:
|
|
|
|
|
|
|
|
|
|
self.package_atom_parser = PackageAtomParser(chroot_path=chroot_path)
|
|
|
|
|
|
|
|
|
|
self._groups = {}
|
|
|
|
|
try:
|
|
|
|
|
groups = list(datavars_module.main.cl.groups.variables.keys())
|
|
|
|
|
for group in groups:
|
|
|
|
|
if isinstance(datavars_module, (Datavars, NamespaceNode)):
|
|
|
|
|
packages = datavars_module.main.cl.groups[group].get_value(
|
|
|
|
|
).get_table()
|
|
|
|
|
else:
|
|
|
|
|
packages = datavars_module.main.cl.groups[group]
|
|
|
|
|
self._groups.update({group: packages})
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
pprint(self._groups)
|
|
|
|
|
|
|
|
|
|
self._inspect_formats_package()
|
|
|
|
|
|
|
|
|
|
self._for_package = None
|
|
|
|
@ -137,6 +157,7 @@ class ParametersProcessor:
|
|
|
|
|
# метод для проверки.
|
|
|
|
|
self.checkers_list = OrderedDict({
|
|
|
|
|
'package': self.check_package_parameter,
|
|
|
|
|
'group': self.check_group_parameter,
|
|
|
|
|
'append': self.check_append_parameter,
|
|
|
|
|
'rebuild': self.check_rebuild_parameter,
|
|
|
|
|
'restart': self.check_restart_parameter,
|
|
|
|
@ -158,19 +179,23 @@ class ParametersProcessor:
|
|
|
|
|
# будет закончен парсинг всех других параметров -- добавляем сюда метод
|
|
|
|
|
# для проверки.
|
|
|
|
|
self.postparse_checkers_list = OrderedDict({
|
|
|
|
|
'package': self.check_postparse_package,
|
|
|
|
|
'append': self.check_postparse_append,
|
|
|
|
|
'source': self.check_postparse_source,
|
|
|
|
|
'autoupdate': self.check_postparse_autoupdate,
|
|
|
|
|
'run': self.check_postparse_run,
|
|
|
|
|
'exec': self.check_postparse_exec,
|
|
|
|
|
'handler': self.check_postparse_handler})
|
|
|
|
|
'handler': self.check_postparse_handler
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
# Если параметр является наследуемым только при некоторых условиях --
|
|
|
|
|
# указываем здесь эти условия.
|
|
|
|
|
self.inherit_conditions = {'chmod': self.is_chmod_inheritable}
|
|
|
|
|
|
|
|
|
|
def set_parameters_container(self, parameters_container):
|
|
|
|
|
'''Метод для установки текущего контейнера параметров.'''
|
|
|
|
|
self._parameters_container = parameters_container
|
|
|
|
|
self._added_parameters = set()
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def for_package(self):
|
|
|
|
@ -207,6 +232,8 @@ class ParametersProcessor:
|
|
|
|
|
if checked_value is None:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
self._added_parameters.add(parameter_name)
|
|
|
|
|
|
|
|
|
|
if (parameter_name in self.inheritable_parameters and
|
|
|
|
|
self.template_type == DIR):
|
|
|
|
|
if parameter_name in self.inherit_conditions:
|
|
|
|
@ -227,11 +254,13 @@ class ParametersProcessor:
|
|
|
|
|
'''Метод, запускающий проверку параметров после их разбора.'''
|
|
|
|
|
for parameter, parameter_checker in\
|
|
|
|
|
self.postparse_checkers_list.items():
|
|
|
|
|
if parameter not in self._parameters_container:
|
|
|
|
|
if parameter not in self._added_parameters:
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
parameter_value = self._parameters_container[parameter]
|
|
|
|
|
parameter_checker(parameter_value)
|
|
|
|
|
result = parameter_checker(parameter_value)
|
|
|
|
|
if result is not None:
|
|
|
|
|
self._parameters_container.change_parameter(parameter,
|
|
|
|
|
result)
|
|
|
|
|
|
|
|
|
|
def check_template_parameters(self, parameters, template_type, lineno):
|
|
|
|
|
'''Метод, запускающий проверку указанных параметров.'''
|
|
|
|
@ -268,24 +297,27 @@ class ParametersProcessor:
|
|
|
|
|
# Методы для проверки параметров во время разбора шаблона.
|
|
|
|
|
|
|
|
|
|
def check_package_parameter(self, parameter_value):
|
|
|
|
|
try:
|
|
|
|
|
if isinstance(parameter_value, str):
|
|
|
|
|
result = self.package_atom_parser.parse_package_parameter(
|
|
|
|
|
parameter_value)
|
|
|
|
|
elif isinstance(parameter_value, list):
|
|
|
|
|
result = []
|
|
|
|
|
for atom in parameter_value:
|
|
|
|
|
result.append(
|
|
|
|
|
self.package_atom_parser.parse_package_parameter(
|
|
|
|
|
atom)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
except PackageAtomError as error:
|
|
|
|
|
if error.errno == NOTEXIST:
|
|
|
|
|
raise ConditionFailed(error.message, self.lineno)
|
|
|
|
|
else:
|
|
|
|
|
raise IncorrectParameter(error.message)
|
|
|
|
|
if not isinstance(parameter_value, str):
|
|
|
|
|
raise IncorrectParameter("'package' parameter must have value of"
|
|
|
|
|
" the 'str' type, not"
|
|
|
|
|
f" {type(parameter_value)}")
|
|
|
|
|
return parameter_value
|
|
|
|
|
|
|
|
|
|
def check_group_parameter(self, parameter_value):
|
|
|
|
|
if isinstance(parameter_value, str):
|
|
|
|
|
result = [group.strip() for group in parameter_value.split(',')]
|
|
|
|
|
elif isinstance(parameter_value, (list, tuple)):
|
|
|
|
|
result = parameter_value if isinstance(parameter_value, list) else\
|
|
|
|
|
list(parameter_value)
|
|
|
|
|
else:
|
|
|
|
|
raise IncorrectParameter("'package' parameter must have value of"
|
|
|
|
|
" the 'str', 'list' or 'tuple' type, not"
|
|
|
|
|
f" {type(parameter_value)}")
|
|
|
|
|
for group in result:
|
|
|
|
|
if group != "install" and group not in self._groups:
|
|
|
|
|
raise IncorrectParameter(f"'group' parameter value '{group}'"
|
|
|
|
|
" is not available. Available values:"
|
|
|
|
|
f" {', '.join(self._groups.keys())}")
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
def check_append_parameter(self, parameter_value):
|
|
|
|
@ -529,7 +561,7 @@ class ParametersProcessor:
|
|
|
|
|
raise IncorrectParameter("'unbound' parameter is incompatible"
|
|
|
|
|
" with 'autoupdate' parameter")
|
|
|
|
|
|
|
|
|
|
def check_postparse_handler(self, parameter_rvalue):
|
|
|
|
|
def check_postparse_handler(self, parameter_value):
|
|
|
|
|
if self._parameters_container.merge:
|
|
|
|
|
raise IncorrectParameter("'merge' parameter is not available"
|
|
|
|
|
" in handler templates.")
|
|
|
|
@ -538,6 +570,52 @@ class ParametersProcessor:
|
|
|
|
|
raise IncorrectParameter("'package' parameter is not available"
|
|
|
|
|
" in handler templates.")
|
|
|
|
|
|
|
|
|
|
def check_postparse_package(self, parameter_value):
|
|
|
|
|
groups = []
|
|
|
|
|
package_atom = PackageAtomParser.parse_atom_name(parameter_value)
|
|
|
|
|
|
|
|
|
|
if (self._parameters_container is None
|
|
|
|
|
or not self._parameters_container.group):
|
|
|
|
|
# Если параметр group не задан или метод используется для проверки
|
|
|
|
|
# отдельного параметра package -- делаем только проверку install.
|
|
|
|
|
# Предполагающую проверку существования пакета.
|
|
|
|
|
groups.append('install')
|
|
|
|
|
else:
|
|
|
|
|
groups = self._parameters_container.group
|
|
|
|
|
|
|
|
|
|
for group in groups:
|
|
|
|
|
if group == 'install':
|
|
|
|
|
try:
|
|
|
|
|
result = self.package_atom_parser.parse_package_parameter(
|
|
|
|
|
package_atom)
|
|
|
|
|
return result
|
|
|
|
|
except PackageAtomError as error:
|
|
|
|
|
if error.errno != NOTEXIST:
|
|
|
|
|
raise IncorrectParameter(error.message)
|
|
|
|
|
elif self._check_package_group(package_atom,
|
|
|
|
|
self._groups[group]):
|
|
|
|
|
self._parameters_container.remove_parameter('package')
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
raise ConditionFailed(f"package '{parameter_value}'"
|
|
|
|
|
" does not template condition", self.lineno)
|
|
|
|
|
|
|
|
|
|
def _check_package_group(self, package: dict, group_packages: list):
|
|
|
|
|
for group_package in group_packages:
|
|
|
|
|
for parameter in ['category', 'name', 'version', 'slot']:
|
|
|
|
|
if package[parameter] is not None:
|
|
|
|
|
if (group_package[parameter] is None
|
|
|
|
|
or group_package[parameter] != package[parameter]):
|
|
|
|
|
return False
|
|
|
|
|
if package['use_flags'] is not None:
|
|
|
|
|
if group_package['use_flags'] is None:
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
for use_flag in package['use_flags']:
|
|
|
|
|
if use_flag not in group_package['use_flags']:
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
# Методы для проверки того, являются ли параметры наследуемыми.
|
|
|
|
|
|
|
|
|
|
def is_chmod_inheritable(self, parameter_value):
|
|
|
|
@ -574,7 +652,6 @@ class ParametersProcessor:
|
|
|
|
|
if self.chroot_path == '/':
|
|
|
|
|
gid = grp.getgrnam(group_name).gr_gid
|
|
|
|
|
else:
|
|
|
|
|
print("using get_gid_from_group")
|
|
|
|
|
gid = self.get_gid_from_group(group_name)
|
|
|
|
|
except (FilesError, KeyError, TypeError) as error:
|
|
|
|
|
raise IncorrectParameter(
|
|
|
|
@ -767,6 +844,18 @@ class ParametersContainer(MutableMapping):
|
|
|
|
|
return (parameter_name not in self.__parameters
|
|
|
|
|
and parameter_name in self.__inheritable)
|
|
|
|
|
|
|
|
|
|
def remove_parameter(self, parameter_name):
|
|
|
|
|
if parameter_name in self.__parameters:
|
|
|
|
|
self.__parameters.pop(parameter_name)
|
|
|
|
|
elif parameter_name in self.__inheritable:
|
|
|
|
|
self.__inheritable.pop(parameter_name)
|
|
|
|
|
|
|
|
|
|
def change_parameter(self, parameter, value):
|
|
|
|
|
if parameter in self.__parameters:
|
|
|
|
|
self.__parameters.update({parameter: value})
|
|
|
|
|
elif parameter in self.__inheritable:
|
|
|
|
|
self.__inheritable.update({parameter: value})
|
|
|
|
|
|
|
|
|
|
def _clear_container(self):
|
|
|
|
|
self.__parameters.clear()
|
|
|
|
|
self.__inheritable.clear()
|
|
|
|
@ -920,6 +1009,7 @@ class CalculateExtension(Extension):
|
|
|
|
|
lineno=lineno)
|
|
|
|
|
|
|
|
|
|
expect_comma_flag = False
|
|
|
|
|
conditions = []
|
|
|
|
|
|
|
|
|
|
while self.stream.current.type != 'block_end':
|
|
|
|
|
if expect_comma_flag:
|
|
|
|
@ -953,10 +1043,11 @@ class CalculateExtension(Extension):
|
|
|
|
|
or self.stream.current.type == 'lparen'
|
|
|
|
|
or self.stream.current.type == 'integer'):
|
|
|
|
|
# разбираем условие. Если условие False -- кидаем исключение.
|
|
|
|
|
condition_result = self.get_condition_result()
|
|
|
|
|
if not condition_result:
|
|
|
|
|
raise ConditionFailed('Condition is failed',
|
|
|
|
|
lineno=self.stream.current.lineno)
|
|
|
|
|
# condition_result = self.get_condition_result()
|
|
|
|
|
# if not condition_result:
|
|
|
|
|
# raise ConditionFailed('Condition is failed',
|
|
|
|
|
# lineno=self.stream.current.lineno)
|
|
|
|
|
conditions.append(self.parse_condition())
|
|
|
|
|
elif self.stream.current.type == 'name':
|
|
|
|
|
raise TemplateSyntaxError(
|
|
|
|
|
f"Unknown identifier '{self.stream.current.value}'"
|
|
|
|
@ -969,12 +1060,8 @@ class CalculateExtension(Extension):
|
|
|
|
|
lineno=self.stream.current.lineno)
|
|
|
|
|
expect_comma_flag = True
|
|
|
|
|
|
|
|
|
|
# dictionary_node = nodes.Dict(pairs_list)
|
|
|
|
|
# save_node = self.call_method('save_parameters',
|
|
|
|
|
# [dictionary_node,
|
|
|
|
|
# nodes.ContextReference()],
|
|
|
|
|
# lineno=lineno)
|
|
|
|
|
# return nodes.Output([save_node], lineno=lineno)
|
|
|
|
|
self.parameters_processor.check_postparse_parameters()
|
|
|
|
|
self.check_conditions(conditions)
|
|
|
|
|
|
|
|
|
|
self.calculate_parsed = True
|
|
|
|
|
return nodes.Output([nodes.Const('')], lineno=lineno)
|
|
|
|
@ -998,11 +1085,42 @@ class CalculateExtension(Extension):
|
|
|
|
|
self.stream.current.lineno)
|
|
|
|
|
return ''
|
|
|
|
|
|
|
|
|
|
def parse_condition(self):
|
|
|
|
|
try:
|
|
|
|
|
condition_node = self.parser.parse_expression(with_condexpr=True)
|
|
|
|
|
condition_node = self.call_method(
|
|
|
|
|
'set_condition_result',
|
|
|
|
|
[condition_node],
|
|
|
|
|
lineno=self.stream.current.lineno)
|
|
|
|
|
condition_template = nodes.Template(
|
|
|
|
|
[nodes.Output([condition_node])])
|
|
|
|
|
|
|
|
|
|
condition_template = condition_template.set_environment(
|
|
|
|
|
self.environment)
|
|
|
|
|
template = self.environment.from_string(condition_template)
|
|
|
|
|
|
|
|
|
|
return template
|
|
|
|
|
except Exception as error:
|
|
|
|
|
raise ConditionFailed('Error during parsing condition:{}'
|
|
|
|
|
.format(str(error)),
|
|
|
|
|
lineno=self.stream.current.lineno)
|
|
|
|
|
|
|
|
|
|
def check_conditions(self, conditions: list):
|
|
|
|
|
for condition in conditions:
|
|
|
|
|
self.condition_result = False
|
|
|
|
|
try:
|
|
|
|
|
condition.render(__datavars__=self._datavars)
|
|
|
|
|
except Exception as error:
|
|
|
|
|
raise ConditionFailed('Error during handling condition: {}'
|
|
|
|
|
.format(str(error)),
|
|
|
|
|
lineno=self.stream.current.lineno)
|
|
|
|
|
if not self.condition_result:
|
|
|
|
|
raise ConditionFailed('Condition is failed',
|
|
|
|
|
lineno=self.stream.current.lineno)
|
|
|
|
|
|
|
|
|
|
# DEPRECATED
|
|
|
|
|
def get_condition_result(self):
|
|
|
|
|
'''Метод для разбора условий из тега calculate.'''
|
|
|
|
|
# лучший способ -- парсим в AST дерево, после чего компилируем и
|
|
|
|
|
# выполняем его.
|
|
|
|
|
print('GET CONDITION')
|
|
|
|
|
self.condition_result = False
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
@ -1019,43 +1137,11 @@ class CalculateExtension(Extension):
|
|
|
|
|
template = self.environment.from_string(condition_template)
|
|
|
|
|
|
|
|
|
|
template.render(__datavars__=self._datavars)
|
|
|
|
|
except Exception as error:
|
|
|
|
|
print('Error during running condition:', str(error))
|
|
|
|
|
except Exception:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
print('condition result:', self.condition_result)
|
|
|
|
|
return self.condition_result
|
|
|
|
|
|
|
|
|
|
# собираем исходный код условия из токенов.
|
|
|
|
|
# вероятно, следует придумать лучший способ.
|
|
|
|
|
# while (self.stream.current.type != 'block_end' and
|
|
|
|
|
# self.stream.current.type != 'comma'):
|
|
|
|
|
# if self.stream.current.type == 'string':
|
|
|
|
|
# condition_list.append("'{}'".format(
|
|
|
|
|
# self.stream.current.value
|
|
|
|
|
# ))
|
|
|
|
|
# elif self.stream.current.type == 'dot':
|
|
|
|
|
# self.stream.skip(1)
|
|
|
|
|
# if self.stream.current.type == 'name':
|
|
|
|
|
# next_name = '.' + self.stream.current.value
|
|
|
|
|
# else:
|
|
|
|
|
# raise TemplateSyntaxError(
|
|
|
|
|
# 'Variable name is not correct.',
|
|
|
|
|
# lineno=self.stream.current.lineno
|
|
|
|
|
# )
|
|
|
|
|
# condition_list[-1] = condition_list[-1] + next_name
|
|
|
|
|
# else:
|
|
|
|
|
# condition_list.append(str(self.stream.current.value))
|
|
|
|
|
# self.stream.skip(1)
|
|
|
|
|
|
|
|
|
|
# condition = ' '.join(condition_list)
|
|
|
|
|
|
|
|
|
|
# компилируем исходный код условия и получаем результат его вычисления.
|
|
|
|
|
|
|
|
|
|
# cond_expr = self.environment.compile_expression(condition)
|
|
|
|
|
# condition_result = cond_expr(__datavars__=self._datavars)
|
|
|
|
|
# return condition_result
|
|
|
|
|
|
|
|
|
|
def set_condition_result(self, condition_result):
|
|
|
|
|
'''Метод для сохранения результата вычисления условия.'''
|
|
|
|
|
self.condition_result = condition_result
|
|
|
|
@ -1402,14 +1488,13 @@ class TemplateEngine:
|
|
|
|
|
else:
|
|
|
|
|
CalculateContext._env_set = set()
|
|
|
|
|
|
|
|
|
|
self.parameters_processor._parameters_container =\
|
|
|
|
|
self._parameters_object
|
|
|
|
|
self.parameters_processor.set_parameters_container(
|
|
|
|
|
self._parameters_object)
|
|
|
|
|
|
|
|
|
|
self.calculate_extension.template_type = template_type
|
|
|
|
|
self.calculate_extension.calculate_parsed = False
|
|
|
|
|
|
|
|
|
|
template = self.environment.get_template(template_path)
|
|
|
|
|
self.parameters_processor.check_postparse_parameters()
|
|
|
|
|
|
|
|
|
|
self._template_text = template.render(
|
|
|
|
|
__datavars__=self._datavars_module,
|
|
|
|
@ -1430,14 +1515,13 @@ class TemplateEngine:
|
|
|
|
|
else:
|
|
|
|
|
CalculateContext._env_set = set()
|
|
|
|
|
|
|
|
|
|
self.parameters_processor._parameters_container =\
|
|
|
|
|
self._parameters_object
|
|
|
|
|
self.parameters_processor.set_parameters_container(
|
|
|
|
|
self._parameters_object)
|
|
|
|
|
|
|
|
|
|
self.calculate_extension.template_type = template_type
|
|
|
|
|
self.calculate_extension.calculate_parsed = False
|
|
|
|
|
|
|
|
|
|
template = self.environment.from_string(string)
|
|
|
|
|
self.parameters_processor.check_postparse_parameters()
|
|
|
|
|
|
|
|
|
|
self._template_text = template.render(
|
|
|
|
|
__datavars__=self._datavars_module,
|
|
|
|
|