The template type conflict check is tested. Added method for getting target path from symlinks. The template package collision check is also tested.

packages
Иванов Денис 4 years ago
parent e2f8af977b
commit 59e3c93a6f

@ -35,7 +35,39 @@
"tests/templates/test_template_executor.py::TestTemplateAction::test_link_directory",
"tests/templates/test_template_executor.py::TestTemplateAction::test_remove_directory",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_the_TemplateWrapper_object_has_already_been_created__it_contains_the_correct_list_of_protected_and_unprotected_paths",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_FILE_and_target_file_does_not_exist__the_TemplateWrapper_target_type_is_None",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_DIR_and_target_file_is_DIR__the_TemplateWrapper_target_type_is_DIR",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_FILE_and_target_file_is_FILE__the_TemplateWrapper_target_type_is_FILE",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_FILE_and_target_file_is_FILE_and_force_parameter_is_set__the_TemplateWrapper_target_type_is_FILE_and_target_path_is_same",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_FILE_but_target_file_is_DIR_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_FILE_but_target_file_is_a_link_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_FILE_but_target_file_is_DIR_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_FILE_but_target_file_is_a_link_to_a_DIR_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_FILE_but_target_file_is_a_link_to_a_FILE_and_force_parameter_is_set__the_TemplateWrapper_changes_its_target_path_to_the_link_source_file",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_DIR_and_target_file_is_DIR_and_force_parameter_is_set__the_TemplateWrapper_target_type_is_DIR_and_target_path_is_the_same",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_DIR_and_target_file_is_a_link_to_a_DIR_and_force_parameter_is_not_set__the_TemplateWrapper_changes_its_target_path_to_the_link_source_file",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_DIR_but_target_file_is_FILE_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_DIR_and_target_file_is_a_link_to_a_file_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_DIR_and_target_file_is_FILE_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_DIR_and_target_file_is_the_link_to_a_FILE_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_DIR_and_target_file_is_the_link_to_a_DIR_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_FILE_with_the_append_link_parameter_and_target_file_is_the_link_to_a_FILE__the_TemplateWrapper_sets_remove_original_flag",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_FILE_with_the_append_link_parameter_and_target_file_is_the_link_to_a_DIR__the_TemplateWrapper_sets_remove_original_flag",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_DIR_with_the_append_link_parameter_and_target_file_is_the_link_to_a_FILE__the_TemplateWrapper_sets_remove_original_flag",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_DIR_with_the_append_link_parameter_and_target_file_is_the_link_to_a_DIR__the_TemplateWrapper_sets_remove_original_flag",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_FILE_with_the_append_link_parameter_and_target_file_is_FILE_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_FILE_with_the_append_link_parameter_and_target_file_is_DIR_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_DIR_with_the_append_link_parameter_and_target_file_is_FILE_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_DIR_with_the_append_link_parameter_and_target_file_is_DIR_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_FILE_with_the_append_link_parameter_and_target_file_is_FILE_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_FILE_with_the_append_link_parameter_and_target_file_is_DIR_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_DIR_with_the_append_link_parameter_and_target_file_is_FILE_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_type_is_DIR_with_the_append_link_parameter_and_target_file_is_DIR_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_contains_append_parameters_but_does_not_have_package_parameter_and_target_file_does_not_belong_to_any_package__the_TemplateWrapper_throws_TemplateCollisionError_exception",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_contains_package_parameter_and_target_file_does_not_belong_to_any_package__the_TemplateWrapper_uses_package_from_parameter_and_sets_target_without_package_flag",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_does_not_have_package_parameter_but_target_file_belongs_to_the_package__the_TemplateWrapper_uses_package_from_parameter",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_contains_package_parameter_and_target_file_belongs_to_the_package_from_package_parameter__the_TemplateWrapper_uses_package_from_them",
"tests/templates/test_template_wrapper.py::TestTemplateWrapper::test_if_template_contains_package_parameter_but_target_file_belongs_to_the_other_package__the_TemplateWrapper_throws_TemplateCollisionError",
"tests/templates/format/test_base.py::TestJoinMethod::test_if_inputs_are_dictionaries_with_string_keys_without_any_action_marks__the_dictionaties_just_merged",
"tests/templates/format/test_base.py::TestJoinMethod::test_if_inputs_are_dictionaries_with_tuple_keys_without_any_action_marks_as_their_keys__the_dictionaries_just_merged",
"tests/templates/format/test_base.py::TestJoinMethod::test_if_inputs_are_dictionaries_with_same_sections_which_contain_different_parameters__a_section_from_the_template_added_to_the_same_section_of_original_dictionary",

