Now save tag can save variables to the calculate.ini files. Tested adding to calculate ini file of hash and simple variables. Developing of the errors processing is started.

packages
Иванов Денис 4 years ago
parent 970f19cd3b
commit a2ce6f87f7

@ -19,8 +19,7 @@ from ..utils.files import join_paths, check_directory_link, check_command,\
FilesError
from calculate.variables.datavars import HashType, NamespaceNode,\
VariableNode, IniType, IntegerType,\
FloatType, ListType,\
VariableNotFoundError
FloatType, ListType
# Типы шаблона: директория или файл.
@ -852,7 +851,7 @@ class CalculateExtension(Extension):
self.CONDITION_TOKENS_TYPES):
# разбираем параметр.
# pairs_list.append(self.get_parameter_node())
name_node, value_node = self.get_parameter()
name_node, value_node = self._get_parameter()
check_node = self.call_method('check_parameter',
[name_node,
@ -977,11 +976,6 @@ class CalculateExtension(Extension):
optype, context):
'''Метод для сохранения значений переменных указанных в теге save.'''
datavars = context.parent['__datavars__']
optypes = {self.ASSIGN: '=', self.APPEND: '+=', self.REMOVE: '-='}
print('SAVE VARIABLE: {} {} {}'.format('.'.join(variable),
optypes[optype],
right_value))
print('TARGET FILE: {}'.format(target_file))
if variable[0] not in datavars:
raise SaveError("can not save variable '{}'. The variable's"
" package '{}' is not found".format(
@ -989,12 +983,42 @@ class CalculateExtension(Extension):
variable[0]))
modify_only = (variable[0] != 'custom')
current_container = datavars[variable[0]]
variable_path = variable[1:]
variable_name = variable_path.pop()
package = datavars[variable[0]]
variable_name = variable[-1]
value_container = self._find_value_container(variable, package,
modify_only=modify_only)
# Теперь меняем знaчение переменной.
if isinstance(value_container, NamespaceNode):
self._modify_variables(variable, value_container, right_value,
optype, target=target_file,
modify_only=modify_only)
elif isinstance(value_container, VariableNode):
hash_value = value_container.get_value().get_hash()
if variable_name in hash_value:
if optype == self.ASSIGN:
new_value = right_value
elif optype == self.APPEND:
new_value = new_value + right_value
elif optype == self.REMOVE:
new_value = new_value - right_value
else:
new_value = right_value
hash_value.update({variable_name: new_value})
value_container.set(hash_value)
if target_file:
self._save_to_target(variable[:-1], variable_name,
new_value, target_file)
return ''
def _find_value_container(self, variable, vars_package, modify_only=True):
'''Метод для поиска контейнера, путь к которому указан в аргументе.
Этим контейнером может быть пространство имен или хэш.'''
current_container = vars_package
variable_path = variable[1:-1]
# Ищем пространство имен или в хэш, в котором должна быть переменная
# или значение.
for section in variable_path:
if section in current_container.namespaces:
current_container = current_container.namespaces[section]
@ -1003,7 +1027,7 @@ class CalculateExtension(Extension):
current_container = current_container.variables[section]
if section != variable_path[-1]:
# Если обнаружен хэш, но в пути к переменной кроме ключа
# хэша есть что-то еще -- значит путь к переменной
# хэша есть еще что-то далее -- значит путь к переменной
# ошибочен.
raise SaveError("can not save variable '{}'. Other"
" variable '{}' on the path".format(
@ -1018,57 +1042,64 @@ class CalculateExtension(Extension):
'.'.join(variable),
section,
current_container.get_fullname()))
# Теперь меняем знaчение переменной.
if isinstance(current_container, NamespaceNode):
if variable_name in current_container.variables:
variable_node = current_container[variable_name]
if optype == self.ASSIGN:
variable_node.set(right_value)
elif optype == self.APPEND:
new_value = self._append_variable_value(variable_node,
right_value)
variable_node.set(new_value)
elif optype == self.REMOVE:
new_value = self._remove_variable_value(variable_node,
right_value)
variable_node.set(new_value)
if target_file:
self.save_to_target(variable[:-1], variable_name,
new_value, target_file)
elif not modify_only:
VariableNode(variable_name, current_container,
variable_type=IniType, source=str(right_value))
if target_file:
self.save_to_target(variable[:-1], variable_name,
right_value, target_file)
else:
raise SaveError("can not create variable '{}' in the not"
" 'custom' namespace".
format('.'.join(variable)))
elif isinstance(current_container, VariableNode):
hash_value = current_container.get_value().get_hash()
if variable_name in hash_value:
if optype == self.ASSIGN:
new_value = right_value
elif optype == self.APPEND:
new_value = new_value + right_value
elif optype == self.REMOVE:
new_value = new_value - right_value
return current_container
def _modify_variables(self, variable, namespace, new_value, optype,
target='', modify_only=True):
'''Метод для модификации значения переменной.'''
variable_name = variable[-1]
if variable_name in namespace.variables:
variable_node = namespace[variable_name]
if optype == self.ASSIGN:
variable_node.set(new_value)
elif optype == self.APPEND:
new_value = self._append_variable_value(variable_node,
new_value)
variable_node.set(new_value)
elif optype == self.REMOVE:
new_value = self._remove_variable_value(variable_node,
new_value)
variable_node.set(new_value)
elif not modify_only:
VariableNode(variable_name, namespace,
variable_type=IniType, source=str(new_value))
else:
raise SaveError("can not create variable '{}' in the not"
" 'custom' namespace".
format('.'.join(variable)))
if target:
if namespace.variables[variable_name].variable_type is HashType:
for key, value in new_value.items():
self._save_to_target(variable, key, value, target)
else:
new_value = right_value
hash_value.update({variable_name: new_value})
current_container.set(hash_value)
if target_file:
self.save_to_target(variable[:-1], variable_name,
new_value, target_file)
print('VARIABLE IS SAVED')
return ''
def save_to_target(self, namespace_name, variable_name, value, target):
self._save_to_target(variable[:-1], variable_name,
new_value, target)
def _modify_hash(self, variable, hash_variable, new_value, optype,
target=''):
'''Метод для модификации значения в переменной-хэше.'''
value_name = variable[-1]
hash_value = hash_variable.get_value().get_hash()
if value_name in hash_value:
if optype == self.APPEND:
new_value = hash_value[value_name] + new_value
elif optype == self.REMOVE:
new_value = hash_value[value_name] - new_value
hash_value.update({value_name: new_value})
hash_variable.set(hash_value)
if target:
self._save_to_target(variable[:-1], value_name,
new_value, target)
def _save_to_target(self, namespace_name, variable_name, value, target):
'''Метод для добавления переменной в список переменных, значение
которых было установлено через тег save и при этом должно быть
сохранено в указанном файле: save.target_file.'''
namespace_name = tuple(namespace_name)
target_file_dict = self._datavars.variables_to_save[target]
if namespace_name not in target_file_dict:
@ -1083,6 +1114,7 @@ class CalculateExtension(Extension):
variable.variable_type is FloatType):
variable_value += value
return variable_value
elif variable.variable_type is ListType:
if isinstance(value, str):
value = value.split(',')
@ -1093,6 +1125,7 @@ class CalculateExtension(Extension):
else:
variable_value.append(value)
return variable_value
elif variable.variable_type is IniType:
if not isinstance(variable_value, str):
variable_value = str(variable_value)
@ -1115,10 +1148,12 @@ class CalculateExtension(Extension):
def _remove_variable_value(self, variable, value):
'''Метод описывающий операцию -= в теге save.'''
variable_value = variable.get_value()
if (variable.variable_type is IntegerType or
variable.variable_type is FloatType):
variable_value -= value
return variable_value
elif variable.variable_type is ListType:
if isinstance(value, str):
value = value.split(',')
@ -1129,6 +1164,7 @@ class CalculateExtension(Extension):
elif value in variable_value:
variable_value.remove(value)
return variable_value
elif variable.variable_type is IniType:
if not isinstance(variable_value, list):
if not isinstance(variable_value, str):
@ -1149,8 +1185,8 @@ class CalculateExtension(Extension):
# значение.
return variable_value
def get_parameter(self):
'''Метод для разбра параметров, содержащихся в теге calculate.'''
def _get_parameter(self):
'''Метод для разбора параметров, содержащихся в теге calculate.'''
lineno = self.stream.current.lineno
parameter_name = self.stream.expect('name').value
@ -1177,7 +1213,12 @@ class CalculateExtension(Extension):
return ''
@contextfunction
def pkg(self, context, *args):
def pkg(self, context, *args) -> Version:
'''Метод, реализующий функцию pkg() шаблонов. Функция предназначена для
получения версии пакета, к которому уже привязан шаблон, если
аргументов нет, или версию пакета в аргументе функции. Если аргументов
нет, а шаблон не привязан к какому-либо пакету, или если указанного в
аргументе пакета нет -- функция возвращает пустой объект Version().'''
package_atom_parser = PackageAtomParser()
if args:

