Method for the append = 'join' processing is implemented. Added support for the 'unbound' parameter

packages
Иванов Денис 4 years ago
parent 2e846c9586
commit c3e5cdb9e1

@ -74,7 +74,7 @@ class ParametersProcessor:
'''Класс для проверки и разбора параметров шаблона.'''
available_parameters = {'name', 'path', 'append', 'chmod', 'chown',
'autoupdate', 'env', 'force', 'source', 'format',
'protected', 'mirror', 'run', 'exec', 'env',
'unbound', 'mirror', 'run', 'exec', 'env',
'package', 'merge', 'postmerge', 'action',
'rebuild', 'restart', 'stop', 'start'}
@ -132,8 +132,9 @@ class ParametersProcessor:
# будет закончен парсинг всех других параметров -- добавляем сюда метод
# для проверки.
self.postparse_checkers_list = OrderedDict({
'append': self.check_postparse_append,
'source': self.check_postparse_source})
'append': self.check_postparse_append,
'source': self.check_postparse_source,
'autoupdate': self.check_postparse_autoupdate})
# Если параметр является наследуемым только при некоторых условиях --
# указываем здесь эти условия.
@ -393,6 +394,11 @@ class ParametersProcessor:
"append = 'link' for directory template")
)
def check_postparse_autoupdate(self, parameter_value):
if self._parameters_container.unbound:
raise IncorrectParameter("'unbound' parameter is incompatible"
" with 'autoupdate' parameter")
def is_chmod_inheritable(self, parameter_value):
chmod_regex = re.compile(r'\d+')

@ -312,7 +312,8 @@ def write_file(file_path):
directory_path = path.dirname(file_path)
if not path.exists(directory_path):
os.makedirs(directory_path)
return open(file_path, 'w')
file_to_write = open(file_path, 'w')
return file_to_write
def read_file_lines(file_name, grab=False):

