Method for append = 'join' for files is almost implemented.

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

@ -32,7 +32,7 @@ class PackageNotFound(Exception):
class Version:
'''Временный класс для работы со значениями версий.'''
'''Класс для работы со значениями версий.'''
def __init__(self, version_value=None):
if version_value is None:
self._version_string = '-1'
@ -55,6 +55,8 @@ class Version:
self._version_value = value
def _get_version_value(self, version):
'''Вспомогательный метод для получения значения версии, представленного
в виде списка.'''
if isinstance(version, Version):
return version._version_value
@ -88,6 +90,8 @@ class Version:
return version_value
def _use_compare_operation(self, compare_operator, other_value):
'''Вспомогательный метод для реализации различных операций сравнения.
'''
version_value = self._version_value[:]
other_value_length = len(other_value)
@ -193,6 +197,8 @@ class Version:
class PackageAtomName:
'''Класс для хранения результата определения пакета. Для определения пакета
использует путь к его pkg директории.'''
def __init__(self, atom_dictionary):
self._package_directory = atom_dictionary['pkg_path']
self._version = atom_dictionary['version']
@ -261,6 +267,8 @@ class PackageAtomName:
class PackageAtomParser:
'''Класс для парсинга параметра package, его проверки, а также определения
принадлежности файла пакету.'''
package_name_pattern =\
r'(?P<name>\D[\w\d]*(\-\D[\w\d]*)*)(?P<version>-\d[^\s:]*)?'
@ -286,6 +294,8 @@ class PackageAtomParser:
self._atom_dictionary = {}
def parse_package_parameter(self, package_atom):
'''Метод для разбора значения package, после разбора инициирует
проверку полученных значений. Возвращает объект PackageAtomName.'''
self.package_atom = package_atom
self._atom_dictionary = {}
@ -328,6 +338,8 @@ class PackageAtomParser:
return atom_name_object
def _check_package_existance(self, package_atom=''):
'''Метод для проверки существования пакета. Существование пакета
определяется наличием соответствующего CONTENTS файла.'''
if package_atom:
self.parse_package_parameter(package_atom)
return True
@ -400,6 +412,8 @@ class PackageAtomParser:
self._atom_dictionary['version'] = packages[pkg_path]
def _check_slot_value(self, pkg_path):
'''Метод для проверки полученного из параметра package значения slot.
'''
if 'slot' in self._atom_dictionary:
slot = self._get_slot_value(pkg_path)
@ -410,6 +424,8 @@ class PackageAtomParser:
errno=NOTEXIST)
def _check_use_flags_value(self, pkg_path):
'''Метод для проверки полученных из параметра package значений
use-флагов.'''
if 'use_flags' in self._atom_dictionary:
use_flags = self._get_use_flags_value(pkg_path)
@ -422,6 +438,7 @@ class PackageAtomParser:
errno=NOTEXIST)
def _get_slot_value(self, pkg_path):
'''Метод для получения значения slot из файла SLOT.'''
slot_path = os.path.join(pkg_path, 'SLOT')
try:
return read_file(slot_path).strip('\n')
@ -430,6 +447,7 @@ class PackageAtomParser:
" 'package': {}".format(self.package_atom))
def _get_use_flags_value(self, pkg_path):
'''Метод для получения списка значений use-флагов из файла USE.'''
use_path = os.path.join(pkg_path, 'USE')
try:
return read_file(use_path).strip('\n').split(' ')
@ -438,11 +456,14 @@ class PackageAtomParser:
" parameter: {}".format(self.package_atom))
def _get_category_packages(self, category):
'''Генератор имен категорий, имеющихся в /var/db/pkg'''
for path in glob.glob('{0}/{1}/*/CONTENTS'.format(self.pkg_path,
category)):
yield path
def get_file_package(self, file_path):
'''Метод для определения пакета, которому принадлежит файл.'''
# Удаляем часть пути соответствующую chroot_path
if self.chroot_path != '/' and file_path.startswith(self.chroot_path):
file_path = file_path[len(self.chroot_path):]
@ -595,7 +616,7 @@ class Package:
contents_item = OrderedDict({'type': 'dir'})
self.contents_dictionary[file_name] = contents_item
def add_sym(self, file_name):
def add_sym(self, file_name, target_path=None):
file_name = self.remove_cfg_prefix(file_name)
real_path = file_name
@ -604,18 +625,23 @@ class Package:
if real_path == file_name:
real_path = join_paths(self.chroot_path, file_name)
if target_path is None:
target = read_link(real_path)
else:
target = target_path
self.add_dir(os.path.dirname(file_name))
mtime = str(int(os.lstat(real_path).st_mtime))
try:
contents_item = OrderedDict({'type': 'sym',
'target': read_link(real_path),
'target': target,
'mtime': mtime})
except FilesError as error:
raise PackageError(str(error))
self.contents_dictionary[file_name] = contents_item
def add_obj(self, file_name):
def add_obj(self, file_name, file_md5=None):
file_name = self.remove_cfg_prefix(file_name)
real_path = file_name
@ -624,14 +650,17 @@ class Package:
if real_path == file_name:
real_path = join_paths(self.chroot_path, file_name)
self.add_dir(os.path.dirname(file_name))
try:
file_text = read_file(real_path).encode()
except FilesError as error:
raise PackageError(str(error))
if file_md5 is not None:
md5_value = file_md5
else:
try:
file_text = read_file(real_path).encode()
except FilesError as error:
raise PackageError(str(error))
md5_value = hashlib.md5(file_text).hexdigest()
contents_item = OrderedDict({'type': 'obj',
'md5': hashlib.md5(file_text).hexdigest(),
'md5': md5_value,
'mtime':
str(int(os.lstat(real_path).st_mtime))})
self.contents_dictionary[file_name] = contents_item

