You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
7.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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))