@ -1,7 +1,6 @@
# vim: fileencoding=utf-8
#
from pprint import pprint
from typing import Tuple
from ..utils.package import PackageAtomParser, Package, PackageNotFound,\
PackageAtomName, Version
from ..utils.files import join_paths, write_file, read_file_lines, FilesError,\
@ -21,7 +20,6 @@ import errno
import stat
import glob
import copy
import re
import os
@ -723,30 +721,6 @@ class TemplateExecutor:
# Пока сохраняем только получившееся содержимое config-файла.
self.calculate_config_file.save_changes()
def _get_header_and_file_text(self, input_text: str, target_path: str,
target_format: Format, template_path: str):
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<template_paths>({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) -> None:
'''Метод описывающий действия для append = "join", если шаблон --
директория. Создает директорию, если ее нет.'''
@ -1401,7 +1375,7 @@ class TemplateExecutor:
chown_value['gid']),
str(error)))
def _chmod_file(self, target_path: str, chmod_value: int):
def _chmod_file(self, target_path: str, chmod_value: int) -> None:
'''Метод для смены прав доступа к директории.'''
try:
if not os.path.exists(target_path):
@ -1415,7 +1389,7 @@ class TemplateExecutor:
'Can not chmod file: {0}, reason: {1}'.
format(target_path, str(error)))
def _get_file_mode(self, file_path: str):
def _get_file_mode(self, file_path: str) -> int:
'''Метод для получения прав доступа для указанного файла.'''
if not os.path.exists(file_path):
raise TemplateExecutorError(
@ -1424,7 +1398,7 @@ class TemplateExecutor:
file_stat = os.stat(file_path)
return stat.S_IMODE(file_stat.st_mode)
def _get_file_owner(self, file_path: str):
def _get_file_owner(self, file_path: str) -> dict:
'''Метод для получения uid и gid значений для владельца указанного
файла.'''
if not os.path.exists(file_path):

@ -1,9 +1,12 @@
# vim: fileencoding=utf-8
#
import ast
import dis
from typing import List, Any
from contextlib import contextmanager
from inspect import signature, getsource
from types import FunctionType, LambdaType
from calculate.utils.tools import Singleton
class DependenceError(Exception):
@ -418,7 +421,10 @@ class DependenceSource:
in self._args]),
str(error)))
def get_args(self, namespace):
def _get_args(self, namespace):
'''Метод для преобразования списка аргументов функции зависимости,
содержащего переменные и строки, в список аргументов состоящий только
из нод переменных и значений хэшей.'''
if not self._args_founded:
for index in range(0, len(self._args)):
if isinstance(self._args[index], str):
@ -546,7 +552,7 @@ class VariableNode:
format(self.get_fullname()))
if isinstance(self._source, DependenceSource):
self._source.get_args(self.namespace)
self._source._get_args(self.namespace)
with self._start_calculate():
try:
value = self._source.calculate_value()
@ -705,11 +711,21 @@ class NamespaceNode:
def add_variable(self, variable: VariableNode) -> None:
'''Метод для добавления переменной в пространство имен.'''
if variable.name in self.namespaces:
raise VariableError("namespace with the name '{}' is already in"
" the namespace '{}'".format(
variable.name,
self.get_fullname()))
self.variables.update({variable.name: variable})
variable.namespace = self
def add_namespace(self, namespace) -> None:
'''Метод для добавления пространства имен в пространство имен.'''
if namespace.name in self.variables:
raise VariableError("variable with the name '{}' is already in"
" the namespace '{}'".format(
namespace.name,
self.get_fullname()))
self.namespaces.update({namespace.name: namespace})
namespace.parent = self
@ -762,7 +778,7 @@ class NamespaceNode:
return '<Namespace: {}>'.format(self.get_fullname())
class DependenceAPI:
class DependenceAPI(metaclass=Singleton):
'''Класс образующий интерфейс для создания зависимостей.'''
def __init__(self):
self.current_namespace = None
@ -813,7 +829,7 @@ class DependenceAPI:
return search_result
class VariableAPI:
class VariableAPI(metaclass=Singleton):
'''Класс для создания переменных при задании их через
python-скрипты.'''
def __init__(self):
@ -849,7 +865,7 @@ class VariableAPI:
return variable
class NamespaceAPI:
class NamespaceAPI(metaclass=Singleton):
'''Класс для создания пространств имен при задании переменных через
python-скрипты.'''
def __init__(self, var_fabric: VariableAPI,
@ -891,6 +907,8 @@ class NamespaceAPI:
self._dependence_fabric.current_namespace = self._datavars
def set_current_namespace(self, namespace: NamespaceNode):
'''Метод для установки текущего пространства имен, в которое будут
добавляться далее переменные и пространства имен.'''
self.current_namespace = namespace
self._variables_fabric.current_namespace = namespace
self._dependence_fabric.current_namespace = namespace

@ -0,0 +1,6 @@
{% for namespace_name, namespace in ini_dictionary.items() -%}
[{{ namespace_name | join('][') }}]
{% for variable, value in namespace.items() -%}
{{ variable }} {{ value | join(' ') }}
{% endfor %}
{% endfor -%}

@ -1,7 +1,9 @@
# vim: fileencoding=utf-8
#
import os
import importlib
import importlib.util
from pprint import pprint
from jinja2 import Environment, FileSystemLoader
from calculate.variables.datavars import NamespaceNode, VariableNode,\
ListType, IntegerType,\
FloatType, IniType, TableType,\
@ -9,6 +11,8 @@ from calculate.variables.datavars import NamespaceNode, VariableNode,\
VariableNotFoundError
from calculate.utils.gentoo import ProfileWalker
from calculate.utils.files import read_file, FilesError
from calculate.utils.tools import Singleton
from calculate.utils.io_module import IOModule
from pyparsing import Literal, Word, ZeroOrMore, Group, Optional, restOfLine,\
empty, printables, OneOrMore, lineno, line, col, SkipTo,\
LineEnd, Combine, nums
@ -16,13 +20,19 @@ from enum import Enum
from contextlib import contextmanager
class LoaderError(Exception):
'''Исключение выбрасываемое загрузчиком, если тот в принципе не может
загрузить переменные.'''
pass
class Define(Enum):
assign = 0
append = 1
remove = 2
class CalculateIniParser:
class CalculateIniParser(metaclass=Singleton):
'''Класс парсера calculate.ini файлов.'''
def __init__(self):
@ -140,11 +150,16 @@ class NamespaceIniFiller:
из calculate.ini файла.'''
available_sections = {'custom'}
def __init__(self, restrict_creation=True):
def __init__(self, restrict_creation=True, ouput=None):
self.ini_parser = CalculateIniParser()
# Флаги, определяющие возможность создания новых переменных и новых
# пространств имен в данном пространстве имен.
self.restricted = restrict_creation
self.modify_only = False
self.output = ouput
def error(self, lineno, error_message):
self.errors.append(lineno, error_message)
@ -184,12 +199,14 @@ class NamespaceIniFiller:
'''Метод для получения доступа и создания пространств имен.'''
if self.restricted:
self.modify_only = sections[0] not in self.available_sections
self.current_namespace = self.namespace
for section in sections:
if isinstance(self.current_namespace, Datavars):
if section not in self.current_namespace:
raise VariableError("variables package '{}' is not found".
format(section))
# TODO Поменять на простой вывод.
raise VariableNotFoundError("variables package '{}' is not"
" found".format(section))
elif isinstance(self.current_namespace, NamespaceNode):
if section not in self.current_namespace.namespaces:
if (section in self.current_namespace.variables and
@ -206,6 +223,7 @@ class NamespaceIniFiller:
else:
self.current_namespace = None
return
self.current_namespace = self.current_namespace.namespaces[section]
def clear_section(self, sections: list) -> None:
@ -266,6 +284,7 @@ class NamespaceIniFiller:
table_variable.source = table
def define_key(self, key: str, value: str, optype) -> None:
'''Метод для создания и модификации переменных.'''
if self.current_namespace is None:
return
@ -301,7 +320,10 @@ class NamespaceIniFiller:
source=value)
else:
# TODO Какая-то обработка ошибки.
pass
self.output.set_error("Can not create variable '{}.{}' in not"
" 'custom' namespace".format(
self.current_namespace.get_fullname(),
key))
def append_value(self, key: str, value: str) -> None:
'''Метод выполняющий действия возложенные на оператор +=.'''
@ -405,6 +427,7 @@ class VariableLoader:
def __init__(self, datavars, variables_path, repository_map=None):
self.datavars = datavars
self.output = datavars.output
self.ini_filler = NamespaceIniFiller()
self.variables_path = variables_path
@ -432,8 +455,9 @@ class VariableLoader:
if section in current_namespace:
current_namespace = current_namespace[section]
else:
# TODO детальнее продумать действия при отсутствии нужной
# переменной.
self.output.set_error("Variable 'os.gentoo.repositories'"
" is not found. Can not load profile"
" variables.")
return
self.repository_map = self._get_repository_map(self.datavars)
@ -442,8 +466,9 @@ class VariableLoader:
'path' in self.datavars.os.gentoo.profile):
profile_path = self.datavars.os.gentoo.profile.path
else:
# TODO детальнее продумать действия при отсутствии нужной
# переменной.
self.output.set_error("Variable 'os.gentoo.profile.path'"
" is not found. Can not load profile"
" variables.")
return
self._fill_from_ini(profile_path)
@ -451,13 +476,17 @@ class VariableLoader:
def load_user_variables(self):
'''Метод для загрузки переменных из calculate.ini указанных в
переменных env_order и env_path.'''
if ('system' in self.datavars and 'env_order' in self.datavars.system
and 'env_path' in self.datavars.system):
try:
env_order = self.datavars.system.env_order
env_path = self.datavars.system.env_path
for ini_file in env_order:
if ini_file in env_path:
self.fill_from_custom_ini(env_path[ini_file].value)
except VariableNotFoundError as error:
self.output.set_warning("Can not load additional variables: {}".
format(str(error)))
return
for ini_file in env_order:
if ini_file in env_path:
self.fill_from_custom_ini(env_path[ini_file].value)
def _fill_from_package(self, current_namespace: NamespaceNode,
directory_path: str, package: str) -> None:
@ -500,8 +529,8 @@ class VariableLoader:
ini_file_text = read_file(file_path)
self.ini_filler.fill(self.datavars, ini_file_text)
except FilesError:
# TODO продумать обработку ошибок.
pass
self.output.set_error("Can not load profile variables from"
" unexisting file: {}".format(file_path))
def _get_repository_map(self, datavars):
'''Метод для получения из переменной словаря с репозиториями и путями
@ -517,6 +546,7 @@ class VariableLoader:
@contextmanager
def test(self, file_name, namespace):
'''Контекстный менеджер для тестирования.'''
print('IMPORT: {}.{}'.format(namespace.get_fullname(), file_name))
try:
yield self
@ -526,16 +556,73 @@ class VariableLoader:
class CalculateIniSaver:
'''Класс для сохранения значений пользовательских переменных.'''
def __init__(self):
'''Класс для сохранения значений переменных в указанные ini-файлы.'''
def __init__(self, ini_parser=None):
self.ini_parser = CalculateIniParser()
self.operations = {Define.assign: '=',
Define.append: '+=',
Define.remove: '-='}
file_loader = FileSystemLoader('calculate/variables')
environment = Environment(loader=file_loader)
self.ini_template = environment.get_template('ini_template')
def save_to_ini(self, target_path, variables_to_save):
'''Метод для сохранения переменных в указанный ini-файл.'''
ini_file_text = read_file(target_path)
ini_dictionary = self._parse_ini(ini_file_text)
for namespace in variables_to_save:
if namespace in ini_dictionary:
ini_dictionary[namespace].update(variables_to_save[namespace])
else:
ini_dictionary[namespace] = variables_to_save[namespace]
ini_file_text = self._get_ini_text(ini_dictionary)
with open(target_path, 'w') as ini_file:
ini_file.write(ini_file_text)
def _parse_ini(self, ini_file_text):
'''Метод для разбора текста ini-файла в словарь, в который далее будут
добавляться измененные переменные.'''
current_namespace = None
ini_dictionary = dict()
for parsed_line in self.ini_parser.parse(ini_file_text):
line_type = next(iter(parsed_line))
line_content = parsed_line[line_type]
if (line_type == 'start_section' or
line_type == 'start_table'):
current_namespace = tuple(line_content[0])
if current_namespace not in ini_dictionary:
ini_dictionary[current_namespace] = dict()
elif (line_type == 'clear_section' or
line_type == 'clear_table'):
current_namespace = (*line_content[0], '')
ini_dictionary[current_namespace] = dict()
elif line_type == 'define_key':
namespace = ini_dictionary[current_namespace]
namespace.update({line_content[0]:
(self.operations[line_content[2]],
line_content[1])})
return ini_dictionary
def _get_ini_text(self, ini_dictionary):
'''Метод для получения текста ini файла, полученного в результате
наложения изменений из тегов save в шаблонах.'''
ini_text = self.ini_template.render(ini_dictionary=ini_dictionary)
return ini_text.strip()
class Datavars:
'''Класс для хранения переменных и управления ими.'''
def __init__(self, variables_path='calculate/vars', repository_map=None):
def __init__(self, variables_path='calculate/vars', repository_map=None,
io_module=IOModule()):
self._variables_path = variables_path
self._available_packages = self._get_available_packages()
self.output = io_module
self.root = NamespaceNode('<root>')
self._loader = VariableLoader(self, self._variables_path,
@ -619,59 +706,20 @@ class Datavars:
self._loader.load_variables_package(package_name)
return True
def add_namespace(self, namespace_node):
self.root.add_namespace(namespace_node)
@property
def namespaces(self):
return self.root.namespaces
def save_variables(self):
'''Метод для сохранения в calculate.ini файлах '''
ini_parser = self._loader.ini_filler.ini_parser
'''Метод для сохранения значений переменных в calculate.ini файлах.'''
target_paths = self.system.env_path
operations = {Define.assign: '=',
Define.append: '+=',
Define.remove: '-='}
saver = CalculateIniSaver()
for target in self.variables_to_save:
if self.variables_to_save[target]:
dict_to_save = self.variables_to_save[target]
# Распарсим файл в словарь.
current_namespace = None
ini_dictionary = dict()
ini_file_text = read_file(target_paths[target].value)
for parsed_line in ini_parser.parse(ini_file_text):
line_type = next(iter(parsed_line))
print('line_type: {}'.format(line_type))
line_content = parsed_line[line_type]
print('line_content: {}'.format(line_content))
if (line_type == 'start_section' or
line_type == 'start_table'):
current_namespace = tuple(line_content[0])
if current_namespace not in ini_dictionary:
ini_dictionary[current_namespace] = dict()
elif (line_type == 'clear_section' or
line_type == 'clear_table'):
current_namespace = (*line_content[0], '')
ini_dictionary[current_namespace] = dict()
elif line_type == 'define_key':
namespace = ini_dictionary[current_namespace]
namespace.update({line_content[0]:
(operations[line_content[2]],
line_content[1])})
for namespace in dict_to_save:
if namespace in ini_dictionary:
ini_dictionary[namespace].update(
dict_to_save[namespace])
else:
ini_dictionary[namespace] = dict_to_save[namespace]
print('INI DICTIONARY FOR {}:'.format(target))
pprint(ini_dictionary)
def _get_text(self, ini_dictionary):
pass
target_path = target_paths[target].value
saver.save_to_ini(target_path, dict_to_save)

@ -52,7 +52,7 @@ with Namespace('profile'):
# Название профиля
Variable('name', type=StringType,
source=Dependence('.path', '..repositories',
depend=get_profile_link))
depend=get_profile_name))
def get_repository_table(config):