@ -270,7 +270,7 @@ class PackageAtomParser:
'''Класс для парсинга параметра package, его проверки, а также определения
принадлежности файла пакету.'''
package_name_pattern =\
r'(?P<name>\D[\w\d]*(\-\D[\w\d]*)*)(?P<version>-\d[^\s:]*)?'
r'(?P<name>\D[\w\d]*(\-\D[\w\d]*)*)(?P<version>-\d[^\s:]*)?'
atom_regex = re.compile(r'''(?P<category>[^\s/]*)/
{0}
@ -492,6 +492,12 @@ class PackageAtomParser:
else:
raise PackageNotFound("The file does not belong to any package")
def set_chroot(self, chroot_path):
if chroot_path != '/':
self.pkg_path = join_paths(chroot_path, self.default_pkg_path)
else:
self.pkg_path = self.default_pkg_path
@property
def atom_dictionary(self):
return self._atom_dictionary
@ -571,8 +577,8 @@ class Package:
'CONTENTS')
else:
raise PackageError(
"Incorrect 'pakage_atom' value: '{}', type: '{}''".
format(package_atom, type(package_atom)))
"Incorrect 'package_atom' value: '{}', type: '{}''".
format(package_atom, type(package_atom)))
def remove_cfg_prefix(self, file_name):
return self.re_cfg.sub('/', file_name)
@ -598,7 +604,10 @@ class Package:
return False
def write_contents_file(self):
pass
contents_file = open(self.contents_file_path, 'w')
contents_text = self.render_contents_file()
contents_file.write(contents_text)
contents_file.close()
def render_contents_file(self):
contents_format = ContentsFormat('', template_parser=False)
@ -679,14 +688,24 @@ class Package:
elif os.path.isfile(real_path):
self.add_obj(file_name)
def modify_contents_item(self, file_name, item_value):
pass
def remove_file(self, file_name):
pass
def remove_file(self, file_path):
file_path = self.remove_chroot_path(file_path)
if file_path in self.contents_dictionary:
self.contents_dictionary.remove(file_path)
def remove_empty_directories(self):
pass
used_directories = set()
not_directory_list = [path for path, value in
self.contents_dictionary.items()
if value[type] != 'dir']
for filepath in not_directory_list:
file_directory = os.path.dirname(filepath)
while file_directory != '/':
used_directories.add(file_directory)
file_directory = os.path.dirname(file_directory)
for filepath, value in self.contents_dictionary.items():
if value['type'] == 'dir' and filepath not in used_directories:
self.contents_dictionary.remove(filepath)
def get_md5(self, file_path):
try:
@ -698,6 +717,8 @@ class Package:
return file_md5
def is_md5_equal(self, file_path, file_md5=None):
'''Метод для проверки соответствия md5 хэш суммы той, что указана в
в файле CONTENTS.'''
if file_md5 is None:
file_md5 = self.get_md5(file_path)

@ -13,13 +13,14 @@ import shutil
import os
template_text = '''{% calculate append = 'join' -%}
{% calculate package = 'dev-lang/python', format = 'samba' -%}
{% calculate package = 'test-category/test-package', format = 'samba' -%}
[section one]
parameter_1 = {{ vars_1.value_1 }}
!parameter_2
'''
backup_template_text = '''{% calculate append = 'join', format = 'samba' -%}
backup_template_text = '''{% calculate append = 'join', format = 'samba',
autoupdate -%}
[section one]
parameter_1 = value
parameter_2 = value_2
@ -32,6 +33,8 @@ DATAVARS_MODULE = Variables({'vars_1': vars_1})
CHROOT_PATH = os.path.join(os.getcwd(), 'tests/templates/testfiles/test_root')
CL_CONFIG_PATH = os.path.join(CHROOT_PATH, 'var/lib/calculate/config')
CL_CONFIG_ARCHIVE_PATH = os.path.join(CHROOT_PATH,
'var/lib/calculate/config-archive')
template_engine = TemplateEngine(datavars_module=DATAVARS_MODULE,
appends_set=APPENDS_SET,
@ -54,8 +57,8 @@ class TemplateCollisionError(Exception):
class CalculateConfigFile:
def __init__(self, cl_config_path='/var/lib/calculate/config',
chroot_path='/'):
self.chroot_path = chroot_path
cl_chroot_path='/'):
self.chroot_path = cl_chroot_path
self.cl_config_path = cl_config_path
@ -113,6 +116,8 @@ class CalculateConfigFile:
return False
def save_changes(self):
if not self._unsaved_changes:
return
config_file = write_file(self.cl_config_path)
for file_name, file_md5 in self._config_dictionary.items():
@ -127,13 +132,6 @@ class CalculateConfigFile:
return file_path
def __del__(self):
'''При окончании работы исполнительного модуля не забываем сохранить
изменения внесенные в /var/lib/calculate/config.'''
if self._unsaved_changes:
self.save_changes()
self._config_dictionary = OrderedDict()
class TemplateWrapper:
'''Класс связывающий шаблон с целевым файлом и определяющий параметры
@ -145,8 +143,6 @@ class TemplateWrapper:
chroot_path = '/'
config_archive_path = '/var/lib/calculate/config-archive'
package_atom_parser = PackageAtomParser(chroot_path=chroot_path)
_protected_is_set = False
_protected_set = {'/etc'}
_unprotected_set = set()
@ -156,6 +152,9 @@ class TemplateWrapper:
self.target_path = target_file_path
self.target_package_name = None
print("TemplateWrapper init chroot: {}".format(self.chroot_path))
self.package_atom_parser = PackageAtomParser(
chroot_path=self.chroot_path)
# Вспомогательный флаг, включается, если по целевому пути лежит файл,
# для которого не определился никакой пакет.
@ -176,6 +175,7 @@ class TemplateWrapper:
# Временный флаг для определения того, является ли шаблон userspace.
self.is_userspace = False
print("Getting format class...")
# Получаем класс соответствующего формата файла.
if self.parameters.format:
self.format_class = ParametersProcessor.\
@ -184,6 +184,7 @@ class TemplateWrapper:
# Здесь будет детектор форматов.
pass
print("Checking file types conflicts...")
# Если по этому пути что-то есть -- проверяем конфликты.
if os.path.exists(target_file_path):
for file_type, checker in self.type_checks.items():
@ -196,6 +197,7 @@ class TemplateWrapper:
self.check_conflicts()
print("Checking package collision...")
self.check_package_collision()
# Если целью является файл -- проверяем наличие ._cfg0000_filename
@ -287,13 +289,13 @@ class TemplateWrapper:
raise TemplateCollisionError(
"'package' parameter is not defined for"
" template with 'append' parameter.")
if parameter_package is None:
elif parameter_package is None:
self.target_package_name = file_package
if file_package is None:
elif file_package is None:
self.target_package_name = parameter_package
if file_package != parameter_package:
elif file_package != parameter_package:
raise TemplateCollisionError(
"The template package is {0} while target"
" file package is {1}").format(
@ -307,34 +309,59 @@ class TemplateWrapper:
chroot_path=self.chroot_path)
def check_user_changes(self):
if self.target_type is None:
self.md5_matching = True
elif self.target_without_package:
if self.parameters.autoupdate:
self.md5_matching = True
self.remove_original = True
else:
self.md5_matching = False
if (self.target_type is None or
self.target_package is None or
self.target_type != FILE):
'''Метод для проверки наличия пользовательских изменений в
конфигурационных файлах.'''
# Эта проверка только для файлов.
if self.target_type != FILE:
return
print("Looking for ._cfg files...")
# Собираем список имеющихся ._cfg файлов.
cfg_pattern = os.path.join(os.path.dirname(self.target_path),
"._cfg????_{}".format(
os.path.basename(self.target_path)))
self.cfg_list = glob.glob(cfg_pattern)
target_md5 = self.target_package.get_md5(self.target_path)
self.md5_matching = self.target_package.is_md5_equal(
# Путь к архивной версии файла.
self.archive_path = self._get_archive_path(self.target_path)
if self.parameters.unbound:
# Если присутствует unbound, то просто модифицируем файл и
# удаляем его из CONTENTS.
self.md5_matching = True
elif self.target_type is None:
print("There is no files in target path...")
# Если целевой файл отсутствует.
if self.target_path in self.target_package:
# Проверка -- был ли файл удален.
self.md5_matching = False
else:
self.md5_matching = True
elif self.target_without_package:
print("There is file without package in target path...")
# Если файл по целевому пути не относится к какому-либо пакету.
if self.parameters.unbound:
self.md5_matching = True
else:
self.md5_matching = False
else:
print("Check md5 hash...")
# Если файл есть и он относится к текущему пакету.
target_md5 = self.target_package.get_md5(self.target_path)
self.md5_matching = self.target_package.is_md5_equal(
self.target_path,
file_md5=target_md5)
# Если по целевому пути файл не относящийся к какому-либо пакету и
# присутствует параметр autoupdate -- удаляем этот файл.
if self.target_without_package and self.parameters.autoupdate:
self.remove_original = True
self.md5_matching = self.md5_matching or self.parameters.autoupdate
self.archive_path = self._get_archive_path(self.target_path)
# Определяем путей входных и выходных файлов.
if self.md5_matching:
print("md5 matches")
# Приоритет отдаем пути из параметра source.
if self.parameters.source:
self.input_path = self.parameters.source
@ -343,6 +370,7 @@ class TemplateWrapper:
self.output_path = self.target_path
else:
print("md5 does not match")
# Приоритет отдаем пути из параметра source.
if self.parameters.source:
self.input_path = self.parameters.source
@ -352,11 +380,13 @@ class TemplateWrapper:
self.output_path = self._get_cfg_path(self.target_path)
def _get_archive_path(self, file_path):
print("Getting archive path...")
if self.chroot_path != "/" and file_path.startswith(self.chroot_path):
file_path = file_path[len(self.chroot_path):]
return join_paths(self.config_archive_path, file_path)
def _get_cfg_path(self, file_path):
print("Getting ._cfg path...")
if self.cfg_list:
last_cfg_name = os.path.basename(self.cfg_list[-1])
@ -376,7 +406,7 @@ class TemplateWrapper:
return new_cfg_path
def remove_from_contents(self):
pass
self.target_package.remove_file(self.target_path)
def add_to_contents(self, file_md5=None):
if self.parameters.append == 'link':
@ -403,6 +433,10 @@ class TemplateWrapper:
cls._protected_is_set = True
def save_changes(self):
if self.target_package and not self.parameters.unbound:
self.target_package.write_contents_file()
class TemplateExecutor:
def __init__(self, datavars_module=Variables(), chroot_path='/',
@ -429,7 +463,7 @@ class TemplateExecutor:
cl_chroot_path=chroot_path)
TemplateWrapper.chroot_path = self.chroot_path
TemplateWrapper.cl_config_archive = cl_config_archive
TemplateWrapper.config_archive_path = cl_config_archive
@property
def available_appends(self):
@ -449,8 +483,15 @@ class TemplateExecutor:
template_text=template_text)
except TemplateTypeConflict as error:
print('type conflict: {}'.format(str(error)))
return
except TemplateCollisionError as error:
print('collision: {}'.format(str(error)))
return
# Temporary
print("Wrapper succesfully initialized.")
print("Input path:", template_object.input_path)
print("Output path:", template_object.output_path)
if template_object.remove_original:
if template_object.target_type == DIR:
@ -459,13 +500,17 @@ class TemplateExecutor:
self._remove_file(template_object.target_path)
template_object.target_type = None
# Добавить поддержку run, excute и т.д.
# Добавить поддержку run, execute и т.д.
if template_object.template_type == DIR:
self.directory_appends[template_object.parameters.append](
template_object)
elif template_object.template_type == FILE:
self.file_appends[template_object.parameters.append](
template_object)
template_object.save_changes()
def save_changes(self):
self.calculate_config_file.save_changes()
def _append_join_directory(self, template_object: TemplateWrapper):
if template_object.target_type is None:
@ -496,7 +541,7 @@ class TemplateExecutor:
if template_object.md5_matching:
output_paths = [output_path]
# Проверка на предмет userspace.
if template_object.is_userspace:
if not template_object.is_userspace:
output_paths.append(template_object.archive_path)
if template_object.target_type is not None:
@ -529,7 +574,10 @@ class TemplateExecutor:
self.calculate_config_file.remove_file(template_object.target_path)
# Обновляем CONTENTS.
template_object.add_to_contents(file_md5=output_text_md5)
if template_object.parameters.unbound:
template_object.remove_from_contents()
else:
template_object.add_to_contents(file_md5=output_text_md5)
else:
with open(input_path, 'r') as input_file:
input_text = input_file.read()
@ -546,12 +594,17 @@ class TemplateExecutor:
if not self.calculate_config_file.compare_md5(target_path,
output_text_md5):
print("cl is different, create ._cfg")
with open(output_path, 'w') as output_file:
output_file.write(output_text)
self.calculate_config_file.set_files_md5(template_object,
output_text_md5)
self.calculate_config_file.set_files_md5(
template_object.target_path,
output_text_md5)
print("current config: ",
self.calculate_config_file._config_dictionary)
else:
# Действия если CL совпало. Пока ничего не делаем.
print("cl is similar...")
pass
# Обновляем CONTENTS.
@ -771,9 +824,13 @@ class TemplateExecutor:
self.output.set_error('error with owner: {}'.format(owner))
def check_filesystem(self, target_path):
'''Метод, который предположительно будет использоваться для проверки
файловой системы перед применением шаблона.'''
pass
def is_vfat(self, path):
'''Метод, проверяющий является ли файловая система vfat. Нужно для того,
чтобы заранее знать о возможности применения chown, chmod и т.д.'''
if self.mounts is None:
self.mounts = Mounts()
if self.mounts.get_from_fstab(what=self.mounts.TYPE,
@ -798,17 +855,25 @@ template_engine.process_template_from_string(template_text, FILE)
template_parameters = template_engine.parameters
template_text = template_engine.template_text
template_action_obj = TemplateExecutor(datavars_module=DATAVARS_MODULE,
chroot_path=CHROOT_PATH)
result = template_action_obj.use_file_template(target_path,
template_parameters,
template_text=template_text)
print('MAIN TEST TEMPLATE IS USED')
# Применение шаблона бэкапа:
template_executor_obj = TemplateExecutor(
datavars_module=DATAVARS_MODULE,
chroot_path=CHROOT_PATH,
cl_config_archive=CL_CONFIG_ARCHIVE_PATH,
cl_config_path=CL_CONFIG_PATH)
template_executor_obj.execute_template(target_path,
template_parameters,
FILE, template_text=template_text)
template_executor_obj.save_changes()
input()
template_engine.process_template_from_string(backup_template_text, FILE)
result = template_action_obj.use_file_template(
target_path,
template_engine.parameters,
template_text=template_engine.template_text)
print('BACKUP TEMPLATE IS USED')
template_parameters = template_engine.parameters
template_text = template_engine.template_text
template_executor_obj = TemplateExecutor(
datavars_module=DATAVARS_MODULE,
chroot_path=CHROOT_PATH,
cl_config_archive=CL_CONFIG_ARCHIVE_PATH,
cl_config_path=CL_CONFIG_PATH)
template_executor_obj.execute_template(target_path,
template_parameters,
FILE, template_text=template_text)
template_executor_obj.save_changes()

@ -3,3 +3,4 @@
parameter_2 = value_2
[section two]
parameter_3 = value_3
origin_parameter = origin_value

@ -0,0 +1,3 @@
dir /etc
dir /etc/dir
obj /etc/dir/file.conf f050e31b0c059cc6b1edbd4871db1b91 1590420040

@ -0,0 +1,6 @@
[section one]
parameter_1 = value
parameter_2 = value_2
[section two]
parameter_3 = value_3
origin_parameter = origin_value
Loading…
Cancel
Save