|
|
|
@ -1,17 +1,12 @@
|
|
|
|
|
import re
|
|
|
|
|
import sys
|
|
|
|
|
import os
|
|
|
|
|
import importlib
|
|
|
|
|
import importlib.util
|
|
|
|
|
import site
|
|
|
|
|
from calculate.variables.old_vars.datavars import Variable, HashVariable,\
|
|
|
|
|
TableVariable
|
|
|
|
|
from calculate.variables.datavars import NamespaceNode, VariableNode,\
|
|
|
|
|
ListType, IntegerType,\
|
|
|
|
|
FloatType, IniType, TableType,\
|
|
|
|
|
Namespace, VariableError
|
|
|
|
|
Namespace, VariableError, HashType
|
|
|
|
|
from calculate.utils.gentoo import ProfileWalker
|
|
|
|
|
from calculate.utils.files import list_directory, read_file, FilesError
|
|
|
|
|
from calculate.utils.files import read_file, FilesError
|
|
|
|
|
from pyparsing import Literal, Word, ZeroOrMore, Group, Optional, restOfLine,\
|
|
|
|
|
empty, printables, OneOrMore, lineno, line, col, SkipTo,\
|
|
|
|
|
LineEnd, Combine, nums
|
|
|
|
@ -167,6 +162,8 @@ class NamespaceIniFiller:
|
|
|
|
|
clear_table=None,
|
|
|
|
|
define_key=None,
|
|
|
|
|
error=None, **kwargs):
|
|
|
|
|
'''Метод вызывающий обработку токенов, выдаваемых парсером в
|
|
|
|
|
зависимости от их типа.'''
|
|
|
|
|
if start_section is not None:
|
|
|
|
|
self.start_section(*start_section)
|
|
|
|
|
elif clear_section is not None:
|
|
|
|
@ -195,12 +192,20 @@ class NamespaceIniFiller:
|
|
|
|
|
format(section))
|
|
|
|
|
elif isinstance(self.current_namespace, NamespaceNode):
|
|
|
|
|
if section not in self.current_namespace.namespaces:
|
|
|
|
|
if not self.modify_only:
|
|
|
|
|
self.current_namespace.add_namespace(
|
|
|
|
|
NamespaceNode(section))
|
|
|
|
|
else:
|
|
|
|
|
self.current_namespace = None
|
|
|
|
|
if (section in self.current_namespace.variables and
|
|
|
|
|
self.current_namespace[section].variable_type
|
|
|
|
|
is HashType):
|
|
|
|
|
# Если секция является хэшем, используем ее.
|
|
|
|
|
self.current_namespace = self.current_namespace.\
|
|
|
|
|
variables[section]
|
|
|
|
|
return
|
|
|
|
|
else:
|
|
|
|
|
if not self.modify_only:
|
|
|
|
|
self.current_namespace.add_namespace(
|
|
|
|
|
NamespaceNode(section))
|
|
|
|
|
else:
|
|
|
|
|
self.current_namespace = None
|
|
|
|
|
return
|
|
|
|
|
self.current_namespace = self.current_namespace.namespaces[section]
|
|
|
|
|
|
|
|
|
|
def clear_section(self, sections: list) -> None:
|
|
|
|
@ -266,21 +271,25 @@ class NamespaceIniFiller:
|
|
|
|
|
if self.current_namespace is None:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if optype == Define.assign:
|
|
|
|
|
if key not in self.current_namespace:
|
|
|
|
|
self.define_variable(key, value)
|
|
|
|
|
else:
|
|
|
|
|
self.change_value(key, value)
|
|
|
|
|
elif optype == Define.append:
|
|
|
|
|
if key not in self.current_namespace:
|
|
|
|
|
self.define_variable(key, value)
|
|
|
|
|
else:
|
|
|
|
|
self.append_value(key, value)
|
|
|
|
|
elif optype == Define.remove:
|
|
|
|
|
if key not in self.current_namespace:
|
|
|
|
|
self.define_variable(key, value)
|
|
|
|
|
else:
|
|
|
|
|
self.remove_value(key, value)
|
|
|
|
|
if (isinstance(self.current_namespace, VariableNode) and
|
|
|
|
|
self.current_namespace.variable_type is HashType):
|
|
|
|
|
self.update_hash(key, value, optype)
|
|
|
|
|
else:
|
|
|
|
|
if optype == Define.assign:
|
|
|
|
|
if key not in self.current_namespace:
|
|
|
|
|
self.define_variable(key, value)
|
|
|
|
|
else:
|
|
|
|
|
self.change_value(key, value)
|
|
|
|
|
elif optype == Define.append:
|
|
|
|
|
if key not in self.current_namespace:
|
|
|
|
|
self.define_variable(key, value)
|
|
|
|
|
else:
|
|
|
|
|
self.append_value(key, value)
|
|
|
|
|
elif optype == Define.remove:
|
|
|
|
|
if key not in self.current_namespace:
|
|
|
|
|
self.define_variable(key, value)
|
|
|
|
|
else:
|
|
|
|
|
self.remove_value(key, value)
|
|
|
|
|
|
|
|
|
|
def change_value(self, key: str, value: str) -> None:
|
|
|
|
|
'''Метод для изменения значения переменной.'''
|
|
|
|
@ -353,6 +362,40 @@ class NamespaceIniFiller:
|
|
|
|
|
|
|
|
|
|
variable.source = variable_value
|
|
|
|
|
|
|
|
|
|
def update_hash(self, key: str, value: str, optype):
|
|
|
|
|
'''Метод для изменения переменных хэшей через calculate.ini.'''
|
|
|
|
|
hash_to_update = self.current_namespace.get_value().get_hash()
|
|
|
|
|
if key not in hash_to_update:
|
|
|
|
|
# Если ключ отсутствует в хэше, то проверяем, является ли он
|
|
|
|
|
# фиксированным.
|
|
|
|
|
if self.current_namespace.fixed:
|
|
|
|
|
raise VariableError("key '{}' is unavailable for fixed"
|
|
|
|
|
" hash, available keys: '{}'".
|
|
|
|
|
format(key,
|
|
|
|
|
', '.join(self.current_namespace.
|
|
|
|
|
get_value()._fields)))
|
|
|
|
|
else:
|
|
|
|
|
hash_to_update.update({key: value})
|
|
|
|
|
elif optype == Define.assign:
|
|
|
|
|
hash_to_update.update({key: value})
|
|
|
|
|
elif optype == Define.append:
|
|
|
|
|
current_value = hash_to_update[key]
|
|
|
|
|
hash_to_update[key] = current_value + value
|
|
|
|
|
elif optype == Define.remove:
|
|
|
|
|
current_value = hash_to_update[key]
|
|
|
|
|
if (isinstance(current_value, int) or
|
|
|
|
|
isinstance(current_value, float)):
|
|
|
|
|
hash_to_update[key] = current_value - value
|
|
|
|
|
elif isinstance(current_value, str):
|
|
|
|
|
value_list = [item.strip() for item in value.split(',')]
|
|
|
|
|
current_value = [item.strip() for item in
|
|
|
|
|
current_value.split(',')]
|
|
|
|
|
for value_to_remove in value_list:
|
|
|
|
|
if value_to_remove in current_value:
|
|
|
|
|
current_value.remove(value_to_remove)
|
|
|
|
|
hash_to_update[key] = ','.join(current_value)
|
|
|
|
|
self.current_namespace.source = hash_to_update
|
|
|
|
|
|
|
|
|
|
def set_error(self, line, lineno, col):
|
|
|
|
|
'''Метод для добавления ошибки в лог.'''
|
|
|
|
|
self.error(lineno, "Syntax error: {}".format(line))
|
|
|
|
@ -379,11 +422,44 @@ class VariableLoader:
|
|
|
|
|
self._fill_from_package(package_namespace, directory_path, package)
|
|
|
|
|
|
|
|
|
|
def load_from_profile(self):
|
|
|
|
|
if self.repository_map != {}:
|
|
|
|
|
self.repository_map = (self.repository_map or
|
|
|
|
|
self._get_repository_map(self.datavars))
|
|
|
|
|
'''Метод для загрузки переменных из calculate.ini профиля.'''
|
|
|
|
|
# Проверяем наличие таблицы репозиториев в переменных.
|
|
|
|
|
if self.repository_map == {}:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if self.repository_map is None:
|
|
|
|
|
repositories_variable_path = ['os', 'gentoo', 'repositories']
|
|
|
|
|
current_namespace = self.datavars
|
|
|
|
|
for section in repositories_variable_path:
|
|
|
|
|
if section in current_namespace:
|
|
|
|
|
current_namespace = current_namespace[section]
|
|
|
|
|
else:
|
|
|
|
|
# TODO детальнее продумать действия при отсутствии нужной
|
|
|
|
|
# переменной.
|
|
|
|
|
return
|
|
|
|
|
self.repository_map = self._get_repository_map(self.datavars)
|
|
|
|
|
|
|
|
|
|
# Проверяем наличие пути к профилю в переменных.
|
|
|
|
|
if ('profile' in self.datavars.os.gentoo and
|
|
|
|
|
'path' in self.datavars.os.gentoo.profile):
|
|
|
|
|
profile_path = self.datavars.os.gentoo.profile.path
|
|
|
|
|
self._fill_from_ini(profile_path)
|
|
|
|
|
else:
|
|
|
|
|
# TODO детальнее продумать действия при отсутствии нужной
|
|
|
|
|
# переменной.
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
self._fill_from_ini(profile_path)
|
|
|
|
|
|
|
|
|
|
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):
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
def _fill_from_package(self, current_namespace: NamespaceNode,
|
|
|
|
|
directory_path: str, package: str) -> None:
|
|
|
|
@ -419,12 +495,10 @@ class VariableLoader:
|
|
|
|
|
|
|
|
|
|
def _fill_from_ini(self, profile_path):
|
|
|
|
|
'''Метод для зaполнения переменных из ini-файла.'''
|
|
|
|
|
print('PROCESSING INI FROM PROFILE')
|
|
|
|
|
profile_walker = ProfileWalker(self.ini_basename,
|
|
|
|
|
self.repository_map)
|
|
|
|
|
for file_path in profile_walker.find(profile_path):
|
|
|
|
|
try:
|
|
|
|
|
print('PROCESS FILE: {}'.format(file_path))
|
|
|
|
|
ini_file_text = read_file(file_path)
|
|
|
|
|
self.ini_filler.fill(self.datavars, ini_file_text)
|
|
|
|
|
except FilesError:
|
|
|
|
@ -432,6 +506,8 @@ class VariableLoader:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def _get_repository_map(self, datavars):
|
|
|
|
|
'''Метод для получения из переменной словаря с репозиториями и путями
|
|
|
|
|
к ним.'''
|
|
|
|
|
return {repo['name']: repo['path']
|
|
|
|
|
for repo in datavars.os.gentoo.repositories}
|
|
|
|
|
|
|
|
|
@ -465,6 +541,7 @@ class Datavars:
|
|
|
|
|
Namespace.set_datavars(self)
|
|
|
|
|
|
|
|
|
|
self._loader.load_from_profile()
|
|
|
|
|
self._loader.load_user_variables()
|
|
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
|
'''Метод для сброса модуля переменных.'''
|
|
|
|
@ -489,9 +566,12 @@ class Datavars:
|
|
|
|
|
def __getattr__(self, package_name: str):
|
|
|
|
|
'''Метод возвращает ноду пространства имен, соответствующего искомому
|
|
|
|
|
пакету.'''
|
|
|
|
|
print('getattr: {}'.format(package_name))
|
|
|
|
|
if package_name in self.root.namespaces:
|
|
|
|
|
return self.root[package_name]
|
|
|
|
|
elif package_name == 'custom':
|
|
|
|
|
custom_namespace = NamespaceNode('custom')
|
|
|
|
|
self.root.add_namespace(custom_namespace)
|
|
|
|
|
return self.root[package_name]
|
|
|
|
|
elif package_name not in self._available_packages:
|
|
|
|
|
raise VariableError("variables package '{}' is not found".
|
|
|
|
|
format(package_name))
|
|
|
|
@ -502,9 +582,12 @@ class Datavars:
|
|
|
|
|
def __getitem__(self, package_name: str) -> None:
|
|
|
|
|
'''Метод возвращает ноду пространства имен, соответствующего искомому
|
|
|
|
|
пакету.'''
|
|
|
|
|
print('getitem: {}'.format(package_name))
|
|
|
|
|
if package_name in self.root:
|
|
|
|
|
return self.root[package_name]
|
|
|
|
|
elif package_name == 'custom':
|
|
|
|
|
custom_namespace = NamespaceNode('custom')
|
|
|
|
|
self.root.add_namespace(custom_namespace)
|
|
|
|
|
return self.root[package_name]
|
|
|
|
|
elif package_name not in self._available_packages:
|
|
|
|
|
raise VariableError("variables package '{}' is not found".
|
|
|
|
|
format(package_name))
|
|
|
|
@ -515,7 +598,12 @@ class Datavars:
|
|
|
|
|
def __contains__(self, package_name):
|
|
|
|
|
if package_name in self.root.namespaces:
|
|
|
|
|
return True
|
|
|
|
|
elif package_name not in self._available_packages:
|
|
|
|
|
elif package_name == 'custom':
|
|
|
|
|
custom_namespace = NamespaceNode('custom')
|
|
|
|
|
self.root.add_namespace(custom_namespace)
|
|
|
|
|
return True
|
|
|
|
|
elif (package_name not in self._available_packages
|
|
|
|
|
and package_name != 'custom'):
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
self._loader.load_variables_package(package_name)
|
|
|
|
@ -524,80 +612,3 @@ class Datavars:
|
|
|
|
|
@property
|
|
|
|
|
def namespaces(self):
|
|
|
|
|
return self.root.namespaces
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OldVariableLoader:
|
|
|
|
|
'''Класс, используемый для загрузки переменных из python модуля.'''
|
|
|
|
|
re_upper = re.compile("(.)([A-Z])")
|
|
|
|
|
|
|
|
|
|
def _get_varlike_attrs(self, obj):
|
|
|
|
|
'''Метод для получения списка аттрибутов похожих на переменные.'''
|
|
|
|
|
for attrname in (x for x in dir(obj) if x[:1].isupper()):
|
|
|
|
|
yield self.re_upper.sub(r"\1_\2", attrname).lower(), \
|
|
|
|
|
getattr(obj, attrname)
|
|
|
|
|
|
|
|
|
|
def fill(self, namespace, dirpath, package):
|
|
|
|
|
'''Загрузить в namespace переменные из указанных модулей.'''
|
|
|
|
|
for fullfn in list_directory(dirpath, fullpath=True):
|
|
|
|
|
dn, fn = os.path.split(fullfn)
|
|
|
|
|
if os.path.isdir(fullfn):
|
|
|
|
|
newns = namespace.add_namespace(Namespace(fn))
|
|
|
|
|
self.fill(newns, fullfn, "{}.{}".format(package, fn))
|
|
|
|
|
elif fn.endswith(".py"):
|
|
|
|
|
module = self._load_module_source(package, fn, fullfn)
|
|
|
|
|
for varname, cls in self._get_varlike_attrs(module):
|
|
|
|
|
if Variable.is_implementation(cls):
|
|
|
|
|
namespace.add_variable(cls(varname))
|
|
|
|
|
elif HashVariable.is_implementation(cls) or \
|
|
|
|
|
TableVariable.is_implementation(cls) or \
|
|
|
|
|
Namespace.is_implementation(cls):
|
|
|
|
|
_newns = namespace.add_namespace(cls(varname,
|
|
|
|
|
namespace))
|
|
|
|
|
for _varname, _cls in self._get_varlike_attrs(cls):
|
|
|
|
|
if Variable.is_implementation(_cls):
|
|
|
|
|
_newns.add_variable(_cls(_varname))
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def default(cls):
|
|
|
|
|
site_dirs = [os.path.normpath(x) for x in site.getsitepackages()]
|
|
|
|
|
for site_dir in site_dirs:
|
|
|
|
|
calculate_dir = os.path.join(site_dir, "calculate/vars")
|
|
|
|
|
if os.path.exists(calculate_dir):
|
|
|
|
|
return (calculate_dir, "calculate.vars")
|
|
|
|
|
|
|
|
|
|
def _load_module_source(self, package, name, path):
|
|
|
|
|
if name.startswith('calculate.vars.'):
|
|
|
|
|
full_name = name
|
|
|
|
|
else:
|
|
|
|
|
full_name = '.'.join([package, name])
|
|
|
|
|
|
|
|
|
|
if full_name in sys.modules:
|
|
|
|
|
return sys.modules[full_name]
|
|
|
|
|
|
|
|
|
|
spec = importlib.util.spec_from_file_location(full_name, path)
|
|
|
|
|
module = importlib.util.module_from_spec(spec)
|
|
|
|
|
spec.loader.exec_module(module)
|
|
|
|
|
sys.modules[full_name] = module
|
|
|
|
|
return module
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OldProfileFiller:
|
|
|
|
|
"""
|
|
|
|
|
Заполнитель значений переменных из файлов calculate.ini в профилях
|
|
|
|
|
"""
|
|
|
|
|
basename = "calculate.ini"
|
|
|
|
|
|
|
|
|
|
def get_repository_map(self, datavars):
|
|
|
|
|
return {repo['name']: repo['path']
|
|
|
|
|
for repo in datavars.os.gentoo.repositories}
|
|
|
|
|
|
|
|
|
|
def fill(self, datavars, profile_path):
|
|
|
|
|
ini_filler = NamespaceIniFiller()
|
|
|
|
|
profile_walker = ProfileWalker(self.basename,
|
|
|
|
|
self.get_repository_map(datavars))
|
|
|
|
|
for file_path in profile_walker.find(profile_path):
|
|
|
|
|
try:
|
|
|
|
|
ini_file_text = read_file(file_path)
|
|
|
|
|
ini_filler.fill(datavars, ini_file_text)
|
|
|
|
|
except FilesError:
|
|
|
|
|
pass
|
|
|
|
|