@ -1157,7 +1157,7 @@ class TestTemplateWrapper:
join_paths(CHROOT_PATH,
'/etc/dir/file.conf'),
parameters_object, FILE,
'/path/to/template',
'/path/to/template',
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
except Exception as error:
@ -1210,13 +1210,11 @@ class TestTemplateWrapper:
'mirror': True})
with pytest.raises(TemplateExecutorError):
template_wrapper = TemplateWrapper(
join_paths(CHROOT_PATH,
'/etc/dir/none'),
parameters_object, FILE,
'/path/to/template',
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
TemplateWrapper(join_paths(CHROOT_PATH, '/etc/dir/none'),
parameters_object, FILE,
'/path/to/template',
chroot_path=CHROOT_PATH,
config_archive_path=CONFIG_ARCHIVE_PATH)
def test_if_mirror_parameter_is_set_and_file_from_the_source_parameter_does_not_exist__a_TemplateWrapper_object_sets_remove_original_flag_as_True(self):
parameters_object = ParametersContainer({'package': test_package_name,

@ -1,7 +1,6 @@
import os
import shutil
import pytest
from pprint import pprint
from calculate.variables.datavars import NamespaceNode, VariableNode,\
Namespace, Variable, Dependence,\
CyclicVariableError, HashType,\
@ -13,7 +12,7 @@ from calculate.variables.datavars import NamespaceNode, VariableNode,\
from calculate.templates.template_engine import TemplateEngine, FILE
from calculate.templates.template_processor import TemplateExecutor
from calculate.variables.loader import NamespaceIniFiller, Datavars
from calculate.utils.files import stderr_devnull
from calculate.utils.files import stderr_devnull, read_file
TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/variables/testfiles')
@ -25,7 +24,7 @@ APPENDS_SET = TemplateExecutor(cl_config_path=os.path.join(
@pytest.mark.vars
class TestNamespace:
class TestDatavars:
# Сначала тестируем классы и методы необходимые для построения дерева
# переменных и пространств имен.
def test_if_NamespaceNode_just_initialized_with_its_name__the_NamespaceNode_object_contains_empty_namespaces_and_variables_dictionaries_and_fullname_method_returns_only_the_namespace_s_name(self):
@ -1016,6 +1015,8 @@ value = another_value
{'name': 'common_name', 'value': 'another_value'},
{'name': 'name_3', 'value': 'value_3'}]
# Теперь тестируем применение объекта Datavars, через который
# осуществляется доступ к переменным и их загрузка.
def test_if_a_Datavars_object_is_created_with_path_to_the_variables_without_any_Dependencies_and_then_used_to_get_access_to_the_some_variables_from__the_datavars_object_dynamically_loads_variables_and_retruns_necessary_variables(self):
datavars = Datavars(
variables_path='tests/variables/testfiles/variables_0',
@ -1197,6 +1198,7 @@ value = another_value
assert datavars.os.calculate == 'new1 new2'
# Теперь тестируем применение объекта Datavars в шаблонах.
def test_if_Datavars_object_is_set_as_the_datavars_for_the_TemplateEngine_object__variables_from_the_Datavars_object_can_be_inserted_in_the_processed_template(self):
datavars = Datavars(
variables_path=os.path.join(TESTFILES_PATH, 'variables_7'))
@ -1217,7 +1219,7 @@ os.calculate = new1 new2'''
text = template_engine.template_text
assert text == output_text
def test_if_Datavars_object_is_set_as_the_datavars_for_the_TemplateEngine_object_and_save_tag_is_used_for_saving_some_variables_and_target_file_is_not_set_for_the_save_tag__variables_from_the_Datavars_object_can_be_inserted_in_the_processed_template(self):
def test_if_Datavars_object_is_set_as_the_datavars_for_the_TemplateEngine_object_and_save_tag_is_used_for_saving_some_variables_and_target_file_is_not_set_for_the_save_tag__the_Datavars_object_saves_and_modifies_variables_from_the_save_tag(self):
datavars = Datavars(
variables_path=os.path.join(TESTFILES_PATH, 'variables_7'))
template_engine = TemplateEngine(appends_set=APPENDS_SET,
@ -1246,7 +1248,7 @@ os.calculate = new1 new2'''
assert datavars.os.hashvar.value2 == 'weird2'
assert datavars.os.calculate == 'new1 weird2'
def test_if_Datavars_object_is_set_as_the_datavars_for_the_TemplateEngine_object_and_save_tag_is_used_for_appending_and_removing_some_variable_s_values_and_target_file_is_not_set_for_the_save_tag__variables_from_the_Datavars_object_can_be_inserted_in_the_processed_template(self):
def test_if_Datavars_object_is_set_as_the_datavars_for_the_TemplateEngine_object_and_save_tag_is_used_for_appending_and_removing_some_variable_s_values_and_target_file_is_not_set_for_the_save_tag__the_Datavars_object_changes_variables_from_the_save_tag(self):
datavars = Datavars(
variables_path=os.path.join(TESTFILES_PATH, 'variables_8'))
template_engine = TemplateEngine(appends_set=APPENDS_SET,
@ -1289,7 +1291,7 @@ os.calculate = new1 new2'''
assert datavars.os.linux.test_4 == [2, 4, 5]
assert datavars.custom.ns.var_2 == 'val2,val3,val5'
def test_save_variables_to_target_files(self):
def test_if_Datavars_object_is_set_as_the_datavars_for_the_TemplateEngine_object_and_save_tag_is_used_for_changing_some_variable_s_values_and_target_file_is_set_for_the_save_tag__the_Datavars_object_creates_new_and_modifies_existing_variables_and_saves_them_to_the_target_files(self):
datavars = Datavars(
variables_path=os.path.join(TESTFILES_PATH, 'variables_9'))
template_engine = TemplateEngine(appends_set=APPENDS_SET,
@ -1299,13 +1301,64 @@ os.calculate = new1 new2'''
input_template_1 = '''{% calculate name = 'filename', force -%}
{% save.local custom.ns.var_3 = 'value' -%}
{% save.local custom.ns.var_2 += 'val4' -%}
{% save.system custom.ns.var_5 = '/highway/to/hell' -%}
'''
local_ini_result = '''[custom][ns]
var_1 = 1
var_2 = val1,val2,val3,val4
var_3 = value
[os][linux]
test_1 += 12'''
system_ini_result = '''[custom][ns]
var_5 = /highway/to/hell
var_6 = 12
[os][linux]
test = new value'''
template_engine.process_template_from_string(input_template_1, FILE)
print('VARIABLES TO SAVE:')
pprint(datavars.variables_to_save)
datavars.save_variables()
assert False
assert local_ini_result == read_file(
datavars.system.env_path['local'].value)
assert system_ini_result == read_file(
datavars.system.env_path['system'].value)
def test_if_Datavars_object_is_set_as_the_datavars_for_the_TemplateEngine_object_and_save_tag_is_used_for_changing_some_hash_variable_s_values_and_target_file_is_set_for_the_save_tag__the_Datavars_object_modifies_hash_variables_and_saves_them_to_the_target_files_as_namespaces(self):
datavars = Datavars(
variables_path=os.path.join(TESTFILES_PATH, 'variables_10'))
template_engine = TemplateEngine(appends_set=APPENDS_SET,
chroot_path=TESTFILES_PATH,
datavars_module=datavars)
input_template_1 = '''{% calculate name = 'filename', force -%}
{% save.system os.hashvar_0 = {'value1': 'new1', 'value2': 'new2'} -%}
{% save.system os.hashvar_1.key1 = 'weird1' -%}
{% save.system os.hashvar_2.id_1 = 1575 -%}
{% save.system os.hashvar_2.id_2 = 1349 -%}
'''
system_ini_result = '''[os][hashvar_0]
value1 = new1
value2 = new2
[os][hashvar_1]
key1 = weird1
[os][hashvar_2]
id_1 = 1575
id_2 = 1349'''
template_engine.process_template_from_string(input_template_1, FILE)
datavars.save_variables()
assert system_ini_result ==\
read_file(datavars.system.env_path['system'].value)
# Теперь тестируем обработку ошибок.
def test_for_removing_testfiles(self):
shutil.rmtree(os.path.join(TESTFILES_PATH, 'gentoo'))

@ -1,3 +1,6 @@
[custom][ns]
var_1 = 1
var_2 = val1,val2,val3
[os][linux]
test_1 += 12

@ -1,3 +1,6 @@
[custom][ns]
var_1 = 1
var_2 = val1,val2,val3
var_5 = /the/true/path/to/eternity/in/the/abyss
var_6 = 12
[os][linux]
test = new value

@ -0,0 +1,4 @@
from calculate.variables.datavars import Variable, StringType
Variable('chroot', type=StringType.readonly, source='/')

@ -0,0 +1,47 @@
from calculate.variables.datavars import Namespace, Variable, Dependence,\
StringType, HashType, TableType,\
ListType, IntegerType, FloatType
with Namespace('linux'):
Variable('shortname', source='', type=StringType)
Variable('ver', source='', type=StringType)
Variable('fullname', source='', type=StringType)
Variable('subname', source='', type=StringType)
Variable('arch', source='', type=StringType)
Variable('test_1', source=12, type=IntegerType)
Variable('test_2', source=1.2, type=FloatType)
def get_title(subname, fullname, ver):
if subname.value:
return '{} {} {}'.format(fullname.value, subname.value, ver.value)
else:
return '{} {}'.format(fullname.value, ver.value)
Variable('title', type=StringType,
source=Dependence('.subname', '.fullname', '.ver',
depend=get_title))
Variable('hashvar_0', source={'value1': 'test1',
'value2': 'test2'}, type=HashType)
Variable('hashvar_1', source={'key1': 'value1',
'key2': 'value2'}, type=HashType)
Variable('hashvar_2', source={'id_1': 1349,
'id_2': 1575}, type=HashType)
Variable('calculate', type=StringType,
source=Dependence('.hashvar_0',
depend=lambda hashvar: "{} {}".format(
hashvar.value['value1'],
hashvar.value['value2'])))
Variable('tablevar', type=TableType, source=[{"dev": "/dev/sdb1",
"mount": "/"},
{"dev": "/dev/sdb2",
"mount": "/var/calculate"}])

@ -0,0 +1,57 @@
import os
from calculate.variables.datavars import Variable, Namespace, Dependence,\
StringType, TableType
'''
gentoo:
make_profile -> string
profile:
path -> string
name -> string
repositories[*]{name, path} -> table
config -> undefined
'''
TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/variables/testfiles')
# Путь до файла, указывающего на активный профиль
Variable('make_profile', type=StringType, source='/etc/portage/make.profile')
# Параметры текущего профиля.
with Namespace('profile'):
# Абсолютный путь до профиля
Variable('path', type=StringType,
source=os.path.join(TESTFILES_PATH,
"gentoo/repos/distros/profiles/CLD/amd64"))
def get_profile_name(path, repositories):
profile_path = path.value
if not profile_path:
return ""
for repository in repositories.value:
repository_path = repository['path']
repository_name = repository['name']
remove_part = os.path.normpath(os.path.join(repository_path,
"profiles"))
if profile_path.startswith(remove_part):
return "{}:{}".format(repository_name,
profile_path[len(remove_part) + 1:])
return profile_path
# Название профиля
Variable('name', type=StringType,
source=Dependence('.path', '..repositories',
depend=get_profile_name))
# Информация о репозиториях
# name: имя репозитория
# path: полный путь до репозитория
Variable('repositories', type=TableType,
source=[{'name': 'distros',
'path': os.path.join(TESTFILES_PATH,
"gentoo/repos/distros")},
{'name': 'calculate',
'path': os.path.join(TESTFILES_PATH,
"gentoo/repos/calculate")},
{'name': 'gentoo',
'path': os.path.join(TESTFILES_PATH,
"gentoo/portage")}])

@ -0,0 +1,19 @@
import os
from calculate.variables.datavars import Variable, ListType, HashType
'''
system:
env_order -> list
env_path -> hash
'''
TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/variables/testfiles')
# Список мест, где есть calculate.ini файлы.
Variable('env_order', type=ListType, source=['system', 'local'])
# Отображение множества мест, где есть calculate.ini файлы, на пути к ним.
Variable('env_path', type=HashType,
source={'system': os.path.join(TESTFILES_PATH,
'ini_vars/calculate_6.ini')})

@ -15,7 +15,7 @@ Variable('env_order', type=ListType, source=['system', 'local'])
# Отображение множества мест, где есть calculate.ini файлы, на пути к ним.
Variable('env_path', type=HashType,
source={'system': os.path.join(TESTFILES_PATH,
'ini_vars/calculate_4.ini'),
'local': os.path.join(TESTFILES_PATH,
'ini_vars/calculate_5.ini')})
source={'local': os.path.join(TESTFILES_PATH,
'ini_vars/calculate_4.ini'),
'system': os.path.join(TESTFILES_PATH,
'ini_vars/calculate_5.ini')})

Loading…
Cancel
Save