|
|
@ -144,15 +144,20 @@ class TemplateWrapper:
|
|
|
|
config_archive_path = '/var/lib/calculate/config-archive'
|
|
|
|
config_archive_path = '/var/lib/calculate/config-archive'
|
|
|
|
|
|
|
|
|
|
|
|
_protected_is_set = False
|
|
|
|
_protected_is_set = False
|
|
|
|
_protected_set = {'/etc'}
|
|
|
|
_protected_set = set()
|
|
|
|
_unprotected_set = set()
|
|
|
|
_unprotected_set = set()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __new__(cls, *args, **kwargs):
|
|
|
|
|
|
|
|
if not cls._protected_is_set:
|
|
|
|
|
|
|
|
# Устанавливаем значения PROTECTED, если не заданы.
|
|
|
|
|
|
|
|
cls._set_protected()
|
|
|
|
|
|
|
|
return super().__new__(cls)
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, target_file_path, parameters, template_type,
|
|
|
|
def __init__(self, target_file_path, parameters, template_type,
|
|
|
|
template_text=''):
|
|
|
|
template_text=''):
|
|
|
|
self.target_path = target_file_path
|
|
|
|
self.target_path = target_file_path
|
|
|
|
|
|
|
|
|
|
|
|
self.target_package_name = None
|
|
|
|
self.target_package_name = None
|
|
|
|
print("TemplateWrapper init chroot: {}".format(self.chroot_path))
|
|
|
|
|
|
|
|
self.package_atom_parser = PackageAtomParser(
|
|
|
|
self.package_atom_parser = PackageAtomParser(
|
|
|
|
chroot_path=self.chroot_path)
|
|
|
|
chroot_path=self.chroot_path)
|
|
|
|
|
|
|
|
|
|
|
@ -172,10 +177,15 @@ class TemplateWrapper:
|
|
|
|
# применением шаблона.
|
|
|
|
# применением шаблона.
|
|
|
|
self.remove_original = False
|
|
|
|
self.remove_original = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Флаг, указывающий, что целевой путь был изменен.
|
|
|
|
|
|
|
|
self.target_path_is_changed = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Флаг, указывающий, что файл является PROTECTED.
|
|
|
|
|
|
|
|
self.protected = False
|
|
|
|
|
|
|
|
|
|
|
|
# Временный флаг для определения того, является ли шаблон userspace.
|
|
|
|
# Временный флаг для определения того, является ли шаблон userspace.
|
|
|
|
self.is_userspace = False
|
|
|
|
self.is_userspace = False
|
|
|
|
|
|
|
|
|
|
|
|
print("Getting format class...")
|
|
|
|
|
|
|
|
# Получаем класс соответствующего формата файла.
|
|
|
|
# Получаем класс соответствующего формата файла.
|
|
|
|
if self.parameters.format:
|
|
|
|
if self.parameters.format:
|
|
|
|
self.format_class = ParametersProcessor.\
|
|
|
|
self.format_class = ParametersProcessor.\
|
|
|
@ -184,7 +194,6 @@ class TemplateWrapper:
|
|
|
|
# Здесь будет детектор форматов.
|
|
|
|
# Здесь будет детектор форматов.
|
|
|
|
pass
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
print("Checking file types conflicts...")
|
|
|
|
|
|
|
|
# Если по этому пути что-то есть -- проверяем конфликты.
|
|
|
|
# Если по этому пути что-то есть -- проверяем конфликты.
|
|
|
|
if os.path.exists(target_file_path):
|
|
|
|
if os.path.exists(target_file_path):
|
|
|
|
for file_type, checker in self.type_checks.items():
|
|
|
|
for file_type, checker in self.type_checks.items():
|
|
|
@ -197,7 +206,6 @@ class TemplateWrapper:
|
|
|
|
|
|
|
|
|
|
|
|
self.check_conflicts()
|
|
|
|
self.check_conflicts()
|
|
|
|
|
|
|
|
|
|
|
|
print("Checking package collision...")
|
|
|
|
|
|
|
|
self.check_package_collision()
|
|
|
|
self.check_package_collision()
|
|
|
|
|
|
|
|
|
|
|
|
# Если целью является файл -- проверяем наличие ._cfg0000_filename
|
|
|
|
# Если целью является файл -- проверяем наличие ._cfg0000_filename
|
|
|
@ -217,7 +225,6 @@ class TemplateWrapper:
|
|
|
|
if self.parameters.append == 'link':
|
|
|
|
if self.parameters.append == 'link':
|
|
|
|
if self.parameters.force:
|
|
|
|
if self.parameters.force:
|
|
|
|
self.remove_original = True
|
|
|
|
self.remove_original = True
|
|
|
|
return
|
|
|
|
|
|
|
|
elif self.target_type == DIR:
|
|
|
|
elif self.target_type == DIR:
|
|
|
|
raise TemplateTypeConflict(
|
|
|
|
raise TemplateTypeConflict(
|
|
|
|
"The target is a directory while the"
|
|
|
|
"The target is a directory while the"
|
|
|
@ -227,40 +234,34 @@ class TemplateWrapper:
|
|
|
|
"The target is a file while the"
|
|
|
|
"The target is a file while the"
|
|
|
|
" template has append = 'link'.")
|
|
|
|
" template has append = 'link'.")
|
|
|
|
|
|
|
|
|
|
|
|
if self.template_type == DIR:
|
|
|
|
elif self.template_type == DIR:
|
|
|
|
if self.parameters.force:
|
|
|
|
if self.target_type == FILE:
|
|
|
|
self.remove_original = True
|
|
|
|
if self.parameters.force:
|
|
|
|
return
|
|
|
|
self.remove_original = True
|
|
|
|
elif self.target_type == FILE:
|
|
|
|
else:
|
|
|
|
raise TemplateTypeConflict("The target is a file while the"
|
|
|
|
raise TemplateTypeConflict("The target is a file while the"
|
|
|
|
" template is a directory.")
|
|
|
|
" template is a directory.")
|
|
|
|
elif self.target_is_link and self.target_type == DIR:
|
|
|
|
elif self.target_is_link and self.target_type == DIR:
|
|
|
|
try:
|
|
|
|
if self.parameters.force:
|
|
|
|
self.target_path = read_link(self.target_path)
|
|
|
|
self.remove_original = True
|
|
|
|
except FilesError as error:
|
|
|
|
else:
|
|
|
|
raise TemplateExecutorError("files error: {}".
|
|
|
|
try:
|
|
|
|
format(str(error)))
|
|
|
|
self.target_path = read_link(self.target_path)
|
|
|
|
return
|
|
|
|
except FilesError as error:
|
|
|
|
else:
|
|
|
|
raise TemplateExecutorError("files error: {}".
|
|
|
|
return
|
|
|
|
format(str(error)))
|
|
|
|
|
|
|
|
|
|
|
|
if self.template_type == FILE:
|
|
|
|
elif self.template_type == FILE:
|
|
|
|
if self.parameters.force:
|
|
|
|
if self.parameters.force:
|
|
|
|
if self.target_type == DIR:
|
|
|
|
if self.target_type == DIR:
|
|
|
|
self.remove_original = True
|
|
|
|
self.remove_original = True
|
|
|
|
return
|
|
|
|
|
|
|
|
elif self.target_is_link and self.target_type == FILE:
|
|
|
|
elif self.target_is_link and self.target_type == FILE:
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
self.target_path = read_link(self.target_path)
|
|
|
|
self.target_path = read_link(self.target_path)
|
|
|
|
except FilesError as error:
|
|
|
|
except FilesError as error:
|
|
|
|
raise TemplateExecutorError("files error: {}".
|
|
|
|
raise TemplateExecutorError("files error: {}".
|
|
|
|
format(str(error)))
|
|
|
|
format(str(error)))
|
|
|
|
return
|
|
|
|
elif self.target_type == DIR:
|
|
|
|
else:
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
elif self.target_type == FILE:
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
raise TemplateTypeConflict("The target file is a directory"
|
|
|
|
raise TemplateTypeConflict("The target file is a directory"
|
|
|
|
" while the template is a file.")
|
|
|
|
" while the template is a file.")
|
|
|
|
|
|
|
|
|
|
|
@ -315,7 +316,20 @@ class TemplateWrapper:
|
|
|
|
if self.target_type != FILE:
|
|
|
|
if self.target_type != FILE:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
print("Looking for ._cfg files...")
|
|
|
|
# Проверим, является ли файл защищенным.
|
|
|
|
|
|
|
|
# Сначала проверяем по переменной CONFIG_PROTECT.
|
|
|
|
|
|
|
|
for protected_path in self._protected_set:
|
|
|
|
|
|
|
|
if self.target_path.startswith(protected_path):
|
|
|
|
|
|
|
|
self.protected = True
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
# Затем по переменной CONFIG_PROTECT_MASK.
|
|
|
|
|
|
|
|
for unprotected_path in self._unprotected_set:
|
|
|
|
|
|
|
|
if self.target_path.startswith(unprotected_path):
|
|
|
|
|
|
|
|
self.protected = False
|
|
|
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print('Is protected:', self.protected)
|
|
|
|
|
|
|
|
|
|
|
|
# Собираем список имеющихся ._cfg файлов.
|
|
|
|
# Собираем список имеющихся ._cfg файлов.
|
|
|
|
cfg_pattern = os.path.join(os.path.dirname(self.target_path),
|
|
|
|
cfg_pattern = os.path.join(os.path.dirname(self.target_path),
|
|
|
|
"._cfg????_{}".format(
|
|
|
|
"._cfg????_{}".format(
|
|
|
@ -325,12 +339,13 @@ class TemplateWrapper:
|
|
|
|
# Путь к архивной версии файла.
|
|
|
|
# Путь к архивной версии файла.
|
|
|
|
self.archive_path = self._get_archive_path(self.target_path)
|
|
|
|
self.archive_path = self._get_archive_path(self.target_path)
|
|
|
|
|
|
|
|
|
|
|
|
if self.parameters.unbound:
|
|
|
|
if not self.protected:
|
|
|
|
|
|
|
|
self.md5_matching = True
|
|
|
|
|
|
|
|
elif self.parameters.unbound:
|
|
|
|
# Если присутствует unbound, то просто модифицируем файл и
|
|
|
|
# Если присутствует unbound, то просто модифицируем файл и
|
|
|
|
# удаляем его из CONTENTS.
|
|
|
|
# удаляем его из CONTENTS.
|
|
|
|
self.md5_matching = True
|
|
|
|
self.md5_matching = True
|
|
|
|
elif self.target_type is None:
|
|
|
|
elif self.target_type is None:
|
|
|
|
print("There is no files in target path...")
|
|
|
|
|
|
|
|
# Если целевой файл отсутствует.
|
|
|
|
# Если целевой файл отсутствует.
|
|
|
|
if self.target_path in self.target_package:
|
|
|
|
if self.target_path in self.target_package:
|
|
|
|
# Проверка -- был ли файл удален.
|
|
|
|
# Проверка -- был ли файл удален.
|
|
|
@ -338,14 +353,12 @@ class TemplateWrapper:
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
self.md5_matching = True
|
|
|
|
self.md5_matching = True
|
|
|
|
elif self.target_without_package:
|
|
|
|
elif self.target_without_package:
|
|
|
|
print("There is file without package in target path...")
|
|
|
|
|
|
|
|
# Если файл по целевому пути не относится к какому-либо пакету.
|
|
|
|
# Если файл по целевому пути не относится к какому-либо пакету.
|
|
|
|
if self.parameters.unbound:
|
|
|
|
if self.parameters.unbound:
|
|
|
|
self.md5_matching = True
|
|
|
|
self.md5_matching = True
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
self.md5_matching = False
|
|
|
|
self.md5_matching = False
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
print("Check md5 hash...")
|
|
|
|
|
|
|
|
# Если файл есть и он относится к текущему пакету.
|
|
|
|
# Если файл есть и он относится к текущему пакету.
|
|
|
|
target_md5 = self.target_package.get_md5(self.target_path)
|
|
|
|
target_md5 = self.target_package.get_md5(self.target_path)
|
|
|
|
self.md5_matching = self.target_package.is_md5_equal(
|
|
|
|
self.md5_matching = self.target_package.is_md5_equal(
|
|
|
@ -361,7 +374,6 @@ class TemplateWrapper:
|
|
|
|
|
|
|
|
|
|
|
|
# Определяем путей входных и выходных файлов.
|
|
|
|
# Определяем путей входных и выходных файлов.
|
|
|
|
if self.md5_matching:
|
|
|
|
if self.md5_matching:
|
|
|
|
print("md5 matches")
|
|
|
|
|
|
|
|
# Приоритет отдаем пути из параметра source.
|
|
|
|
# Приоритет отдаем пути из параметра source.
|
|
|
|
if self.parameters.source:
|
|
|
|
if self.parameters.source:
|
|
|
|
self.input_path = self.parameters.source
|
|
|
|
self.input_path = self.parameters.source
|
|
|
@ -370,7 +382,6 @@ class TemplateWrapper:
|
|
|
|
|
|
|
|
|
|
|
|
self.output_path = self.target_path
|
|
|
|
self.output_path = self.target_path
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
print("md5 does not match")
|
|
|
|
|
|
|
|
# Приоритет отдаем пути из параметра source.
|
|
|
|
# Приоритет отдаем пути из параметра source.
|
|
|
|
if self.parameters.source:
|
|
|
|
if self.parameters.source:
|
|
|
|
self.input_path = self.parameters.source
|
|
|
|
self.input_path = self.parameters.source
|
|
|
@ -380,13 +391,13 @@ class TemplateWrapper:
|
|
|
|
self.output_path = self._get_cfg_path(self.target_path)
|
|
|
|
self.output_path = self._get_cfg_path(self.target_path)
|
|
|
|
|
|
|
|
|
|
|
|
def _get_archive_path(self, file_path):
|
|
|
|
def _get_archive_path(self, file_path):
|
|
|
|
print("Getting archive path...")
|
|
|
|
'''Метод для получения пути к архивной версии указанного файла.'''
|
|
|
|
if self.chroot_path != "/" and file_path.startswith(self.chroot_path):
|
|
|
|
if self.chroot_path != "/" and file_path.startswith(self.chroot_path):
|
|
|
|
file_path = file_path[len(self.chroot_path):]
|
|
|
|
file_path = file_path[len(self.chroot_path):]
|
|
|
|
return join_paths(self.config_archive_path, file_path)
|
|
|
|
return join_paths(self.config_archive_path, file_path)
|
|
|
|
|
|
|
|
|
|
|
|
def _get_cfg_path(self, file_path):
|
|
|
|
def _get_cfg_path(self, file_path):
|
|
|
|
print("Getting ._cfg path...")
|
|
|
|
'''Метод для получения пути для создания нового ._cfg????_ файла.'''
|
|
|
|
if self.cfg_list:
|
|
|
|
if self.cfg_list:
|
|
|
|
last_cfg_name = os.path.basename(self.cfg_list[-1])
|
|
|
|
last_cfg_name = os.path.basename(self.cfg_list[-1])
|
|
|
|
|
|
|
|
|
|
|
@ -406,9 +417,20 @@ class TemplateWrapper:
|
|
|
|
return new_cfg_path
|
|
|
|
return new_cfg_path
|
|
|
|
|
|
|
|
|
|
|
|
def remove_from_contents(self):
|
|
|
|
def remove_from_contents(self):
|
|
|
|
self.target_package.remove_file(self.target_path)
|
|
|
|
'''Метод для удаления целевого файла из CONTENTS.'''
|
|
|
|
|
|
|
|
if self.template_type == DIR:
|
|
|
|
|
|
|
|
self.target_package.remove_dir(self.target_path)
|
|
|
|
|
|
|
|
elif self.template_type == FILE:
|
|
|
|
|
|
|
|
self.target_package.remove_obj(self.target_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def clear_dir_contents(self):
|
|
|
|
|
|
|
|
'''Метод для удаления из CONTENTS всего содержимого директории после
|
|
|
|
|
|
|
|
применения append = "clear".'''
|
|
|
|
|
|
|
|
if self.template_type == DIR:
|
|
|
|
|
|
|
|
self.target_package.clear_dir(self.target_path)
|
|
|
|
|
|
|
|
|
|
|
|
def add_to_contents(self, file_md5=None):
|
|
|
|
def add_to_contents(self, file_md5=None):
|
|
|
|
|
|
|
|
'''Метод для добавления целевого файла в CONTENTS.'''
|
|
|
|
if self.parameters.append == 'link':
|
|
|
|
if self.parameters.append == 'link':
|
|
|
|
self.target_package.add_sym(target_path, self.parameters.source)
|
|
|
|
self.target_package.add_sym(target_path, self.parameters.source)
|
|
|
|
elif self.template_type == DIR:
|
|
|
|
elif self.template_type == DIR:
|
|
|
@ -418,23 +440,32 @@ class TemplateWrapper:
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
@classmethod
|
|
|
|
def _set_protected(cls):
|
|
|
|
def _set_protected(cls):
|
|
|
|
|
|
|
|
'''Метод для получения множества защищенных директорий.'''
|
|
|
|
if cls._protected_is_set:
|
|
|
|
if cls._protected_is_set:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
cls._protected_set = set()
|
|
|
|
|
|
|
|
cls._protected_set.add(join_paths(cls.chroot_path, '/etc'))
|
|
|
|
|
|
|
|
|
|
|
|
config_protect_env = os.environ.get('CONFIG_PROTECT', False)
|
|
|
|
config_protect_env = os.environ.get('CONFIG_PROTECT', False)
|
|
|
|
if config_protect_env:
|
|
|
|
if config_protect_env:
|
|
|
|
for protected_path in config_protect_env.split():
|
|
|
|
for protected_path in config_protect_env.split():
|
|
|
|
cls._protected_set.add(protected_path.strip())
|
|
|
|
protected_path = join_paths(cls.chroot_path,
|
|
|
|
|
|
|
|
protected_path.strip())
|
|
|
|
|
|
|
|
cls._protected_set.add(protected_path)
|
|
|
|
|
|
|
|
|
|
|
|
config_protect_mask_env = os.environ.get('CONFIG_PROTECT_MASK', False)
|
|
|
|
config_protect_mask_env = os.environ.get('CONFIG_PROTECT_MASK', False)
|
|
|
|
if config_protect_mask_env:
|
|
|
|
if config_protect_mask_env:
|
|
|
|
for unprotected_path in config_protect_mask_env.split():
|
|
|
|
for unprotected_path in config_protect_mask_env.split():
|
|
|
|
cls._unprotected_set.add(protected_path.strip())
|
|
|
|
unprotected_path = join_paths(cls.chroot_path,
|
|
|
|
|
|
|
|
unprotected_path.strip())
|
|
|
|
|
|
|
|
cls._unprotected_set.add(unprotected_path)
|
|
|
|
|
|
|
|
|
|
|
|
cls._protected_is_set = True
|
|
|
|
cls._protected_is_set = True
|
|
|
|
|
|
|
|
|
|
|
|
def save_changes(self):
|
|
|
|
def save_changes(self):
|
|
|
|
|
|
|
|
'''Метод для сохранения изменений внесенных в CONTENTS.'''
|
|
|
|
if self.target_package and not self.parameters.unbound:
|
|
|
|
if self.target_package and not self.parameters.unbound:
|
|
|
|
|
|
|
|
self.target_package.remove_empty_directories()
|
|
|
|
self.target_package.write_contents_file()
|
|
|
|
self.target_package.write_contents_file()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -453,7 +484,10 @@ class TemplateExecutor:
|
|
|
|
|
|
|
|
|
|
|
|
self.directory_appends = {'join': self._append_join_directory,
|
|
|
|
self.directory_appends = {'join': self._append_join_directory,
|
|
|
|
'remove': self._append_remove_directory,
|
|
|
|
'remove': self._append_remove_directory,
|
|
|
|
'clear': self._append_clear_directory}
|
|
|
|
'skip': self._append_skip_directory,
|
|
|
|
|
|
|
|
'clear': self._append_clear_directory,
|
|
|
|
|
|
|
|
'link': self._append_link_directory,
|
|
|
|
|
|
|
|
'replace': self._append_replace_directory}
|
|
|
|
|
|
|
|
|
|
|
|
self.file_appends = {'join': self._append_join_file}
|
|
|
|
self.file_appends = {'join': self._append_join_file}
|
|
|
|
|
|
|
|
|
|
|
@ -467,6 +501,7 @@ class TemplateExecutor:
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
@property
|
|
|
|
def available_appends(self):
|
|
|
|
def available_appends(self):
|
|
|
|
|
|
|
|
'''Метод для получения множества возможных значений append.'''
|
|
|
|
appends_set = set(self.directory_appends.keys()).union(
|
|
|
|
appends_set = set(self.directory_appends.keys()).union(
|
|
|
|
set(self.file_appends.keys()))
|
|
|
|
set(self.file_appends.keys()))
|
|
|
|
|
|
|
|
|
|
|
@ -474,25 +509,18 @@ class TemplateExecutor:
|
|
|
|
|
|
|
|
|
|
|
|
def execute_template(self, target_path, parameters, template_type,
|
|
|
|
def execute_template(self, target_path, parameters, template_type,
|
|
|
|
template_text=''):
|
|
|
|
template_text=''):
|
|
|
|
print('Template parameters:')
|
|
|
|
'''Метод для запуска выполнения шаблонов.'''
|
|
|
|
parameters.print_parameters_for_debug()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
template_object = TemplateWrapper(target_path, parameters,
|
|
|
|
template_object = TemplateWrapper(target_path, parameters,
|
|
|
|
template_type,
|
|
|
|
template_type,
|
|
|
|
template_text=template_text)
|
|
|
|
template_text=template_text)
|
|
|
|
except TemplateTypeConflict as error:
|
|
|
|
except TemplateTypeConflict as error:
|
|
|
|
print('type conflict: {}'.format(str(error)))
|
|
|
|
|
|
|
|
return
|
|
|
|
return
|
|
|
|
except TemplateCollisionError as error:
|
|
|
|
except TemplateCollisionError as error:
|
|
|
|
print('collision: {}'.format(str(error)))
|
|
|
|
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
# Temporary
|
|
|
|
# Удаляем оригинал, если это необходимо из-за наличия force или по
|
|
|
|
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.remove_original:
|
|
|
|
if template_object.target_type == DIR:
|
|
|
|
if template_object.target_type == DIR:
|
|
|
|
self._remove_directory(template_object.target_path)
|
|
|
|
self._remove_directory(template_object.target_path)
|
|
|
@ -500,48 +528,87 @@ class TemplateExecutor:
|
|
|
|
self._remove_file(template_object.target_path)
|
|
|
|
self._remove_file(template_object.target_path)
|
|
|
|
template_object.target_type = None
|
|
|
|
template_object.target_type = None
|
|
|
|
|
|
|
|
|
|
|
|
# Добавить поддержку run, execute и т.д.
|
|
|
|
# (!) Добавить поддержку run, execute и т.д.
|
|
|
|
if template_object.template_type == DIR:
|
|
|
|
if template_object.template_type == DIR:
|
|
|
|
self.directory_appends[template_object.parameters.append](
|
|
|
|
self.directory_appends[template_object.parameters.append](
|
|
|
|
template_object)
|
|
|
|
template_object)
|
|
|
|
elif template_object.template_type == FILE:
|
|
|
|
elif template_object.template_type == FILE:
|
|
|
|
self.file_appends[template_object.parameters.append](
|
|
|
|
self.file_appends[template_object.parameters.append](
|
|
|
|
template_object)
|
|
|
|
template_object)
|
|
|
|
|
|
|
|
# Сохраняем изменения в CONTENTS внесенные согласно шаблону.
|
|
|
|
template_object.save_changes()
|
|
|
|
template_object.save_changes()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Возвращаем целевой путь, если он был изменен.
|
|
|
|
|
|
|
|
if template_object.target_path_is_changed:
|
|
|
|
|
|
|
|
return template_object.target_path
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
def save_changes(self):
|
|
|
|
def save_changes(self):
|
|
|
|
|
|
|
|
'''Метод для сохранения чего-нибудь после выполнения всех шаблонов.'''
|
|
|
|
|
|
|
|
# Пока сохраняем только получившееся содержимое config-файла.
|
|
|
|
self.calculate_config_file.save_changes()
|
|
|
|
self.calculate_config_file.save_changes()
|
|
|
|
|
|
|
|
|
|
|
|
def _append_join_directory(self, template_object: TemplateWrapper):
|
|
|
|
def _append_join_directory(self, template_object: TemplateWrapper):
|
|
|
|
|
|
|
|
'''Метод описывающий действия для append = "join", если шаблон --
|
|
|
|
|
|
|
|
директория. Создает директорию, если ее нет.'''
|
|
|
|
if template_object.target_type is None:
|
|
|
|
if template_object.target_type is None:
|
|
|
|
self._create_directory(template_object)
|
|
|
|
self._create_directory(template_object)
|
|
|
|
|
|
|
|
|
|
|
|
template_object.add_to_contents()
|
|
|
|
template_object.add_to_contents()
|
|
|
|
else:
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _append_remove_directory(self, template_object: TemplateWrapper):
|
|
|
|
def _append_remove_directory(self, template_object: TemplateWrapper):
|
|
|
|
|
|
|
|
'''Метод описывающий действия для append = "remove", если шаблон --
|
|
|
|
|
|
|
|
директория. Удаляет директорию со всем содержимым, если она есть.'''
|
|
|
|
if template_object.target_type is not None:
|
|
|
|
if template_object.target_type is not None:
|
|
|
|
self._remove_directory(template_object.target_path)
|
|
|
|
self._remove_directory(template_object.target_path)
|
|
|
|
|
|
|
|
|
|
|
|
template_object.remove_from_contents()
|
|
|
|
template_object.remove_from_contents()
|
|
|
|
else:
|
|
|
|
|
|
|
|
pass
|
|
|
|
def _append_skip_directory(self, template_object: TemplateWrapper):
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def _append_clear_directory(self, template_object: TemplateWrapper):
|
|
|
|
def _append_clear_directory(self, template_object: TemplateWrapper):
|
|
|
|
|
|
|
|
'''Метод описывающий действия для append = "clear", если шаблон --
|
|
|
|
|
|
|
|
директория. Удаляет все содержимое директории, если она есть.'''
|
|
|
|
if template_object.target_type is not None:
|
|
|
|
if template_object.target_type is not None:
|
|
|
|
# Подумать об организации очистки CONTENTS для этого append.
|
|
|
|
self._clear_directory(template_object.target_path)
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
template_object.clear_dir_contents()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _append_link_directory(self, template_object: TemplateWrapper):
|
|
|
|
|
|
|
|
'''Метод описывающий действия для append = "link", если шаблон --
|
|
|
|
|
|
|
|
директория. Создает ссылку на директорию, если она есть.'''
|
|
|
|
|
|
|
|
target = template_object.parameters.source
|
|
|
|
|
|
|
|
link_path = template_object.target_path
|
|
|
|
|
|
|
|
self._link_directory(link_path, target)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template_object.add_to_contents()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _append_replace_directory(self, template_object: TemplateWrapper):
|
|
|
|
|
|
|
|
'''Метод описывающий действия для append = "replace", если шаблон --
|
|
|
|
|
|
|
|
директория. Очищает директорию или создает, если ее нет.'''
|
|
|
|
|
|
|
|
if template_object.target_type is None:
|
|
|
|
|
|
|
|
self._create_directory(template_object)
|
|
|
|
|
|
|
|
template_object.add_to_contents()
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
self._clear_directory(template_object.target_path)
|
|
|
|
|
|
|
|
template_object.clear_dir_contents()
|
|
|
|
|
|
|
|
|
|
|
|
def _append_join_file(self, template_object: TemplateWrapper):
|
|
|
|
def _append_join_file(self, template_object: TemplateWrapper):
|
|
|
|
'''Метод описывающий действия при append = "join".'''
|
|
|
|
'''Метод описывающий действия при append = "join", если шаблон --
|
|
|
|
|
|
|
|
файл. Объединяет шаблон с целевым файлом.'''
|
|
|
|
input_path = template_object.input_path
|
|
|
|
input_path = template_object.input_path
|
|
|
|
output_path = template_object.output_path
|
|
|
|
output_path = template_object.output_path
|
|
|
|
|
|
|
|
|
|
|
|
template_format = template_object.format_class
|
|
|
|
template_format = template_object.format_class
|
|
|
|
|
|
|
|
|
|
|
|
if template_object.md5_matching:
|
|
|
|
if template_object.md5_matching:
|
|
|
|
|
|
|
|
# Действия при совпадении md5 из CONTENTS и md5 целевого файла.
|
|
|
|
output_paths = [output_path]
|
|
|
|
output_paths = [output_path]
|
|
|
|
# Проверка на предмет userspace.
|
|
|
|
|
|
|
|
if not template_object.is_userspace:
|
|
|
|
# Если целевой файл защищен, а шаблон не userspace.
|
|
|
|
|
|
|
|
if template_object.protected and not template_object.is_userspace:
|
|
|
|
output_paths.append(template_object.archive_path)
|
|
|
|
output_paths.append(template_object.archive_path)
|
|
|
|
|
|
|
|
|
|
|
|
if template_object.target_type is not None:
|
|
|
|
if template_object.target_type is not None:
|
|
|
@ -565,6 +632,16 @@ class TemplateExecutor:
|
|
|
|
with open(save_path, 'w') as output_file:
|
|
|
|
with open(save_path, 'w') as output_file:
|
|
|
|
output_file.write(output_text)
|
|
|
|
output_file.write(output_text)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if template_object.parameters.chown:
|
|
|
|
|
|
|
|
self.chown_file(save_path,
|
|
|
|
|
|
|
|
template_object.parameters.chown,
|
|
|
|
|
|
|
|
check_existation=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if template_object.parameters.chmod:
|
|
|
|
|
|
|
|
self.chmod_file(save_path,
|
|
|
|
|
|
|
|
template_object.parameters.chmod,
|
|
|
|
|
|
|
|
check_existation=False)
|
|
|
|
|
|
|
|
|
|
|
|
# Убираем все ._cfg файлы.
|
|
|
|
# Убираем все ._cfg файлы.
|
|
|
|
if template_object.cfg_list:
|
|
|
|
if template_object.cfg_list:
|
|
|
|
for cfg_file_path in template_object.cfg_list:
|
|
|
|
for cfg_file_path in template_object.cfg_list:
|
|
|
@ -574,10 +651,11 @@ class TemplateExecutor:
|
|
|
|
self.calculate_config_file.remove_file(template_object.target_path)
|
|
|
|
self.calculate_config_file.remove_file(template_object.target_path)
|
|
|
|
|
|
|
|
|
|
|
|
# Обновляем CONTENTS.
|
|
|
|
# Обновляем CONTENTS.
|
|
|
|
if template_object.parameters.unbound:
|
|
|
|
if template_object.protected:
|
|
|
|
template_object.remove_from_contents()
|
|
|
|
if template_object.parameters.unbound:
|
|
|
|
else:
|
|
|
|
template_object.remove_from_contents()
|
|
|
|
template_object.add_to_contents(file_md5=output_text_md5)
|
|
|
|
else:
|
|
|
|
|
|
|
|
template_object.add_to_contents(file_md5=output_text_md5)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
with open(input_path, 'r') as input_file:
|
|
|
|
with open(input_path, 'r') as input_file:
|
|
|
|
input_text = input_file.read()
|
|
|
|
input_text = input_file.read()
|
|
|
@ -594,23 +672,32 @@ class TemplateExecutor:
|
|
|
|
|
|
|
|
|
|
|
|
if not self.calculate_config_file.compare_md5(target_path,
|
|
|
|
if not self.calculate_config_file.compare_md5(target_path,
|
|
|
|
output_text_md5):
|
|
|
|
output_text_md5):
|
|
|
|
print("cl is different, create ._cfg")
|
|
|
|
|
|
|
|
with open(output_path, 'w') as output_file:
|
|
|
|
with open(output_path, 'w') as output_file:
|
|
|
|
output_file.write(output_text)
|
|
|
|
output_file.write(output_text)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if template_object.parameters.chown:
|
|
|
|
|
|
|
|
self.chown_file(output_path,
|
|
|
|
|
|
|
|
template_object.parameters.chown,
|
|
|
|
|
|
|
|
check_existation=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if template_object.parameters.chmod:
|
|
|
|
|
|
|
|
self.chmod_file(output_file,
|
|
|
|
|
|
|
|
template_object.parameters.chmod,
|
|
|
|
|
|
|
|
check_existation=False)
|
|
|
|
|
|
|
|
|
|
|
|
self.calculate_config_file.set_files_md5(
|
|
|
|
self.calculate_config_file.set_files_md5(
|
|
|
|
template_object.target_path,
|
|
|
|
template_object.target_path,
|
|
|
|
output_text_md5)
|
|
|
|
output_text_md5)
|
|
|
|
print("current config: ",
|
|
|
|
|
|
|
|
self.calculate_config_file._config_dictionary)
|
|
|
|
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
# Действия если CL совпало. Пока ничего не делаем.
|
|
|
|
# Действия если CL совпало. Пока ничего не делаем.
|
|
|
|
print("cl is similar...")
|
|
|
|
|
|
|
|
pass
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
# Обновляем CONTENTS.
|
|
|
|
# Обновляем CONTENTS.
|
|
|
|
template_object.add_to_contents(file_md5=output_text_md5)
|
|
|
|
template_object.add_to_contents(file_md5=output_text_md5)
|
|
|
|
|
|
|
|
|
|
|
|
def _create_directory(self, template_object: TemplateWrapper):
|
|
|
|
def _create_directory(self, template_object: TemplateWrapper):
|
|
|
|
|
|
|
|
'''Метод для создания директории и, при необходимости, изменения
|
|
|
|
|
|
|
|
владельца и доступа все директорий на пути к целевой.'''
|
|
|
|
target_path = template_object.target_path
|
|
|
|
target_path = template_object.target_path
|
|
|
|
template_parameters = template_object.parameters
|
|
|
|
template_parameters = template_object.parameters
|
|
|
|
|
|
|
|
|
|
|
@ -655,7 +742,7 @@ class TemplateExecutor:
|
|
|
|
|
|
|
|
|
|
|
|
if (template_parameters.chown and
|
|
|
|
if (template_parameters.chown and
|
|
|
|
template_parameters.chown != current_owner):
|
|
|
|
template_parameters.chown != current_owner):
|
|
|
|
self.chown_directory
|
|
|
|
self.chown_directory(create_path)
|
|
|
|
elif 'chown' in self.directory_default_parameters:
|
|
|
|
elif 'chown' in self.directory_default_parameters:
|
|
|
|
self.chown_directory(
|
|
|
|
self.chown_directory(
|
|
|
|
create_path,
|
|
|
|
create_path,
|
|
|
@ -667,6 +754,7 @@ class TemplateExecutor:
|
|
|
|
format(create_path, str(error)))
|
|
|
|
format(create_path, str(error)))
|
|
|
|
|
|
|
|
|
|
|
|
def _remove_directory(self, target_path):
|
|
|
|
def _remove_directory(self, target_path):
|
|
|
|
|
|
|
|
'''Метод для удаления директории.'''
|
|
|
|
if os.path.exists(target_path):
|
|
|
|
if os.path.exists(target_path):
|
|
|
|
if os.path.isdir(target_path):
|
|
|
|
if os.path.isdir(target_path):
|
|
|
|
try:
|
|
|
|
try:
|
|
|
@ -689,6 +777,7 @@ class TemplateExecutor:
|
|
|
|
error_message))
|
|
|
|
error_message))
|
|
|
|
|
|
|
|
|
|
|
|
def _clear_directory(self, target_path):
|
|
|
|
def _clear_directory(self, target_path):
|
|
|
|
|
|
|
|
'''Метод для очистки содержимого целевой директории.'''
|
|
|
|
if os.path.exists(target_path):
|
|
|
|
if os.path.exists(target_path):
|
|
|
|
if os.path.isdir(target_path):
|
|
|
|
if os.path.isdir(target_path):
|
|
|
|
for node in os.scandir(target_path):
|
|
|
|
for node in os.scandir(target_path):
|
|
|
@ -706,18 +795,16 @@ class TemplateExecutor:
|
|
|
|
error_message))
|
|
|
|
error_message))
|
|
|
|
|
|
|
|
|
|
|
|
def _link_directory(self, target_path, source):
|
|
|
|
def _link_directory(self, target_path, source):
|
|
|
|
|
|
|
|
'''Метод для создания по целевому пути ссылки на директорию
|
|
|
|
|
|
|
|
расположенную на пути, указанному в source.'''
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
os.symlink(source, target_path, target_is_directory=True)
|
|
|
|
os.symlink(source, target_path, target_is_directory=True)
|
|
|
|
print('linked: {0} -> {1}'.format(os.path.basename(target_path),
|
|
|
|
|
|
|
|
os.path.basename(source)))
|
|
|
|
|
|
|
|
except OSError:
|
|
|
|
except OSError:
|
|
|
|
raise TemplateExecutorError("Failed to create symlink: {0} -> {1}".
|
|
|
|
raise TemplateExecutorError("Failed to create symlink: {0} -> {1}".
|
|
|
|
format(target_path, self.source))
|
|
|
|
format(target_path, self.source))
|
|
|
|
|
|
|
|
|
|
|
|
def _execute_template(self, template_object):
|
|
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _remove_file(self, target_path):
|
|
|
|
def _remove_file(self, target_path):
|
|
|
|
|
|
|
|
'''Метод для удаления файлов.'''
|
|
|
|
if os.path.islink(target_path):
|
|
|
|
if os.path.islink(target_path):
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
os.unlink(target_path)
|
|
|
|
os.unlink(target_path)
|
|
|
@ -728,10 +815,11 @@ class TemplateExecutor:
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
os.remove(target_path)
|
|
|
|
os.remove(target_path)
|
|
|
|
except OSError:
|
|
|
|
except OSError:
|
|
|
|
self.output.set_error('failed to delete the file: {}'.
|
|
|
|
raise TemplateExecutorError('failed to delete the file: {}'.
|
|
|
|
format(target_path))
|
|
|
|
format(target_path))
|
|
|
|
|
|
|
|
|
|
|
|
def _clear_file(self, target_path):
|
|
|
|
def _clear_file(self, target_path):
|
|
|
|
|
|
|
|
'''Метод для очистки файлов.'''
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
with open(target_path, 'w') as f:
|
|
|
|
with open(target_path, 'w') as f:
|
|
|
|
f.truncate(0)
|
|
|
|
f.truncate(0)
|
|
|
@ -739,11 +827,18 @@ class TemplateExecutor:
|
|
|
|
raise TemplateExecutorError("failed to clear the file: {}".
|
|
|
|
raise TemplateExecutorError("failed to clear the file: {}".
|
|
|
|
format(target_path))
|
|
|
|
format(target_path))
|
|
|
|
|
|
|
|
|
|
|
|
def _link_file(self, target_path):
|
|
|
|
def _link_file(self, target_path, source):
|
|
|
|
pass
|
|
|
|
'''Метод для создания по целевому пути ссылки на файл расположенный на
|
|
|
|
|
|
|
|
пути, указанному в source.'''
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
os.symlink(source, target_path)
|
|
|
|
|
|
|
|
except OSError:
|
|
|
|
|
|
|
|
raise TemplateExecutorError(
|
|
|
|
|
|
|
|
"Failed to create symlink to the file: {0} -> {1}".
|
|
|
|
|
|
|
|
format(target_path, self.source))
|
|
|
|
|
|
|
|
|
|
|
|
def chown_directory(self, target_path, chown_value={}):
|
|
|
|
def chown_directory(self, target_path, chown_value={}):
|
|
|
|
"""Сменить владельца директории."""
|
|
|
|
"""Метод для смены владельца директории."""
|
|
|
|
if not chown_value:
|
|
|
|
if not chown_value:
|
|
|
|
chown_value = self.template_parameters.chown
|
|
|
|
chown_value = self.template_parameters.chown
|
|
|
|
print('chown value = {}'.format(chown_value))
|
|
|
|
print('chown value = {}'.format(chown_value))
|
|
|
@ -751,47 +846,42 @@ class TemplateExecutor:
|
|
|
|
os.chown(target_path, chown_value['uid'], chown_value['gid'])
|
|
|
|
os.chown(target_path, chown_value['uid'], chown_value['gid'])
|
|
|
|
except (OSError, Exception) as error:
|
|
|
|
except (OSError, Exception) as error:
|
|
|
|
# возможно потребуются дополнительные проверки.
|
|
|
|
# возможно потребуются дополнительные проверки.
|
|
|
|
self.output.set_error('Can not chown directory: {}'.
|
|
|
|
raise TemplateExecutorError(
|
|
|
|
format(target_path))
|
|
|
|
'Can not chown directory: {0}, reason: {1}'.
|
|
|
|
return False
|
|
|
|
format(target_path, str(error)))
|
|
|
|
|
|
|
|
|
|
|
|
def chmod_directory(self, target_path, chmod_value=False):
|
|
|
|
def chmod_directory(self, target_path, chmod_value=False):
|
|
|
|
"""Сменить права доступа к директории."""
|
|
|
|
'''Метод для смены прав доступа к директории.'''
|
|
|
|
if not chmod_value:
|
|
|
|
if not chmod_value:
|
|
|
|
chmod_value = self.template_parameters.chmod
|
|
|
|
chmod_value = self.template_parameters.chmod
|
|
|
|
print('chmod value = {}'.format(chmod_value))
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
os.chmod(target_path, chmod_value)
|
|
|
|
os.chmod(target_path, chmod_value)
|
|
|
|
except (OSError, Exception) as error:
|
|
|
|
except (OSError, Exception) as error:
|
|
|
|
# возможно потребуются дополнительные проверки.
|
|
|
|
# возможно потребуются дополнительные проверки.
|
|
|
|
self.output.set_error('Can not chmod directory: {}'.
|
|
|
|
self.output.set_error('Can not chmod directory: {0}, reason: {1}'.
|
|
|
|
format(target_path))
|
|
|
|
format(target_path, str(error)))
|
|
|
|
self.output.set_error('reason: {}'.format(str(error)))
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def chown_file(self, target_path, check_existation=True):
|
|
|
|
def chown_file(self, target_path, chown_value, check_existation=True):
|
|
|
|
"""Сменить владельца файла."""
|
|
|
|
'''Метод для смены владельца файла.'''
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
if check_existation and not os.path.exists(target_path):
|
|
|
|
if check_existation and not os.path.exists(target_path):
|
|
|
|
open(target_path, 'w').close()
|
|
|
|
open(target_path, 'w').close()
|
|
|
|
os.lchown(target_path, self.chown['uid'], self.chown['gid'])
|
|
|
|
os.lchown(target_path, chown_value['uid'], chown_value['gid'])
|
|
|
|
return True
|
|
|
|
|
|
|
|
except (OSError, Exception) as error:
|
|
|
|
except (OSError, Exception) as error:
|
|
|
|
# возможно потребуются дополнительные проверки.
|
|
|
|
# возможно потребуются дополнительные проверки.
|
|
|
|
self.output.set_error('Can not chown file: {}'.format(target_path))
|
|
|
|
raise TemplateExecutorError('Can not chown file: {0}, reason: {1}'.
|
|
|
|
return False
|
|
|
|
format(target_path, str(error)))
|
|
|
|
|
|
|
|
|
|
|
|
def chmod_file(self, target_path, check_existation=True):
|
|
|
|
def chmod_file(self, target_path, chmod_value, check_existation=True):
|
|
|
|
"""Сменить права доступа к директории."""
|
|
|
|
'''Метод для смены прав доступа к директории.'''
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
if check_existation and not os.path.exists(target_path):
|
|
|
|
if check_existation and not os.path.exists(target_path):
|
|
|
|
open(target_path, 'w').close()
|
|
|
|
open(target_path, 'w').close()
|
|
|
|
os.chmod(target_path, self.chmod)
|
|
|
|
os.chmod(target_path, chmod_value)
|
|
|
|
return True
|
|
|
|
|
|
|
|
except (OSError, Exception) as error:
|
|
|
|
except (OSError, Exception) as error:
|
|
|
|
# возможно потребуются дополнительные проверки.
|
|
|
|
# возможно потребуются дополнительные проверки.
|
|
|
|
self.output.set_error('Can not chmod file: {}'.format(target_path))
|
|
|
|
raise TemplateExecutorError('Can not chmod file: {0}, reason: {1}'.
|
|
|
|
return False
|
|
|
|
format(target_path, str(error)))
|
|
|
|
|
|
|
|
|
|
|
|
def get_file_info(self, path, info='all'):
|
|
|
|
def get_file_info(self, path, info='all'):
|
|
|
|
file_stat = os.stat(path)
|
|
|
|
file_stat = os.stat(path)
|
|
|
|