diff --git a/calculate/templates/format/base_format.py b/calculate/templates/format/base_format.py index a813c5e..dbf9413 100644 --- a/calculate/templates/format/base_format.py +++ b/calculate/templates/format/base_format.py @@ -4,6 +4,7 @@ from collections import OrderedDict from jinja2 import Environment, PackageLoader from pprint import pprint from copy import copy +import re try: from lxml.etree.ElementTree import fromstring except ImportError: @@ -16,6 +17,7 @@ class FormatError(Exception): class BaseFormat(): FORMAT = 'none' + CALCULATE_VERSION = None def __init__(self, processing_methods): self._processing_methods = processing_methods @@ -318,7 +320,7 @@ class BaseFormat(): document_text = template.render( document_dictionary=self._document_dictionary ) - return document_text + return '{}{}'.format(self.header, document_text) def _finish_method(self): '''Метод для выполнения заключительных действий парсинга. @@ -338,3 +340,29 @@ class BaseFormat(): другие парсеры не нужно.''' is_match, self._match = self._match, False return is_match + + def _get_header_and_document_text(self, input_text, + template_path, + already_changed=False): + '''Метод для создания заголовка измененного файла и удаления его из + текста исходного файла.''' + header_pattern = (r'^{0}' + r'-' * 79 + r'\n' + + r'{0} Modified by Calculate Utilities [\d\w\.]*\n' + + r'{0} Processed template files:\n' + + r'(?P({0}\s*[/\w\d\-_\.]*\n)+)' + + r'{0}' + r'-' * 79 + r'\n?').format( + self.comment_symbol) + template_paths = [template_path] + if already_changed: + header_regex = re.compile(header_pattern) + parsing_result = header_regex.search(input_text) + template_paths.extend(parsing_result.groupdict()[ + 'template_paths'].strip().split('\n')) + header = ('{0}' + '-' * 79 + '\n' + + '{0} Modified by Calculate Utilities {1}\n' + + '{0} Processed template files:\n' + + '{0} ' + '\n{0} '.join(template_paths) + '\n' + + '{0}' + '-' * 79 + '\n').format(self.comment_symbol, + self.CALCULATE_VERSION) + document_text = re.sub(header_pattern, '', input_text) + return header, document_text diff --git a/calculate/templates/format/bind_format.py b/calculate/templates/format/bind_format.py index 4da7daa..ba7876b 100644 --- a/calculate/templates/format/bind_format.py +++ b/calculate/templates/format/bind_format.py @@ -18,9 +18,14 @@ class BINDFormat(BaseFormat): FORMAT = 'bind' EXECUTABLE = False + comment_symbol = '#' + def __init__(self, document_text: str, + template_path, ignore_comments=False, join_before=False, + add_header=False, + already_changed=False, parameters=ParametersContainer()): processing_methods = [] @@ -33,6 +38,15 @@ class BINDFormat(BaseFormat): self._last_comments_list = [] self._initialize_parser() + if add_header and not ignore_comments: + self.header, document_text = self._get_header_and_document_text( + document_text, + template_path, + already_changed=already_changed) + else: + self.header = '' + + document_text = document_text.strip() if document_text == '': self._document_dictionary = OrderedDict() else: diff --git a/calculate/templates/format/compiz_format.py b/calculate/templates/format/compiz_format.py index 5939f0e..094a610 100644 --- a/calculate/templates/format/compiz_format.py +++ b/calculate/templates/format/compiz_format.py @@ -14,6 +14,8 @@ class CompizFormat(BaseFormat): _initialized = False + comment_symbol = '#' + def __new__(cls, *args, **kwargs): if not cls._initialized: cls._initialize_parser() @@ -78,7 +80,7 @@ class CompizFormat(BaseFormat): + restOfLine.suppress())('parameter_name') cls._comment_line = originalTextFor( - Literal('#') + Literal(cls.comment_symbol) + ZeroOrMore(Word( printables + pyparsing_unicode.alphanums)) diff --git a/calculate/templates/format/contents_format.py b/calculate/templates/format/contents_format.py index cafb93c..3dbfc1b 100644 --- a/calculate/templates/format/contents_format.py +++ b/calculate/templates/format/contents_format.py @@ -13,6 +13,8 @@ class ContentsFormat(BaseFormat): _initialized = False + comment_symbol = '#' + def __new__(cls, *args, **kwargs): '''Метод для инициализации парсеров.''' if not cls._initialized: diff --git a/calculate/templates/format/dovecot_format.py b/calculate/templates/format/dovecot_format.py index 3bf8664..e0a3679 100644 --- a/calculate/templates/format/dovecot_format.py +++ b/calculate/templates/format/dovecot_format.py @@ -17,6 +17,8 @@ class DovecotFormat(BaseFormat): _initialized = False + comment_symbol = '#' + def __new__(cls, *args, **kwargs): if not cls._initialized: cls._initialize_parser() @@ -58,7 +60,7 @@ class DovecotFormat(BaseFormat): action_symbols = (Literal('!') | Literal('-')) cls._comment_line_parser = originalTextFor( - Literal('#') + Literal(cls.comment_symbol) + ZeroOrMore(Word( printables + pyparsing_unicode.alphanums) diff --git a/calculate/templates/format/json_format.py b/calculate/templates/format/json_format.py index a7c9c6a..d8ef6e3 100644 --- a/calculate/templates/format/json_format.py +++ b/calculate/templates/format/json_format.py @@ -10,6 +10,8 @@ class JSONFormat(BaseFormat): FORMAT = 'json' EXECUTABLE = False + comment_symbol = False + def __init__(self, document_text: str, ignore_comments=False, join_before=False, diff --git a/calculate/templates/format/kde_format.py b/calculate/templates/format/kde_format.py index e946e51..68dd361 100644 --- a/calculate/templates/format/kde_format.py +++ b/calculate/templates/format/kde_format.py @@ -14,6 +14,8 @@ class KDEFormat(BaseFormat): _initialized = False + comment_symbol = '#' + def __new__(cls, *args, **kwargs): if not cls._initialized: cls._initialize_parser() @@ -81,9 +83,8 @@ class KDEFormat(BaseFormat): + parameter_name('name') + restOfLine.suppress())('parameter_name') - cls._comment_line = originalTextFor( - Literal('#') + restOfLine - )('comment') + cls._comment_line = originalTextFor(Literal(cls.comment_symbol) + + restOfLine)('comment') cls._initialized = True def _parse_section_line(self, line): diff --git a/calculate/templates/format/kernel_format.py b/calculate/templates/format/kernel_format.py index c9cd342..4cb5901 100644 --- a/calculate/templates/format/kernel_format.py +++ b/calculate/templates/format/kernel_format.py @@ -14,6 +14,8 @@ class KernelFormat(BaseFormat): _initialized = False + comment_symbol = '#' + def __new__(cls, *args, **kwargs): if not cls._initialized: cls._initialize_parser() @@ -64,7 +66,7 @@ class KernelFormat(BaseFormat): + restOfLine.suppress()) cls._comment_line = originalTextFor( - Literal('#').suppress() + Literal(cls.comment_symbol).suppress() + ZeroOrMore(Word(printables + pyparsing_unicode.alphanums)) )('Comment') diff --git a/calculate/templates/format/ldap_format.py b/calculate/templates/format/ldap_format.py index 2ac50a4..29fb0a7 100644 --- a/calculate/templates/format/ldap_format.py +++ b/calculate/templates/format/ldap_format.py @@ -15,6 +15,8 @@ class LDAPFormat(BaseFormat): _initialized = False + comment_symbol = '#' + def __new__(cls, *args, **kwargs): if not cls._initialized: cls._initialize_parser() @@ -61,7 +63,7 @@ class LDAPFormat(BaseFormat): def _initialize_parser(cls): '''Метод для инициализации парсеров.''' cls._comment_line = originalTextFor( - Literal('#') + Literal(cls.comment_symbol) + ZeroOrMore(Word(printables + pyparsing_unicode.alphanums)) )('comment') diff --git a/calculate/templates/format/openrc_format.py b/calculate/templates/format/openrc_format.py index a703e94..f95a62f 100644 --- a/calculate/templates/format/openrc_format.py +++ b/calculate/templates/format/openrc_format.py @@ -14,6 +14,8 @@ class OpenRCFormat(BaseFormat): _initialized = False + comment_symbol = '#' + def __new__(cls, *args, **kwargs): if not cls._initialized: cls._initialize_parser() @@ -60,7 +62,7 @@ class OpenRCFormat(BaseFormat): + restOfLine.suppress()) cls._comment_line = originalTextFor( - Literal('#') + Literal(cls.comment_symbol) + ZeroOrMore(Word(printables + pyparsing_unicode.alphanums)) )('comment') diff --git a/calculate/templates/format/postfix_format.py b/calculate/templates/format/postfix_format.py index 08dfddd..166c54e 100644 --- a/calculate/templates/format/postfix_format.py +++ b/calculate/templates/format/postfix_format.py @@ -14,6 +14,8 @@ class PostfixFormat(BaseFormat): _initialized = False + comment_symbol = '#' + def __new__(cls, *args, **kwargs): if not cls._initialized: cls._initialize_parser() @@ -61,7 +63,7 @@ class PostfixFormat(BaseFormat): )('parameter_name') cls._comment_line = originalTextFor( - Literal('#') + Literal(cls.comment_symbol) + ZeroOrMore(Word(printables + pyparsing_unicode.alphanums)) )('comment') diff --git a/calculate/templates/format/procmail_format.py b/calculate/templates/format/procmail_format.py index 529a1d6..3790ba3 100644 --- a/calculate/templates/format/procmail_format.py +++ b/calculate/templates/format/procmail_format.py @@ -14,6 +14,8 @@ class ProcmailFormat(BaseFormat): _initialized = False + comment_symbol = '#' + def __new__(cls, *args, **kwargs): if not cls._initialized: cls._initialize_parser() @@ -62,7 +64,7 @@ class ProcmailFormat(BaseFormat): + restOfLine.suppress()) cls._comment_line = originalTextFor( - Literal('#') + Literal(cls.comment_symbol) + ZeroOrMore( Word(printables + pyparsing_unicode.alphanums) diff --git a/calculate/templates/format/proftpd_format.py b/calculate/templates/format/proftpd_format.py index a8c96c3..f3822ac 100644 --- a/calculate/templates/format/proftpd_format.py +++ b/calculate/templates/format/proftpd_format.py @@ -21,6 +21,8 @@ class ProFTPDFormat(BaseFormat): _initialized = False + comment_symbol = '#' + def __new__(cls, *args, **kwargs): if not cls._initialized: cls._initialize_parser() @@ -206,7 +208,7 @@ class ProFTPDFormat(BaseFormat): ) cls._comment_line = originalTextFor( - Literal('#') + Literal(cls.comment_symbol) + ZeroOrMore(Word(printables + pyparsing_unicode.alphanums)) )('comment') diff --git a/calculate/templates/format/regex_format.py b/calculate/templates/format/regex_format.py index 135ca05..c7d621b 100644 --- a/calculate/templates/format/regex_format.py +++ b/calculate/templates/format/regex_format.py @@ -15,6 +15,8 @@ class RegexFormat(BaseFormat): EXECUTABLE = False FORMAT_PARAMETERS = {'multiline', 'dotall', 'comment'} + comment_symbol = '#' + def __init__(self, document_text: str, ignore_comments=False, join_before=False, diff --git a/calculate/templates/format/samba_format.py b/calculate/templates/format/samba_format.py index b3febc3..8153545 100644 --- a/calculate/templates/format/samba_format.py +++ b/calculate/templates/format/samba_format.py @@ -13,6 +13,8 @@ class SambaFormat(BaseFormat): _initialized = False + comment_symbol = '#' + def __new__(cls, *args, **kwargs): if not cls._initialized: cls._initialize_parser() @@ -49,7 +51,7 @@ class SambaFormat(BaseFormat): def _initialize_parser(cls): action_symbols = (Literal('!') | Literal('-')) - comment_symbols = (Literal('#') | Literal(';')) + comment_symbols = (Literal(cls.comment_symbol) | Literal(';')) assignment_symbol = Literal('=') diff --git a/calculate/templates/template_processor.py b/calculate/templates/template_processor.py index b25bf90..7faedc5 100644 --- a/calculate/templates/template_processor.py +++ b/calculate/templates/template_processor.py @@ -2,13 +2,14 @@ # from pprint import pprint from ..utils.package import PackageAtomParser, Package, PackageNotFound,\ - PackageAtomName + PackageAtomName, Version from ..utils.files import join_paths, write_file, read_file_lines, FilesError,\ check_directory_link, read_link, Process,\ get_target_from_link from .template_engine import TemplateEngine, Variables, ConditionFailed,\ ParametersProcessor, DIR, FILE,\ ParametersContainer +from .format.base_format import BaseFormat from ..utils.io_module import IOModule from collections import OrderedDict, abc from ..utils.mount import Mounts @@ -23,6 +24,9 @@ import re import os +CALCULATE_VERSION = Version('4.0') + + class TemplateExecutorError(Exception): pass @@ -145,11 +149,13 @@ class TemplateWrapper: def __init__(self, target_file_path, parameters, template_type, + template_path, template_text='', target_package=None, chroot_path='/', config_archive_path='/var/lib/calculate/config-archive'): self.target_path = target_file_path + self.template_path = template_path self.chroot_path = chroot_path self.config_archive_path = config_archive_path @@ -244,13 +250,13 @@ class TemplateWrapper: chroot_path=self.chroot_path) return - self.check_type_conflicts() + self._check_type_conflicts() - self.check_package_collision() + self._check_package_collision() - self.check_user_changes() + self._check_user_changes() - def check_type_conflicts(self): + def _check_type_conflicts(self): '''Метод для проверки конфликтов типов.''' if self.parameters.append == 'link': if self.parameters.force: @@ -322,7 +328,7 @@ class TemplateWrapper: raise TemplateTypeConflict("the target file is a directory" " while the template is a file") - def check_package_collision(self): + def _check_package_collision(self): '''Метод для проверки на предмет коллизии, то есть конфликта пакета шаблона и целевого файла.''' if self.parameters.package: @@ -370,7 +376,7 @@ class TemplateWrapper: self.target_package = Package(self.target_package_name, chroot_path=self.chroot_path) - def check_user_changes(self): + def _check_user_changes(self): '''Метод для проверки наличия пользовательских изменений в конфигурационных файлах.''' # Эта проверка только для файлов. @@ -595,6 +601,10 @@ class TemplateExecutor: self.execute_archive_path = execute_archive_path self.execute_files = OrderedDict() + # Список целевых путей измененных файлов. Нужен для корректиного + # формирования calculate-заголовка. + self.processed_targets = [] + self.directory_default_parameters =\ ParametersProcessor.directory_default_parameters self.file_default_parameters =\ @@ -623,6 +633,7 @@ class TemplateExecutor: cl_config_path=cl_config_path, cl_chroot_path=chroot_path) self.cl_config_archive_path = cl_config_archive + BaseFormat.CALCULATE_VERSION = CALCULATE_VERSION @property def available_appends(self): @@ -633,7 +644,7 @@ class TemplateExecutor: return appends_set def execute_template(self, target_path, parameters, template_type, - template_text='', save_changes=True, + template_path, template_text='', save_changes=True, target_package=None): '''Метод для запуска выполнения шаблонов.''' # Словарь с данными о результате работы исполнительного метода. @@ -641,10 +652,14 @@ class TemplateExecutor: 'stdout': None, 'stderr': None} + if parameters.append == 'skip': + return self.executor_output + try: template_object = TemplateWrapper( target_path, parameters, template_type, + template_path, template_text=template_text, target_package=target_package, chroot_path=self.chroot_path, @@ -659,7 +674,6 @@ class TemplateExecutor: # Удаляем оригинал, если это необходимо из-за наличия force или по # другим причинам. if template_object.remove_original: - print('REMOVE ORIGINAL') if template_object.target_type == DIR: self._remove_directory(template_object.target_path) else: @@ -718,6 +732,30 @@ class TemplateExecutor: # Пока сохраняем только получившееся содержимое config-файла. self.calculate_config_file.save_changes() + def _get_header_and_file_text(self, input_text, target_path, + target_format, template_path): + header_pattern = (r'^{0}' + r'-' * 79 + r'\n' + + r'{0} Modified by Calculate Utilities [\d\w\.]*\n' + + r'{0} Processed template files:\n' + + r'(?P({0}\s*[/\w\d\-_\.]*\n)+)' + + r'{0}' + r'-' * 79 + r'\n?').format( + target_format.comment_symbol) + template_paths = [template_path] + if target_path in self.processed_targets: + header_regex = re.compile(header_pattern) + parsing_result = header_regex.search(input_text) + template_paths.extend(parsing_result.groupdict()[ + 'template_paths'].strip().split('\n')) + else: + self.processed_targets.append(target_path) + header = ('{0}' + '-' * 79 + + '{0} Modified by Calculate Utilities {1}\n' + + '{0} Processsed temlate files:\n' + + '{0}' + '\n{0} '.join + '\n' + + '{0}' + '-' * 79 + '\n').format(target_format.comment_symbol, + CALCULATE_VERSION) + return header, re.sub(header_pattern, '', input_text) + def _append_join_directory(self, template_object: TemplateWrapper): '''Метод описывающий действия для append = "join", если шаблон -- директория. Создает директорию, если ее нет.''' @@ -836,12 +874,19 @@ class TemplateExecutor: input_text = '' parsed_template = template_format(template_object.template_text, + template_object.template_path, ignore_comments=True) if not template_object.format_class.EXECUTABLE: # Если шаблон не исполнительный разбираем входной текст. - parsed_input = template_format(input_text, - join_before=join_before) + parsed_input = template_format( + input_text, + template_object.template_path, + add_header=True, + join_before=join_before, + already_changed=(template_object.target_path + in self.processed_targets), + parameters=template_object.parameters) parsed_input.join_template(parsed_template) # Результат наложения шаблона. output_text = parsed_input.document_text @@ -903,9 +948,15 @@ class TemplateExecutor: else: input_text = '' - parsed_input = template_format(input_text, - join_before=join_before) + parsed_input = template_format( + input_text, + template_object.template_path, + add_header=True, + join_before=join_before, + already_changed=False, + parameters=template_object.parameters) parsed_template = template_format(template_object.template_text, + template_object.template_path, ignore_comments=True) parsed_input.join_template(parsed_template) @@ -1477,9 +1528,12 @@ class DirectoryTree: self._tree = {} def update_tree(self, tree): + '''Метод, инициирующий наложение заданного дерева каталогов на данный + экземпляр дерева.''' self._update(self._tree, tree) def _update(self, original_tree, tree): + '''Метод для рекурсивного наложения одного дерева на другое.''' for parent, child in tree.items(): if isinstance(child, abc.Mapping): original_tree[parent] = self._update(original_tree.get(parent, @@ -1493,9 +1547,13 @@ class DirectoryTree: pprint(self._tree) def get_directory_tree(self, directory): + '''Метод для получения нового дерева из ветви данного дерева, + соответствующей некоторому каталогу, содержащемуся в корне данного + дерева.''' directory_tree = DirectoryTree(os.path.join(self.base_directory, directory)) - directory_tree._tree = self._tree[directory] + if directory in self._tree: + directory_tree._tree = self._tree[directory] return directory_tree def __getitem__(self, name): @@ -1521,8 +1579,7 @@ class DirectoryTree: class DirectoryProcessor: - chmod_regex = re.compile(r'\d{3}') - + '''Класс обработчика директорий шаблонов.''' def __init__(self, action, datavars_module=Variables(), package='', output_module=IOModule()): self.action = action @@ -1536,7 +1593,7 @@ class DirectoryProcessor: else: self.cl_chroot_path = '/' - self.cl_ignore_files = self.get_cl_ignore_files() + self.cl_ignore_files = self._get_cl_ignore_files() # Путь к файлу config с хэш-суммами файлов, для которых уже # предлагались изменения. @@ -1556,6 +1613,8 @@ class DirectoryProcessor: self.cl_config_archive = self._add_chroot_path( '/var/lib/calculate/config-archive') + # Путь к директории .execute для хранения хранения файлов скриптов, + # полученных из шаблонов с параметром exec. if 'cl_exec_dir_path' in datavars_module.main: self.cl_exec_dir_path = self._add_chroot_path( self.datavars_module.main.cl_exec_dir_path) @@ -1574,10 +1633,12 @@ class DirectoryProcessor: # Инициализируем шаблонизатор. self.template_engine = TemplateEngine( - datavars_module=datavars_module, + datavars_module=self.datavars_module, chroot_path=self.cl_chroot_path, appends_set=self.template_executor.available_appends) + # Разбираем atom имя пакета, для которого накладываем шаблоны. + self.for_package = False if package: if isinstance(package, PackageAtomName): self.for_package = package @@ -1586,29 +1647,28 @@ class DirectoryProcessor: self.for_package = self.template_engine.\ parameters_processor.check_package_parameter(package) except ConditionFailed as error: + # ConfitionFailed потому что для проверки значения пакета, + # используется тот же метод, что проверяет параметр package + # в шаблонах, а в них этот параметр играет роль условия. self.output.set_error(str(error)) return - else: - self.for_package = False - else: - self.for_package = False + # Получаем список директорий шаблонов. self.template_paths = (self.datavars_module. main.cl_template_path.split(',')) - self.inheritable_parameters = set( - ParametersProcessor.inheritable_parameters) - + # Список обработанных пакетов. self.processed_packages = [] + # Список пакетов, взятый из значений параметра merge. self.packages_to_merge = [] - self.packages_file_trees = {} - # Список файлов сохраненных в .execute для выполнения после всех - # шаблонов. - self.exec_files = dict() + # Словарь для хранения деревьев директорий для различных пакетов. + self.packages_file_trees = {} - def get_cl_ignore_files(self): + def _get_cl_ignore_files(self): + '''Метод для получения из соответствующей переменной списка паттернов + для обнаружения игнорируемых в ходе обработки шаблонов файлов.''' if 'cl_ignore_files' in self.datavars_module.main: cl_ignore_files = self.datavars_module.main.cl_ignore_files cl_ignore_files_list = [] @@ -1620,6 +1680,8 @@ class DirectoryProcessor: return [] def _add_chroot_path(self, path_to_add: str): + '''Метод для добавления корневого пути к заданному пути, если таковой + задан и отсутствует в заданном пути.''' if (self.cl_chroot_path != '/' and not path_to_add.startswith(self.cl_chroot_path)): return join_paths(self.cl_chroot_path, path_to_add) @@ -1627,14 +1689,11 @@ class DirectoryProcessor: return path_to_add def process_template_directories(self): - # Проходим каталоги из main.cl_template.path - + '''Метод для обхода шаблонов, содержащихся в каталогах из + main.cl_template.path.''' # Режим заполнения очередей директорий пакетов, необходимых для более # быстрой обработки параметра merge. - if self.for_package: - self.fill_trees = True - else: - self.fill_trees = False + self.fill_trees = bool(self.for_package) for directory_path in self.template_paths: self.base_directory = directory_path.strip() @@ -1642,10 +1701,10 @@ class DirectoryProcessor: for node in entries: self.directory_tree = {} - self.walk_directory_tree(node.path, - self.cl_chroot_path, - ParametersContainer(), - directory_tree=self.directory_tree) + self._walk_directory_tree(node.path, + self.cl_chroot_path, + ParametersContainer(), + directory_tree=self.directory_tree) # Теперь когда дерево заполнено, можно выключить этот режим. self.fill_trees = False @@ -1653,9 +1712,11 @@ class DirectoryProcessor: if self.for_package: self.output.set_info('Processing packages from merge parameter...') self.processed_packages.append(self.for_package) - self.merge_packages() + self._merge_packages() - def merge_packages(self): + def _merge_packages(self): + '''Метод для выполнения шаблонов относящихся к пакетам, указанным во + всех встреченных значениях параметра merge.''' not_merged_packages = [] while self.packages_to_merge: @@ -1673,10 +1734,10 @@ class DirectoryProcessor: directory_tree = self.packages_file_trees[self.for_package].\ get_directory_tree(directory_name) - self.walk_directory_tree(directory_tree.base_directory, - self.cl_chroot_path, - ParametersContainer(), - directory_tree=directory_tree) + self._walk_directory_tree(directory_tree.base_directory, + self.cl_chroot_path, + ParametersContainer(), + directory_tree=directory_tree) self.processed_packages.append(self.for_package) @@ -1686,7 +1747,7 @@ class DirectoryProcessor: else: self.output.set_success('All packages are merged...') - def get_directories_queue(self, path): + def _get_directories_queue(self, path): '''Уже не актуальный метод для построение очередей из путей к шаблонам. Хотя возможно еще пригодится.''' directories_queue = [] @@ -1703,120 +1764,53 @@ class DirectoryProcessor: return base_directory, directories_queue - def check_file_name(self, filename: str): - '''Метод для проверки соответствия имени файла содержимому переменной - main.cl_ignore_files.''' - for pattern in self.cl_ignore_files: - if not fnmatch.fnmatch(filename, pattern): - return False - return True - - def walk_directory_tree(self, current_directory_path, target_path, - directory_parameters, directory_tree={}): + def _walk_directory_tree(self, current_directory_path, current_target_path, + directory_parameters, directory_tree={}): '''Метод для рекурсивного обхода директорий с шаблонами, а также, при необходимости, заполнения деревьев директорий шаблонов, с помощью которых далее выполняются шаблоны пакетов из merge.''' print('current_directory: {}'.format(current_directory_path)) - print('fill trees = {}'.format(self.fill_trees)) - template_files = [] - template_directories = [] - directory_name = os.path.basename(current_directory_path) + # Если включено заполнение дерева создаем пустой словарь для сбора + # содержимого текущей директории. if self.fill_trees: directory_tree[directory_name] = {} - current_target_path = target_path - - entries = os.scandir(current_directory_path) self.template_engine.change_directory(current_directory_path) - - for node in entries: - if self.check_file_name(node.name): - continue - - if node.is_symlink(): - self.output.set_warning('symlink: {} is ignored'. - format(node.path)) - continue - elif node.is_dir(): - template_directories.append(node.path) - elif node.is_file(): - template_files.append(node.name) + template_directories, template_files = self._scan_directory( + current_directory_path) # обрабатываем в первую очередь шаблон директории. if '.calculate_directory' in template_files: template_files.remove('.calculate_directory') - - try: - self.template_engine.process_template( - '.calculate_directory', - template_type=DIR, - parameters=directory_parameters) - except ConditionFailed as error: - self.output.set_warning('{}. Template: {}'. - format(str(error), - current_directory_path)) - directory_tree = {} - return - except Exception as error: - self.output.set_error('Template error: {0} Template: {1}'. - format(str(error), - current_directory_path)) + template_text = self._parse_template(directory_parameters, + '.calculate_directory', + DIR, current_directory_path) + if template_text is False: directory_tree = {} return directory_parameters.print_parameters_for_debug() - # Если есть параметр name -- меняем имя текущего каталога. - if directory_parameters.name: - directory_name = directory_parameters.name - - # Если есть параметр path -- меняем текущий путь к целевому - # каталогу. - if directory_parameters.path: - current_target_path = join_paths(self.cl_chroot_path, - directory_parameters.path) - - # В зависимости от того, нужно ли нам заполнять дерево директорий, - # отправляем в метод для проверки параметров package и action - # или текущее дерево, или пустое значение. - if self.fill_trees: - tree_for_checker = directory_tree - else: - tree_for_checker = None - - if self.check_package_and_action(directory_parameters, - current_directory_path, - directory_tree=tree_for_checker): - # Если проверка параметров package и action пройдена и - # и параметр append не равен skip -- обновляем целевой путь - # именем текущей директории. - if not directory_parameters.append == 'skip': - current_target_path = os.path.join(current_target_path, - directory_name) - else: - # Если проверка не пройдена, включено заполнение дерева, а - # метод для проверки заменил для текущей директории значение {} - # на None (являющейся для этого дерева заглушкой), то, + # Корректируем путь к целевой директории. + current_target_path = self._make_target_path(current_target_path, + directory_name, + directory_parameters) + + # Если нужно заполнять дерево директорий, отправляем в метод для + # проверки параметров package и action текущее дерево. + if not self._check_package_and_action( + directory_parameters, + current_directory_path, + directory_tree=(directory_tree if + self.fill_trees else None)): + # Если проверка не пройдена и включено заполнение дерева, то, # используя нынешнее состояние дерева директорий, обновляем # дерево пакета текущего шаблона директории. - if (self.fill_trees and - directory_tree[directory_name] is None): - package_name = directory_parameters.package - if package_name in self.packages_file_trees: - # Если для данного пакета уже есть дерево -- - # накладываем на него текущее. - self.packages_file_trees[package_name].update_tree( - copy.deepcopy(self.directory_tree) - ) - else: - # Если для данного пакета еще нет дерева -- - # копируем для него текущее. - directory_tree = DirectoryTree(self.base_directory) - directory_tree.update_tree( - copy.deepcopy(self.directory_tree)) - self.packages_file_trees[package_name] = directory_tree + if self.fill_trees: + self._update_package_tree(directory_parameters.package, + directory_tree[directory_name]) # Перед выходом из директории очищаем текущий уровень # дерева. directory_tree = {} @@ -1828,238 +1822,119 @@ class DirectoryProcessor: self.packages_to_merge.extend(directory_parameters.merge) else: - # Если .calculate_directory отсутствует -- создаем директорию + # Если .calculate_directory отсутствует -- создаем директорию, # используя унаследованные параметры и имя самой директории. - if self.fill_trees: - tree_for_checker = directory_tree - else: - tree_for_checker = None - if not self.check_package_and_action( - directory_parameters, - current_directory_path, - directory_tree=tree_for_checker): + if not self._check_package_and_action( + directory_parameters, + current_directory_path, + directory_tree=(directory_tree if + self.fill_trees else None)): # Обновляем дерево директорий для данного пакета. - if (directory_tree[directory_name] is None and - self.fill_trees): - package_name = directory_parameters.package - if package_name in self.packages_file_trees: - # Если для данного пакета уже есть дерево -- - # накладываем на него текущее. - self.packages_file_trees[package_name].update_tree( - copy.deepcopy(self.directory_tree) - ) - else: - # Если для данного пакета еще нет дерева -- - # копируем для него текущее. - directory_tree = DirectoryTree(self.base_directory) - directory_tree.update_tree( - copy.deepcopy(self.directory_tree)) - self.packages_file_trees[package_name] = directory_tree - + if self.fill_trees: + self._update_package_tree(directory_parameters.package, + directory_tree[directory_name]) # Перед выходом из директории очищаем текущий уровень # дерева. directory_tree = {} return - # Для того чтобы директория была создана просто добавляем параметр + # Для того чтобы директория была создана, просто добавляем параметр # append = join. directory_parameters.set_parameter({'append': 'join'}) current_target_path = os.path.join(current_target_path, directory_name) - # * * * МОЖНО ВЫДЕЛИТЬ В ОТДЕЛЬНЫЙ МЕТОД * * * # Выполняем наложение шаблона. - try: - output = self.template_executor.execute_template( - current_target_path, - directory_parameters, - DIR) - # Если во время выполнения шаблона был изменен целевой путь, - # например, из-за ссылки на директорию в source -- обновляем - # целевой путь. - if output['target_path'] is not None: - current_target_path = output['target_path'] - - # Если есть вывод от параметра run -- выводим как info. - if output['stdout'] is not None: - self.output.set_info("stdout from template: {}:\n{}\n".format( - current_directory_path, - output['stdout'] - )) - - # Если есть ошибки от параметра run -- выводим их как error. - if output['stderr'] is not None: - self.output.set_error("stderr from template: {}:\n{}\n". - format(current_directory_path, - output['stderr'])) - # Если run выполнен с ошибками -- пропускаем директорию. - return - except TemplateExecutorError as error: - self.output.set_error('Template execution error: {} Template: {}'. - format(str(error), - current_directory_path)) + current_target_path = self._execute_template(current_target_path, + directory_parameters, DIR, + current_directory_path) + if not current_target_path: + directory_tree = {} return - self.output.set_success('Processing directory: {}'. - format(current_directory_path)) - - # * * * МОЖНО ВЫДЕЛИТЬ В ОТДЕЛЬНЫЙ МЕТОД * * * # Далее обрабатываем файлы шаблонов хранящихся в директории. - # Список файлов и директорий для дальнейшего обхода получаем из - # списоков полученных при начальном сканировании директории или, - # если в данный момент обходим дерево директорий, что можно определить - # по выключенному флагу fill_trees и по наличию дерева в переменной - # directory_tree, берем файлы и каталоги для обхода из дерева. + # Если в данный момент обходим дерево -- берем список файлов и + # директорий из него. if not self.fill_trees and directory_tree: - tree_files = [] - tree_directories = [] - - for template in directory_tree: - if template in template_files: - tree_files.append(template) - else: - next_directory_tree =\ - directory_tree.get_directory_tree(template) - tree_directories.append(next_directory_tree) + template_directorie, template_file =\ + self._get_files_and_dirs_from_tree(template_files, + template_directories, + directory_tree) - template_files = tree_files - template_directories = tree_directories + # Просто псевдоним, чтобы меньше путаницы было далее. + template_parameters = directory_parameters # Обрабатываем файлы шаблонов. for template_name in template_files: # Удаляем все параметры, которые не наследуются и используем # полученный контейнер для сбора параметров файлов шаблонов. - directory_parameters.remove_not_inheritable() - + template_parameters.remove_not_inheritable() template_path = os.path.join(current_directory_path, template_name) # Применяем к файлу шаблона шаблонизатор. - try: - self.template_engine.process_template( - template_name, FILE, - parameters=directory_parameters) - except ConditionFailed as error: - self.output.set_warning('{0}. Template: {1}'. - format(str(error), - template_path)) + template_text = self._parse_template(template_parameters, + template_name, + FILE, current_directory_path) + if template_text is False: continue - except Exception as error: - self.output.set_error('Template error: {0} Template: {1}'. - format(str(error), - template_path)) - continue - - directory_parameters.print_parameters_for_debug() - template_text = self.template_engine.template_text + template_parameters.print_parameters_for_debug() # Если находимся на стадии заполнения дерева директорий -- # проверяем параметры package и action с заполнением дерева. - if self.fill_trees: - tree_for_checker = directory_tree[directory_name] - else: - tree_for_checker = None - - # Проверяем параметры action и package. - if not self.check_package_and_action( - directory_parameters, - template_path, - directory_tree=tree_for_checker): + if not self._check_package_and_action( + template_parameters, + template_path, + directory_tree=(directory_tree[directory_name] if + self.fill_trees else None)): continue - # Если есть параметр merge добавляем в список пакетов для - # последующей обработки. - if self.for_package and directory_parameters.merge: - self.packages_to_merge.extend(directory_parameters.merge) - - # Если для шаблона задано имя -- меняем его. - if directory_parameters.name: - template_name = directory_parameters.name + # Если есть параметр merge добавляем его содержимое в список + # пакетов для последующей обработки. + if self.for_package and template_parameters.merge: + self.packages_to_merge.extend(template_parameters.merge) - # Если для шаблона задан путь -- меняем его. - if directory_parameters.path: - target_file_path = join_paths(self.cl_chroot_path, - directory_parameters.path, - template_name) - else: - target_file_path = join_paths(current_target_path, - template_name) + # Корректируем путь к целевому файлу. + target_file_path = self._make_target_path(current_target_path, + template_name, + template_parameters) # Выполняем действия, указанные в шаблоне. - try: - output = self.template_executor.execute_template( + target_file_path = self._execute_template( target_file_path, - directory_parameters, - FILE, + template_parameters, + FILE, template_path, template_text=template_text) - except TemplateExecutorError as error: - self.output.set_error( - 'Template execution error: {0} Template: {1}'. - format(str(error), - template_path)) + if not target_file_path: continue - # Если во время выполнения шаблона был изменен целевой путь, - # например, из-за ссылки на директорию в source -- обновляем - # целевой путь. - if output['target_path'] is not None: - current_target_path = output['target_path'] - - # Если есть вывод от параметра run -- выводим как info. - if output['stdout'] is not None: - self.output.set_info("stdout from template: {}\n{}".format( - current_directory_path, - output['stdout'] - )) - - # Если есть ошибки от параметра run -- выводим их как error - if output['stderr'] is not None: - self.output.set_error("stderr from template: {}\n{}". - format(current_directory_path, - output['stderr'])) - # Если run выполнен с ошибками -- пропускаем директорию. - return - - self.output.set_success('Processed template: {}...'. - format(template_path)) - + # * * * ПРИДУМАТЬ ОПТИМИЗАЦИЮ * * * + # Потому что накладывать дерево каждый раз, когда обнаружены файлы + # какого-то пакета не рационально. # Обновляем дерево директорий для данного пакета, если происходит # его заполнение. - self.output.set_info("Let's update tree using current: {}". - format(directory_tree)) - if (self.fill_trees and directory_tree[directory_name]): - package_name = directory_parameters.package - - if package_name in self.packages_file_trees: - # Если для данного пакета дерево уже есть -- обновляем его. - self.packages_file_trees[package_name].update_tree( - copy.deepcopy(self.directory_tree)) - else: - # Если нет создаем новое. - directory_tree = DirectoryTree(self.base_directory) - directory_tree.update_tree(copy.deepcopy( - self.directory_tree)) - self.packages_file_trees[package_name] = directory_tree - + if self.fill_trees: + self._update_package_tree(template_parameters.package, + directory_tree[directory_name]) directory_tree[directory_name] = {} - # проходимся далее по директориям. + # Проходимся далее по директориям. for directory in template_directories: if self.fill_trees: - self.walk_directory_tree( + self._walk_directory_tree( directory, current_target_path, directory_parameters.get_inheritables(), directory_tree=directory_tree[directory_name]) directory_tree[directory_name] = {} else: if isinstance(directory, DirectoryTree): - # Если директории берем из дерева -- путь к директории - # соответствует корню текущего дерева. + # Если директории взяты из дерева -- путь к директории + # соответствует корню каждой взятой ветви дерева. directory_path = directory.base_directory else: directory_path = directory - self.walk_directory_tree( + self._walk_directory_tree( directory_path, current_target_path, directory_parameters.get_inheritables()) @@ -2068,11 +1943,173 @@ class DirectoryProcessor: directory_tree = {} return - def check_package_and_action(self, parameters, template_path, - directory_tree=None): + def _scan_directory(self, directory_path: str): + '''Метод для получения и фильтрования списка файлов и директорий, + содержащихся в директории шаблонов.''' + template_files = [] + template_directories = [] + + entries = os.scandir(directory_path) + + for node in entries: + if not self._check_file_name(node.name): + continue + + if node.is_symlink(): + self.output.set_warning( + 'symlink: {0} is ignored in the template directory: {1}'. + format(node.path, directory_path)) + continue + elif node.is_dir(): + template_directories.append(node.path) + elif node.is_file(): + template_files.append(node.name) + + return template_directories, template_files + + def _check_file_name(self, filename: str): + '''Метод для проверки соответствия имени файла содержимому переменной + main.cl_ignore_files.''' + for pattern in self.cl_ignore_files: + if fnmatch.fnmatch(filename, pattern): + return False + return True + + def _get_files_and_dirs_from_tree(self, template_files, + template_directories, + directory_tree): + '''Метод для получения списков файлов и директорий из дерева + директорий.''' + tree_files = [] + tree_directories = [] + + for template in directory_tree: + if template in template_files: + tree_files.append(template) + else: + next_directory_tree =\ + directory_tree.get_directory_tree(template) + tree_directories.append(next_directory_tree) + + return tree_directories, tree_files + + def _make_target_path(self, target_path, template_name, + parameters): + '''Метод для получения пути к целевому файлу с учетом наличия + параметров name, path и append = skip.''' + # Если есть параметр name -- меняем имя шаблона. + if parameters.name: + template_name = parameters.name + + # Если для шаблона задан путь -- меняем путь к директории шаблона. + if parameters.path: + target_path = join_paths(self.cl_chroot_path, + parameters.path) + + # Если параметр append не равен skip -- добавляем имя шаблона к + # целевому пути. + if not parameters.append == 'skip': + target_path = os.path.join(target_path, + template_name) + return target_path + + def _parse_template(self, parameters, + template_name, + template_type, + template_directory): + '''Метод для разбора шаблонов, получения значений их параметров и их + текста после отработки шаблонизитора.''' + if template_type == DIR: + template_path = template_directory + else: + template_path = join_paths(template_directory, template_name) + + try: + self.template_engine.process_template(template_name, + template_type, + parameters=parameters) + return self.template_engine.template_text + except ConditionFailed as error: + self.output.set_warning('{0}. Template: {1}'. + format(str(error), + template_path)) + return False + except Exception as error: + self.output.set_error('Template error: {0} Template: {1}'. + format(str(error), + template_path)) + return False + + def _execute_template(self, target_path, + parameters, + template_type, + template_path, + template_text=''): + '''Метод для наложения шаблонов и обработки информации полученной после + наложения.''' + try: + output = self.template_executor.execute_template( + target_path, + parameters, + template_type, + template_path, + template_text=template_text) + # Если во время выполнения шаблона был изменен целевой путь, + # например, из-за ссылки на директорию в source -- обновляем + # целевой путь. + if output['target_path'] is not None: + target_path = output['target_path'] + + # Если есть вывод от параметра run -- выводим как info. + if output['stdout'] is not None: + self.output.set_info("stdout from template: {}:\n{}\n".format( + template_path, + output['stdout'])) + + # Если есть ошибки от параметра run -- выводим их как error. + if output['stderr'] is not None: + self.output.set_error("stderr from template: {}:\n{}\n". + format(template_path, + output['stderr'])) + # Если run выполнен с ошибками -- пропускаем директорию. + return False + + except TemplateExecutorError as error: + self.output.set_error('Template execution error: {} Template: {}'. + format(str(error), + template_path)) + return False + + self.output.set_success('Processing directory: {}'. + format(template_path)) + return target_path + + def _update_package_tree(self, package, current_level_tree): + '''Метод для обновления деревьев директорий пакетов, необходимых для + обработки шаблонов пакетов из значения параметра merge.''' + # Если текущему уровню соответствует заглушка None или он содержит + # файлы, то есть не пустой -- тогда есть смысл обновлять. + if current_level_tree is None or current_level_tree: + if package in self.packages_file_trees: + # Если для данного пакета уже есть дерево -- + # накладываем на него текущее. + self.packages_file_trees[package].update_tree( + copy.deepcopy(self.directory_tree) + ) + else: + # Если для данного пакета еще нет дерева -- + # копируем для него текущее. + directory_tree = DirectoryTree(self.base_directory) + directory_tree.update_tree( + copy.deepcopy(self.directory_tree)) + self.packages_file_trees[package] = directory_tree + + def _check_package_and_action(self, parameters, template_path, + directory_tree=None): '''Метод для проверки параметров action и package во время обработки каталогов с шаблонами. Если среди аргументов указано также - дерево каталогов, то''' + дерево каталогов, то в случае несовпадения значений package для файла + или директории, им в дереве присваивается значение None.''' if parameters.append != 'skip' or parameters.action: if not parameters.action: self.output.set_warning( diff --git a/tests/templates/test_directory_processor.py b/tests/templates/test_directory_processor.py index 118b7f4..875f945 100644 --- a/tests/templates/test_directory_processor.py +++ b/tests/templates/test_directory_processor.py @@ -113,10 +113,22 @@ class TestDirectoryProcessor: directory_processor = DirectoryProcessor('install', datavars_module=datavars) directory_processor.process_template_directories() - output_text = ("options {\n parameter-1 " - + datavars.variables.variable_1 - + ";\n parameter-2 " - + datavars.variables.variable_2 + ";\n};\n") + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# ' + '{0}' + '\n' + + '#' + '-' * 79 + '\n') + + header = header.format('\n# '.join( + [join_paths( + CHROOT_PATH, + 'templates_1/root/file_0')])) + output_text = '{0}{1}'.format(header, + ("options {\n parameter-1 " + + datavars.variables.variable_1 + + ";\n parameter-2 " + + datavars.variables.variable_2 + + ";\n};\n")) assert os.path.exists(join_paths(CHROOT_PATH, '/etc/file_0')) test_package = Package(test_package_name, chroot_path=CHROOT_PATH) @@ -149,10 +161,22 @@ class TestDirectoryProcessor: directory_processor = DirectoryProcessor('install', datavars_module=datavars) directory_processor.process_template_directories() - output_text = ("options {\n parameter-1 " - + datavars.variables.variable_1 - + ";\n parameter-2 " - + datavars.variables.variable_2 + ";\n};\n") + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# ' + '{0}' + '\n' + + '#' + '-' * 79 + '\n') + + header = header.format('\n# '.join( + [join_paths( + CHROOT_PATH, + 'templates_3/root/dir_2/file_0')])) + output_text = '{0}{1}'.format(header, + ("options {\n parameter-1 " + + datavars.variables.variable_1 + + ";\n parameter-2 " + + datavars.variables.variable_2 + + ";\n};\n")) assert os.path.exists(join_paths(CHROOT_PATH, '/etc/dir_2')) assert os.path.exists(join_paths(CHROOT_PATH, '/etc/dir_2/file_0')) @@ -170,10 +194,32 @@ class TestDirectoryProcessor: directory_processor = DirectoryProcessor('install', datavars_module=datavars) directory_processor.process_template_directories() - output_text = ("options {\n parameter-1 " - + datavars.variables.variable_1 - + ";\n parameter-2 " - + datavars.variables.variable_2 + ";\n};\n") + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# ' + '{0}' + '\n' + + '#' + '-' * 79 + '\n') + + header_1 = header.format('\n# '.join( + [join_paths( + CHROOT_PATH, + 'templates_5/root/dir_4/file_0')])) + output_text_1 = '{0}{1}'.format(header_1, + ("options {\n parameter-1 " + + datavars.variables.variable_1 + + ";\n parameter-2 " + + datavars.variables.variable_2 + + ";\n};\n")) + header_2 = header.format('\n# '.join( + [join_paths( + CHROOT_PATH, + 'templates_5/root/dir_5/file_0')])) + output_text_2 = '{0}{1}'.format(header_2, + ("options {\n parameter-1 " + + datavars.variables.variable_1 + + ";\n parameter-2 " + + datavars.variables.variable_2 + + ";\n};\n")) assert os.path.exists(join_paths(CHROOT_PATH, '/etc/dir_4')) assert os.path.exists(join_paths(CHROOT_PATH, '/etc/dir_4/file_0')) @@ -183,7 +229,7 @@ class TestDirectoryProcessor: with open(join_paths(CHROOT_PATH, '/etc/dir_4/file_0'), 'r') as output_file: output_file_text = output_file.read() - assert output_file_text == output_text + assert output_file_text == output_text_1 # Для подробностей см. шаблон. assert os.path.exists(join_paths(CHROOT_PATH, '/etc/dir_5')) @@ -197,7 +243,7 @@ class TestDirectoryProcessor: with open(join_paths(CHROOT_PATH, '/etc/dir_5/dir_6/file_0'), 'r') as output_file: output_file_text = output_file.read() - assert output_file_text == output_text + assert output_file_text == output_text_2 def test_if_templates_consist_only_one_directory_with_a_calculate_directory_file_and_a_single_template_file_and_there_is_a_file_without_user_changes_on_its_target_path__the_directory_processor_joins_a_template_file_with_a_target_file_and_updates_the_CONTENTS_file(self): datavars.main['cl_template_path'] = os.path.join(CHROOT_PATH, @@ -205,20 +251,34 @@ class TestDirectoryProcessor: directory_processor = DirectoryProcessor('install', datavars_module=datavars) directory_processor.process_template_directories() - output_text = ("options {\n parameter-0 yes;\n parameter-1 " - + datavars.variables.variable_1 - + ";\n parameter-2 " - + datavars.variables.variable_2 + ";\n};\n") + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# ' + '{0}' + '\n' + + '#' + '-' * 79 + '\n') + + header = header.format('\n# '.join( + [join_paths( + CHROOT_PATH, + 'templates_6/root/file_1')])) + output_text = '{0}{1}'.format(header, + ("options {\n parameter-0 yes;" + + "\n parameter-1 " + + datavars.variables.variable_1 + + ";\n parameter-2 " + + datavars.variables.variable_2 + + ";\n};\n")) - assert os.path.exists(join_paths(CHROOT_PATH, '/etc/file_1')) test_package = Package(new_package_name, chroot_path=CHROOT_PATH) + + assert os.path.exists(join_paths(CHROOT_PATH, '/etc/file_1')) + with open(join_paths(CHROOT_PATH, '/etc/file_1'), 'r') as output_file: + output_file_text = output_file.read() + assert output_file_text == output_text assert '/etc/file_1' in test_package assert test_package.is_md5_equal('/etc/file_1', hashlib.md5( output_text.encode()).hexdigest()) - with open(join_paths(CHROOT_PATH, '/etc/file_1'), 'r') as output_file: - output_file_text = output_file.read() - assert output_file_text == output_text def test_if_templates_consist_only_one_directory_with_a_calculate_directory_file_with_a_single_directory_with_a_single_template_file_and_there_is_a_file_without_user_changes_on_its_target_path__the_directory_processor_joins_a_template_file_with_a_target_file_and_updates_the_CONTENTS_file(self): datavars.main['cl_template_path'] = os.path.join(CHROOT_PATH, @@ -226,10 +286,23 @@ class TestDirectoryProcessor: directory_processor = DirectoryProcessor('install', datavars_module=datavars) directory_processor.process_template_directories() - output_text = ("options {\n parameter-0 yes;\n parameter-1 " - + datavars.variables.variable_1 - + ";\n parameter-2 " - + datavars.variables.variable_2 + ";\n};\n") + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# ' + '{0}' + '\n' + + '#' + '-' * 79 + '\n') + + header = header.format('\n# '.join( + [join_paths( + CHROOT_PATH, + 'templates_7/root/dir_6/file_0')])) + output_text = '{0}{1}'.format(header, + ("options {\n parameter-0 yes;" + + "\n parameter-1 " + + datavars.variables.variable_1 + + ";\n parameter-2 " + + datavars.variables.variable_2 + + ";\n};\n")) assert os.path.exists(join_paths(CHROOT_PATH, '/etc/dir_6')) assert os.path.exists(join_paths(CHROOT_PATH, '/etc/dir_6/file_0')) @@ -250,10 +323,23 @@ class TestDirectoryProcessor: directory_processor = DirectoryProcessor('install', datavars_module=datavars) directory_processor.process_template_directories() - output_text = ("options {\n parameter-0 yes;\n parameter-1 " - + datavars.variables.variable_1 - + ";\n parameter-2 " - + datavars.variables.variable_2 + ";\n};\n") + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# ' + '{0}' + '\n' + + '#' + '-' * 79 + '\n') + + header = header.format('\n# '.join( + [join_paths( + CHROOT_PATH, + 'templates_8/root/file_2')])) + output_text = '{0}{1}'.format(header, + ("options {\n parameter-0 yes;" + + "\n parameter-1 " + + datavars.variables.variable_1 + + ";\n parameter-2 " + + datavars.variables.variable_2 + + ";\n};\n")) assert os.path.exists(join_paths(CHROOT_PATH, '/etc/file_2')) assert os.path.exists(join_paths(CHROOT_PATH, '/etc/._cfg0001_file_2')) @@ -274,10 +360,22 @@ class TestDirectoryProcessor: directory_processor = DirectoryProcessor('install', datavars_module=datavars) directory_processor.process_template_directories() - output_text = ("options {\n parameter-1 " - + datavars.variables.variable_1 - + ";\n parameter-2 " - + datavars.variables.variable_2 + ";\n};\n") + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# ' + '{0}' + '\n' + + '#' + '-' * 79 + '\n') + + header = header.format('\n# '.join( + [join_paths( + CHROOT_PATH, + 'templates_9/root/etc/file_3')])) + output_text = '{0}{1}'.format(header, + ("options {\n parameter-1 " + + datavars.variables.variable_1 + + ";\n parameter-2 " + + datavars.variables.variable_2 + + ";\n};\n")) assert not os.path.exists(join_paths(CHROOT_PATH, '/etc/file_3')) assert os.path.exists(join_paths(CHROOT_PATH, '/etc/._cfg0001_file_3')) @@ -298,14 +396,45 @@ class TestDirectoryProcessor: directory_processor = DirectoryProcessor('install', datavars_module=datavars) directory_processor.process_template_directories() - output_text_1 = ("options {\n parameter-1 " - + datavars.variables.variable_1 - + ";\n parameter-2 " - + datavars.variables.variable_2 + ";\n};\n") - output_text_2 = ("options {\n parameter-0 no;\n parameter-1 " - + datavars.variables.variable_1 - + ";\n parameter-2 " - + datavars.variables.variable_2 + ";\n};\n") + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# ' + '{0}' + '\n' + + '#' + '-' * 79 + '\n') + + header_1 = header.format('\n# '.join( + [join_paths( + CHROOT_PATH, + 'templates_10/root/etc/file_4')])) + output_text_1 = '{0}{1}'.format(header_1, + ("options {\n parameter-0 no;" + + "\n parameter-1 " + + datavars.variables.variable_1 + + ";\n parameter-2 " + + datavars.variables.variable_2 + + ";\n};\n")) + header_2 = header.format('\n# '.join( + [join_paths( + CHROOT_PATH, + 'templates_10/root/etc/file_5')])) + output_text_2 = '{0}{1}'.format(header_2, + ("options {\n parameter-1 " + + datavars.variables.variable_1 + + ";\n parameter-2 " + + datavars.variables.variable_2 + + ";\n};\n")) + + header_3 = header.format('\n# '.join( + [join_paths( + CHROOT_PATH, + 'templates_10/root/etc/dir_7/file_0')])) + output_text_3 = '{0}{1}'.format(header_3, + ("options {\n parameter-0 no;" + + "\n parameter-1 " + + datavars.variables.variable_1 + + ";\n parameter-2 " + + datavars.variables.variable_2 + + ";\n};\n")) assert os.path.exists(join_paths(CHROOT_PATH, '/etc/file_4')) assert not os.path.exists(join_paths(CHROOT_PATH, @@ -325,24 +454,24 @@ class TestDirectoryProcessor: with open(join_paths(CHROOT_PATH, '/etc/file_4'), 'r') as output_file: output_file_text = output_file.read() - assert output_file_text == output_text_2 + assert output_file_text == output_text_1 assert test_package.is_md5_equal('/etc/file_4', hashlib.md5( - output_text_2.encode()).hexdigest()) + output_text_1.encode()).hexdigest()) with open(join_paths(CHROOT_PATH, '/etc/file_5'), 'r') as output_file: output_file_text = output_file.read() - assert output_file_text == output_text_1 + assert output_file_text == output_text_2 assert test_package.is_md5_equal('/etc/file_5', hashlib.md5( - output_text_1.encode()).hexdigest()) + output_text_2.encode()).hexdigest()) with open(join_paths(CHROOT_PATH, '/etc/dir_7/file_0'), 'r') as output_file: output_file_text = output_file.read() - assert output_file_text == output_text_2 + assert output_file_text == output_text_3 assert test_package.is_md5_equal('/etc/dir_7/file_0', hashlib.md5( - output_text_2.encode()).hexdigest()) + output_text_3.encode()).hexdigest()) def test_if_the_template_directory_have_no_the_action_parameter_value_and_append_parameter_is_not_skip__the_directory_processor_skips_this_template_branch_and_sets_warning(self): datavars.main['cl_template_path'] = os.path.join(CHROOT_PATH, @@ -616,6 +745,18 @@ class TestDirectoryProcessor: show_tree(list_path) assert False + def test_conditions(self): + pass + + def test_config_file(self): + pass + + def test_run(self): + pass + + def test_exec(self): + pass + def test_for_removing_testfile(self): shutil.rmtree(os.path.join(CHROOT_PATH, 'etc')) shutil.rmtree(os.path.join(CHROOT_PATH, 'var')) diff --git a/tests/templates/test_template_executor.py b/tests/templates/test_template_executor.py index 791d98e..7fdbc9d 100644 --- a/tests/templates/test_template_executor.py +++ b/tests/templates/test_template_executor.py @@ -27,11 +27,10 @@ EXECUTE_ARCHIVE_PATH = os.path.join(CHROOT_PATH, 'var/lib/calculate/.execute') -template_executor = TemplateExecutor( - chroot_path=CHROOT_PATH, - cl_config_archive=CONFIG_ARCHIVE_PATH, - cl_config_path=CONFIG_PATH, - execute_archive_path=EXECUTE_ARCHIVE_PATH) +template_executor = TemplateExecutor(chroot_path=CHROOT_PATH, + cl_config_archive=CONFIG_ARCHIVE_PATH, + cl_config_path=CONFIG_PATH, + execute_archive_path=EXECUTE_ARCHIVE_PATH) test_package_name = PackageAtomName( {'pkg_path': os.path.join( @@ -412,6 +411,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_directory, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) dir_owner = template_executor._get_file_owner(target_directory) @@ -434,6 +434,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_directory, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -460,6 +461,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_directory, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._create_directory(template_wrapper) @@ -482,6 +484,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_directory, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._create_directory(template_wrapper) @@ -509,6 +512,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_directory, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._create_directory(template_wrapper) @@ -538,6 +542,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_directory, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._create_directory(template_wrapper) @@ -748,6 +753,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) try: @@ -767,6 +773,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) try: @@ -786,6 +793,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_join_directory(template_wrapper) @@ -806,7 +814,9 @@ class TestTemplateExecutor: output = template_executor.execute_template( target_path, parameters_object, - DIR, save_changes=False, + DIR, + '/path/to/template', + save_changes=False, target_package=test_package) assert os.path.exists(target_path) @@ -826,7 +836,9 @@ class TestTemplateExecutor: output = template_executor.execute_template( target_path, parameters_object, - DIR, save_changes=False, + DIR, + '/path/to/template', + save_changes=False, target_package=test_package) assert output['target_path'] == join_paths( CHROOT_PATH, @@ -843,7 +855,9 @@ class TestTemplateExecutor: output = template_executor.execute_template( target_path, parameters_object, - DIR, save_changes=False, + DIR, + '/path/to/template', + save_changes=False, target_package=test_package) assert os.path.exists(target_path) assert os.path.isdir(target_path) @@ -861,6 +875,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_remove_directory(template_wrapper) @@ -879,6 +894,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_remove_directory(template_wrapper) @@ -896,6 +912,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_remove_directory(template_wrapper) @@ -912,6 +929,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_clear_directory(template_wrapper) @@ -927,6 +945,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_clear_directory(template_wrapper) @@ -944,6 +963,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_clear_directory(template_wrapper) @@ -957,6 +977,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_clear_directory(template_wrapper) @@ -977,6 +998,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_clear_directory(template_wrapper) @@ -1005,6 +1027,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_clear_directory(template_wrapper) @@ -1020,6 +1043,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_replace_directory(template_wrapper) @@ -1040,6 +1064,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_replace_directory(template_wrapper) @@ -1058,6 +1083,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_clear_directory(template_wrapper) @@ -1079,6 +1105,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_clear_directory(template_wrapper) @@ -1096,6 +1123,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_replace_directory(template_wrapper) @@ -1116,6 +1144,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_replace_directory(template_wrapper) @@ -1145,6 +1174,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_link_directory(template_wrapper) @@ -1174,6 +1204,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, DIR, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_link_directory(template_wrapper) @@ -1201,7 +1232,9 @@ class TestTemplateExecutor: assert os.readlink(target_path) == 'dir_2' template_executor.execute_template(target_path, parameters_object, - DIR, save_changes=False, + DIR, + '/path/to/template', + save_changes=False, target_package=test_package) assert os.path.exists(target_path) assert os.path.islink(target_path) @@ -1229,7 +1262,9 @@ class TestTemplateExecutor: with pytest.raises(TemplateExecutorError): template_executor.execute_template(target_path, parameters_object, - DIR, save_changes=False, + DIR, + '/path/to/template', + save_changes=False, target_package=test_package) def test_if_execute_template_method_s_input_is_a_template_of_the_DIR_type_with_the_append_link_parameter_a_target_path_to_an_existing_link_to_a_file_that_belongs_to_the_template_package_and_force_parameter_is_set__the_method_removes_a_link_from_a_target_path_and_creates_a_link_to_a_source_directory(self): @@ -1247,7 +1282,9 @@ class TestTemplateExecutor: assert os.path.isfile(target_path) template_executor.execute_template(target_path, parameters_object, - DIR, save_changes=False, + DIR, + '/path/to/template', + save_changes=False, target_package=test_package) assert os.path.exists(target_path) assert os.path.islink(target_path) @@ -1274,7 +1311,9 @@ class TestTemplateExecutor: with pytest.raises(TemplateExecutorError): template_executor.execute_template(target_path, parameters_object, - DIR, save_changes=False, + DIR, + '/path/to/template', + save_changes=False, target_package=test_package) def test_if_execute_template_method_s_input_is_a_template_of_the_DIR_type_with_the_append_link_parameter_a_target_path_to_an_existing_file_that_belongs_to_the_template_package_and_force_parameter_is_set__the_method_removes_a_file_from_a_target_path_and_creates_a_link_to_a_source_directory(self): @@ -1291,7 +1330,9 @@ class TestTemplateExecutor: assert os.path.isfile(target_path) template_executor.execute_template(target_path, parameters_object, - DIR, save_changes=False, + DIR, + '/path/to/template', + save_changes=False, target_package=test_package) assert os.path.exists(target_path) assert os.path.islink(target_path) @@ -1318,7 +1359,9 @@ class TestTemplateExecutor: with pytest.raises(TemplateExecutorError): template_executor.execute_template(target_path, parameters_object, - DIR, save_changes=False, + DIR, + '/path/to/template', + save_changes=False, target_package=test_package) def test_if_execute_template_method_s_input_is_a_template_of_the_DIR_type_with_the_append_link_parameter_a_target_path_to_an_existing_directory_that_belongs_to_the_template_package_and_force_parameter_is_set__the_method_removes_a_directory_from_a_target_path_and_creates_a_link_to_a_source_directory(self): @@ -1335,7 +1378,9 @@ class TestTemplateExecutor: assert os.path.isdir(target_path) template_executor.execute_template(target_path, parameters_object, - DIR, save_changes=False, + DIR, + '/path/to/template', + save_changes=False, target_package=test_package) assert os.path.exists(target_path) assert os.path.islink(target_path) @@ -1356,11 +1401,19 @@ class TestTemplateExecutor: parameters_object = ParametersContainer({'package': test_package_name, 'append': 'join', 'format': 'bind'}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text = 'section-name {\n parameter-2 no;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n' + ' parameter-2 no;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1382,11 +1435,19 @@ class TestTemplateExecutor: parameters_object = ParametersContainer({'package': test_package_name, 'append': 'join', 'format': 'bind'}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text = 'section-name {\n parameter-2 no;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n' + ' parameter-2 no;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1410,11 +1471,19 @@ class TestTemplateExecutor: 'append': 'join', 'format': 'bind', 'autoupdate': True}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text = 'section-name {\n parameter-2 no;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n' + ' parameter-2 no;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1443,11 +1512,20 @@ class TestTemplateExecutor: 'format': 'bind', 'chown': chown_value, 'chmod': chmod_value}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text = 'section-name {\n parameter-2 no;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n' + ' parameter-2 no;\n' + '};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1478,11 +1556,19 @@ class TestTemplateExecutor: 'chmod': chmod_value}) output_path = os.path.join(os.path.dirname(target_path), '._cfg0001_file_4') + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text = 'section-name {\n parameter-2 no;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {' + '\n parameter-2 no;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1507,12 +1593,19 @@ class TestTemplateExecutor: parameters_object = ParametersContainer({'package': test_package_name, 'append': 'join', 'format': 'bind'}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text =\ - 'section-name {\n parameter-1 yes;\n parameter-2 no;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n parameter-1 yes;' + '\n parameter-2 no;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1541,12 +1634,19 @@ class TestTemplateExecutor: 'format': 'bind', 'chown': chown_value, 'chmod': chmod_value}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text =\ - 'section-name {\n parameter-1 yes;\n parameter-2 no;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n parameter-1 yes;' + '\n parameter-2 no;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1574,12 +1674,19 @@ class TestTemplateExecutor: parameters_object = ParametersContainer({'package': test_package_name, 'append': 'join', 'format': 'bind'}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text =\ - 'section-name {\n parameter-1 yes;\n parameter-2 no;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n parameter-1 yes;' + '\n parameter-2 no;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1606,12 +1713,19 @@ class TestTemplateExecutor: 'format': 'bind', 'chown': chown_value, 'chmod': chmod_value}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text =\ - 'section-name {\n parameter-1 yes;\n parameter-2 no;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n parameter-1 yes;' + '\n parameter-2 no;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1637,12 +1751,19 @@ class TestTemplateExecutor: 'append': 'join', 'format': 'bind', 'autoupdate': True}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text =\ - 'section-name {\n parameter-1 no;\n parameter-2 no;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n parameter-1 no;' + '\n parameter-2 no;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1670,12 +1791,19 @@ class TestTemplateExecutor: 'append': 'join', 'format': 'bind', 'autoupdate': True}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-4 yes; }' - output_text =\ - 'section-name {\n parameter-1 yes;\n parameter-4 yes;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n parameter-1 yes;' + '\n parameter-4 yes;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1709,13 +1837,20 @@ class TestTemplateExecutor: parameters_object = ParametersContainer({'package': test_package_name, 'append': 'join', 'format': 'bind'}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-4 yes; }' - output_text =\ - 'section-name {\n parameter-1 yes;\n parameter-4 yes;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n parameter-1 yes;' + '\n parameter-4 yes;\n};\n')) output_md5 = hashlib.md5(output_text.encode()).hexdigest() template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1747,13 +1882,20 @@ class TestTemplateExecutor: parameters_object = ParametersContainer({'package': test_package_name, 'append': 'join', 'format': 'bind'}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-3 10; }' - output_text =\ - 'section-name {\n parameter-1 yes;\n parameter-3 10;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n parameter-1 yes;' + '\n parameter-3 10;\n};\n')) output_md5 = hashlib.md5(output_text.encode()).hexdigest() template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1778,12 +1920,19 @@ class TestTemplateExecutor: parameters_object = ParametersContainer({'package': test_package_name, 'append': 'join', 'format': 'bind'}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text =\ - 'section-name {\n parameter-1 yes;\n parameter-2 no;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n parameter-1 yes;' + '\n parameter-2 no;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1811,12 +1960,19 @@ class TestTemplateExecutor: parameters_object = ParametersContainer({'package': test_package_name, 'append': 'join', 'format': 'bind'}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text =\ - 'section-name {\n parameter-1 no;\n parameter-2 no;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n parameter-1 no;' + '\n parameter-2 no;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1846,12 +2002,19 @@ class TestTemplateExecutor: 'append': 'join', 'format': 'bind', 'unbound': True}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text =\ - 'section-name {\n parameter-1 yes;\n parameter-2 no;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n parameter-1 yes;' + '\n parameter-2 no;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1877,12 +2040,19 @@ class TestTemplateExecutor: 'append': 'join', 'format': 'bind', 'unbound': True}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text =\ - 'section-name {\n parameter-1 no;\n parameter-2 no;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n parameter-1 no;' + '\n parameter-2 no;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1915,12 +2085,19 @@ class TestTemplateExecutor: 'append': 'join', 'format': 'bind', 'unbound': True}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text =\ - 'section-name {\n parameter-1 no;\n parameter-2 no;\n};\n' + output_text = '{}{}'.format(header, + ('section-name {\n parameter-1 no;' + '\n parameter-2 no;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -1956,7 +2133,9 @@ class TestTemplateExecutor: with pytest.raises(TemplateExecutorError): template_executor.execute_template(target_path, parameters_object, - FILE, save_changes=False, + FILE, + '/path/to/template', + save_changes=False, template_text=template_text, target_package=test_package) @@ -1970,14 +2149,22 @@ class TestTemplateExecutor: 'append': 'join', 'format': 'bind', 'force': True}) + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') template_text = 'section-name { parameter-2 no; }' - output_text =\ - 'section-name {\n parameter-2 no;\n};\n' + output_text = '{}{}'.format( + header, + 'section-name {\n parameter-2 no;\n};\n') assert os.path.isdir(target_path) template_executor.execute_template(target_path, parameters_object, - FILE, save_changes=False, + FILE, + '/path/to/template', + save_changes=False, template_text=template_text, target_package=test_package) @@ -2001,12 +2188,21 @@ class TestTemplateExecutor: parameters_object = ParametersContainer({'package': test_package_name, 'append': 'after', 'format': 'bind'}) - template_text = 'section-1 { parameter-2 no; } section-2 { parameter-1 10; }' - output_text =\ - 'section-1 {\n parameter-1 yes;\n parameter-2 no;\n};\n\nsection-2 {\n parameter-1 10;\n};\n' + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') + template_text = ('section-1 { parameter-2 no; }' + 'section-2 { parameter-1 10; }') + output_text = '{}{}'.format(header, + ('section-1 {\n parameter-1 yes;' + '\n parameter-2 no;\n};\n\n' + 'section-2 {\n parameter-1 10;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -2026,12 +2222,21 @@ class TestTemplateExecutor: parameters_object = ParametersContainer({'package': test_package_name, 'append': 'before', 'format': 'bind'}) - template_text = 'section-1 { parameter-1 no; } section-2 { parameter-2 10; }' - output_text =\ - 'section-1 {\n parameter-1 no;\n};\n\nsection-2 {\n parameter-1 yes;\n parameter-2 10;\n};\n' + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') + template_text = ('section-1 { parameter-1 no; }' + 'section-2 { parameter-2 10; }') + output_text = '{}{}'.format(header, + ('section-1 {\n parameter-1 no;\n};\n' + '\nsection-2 {\n parameter-1 yes;' + '\n parameter-2 10;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -2052,12 +2257,21 @@ class TestTemplateExecutor: parameters_object = ParametersContainer({'package': test_package_name, 'append': 'replace', 'format': 'bind'}) - template_text = 'section-1 { parameter-1 no; }; section-2 { parameter-1 10; }' - output_text =\ - 'section-1 {\n parameter-1 no;\n};\n\nsection-2 {\n parameter-1 10;\n};\n' + header = ('#' + '-' * 79 + '\n' + + '# Modified by Calculate Utilities 4.0\n' + + '# Processed template files:\n' + + '# /path/to/template\n' + + '#' + '-' * 79 + '\n') + template_text = ('section-1 { parameter-1 no; };' + 'section-2 { parameter-1 10; }') + output_text = '{}{}'.format( + header, + ('section-1 {\n parameter-1 no;\n};\n' + '\nsection-2 {\n parameter-1 10;\n};\n')) template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) @@ -2083,6 +2297,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_remove_file(template_wrapper) @@ -2099,6 +2314,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_remove_file(template_wrapper) @@ -2114,6 +2330,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_remove_file(template_wrapper) @@ -2130,6 +2347,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_clear_file(template_wrapper) @@ -2148,6 +2366,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_clear_file(template_wrapper) @@ -2171,6 +2390,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_clear_file(template_wrapper) @@ -2200,6 +2420,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_link_file(template_wrapper) @@ -2229,6 +2450,7 @@ class TestTemplateExecutor: template_wrapper = TemplateWrapper( target_path, parameters_object, FILE, + '/path/to/template', chroot_path=CHROOT_PATH, config_archive_path=CONFIG_ARCHIVE_PATH) template_executor._append_link_file(template_wrapper) @@ -2249,8 +2471,10 @@ class TestTemplateExecutor: parameters_object = ParametersContainer({'package': test_package_name, 'run': '/usr/bin/python'}) template_executor.execute_template(target_path, - parameters_object, - FILE, save_changes=False) + parameters_object, + FILE, + '/path/to/template', + save_changes=False) def test_if_the_execute_template_method_s_input_is_a_template_with_the_run_parameter_and_a_target_path_to_an_existing_directory_and_its_text_is_correct__the_method_runs_a_template_text_in_the_target_directory_and_returns_the_object_with_its_stdout(self): target_path = join_paths( @@ -2265,6 +2489,7 @@ print(os.getcwd())''' target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, save_changes=False) assert output['stdout'].strip() == target_path @@ -2279,7 +2504,9 @@ print(os.getcwd())''' with pytest.raises(TemplateExecutorError): template_executor.execute_template(target_path, parameters_object, - FILE, save_changes=False) + FILE, + '/path/to/template', + save_changes=False) def test_if_the_execute_template_method_s_input_is_a_template_with_the_run_parameter_and_a_target_path_to_an_existing_file_and_its_text_is_correct__the_method_runs_a_template_text_in_a_directory_that_contains_a_file_from_a_target_path_and_returns_the_object_with_its_stdout(self): target_path = join_paths( @@ -2294,6 +2521,7 @@ print(os.getcwd())''' target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, save_changes=False) assert output['stdout'].strip() == os.path.dirname(target_path) @@ -2308,7 +2536,9 @@ print(os.getcwd())''' with pytest.raises(TemplateExecutorError): template_executor.execute_template(target_path, parameters_object, - FILE, save_changes=False) + FILE, + '/path/to/template', + save_changes=False) def test_if_the_execute_template_method_s_input_is_a_template_with_the_run_parameter_a_target_path_to_an_existing_directory_and_its_text_is_not_correct__the_method_runs_a_template_text_and_returns_the_object_with_its_stderr(self): target_path = join_paths( @@ -2328,6 +2558,7 @@ print(os.suspicious_attribute)''' target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, save_changes=False) assert output['stdout'] is None @@ -2346,6 +2577,7 @@ print(os.getcwd())''' template_executor.execute_template(target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, save_changes=False) @@ -2359,7 +2591,9 @@ print(os.getcwd())''' 'exec': interpreter}) template_executor.execute_template(target_path, parameters_object, - FILE, save_changes=False) + FILE, + '/path/to/template', + save_changes=False) assert os.path.exists(execute_file_path) assert template_executor.execute_files[execute_file_path][ 'interpreter'] == interpreter @@ -2387,6 +2621,7 @@ print(os.getcwd())''' template_executor.execute_template(target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, save_changes=False) assert os.path.exists(execute_file_path) @@ -2411,7 +2646,9 @@ print(os.getcwd())''' with pytest.raises(TemplateExecutorError): template_executor.execute_template(target_path, parameters_object, - FILE, save_changes=False) + FILE, + '/path/to/template', + save_changes=False) def test_if_the_execute_template_method_s_input_is_a_template_with_the_exec_parameter_and_a_target_path_to_an_existing_file_and_its_text_is_not_empty__the_method_creates_an_exec_file_and_saves_a_path_to_exec_file_interpreter_and_a_path_to_a_file_from_a_target_path_as_cwd_path(self): target_path = join_paths(CHROOT_PATH, @@ -2426,6 +2663,7 @@ print(os.getcwd())''' template_executor.execute_template(target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, save_changes=False) assert os.path.exists(execute_file_path) @@ -2450,7 +2688,9 @@ print(os.getcwd())''' with pytest.raises(TemplateExecutorError): template_executor.execute_template(target_path, parameters_object, - FILE, save_changes=False) + FILE, + '/path/to/template', + save_changes=False) def test_if_the_execute_template_method_s_input_is_a_several_templates_with_the_exec_parameter_and_a_target_paths_to_an_existing_directories_and_files_and_its_text_is_not_empty__the_method_creates_some_exec_files_and_saves_a_paths_to_exec_files_its_interpreters_and_paths_to_a_directories_from_a_target_path_as_cwd_path(self): interpreter = '/usr/bin/python' @@ -2471,6 +2711,7 @@ print(os.getcwd())''' template_executor.execute_template(target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, save_changes=False) counter += 1 @@ -2506,6 +2747,7 @@ print(os.getcwd())''' template_executor.execute_template(target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, save_changes=False) @@ -2538,6 +2780,7 @@ AttributeError: module 'os' has no attribute 'suspicious_attribute' template_executor.execute_template(target_path, parameters_object, FILE, + '/path/to/template', template_text=template_text, save_changes=False) diff --git a/tests/templates/testfiles/test_executor_root/etc.backup/append_join_file_testfiles/._cfg0001_file_12 b/tests/templates/testfiles/test_executor_root/etc.backup/append_join_file_testfiles/._cfg0001_file_12 index a84cd15..3bae35e 100644 --- a/tests/templates/testfiles/test_executor_root/etc.backup/append_join_file_testfiles/._cfg0001_file_12 +++ b/tests/templates/testfiles/test_executor_root/etc.backup/append_join_file_testfiles/._cfg0001_file_12 @@ -1,3 +1,8 @@ +#------------------------------------------------------------------------------- +# Modified by Calculate Utilities 4.0 +# Processed template files: +# /path/to/template +#------------------------------------------------------------------------------- section-name { parameter-1 yes; parameter-2 no; diff --git a/tests/templates/testfiles/test_executor_root/etc.backup/append_join_file_testfiles/._cfg0002_file_12 b/tests/templates/testfiles/test_executor_root/etc.backup/append_join_file_testfiles/._cfg0002_file_12 index 525594d..98cb55c 100644 --- a/tests/templates/testfiles/test_executor_root/etc.backup/append_join_file_testfiles/._cfg0002_file_12 +++ b/tests/templates/testfiles/test_executor_root/etc.backup/append_join_file_testfiles/._cfg0002_file_12 @@ -1,3 +1,8 @@ +#------------------------------------------------------------------------------- +# Modified by Calculate Utilities 4.0 +# Processed template files: +# /path/to/template +#------------------------------------------------------------------------------- section-name { parameter-1 yes; parameter-3 10; diff --git a/tests/templates/testfiles/test_executor_root/var/lib/calculate/config b/tests/templates/testfiles/test_executor_root/var/lib/calculate/config index 6817122..be629ea 100644 --- a/tests/templates/testfiles/test_executor_root/var/lib/calculate/config +++ b/tests/templates/testfiles/test_executor_root/var/lib/calculate/config @@ -1,4 +1,4 @@ -/etc/append_join_file_testfiles/file_10 1668d31fd2a8e3f2c9ecedc5335d8f67 -/etc/append_join_file_testfiles/file_11 1668d31fd2a8e3f2c9ecedc5335d8f67 -/etc/append_join_file_testfiles/file_12 1668d31fd2a8e3f2c9ecedc5335d8f67 -/etc/append_join_file_testfiles/file_15 1668d31fd2a8e3f2c9ecedc5335d8f67 +/etc/append_join_file_testfiles/file_10 83d2cb222a9c13964102d48ef6449d5b +/etc/append_join_file_testfiles/file_11 83d2cb222a9c13964102d48ef6449d5b +/etc/append_join_file_testfiles/file_12 83d2cb222a9c13964102d48ef6449d5b +/etc/append_join_file_testfiles/file_15 83d2cb222a9c13964102d48ef6449d5b