@ -97,7 +97,6 @@ class CalculateConfigFile:
def set_files_md5(self, file_path, file_md5):
file_path = self._remove_chroot(file_path)
self._config_dictionary[file_path] = file_md5
self._unsaved_changes = True
def remove_file(self, file_path):
@ -108,7 +107,10 @@ class CalculateConfigFile:
def compare_md5(self, file_path, file_md5):
file_path = self._remove_chroot(file_path)
return self._config_dictionary[file_path] == file_md5
if file_path in self._config_dictionary:
return self._config_dictionary[file_path] == file_md5
else:
return False
def save_changes(self):
config_file = write_file(self.cl_config_path)
@ -144,7 +146,6 @@ class TemplateWrapper:
config_archive_path = '/var/lib/calculate/config-archive'
package_atom_parser = PackageAtomParser(chroot_path=chroot_path)
calculate_config_file = CalculateConfigFile()
_protected_is_set = False
_protected_set = {'/etc'}
@ -156,6 +157,10 @@ class TemplateWrapper:
self.target_package_name = None
# Вспомогательный флаг, включается, если по целевому пути лежит файл,
# для которого не определился никакой пакет.
self.target_without_package = False
self.parameters = parameters
self.output_path = self.target_path
@ -168,18 +173,8 @@ class TemplateWrapper:
# применением шаблона.
self.remove_original = False
# Флаг, разрешающий изменение хэш-суммы в contents после отработки
# шаблона.
self.update_contents = False
self.update_config = False
self.update_archive = False
# Флаг, указывающий, что нужно удалить все имеющиеся ._cfg????_filename
# файлы.
self.clean_cfg = False
self.clean_config = False
self.check_config = False
# Временный флаг для определения того, является ли шаблон userspace.
self.is_userspace = False
# Получаем класс соответствующего формата файла.
if self.parameters.format:
@ -271,109 +266,90 @@ class TemplateWrapper:
'''Проверка на предмет коллизии, то есть конфликта пакета шаблона и
целевого файла.'''
if self.parameters.package:
self.target_package_name = self.parameters.package
if self.target_type is None:
return
parameter_package = self.parameters.package
else:
parameter_package = None
try:
file_package = self.package_atom_parser.get_file_package(
if self.target_type is not None:
try:
file_package = self.package_atom_parser.get_file_package(
self.target_path)
except PackageNotFound:
return
if self.target_package_name is None:
except PackageNotFound:
file_package = None
self.target_without_package = True
else:
file_package = None
# Если для шаблона и целевого файла никаким образом не удается
# определить пакет и есть параметр append -- шаблон пропускаем.
if parameter_package is None and file_package is None:
if self.parameters.append:
raise TemplateCollisionError(
"'package' parameter is not defined for"
" template with 'append' parameter.")
if parameter_package is None:
self.target_package_name = file_package
elif file_package != self.target_package_name:
if file_package is None:
self.target_package_name = parameter_package
if file_package != parameter_package:
raise TemplateCollisionError(
"The template package is {0} while target"
" file package is {1}").format(
self.target_package_name.atom,
file_package.atom
)
else:
self.target_package_name = parameter_package
self.target_package = Package(self.target_package_name,
chroot_path=self.chroot_path)
def check_user_changes(self):
if (self.template_type is None or
if self.target_type is None:
self.md5_matching = True
elif self.target_without_package:
if self.parameters.autoupdate:
self.md5_matching = True
self.remove_original = True
else:
self.md5_matching = False
if (self.target_type is None or
self.target_package is None or
self.target_type != FILE):
return
# Собираем список имеющихся ._cfg файлов.
cfg_pattern = os.path.join(os.path.dirname(self.target_path),
"._cfg????_{}".format(
os.path.basename(self.target_path)))
self.cfg_list = glob.glob(cfg_pattern)
target_md5 = self.target_package.get_md5(self.target_path)
md5_comparision_result = self.target_package.is_md5_equal(
self.md5_matching = self.target_package.is_md5_equal(
self.target_path,
file_md5=target_md5)
self.md5_matching = self.md5_matching or self.parameters.autoupdate
self.archive_path = self._get_archive_path(self.target_path)
if (self.parameters.autoupdate or md5_comparision_result):
if not self.cfg_list:
# Приоритет отдаем пути из параметра source.
if self.parameters.source:
self.input_path = self.parameters.source
else:
self.input_path = self.target_path
self.output_path = self.target_path
# Чем обновляем CONTENTS
self.update_contents = self.target_path
# Обновляем CA
# Должна быть какая-то проверка на предмет userspace.
self.update_archive = self._get_archive_path(self.target_path)
# Очищаем CL
self.clean_config = True
if self.md5_matching:
# Приоритет отдаем пути из параметра source.
if self.parameters.source:
self.input_path = self.parameters.source
else:
# Приоритет отдаем пути из параметра source.
if self.parameters.source:
self.input_path = self.parameters.source
else:
self.input_path = self.target_path
self.output_path = self.target_path
# Чем обновляем CONTENTS
self.update_contents = self.target_path
self.input_path = self.target_path
# Обновляем CA
# Должна быть какая-то проверка на предмет userspace.
self.update_archive = self._get_archive_path(self.target_path)
# Очищаем CL
self.clean_config = True
# Убираем имеющиеся ._cfg????_filename
self.clean_cfg = True
self.output_path = self.target_path
else:
if not self.cfg_list:
# Приоритет отдаем пути из параметра source.
if self.parameters.source:
self.input_path = self.parameters.source
else:
self.input_path = self._get_archive_path(self.target_path)
self.output_path = self._get_cfg_path(self.target_path)
# Чем обновляем CONTENTS
self.update_contents = self.output_path
# Oбновляем хэш-сумму в CL
self.update_config = self.output_path
self.check_config = True
# Приоритет отдаем пути из параметра source.
if self.parameters.source:
self.input_path = self.parameters.source
else:
# Приоритет отдаем пути из параметра source.
if self.parameters.source:
self.input_path = self.parameters.source
else:
self.input_path = self._get_archive_path(self.target_path)
self.output_path = self._get_cfg_path(self.target_path)
# Чем обновляем CONTENTS
self.update_contents = self.output_path
# Обновляем хэш-сумму в CL
self.update_config = self.output_path
self.input_path = self.archive_path
self.check_config = True
self.output_path = self._get_cfg_path(self.target_path)
def _get_archive_path(self, file_path):
if self.chroot_path != "/" and file_path.startswith(self.chroot_path):
@ -399,32 +375,16 @@ class TemplateWrapper:
return new_cfg_path
def _update_contents(self):
def remove_from_contents(self):
pass
def use_format(self):
if self.format_class.EXECUTABLE:
# Для исполняемых форматов.
return
if self.target_type is None:
original_file_text = ''
else:
original_file = open(target_path, 'r')
original_file_text = original_file.read()
original_file.close()
original_file = open(target_path, 'w')
original_object = self.format_class(original_file_text)
template_object = self.format_class(self.template_text)
original_object.join_template(template_object)
original_file.write(original_object.document_text)
original_file.close()
def accept_changes(self):
pass
def add_to_contents(self, file_md5=None):
if self.parameters.append == 'link':
self.target_package.add_sym(target_path, self.parameters.source)
elif self.template_type == DIR:
self.target_package.add_dir(target_path)
elif self.template_type == FILE:
self.target_package.add_obj(target_path, file_md5)
@classmethod
def _set_protected(cls):
@ -464,12 +424,12 @@ class TemplateExecutor:
self.file_appends = {'join': self._append_join_file}
self.formats_classes = ParametersProcessor.available_formats
self.calculate_config_file = CalculateConfigFile(
cl_config_path=cl_config_path,
cl_chroot_path=chroot_path)
TemplateWrapper.chroot_path = self.chroot_path
TemplateWrapper.cl_config_archive = cl_config_archive
TemplateWrapper.calculate_config_file = CalculateConfigFile(
cl_config_path=cl_config_path,
cl_chroot_path=chroot_path)
@property
def available_appends(self):
@ -483,64 +443,119 @@ class TemplateExecutor:
print('Template parameters:')
parameters.print_parameters_for_debug()
# try:
template_object = TemplateWrapper(target_path, parameters,
template_type,
template_text=template_text)
# except TemplateTypeConflict as error:
# pass
try:
template_object = TemplateWrapper(target_path, parameters,
template_type,
template_text=template_text)
except TemplateTypeConflict as error:
print('type conflict: {}'.format(str(error)))
except TemplateCollisionError as error:
print('collision: {}'.format(str(error)))
if template_object.remove_original:
if template_object.target_type == DIR:
self._remove_directory(template_object.target_path)
else:
self._remove_file(template_object.target_path)
template_object.target_type = None
# Добавить поддержку run, excute и т.д.
self.directory_appends[template_object.parameters.append](
if template_object.template_type == DIR:
self.directory_appends[template_object.parameters.append](
template_object)
elif template_object.template_type == FILE:
self.file_appends[template_object.parameters.append](
template_object)
def _append_join_directory(self, template_object: TemplateWrapper):
pass
if template_object.target_type is None:
self._create_directory(template_object)
template_object.add_to_contents()
else:
pass
def _append_remove_directory(self, template_object: TemplateWrapper):
pass
if template_object.target_type is not None:
self._remove_directory(template_object.target_path)
template_object.remove_from_contents()
else:
pass
def _append_clear_directory(self, template_object: TemplateWrapper):
pass
if template_object.target_type is not None:
# Подумать об организации очистки CONTENTS для этого append.
pass
def _append_join_file(self, template_object: TemplateWrapper):
'''Метод описывающий действия при append = "join".'''
input_path = template_object.input_path
output_path = template_object.output_path
template_format = template_object.format_class
with open(input_path, 'r') as input_file:
input_text = input_file.read()
if template_object.md5_matching:
output_paths = [output_path]
# Проверка на предмет userspace.
if template_object.is_userspace:
output_paths.append(template_object.archive_path)
if template_object.target_type is not None:
with open(input_path, 'r') as input_file:
input_text = input_file.read()
else:
input_text = ''
parsed_input = template_format(input_text)
parsed_template = template_format(template_object.template_text)
parsed_input.join_template(parsed_template)
parsed_template = template_format(template_object.template_text)
parsed_input.join_template(parsed_template)
output_text = parsed_input.document_text
changed_file_md5 = hashlib.md5(output_text.encode()).hexdigest()
# Результат наложения шаблона.
output_text = parsed_input.document_text
# Удаляем форматный объект входного файла.
del(parsed_input)
output_text_md5 = hashlib.md5(output_text.encode()).hexdigest()
with open(output_path, 'w') as output_file:
output_file.write(parsed_input.document_text)
for save_path in output_paths:
with open(save_path, 'w') as output_file:
output_file.write(output_text)
if template_object.clean_cfg:
for cfg_file_path in template_object.cfg_list:
self._remove_file(cfg_file_path)
# Убираем все ._cfg файлы.
if template_object.cfg_list:
for cfg_file_path in template_object.cfg_list:
self._remove_file(cfg_file_path)
if template_object.update_archive:
with open(template_object.update_archive, 'r') as ca_file:
ca_text = ca_file.read()
parsed_ca = template_format(ca_text)
# Убираем целевой файл из CL.
self.calculate_config_file.remove_file(template_object.target_path)
parsed_ca.join_template(parsed_template)
ca_text = parsed_ca.document_text
# Обновляем CONTENTS.
template_object.add_to_contents(file_md5=output_text_md5)
else:
with open(input_path, 'r') as input_file:
input_text = input_file.read()
parsed_input = template_format(input_text)
parsed_template = template_format(template_object.template_text)
parsed_input.join_template(parsed_template)
# Результат наложения шаблона.
output_text = parsed_input.document_text
# Удаляем форматный объект входного файла.
del(parsed_input)
output_text_md5 = hashlib.md5(output_text.encode()).hexdigest()
if not self.calculate_config_file.compare_md5(target_path,
output_text_md5):
with open(output_path, 'w') as output_file:
output_file.write(output_text)
self.calculate_config_file.set_files_md5(template_object,
output_text_md5)
else:
# Действия если CL совпало. Пока ничего не делаем.
pass
template_object._update_contents()
# Обновляем CONTENTS.
template_object.add_to_contents(file_md5=output_text_md5)
def _create_directory(self, template_object: TemplateWrapper):
target_path = template_object.target_path

Loading…
Cancel
Save