@ -363,10 +363,13 @@ class ParametersProcessor:
" the type of the template file")
# Проверяем, не является ли файл из source зацикленной ссылкой.
if (source_file_type == DIR and os.path.islink(real_path)
and not check_directory_link(real_path)):
raise IncorrectParameter(
"the link from 'source' parameter is cycled")
if (source_file_type == DIR and os.path.islink(real_path)):
try:
check_directory_link(real_path, chroot_path=self.chroot_path)
except FilesError as error:
raise IncorrectParameter(
"the link from 'source' is not correct: {}".
format(str(error)))
return os.path.normpath(real_path)

@ -3,7 +3,8 @@
from pprint import pprint
from ..utils.package import PackageAtomParser, Package, PackageNotFound
from ..utils.files import join_paths, write_file, read_file_lines, FilesError,\
check_directory_link, read_link, Process
check_directory_link, read_link, Process,\
get_target_from_link
from .template_engine import TemplateEngine, Variables, ConditionFailed,\
ParametersProcessor, DIR, FILE,\
ParametersContainer
@ -125,9 +126,6 @@ class TemplateWrapper:
type_checks = {DIR: os.path.isdir,
FILE: os.path.isfile}
chroot_path = '/'
config_archive_path = '/var/lib/calculate/config-archive'
_protected_is_set = False
_protected_set = set()
_unprotected_set = set()
@ -135,12 +133,22 @@ class TemplateWrapper:
def __new__(cls, *args, **kwargs):
if not cls._protected_is_set:
# Устанавливаем значения PROTECTED, если не заданы.
cls._set_protected()
if 'chroot_path' in kwargs:
chroot_path = kwargs['chroot_path']
else:
chroot_path = '/'
cls._set_protected(chroot_path)
return super().__new__(cls)
def __init__(self, target_file_path, parameters, template_type,
template_text=''):
def __init__(self, target_file_path,
parameters,
template_type,
template_text='',
chroot_path='/',
config_archive_path='/var/lib/calculate/config-archive'):
self.target_path = target_file_path
self.chroot_path = chroot_path
self.config_archive_path = config_archive_path
self.target_package_name = None
self.package_atom_parser = PackageAtomParser(
@ -165,6 +173,9 @@ class TemplateWrapper:
# Флаг, указывающий, что целевой путь был изменен.
self.target_path_is_changed = False
# Флаг, указывающий, что файл по целевому пути является ссылкой.
self.target_is_link = False
# Флаг, указывающий, что файл является PROTECTED.
self.protected = False
@ -176,6 +187,8 @@ class TemplateWrapper:
# не нужно.
return
self.format_class = None
if self.parameters.append in {'join', 'before', 'after'}:
# Получаем класс соответствующего формата файла.
if self.parameters.format:
@ -205,7 +218,7 @@ class TemplateWrapper:
" 'mirror' parameter is set")
self.target_type = None
if self.format_class.EXECUTABLE:
if self.format_class is not None and self.format_class.EXECUTABLE:
# Если формат исполняемый, но проверяем, существует ли директория,
# из которой будет выполняться шаблон.
if not os.path.exists(self.target_path):
@ -240,8 +253,9 @@ class TemplateWrapper:
print('target type = {}'.format('FILE' if self.target_type == FILE
else 'DIR' if self.target_type == DIR
else 'None'))
print('target is link = {}'.format(self.target_is_link))
if self.parameters.append == 'link':
if self.parameters.force:
if self.parameters.force or self.target_is_link:
self.remove_original = True
elif self.target_type == DIR:
raise TemplateTypeConflict("the target is a directory while "
@ -262,8 +276,11 @@ class TemplateWrapper:
self.remove_original = True
else:
try:
self.target_path = check_directory_link(
self.target_path)
link_source = check_directory_link(
self.target_path,
chroot_path=self.chroot_path)
self.target_path = link_source
self.target_path_is_changed = True
except FilesError as error:
raise TemplateExecutorError("files error: {}".
format(str(error)))
@ -274,10 +291,24 @@ class TemplateWrapper:
self.remove_original = True
elif self.target_is_link and self.target_type == FILE:
try:
self.target_path = read_link(self.target_path)
link_source = read_link(self.target_path)
self.target_path = get_target_from_link(
self.target_path,
link_source,
chroot_path=self.chroot_path)
self.target_path_is_changed = True
except FilesError as error:
raise TemplateExecutorError("files error: {}".
format(str(error)))
elif self.target_is_link:
if self.target_type == DIR:
raise TemplateTypeConflict("the target file is a link to a"
" directory while the template"
" is a file")
else:
raise TemplateTypeConflict("the target file is a link to"
" a file while the template"
" is a file")
elif self.target_type == DIR:
raise TemplateTypeConflict("the target file is a directory"
" while the template is a file")
@ -294,6 +325,7 @@ class TemplateWrapper:
try:
file_package = self.package_atom_parser.get_file_package(
self.target_path)
print('file package = {}'.format(file_package))
except PackageNotFound:
file_package = None
self.target_without_package = True
@ -314,12 +346,12 @@ class TemplateWrapper:
self.target_package_name = parameter_package
elif file_package != parameter_package:
raise TemplateCollisionError(
raise TemplateCollisionError((
"The template package is {0} while target"
" file package is {1}").format(
self.target_package_name.atom,
parameter_package.atom,
file_package.atom
)
))
else:
self.target_package_name = parameter_package
@ -356,10 +388,12 @@ class TemplateWrapper:
if not self.protected:
self.md5_matching = True
elif self.parameters.unbound:
# Если присутствует unbound, то просто модифицируем файл и
# удаляем его из CONTENTS.
self.md5_matching = True
elif self.target_type is None:
# Если целевой файл отсутствует.
if self.target_path in self.target_package:
@ -367,12 +401,14 @@ class TemplateWrapper:
self.md5_matching = False
else:
self.md5_matching = True
elif self.target_without_package:
# Если файл по целевому пути не относится к какому-либо пакету.
if self.parameters.unbound:
self.md5_matching = True
else:
self.md5_matching = False
else:
# Если файл есть и он относится к текущему пакету.
target_md5 = self.target_package.get_md5(self.target_path)
@ -459,36 +495,39 @@ class TemplateWrapper:
if mode == "modify":
if os.path.islink(file_path):
self.target_package.add_sym(file_path)
elif os.path.isdir(file_path):
self.target_package.add_dir(file_path)
elif os.path.isfile(file_path):
self.target_package.add_obj(file_path)
elif mode == "remove":
if os.path.islink(file_path) or os.path.isfile(file_path):
self.target_package.remove_obj(file_path)
elif os.path.isdir(file_path):
self.target_package.add_dir(file_path)
@classmethod
def _set_protected(cls):
def _set_protected(cls, chroot_path):
'''Метод для получения множества защищенных директорий.'''
if cls._protected_is_set:
return
cls._protected_set = set()
cls._protected_set.add(join_paths(cls.chroot_path, '/etc'))
cls._protected_set.add(join_paths(chroot_path, '/etc'))
config_protect_env = os.environ.get('CONFIG_PROTECT', False)
if config_protect_env:
for protected_path in config_protect_env.split():
protected_path = join_paths(cls.chroot_path,
protected_path = join_paths(chroot_path,
protected_path.strip())
cls._protected_set.add(protected_path)
config_protect_mask_env = os.environ.get('CONFIG_PROTECT_MASK', False)
if config_protect_mask_env:
for unprotected_path in config_protect_mask_env.split():
unprotected_path = join_paths(cls.chroot_path,
unprotected_path = join_paths(chroot_path,
unprotected_path.strip())
cls._unprotected_set.add(unprotected_path)
@ -537,9 +576,7 @@ class TemplateExecutor:
self.calculate_config_file = CalculateConfigFile(
cl_config_path=cl_config_path,
cl_chroot_path=chroot_path)
TemplateWrapper.chroot_path = self.chroot_path
TemplateWrapper.config_archive_path = cl_config_archive
self.cl_config_archive_path = cl_config_archive
@property
def available_appends(self):
@ -558,9 +595,13 @@ class TemplateExecutor:
'exec_file': None}
try:
template_object = TemplateWrapper(target_path, parameters,
template_type,
template_text=template_text)
template_object = TemplateWrapper(
target_path, parameters,
template_type,
template_text=template_text,
chroot_path=self.chroot_path,
config_archive_path=self.cl_config_archive_path)
except TemplateTypeConflict as error:
raise TemplateExecutorError("type conflict: {}".format(str(error)))

@ -310,15 +310,38 @@ def read_link(file_path):
'''Функция для получения целевого пути символьной ссылки.'''
try:
if path.exists(file_path):
return os.readlink(file_path)
source_path = os.readlink(file_path)
return source_path
else:
return None
except (OSError, IOError) as error:
mod, lineno = get_traceback_caller(*sys.exc_info())
FilesError("link read error, {}({}:{})".
FilesError("can not read link: {}({}:{})".
format(str(error), mod, lineno))
def get_target_from_link(link_path, link_source, chroot_path='/'):
'''Метод для получения целевого пути из целевого пути символьной ссылки
с учетом того, что целевой путь символьной ссылки может быть
относительным.'''
if os.path.isabs(link_source):
if chroot_path != '/':
target_path = join_paths(chroot_path,
link_source)
return target_path
else:
link_source = link_source.split('/')
link_dir = os.path.dirname(link_path).split('/')
if link_source[0] == '.':
link_source.pop()
else:
while link_source[0] == '..':
link_source.pop(0)
link_dir.pop(-1)
link_dir.extend(link_source)
return '/'.join(link_dir)
def read_file(file_path):
'''Функция для чтения файлов, возвращает текст файла.'''
try:
@ -401,17 +424,20 @@ def make_directory(directory_path, force=False):
return False
def check_directory_link(link_path):
def check_directory_link(link_path, chroot_path='/'):
'''Метод для проверки наличия зацикливающихся ссылок и их корректности в
целом. В случае успешной проверки возвращает целевой путь ссылки.'''
link_target = read_link(link_path)
link_target = get_target_from_link(link_path, link_target,
chroot_path=chroot_path)
if link_target is None:
# Ссылка не существует.
return False
raise FilesError('the source file does not exist')
if not os.path.isdir(link_target):
# Ссылка не на директорию.
return False
raise FilesError('the source is not directory')
linked_path = os.path.abspath(link_target)
@ -426,14 +452,20 @@ def check_directory_link(link_path):
while to_check:
current_directory = to_check.pop()
for entry in os.scandir(current_directory):
# Обходим только директории и ссылки на директории.
if not entry.is_dir():
continue
if entry.is_symlink():
linked_path = read_link(entry.path)
linked_path = get_target_from_link(entry.path,
linked_path,
chroot_path=chroot_path)
if linked_path in linked_paths:
return False
raise FilesError(
'the source directory contains cycled links')
linked_paths.add(linked_path)
to_check.append(linked_path)
else:

@ -566,6 +566,7 @@ class Package:
def __init__(self, package_atom, pkg_path='/var/db/pkg', chroot_path='/'):
self.chroot_path = chroot_path
print('chroot_path = {}'.format(self.chroot_path))
self.contents_file_path = self._get_contents_path(package_atom)
if (chroot_path != '/' and

@ -36,6 +36,16 @@ other_parameter = other_value
[!section_name]
'''
other_template_text = '''{% calculate append = 'join', format = 'bind',
autoupdate, package = 'test-category/other-package' -%}
options {
parameter_1 yes;
response-policy {
mood "almost.blue";
};
}
'''
class TemplateExecutorError(Exception):
pass
@ -1236,7 +1246,8 @@ vars_1 = Variables({'value_1': 'value_1', 'value_2': 'value_to_print',
'value_3': 5})
DATAVARS_MODULE = Variables({'vars_1': vars_1})
CHROOT_PATH = os.path.join(os.getcwd(), 'tests/templates/testfiles/test_root')
CHROOT_PATH = os.path.join(os.getcwd(),
'tests/templates/testfiles/test_wrapper_root')
CL_CONFIG_PATH = os.path.join(CHROOT_PATH, 'var/lib/calculate/config')
CL_CONFIG_ARCHIVE_PATH = os.path.join(CHROOT_PATH,
'var/lib/calculate/config-archive')
@ -1254,32 +1265,41 @@ template_engine = TemplateEngine(datavars_module=DATAVARS_MODULE,
chroot_path=CHROOT_PATH)
target_path = os.path.join(CHROOT_PATH, 'etc/dir/file.conf')
other_target_path = os.path.join(CHROOT_PATH, 'etc/other_file.conf')
run_target_path = os.path.join(CHROOT_PATH, 'file_to_run.py')
# Применение основного шаблона:
template_engine.process_template_from_string(template_text, FILE)
template_parameters = template_engine.parameters
template_text = template_engine.template_text
template_executor_obj.execute_template(target_path,
template_parameters,
FILE, template_text=template_text)
template_executor_obj.save_changes()
input()
template_engine.process_template_from_string(template_to_run, FILE)
template_parameters = template_engine.parameters
template_text = template_engine.template_text
template_executor_obj.execute_template(target_path,
template_parameters,
FILE, template_text=template_text)
template_executor_obj.save_changes()
input()
template_engine.process_template_from_string(backup_template_text, FILE)
# template_engine.process_template_from_string(template_text, FILE)
# template_parameters = template_engine.parameters
# template_text = template_engine.template_text
#
# template_executor_obj.execute_template(target_path,
# template_parameters,
# FILE, template_text=template_text)
# template_executor_obj.save_changes()
#
# input()
# template_engine.process_template_from_string(template_to_run, FILE)
# template_parameters = template_engine.parameters
# template_text = template_engine.template_text
# template_executor_obj.execute_template(target_path,
# template_parameters,
# FILE, template_text=template_text)
# template_executor_obj.save_changes()
#
# input()
# template_engine.process_template_from_string(backup_template_text, FILE)
# template_parameters = template_engine.parameters
# template_text = template_engine.template_text
# template_executor_obj.execute_template(target_path,
# template_parameters,
# FILE, template_text=template_text)
# template_executor_obj.save_changes()
template_engine.process_template_from_string(other_template_text, FILE)
template_parameters = template_engine.parameters
template_text = template_engine.template_text
template_executor_obj.execute_template(target_path,
template_executor_obj.execute_template(other_target_path,
template_parameters,
FILE, template_text=template_text)
template_executor_obj.save_changes()

@ -2,13 +2,16 @@ import pytest
import os
from calculate.templates.template_engine import ParametersContainer
from calculate.templates.template_processor import TemplateWrapper, FILE, DIR,\
TemplateTypeConflict
TemplateTypeConflict,\
TemplateCollisionError
from calculate.utils.package import PackageAtomName, Version
from calculate.utils.files import join_paths
CHROOT_PATH = os.path.join(os.getcwd(), 'tests/templates/testfiles/test_root')
TemplateWrapper.chroot_path = CHROOT_PATH
CHROOT_PATH = os.path.join(os.getcwd(),
'tests/templates/testfiles/test_wrapper_root')
CONFIG_ARCHIVE_PATH = os.path.join(CHROOT_PATH,
'/var/lib/calculate/config-archive')
test_package_name = PackageAtomName(
{'pkg_path': os.path.join(
@ -23,9 +26,12 @@ class TestTemplateWrapper:
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join',
'format': 'samba'})
template_wrapper = TemplateWrapper(join_paths(CHROOT_PATH,
'/etc/dir/file.conf'),
parameters_object, FILE)
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/file.conf'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
assert template_wrapper._protected_is_set
assert (join_paths(CHROOT_PATH, '/etc') in
@ -39,14 +45,479 @@ class TestTemplateWrapper:
mask_set.add(join_paths(CHROOT_PATH, path))
assert template_wrapper._unprotected_set == mask_set
# Тестируем проверку типов шаблонов и файлов и поиск конфликтов.
# Тесты типов.
def test_if_template_type_is_FILE_and_target_file_does_not_exist__the_TemplateWrapper_target_type_is_None(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join',
'format': 'samba'})
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/none'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
assert template_wrapper.target_type is None
assert template_wrapper.target_path == join_paths(CHROOT_PATH,
'/etc/dir/none')
def test_if_template_type_is_DIR_and_target_file_is_DIR__the_TemplateWrapper_target_type_is_DIR(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join'})
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/dir_2'),
parameters_object, DIR,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
assert template_wrapper.target_type == DIR
assert template_wrapper.target_path == join_paths(CHROOT_PATH,
'/etc/dir/dir_2')
def test_if_template_type_is_FILE_and_target_file_is_FILE__the_TemplateWrapper_target_type_is_FILE(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join',
'format': 'samba'})
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/file.conf'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
assert template_wrapper.target_type == FILE
assert template_wrapper.target_path == join_paths(CHROOT_PATH,
'/etc/dir/file.conf')
# Тесты проверки конфликтов.
# Если шаблон -- файл.
def test_if_template_type_is_FILE_and_target_file_is_FILE_and_force_parameter_is_set__the_TemplateWrapper_target_type_is_FILE_and_target_path_is_same(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join',
'format': 'samba',
'force': True})
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/file.conf'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
assert template_wrapper.target_type == FILE
assert template_wrapper.target_path == join_paths(CHROOT_PATH,
'/etc/dir/file.conf')
def test_if_template_type_is_FILE_but_target_file_is_DIR_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join',
'format': 'samba'})
with pytest.raises(TemplateTypeConflict):
template_wrapper = TemplateWrapper(join_paths(CHROOT_PATH,
'/etc/dir/dir_2'),
parameters_object, FILE)
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/dir_2'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
def test_if_template_type_is_FILE_but_target_file_is_a_link_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join',
'format': 'samba'})
with pytest.raises(TemplateTypeConflict):
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/file_link'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
def test_if_template_type_is_FILE_but_target_file_is_DIR_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join',
'format': 'samba',
'force': True})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/dir_2'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
assert template_wrapper.remove_original
def test_if_template_type_is_FILE_but_target_file_is_a_link_to_a_DIR_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join',
'format': 'samba',
'force': True})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir_link'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
assert template_wrapper.remove_original
def test_if_template_type_is_FILE_but_target_file_is_a_link_to_a_FILE_and_force_parameter_is_set__the_TemplateWrapper_changes_its_target_path_to_the_link_source_file(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join',
'format': 'samba',
'force': True})
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/file_link'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
assert template_wrapper.target_path_is_changed
assert template_wrapper.target_path == join_paths(CHROOT_PATH,
'/etc/file')
# Если шаблон -- директория.
def test_if_template_type_is_DIR_and_target_file_is_DIR_and_force_parameter_is_set__the_TemplateWrapper_target_type_is_DIR_and_target_path_is_the_same(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join',
'force': True})
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/dir_2'),
parameters_object, DIR,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
assert template_wrapper.target_type == DIR
assert template_wrapper.target_path == join_paths(CHROOT_PATH,
'/etc/dir/dir_2')
def test_if_template_type_is_DIR_and_target_file_is_a_link_to_a_DIR_and_force_parameter_is_not_set__the_TemplateWrapper_changes_its_target_path_to_the_link_source_file(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join'})
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir_link'),
parameters_object, DIR,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
assert template_wrapper.target_path_is_changed
assert template_wrapper.target_path == join_paths(CHROOT_PATH,
'/etc/dir/dir_2')
def test_if_template_type_is_DIR_but_target_file_is_FILE_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join',
'format': 'samba'})
with pytest.raises(TemplateTypeConflict):
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/file.conf'),
parameters_object, DIR,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
def test_if_template_type_is_DIR_and_target_file_is_a_link_to_a_file_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join',
'format': 'samba'})
with pytest.raises(TemplateTypeConflict):
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/file_link'),
parameters_object, DIR,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
def test_if_template_type_is_DIR_and_target_file_is_FILE_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join',
'force': True})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/file.conf'),
parameters_object, DIR,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
assert template_wrapper.remove_original
def test_if_template_type_is_DIR_and_target_file_is_the_link_to_a_FILE_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join',
'force': True})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/file_link'),
parameters_object, DIR,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
def test(self):
assert template_wrapper.remove_original
def test_if_template_type_is_DIR_and_target_file_is_the_link_to_a_DIR_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join',
'force': True})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir_link'),
parameters_object, DIR,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
assert template_wrapper.remove_original
# Если шаблон создает ссылку.
def test_if_template_type_is_FILE_with_the_append_link_parameter_and_target_file_is_the_link_to_a_FILE__the_TemplateWrapper_sets_remove_original_flag(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'link'})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/file_link'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
assert template_wrapper.remove_original
def test_if_template_type_is_FILE_with_the_append_link_parameter_and_target_file_is_the_link_to_a_DIR__the_TemplateWrapper_sets_remove_original_flag(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'link'})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir_link'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
assert template_wrapper.remove_original
def test_if_template_type_is_DIR_with_the_append_link_parameter_and_target_file_is_the_link_to_a_FILE__the_TemplateWrapper_sets_remove_original_flag(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'link'})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/file_link'),
parameters_object, DIR,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
assert template_wrapper.remove_original
def test_if_template_type_is_DIR_with_the_append_link_parameter_and_target_file_is_the_link_to_a_DIR__the_TemplateWrapper_sets_remove_original_flag(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'link'})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir_link'),
parameters_object, DIR,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
assert template_wrapper.remove_original
def test_if_template_type_is_FILE_with_the_append_link_parameter_and_target_file_is_FILE_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'link'})
with pytest.raises(TemplateTypeConflict):
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/file.conf'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
def test_if_template_type_is_FILE_with_the_append_link_parameter_and_target_file_is_DIR_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'link'})
with pytest.raises(TemplateTypeConflict):
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/dir_2'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
def test_if_template_type_is_DIR_with_the_append_link_parameter_and_target_file_is_FILE_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'link'})
with pytest.raises(TemplateTypeConflict):
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/file.conf'),
parameters_object, DIR,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
def test_if_template_type_is_DIR_with_the_append_link_parameter_and_target_file_is_DIR_and_force_parameter_is_not_set__the_TemplateWrapper_throws_TemplateTypeConflict_exception(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'link'})
with pytest.raises(TemplateTypeConflict):
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/dir_2'),
parameters_object, DIR,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
def test_if_template_type_is_FILE_with_the_append_link_parameter_and_target_file_is_FILE_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'link',
'force': True})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/file.conf'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
assert template_wrapper.remove_original
def test_if_template_type_is_FILE_with_the_append_link_parameter_and_target_file_is_DIR_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'link',
'force': True})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/dir_2'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
assert template_wrapper.remove_original
def test_if_template_type_is_DIR_with_the_append_link_parameter_and_target_file_is_FILE_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'link',
'force': True})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/file.conf'),
parameters_object, DIR,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
assert template_wrapper.remove_original
def test_if_template_type_is_DIR_with_the_append_link_parameter_and_target_file_is_DIR_and_force_parameter_is_set__the_TemplateWrapper_sets_remove_original_flag(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'link',
'force': True})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/dir_2'),
parameters_object, DIR,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
assert template_wrapper.remove_original
# Тестируем определитель пакетов и проверку на коллизии.
def test_if_template_contains_append_parameters_but_does_not_have_package_parameter_and_target_file_does_not_belong_to_any_package__the_TemplateWrapper_throws_TemplateCollisionError_exception(self):
parameters_object = ParametersContainer({'append': 'join'})
with pytest.raises(TemplateCollisionError):
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/file'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
def test_if_template_contains_package_parameter_and_target_file_does_not_belong_to_any_package__the_TemplateWrapper_uses_package_from_parameter_and_sets_target_without_package_flag(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join'})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/file'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
assert template_wrapper.target_without_package
def test_if_template_does_not_have_package_parameter_but_target_file_belongs_to_the_package__the_TemplateWrapper_uses_package_from_parameter(self):
parameters_object = ParametersContainer({'append': 'join'})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/file.conf'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
assert not template_wrapper.target_without_package
assert template_wrapper.target_package_name == test_package_name
def test_if_template_contains_package_parameter_and_target_file_belongs_to_the_package_from_package_parameter__the_TemplateWrapper_uses_package_from_them(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join'})
try:
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/file.conf'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
pytest.fail("Unexpected exception: {}".format(str(error)))
assert template_wrapper.target_package_name == test_package_name
def test_if_template_contains_package_parameter_but_target_file_belongs_to_the_other_package__the_TemplateWrapper_throws_TemplateCollisionError(self):
parameters_object = ParametersContainer({'package': test_package_name,
'append': 'join'})
with pytest.raises(TemplateCollisionError):
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/other_file.conf'),
parameters_object, FILE,
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
def test_contents_init(self):
pass
# Тестируем проверку наличия пользовательских изменений.

@ -1,3 +1,3 @@
dir /etc
dir /etc/dir
obj /etc/dir/file.conf 0b87fea7f5b65cac5012baa2bf647e72 1591105584
obj /etc/dir/file.conf 0b87fea7f5b65cac5012baa2bf647e72 1591282135

@ -0,0 +1,7 @@
options {
parameter_1 yes;
response-policy {
mood "almost.blue";
};
};

@ -1 +0,0 @@
{% calculate append = 'skip', action = 'install' %}

@ -1 +0,0 @@
{% calculate append = 'skip', path = '/', package = 'media-sound/alsa-utils' %}

@ -1,6 +0,0 @@
{% calculate name = 'important.conf', autoupdate -%}
relay_domains = {{ merge.calculate_domains }}
#Для создания базы используется postmap
transport_maps = hash:/etc/postfix/transport_maps
relay_recipient_maps = hash:/etc/postfix/valid_recipients

@ -1,5 +0,0 @@
{% calculate format = 'json', append = 'join', force -%}
{
"!parameter_1": "important_value",
"parameter_2": {{ os_disk_dev }}
}

@ -1,2 +0,0 @@
{% calculate append = 'join', autoupdate %}
{% calculate pkg() > '1.1.0' %}

@ -1,10 +0,0 @@
{% calculate format = 'kde', path = '/etc/folder/in_folder', name = 'filename.conf' -%}
# KDE or Plasma config file.
# Part from Plasma
[PlasmaViews][Panel 69][Horizontal1024]
alignment={{ install.number }}
length={{ merge.var_1 }}
maxLength={{ merge.var_1 }}
minLength={{ merge.var_1 }}
panelVisibility=1
thickness={{ merge.var_2 }}

@ -1,4 +0,0 @@
{% calculate name = 'settings.conf', mirror, format = 'postfix' -%}
special_directory = /var/any/important/path
command_directory = {{ install.path }}

@ -1 +0,0 @@
{% calculate append = 'skip', path = '/etc', package = 'media-sound/pulseaudio' %}

@ -1,14 +0,0 @@
{% calculate format = 'kde' %}
{% calculate path = file_path %}
{% calculate merge = 'media-sound/alsa-utils' %}
{% set file_path = test.test_root + '/test_root/conf_dir'%}
[section][parts][of][section name]
parameter 1 = {{ variables.variable_1 }}
parameter 2 = {{ variables.variable_2 }}
# Random comment.
parameter 3 = very important and veery interesting value
{% for num in variables.group.list -%}
statement {{ num }} = {{ num * 2 - 1 }}
{% endfor -%}

@ -1 +0,0 @@
{% calculate append = 'skip', package = 'xfce-extra/xfce4-clipman-plugin' %}

@ -1,10 +0,0 @@
{% calculate name = 'wow_file.conf', force, format = 'samba',
path = '/etc/xfce4-clipman/' -%}
[global]
server role = standalone server
hosts allow = 192.168.1. 192.168.2. 127.
log file = /var/log/samba/log.%m
workgroup = {{ variables.variable_1 }}
netbios name = {{ variables.variable_2 }}
server string = Calculate Directory Server
directory mask = 0755

@ -1,2 +0,0 @@
{% calculate append = 'skip', package = 'xfce-extra/xfce4-pulseaudio-plugin' %}
{% calculate merge = 'media-sound/pulseaudio' %}

@ -1,7 +0,0 @@
{% calculate name = 'template', format = 'bind', append = 'before' -%}
acl "trusted" {
{{ merge.ip_value }};
10.0.0.0/8;
192.168.1.0/24;
::1/128;
};

@ -1,10 +0,0 @@
{% calculate format='xml_xfce', mirror -%}
{% save custom.group.parameter = 'DoubleClickTime' -%}
<?xml version="1.0" encoding="UTF-8"?>
<channel name="xsettings" version="{{ version }}">
<property name="Net" type="empty">
<property name="ThemeName" type="string" value="Calculate"/>
<property name="IconThemeName" type="string" value="Calculate"/>
<property name="{{ custom.group.parameter }}" type="int" value="400"/>
</property>
</channel>

@ -1,10 +0,0 @@
{% calculate format='xml_xfce', force, autoupdate -%}
<?xml version="1.0" encoding="UTF-8"?>
<channel name="xsettings" version="{{ version }}">
<property name="Gtk" type="empty">
<property name="FontName" type="string" value="Droid Sans 10"/>
<property name="CursorThemeName" type="string" value="Calculate"/>
<property name="{{ custom.group.parameter }}" type="bool" value="false"/>
</property>
<property name="!Xft" type="empty"/>
</channel>

@ -0,0 +1,2 @@
dir /etc
obj /etc/other_file.conf 61b82a7891c5233b92a5bde68535a71d 1591282672

@ -0,0 +1,7 @@
options {
parameter_1 yes;
response-policy {
mood "almost.blue";
};
};
Loading…
Cancel
Save