|
|
|
@ -12,7 +12,7 @@ import glob
|
|
|
|
|
import shutil
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
|
|
template_text = '''{% calculate append = 'join' -%}
|
|
|
|
|
template_text = '''{% calculate append = 'link', source = '/etc/dir/dir_2' -%}
|
|
|
|
|
{% calculate package = 'test-category/test-package', format = 'samba' -%}
|
|
|
|
|
[section one]
|
|
|
|
|
parameter_1 = {{ vars_1.value_1 }}
|
|
|
|
@ -20,10 +20,12 @@ parameter_1 = {{ vars_1.value_1 }}
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
backup_template_text = '''{% calculate append = 'join', format = 'samba',
|
|
|
|
|
autoupdate -%}
|
|
|
|
|
autoupdate, package = 'test-category/test-package' -%}
|
|
|
|
|
[section one]
|
|
|
|
|
parameter_1 = value
|
|
|
|
|
parameter_2 = value_2
|
|
|
|
|
[section two]
|
|
|
|
|
other_parameter = other_value
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
APPENDS_SET = TemplateAction().available_appends
|
|
|
|
@ -56,6 +58,7 @@ class TemplateCollisionError(Exception):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CalculateConfigFile:
|
|
|
|
|
'''Класс для работы с файлом /var/lib/calculate/config.'''
|
|
|
|
|
def __init__(self, cl_config_path='/var/lib/calculate/config',
|
|
|
|
|
cl_chroot_path='/'):
|
|
|
|
|
self.chroot_path = cl_chroot_path
|
|
|
|
@ -71,6 +74,7 @@ class CalculateConfigFile:
|
|
|
|
|
return file_path in self._config_dictionary
|
|
|
|
|
|
|
|
|
|
def _get_cl_config_dictionary(self):
|
|
|
|
|
'''Метод для загрузки словаря файла /var/lib/calculate/config.'''
|
|
|
|
|
config_dictionary = OrderedDict()
|
|
|
|
|
|
|
|
|
|
if os.path.exists(self.cl_config_path):
|
|
|
|
@ -98,17 +102,21 @@ class CalculateConfigFile:
|
|
|
|
|
return config_dictionary
|
|
|
|
|
|
|
|
|
|
def set_files_md5(self, file_path, file_md5):
|
|
|
|
|
'''Метод для установки в config соответствия файла некоторой
|
|
|
|
|
контрольной сумме.'''
|
|
|
|
|
file_path = self._remove_chroot(file_path)
|
|
|
|
|
self._config_dictionary[file_path] = file_md5
|
|
|
|
|
self._unsaved_changes = True
|
|
|
|
|
|
|
|
|
|
def remove_file(self, file_path):
|
|
|
|
|
'''Метод для удаления файла из config.'''
|
|
|
|
|
file_path = self._remove_chroot(file_path)
|
|
|
|
|
if file_path in self._config_dictionary:
|
|
|
|
|
self._config_dictionary.pop(file_path)
|
|
|
|
|
self._unsaved_changes = True
|
|
|
|
|
|
|
|
|
|
def compare_md5(self, file_path, file_md5):
|
|
|
|
|
'''Метод для сравнения хэш-суммы из config и некоторой заданной.'''
|
|
|
|
|
file_path = self._remove_chroot(file_path)
|
|
|
|
|
if file_path in self._config_dictionary:
|
|
|
|
|
return self._config_dictionary[file_path] == file_md5
|
|
|
|
@ -116,6 +124,7 @@ class CalculateConfigFile:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def save_changes(self):
|
|
|
|
|
'''Метод для записи изменений, внессенных в файл config.'''
|
|
|
|
|
if not self._unsaved_changes:
|
|
|
|
|
return
|
|
|
|
|
config_file = write_file(self.cl_config_path)
|
|
|
|
@ -127,6 +136,7 @@ class CalculateConfigFile:
|
|
|
|
|
self._unsaved_changes = False
|
|
|
|
|
|
|
|
|
|
def _remove_chroot(self, file_path):
|
|
|
|
|
'''Метод для удаления корневого пути из указанного пути.'''
|
|
|
|
|
if self.chroot_path != '/' and file_path.startswith(self.chroot_path):
|
|
|
|
|
file_path = file_path[len(self.chroot_path):]
|
|
|
|
|
|
|
|
|
@ -201,7 +211,14 @@ class TemplateWrapper:
|
|
|
|
|
self.target_type = file_type
|
|
|
|
|
break
|
|
|
|
|
self.target_is_link = os.path.islink(target_path)
|
|
|
|
|
# Если установлен параметр mirror и есть параметр source,
|
|
|
|
|
# содержащий несуществующий путь -- удаляем целевой файл.
|
|
|
|
|
if self.parameters.source is True and self.parameters.mirror:
|
|
|
|
|
self.remove_original = True
|
|
|
|
|
else:
|
|
|
|
|
if self.parameters.mirror:
|
|
|
|
|
raise TemplateExecutorError("target file does not exist, while"
|
|
|
|
|
" 'mirror' parameter is set")
|
|
|
|
|
self.target_type = None
|
|
|
|
|
|
|
|
|
|
self.check_conflicts()
|
|
|
|
@ -313,7 +330,7 @@ class TemplateWrapper:
|
|
|
|
|
'''Метод для проверки наличия пользовательских изменений в
|
|
|
|
|
конфигурационных файлах.'''
|
|
|
|
|
# Эта проверка только для файлов.
|
|
|
|
|
if self.target_type != FILE:
|
|
|
|
|
if self.template_type != FILE:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# Проверим, является ли файл защищенным.
|
|
|
|
@ -328,8 +345,6 @@ class TemplateWrapper:
|
|
|
|
|
self.protected = False
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
print('Is protected:', self.protected)
|
|
|
|
|
|
|
|
|
|
# Собираем список имеющихся ._cfg файлов.
|
|
|
|
|
cfg_pattern = os.path.join(os.path.dirname(self.target_path),
|
|
|
|
|
"._cfg????_{}".format(
|
|
|
|
@ -418,9 +433,11 @@ class TemplateWrapper:
|
|
|
|
|
|
|
|
|
|
def remove_from_contents(self):
|
|
|
|
|
'''Метод для удаления целевого файла из CONTENTS.'''
|
|
|
|
|
print('let s remove')
|
|
|
|
|
if self.template_type == DIR:
|
|
|
|
|
self.target_package.remove_dir(self.target_path)
|
|
|
|
|
elif self.template_type == FILE:
|
|
|
|
|
print('remove as file')
|
|
|
|
|
self.target_package.remove_obj(self.target_path)
|
|
|
|
|
|
|
|
|
|
def clear_dir_contents(self):
|
|
|
|
@ -443,6 +460,7 @@ class TemplateWrapper:
|
|
|
|
|
'''Метод для получения множества защищенных директорий.'''
|
|
|
|
|
if cls._protected_is_set:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
cls._protected_set = set()
|
|
|
|
|
cls._protected_set.add(join_paths(cls.chroot_path, '/etc'))
|
|
|
|
|
|
|
|
|
@ -464,7 +482,9 @@ class TemplateWrapper:
|
|
|
|
|
|
|
|
|
|
def save_changes(self):
|
|
|
|
|
'''Метод для сохранения изменений внесенных в CONTENTS.'''
|
|
|
|
|
if self.target_package and not self.parameters.unbound:
|
|
|
|
|
if self.target_package:
|
|
|
|
|
print('saving CONTENTS: {}'.format(
|
|
|
|
|
self.target_package.contents_dictionary.keys()))
|
|
|
|
|
self.target_package.remove_empty_directories()
|
|
|
|
|
self.target_package.write_contents_file()
|
|
|
|
|
|
|
|
|
@ -515,19 +535,31 @@ class TemplateExecutor:
|
|
|
|
|
template_type,
|
|
|
|
|
template_text=template_text)
|
|
|
|
|
except TemplateTypeConflict as error:
|
|
|
|
|
print('Error: {}'.format(str(error)))
|
|
|
|
|
return
|
|
|
|
|
except TemplateCollisionError as error:
|
|
|
|
|
print('Error: {}'.format(str(error)))
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# Удаляем оригинал, если это необходимо из-за наличия force или по
|
|
|
|
|
# другим причинам.
|
|
|
|
|
if template_object.remove_original:
|
|
|
|
|
print('remove original')
|
|
|
|
|
if template_object.target_type == DIR:
|
|
|
|
|
self._remove_directory(template_object.target_path)
|
|
|
|
|
else:
|
|
|
|
|
self._remove_file(template_object.target_path)
|
|
|
|
|
template_object.remove_from_contents()
|
|
|
|
|
# Если был включен mirror, то после удаления файла завершаем
|
|
|
|
|
# выполнение шаблона.
|
|
|
|
|
if template_object.parameters.mirror:
|
|
|
|
|
template_object.save_changes()
|
|
|
|
|
return
|
|
|
|
|
template_object.target_type = None
|
|
|
|
|
|
|
|
|
|
print('input path: {}'.format(template_object.input_path))
|
|
|
|
|
print('output path: {}'.format(template_object.output_path))
|
|
|
|
|
|
|
|
|
|
# (!) Добавить поддержку run, execute и т.д.
|
|
|
|
|
if template_object.template_type == DIR:
|
|
|
|
|
self.directory_appends[template_object.parameters.append](
|
|
|
|
@ -536,9 +568,10 @@ class TemplateExecutor:
|
|
|
|
|
self.file_appends[template_object.parameters.append](
|
|
|
|
|
template_object)
|
|
|
|
|
# Сохраняем изменения в CONTENTS внесенные согласно шаблону.
|
|
|
|
|
print('it is time to save changes')
|
|
|
|
|
template_object.save_changes()
|
|
|
|
|
|
|
|
|
|
# Возвращаем целевой путь, если он был изменен.
|
|
|
|
|
# Возвращаем целевой путь, если он был изменен, или None если не был.
|
|
|
|
|
if template_object.target_path_is_changed:
|
|
|
|
|
return template_object.target_path
|
|
|
|
|
else:
|
|
|
|
@ -650,11 +683,15 @@ class TemplateExecutor:
|
|
|
|
|
# Убираем целевой файл из CL.
|
|
|
|
|
self.calculate_config_file.remove_file(template_object.target_path)
|
|
|
|
|
|
|
|
|
|
print('is contents update is needed')
|
|
|
|
|
# Обновляем CONTENTS.
|
|
|
|
|
if template_object.protected:
|
|
|
|
|
print('needed')
|
|
|
|
|
if template_object.parameters.unbound:
|
|
|
|
|
print('remove')
|
|
|
|
|
template_object.remove_from_contents()
|
|
|
|
|
else:
|
|
|
|
|
print('add')
|
|
|
|
|
template_object.add_to_contents(file_md5=output_text_md5)
|
|
|
|
|
else:
|
|
|
|
|
with open(input_path, 'r') as input_file:
|
|
|
|
@ -692,8 +729,8 @@ class TemplateExecutor:
|
|
|
|
|
# Действия если CL совпало. Пока ничего не делаем.
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
# Обновляем CONTENTS.
|
|
|
|
|
template_object.add_to_contents(file_md5=output_text_md5)
|
|
|
|
|
# Обновляем CONTENTS.
|
|
|
|
|
template_object.add_to_contents(file_md5=output_text_md5)
|
|
|
|
|
|
|
|
|
|
def _create_directory(self, template_object: TemplateWrapper):
|
|
|
|
|
'''Метод для создания директории и, при необходимости, изменения
|
|
|
|
@ -954,6 +991,7 @@ 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)
|
|
|
|
|
template_parameters = template_engine.parameters
|
|
|
|
|