|
|
from calculate.utils.calculateini import CalculateIniParser
|
|
|
import re
|
|
|
import sys
|
|
|
import os
|
|
|
import importlib
|
|
|
import importlib.util
|
|
|
import site
|
|
|
from calculate.vars.datavars import Variable, Namespace, HashVariable, TableVariable, IniCreated, DefaultValue
|
|
|
from calculate.utils.gentoo import ProfileWalker
|
|
|
from calculate.utils.fs import readFile
|
|
|
from calculate.utils.files import listDirectory
|
|
|
|
|
|
class NamespaceIniFiller(CalculateIniParser):
|
|
|
"""
|
|
|
Объект используемый для наполения Namespace объекта переменными
|
|
|
из calculate.ini файла
|
|
|
"""
|
|
|
def error(self, lineno, s):
|
|
|
self.errors.append(lineno, s)
|
|
|
|
|
|
def fill(self, ns, data):
|
|
|
self.ns = ns
|
|
|
self.curns = self.ns
|
|
|
self.errors = []
|
|
|
self.parse(data)
|
|
|
|
|
|
def startSection(self, sections):
|
|
|
self.curns = self.ns
|
|
|
for section in sections:
|
|
|
if section not in self.curns.childs:
|
|
|
self.curns.addNamespace(Namespace(section))
|
|
|
self.curns = self.curns[section]
|
|
|
|
|
|
def clearSection(self, sections):
|
|
|
curns = self.ns
|
|
|
for section in sections:
|
|
|
if section not in curns.childs:
|
|
|
return
|
|
|
curns = curns[section]
|
|
|
curns.clearChilds()
|
|
|
|
|
|
def changeValue(self, key, value):
|
|
|
self.curns[key].setValue(value)
|
|
|
|
|
|
def defineVariable(self, key, value):
|
|
|
self.curns.addStringVariable(key, value)
|
|
|
|
|
|
def appendValue(self, key, value):
|
|
|
l = self.curns[key].getValue().split(",")
|
|
|
vlist = value.split(",")
|
|
|
for v in vlist:
|
|
|
if v not in l:
|
|
|
l.append(v)
|
|
|
self.changeValue(key,",".join(l))
|
|
|
|
|
|
def removeValue(self, key, value):
|
|
|
l = self.curns[key].getValue().split(",")
|
|
|
vlist = value.split(",")
|
|
|
for v in vlist:
|
|
|
if v in l:
|
|
|
l.remove(v)
|
|
|
self.changeValue(key,",".join(l))
|
|
|
|
|
|
def defineKey(self, section, key, value, optype):
|
|
|
Define = CalculateIniParser.Define
|
|
|
if optype == Define.Assign:
|
|
|
if key not in self.curns:
|
|
|
self.defineVariable(key, value)
|
|
|
else:
|
|
|
self.changeValue(key, value)
|
|
|
elif optype == Define.Append:
|
|
|
if key not in self.curns:
|
|
|
self.defineVariable(key, value)
|
|
|
else:
|
|
|
self.appendValue(key, value)
|
|
|
elif optype == Define.Remove:
|
|
|
if key not in self.curns:
|
|
|
self.defineVariable(key, value)
|
|
|
else:
|
|
|
self.removeValue(key, value)
|
|
|
|
|
|
def parseError(self, line, lineno, col):
|
|
|
self.error(lineno, _("Syntax error: %s") % line)
|
|
|
|
|
|
class NamespaceIniFillerStrict(NamespaceIniFiller):
|
|
|
"""
|
|
|
Объект используемый для наполения Namespace объекта переменными
|
|
|
из calculate.ini файла, с возможность определять только
|
|
|
"""
|
|
|
availableSection = ["custom"]
|
|
|
|
|
|
def fill(self, ns, data):
|
|
|
self.canCreate = False
|
|
|
for newns in self.availableSection:
|
|
|
if newns not in ns:
|
|
|
ns.addNamespace(Namespace(newns))
|
|
|
super().fill(ns, data)
|
|
|
|
|
|
def startSection(self, sections):
|
|
|
self.curns = self.ns
|
|
|
self.canCreate = sections[0] in self.availableSection
|
|
|
for section in sections:
|
|
|
if section not in self.curns.childs:
|
|
|
if isinstance(self.curns, TableVariable) or self.canCreate:
|
|
|
self.curns.addNamespace(Namespace(section))
|
|
|
else:
|
|
|
self.curns = None
|
|
|
self.curns = self.curns[section]
|
|
|
|
|
|
#def clearSection(self, sections):
|
|
|
# curns = self.ns
|
|
|
# self.canCreate = sections[0] in self.availableSection
|
|
|
# for section in sections:
|
|
|
# if section not in curns.childs:
|
|
|
# return
|
|
|
# curns = curns[section]
|
|
|
# curns.clearChilds()
|
|
|
|
|
|
|
|
|
def defineVariable(self, key, value):
|
|
|
if not self.canCreate:
|
|
|
pass
|
|
|
var = Variable(key)
|
|
|
var.addProperty(IniCreated(value))
|
|
|
self.curns.addVariable(var)
|
|
|
|
|
|
def changeValue(self, key, value):
|
|
|
var = self.curns[key]
|
|
|
var.setValue(value)
|
|
|
|
|
|
if isinstance(var, HashVariable.HashValue):
|
|
|
var = var.master_variable
|
|
|
value = var.getValue()
|
|
|
|
|
|
prop = var.findProperty(DefaultValue)
|
|
|
if prop:
|
|
|
prop.value = value
|
|
|
else:
|
|
|
var.addProperty(DefaultValue(value))
|
|
|
var.invalidate()
|
|
|
|
|
|
class VariableLoader:
|
|
|
"""
|
|
|
Объект используемый для загрузки переменных из python модуля
|
|
|
"""
|
|
|
reUpper = re.compile("(.)([A-Z])")
|
|
|
|
|
|
def _getVarlikeAttrs(self, obj):
|
|
|
"""
|
|
|
Получить список аттрибутов похожих на переменные
|
|
|
"""
|
|
|
for attrname in (x for x in dir(obj) if x[:1].isupper()):
|
|
|
yield self.reUpper.sub(r"\1_\2", attrname).lower(), \
|
|
|
getattr(obj, attrname)
|
|
|
|
|
|
def fill(self, ns, dirpath, package):
|
|
|
"""
|
|
|
Загрузить в namespace переменные из указанных модулей
|
|
|
"""
|
|
|
for fullfn in listDirectory(dirpath, fullpath=True):
|
|
|
dn, fn = os.path.split(fullfn)
|
|
|
if os.path.isdir(fullfn):
|
|
|
newns = ns.addNamespace(Namespace(fn))
|
|
|
self.fill(newns, fullfn, "%s.%s"%(package,fn))
|
|
|
elif fn.endswith(".py"):
|
|
|
module = self._load_module_source(package, fn, fullfn)
|
|
|
for varname, cls in self._getVarlikeAttrs(module):
|
|
|
if Variable.isImplementation(cls):
|
|
|
ns.addVariable(cls(varname))
|
|
|
elif HashVariable.isImplementation(cls) or \
|
|
|
TableVariable.isImplementation(cls) or \
|
|
|
Namespace.isImplementation(cls):
|
|
|
_newns = ns.addNamespace(cls(varname,ns))
|
|
|
for _varname, _cls in self._getVarlikeAttrs(cls):
|
|
|
if Variable.isImplementation(_cls):
|
|
|
_newns.addVariable(_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 ProfileFiller:
|
|
|
"""
|
|
|
Заполнитель значений переменных из файлов calculate.ini в профилях
|
|
|
"""
|
|
|
basename = "calculate.ini"
|
|
|
def getRepositoryMap(self, ns):
|
|
|
return {
|
|
|
x.name.getValue(): x.path.getValue()
|
|
|
for x in ns.os.gentoo.repositories
|
|
|
}
|
|
|
|
|
|
def fill(self, ns, profile_path):
|
|
|
nif = NamespaceIniFillerStrict()
|
|
|
pw = ProfileWalker(self.basename, self.getRepositoryMap(ns))
|
|
|
for fn in pw.find(profile_path):
|
|
|
nif.fill(ns, readFile(fn))
|