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.
calculate-utils-3-lib/pym/calculate/lib/cl_template.py

6760 lines
296 KiB

9 years ago
# -*- coding: utf-8 -*-
# Copyright 2008-2016 Mir Calculate. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
import os
import stat
import re
import importlib
from .utils.portage import getInstalledAtom, RepositoryPath, \
searchProfile, RepositorySubstituting
from .cl_xml import xmlShare
from .utils.system import SystemPath, FUser, emerge_running
from functools import wraps
import random
import string
import time
import glob
import hashlib
import codecs
import uuid
from fnmatch import fnmatch
from math import sqrt
from itertools import *
from collections import OrderedDict
from operator import lt, le, eq, ne, ge, gt
import shutil
import errno
3 years ago
from .utils.common import (_error, _warning, getTupleVersion, getPortageUidGid,
isBootstrapDataOnly)
3 years ago
from .utils.text import _u
from .utils.portage import (isPkgInstalled, reVerSplitToPV, EmergeLog,
getInstalledAtom,
EmergeLogPackageTask, getPkgUses, RepositoryPath)
3 years ago
from .utils.content import PkgContents, checkContents, getCfgFiles, fillContents
from .utils.files import (getModeFile, listDirectory, removeDir, typeFile,
scanDirectory, FilesError, dir_sync, find, getProgPath,
pathJoin, readFile, readLinesFile, process)
3 years ago
from .utils.mount import Mounts
from .utils.tools import iterate_list, has_any, Locker
from .datavars import DataVarsError, VariableError, CriticalError, SimpleDataVars
from .configparser import (ConfigParser, NoSectionError,
ParsingError)
from .cl_lang import setLocalTranslate, RegexpLocalization
9 years ago
_ = lambda x: x
setLocalTranslate('cl_lib3', sys.modules[__name__])
9 years ago
PORTAGEUID, PORTAGEGID = getPortageUidGid()
11 years ago
9 years ago
class TemplatesError(Exception):
"""
Error on templates appling
"""
9 years ago
def catch_no_space_left(f):
def wrapper(*args, **kw):
try:
9 years ago
return f(*args, **kw)
except IOError as e:
if e.errno == 28:
raise TemplatesError(_("No space left on device"))
raise
9 years ago
return wrapper
def post_unlock_packages(f):
def wrapper(self, *args, **kw):
if not kw.get("rerun", True):
return f(self, *args, **kw)
else:
try:
return f(self, *args, **kw)
except BaseException as e:
raise
finally:
self.unlock_packages()
return wrapper
def try_decode_utf8(_bytes):
try:
return _bytes.decode("UTF-8"), True
except UnicodeDecodeError as e:
return _bytes, False
class DataVarsConfig(SimpleDataVars):
"""
Получить профиль и emerge config из chroot системы
"""
def __init__(self, chroot_path='/'):
from .variables import env
SimpleDataVars.__init__(
self,
env.VariableClMakeProfile(systemRoot=chroot_path),
env.VariableClEmergeConfig(systemRoot=chroot_path))
class LayeredIni():
_baseDir = None
objVar = None
class IniPath():
IniName = "ini.env"
Grp = os.path.join('/var/lib/calculate/calculate-update', IniName)
System = os.path.join('/var/lib/calculate/', IniName)
Etc = os.path.join('/etc/calculate', IniName)
Local = os.path.join('/var/calculate', IniName)
Remote = os.path.join('/var/calculate/remote', IniName)
Hardcode = os.path.join(RepositoryPath.CalculateProfiles, IniName)
Work = System
def __init__(self):
# комплексное содержимое ini.env с приоритетом меньше, чем у
# изменяемого
self.lowerIni = None
# комплексное содержимое ini.env с приоритетом выше, чем у
# изменяемого
self.upperIni = None
def is_user(self):
return self.objVar and self.objVar.Get('cl_action') == "desktop"
def get_profile_path(self, dv):
"""
Получить путь до системного профиля
:param dv:
:return:
"""
if not dv:
return ""
try:
make_profile = dv.Get('main.cl_make_profile')
if os.path.exists(make_profile):
profiledir = os.path.dirname(make_profile)
return os.path.join(profiledir, os.readlink(make_profile))
return ""
except VariableError:
return ""
def get_profiles_inienv(self, dv):
"""
Получить список ini.env находящихся в профиле с учётом их расположения
в parent файлах
:param dv:
:return:
"""
if dv:
profile_path = self.get_profile_path(dv)
if profile_path:
repos = RepositorySubstituting(dv, self._baseDir)
return list(searchProfile(
profile_path, self.IniPath.IniName, repository_sub=repos))
return []
def read_other_ini(self):
"""
Прочитать все необходимые файлы env
:return:
"""
if not self.lowerIni:
inifiles = self.get_profiles_inienv(self.objVar)
inifiles.append(pathJoin(self._baseDir, self.IniPath.Grp))
try:
if (self.objVar and
(self.objVar.Get('core.ac_backup_restore') == 'on' or
self.objVar.Get(
'core.ac_backup_service') == 'on')):
backup_path = self.objVar.Get('cl_backup_ini_env')
inifiles.append(backup_path)
except DataVarsError as e:
pass
#print "lower:", inifiles
self.lowerIni = ConfigParser(strict=False)
for inifn in inifiles:
try:
self.lowerIni.read(inifn, encoding="utf-8")
except ParsingError as e:
sys.stderr.write("%s\n" % str(e))
sys.stderr.flush()
if not self.upperIni:
inifiles = [self.IniPath.Etc,
self.IniPath.Local,
self.IniPath.Remote]
if self.is_user():
inifiles = [self.IniPath.Work] + inifiles
inifiles = [pathJoin(self._baseDir, x) for x in inifiles]
#print "upper:", inifiles
self.upperIni = ConfigParser(strict=False)
for inifn in inifiles:
try:
self.upperIni.read(inifn, encoding="utf-8")
except ParsingError as e:
sys.stderr.write("%s\n" % str(e))
sys.stderr.flush()
class SystemIni(LayeredIni):
_inifile = LayeredIni.IniPath.Work
@property
def inifile(self):
if self.objVar:
return pathJoin(self.objVar.Get('cl_chroot_path'), self._inifile)
else:
return self._inifile
def is_user(self):
return False
def __init__(self, dv=None):
self.objVar = dv
if dv:
self._baseDir = self.objVar.Get('cl_chroot_path')
else:
self._baseDir = '/'
super().__init__()
self.config = ConfigParser(strict=False)
try:
self.config.read(self.inifile, encoding="utf-8")
except ParsingError as e:
sys.stderr.write("%s\n" % str(e))
sys.stderr.flush()
self.read_other_ini()
def getVar(self, section, varname):
value = self.upperIni.get(section, varname, raw=True, fallback=None)
if value is None:
value = self.config.get(section, varname, raw=True, fallback=None)
if value is None:
value = self.lowerIni.get(section, varname, raw=True, fallback="")
return value
def getKeys(self, section):
skeys = []
for iniobj in (self.upperIni, self.config, self.lowerIni):
if iniobj.has_section(section):
skeys.extend(list(iniobj[section].keys()))
return list(sorted(list(set(skeys))))
def delVar(self, section, varname):
try:
self.config.remove_option(section, varname)
for section in (x for x
in self.config.sections() if not self.config[x]):
self.config.remove_section(section)
self.__write()
except NoSectionError:
pass
def __write(self):
comment_block = "\n".join(takewhile(lambda x: x.startswith("#"),
readLinesFile(self.inifile)))
with open(self.inifile, 'w') as f:
if comment_block:
f.write(comment_block)
f.write('\n\n')
self.config.write(f)
def setVar(self, section, var_dict):
if not self.config.has_section(section):
self.config.add_section(section)
for k, v in var_dict.items():
self.config.set(section, k, v)
self.__write()
9 years ago
class _shareTemplate():
"""Общие аттрибуты для классов шаблонов"""
# Метка начала переменной
varStart = "#-"
# Метка конца переменной
varEnd = "-#"
_deltVarStart = len(varStart)
_deltVarEnd = len(varEnd)
objVar = None
_reVar = re.compile(
"%s(?:[a-z0-9_]+\.)?[a-zA-Z0-9_-]+%s" % (varStart, varEnd), re.M)
def applyVarsTemplate(self, textTemplate, nameTemplate):
""" Заменяет переменные на их значения
"""
resS = self._reVar.search(textTemplate)
textTemplateTmp = textTemplate
while resS:
mark = textTemplateTmp[resS.start():resS.end()]
varName = mark[self._deltVarStart:-self._deltVarEnd]
try:
t = self.objVar.getInfo(varName).type
if "list" in t:
varValue = self.objVar.serialize(t,
self.objVar.Get(varName))
else:
varValue = self.objVar.Get(varName)
if not varValue:
varValue = ""
else:
varValue = str(varValue)
3 years ago
except DataVarsError as e:
raise TemplatesError(_("error in template %s") % nameTemplate
+ "\n" + str(e))
textTemplateTmp = textTemplateTmp.replace(mark, varValue)
resS = self._reVar.search(textTemplateTmp)
return textTemplateTmp
def getDataUser(self, groupsInfo=False):
"""Получить информацию о пользователе"""
userName = self.objVar.Get("ur_login")
if not userName:
userName = "root"
import pwd
try:
pwdObj = pwd.getpwnam(userName)
uid = pwdObj.pw_uid
gid = pwdObj.pw_gid
homeDir = self.objVar.Get('ur_home_path')
except Exception:
raise TemplatesError(_("User %s not found") % str(userName))
if groupsInfo:
import grp
try:
groupName = grp.getgrgid(gid).gr_name
except Exception:
raise TemplatesError(_("Group ID %s not found") % str(gid))
groupsNames = [x.gr_name for x in grp.getgrall() if userName in x.gr_mem]
groupsNames = [groupName] + groupsNames
return uid, gid, homeDir, groupsNames
return uid, gid, homeDir
class _shareTermsFunction():
"""Общие аттрибуты для классов _terms и templateFunctions"""
# Символы допустимые в скобках функции шаблона
_reFunctionArgvInSquareBrackets = (
"a-zA-Z0-9_:;%@<>=\!\|\{\}\^\$\?\(\)\[\]\-"
"\n\+\,\*\/\.\'\"~\\\\ ")
_reFunctionArgvText = "[%s]" % _reFunctionArgvInSquareBrackets
# регулярное выражение для поиска функции в шаблоне
_reFunctionText = ("([a-zA-Z0-9\_-]+)\(((?:#-|-#|%s)+|)\)" %
_reFunctionArgvText)
class _terms(_error, _shareTermsFunction, _shareTemplate):
"""Вычисление условий применяемых в шаблонах
"""
# регулярное выражение для поиска функции в шаблоне
_reFunction = re.compile(_shareTermsFunction._reFunctionText)
# регулярное выражение для не версии
_re_not_Version = re.compile("[^0-9\.]")
# регулярное выражение не номер
_re_not_Number = re.compile("[^0-9]")
_suffixDict = {"pre": -2, "p": 0, "alpha": -4, "beta": -3, "rc": -1}
_lenSuffixDict = len(_suffixDict)
# Регулярное выражение для названия переменной
_reRightName = re.compile("^(?:[a-z_\-]+\.)?(?:[a-zA-Z0-9_\-]+)$")
# Регулярное выражение для сравниваемого значения
_reDenyValue = re.compile("[^0-9a-zA-Z_/\.,-]")
# латинские буквы в нижнем регистре
_letters = list(string.ascii_lowercase)
9 years ago
# использует из других объектов
objVar = None
def _splitVersion(self, strVersion):
"""
Split version. Version, addition letter, list suffixes with version,
revision.
Examples:
12 years ago
3.0.0_beta2
("3.0.0_beta2","",[],"")
3.0.0_beta2-r1
("3.0.0_beta2","",[],"r1")
3.0.0_beta2a-r1
("3.0.0_beta2","a",[],"r1")
3.0.0_beta2a_rc1-r1
("3.0.0_beta2","a",[("rc","1")],"r1")
3.0.0_beta2a_rc1_p20111212-r1
("3.0.0_beta2","a",[("rc1","1"),("p","20111212")],"r1")
"""
# get revision from version
strWorkVersion, spl, rVersion = strVersion.rpartition("-")
if rVersion == strVersion:
strWorkVersion = rVersion
rVersion = ""
suffixes = []
# get suffixes from version
while "_" in strWorkVersion:
# 2.3_p45 ('2.3','_','p43')
# 2.3_rc4_p45 ('2.3_rc4','_','p43')
strWorkVersion, spl, suffix = strWorkVersion.rpartition("_")
suffSplList = [x for x in self._suffixDict.keys() if suffix.startswith(x)]
if suffSplList:
suffSpl = suffSplList[0]
lenSuffSpl = len(suffSpl)
suffixVersion = suffix[lenSuffSpl:]
9 years ago
suffixes.append((suffSpl, suffixVersion))
letters = ""
numberVersion = strWorkVersion
if numberVersion and numberVersion[-1:] in self._letters:
letters = numberVersion[-1:]
numberVersion = numberVersion[:-1]
return numberVersion, letters, suffixes, rVersion
def _isVersion(self, strVersion):
"""strVersion is not version - True"""
9 years ago
numberVersion, letters, suffixes, rVersion = \
self._splitVersion(strVersion)
if not numberVersion.strip():
return False
if self._re_not_Version.search(numberVersion):
return False
if letters and letters not in self._letters:
return False
9 years ago
for suffix, suffixVersion in suffixes:
if suffixVersion and self._re_not_Number.search(suffixVersion):
return False
if rVersion:
if rVersion[0] != "r" or len(rVersion) == 1:
return False
if self._re_not_Number.search(rVersion[1:]):
return False
return True
def _isIntervalVersion(self, strVersion):
if "," in strVersion and strVersion.count(',') == 1:
version1, op, version2 = strVersion.partition(",")
return self._isVersion(version1) and self._isVersion(version2)
return False
def _convertVers(self, verA, verB):
"""Конвертирование номеров версий для корректного сравнения
"""
9 years ago
def fillZero(elemA, elemB):
9 years ago
# elemA, elemB = elemA[], elemB[]
if len(elemA) > len(elemB):
9 years ago
maxElemB = len(elemB) - 1
for i in range(len(elemA)):
if i > maxElemB:
elemB.append("0")
else:
9 years ago
maxElemA = len(elemA) - 1
for i in range(len(elemB)):
if i > maxElemA:
elemA.append("0")
for i in range(len(elemB)):
lenA = len(elemA[i])
lenB = len(elemB[i])
if lenA == lenB:
pass
elif lenA > lenB:
res = lenA - lenB
for z in range(res):
elemB[i] = "0" + elemB[i]
elif lenB > lenA:
res = lenB - lenA
for z in range(res):
elemA[i] = "0" + elemA[i]
9 years ago
def fillSuffix(elemA, elemB, sA, svA, sB, svB):
if str(sA) or str(sB):
svA, svB = [[x] if x else ['0'] for x in (svA, svB)]
fillZero(svA, svB)
sA, sB = [x if x else 0 for x in (sA, sB)]
elemA.append(str(self._lenSuffixDict + sA))
elemA.extend(svA)
elemB.append(str(self._lenSuffixDict + sB))
elemB.extend(svB)
9 years ago
# Version, letters, suffix, suffixVersion, rVersion
vA, lA, ssA, rvA = self._splitVersion(verA)
vB, lB, ssB, rvB = self._splitVersion(verB)
elemA = vA.split(".")
elemB = vB.split(".")
fillZero(elemA, elemB)
if lA or lB:
lA, lB = [x if x else '0' for x in (lA, lB)]
elemA.append(lA)
elemB.append(lB)
# dereferencing suffix in suffixes list
ssA = [(self._suffixDict.get(x[0], 0), x[1]) for x in ssA]
ssB = [(self._suffixDict.get(x[0], 0), x[1]) for x in ssB]
9 years ago
for suffix, sufVer in reversed(ssA):
if ssB:
9 years ago
sB, svB = ssB.pop()
else:
9 years ago
sB, svB = "", ""
fillSuffix(elemA, elemB, suffix, sufVer, sB, svB)
while ssB:
9 years ago
sB, svB = ssB.pop()
fillSuffix(elemA, elemB, "", "", sB, svB)
if rvA or rvB:
rvA, rvB = [[x[1:]] for x in (rvA, rvB)]
fillZero(rvA, rvB)
elemA += rvA
elemB += rvB
9 years ago
return ".".join(elemA), ".".join(elemB)
def _checkInterval(self, val, op, interval):
ver1, ver2 = interval.split(',')
val1, ver1 = self._convertVers(val, ver1)
val2, ver2 = self._convertVers(val, ver2)
comparator = {
'==': lambda a,b,c,d: a>=b and c <= d,
'!=': lambda a,b,c,d: a<b or c > d,
'<=': lambda a,b,c,d: a>b and c <= d,
'<>': lambda a,b,c,d: a>b and c < d,
'=>': lambda a,b,c,d: a>=b and c < d
}
if op not in comparator:
raise TemplatesError(_("Wrong interval operator"))
return comparator[op](val1, ver1, val2, ver2)
9 years ago
def _equalTerm(self, term, textError, function=None):
"""Вычисление логических выражений для условий
Для корректной работы в классе который наследует этот класс
должен быть объявлен аттрибут self.objVar
(объект для работы с переменными)
function - функция для для обработки функций в заголовке блока
"""
9 years ago
rpl = lambda x: x.replace("@@", " ")
trm = {"&&": "@@and@@", "||": "@@or@@"}
dictRuleFunc = OrderedDict((("==", eq), ("!=", ne),
(">=", ge),
("<=", le),
("<>", ne), ("=>", ge),
(">", gt), ("<", lt),
))
rule = dictRuleFunc.keys()
listEqual = []
for k in trm.keys():
if k in term:
9 years ago
term = term.replace(k, trm[k])
trs = term.split("@@")
14 years ago
listSplitOr = []
if "or" in trs:
lst = []
for t in trs:
if t != "or":
lst.append(t)
else:
14 years ago
listSplitOr.append(lst)
lst = []
if lst:
listSplitOr.append(lst)
else:
listSplitOr = [trs]
for trsAnd in listSplitOr:
listEqual = []
for t in trsAnd:
def search_rule(t, rule, prefix=""):
for sepF in rule:
if sepF in t:
vals = list(t.partition(sepF)[::2])
if vals[0].endswith("\\"):
9 years ago
return search_rule(vals[1], rule,
prefix="%s%s%s" % (
prefix, vals[0], sepF))
return True, sepF, ["%s%s" % (prefix, vals[0]),
vals[1]]
return False, None, []
flagRule, sepF, vals = search_rule(t, rule)
14 years ago
if flagRule:
9 years ago
# проверка на допустимость названия переменной
14 years ago
flagFunction = False
12 years ago
if not self._reRightName.search(vals[0]):
9 years ago
# проверка на допустимость функции
14 years ago
flagError = True
if callable(function):
14 years ago
searchFunct = self._reFunction.search(vals[0])
if searchFunct:
flagError = False
flagFunction = True
if flagError:
9 years ago
self.setError(
"'%s'" % rpl(term) + " " + _("incorrect"))
14 years ago
self.setError(textError)
return False
9 years ago
# проверка на допустимость значения
try:
if "#-" in vals[1]:
vals[1] = self.applyVarsTemplate(vals[1], "")
vals[1] = function(vals[1])
except TemplatesError:
pass
14 years ago
if self._reDenyValue.search(vals[1]):
9 years ago
self.setError("'%s'" % rpl(term) + " " + _("incorrect"))
self.setError(textError)
return False
14 years ago
flagIntTypeVar = None
9 years ago
if flagFunction and callable(function):
valVars = function("#-%s-#" % vals[0])
14 years ago
if valVars is False:
9 years ago
self.setError(
"'%s'" % rpl(term) + " " + _("incorrect"))
14 years ago
self.setError(textError)
return False
9 years ago
if "load" == searchFunct.group(1) and \
re.search("\(\s*num\s*,", vals[0]):
14 years ago
if valVars:
try:
valVars = int(valVars)
9 years ago
except ValueError:
self.setError("'%s'" % rpl(term) + " " +
_("incorrect"))
14 years ago
self.setError(textError)
return False
flagIntTypeVar = True
else:
flagIntTypeVar = False
else:
9 years ago
if valVars == "" and \
(self._isVersion(vals[1]) or
self._isIntervalVersion(vals[1])):
9 years ago
valVars = "0"
elif vals[1] == "" and self._isVersion(valVars):
9 years ago
vals[1] = "0"
else:
14 years ago
try:
14 years ago
valVars = self.objVar.Get(vals[0])
varTable = self.objVar.Get('cl_used_action')
9 years ago
varTable.append((vals[0], vals[1]))
if not valVars:
valVars = ""
3 years ago
except DataVarsError as e:
raise TemplatesError("{header}\n{body}".format(
9 years ago
header=textError, body=str(e)))
14 years ago
# Номера версий для ini
flagNotIniFunct = True
# Два значения не пусты
flagNotEmptyVals = not (valVars == "" and vals[1] == "")
9 years ago
if flagFunction and flagNotEmptyVals and \
searchFunct.group(1) == "ini":
14 years ago
# Проверка значения на версию
if self._isVersion(valVars) and \
self._isVersion(vals[1]):
9 years ago
verFile, verVar = self._convertVers(vals[1],
valVars)
res = dictRuleFunc[sepF](verVar, verFile)
14 years ago
if res:
listEqual.append(True)
else:
listEqual.append(False)
break
14 years ago
flagNotIniFunct = False
if self._isVersion(valVars) and \
self._isIntervalVersion(vals[1]):
res = False
try:
res = self._checkInterval(
valVars, sepF, vals[1])
except TemplatesError:
self.setError("'%s'" % rpl(term) + " " + \
_("incorrect"))
self.setError(
_("Wrong interval operator"))
if res:
listEqual.append(True)
else:
listEqual.append(False)
break
flagNotIniFunct = False
14 years ago
# Cравниваем номера версий
if flagNotIniFunct:
9 years ago
if flagNotEmptyVals and \
("_ver" in vals[0] or
(flagFunction and searchFunct.group(
1) in
("pkg", "merge", "mergepkg")) or
9 years ago
(flagFunction and searchFunct.group(
1) == "load" and
re.search("\(\s*ver\s*,",
9 years ago
vals[0]))):
# Проверка значения на версию (или интервал)
if (not self._isVersion(vals[1]) and
not self._isIntervalVersion(vals[1])):
9 years ago
self.setError("'%s'" % rpl(term) + " " + \
_("incorrect"))
12 years ago
self.setError(
_("This value is not a version"))
14 years ago
return False
# Проверка значения функции на версию
if not self._isVersion(valVars):
9 years ago
self.setError("'%s'" % rpl(term) + " " + \
_("incorrect"))
9 years ago
self.setError(
12 years ago
_("The function value is not a version"))
return False
if self._isIntervalVersion(vals[1]):
res = False
try:
res = self._checkInterval(
valVars, sepF, vals[1])
except TemplatesError:
self.setError("'%s'" % rpl(term) + " " + \
_("incorrect"))
self.setError(
_("Wrong interval operator"))
else:
verFile, verVar = self._convertVers(vals[1],
valVars)
res = dictRuleFunc[sepF](verVar, verFile)
if res:
listEqual.append(True)
else:
listEqual.append(False)
break
else:
14 years ago
if flagIntTypeVar is None:
flagIntTypeVar = True
try:
valVars = int(valVars)
except (TypeError, ValueError):
14 years ago
flagIntTypeVar = False
if flagIntTypeVar:
if not vals[1].strip():
14 years ago
vals[1] = 0
try:
valFile = int(vals[1])
valVar = valVars
res = dictRuleFunc[sepF](valVar, valFile)
if res:
listEqual.append(True)
else:
listEqual.append(False)
break
9 years ago
except ValueError:
flagIntTypeVar = False
if not flagIntTypeVar:
14 years ago
if sepF == "!=" or sepF == "==":
if not vals[1].strip():
vals[1] = ""
valFile = vals[1]
valVar = valVars
res = dictRuleFunc[sepF](valVar, valFile)
14 years ago
if res:
listEqual.append(True)
else:
listEqual.append(False)
break
else:
14 years ago
if not flagNotEmptyVals:
listEqual.append(False)
break
14 years ago
else:
9 years ago
self.setError("'%s'" % rpl(term) + " " \
+ _("incorrect"))
14 years ago
self.setError(textError)
return False
else:
if t == "and":
if listEqual == [] or False in listEqual:
listEqual = [False]
break
14 years ago
else:
listEqual = [True]
else:
9 years ago
self.setError("'%s'" % rpl(term) + " " + _("incorrect"))
14 years ago
self.setError(textError)
return False
if not (listEqual == [] or False in listEqual):
break
if listEqual == [] or False in listEqual:
return False
return True
def splitParLine(self, linePar):
9 years ago
"""
Split params line
"""
def splitQuote(listPar, quoteSymbol):
listTerm = [x + quoteSymbol for x in ("=", ">", "<")]
flagQ = False
mass = []
v = ""
for i in listPar:
9 years ago
if i.count(quoteSymbol) == 1:
if flagQ and i.endswith(quoteSymbol):
v = v + " " + i
mass.append(v)
v = ""
flagQ = False
elif [x for x in listTerm if x in i]:
flagQ = True
v = i
else:
9 years ago
mass.append(i)
elif flagQ:
v = v + " " + i
else:
mass.append(i)
9 years ago
foundPar = list(set(mass) - set(listPar))
return not flagQ, [x for x in mass if not x in foundPar], foundPar
listPar = re.split("\s+", linePar)
flagFoundQ = "'" in linePar
flagFoundQQ = '"' in linePar
if flagFoundQ and flagFoundQQ:
9 years ago
flagQ, listSplQPar, listFoundQPar = splitQuote(listPar, "'")
if flagQ:
flagQQ, listSplQQPar, listFoundQQPar = splitQuote(listSplQPar, '"')
if flagQQ:
listPar = listSplQQPar + listFoundQPar + listFoundQQPar
elif flagFoundQQ:
9 years ago
flagQQ, listSplQQPar, listFoundQQPar = splitQuote(listPar, '"')
if flagQQ:
listPar = listSplQQPar + listFoundQQPar
elif flagFoundQ:
9 years ago
flagQ, listSplQPar, listFoundQPar = splitQuote(listPar, "'")
if flagQ:
listPar = listSplQPar + listFoundQPar
if flagFoundQ:
listQPar = []
for par in listPar:
9 years ago
if par.endswith("'") and par.count("'") > 1:
listQPar.append(par[:-1].replace("='", "="))
else:
listQPar.append(par)
listPar = listQPar
if flagFoundQQ:
listQQPar = []
for par in listPar:
9 years ago
if par.endswith('"') and par.count('"') > 1:
listQQPar.append(par[:-1].replace('="', '='))
else:
listQQPar.append(par)
listPar = listQQPar
return listPar
class HParams():
Format = "format"
DotAll = "dotall"
Multiline = "multiline"
Comment = "comment"
Append = "append"
Force = "force"
DConf = "dconf"
Convert = "convert"
Link = "link"
DirectoryLink = Link
Mirror = "mirror"
Symbolic = "symbolic"
ChangeMode = "chmod"
ChangeOwner = "chown"
Name = "name"
Path = "path"
Autoupdate = "autoupdate"
Protected = "protected"
RunNow = "run"
RunPost = "exec"
Merge = "merge"
PostMerge = "postmerge"
Module = "module"
Environ = "env"
RestartService = "restart"
StartService = "start"
StopService = "stop"
Rebuild = "rebuild"
Stretch = "stretch"
ServiceControl = (StopService, StartService, RestartService)
_Single = (DotAll, Multiline, Force, Mirror, Symbolic, Autoupdate,
Protected, Stretch)
class AppendParams():
Join = "join"
Before = "before"
After = "after"
Replace = "replace"
Remove = "remove"
Skip = "skip"
Patch = "patch"
Clear = "clear"
LinkDirCompatible = (Replace, Join)
class ActionType():
Merge = "merge"
Patch = "patch"
Profile = "profile"
class ExecuteType():
Now = "run"
Post = "exec"
class Formats():
Executable = ("diff", "dconf", "ldif", "contents", "sqlite",
"backgrounds")
Meta = ("backgrounds",)
Modificator = ("sqlite",)
class OptDir():
Path = "path"
Skip = "skip"
Autoupdate = "autoupdate"
9 years ago
@classmethod
def single(cls, it):
return [x for x in it if x in cls._Single]
class fileHeader(HParams, _terms):
"""Обработка заголовков шаблонов и конфигурационных файлов
"""
# Допустимые параметры заголовка
allowParam = (
HParams.Format, HParams.DotAll, HParams.Multiline, HParams.Comment,
HParams.Append, HParams.Force, HParams.DConf, HParams.Convert,
HParams.Link, HParams.Mirror, HParams.Symbolic, HParams.Stretch,
HParams.ChangeMode, HParams.ChangeOwner,
HParams.Name, HParams.Path, HParams.Autoupdate,
HParams.Protected, HParams.RunNow, HParams.RunPost,
HParams.Merge, HParams.PostMerge, HParams.Module, HParams.Environ,
HParams.RestartService, HParams.StartService, HParams.StopService,
HParams.Rebuild
)
# Тип шаблона
fileType = ""
# Тип вставки шаблона
typeAppend = ""
# Возможные типы вставки шаблонов
_fileAppend = (
HParams.AppendParams.Join,
HParams.AppendParams.Before,
HParams.AppendParams.After,
HParams.AppendParams.Replace,
HParams.AppendParams.Remove,
HParams.AppendParams.Skip,
HParams.AppendParams.Patch,
HParams.AppendParams.Clear)
# Интерпретатор (#!/bin/bash) (#!/usr/bin/python)
execStr = ""
# Символ комментария
comment = False
# Выражение для поиска строки интерпретатора
reExecStr = re.compile("^(#!/.+[^#]\s)", re.M)
# условные операторы
terms = ('>', '<', '==', '!=', '>=', '<=', '<>', '=>')
# параметры без значения
listParNotVal = HParams.single(allowParam)
# Результат вычисления условия в заголовке
headerTerm = True
9 years ago
def __init__(self, templateName, text, comment=None, fileType=False,
objVar=False, function=None, templateObj=None):
self.body = text
# Объект с переменными
9 years ago
self.objVar = objVar
# Параметры описанные в заголовке файла шаблона
self.params = {}
# некорректные параметры
incorrectParams = []
used_params = []
14 years ago
# Поиск строки запустка (#!/bin/bash и.т. д)
9 years ago
if comment or fileType != "bin":
14 years ago
reExecRes = self.reExecStr.search(self.body)
if reExecRes:
self.execStr = self.body[reExecRes.start():reExecRes.end()]
9 years ago
self.body = self.body[:reExecRes.start()] + \
self.body[reExecRes.end():]
# Удаление Заголовка Calculate
if comment:
titleFirst = "Modified"
# В случае текста XML
9 years ago
if isinstance(comment, tuple) and len(comment) == 2:
reCalcHeader = \
re.compile("\s*%s\s+%s.+\s+(.+\n)+%s\s?" \
9 years ago
% (comment[0], titleFirst, comment[1]),
re.M | re.I)
reS = reCalcHeader.search(self.body)
if reS:
9 years ago
self.body = self.body[:reS.start()] + self.body[reS.end():]
else:
9 years ago
reCalcHeader = re.compile(
"\s*%s\-+\s+%s\s+%s.+\s+(%s.+\s+)+%s\-+\s?" \
9 years ago
% (comment, comment, titleFirst, comment, comment),
re.M | re.I)
reS = reCalcHeader.search(self.body)
if reS:
self.body = self.body[reS.end():]
9 years ago
if fileType is not False:
if fileType == "bin":
self.params[HParams.Format] = fileType
self.fileType = self._getType()
self.typeAppend = self._getAppend()
else:
textLines = self.body.splitlines()
if textLines:
textLine = textLines[0]
#py3 regex problems
9 years ago
rePar = re.compile(
"\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$", re.I)
reP = rePar.search(textLine)
if reP:
9 years ago
reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*", re.M)
reLs = reLns.search(self.body)
if reLs:
reL = reLs
paramLine = self.body[reP.end():reLs.end()]
9 years ago
paramLine = paramLine.replace("\\", " ")
else:
reLn = re.compile("\n")
reL = reLn.search(self.body)
paramLine = textLine[reP.end():]
if reL:
self.body = self.body[reL.end():]
else:
self.body = ""
paramList = self.splitParLine(paramLine)
if paramList:
for i in paramList:
for term in self.terms:
if term in i:
if self.headerTerm:
errorMsg = (
_("Incorrect template") +
_(": ") + templateName + "\n" +
_("template header not valid") +
_(": ") + i)
if function:
rezTerm = self._equalTerm(
i, errorMsg, function)
else:
rezTerm = self._equalTerm(
i, errorMsg)
if not rezTerm:
self.headerTerm = False
break
else:
par = i.split("=")
if len(par) == 1:
if i in self.listParNotVal:
self.params[i] = "True"
used_params.append(i)
else:
if i.strip():
9 years ago
incorrectParams = {i}
elif len(par) == 2:
par[1] = self.applyVarsTemplate(
par[1], "")
par[1] = templateObj.applyFuncTemplate(
par[1], templateName)
self.params[par[0]] = par[1]
used_params.append(par[0])
if par[0] == HParams.Environ:
try:
9 years ago
importlib.import_module(
"calculate.%s.variables"
9 years ago
% par[1])
except (ImportError,
9 years ago
AttributeError):
self.headerTerm = False
self.comment = self._getComment()
self.fileType = self._getType()
14 years ago
typeAppend = self._getAppend()
if typeAppend:
self.typeAppend = typeAppend
else:
self.headerTerm = False
self.setError(
_("incorrect header parameter: '%s'")
% "%s=%s" % (HParams.Append,
self.params[HParams.Append]))
if any(x in self.params for x in (HParams.RunPost,
HParams.RunNow)):
if HParams.RunPost in self.params:
self.execStr = "#!%s\n" % self.params[HParams.RunPost]
if HParams.RunNow in self.params:
self.execStr = "#!%s\n" % self.params[HParams.RunNow]
if "python" in self.execStr:
self.execStr += "# -*- coding: utf-8 -*-\n"
double_params = list(set([x for x in used_params
if used_params.count(x) > 1]))
if double_params:
self.headerTerm = False
8 years ago
self.setError(_("redefine header parameter: '%s'")
% " ".join(double_params))
if not incorrectParams and self.params:
incorrectParams = set(self.params.keys()) - set(self.allowParam)
if incorrectParams:
self.headerTerm = False
9 years ago
self.setError(_("incorrect header parameter: '%s'") \
% " ".join(list(incorrectParams)))
def _getType(self):
"""Выдать тип файла"""
return self.params.get(HParams.Format, "raw")
def _getAppend(self):
"""Выдать тип добавления файла"""
if HParams.Append in self.params:
if self.params[HParams.Append] in self._fileAppend:
return self.params[HParams.Append]
14 years ago
else:
return False
else:
9 years ago
if self.fileType != "raw" and self.fileType != "bin" and \
self.fileType != "":
if (HParams.Format in self.params and
self.params[HParams.Format] in
chain(("patch",), HParams.Formats.Executable)):
self.params[HParams.Append] = HParams.AppendParams.Patch
else:
self.params[HParams.Append] = HParams.AppendParams.Join
else:
self.params[HParams.Append] = HParams.AppendParams.Replace
return self.params[HParams.Append]
def _getComment(self):
"""Выдать символ комментария файла"""
if HParams.Comment in self.params:
if self.params[HParams.Comment] in ("xml", "XML"):
9 years ago
return "<!--", "-->"
else:
return self.params[HParams.Comment]
else:
return False
class dirHeader(HParams, _terms):
"""Обработка заголовков шаблонов директорий
"""
# Допустимые параметры заголовка
allowParam = (
HParams.Append, HParams.ChangeMode,
HParams.ChangeOwner, HParams.Name,
HParams.Path, HParams.Autoupdate,
HParams.Module, HParams.Environ,
HParams.Merge, HParams.PostMerge,
HParams.Rebuild,
HParams.RestartService, HParams.StartService, HParams.StopService,
HParams.DirectoryLink
)
# Тип вставки шаблона
typeAppend = ""
14 years ago
# Возможные типы вставки шаблонов
_fileAppend = (
HParams.AppendParams.Join,
HParams.AppendParams.Remove,
HParams.AppendParams.Skip,
HParams.AppendParams.Clear,
HParams.AppendParams.Replace
)
14 years ago
# условные операторы
terms = ('>', '<', '==', '!=', '>=', '<=', '<>', '=>')
14 years ago
# параметры без значения
listParNotVal = (HParams.Symbolic, HParams.Force,
HParams.Autoupdate)
14 years ago
# Результат вычисления условия в заголовке
headerTerm = True
def __init__(self, templateName, text, objVar=False, function=None,
templateObj=None):
self.body = text
# Объект с переменными
9 years ago
self.objVar = objVar
# Параметры описанные в заголовке файла шаблона
self.params = {}
# некорректные параметры
incorrectParams = set([])
used_params = []
textLines = text.splitlines()
flagErrorBody = False
if textLines:
textLine = textLines[0]
#py3 regex problems
9 years ago
rePar = re.compile(
"\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$", re.I)
reP = rePar.search(textLine)
if reP:
9 years ago
reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*", re.M)
reLs = reLns.search(text)
if reLs:
reL = reLs
paramLine = text[reP.end():reLs.end()]
paramLine = paramLine.replace("\\", " ")
else:
reLn = re.compile("\n")
reL = reLn.search(text)
paramLine = textLine[reP.end():]
if reL:
self.body = text[reL.end():]
else:
self.body = ""
if self.body.strip():
self.headerTerm = False
9 years ago
self.setError(_("incorrect text in the template: '%s'")
9 years ago
% self.body)
flagErrorBody = True
if not flagErrorBody:
paramList = self.splitParLine(paramLine)
if paramList:
for i in paramList:
for term in self.terms:
if term in i:
if self.headerTerm:
errorMsg = (
_("Incorrect template") +
_(": ") + templateName + "\n" +
_("template header not valid")
+ _(": ") + i)
if function:
rezTerm = self._equalTerm(
i, errorMsg, function)
else:
rezTerm = self._equalTerm(
i, errorMsg)
if not rezTerm:
self.headerTerm = False
break
else:
par = i.split("=")
if len(par) == 1:
if i in self.listParNotVal:
self.params[i] = "True"
used_params.append(i)
else:
if i.strip():
9 years ago
incorrectParams = {i}
elif len(par) == 2:
# self.params[par[0]] = par[1]
par[1] = self.applyVarsTemplate(
par[1], "")
par[1] = templateObj.applyFuncTemplate(
par[1], templateName)
used_params.append(par[0])
self.params[par[0]] = par[1]
if par[0] == HParams.Environ:
try:
9 years ago
importlib.import_module(
"calculate.%s.variables" %
par[1])
except (ImportError, AttributeError):
self.headerTerm = False
12 years ago
self.objVar.defaultModule = \
self.params[HParams.Environ]
typeAppend = self._getAppend()
if typeAppend:
self.typeAppend = typeAppend
else:
self.headerTerm = False
9 years ago
self.setError(_("incorrect header parameter: '%s'") \
% "%s=%s" % (
HParams.Append,
self.params[HParams.Append]))
double_params = list(set([x for x in used_params
if used_params.count(x) > 1]))
if double_params:
self.headerTerm = False
8 years ago
self.setError(_("redefine header parameter: '%s'")
% " ".join(double_params))
if not flagErrorBody:
if not incorrectParams:
incorrectParams = set(self.params.keys()) - set(self.allowParam)
if incorrectParams:
self.headerTerm = False
9 years ago
self.setError(_("incorrect header parameter: '%s'") \
% " ".join(list(incorrectParams)))
def _getAppend(self):
"""Выдать тип добавления директории"""
if HParams.Append in self.params:
if (self.params[HParams.Append] == HParams.AppendParams.Replace and
HParams.DirectoryLink not in self.params):
return False
if self.params[HParams.Append] in self._fileAppend:
return self.params[HParams.Append]
else:
return False
else:
return HParams.AppendParams.Join
class blocText():
"""Разбиваем текст на блоки"""
9 years ago
def splitTxtToBloc(self, text, openTxtBloc, closeTxtBloc,
commentTxtBloc, sepField):
"""Делит текст на блоки (без заголовков)
openTxtBloc - регулярное выражение для начала блока
closeTxtBloc - регулярное выражение для конца блока
commentTxtBloc - регулярное выражение - комментарий
возвращает блоки текста
"""
blocs = []
level = 0
# Нахождение нескольких блоков в строке
# разделители линий, разделителями могут быть ("","\n")
sepsLines = []
# линии
txtLines = []
# Исходные строки
txtLinesSrc = text.splitlines()
for line in txtLinesSrc:
lineTmpA = line
closeBl = False
txtLinesTmp = []
commentSpl = commentTxtBloc.split(line)
9 years ago
textLine = None
commentLine = None
if commentSpl[0].strip():
closeBl = True
if len(commentSpl) > 1:
commentBl = commentTxtBloc.search(line)
9 years ago
textLine = commentSpl[0]
commentLine = line[commentBl.start(0):]
lineTmpA = textLine
9 years ago
while closeBl:
closeBl = sepField.search(lineTmpA)
if closeBl:
lineTmpB = lineTmpA[closeBl.end(0):]
txtLinesTmp.append(lineTmpA[:closeBl.end(0)])
lineTmpA = lineTmpB
if lineTmpA.strip():
txtLinesTmp.append(lineTmpA)
# Если есть значение и комментарий в строке
9 years ago
if textLine is not None:
for l in txtLinesTmp:
txtLines.append(l)
sepsLines.append("")
if not txtLinesTmp:
txtLines.append(textLine)
sepsLines.append("")
txtLines.append(commentLine)
sepsLines.append("\n")
# Если есть несколько блоков в строке
9 years ago
elif len(txtLinesTmp) > 1 and txtLinesTmp[1].strip():
lenTmpLines = len(txtLinesTmp)
for l in range(lenTmpLines):
txtLines.append(txtLinesTmp[l])
9 years ago
if l == lenTmpLines - 1:
sepsLines.append("\n")
else:
sepsLines.append("")
# Cтрока не преобразована
else:
txtLines.append(line)
sepsLines.append("\n")
# разбивание на блоки
z = 0
bl = ""
for i in txtLines:
if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(i):
level += len(openTxtBloc.split(i)) - 1
if commentTxtBloc.split(i)[0].strip() and closeTxtBloc.search(i):
level -= len(closeTxtBloc.split(i)) - 1
bl += i + sepsLines[z]
if level == 0:
if bl:
blocs.append(bl)
bl = ""
z += 1
# cоздание блоков с элементами не входящими в блоки
realBlocs = []
z = 0
bl = ""
for i in blocs:
txtLines = i.splitlines()
if len(txtLines) > 0:
line = txtLines[0]
else:
line = i
if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(line):
if bl:
realBlocs.append(bl)
bl = ""
realBlocs.append(i)
else:
bl += i
z += 1
if bl:
realBlocs.append(bl)
if level == 0:
if text and text[-1] != "\n":
tmpBlocs = realBlocs.pop()
tmpBlocs = tmpBlocs[:-1]
realBlocs.append(tmpBlocs)
return realBlocs
else:
return []
def findArea(self, text, reTextHeader, reTextArea, numGroupArea=0):
""" Делит текст на области (с заголовками)
reTextHeader - регулярное выражение для заголовка области
reTextArea - регулярное выражение для всей области
numGroupArea - номер групы результата поиска по регулярному выражению
по всей области
возвращает два списка: первый - заголовки, второй - тела областей без
заголоков
"""
# Заголовки областей
headersArea = []
# Тексты областей без заголовков
textBodyArea = []
r = reTextArea.search(text)
if not r:
headersArea.append("")
textBodyArea.append(text)
9 years ago
return headersArea, textBodyArea
txtWr = text
while r:
textArea = r.group(numGroupArea)
txtSpl = txtWr.split(textArea)
9 years ago
area = txtSpl[0]
txtWr = txtSpl[1]
if area:
headersArea.append("")
textBodyArea.append(area)
res = reTextHeader.search(textArea)
header = textArea[:res.end()]
body = textArea[res.end():]
headersArea.append(header)
textBodyArea.append(body)
if txtWr:
r = reTextArea.search(txtWr)
else:
r = False
if txtWr:
headersArea.append("")
textBodyArea.append(txtWr)
9 years ago
return headersArea, textBodyArea
def findBloc(self, text, captionTxtBloc, bodyTxtBloc):
""" Делит текст на блоки (с заголовками)
captionTxtBloc - регулярное выражение для заголовка блока
bodyTxtBloc - регулярное выражение для тела блока
возвращает два списка: первый - заголовки, второй - тела блоков
"""
# Заголовки блоков
headersTxt = []
# Тексты блоков
blocsTxt = []
r = captionTxtBloc.search(text)
if r:
headersTxt.append(r.group(0))
txtSpl = text.partition(r.group(0))
9 years ago
blocTxt = txtSpl[0]
txtWr = txtSpl[2]
rb = bodyTxtBloc.search(blocTxt)
if not blocTxt:
blocsTxt.append(blocTxt)
if rb:
blocsTxt.append(rb.group(0))
9 years ago
while r:
r = captionTxtBloc.search(txtWr)
if r:
headersTxt.append(r.group(0))
txtSpl = txtWr.partition(r.group(0))
9 years ago
blocTxt = txtSpl[0]
txtWr = txtSpl[2]
rb = bodyTxtBloc.search(blocTxt)
if rb:
blocsTxt.append(rb.group(0))
else:
blocsTxt.append(txtWr)
if headersTxt and blocsTxt:
9 years ago
if len(headersTxt) > len(blocsTxt):
blocsTxt.insert(0, "")
elif len(headersTxt) < len(blocsTxt):
headersTxt.insert(0, "")
if len(headersTxt) != len(blocsTxt):
return False
9 years ago
return headersTxt, blocsTxt
else:
return False
class _file(_error):
"""
9 years ago
Класс для работы с файлами
"""
configMode = None
def printWARNING(self, s):
raise NotImplemented()
def __init__(self):
14 years ago
# Имя файла конфигурационного файла
self.nameFileConfig = ""
self.nameFileConfigOrig = ""
14 years ago
# Содержимое конфигурационного файла
14 years ago
self.textConfig = ""
# Имя файла шаблона
self.nameFileTemplate = ""
14 years ago
# Содержимое шаблона
14 years ago
self.textTemplate = ""
# Дескриптор файла шаблона
9 years ago
self.F_TEMPL = None
14 years ago
# Дескриптор файла конфигурационного файла
9 years ago
self.F_CONF = None
# тип запускаемого шаблона
self.executeType = None
# список скриптов на запуск
self.queueExecute = []
14 years ago
def saveConfFile(self):
"""Записать конфигурацию"""
if not self.textConfig:
self.textConfig = self.textTemplate
14 years ago
if self.F_CONF:
try:
9 years ago
self.F_CONF.truncate(0)
self.F_CONF.seek(0)
if isinstance(self.textConfig, str):
self.F_CONF.write(self.textConfig.encode("UTF-8"))
elif isinstance(self.textConfig, bytes):
self.F_CONF.write(self.textConfig)
else:
#TODO if after testing this doesn't pop up, replace elif above with else
raise Exception(f"self.textConfig is not str or bytes: type == {type(self.textConfig)}")
9 years ago
except IOError:
12 years ago
self.setError(_("unable to open the file:")
9 years ago
+ self.nameFileConfig)
return False
14 years ago
self.F_CONF.flush()
return True
elif self.executeType == HParams.ExecuteType.Post:
processor = self.textConfig.partition("\n")[0]
if processor.startswith("#!"):
9 years ago
self.queueExecute.append((processor[2:], self.textConfig,
self.nameFileTemplate))
else:
12 years ago
self.setError(_("unable to execute '%s'")
9 years ago
+ self.textConfig)
return False
14 years ago
def openTemplFile(self, nameFileTemplate):
"""Открыть файл шаблона"""
try:
F_TEMPL = open(nameFileTemplate, "rb")
9 years ago
except IOError:
12 years ago
self.setError(_("unable to open the file:")
9 years ago
+ nameFileTemplate)
return False
14 years ago
return F_TEMPL
14 years ago
def closeTemplFile(self):
if self.F_TEMPL:
self.F_TEMPL.close()
9 years ago
self.F_TEMPL = None
def __closeOldFile(self):
14 years ago
if self.F_CONF:
self.F_CONF.close()
9 years ago
self.F_CONF = None
14 years ago
def __openConfFile(self, nameFileConfig):
14 years ago
"""Отктрыть конфигурационный файл"""
try:
14 years ago
if os.path.islink(nameFileConfig):
# если ссылка то удаляем её
14 years ago
os.unlink(nameFileConfig)
F_CONF = open(nameFileConfig, "rb+")
9 years ago
except (IOError, OSError):
try:
if os.path.isdir(nameFileConfig):
11 years ago
self.printWARNING(_("unable to open the directory as file:")
9 years ago
+ nameFileConfig)
return False
F_CONF = open(nameFileConfig, "wb+")
9 years ago
except (IOError, OSError):
12 years ago
self.setError(_("unable to open the file:")
9 years ago
+ nameFileConfig)
return False
14 years ago
return F_CONF
def openFiles(self, nameFileTemplate, nameFileConfig, typeFormat=None,
9 years ago
newBuffer=None):
"""Открывает шаблон и конфигурационный файл"""
14 years ago
self.textConfig = ""
self.textTemplate = ""
self.closeFiles()
9 years ago
self.F_TEMPL = None
self.F_CONF = None
14 years ago
self.nameFileConfig = os.path.abspath(nameFileConfig)
self.nameFileTemplate = os.path.abspath(nameFileTemplate)
self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
copy_stat = not os.path.exists(self.nameFileConfig)
if (not self.executeType and
typeFormat not in HParams.Formats.Executable):
self.F_CONF = self.__openConfFile(self.nameFileConfig)
14 years ago
if self.F_TEMPL and self.F_CONF:
self.textTemplate, ___ = try_decode_utf8(self.F_TEMPL.read())
self.closeTemplFile()
if self.configMode == T_NEWCFG:
origConfigName = re.sub(r'/._cfg\d{4}_([^/]+)$', '/\\1',
9 years ago
self.nameFileConfig)
if newBuffer is None:
self.textConfig = readFile(origConfigName)
if copy_stat:
self.copy_mod_own(origConfigName, self.nameFileConfig)
else:
self.textConfig = newBuffer
else:
self.textConfig, ___ = try_decode_utf8(self.F_CONF.read())
def copy_mod_own(self, source, target):
try:
statdata = os.stat(source)
statdata_old = os.stat(target)
if statdata.st_mode != statdata_old.st_mode:
os.chmod(target, statdata.st_mode)
if (statdata.st_uid != statdata_old.st_uid or
statdata.st_gid != statdata_old.st_gid):
os.chown(target, statdata.st_uid, statdata.st_gid)
except OSError:
pass
def __del__(self):
self.closeFiles()
def closeFiles(self):
"""Закрытие файлов"""
14 years ago
self.closeTemplFile()
self.__closeOldFile()
class utfBin():
"""Класс для преобразования в utf-8
преобразование бинарного или смеси бинарного и utf-8 кода в utf-8 и
обратное преобразование
методы класса encode и decode
"""
9 years ago
def _retUTF(self, char):
byte = ord(char)
9 years ago
if byte <= 127:
return '_ch_', 1
elif byte <= 191:
return '_nb_', 1
elif byte <= 223:
return '_fb_', 2
elif byte <= 239:
return '_fb_', 3
elif byte <= 247:
return '_fb_', 4
else:
9 years ago
return '_er_', 1
def _sumbUtf(self, symbols, lenTail):
if not symbols:
9 years ago
return False, 0
lenSymb = len(symbols)
if lenSymb >= 4:
l = 4
elif lenSymb >= 3:
l = 3
elif lenSymb >= 2:
l = 2
else:
if symbols[0] == '_ch_':
9 years ago
return True, 1
else:
9 years ago
return False, 1
result = False
9 years ago
i_ = 0
for i in range(l):
9 years ago
i_ = i
if i == 0 and symbols[i] != '_fb_':
break
elif i > 0 and symbols[i] != '_nb_':
9 years ago
break
if lenTail > 1 and lenTail != i_:
return False, 1
if i_ > 0:
result = True
9 years ago
return result, i_
def _intToChar(self, x):
he = hex(x)[2:]
return chr(int(he, 16))
def _hexToChar(self, he):
return chr(int(he, 16))
def encode(self, text):
"""Кодирует смешанный формат в UTF-8"""
ind = 0
utf = []
lenUtf = []
indErr = []
i = 0
for ch in text:
r, l = self._retUTF(ch)
utf.append(r)
lenUtf.append(l)
9 years ago
i += 1
while 1:
if utf[ind] == '_fb_':
9 years ago
res, l = self._sumbUtf(utf[ind:], lenUtf[ind])
if res is False:
indErr.append(ind)
9 years ago
if l > 0:
ind += l
if ind >= len(utf):
break
else:
if utf[ind] != '_ch_':
indErr.append(ind)
9 years ago
ind += 1
if ind >= len(utf):
break
if indErr:
lenIndErr = len(indErr)
block = []
blocks = []
if lenIndErr > 1:
i = 1
while 1:
if i == 1:
9 years ago
block.append(indErr[i - 1])
if indErr[i] - indErr[i - 1] == 1:
block.append(indErr[i])
else:
if block:
blocks.append(block)
9 years ago
block = [indErr[i]]
i += 1
if i >= lenIndErr:
break
else:
block.append(indErr[0])
if block:
blocks.append(block)
listErr = []
for block in blocks:
string = ""
9 years ago
last_elem = None
for elem in block:
string += hex(ord(text[elem]))[-2:]
9 years ago
last_elem = elem
if last_elem is not None:
listErr.append((block[0], "__hex__?%s?__hex__" % string,
last_elem))
textOut = text
deltaInd = 0
for erEl in listErr:
startInd = erEl[0] + deltaInd
endInd = erEl[2] + 1 + deltaInd
textOut = textOut[:startInd] + erEl[1] + textOut[endInd:]
9 years ago
deltaInd += len(erEl[1]) - (erEl[2] - erEl[0] + 1)
# if i == 1:
# break
# i += 1
return textOut
def decode(self, text):
"""Декодирует UTF-8 в смешанный формат"""
varStart = "__hex__\?"
varEnd = "\?__hex__"
# -1 Это экранирование '?' которое тоже считается
9 years ago
deltVarStart = len(varStart) - 1
deltVarEnd = len(varEnd) - 1
reVar = re.compile("%s[a-f0-9]+%s" % (varStart, varEnd), re.M)
resS = reVar.search(text)
textTemplateTmp = text
while resS:
mark = textTemplateTmp[resS.start():resS.end()]
hexString = mark[deltVarStart:-deltVarEnd]
i = 0
stringInsert = ""
hexCode = ""
for ch in hexString:
9 years ago
if i >= 1:
hexCode += ch
stringInsert += self._hexToChar(hexCode)
hexCode = ""
i = 0
else:
hexCode += ch
i += 1
textTemplateTmp = textTemplateTmp.replace(mark, stringInsert)
resS = reVar.search(textTemplateTmp)
return textTemplateTmp
9 years ago
class TemplateFormat(_error):
"""
Формат шаблон
"""
def __init__(self, text, parent=None):
self.text = text
self.changed_files = []
self.set_parent(parent)
self.prepare()
def prepare(self):
pass
def setError(self, error):
super().setError(error)
if hasattr(self.parent, "bHasError"):
self.parent.bHasError = True
def set_parent(self, parent):
self.parent = parent
@property
def template_name(self):
return self.parent.nameFileTemplate
def getIni(self, key, nameFile=""):
return self.parent.functObj.getIni(key, nameFile)
def setIni(self, key, value, nameFile=""):
return self.parent.functObj.setIni(key, value, nameFile)
@property
def objVar(self):
return self.parent.objVar
class FormatFactory():
"""
Фабрика классов форматов шаблонов
"""
# Импортированные классы поддерживаемых форматов шаблонов
importFormats = {}
9 years ago
newObjProt = {}
def __init__(self, parent):
self.parent = parent
9 years ago
def createNewClass(self, name, bases, attrs=None):
raise NotImplemented()
def getClassObj(self, nameClassTemplate):
"""Создает класс шаблона по имени"""
if nameClassTemplate in self.importFormats:
classFormat = self.importFormats[nameClassTemplate]
else:
try:
9 years ago
classFormat = getattr(__import__("calculate.lib.format.%s" %
nameClassTemplate,
globals(), locals(),
[nameClassTemplate]),
nameClassTemplate)
except (ImportError, AttributeError) as e:
9 years ago
# Создаем объект из self.newObjProt с помощью
# метаклассов
if nameClassTemplate in self.newObjProt:
# Прототип класса
nameProt = self.newObjProt[nameClassTemplate]
if nameProt in self.importFormats:
classProt = self.importFormats[nameProt]
else:
try:
classProt = getattr(
9 years ago
__import__("calculate.lib.format.%s" % nameProt,
globals(), locals(),
[nameProt]),
nameProt)
except (ImportError, AttributeError) as e:
return False
self.importFormats[nameProt] = classProt
classFormat = self.createNewClass(nameClassTemplate,
(classProt,))
else:
return False
self.importFormats[nameClassTemplate] = classFormat
return classFormat
def createObject(self, formatTemplate, textTemplate):
"""Создание объекта формата шаблона.
Объект создается на основании формата шаблона и текста шаблона"""
classFormat = self.getClassObj(formatTemplate)
9 years ago
if callable(classFormat):
obj = classFormat(textTemplate, self.parent)
return obj
else:
return False
class TemplateFunctionError(Exception):
pass
def template_function(lastall=False):
"""
Подготовить метод для использования в качестве функции
lastall: поволяет поделить строку аргументов на указанное число,
при этом последний аргумент получит все данные, которые
могут содержать разделитель параметров
"""
def decor(f):
@wraps(f)
def wrapper(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
def pretty_num(num):
if num > 1:
return _("%d argumens") % num
else:
return _("1 argument")
funArgv = funArgv.strip()
# поиск всех служебных переменных
3 years ago
spec_vars = [x for x in f.__code__.co_varnames[:f.__code__.co_argcount]
if x in ("self", "nameTemp", "localVars")]
3 years ago
varnum = f.__code__.co_argcount - len(spec_vars)
defnum = len(f.__defaults__) if f.__defaults__ else 0
# число обязательных параметров
reqnum = varnum - defnum
if funArgv:
terms = [x.strip() for x in funArgv.split(",")]
else:
terms = []
if not varnum and len(terms) != varnum:
raise self.raiseErrTemplate(_("Function takes no arguments"))
if len(terms) < reqnum:
if defnum:
raise self.raiseErrTemplate(
_("Function takes at least {num}").format(
num=pretty_num(reqnum)))
else:
raise self.raiseErrTemplate(
_("Function takes exactly {num}").format(
num=pretty_num(reqnum)))
if not lastall:
if len(terms) > varnum:
if defnum:
raise self.raiseErrTemplate(
_("Function takes at most {num}").format(
num=pretty_num(varnum)))
else:
raise self.raiseErrTemplate(
_("Function takes exactly {num}").format(
num=pretty_num(varnum)))
else:
terms = terms[:varnum-1] + [",".join(terms[varnum-1:])]
args = [self]
if "nameTemp" in spec_vars:
args.append(nameTemp)
if "localVars" in spec_vars:
args.append(localVars)
args.extend(terms)
try:
replace = f(*args)
except TemplateFunctionError as e:
raise self.raiseErrTemplate(str(e))
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
return wrapper
return decor
9 years ago
class templateFunction(_error, _warning, _shareTemplate, _shareTermsFunction,
LayeredIni):
"""Класс для функций шаблонов"""
# Словарь установленных программ {"имя программы":[версии]}
installProg = {}
# Cписок просканированных категорий установленных программ
installCategory = []
# Флаг сканирования всех установленных программ
flagAllPkgScan = False
# Список названий функций шаблона
namesTemplateFunction = []
# Словарь {название функции шаблона: функция шаблона, ...}
templateFunction = {}
# Регулярное выражение для сложения
sNum = re.compile("\-[^\-\+]+|[^\-\+]+")
# Регулярное выражение для умножениея и деления
sMD = re.compile("[^\-\+\*/]+")
# директория установленных программ
_basePkgDir = "/var/db/pkg"
basePkgDir = _basePkgDir
# кэш для проверки наличия пакета в портежах
cachePortdir = {}
# стек глобальных переменных
stackGlobalVars = []
# регулярное выражение для поиска версии
reFindVer = re.compile("(?<=-)(?:\d+)(?:(?:\.\d+)*)"
"(?:[a-z]?)(?:(?:_(?:pre|p|beta|alpha|rc)\d*)*)"
"(?:-r\d+)?$")
reEmptyLoad = re.compile("^\s*$|^\s*;|^\s*#")
# Имя обрабатываемого шаблона
nameTemplate = ""
# Текст функции шаблона
functText = ""
# regular for discard sort number and version
reData = re.compile(r"^(?:\d+-)?(.+?)(?:-(?:|always|\d+|\d(?:\d|\.|pre|_"
"|-always|alpha|beta|pre|rc|[a-z][^a-z])*[a-z]?)(?:"
"-r\d+)?)?$", re.S)
9 years ago
currentAction = HParams.ActionType.Merge
9 years ago
def printSUCCESS(self, s):
raise NotImplemented()
def printWARNING(self, s):
raise NotImplemented()
def printERROR(self, s):
raise NotImplemented()
@classmethod
def get_pkgname_by_filename(cls, fn):
fileName = os.path.split(fn)[1]
if fileName == '.calculate_directory':
parentDir = os.path.dirname(fn)
parentDir, pkgName = os.path.split(parentDir)
else:
parentDir, pkgName = os.path.split(fn)
category = os.path.split(parentDir)[1]
# reg for discard version and sort number
pkgName = cls.reData.search(pkgName).group(1)
category = cls.reData.search(category).group(1)
9 years ago
return "%s/%s" % (category, pkgName)
currentBelong = ""
currentBelongSlot = ""
11 years ago
alreadyInformed = []
def __init__(self, objVar):
# Если не определен словарь функций шаблона
# import services api
LayeredIni.__init__(self)
if not self.templateFunction:
# префикс функций шаблона
pref = "func"
# cписок [(название функции, функция), ...]
# удаляем у названия функции префикс и переводим остаток названия
# в нижний регистр
dictFunc = [(x[0][len(pref):].lower(), x[1]) for x
in self.__class__.__dict__.items()
if x[0].startswith(pref) and hasattr(x[1], "__call__")]
# Формируем словарь функций шаблона
self.templateFunction.update(dictFunc)
# Формируем список функций шаблона
for nameFunction in self.templateFunction.keys():
self.namesTemplateFunction.append(nameFunction)
# Объект хранения переменных
self.objVar = objVar
self._reFunc = re.compile("%s%s%s"
9 years ago
% (self.varStart, self._reFunctionText,
self.varEnd), re.M)
self._rePrePattern = "%s.{%%d,}?%s" % (self.varStart, self.varEnd)
self._rePreFuncPattern = "%s.{%%d,}?\)%s" % (self.varStart, self.varEnd)
# Аттрибуты для функции шаблона ini()
# Первоначальный словарь переменных для ini()
self.prevDictIni = {}
# Текущий словарь переменных для ini()
self.currDictIni = {}
# Время модификации конфигурационного файла для ini()
self.timeIni = -1
self.recalculateBaseDir()
# Словарь времен модификации env файлов
self.timeConfigsIni = {}
# Словарь хранения переменых полученных функцией env() из env файлов
self.valuesVarEnv = {}
# Словарь хранения опций для функции info()
self.optionsInfo = {}
# файл параметров сервисов
envFile = self.objVar.Get("cl_env_server_path")
# объект конвертирования из старого remote env файла
self.convObj = False
if os.access(envFile, os.R_OK):
self.convObj = False
elif os.access("/var/calculate/remote/calculate.env", os.R_OK):
3 years ago
from .convertenv import convertEnv
9 years ago
self.convObj = convertEnv()
def recalculateBaseDir(self):
"""Recalculate basedir and homedir"""
# Директория другой системы
self._chrootDir = self.objVar.Get("cl_chroot_path")
# Изменение директории к базе пакетов
self.basePkgDir = pathJoin(self._chrootDir, self._basePkgDir)
self.basePkgDir = os.path.normpath(self.basePkgDir)
# Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
9 years ago
self._baseDir = pathJoin(self._chrootDir,
self.objVar.Get("cl_root_path"))
self._baseDir = os.path.normpath(self._baseDir)
9 years ago
self.uid, self.gid, self.homeDir, self.groups = \
self.getDataUser(groupsInfo=True)
# Домашняя директория, плюс базовая директория
self.homeDir = pathJoin(self._baseDir, self.homeDir)
# path to configuration file for ini() function
# if action is desktop configuration, then path in user directory
# else config file place in /etc/calculate
if self.objVar.Get('cl_action') == "desktop":
self.pathConfigIni = os.path.join(self.homeDir, ".calculate")
self.fileConfigIni = os.path.join(self.pathConfigIni,
LayeredIni.IniPath.IniName)
3 years ago
self.modeConfigIni = 0o640
else:
self.fileConfigIni = pathJoin(self._chrootDir,
LayeredIni.IniPath.Work)
self.pathConfigIni = os.path.dirname(self.fileConfigIni)
3 years ago
self.modeConfigIni = 0o644
def equalTerm(self, term, localVars):
"""Метод для вычисления выражения"""
terms = self.sNum.findall(term)
if terms:
strNumers = []
for n in terms:
strNum = n.strip()
if "*" in strNum or "/" in strNum:
9 years ago
strNum = self.multAndDiv(strNum, localVars)
num = 0
try:
num = int(strNum)
9 years ago
except ValueError:
minus = False
if strNum[:1] == "-":
minus = True
strNum = strNum[1:]
3 years ago
if strNum in localVars:
try:
num = int(localVars[strNum])
9 years ago
except ValueError:
raise self.raiseErrTemplate(
_("error: variable %s is not integer") %
str(strNum))
elif self.objVar.exists(strNum):
try:
num = int(self.objVar.Get(strNum))
9 years ago
except ValueError:
raise self.raiseErrTemplate(
_("error: variable %s is not integer") %
str(strNum))
else:
9 years ago
raise self.raiseErrTemplate(
_("error: local variable %s not defined") %
str(strNum))
if minus:
num = -num
strNumers.append(num)
return sum(strNumers)
9 years ago
raise self.raiseErrTemplate(_("error: template term %s, incorrect data") \
% str(term))
def multAndDiv(self, term, localVars):
"""Метод для умножения и деления"""
termTmp = term
varsLocal = self.sMD.findall(term)
for var in varsLocal:
flagVarTxt = True
try:
int(var)
9 years ago
except ValueError:
flagVarTxt = False
if flagVarTxt:
continue
varReplace = str(self.equalTerm(var, localVars))
9 years ago
termTmp = termTmp.replace(var, varReplace)
ret = eval(termTmp)
return ret
def getIni(self, key, nameTemp=""):
class FakeMatch():
def start(self):
return 0
def end(self):
return 0
return self.funcIni(key, FakeMatch(), None, "", nameTemp)
def setIni(self, key, value, nameTemp=""):
class FakeMatch():
def start(self):
return 0
def end(self):
return 0
self.funcIni("%s,%s" % (key, value), FakeMatch(), None, "", nameTemp)
def funcProfile(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Функция проверят состояние пользовательского профиля:
configured - профиль настраивался утилитами calculate
empty - профиль пустой, либо содержит skel, либо сертификат утилит
custom - профиль настроен и он настраивался не утилитами
"""
ini_value = self.funcIni("main.update", resS, localVars, "", nameTemp)
if ini_value:
replace = "configured"
else:
user_dir = self.objVar.Get('ur_home_path')
if isBootstrapDataOnly(user_dir):
replace = "empty"
else:
replace = "custom"
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
def check_command(self, command, prefix="/"):
cmd = getProgPath(command, prefix=prefix)
if not cmd:
raise self.raiseErrTemplate(
_("Command not found '%s'")%command)
return cmd
def warning_message(self, message):
if callable(self.printWARNING):
self.printWARNING(message)
@template_function()
def funcWorld(self, category):
"""
Функция выполняет eix и возвращает список пакетов
"""
prefix = self.objVar.Get('cl_chroot_path')
nfenv = dict(os.environ)
nfenv["NOFOUND_STATUS"]="0"
kwargs = {'lang':'C', 'envdict': nfenv}
if prefix == "/":
args = [self.check_command("/usr/bin/eix", prefix=prefix)]
else:
args = ["/bin/chroot", prefix, self.check_command("/usr/bin/eix", prefix=prefix)]
args.extend(["-*", "--format", "<bestslotversions:NAMEASLOT>"])
if "/" in category:
args.extend(["-e", category])
else:
args.extend(["--category", "-e", category])
p = process(*args, **kwargs)
if p.success():
atoms = [x for x in p.read().split() if x.strip()]
if not atoms:
self.warning_message(_("No packages in %s category")%category)
return "\n".join(atoms)
else:
raise TemplateFunctionError(_("Failed to execute") + _(": ") +
"eix")
def funcLs(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Функция получения списка файлов из директории
"""
globpath, o, pattern = funArgv.partition(',')
if not pattern:
pattern = r" "
pattern = pattern.replace(r"\1", "{0}")
pattern = re.sub(r"(^|[^\\])\\n", "\\1\n", pattern)
pattern = pattern.replace(r"\n", "\n")
pattern = pattern.replace(r"\t", "\t")
chroot_path = os.path.normpath(self.objVar.Get('cl_chroot_path'))
globpath = pathJoin(chroot_path, globpath)
if "*" in globpath:
files = glob.glob(globpath)
else:
files = listDirectory(globpath, fullPath=True)
if files:
files = (x for x in files if not os.path.isdir(x))
if chroot_path != '/':
l = len(chroot_path)
files = (x[l:] for x in files)
if r"{0}" not in pattern:
replace = pattern.join(files)
else:
replace = "".join(pattern.format(x) for x in files)
else:
replace = ""
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
8 years ago
def funcForeach(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Функция получения списка файлов из директории
"""
varname, o, pattern = funArgv.partition(',')
values = ""
try:
values = self.objVar.Get(varname)
3 years ago
except DataVarsError as e:
8 years ago
raise TemplatesError(_("error: variable %s does not exist")
% varname)
if not pattern:
pattern = r" "
if values:
pattern = pattern.replace(r"\1", "{0}")
pattern = re.sub(r"(^|[^\\])\\n", "\\1\n", pattern)
pattern = pattern.replace(r"\n", "\n")
pattern = pattern.replace(r"\t", "\t")
8 years ago
if r"{0}" not in pattern:
replace = pattern.join(values)
else:
replace = "".join(pattern.format(x) for x in values)
else:
replace = ""
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
9 years ago
def funcSum(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона, вычисляет функцию sum()"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
# Название локальной переменной
nameLocVar = terms[0]
3 years ago
if nameLocVar not in localVars:
localVars[nameLocVar] = 0
if len(terms) == 2:
if terms[1].strip():
localVars[nameLocVar] = self.equalTerm(terms[1], localVars)
replace = str(localVars[nameLocVar])
else:
replace = ""
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
elif len(terms) == 3:
if terms[1].strip():
replaceInt = self.equalTerm(terms[1], localVars)
replace = str(replaceInt)
else:
replace = ""
9 years ago
localVars[nameLocVar] = self.equalTerm(terms[2], localVars)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
else:
9 years ago
raise self.raiseErrTemplate()
return textTemplateTmp
12 years ago
def funcExists(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона exists(),
проверяет существование файла, если существует выдает '1'
если второй параметр root, то проверка осуществляется от корня.
"""
if funArgv.strip():
terms = [x.strip() for x in funArgv.split(",")]
if len(terms) > 2:
raise self.raiseErrTemplate()
fileName = terms[0]
flagNotRootFS = True
if len(terms) == 2:
if terms[1] == "root":
flagNotRootFS = False
else:
raise self.raiseErrTemplate(
_("The second argument of the function is not 'root'"))
if fileName[0] == "~":
# Получаем директорию пользователя
fileName = os.path.join(self.homeDir,
fileName.partition("/")[2], "")[:-1]
elif fileName[0] != "/":
raise self.raiseErrTemplate(_("wrong path '%s'") % fileName)
else:
if flagNotRootFS:
fileName = pathJoin(self._baseDir, fileName)
replace = ""
if os.path.exists(fileName):
check_map = (
('f', stat.S_ISREG),
('d', stat.S_ISDIR),
('l', stat.S_ISLNK),
('b', stat.S_ISBLK),
('c', stat.S_ISCHR),
('p', stat.S_ISFIFO),
('s', stat.S_ISSOCK))
fmode = os.lstat(fileName)
for t, func in check_map:
if func(fmode.st_mode):
replace = t
break
else:
replace = "1"
else:
replace = ""
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcLoad(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона load(),
если файл существует читает из файла локальную переменную
если один параметр - выводит значение локальной переменной
"""
terms = funArgv.split(",")
if terms:
lenTerms = len(terms)
9 years ago
if not terms[0].strip() or \
(lenTerms == 2 and not terms[1].strip()) or \
(lenTerms == 3 and not terms[2].strip()) or \
lenTerms > 3:
raise self.raiseErrTemplate()
else:
9 years ago
raise self.raiseErrTemplate()
flagNotRootFS = True
if lenTerms == 3:
9 years ago
if terms[2] == "root":
flagNotRootFS = False
else:
9 years ago
raise self.raiseErrTemplate(
12 years ago
_("The third argument of the function is not 'root'"))
if lenTerms >= 2:
9 years ago
if not terms[0] in ["ver", "num", "char", "key", "empty"]:
raise self.raiseErrTemplate(
12 years ago
_("the first argument of the function is neither 'ver'"
12 years ago
" or 'num' or 'char' or 'empty'"))
if lenTerms == 1:
fileName = terms[0].strip()
else:
fileName = terms[1].strip()
# Если домашняя директория
if fileName[0] == "~":
# Получаем директорию пользователя
fileName = os.path.join(self.homeDir,
9 years ago
fileName.partition("/")[2], "")[:-1]
elif fileName[0] != "/":
9 years ago
raise self.raiseErrTemplate(_("wrong path '%s'") % fileName)
else:
if flagNotRootFS:
9 years ago
fileName = pathJoin(self._baseDir, fileName)
replace = ""
if os.path.exists(fileName):
replace = readFile(fileName).strip()
if replace and lenTerms >= 2 and terms[0] == "empty":
replace = "\n".join((x for x in replace.split("\n") if not self.reEmptyLoad.search(x)))
9 years ago
if not replace and lenTerms >= 2 and terms[0] in ["ver", "num"]:
replace = "0"
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
9 years ago
def sharePkg(self, pkgs, force=False):
"""
Update packages from pkgs list
"""
9 years ago
for pkgname, category, ver, slot in pkgs:
fullname = "%s/%s" % (category, pkgname)
if not fullname in self.installProg or \
9 years ago
type(self.installProg[fullname]) != dict:
self.installProg[fullname] = self.installProg[pkgname] = {}
if force or not slot in self.installProg[fullname]:
self.installProg[fullname][slot] = ver
return self.installProg
# os.path.walk is deprecated in py3
9 years ago
def getInstallPkgGentoo(self, category=""):
pkgs = []
filterFunc = lambda x: "SLOT" == x
for dirname, dirs, files in os.walk(os.path.join(self.basePkgDir, category)):
for nameFile in filter(filterFunc, files+dirs):
9 years ago
absNameFile = os.path.join(dirname, nameFile)
category, spl, pkgname = dirname.rpartition('/')
dbpkg, spl, category = category.rpartition('/')
slot = readFile(absNameFile).strip().partition('/')[0]
9 years ago
pkgname, spl, rev = pkgname.rpartition("-")
if rev.startswith('r'):
pkgname, spl, ver = pkgname.rpartition("-")
9 years ago
ver = "%s-%s" % (ver, rev)
else:
ver = rev
9 years ago
pkgs.append((pkgname, category, ver, slot))
return self.sharePkg(pkgs)
9 years ago
def pkg(self, nameProg, slot=None):
if len(self.installProg) > 0:
if type(list(self.installProg.values())[0]) != dict:
self.installProg.clear()
self.getInstallPkgGentoo()
if nameProg in self.installProg:
versions = self.installProg[nameProg]
if slot:
9 years ago
return versions.get(slot, "")
if len(versions) == 1:
return list(versions.values())[0]
else:
9 years ago
return versions[max(versions.keys(), key=getTupleVersion)]
else:
return ""
12 years ago
def funcPkg(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона pkg(), выдает номер версии программы"""
# Название программы
9 years ago
nameProg = funArgv.replace(" ", "")
if not nameProg:
nameProg = self.get_pkgname_by_filename(self.nameTemplate)
# Замена функции в тексте шаблона
if "/" in nameProg:
category, spl, nameProg = nameProg.partition("/")
nameProg, spl, uses = nameProg.partition('[')
nameProg, spl, slot = nameProg.partition(":")
if uses:
uses = uses.rstrip("]")
if not category in self.installCategory:
self.getInstallPkgGentoo(category=category)
12 years ago
self.installCategory.append(category)
replace = self.pkg(nameProg, slot=slot or None)
if replace and uses:
9 years ago
pkg_use, pkg_iuse = getPkgUses("%s/%s" % (category, nameProg),
replace, prefix=self.objVar.Get(
'cl_chroot_path'))
for use in (x for x in uses.split(',') if x):
if (use[0] == "-" and use[1:] in pkg_use or
9 years ago
use[0] != "-" and use not in pkg_use):
replace = ""
break
else:
if not self.flagAllPkgScan:
self.getInstallPkgGentoo()
templateFunction.flagAllPkgScan = True
9 years ago
nameProg, spl, slot = nameProg.partition(":")
replace = self.pkg(nameProg,
slot=slot)
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcKernel(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Функция kernel(...), выдает значение опции конфига ядра (y,m,)
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
if not terms[0].strip() or len(terms) != 1:
raise self.raiseErrTemplate()
kernel_opt = terms[0].upper()
if kernel_opt.startswith("CONFIG_"):
9 years ago
raise self.raiseErrTemplate(
_("the option name should not starts with CONFIG_"))
kernel_config = self.objVar.Get('install.os_install_kernel_config')
9 years ago
find_str = "CONFIG_%s" % kernel_opt
replace = ""
for line in kernel_config:
if find_str in line:
9 years ago
if "%s=" % find_str in line:
key, op, value = line.partition("=")
replace = value.strip("'\"")
break
9 years ago
elif "%s is not set" % find_str in line:
break
textTemplateTmp = (textTemplateTmp[:resS.start()] + replace +
9 years ago
textTemplateTmp[resS.end():])
return textTemplateTmp
def funcGrep(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Функция grep (...), выдает значение из файла по регулярному выражению
"""
9 years ago
fname, op, regpattern = funArgv.replace(" ", "").partition(",")
regpattern = regpattern.replace("(?\<", "(?<")
regpattern = self._replace_hex(regpattern)
if not fname or not regpattern:
9 years ago
raise self.raiseErrTemplate()
try:
reg = re.compile(regpattern)
9 years ago
except re.error:
raise self.raiseErrTemplate(_("Wrong regular expression"))
if fname[0] == "~":
# Получаем директорию пользователя
fname = os.path.join(self.homeDir,
9 years ago
fname.partition("/")[2], "")[:-1]
fname = pathJoin(self.objVar.Get('cl_chroot_path'), fname)
fileContent = readFile(fname)
match_data = reg.search(fileContent)
if match_data:
md_groups = match_data.groups()
if md_groups:
replace = md_groups[0] or ""
else:
replace = match_data.group()
else:
replace = ""
9 years ago
return (
textTemplateTmp[:resS.start()] + replace + textTemplateTmp[
resS.end():])
def funcCut(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Функция разбивающая третий аргумент на строки по указанному разеделителю
и возвращающая указанный блок
#-cut(2,-,1-2-3-4)-# -> 3
#-cut(2,,1,2,3,4)-# -> 3
:param funArgv:
:param resS:
:param localVars:
:param textTemplateTmp:
:param nameTemp:
:return:
"""
if funArgv:
terms = funArgv.split(",")
else:
terms = []
if len(terms) > 3:
terms = terms[:2] + [",".join(terms[2:])]
if len(terms) < 1:
terms = ["0"]
if len(terms) < 2:
terms.append("-")
if len(terms) < 3:
terms.append(self.objVar.Get('cl_pass_file'))
num, delimeter, data = terms
if not num.isdigit():
raise self.raiseErrTemplate(
_("first parameter must be number"))
delimeter = delimeter or ","
num = int(num)
data = data.split(delimeter)
if num < len(data):
replace = data[num]
else:
replace = ""
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcRnd(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона rnd(), выдает строку случайных символов
первый аргумент:
'num' - числа,
'pas' - цифры и буквы
'uuid' - цифры и строчные буквы a-f
второй аргумент:
количество символов
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
gentype = terms[0].strip()
genlen = None
uuidmax = 32
if len(terms) not in (1,2):
raise self.raiseErrTemplate(
_("function rnd support one or two arguments only"))
if len(terms) == 2:
genlen = terms[1]
if not genlen.isdigit():
raise self.raiseErrTemplate(
_("the second argument of the function is not a number"))
genlen = int(terms[1])
if gentype == 'uuid':
if not genlen:
genlen = uuidmax
if genlen > uuidmax:
raise self.raiseErrTemplate(
8 years ago
_("length of UUID must not be above {maxlen}").format(
maxlen=uuidmax))
if not gentype or not genlen or len(terms) not in (1, 2):
9 years ago
raise self.raiseErrTemplate()
fArgvNames = {'num': string.digits,
'pas': string.ascii_letters + string.digits,
'hex': string.ascii_lowercase[:6] + string.digits,
9 years ago
'uuid': string.ascii_lowercase[:6] + string.digits}
if not gentype in fArgvNames:
9 years ago
raise self.raiseErrTemplate(
_("the first argument of the function must "
12 years ago
"be 'num', 'pas' or 'uuid'"))
if gentype == 'uuid':
offset = [y for x, y in (
(0, 0), (9, 1), (13, 2), (17, 3), (21, 4)) if genlen >= x][-1]
replace = str(uuid.uuid4())
replace = replace[:genlen+offset]
else:
choiceStr = fArgvNames[gentype]
replace = ''.join([random.choice(choiceStr) for i in range(genlen)])
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcCase(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона case(), выдает переменную в определенном регистре
первый аргумент:
'upper' - верхний регистр,
'lower' - нижний регистр,
'capitalize' - первая буква в верхнем регистре
второй аргумент:
название переменной
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
if not terms[0].strip() or \
(len(terms) == 2 and not terms[1].strip()) or len(terms) != 2:
raise self.raiseErrTemplate()
fArgvNames = ['upper', 'lower', 'capitalize']
if not terms[0] in fArgvNames:
9 years ago
raise self.raiseErrTemplate(_("the first argument of the function"
" is neither 'upper' or 'lower' or"
" 'capitalize'"))
try:
12 years ago
strValue = self.objVar.Get(terms[1])
if not strValue:
strValue = ""
else:
strValue = str(strValue)
except Exception:
raise TemplatesError(
9 years ago
_("error in template %s") % self.nameTemplate + "\n" +
_("error: variable %s not found") % str(terms[1]))
replace = ""
9 years ago
strValue = _u(strValue)
if terms[0] == 'upper':
replace = strValue.upper()
elif terms[0] == 'lower':
replace = strValue.lower()
elif terms[0] == 'capitalize':
replace = strValue.capitalize()
if replace:
replace = replace #there used to be encode utf-8 here
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcIn(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Function in for check value in variable
"""
terms = funArgv.replace(" ", "").split(",")
12 years ago
# Название локальной переменной
nameLocVar = terms[0]
try:
value = self.objVar.Get(nameLocVar)
terms = terms[1:]
if any(x in terms for x in iterate_list(value)):
replace = "1"
12 years ago
else:
replace = ""
9 years ago
except Exception:
raise self.raiseErrTemplate(_("error: variable %s does not exist") \
% str(nameLocVar))
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
12 years ago
return textTemplateTmp
12 years ago
def funcPush(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""локальная функция записывает значение переменной
в стек глобальных переменных
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
# Название локальной переменной
nameLocVar = terms[0]
9 years ago
value = ""
if nameLocVar in localVars.keys():
9 years ago
flagFoundVar = True
value = localVars[nameLocVar]
else:
try:
9 years ago
value = self.objVar.Get(nameLocVar)
flagFoundVar = True
9 years ago
except Exception:
flagFoundVar = False
if flagFoundVar:
# Если переменная существует
if len(terms) == 1:
self.stackGlobalVars.append(str(value))
else:
9 years ago
raise self.raiseErrTemplate(_("error: variable %s exists") \
% str(nameLocVar))
else:
# Если переменная не существует
if len(terms) == 1:
9 years ago
raise self.raiseErrTemplate(
_("error: variable %s does not exist") \
% str(nameLocVar))
elif len(terms) == 2:
value = terms[1].strip()
self.stackGlobalVars.append(str(value))
localVars[nameLocVar] = value
else:
9 years ago
raise self.raiseErrTemplate()
replace = ""
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcPop(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""локальная функция получает значение
из стека глобальных переменных и присваивает локальной переменной
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
# Название локальной переменной
nameLocVar = terms[0]
if len(terms) == 1:
if self.stackGlobalVars:
localVars[nameLocVar] = self.stackGlobalVars.pop()
else:
9 years ago
raise self.raiseErrTemplate(
12 years ago
_("error: global variables stack empty"))
else:
9 years ago
raise self.raiseErrTemplate()
replace = ""
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
9 years ago
def funcPrint(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
11 years ago
"""
Вывод успешного сообщения
"""
if funArgv:
funArgv = _(funArgv)
self.printSUCCESS(funArgv)
11 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + \
9 years ago
textTemplateTmp[resS.end():]
11 years ago
return textTemplateTmp
9 years ago
def funcWarning(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
11 years ago
"""
Вывод сообщения с предупреждением
"""
if funArgv:
funArgv = _(funArgv)
self.printWARNING(funArgv)
11 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + \
9 years ago
textTemplateTmp[resS.end():]
11 years ago
return textTemplateTmp
9 years ago
def funcError(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
11 years ago
"""
Вывод сообщения с ошибкой
"""
if funArgv:
funArgv = _(funArgv)
self.printERROR(funArgv)
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + \
textTemplateTmp[resS.end():]
return textTemplateTmp
11 years ago
def getElogTimestamp(self):
# Получаем время модификации конфигурационного файла
curTime = self.getTimeFile(self.fileConfigIni)
nameLocVar = "update.timestamp"
if self.timeIni != curTime:
# читаем переменные из файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
9 years ago
self.currDictIni = {}
11 years ago
self.currDictIni.update(self.prevDictIni)
self.timeIni = self.getTimeFile(self.fileConfigIni)
if nameLocVar in self.currDictIni.keys():
if self.currDictIni[nameLocVar] is None:
return 0
else:
val = self.currDictIni[nameLocVar] #used to be encode utf-8 here
11 years ago
if val.isdigit():
return int(val)
return 0
elogFile = '/var/log/emerge.log'
@classmethod
def getLastElog(cls):
# get last timestamp (of ::completed emerge)
entry = EmergeLog(EmergeLogPackageTask()).get_last_time()
if entry:
return entry.partition(":")[0]
else:
return "0"
9 years ago
def funcElog(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
11 years ago
"""Function for work with emerge.log"""
funArgv = funArgv.strip()
9 years ago
rePkg = re.compile(r'\) Merging (?:Binary )?\((\S+)::', re.S)
11 years ago
replace = ""
if funArgv:
lastTimestamp = self.getElogTimestamp()
for line in reversed(list(readLinesFile(self.elogFile))):
9 years ago
timestamp, op, info = line.partition(':')
11 years ago
if timestamp.isdigit() and lastTimestamp and \
9 years ago
int(timestamp) < lastTimestamp:
break
11 years ago
match = rePkg.search(info)
if match and match.group(1).startswith(funArgv):
pkgInfo = reVerSplitToPV(match.group(1))
if "{CATEGORY}/{PN}".format(**pkgInfo) == funArgv:
replace = pkgInfo['PVR']
break
else:
replace = self.getLastElog()
11 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
9 years ago
textTemplateTmp[resS.end():]
return textTemplateTmp
@classmethod
def splash_cmd(cls, splash_type):
cmd_map = {
'splashutils': "splash=silent,theme:calculate console=tty1",
'plymouth': "splash",
}
return cmd_map.get(splash_type, "verbose")
9 years ago
def funcLivemenu(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
def generateSubmenu(data):
base_dn = self.objVar.Get('builder.cl_builder_flash_path')
9 years ago
for id, label, iso, vmlinuz_orig, vmlinuz, initrd_orig, initrd, \
xorg, drivers, splash in data:
splash = self.splash_cmd(splash)
yield ("{id};\n{label};\n/boot/{kernel};\n"
"root=live iso-scan/filename={iso};\n"
"/boot/{initrd};\n"
"init=/linuxrc rd.live.squashimg=livecd.squashfs "
"{splash} "
"nodevfs quiet noresume;\n".format(
id=id, label=label, kernel=vmlinuz, initrd=initrd,
splash=splash, iso=iso[len(base_dn):]
))
def generateXorg(data):
for id, label, iso, vmlinuz_orig, vmlinuz, initrd_orig, initrd, \
xorg, drivers, splash in data:
if xorg == "on":
yield id
def generateVideo(data):
for id, label, iso, vmlinuz_orig, vmlinuz, initrd_orig, initrd, \
xorg, drivers, splash in data:
if drivers == "on":
yield id
data = [x for x in self.objVar.Get('builder.cl_builder_image_data') if x]
if funArgv == 'submenu':
res = "\n".join(generateSubmenu(data))
elif funArgv == 'xorg':
res = " ".join(generateXorg(data))
elif funArgv == 'video':
res = " ".join(generateVideo(data))
else:
res = ""
textTemplateTmp = textTemplateTmp[:resS.start()] + res + \
textTemplateTmp[resS.end():]
11 years ago
return textTemplateTmp
def loadVarsIni(self, iniFileName):
""" Читает файл fileName
создает и заполняет переменные на основе этого файла
Используеться совместно c funcIni
"""
localVarsIni = {}
# получить объект ini файла
config = ConfigParser(strict=False)
config.read(iniFileName, encoding="utf-8")
# получаем все секции из конфигурационного файла
allsect = config.sections()
if not allsect:
return localVarsIni
# Заполняем переменные для funcIni
for sect in allsect:
for name, valueVar in config.items(sect, raw=True):
9 years ago
nameVar = "%s.%s" % (sect, name)
localVarsIni[nameVar] = valueVar
return localVarsIni
def getTimeFile(self, fileName):
# Получаем время модификации файла
14 years ago
nameEnvFile = os.path.split(fileName)[1]
if nameEnvFile in self.timeConfigsIni:
return self.timeConfigsIni[nameEnvFile]
return 0
def funcWallpaper(self, funArgv, resS, localVars, textTemplateTmp,
nameTemp):
"""
Получить наиболее близкое к заданному разрешение из списка обоев
"""
terms = funArgv.replace(" ", "").split(",")
onlyfile = ""
if len(terms) == 3:
resol, wpath, onlyfile = terms
if onlyfile != "file":
raise self.raiseErrTemplate(
_("third parameter may be 'file' only"))
elif len(terms) == 2:
resol, wpath = terms
else:
raise self.raiseErrTemplate(
8 years ago
_("function support two or three parameters"))
if not resol:
resol = "1024x768"
_wpath = wpath
wpath = pathJoin(self._baseDir, wpath)
if os.path.isdir(wpath):
re_resol = re.compile("^(\d+)x(\d+)(-\d+(@\d+)?)?$")
resol = re_resol.match(resol)
if not resol:
raise self.raiseErrTemplate(
_("the first parameter must be the resolution"))
re_resol = re.compile(".*?(\d+)x(\d+).*")
res = [(int(x.group(1)), int(x.group(2)), x.group()) for x in
[re_resol.search(y) for y in listDirectory(wpath)] if x]
width = int(resol.group(1))
height = int(resol.group(2))
gep = sqrt(height ** 2 + width ** 2)
k = float(width) / float(height)
if res:
# наиболее подходящее разрешение:
# минимальная разность между пропорциями (отношение ширины к высоте)
# минимальная разность между размерами (гепотенуза)
near_res = min(res,
key=lambda x: (abs(x[0] / float(x[1]) - k),
abs(gep - sqrt(
x[0] ** 2 + x[1] ** 2))))
replace = near_res[2]
if not onlyfile:
replace = pathJoin(_wpath, replace)
else:
replace = ""
else:
if os.path.exists(wpath):
if onlyfile:
replace = os.path.basename(_wpath)
else:
replace = _wpath
else:
replace = ""
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
9 years ago
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcIni(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""локальная функция записывает и считывает значение переменной
из ini файла ~./calculate/ini.env
"""
# Создаем директорию
if not os.path.exists(self.pathConfigIni):
os.makedirs(self.pathConfigIni)
14 years ago
os.chown(self.pathConfigIni, self.uid, self.gid)
termsRaw = funArgv.split(",")
flagFirst = True
terms = []
for term in termsRaw:
if flagFirst:
9 years ago
terms.append(term.replace(" ", ""))
flagFirst = False
else:
val = term.strip()
# Флаг (не найдены кавычки)
flagNotFoundQuote = True
9 years ago
for el in ('"', "'"):
if val.startswith(el) and val.endswith(el):
terms.append(val[1:-1])
flagNotFoundQuote = False
break
if flagNotFoundQuote:
if not val:
terms.append(None)
else:
terms.append(val)
# Название локальной переменной
if self.objVar.Get('cl_action') in ('image', 'system'):
oldbasedir = self._baseDir
old_profile = self.objVar.Get('cl_make_profile')
old_config = self.objVar.Get('cl_emerge_config')
try:
if self.objVar.Get('cl_action') == 'image':
self._baseDir = self.objVar.Get('builder.cl_builder_path')
else:
self._baseDir = self.objVar.Get('cl_chroot_path')
dvc = DataVarsConfig(self._baseDir)
self.objVar.Set('cl_make_profile',
dvc.Get('cl_make_profile'), force=True)
self.objVar.Set('cl_emerge_config',
dvc.Get('cl_emerge_config'), force=True)
self.read_other_ini()
finally:
self._baseDir = oldbasedir
self.objVar.Set('cl_make_profile', old_profile, force=True)
self.objVar.Set('cl_emerge_config', old_config, force=True)
else:
self.read_other_ini()
nameLocVar = terms[0]
namesVar = nameLocVar.split(".")
if len(namesVar) == 1:
9 years ago
nameLocVar = "main.%s" % nameLocVar
elif len(namesVar) > 2:
raise self.raiseErrTemplate()
replace = b""
# Получаем время модификации конфигурационного файла
curTime = self.getTimeFile(self.fileConfigIni)
if 1 <= len(terms) <= 3:
if self.timeIni != curTime:
# читаем переменные из файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
9 years ago
self.currDictIni = {}
self.currDictIni.update(self.prevDictIni)
self.timeIni = self.getTimeFile(self.fileConfigIni)
section, op, varname = nameLocVar.partition(".")
value = self.upperIni.get(section, varname, raw=True, fallback=None)
if value is None:
if nameLocVar in self.currDictIni.keys():
if self.currDictIni[nameLocVar] is not None:
value = self.currDictIni[nameLocVar]
if value is None:
value = self.lowerIni.get(section, varname, raw=True,
fallback="")
else:
raise self.raiseErrTemplate()
if len(terms) == 1:
replace = value.encode("UTF-8")
elif len(terms) == 2:
# Значение локальной переменной
valueLocVar = terms[1]
self.currDictIni[nameLocVar] = valueLocVar
elif len(terms) == 3:
if not terms[2] in ['url', 'purl', 'unicode', 'hexcode']:
9 years ago
raise self.raiseErrTemplate(
12 years ago
_("the third argument of the function is neither "
12 years ago
"'url' or 'purl' or 'unicode'"))
if terms[1]:
9 years ago
raise self.raiseErrTemplate()
if value:
#awww yesss, legacy stuff
if terms[2] in ('url', 'purl'):
replace = (value.encode("UTF-8").__repr__()[1:-1].replace(
'\\x', '%').replace(' ', '%20'))
if terms[2] == 'purl':
9 years ago
replace = replace.replace('/', '%2f')
elif terms[2] == 'unicode':
replace = value.__repr__()[2:-1]
elif terms[2] == 'hexcode':
replace = value.__repr__()[2:-1].replace('\\u0','\\x')
replace = replace.decode("UTF-8")
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
def _replace_hex(self, text):
"""
Заменить в строке комбинацию \\x00 на символ
"""
return re.sub(r'\\x([0-9a-fA-F]{2})',
9 years ago
lambda x: chr(int(x.group(1), 16)), text)
12 years ago
def funcReplace(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""локальная функция заменяет в значении переменной old на new
replace(old, new, name_var_template)
одинарные и двойные кавычки должны быть обязательно использованы
в первых двух аргументах old и new
"test\ntest" - преобразование строки (строка с переводом)
'test\ntest' - без преобразования (одна строка)
"""
9 years ago
def getStrArgv(terms):
"""Определяет в двойных или одинарных кавычках параметры
Результат [(тип, аргумент),...] [("double", arg1).]
"""
listArgv = []
for term in terms:
if term.startswith('"') and term.endswith('"'):
replTerms = [(r"\'", "'"), (r'\"', '"'), (r'\n', '\n'),
(r'\r', '\r'),
(r'\t', '\t'), (r"\\", "\\")]
textArgv = term[1:-1]
for replTerm in replTerms:
textArgv = textArgv.replace(*replTerm)
textArgv = self._replace_hex(textArgv)
listArgv.append(textArgv)
elif term.startswith("'") and term.endswith("'"):
listArgv.append(term[1:-1])
else:
9 years ago
raise self.raiseErrTemplate()
return listArgv
terms = [x.strip() for x in funArgv.split(",")]
if len(terms) != 3:
9 years ago
raise self.raiseErrTemplate()
listArgv = getStrArgv(terms[:2])
old = listArgv[0]
new = listArgv[1]
nameVar = terms[2]
# Получаем значение переменной
if nameVar in localVars:
value = str(localVars[nameVar])
else:
try:
value = str(self.objVar.Get(nameVar))
9 years ago
except Exception:
raise self.raiseErrTemplate(
_("template variable '%s' not found") \
% str(nameVar))
replace = value.replace(old, new)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcEnv(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона env(), выдает значение переменной из env файлов
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
if len(terms) != 1:
9 years ago
raise self.raiseErrTemplate()
nameVar = terms[0]
if nameVar in self.valuesVarEnv:
replace = self.valuesVarEnv[nameVar]
else:
# Получаем значение из env файлов
value = self.objVar.getIniVar(nameVar)
if value is False:
9 years ago
raise self.raiseErrTemplate(self.getError())
self.valuesVarEnv[nameVar] = value
replace = value
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcServer(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона info(), выдает значение опций сервиса
из /var/calculate/remote/calculate.env
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
if len(terms) == 0 or len(terms) > 2:
raise self.raiseErrTemplate()
nameLocalVar = ""
9 years ago
if len(terms) == 2:
if not terms[1]:
9 years ago
raise self.raiseErrTemplate()
nameLocalVar = terms[1]
14 years ago
textLine = terms[0]
vals = textLine.split(".")
9 years ago
if len(vals) != 2:
raise self.raiseErrTemplate()
if [x for x in vals if not x.strip()]:
9 years ago
raise self.raiseErrTemplate()
14 years ago
service, option = vals
if not service or not option:
9 years ago
raise self.raiseErrTemplate()
if not self.optionsInfo:
# файл /var/calculate/remote/server.env
envFile = self.objVar.Get("cl_env_server_path")
# получаем словарь всех информационных переменных
if self.convObj:
optInfo = self.convObj.convert()
else:
12 years ago
optInfo = self.objVar.getRemoteInfo(envFile)
if optInfo is False:
9 years ago
raise self.raiseErrTemplate()
if optInfo:
self.optionsInfo = optInfo
replace = ''
if service in self.optionsInfo and option in self.optionsInfo[service]:
value = self.optionsInfo[service][option]
if nameLocalVar:
localVars[nameLocalVar] = value
else:
replace = value
14 years ago
elif nameLocalVar:
localVars[nameLocalVar] = ""
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcGroups(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона groups(),
проверяет нахождение пользователя в группах, если находится выдает '1'
"""
terms = [x.strip() for x in funArgv.split(",")]
groupNames = set(terms)
userGroups = set(self.groups)
replace = ""
if groupNames & userGroups:
replace = "1"
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcBelong(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
11 years ago
self.printWARNING(_("Function '{funcname}' used by {template} "
"is deprecated and will be removed in the future"
9 years ago
).format(funcname="belong", template=nameTemp))
replace = ""
9 years ago
return textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
12 years ago
def funcMergepkg(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Функция объединяющая выполнение merge и pkg
:param funArgv:
:param resS:
:param localVars:
:param textTemplateTmp:
:param nameTemp:
:return:
"""
term = funArgv.replace(" ", "")
funcPkg = term
replace = self.funcMerge(funcPkg, resS, localVars, "", nameTemp)
if replace == "1":
replace = self.funcPkg(funcPkg, resS, localVars, "", nameTemp)
return textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
12 years ago
def funcMerge(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Belong function use value in first arg and compare it
12 years ago
for all values in cl_merge_pkg.
If cl_merge_pkg empty or first arg <=cl_belogn_pkg
then "1" else ""
"""
9 years ago
def uniq_warning(message):
hashMessage = hashlib.md5(message).digest()
if not hashMessage in self.alreadyInformed:
self.printWARNING(message)
self.alreadyInformed.append(hashMessage)
def check_skip(pkgName):
varname_map = {
HParams.ActionType.Merge: "cl_setup_skip_merge",
HParams.ActionType.Patch: "cl_setup_skip_patch",
HParams.ActionType.Profile: "cl_setup_skip_profile",
}
skip_data_varname = varname_map.get(self.currentAction)
skip_data = self.objVar.Get(skip_data_varname)
pass_location = self.objVar.Get('cl_pass_location')
if any(skip_data):
for data in skip_data:
if len(data) != 2:
uniq_warning(
_("Wrong entry '{data}' for {var_name}").format(
9 years ago
data=",".join(data),
var_name=skip_data_varname))
else:
pkg, location = data
if fnmatch(pkgName, pkg) and (location == "*"
or location == pass_location):
return True
return False
9 years ago
term = funArgv.replace(" ", "")
funcPkg = term
funcPkg, spl, uses = funcPkg.partition('[')
funcPkg, spl, slot = funcPkg.partition(":")
if uses:
uses = uses.rstrip("]")
if not funcPkg:
funcPkg = self.get_pkgname_by_filename(self.nameTemplate)
self.currentBelong = funcPkg
self.currentBelongSlot = slot
11 years ago
if self.objVar.Get('cl_action') == 'patch':
if funcPkg == "%s/%s" % (
9 years ago
self.objVar.Get('core.cl_core_pkg_category'),
self.objVar.Get('core.cl_core_pkg_name')):
spec_slot = self.objVar.Get('core.cl_core_pkg_slot')
spec_slot = spec_slot.partition('/')[0]
if not slot or spec_slot == slot:
replace = self.objVar.Get('core.cl_core_pkg_version')
if uses:
from os import environ
pkg_use = environ.get("USE", "").split(" ")
for use in filter(None, uses.split(',')):
if (use[0] == "-" and use[1:] in pkg_use or
use[0] != "-" and use not in pkg_use):
replace = ""
if check_skip(funcPkg):
replace = ""
else:
replace = ""
11 years ago
else:
replace = ""
else:
11 years ago
replace = ""
pkgs = self.objVar.Get("cl_merge_pkg")
if pkgs:
pkgs = [x for x in pkgs if x]
if slot:
for pkg in pkgs:
if ":" in pkg:
pkg, _, pkgslot = pkg.partition(":")
if pkg == funcPkg and pkgslot == slot:
replace = "1"
break
elif pkg == funcPkg:
replace = "1"
break
else:
if funcPkg in [x.partition(":")[0] for x in pkgs]:
replace = "1"
11 years ago
else:
replace = "1"
if replace == "1" and check_skip(funcPkg):
replace = ""
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcList(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона list().
Если первый аргумент является именем локальной или глобальной
переменной и значение переменной является списком, выдает
элемент списка по второму аргументу индексу.
Первый элемент имеет индекс 0
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
# У функции должно быть два аргумента
if len(terms) != 2:
9 years ago
raise self.raiseErrTemplate()
# Название локальной или глобальной переменной
nameLocVar = terms[0]
strIndex = terms[1]
try:
try:
9 years ago
intIndex = int(strIndex)
except ValueError:
raise TemplatesError(_("'%s' is not a number") % strIndex)
if nameLocVar in localVars.keys():
value = localVars[nameLocVar]
else:
try:
value = self.objVar.Get(nameLocVar)
except Exception:
raise TemplatesError(_("error: variable %s does not exist")
% str(nameLocVar))
if not type(value) in (list, tuple):
# Значение переменной не список или кортеж
raise TemplatesError(_("value of %s is not a list or a tuple")
% str(nameLocVar))
if len(value) > intIndex:
try:
replace = str(value[intIndex])
except IndexError:
replace = ""
else:
replace = ""
9 years ago
return textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
except TemplatesError as e:
raise self.raiseErrTemplate(str(e))
12 years ago
def funcDisk(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона disk().
Первый аргумент ищется в значении переменной os_disk_install
(значение os_install_disk_mount -
список точек монтирования при установке)
второй аргумент используется для поиска в переменной
os_disk_второй_аргумент (значение os_disk_второй_аргумент - список)
В os_install_disk_mount ищется первый аргумент, находим его индекс
результат - элемент cписка из os_disk_второй_аргумент с этим индексом
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
# У функции должно быть два аргумента
if len(terms) != 2:
9 years ago
raise self.raiseErrTemplate()
# Название глобальной переменной
mountPoint = terms[0]
lastElementVar = terms[1]
9 years ago
if not mountPoint or mountPoint[:1] != "/":
raise self.raiseErrTemplate(_("wrong %s") % lastElementVar)
12 years ago
nameVar = "install.os_install_disk_mount"
try:
try:
9 years ago
valueVar = self.objVar.Get(nameVar)
except Exception:
raise TemplatesError(
_("error: variable %s does not exist") % nameVar)
nameElementVar = "install.os_install_disk_%s" % lastElementVar
try:
valueElementVar = self.objVar.Get(nameElementVar)
except Exception:
# Если переменная не существует
nameElementVar = "install.os_disk_%s" % lastElementVar
try:
valueElementVar = self.objVar.Get(nameElementVar)
except Exception:
raise TemplatesError(_("wrong %s") % lastElementVar + "\n" +
_("error: variable %s does not exist")
% nameElementVar)
for k, v in ((nameVar, valueVar),
(nameElementVar, valueElementVar)):
if not type(v) in (list, tuple):
# Значение переменной не список или кортеж
raise TemplatesError(
_("value of %s is not a list or a tuple") % k)
if len(valueVar) != len(valueElementVar):
raise TemplatesError(
_("%(name)s does not match %(nameElement)s in size")
% {'name': nameVar, 'nameElement': nameElementVar})
index = None
for num, mPoint in enumerate(valueVar):
9 years ago
if mountPoint == mPoint:
index = num
break
9 years ago
if index is None:
for num, mPoint in enumerate(valueVar):
if "/" == mPoint:
index = num
break
if index is None:
raise TemplatesError(
_("mount point '/' or '/%s' not found "
" in the value of variable os_disk_install") % mountPoint)
replace = valueElementVar[index]
return textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
except TemplatesError as e:
raise self.raiseErrTemplate(str(e))
12 years ago
def funcModule(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона module(), выдает значение аттрибута api.
аргумент:
путь_к_атрибуту - путь к аттрибуту
возможные пути:
имя_пакета.var.имя_переменной - получаем значение переменной
имя_пакета.имя_метода_api - выполнение метода, получение результата
all.имя_метода_api - выполнение метода для всех пакетов с api
"""
current_version = self.objVar.Get('cl_ver')
try:
if funArgv not in self.objVar.importedModules:
importlib.import_module(
"calculate.%s.variables" % funArgv)
if self.objVar.Get('cl_chroot_path') == "/":
replace = current_version
else:
usrlib = SystemPath(self.objVar.Get('cl_chroot_path')).usrlib
module_path = os.path.join(
3 years ago
usrlib, "python3.9/site-packages/calculate/%s/variables"
% funArgv)
if os.path.exists(module_path):
pkg = "sys-apps/calculate-utils:3"
chroot_version = self.funcPkg(
pkg, re.search(".*", pkg), localVars, pkg, nameTemp)
t_chroot_version = getTupleVersion(chroot_version)
t_current_version = getTupleVersion(current_version)
if t_chroot_version < t_current_version:
replace = chroot_version
else:
replace = current_version
else:
replace = ""
except (ImportError, AttributeError):
replace = ""
return textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
9 years ago
def raiseErrTemplate(self, message=""):
"""Возвращает ошибки при обработке функций шаблона"""
if message:
9 years ago
message = "%s\n" % message
else:
message = ""
9 years ago
return TemplatesError(
_("error in template %s") % self.nameTemplate + "\n" + \
_("error, template term '%s'") % str(self.functText) + \
" " + message)
def applyFuncTemplate(self, textTemplate, nameTemplate):
"""Применяет функции к тексту шаблона"""
# Локальные переменные
localVars = {}
# Имя обрабатываемого шаблона
self.nameTemplate = nameTemplate
# Регулярное выражение для поиска функции в шаблоне
reFunc = self._reFunc
textTemplateTmp = textTemplate
flagIniFunc = False
writeIniFunc = False
def funcSearch(s):
minlen = 1
resS = re.search(self._rePreFuncPattern % minlen, s, re.M)
while resS and resS.group().count("#-") != (resS.group().count("-#")
- resS.group().count("-#-")):
minlen = len(resS.group()) - 2
resS = re.search(self._rePreFuncPattern % minlen, s, re.M)
if resS:
funcblock = resS.group()
resS = reFunc.search(s[:resS.end()])
if not resS:
raise self.raiseErrTemplate(
_("wrong function syntax %s") % funcblock)
return resS
resS = funcSearch(textTemplateTmp)
while resS:
mark = textTemplateTmp[resS.start():resS.end()]
self.functText = mark[self._deltVarStart:-self._deltVarEnd]
9 years ago
funcName, spl, funcEnd = self.functText.partition("(")
if funcName in self.namesTemplateFunction:
# аргументы функции - '(' аргументы ')'
funArgv = funcEnd.rpartition(")")[0]
# вызов функции шаблона
if "#-" in funArgv and "-#" in funArgv:
funArgv = self.applyVarsTemplate(funArgv, nameTemplate)
funArgv = self.applyFuncTemplate(funArgv, nameTemplate)
textTemplateTmp = self.templateFunction[funcName](self, funArgv,
9 years ago
resS,
localVars,
textTemplateTmp,
nameTemplate)
resS = funcSearch(textTemplateTmp)
if funcName == "ini":
if "," in funArgv:
writeIniFunc = True
flagIniFunc = True
else:
9 years ago
raise self.raiseErrTemplate(
_("function of templates '%s' not found") \
% str(self.functText))
if flagIniFunc:
# Очистка файла в случае его ошибочного чтения
if not self.prevDictIni and os.path.exists(self.fileConfigIni):
with open(self.fileConfigIni, "r+") as FD:
FD.truncate(0)
FD.seek(0)
# Если конф. файл модифицирован шаблоном
curTime = self.getTimeFile(self.fileConfigIni)
if curTime != self.timeIni:
# Считаем переменные из конф. файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
self.currDictIni.update(self.prevDictIni)
self.timeIni = curTime
# Если словари переменных не совпадают
if self.prevDictIni != self.currDictIni:
# Запишем переменные в конфигурационный файл
# Создание объекта парсера
config = ConfigParser(strict=False)
config.read(self.fileConfigIni, encoding="utf-8")
9 years ago
comment_block = "\n".join(takewhile(lambda x: x.startswith("#"),
readLinesFile(
self.fileConfigIni)))
for k, v in self.currDictIni.items():
if "." in k:
sect, op, k = k.rpartition('.')
if v is None:
if config.has_section(sect):
config.remove_option(sect, k)
else:
if not config.has_section(sect):
config.add_section(sect)
config[sect][k] = v
for section in (x for x in config.sections() if not config[x]):
config.remove_section(section)
with codecs.open(self.fileConfigIni, 'wb',
'utf-8', 'ignore') as f:
if comment_block:
f.write(comment_block)
f.write('\n\n')
config.write(f)
try:
oMode = getModeFile(self.fileConfigIni, mode="mode")
if oMode != self.modeConfigIni:
os.chmod(self.fileConfigIni, self.modeConfigIni)
9 years ago
except OSError:
pass
# читаем переменные из файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
self.currDictIni.update(self.prevDictIni)
self.timeConfigsIni[self.fileConfigIni] = float(time.time())
self.timeIni = self.getTimeFile(self.fileConfigIni)
# Меняем владельца в случае необходимости
if writeIniFunc and os.path.exists(self.fileConfigIni):
14 years ago
uid, gid = getModeFile(self.fileConfigIni, "owner")
if self.uid not in (uid, PORTAGEUID) or \
self.gid not in (gid, PORTAGEGID):
try:
os.chown(self.fileConfigIni, self.uid, self.gid)
9 years ago
except OSError:
self.setError(_("error") + " " +
"'chown %d:%d %s'" % (self.uid, self.gid,
self.fileConfigIni))
return textTemplateTmp
9 years ago
class ChangedFiles():
"""
Object which contains modified files and package
"""
9 years ago
FILE_MODIFIED, FILE_REMOVED, DIR_CREATED, DIR_REMOVED, DIR_EXISTS = 0, 1, 2, 3, 4
def __init__(self):
self.data = {}
self.pkgs = set()
9 years ago
def _createEntry(self, fn):
if not fn in self.data:
self.data[fn] = []
def addObj(self, filename, action, pkg, slot=""):
if slot:
pkgslot = "{}:{}".format(pkg,slot)
else:
pkgslot = pkg
self._createEntry(filename)
self.data[filename].append((pkgslot, action))
self.pkgs.add(pkgslot)
def getPkgs(self):
return self.pkgs
9 years ago
def getPkgFiles(self, pkg):
return [(x[0], x[1][0][1]) for x
in [(y[0], [z for z in y[1] if z[0] == pkg]) for y
in self.data.items()] if x[1]]
# modes work with configuration file
# T_ORIGIN - work with original config file
# T_CFG - work with last ._cfg file
# T_NEWCFG - new content has difference with (create new ._cfg file)
9 years ago
T_ORIGIN, T_CFG, T_NEWCFG = 0, 1, 2
9 years ago
class Template(_file, _terms, _warning, xmlShare, _shareTemplate):
"""Класс для работы с шаблонами
На вход 2 параметра: объект хранения переменных, имя сервиса - не
обязательный параметр
"""
# Название файла шаблона директории
templDirNameFile = ".calculate_directory"
_titleList = ("Modified", "Processed template files" + ":")
titleEnd_old = "For modify this file, create %(conf_path)s.clt template."
titleEnd = "To modify this file, create a %(conf_path)s.clt template."
protectPaths = []
allContents = {}
if "CONFIG_PROTECT" in os.environ:
protectPaths = ["/etc"] + [x for x in os.environ["CONFIG_PROTECT"].split(" ") if x.strip()]
protectPaths = [os.path.normpath(x) for x in protectPaths]
@classmethod
9 years ago
def removeComment(cls, text):
re_comment = re.compile('(?:<!--|[{symb}]-*)\n'
'[{symb}]? {modified} .*\n'
'[{symb}]? {processed}\n'
'([{symb}]? /.*\n'
')+(?:[{symb}]? (?:{endtitle}|{endtitle_old}).*\n)?'
r'(-->|[{symb}]-*)\n'.format(
9 years ago
modified=cls._titleList[0],
processed=cls._titleList[1],
endtitle_old=cls.titleEnd_old % {'conf_path': '.*'},
9 years ago
endtitle=cls.titleEnd % {'conf_path': '.*'},
symb='"#'
))
return re_comment.sub('', text)
def hasError(self):
return self.getError() or self.bHasError or (
self.cltObj and self.cltObj.bHasError)
9 years ago
def __init__(self, objVar, servDir=False, dirsFilter=(), filesFilter=(),
cltObj=True, cltFilter=True, printWarning=True,
9 years ago
printSUCCESS=lambda x: x, printWARNING=lambda x: x,
printERROR=lambda x: x, askConfirm=lambda x: x,
userProfile=False, dispatchConf=None,
critical=False):
_file.__init__(self)
# совместимость с вызовами из модулей предыдущих версий
self.translator = RegexpLocalization("cl_templates3")
if userProfile and objVar:
9 years ago
objVar.Set('cl_protect_use_set', 'off', force=True)
self.protectPaths = objVar.Get('cl_config_protect')
self.dispatchConf = dispatchConf
self.changedFiles = ChangedFiles()
self.printSUCCESS = printSUCCESS
self.formatFactory = FormatFactory(self)
self.printERROR = printERROR
self.critical = critical
self.postmergePkgs = []
self._locked_packages = {}
if objVar and objVar.Get("cl_merge_pkg"):
self._locked_packages = {
x.partition(":")[0]: None
for x in objVar.Get('cl_merge_pkg')
if x
}
self.postmergeFile = "/var/lib/calculate/-postmerge"
self.bHasError = False
11 years ago
if printERROR:
def newSetError(s):
self.printERROR(s)
self.bHasError = True
9 years ago
self.setError = newSetError
self.printWARNING = printWARNING
11 years ago
self.askConfirm = askConfirm
self.cltObj = None
self.functObj = None
self.mounts = None
# Бесконченое ожидание завершения emerge если выполняется настройка пакетов
#if objVar:
# if (not objVar.Get('cl_ebuild_phase')
# and emerge_running()
# and objVar.GetBool('install.ac_install_merge')):
# self.printWARNING(_("Waiting for emerge to be complete"))
# while emerge_running():
# time.sleep(1)
# Предупреждения
9 years ago
# self.warning = []
# Печатать ли предупреждения о корневых шаблонах без cl_name==pkg
self.printWarning = printWarning
# Необрабатываемые директории
self.dirsFilter = dirsFilter
# Необрабатываемые файлы
self.filesFilter = filesFilter
_file.__init__(self)
# Словарь для создания объектов новых классов по образцу
9 years ago
self.newObjProt = {'proftpd': 'apache'}
# Заголовок title
self.__titleHead = "--------------------------------------\
----------------------------------------"
self._titleBody = ""
# Условия
12 years ago
self._reTermBloc = re.compile(
"#\?(?P<rTerm>(?:[a-z0-9_]+\.)?[a-zA-Z0-9\-_]+)"
"(?P<func>\(((?:#-|-#|%s)+|)\))?"
"(?P<lTerm>[><=!&\|]+"
"(?:#-|-#|[><=!\|&\(\)%s])*)#"
"\n?(?P<body>.+?\n*?)\n?#(?P=rTerm)#(?P<end>[ ,\t]*\n?)"
9 years ago
% (self._reFunctionArgvText, self._reFunctionArgvInSquareBrackets),
re.M | re.S)
# Объект с переменными
self.objVar = objVar
self.recalculateBaseDir()
# Последняя часть директории шаблона (имя сервиса: samba, mail)
9 years ago
self._servDir = servDir
if self._servDir:
if self._servDir[0] != "/":
self._servDir = "/" + self._servDir
if self._servDir[-1] != "/":
self._servDir += "/"
self._servDir = os.path.split(self._servDir)[0]
# Созданные директории
self.createdDirs = []
# Примененные файлы
self.filesApply = []
# номер обрабатываемого файла
self.numberProcessTempl = 0
# имя текущей программы
_nameProgram = "Calculate Utilities"
# версия текущей программы
_versionProgram = self.objVar.Get("cl_ver")
# имя и версия текущей программы
9 years ago
self.programVersion = "%s %s" % (_nameProgram, _versionProgram)
# Словарь директорий с количеством файлов шаблонов
self.dictTemplates = {}
# Общее количество шаблонов
self.allTemplates = 0
# Объект функций шаблона
self.functObj = templateFunction(self.objVar)
self.functObj.printSUCCESS = self.printSUCCESS
self.functObj.printWARNING = self.printWARNING
self.functObj.printERROR = self.printERROR
11 years ago
if self.printERROR:
self.functObj.setError = self.printERROR
11 years ago
self.functObj.askConfirm = self.askConfirm
# Метод применения функций к шаблонам
self.applyFuncTemplate = self.functObj.applyFuncTemplate
14 years ago
# Объект для определения типа файла шаблона
self.typeFileObj = typeFile()
# Глобальный словарь обработанных шаблонов файлов
# {путь к конф. файлу:[имена шаблонов] ...}
self.dictProcessedTemplates = {}
if cltObj is True:
# Объект templateClt
9 years ago
self.cltObj = templateClt(self.objVar, self.postmergePkgs,
printSUCCESS=self.printSUCCESS,
printERROR=self.printERROR,
printWARNING=self.printWARNING,
askConfirm=self.askConfirm,
critical=self.critical)
elif cltObj:
# Объект templateClt
self.cltObj = cltObj
else:
# Объект templateClt
9 years ago
self.cltObj = None
14 years ago
# Фильтровать ли шаблоны clt по конфигурационным файлам обычных шаблонов
self.cltFilter = cltFilter
# autoupdate файлы
self.autoUpdateFiles = []
self.autoUpdateDirs = []
self.protectedFiles = [
pathJoin(self._baseDir, x)
for x in self.objVar.Get('main.cl_env_path')
] + [self.functObj.fileConfigIni]
# список выполненных файлов
self.executedFiles = []
def recalculateBaseDir(self):
"""Recalculate basedir and homedir"""
# Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
self._baseDir = pathJoin(self.objVar.Get("cl_chroot_path"),
self.objVar.Get("cl_root_path"))
self._baseDir = os.path.normpath(self._baseDir)
self.uid, self.gid, self.homeDir = self.getDataUser()
# Домашняя директория, плюс базовая директория
self.homeDir = pathJoin(self._baseDir, self.homeDir)
if self.cltObj:
self.cltObj.recalculateBaseDir()
if self.functObj:
self.functObj.recalculateBaseDir()
9 years ago
def _addFile(self, filesApl, pkg=None, slot=None):
"""
Add files to ChangedFiles
"""
for fn in filesApl:
if os.path.exists(fn):
self.changedFiles.addObj(
fn, ChangedFiles.FILE_MODIFIED,
pkg or self.functObj.currentBelong,
slot or self.functObj.currentBelongSlot)
else:
self.changedFiles.addObj(
fn, ChangedFiles.FILE_REMOVED,
pkg or self.functObj.currentBelong,
slot or self.functObj.currentBelongSlot)
def execute_command(self, cmd, lang):
env = dict(os.environ)
env['TERM'] = "linux"
env['EINFO_QUIET'] = "yes"
return process(cmd, lang=lang, envdict=dict(os.environ))
def executeTemplate(self, code, execPath):
"""Execute template"""
p = self.execute_command(execPath, self.objVar.Get('os_locale_locale'))
if "/bin/bash" in code.partition('\n')[0]:
p.write("""function translate() {
gettext -d cl_template "$*"
}
""")
p.write(code)
p.pipe.stdin.close()
for line in p.readByLine():
if line:
line = self.translator.translate(line)
self.printSUCCESS(line.strip())
p.pipe.wait()
if p.success():
9 years ago
self.executedFiles.append((code, execPath))
errdata = p.readerr().rstrip()
if errdata:
for line in errdata.split('\n'):
if line:
line = self.translator.translate(line)
11 years ago
self.printWARNING(line.strip())
return True
else:
errdata = p.readerr().rstrip()
if errdata:
for line in errdata.split('\n'):
if line:
line = self.translator.translate(line)
11 years ago
self.printERROR(line.strip())
return False
def __octToInt(self, strOct):
"""Преобразование восьмеричного в целое (ввод строка, вывод число)"""
if strOct:
try:
# res = string.atoi(strOct, 8)
res = int(strOct, 8)
except ValueError:
12 years ago
self.setError(_("Invalid oct value: ") + str(strOct))
return False
return res
else:
14 years ago
self.setError(_("Empty oct value"))
return False
14 years ago
def getTemplateType(self):
"""выдать тип шаблона (text, bin)"""
14 years ago
return self.getFileType(self.nameFileTemplate)
def getFileType(self, fileName):
"""выдать тип файла (text, bin)"""
isBin = self.typeFileObj.isBinary(fileName)
14 years ago
if isBin is True:
typeTemplate = "bin"
elif isBin is False:
typeTemplate = "text"
else:
14 years ago
self.setError(_("ERROR") + ": getFileType()")
14 years ago
self.setError(isBin)
return False
return typeTemplate
def createDir(self, dirName, mode=False, uid=False, gid=False):
"""Создает директорию"""
if os.access(dirName, os.F_OK):
14 years ago
return True
else:
dMode = False
prevDir, tmpSubdir = os.path.split(dirName)
createDirs = []
while not os.access(prevDir, os.F_OK) and prevDir:
createDirs.append(prevDir)
prevDir = os.path.split(prevDir)[0]
try:
9 years ago
dUid, dGid = getModeFile(prevDir, "owner")
except OSError:
12 years ago
self.setError(_("No access to the directory: ") + prevDir)
return False
if not mode is False:
dMode = mode
if not uid is False:
dUid = uid
if not gid is False:
dGid = gid
createDirs.reverse()
for nameDir in createDirs:
try:
if dMode:
os.mkdir(nameDir, dMode)
os.chmod(nameDir, dMode)
else:
os.mkdir(nameDir)
self.chownConfDir(nameDir, dUid, dGid, None)
9 years ago
except OSError:
12 years ago
self.setError(_("Failed to create the directory: ")
9 years ago
+ nameDir)
return False
try:
if dMode:
os.mkdir(dirName, dMode)
os.chmod(dirName, dMode)
else:
os.mkdir(dirName)
self.chownConfDir(dirName, dUid, dGid, None)
createDirs.append(dirName)
9 years ago
except OSError:
12 years ago
self.setError(_("Failed to create the directory: ")
9 years ago
+ dirName)
return False
return createDirs
reBlock = re.compile(
"#\?(?P<rTerm>(?:[a-z0-9_]+\.)?[a-zA-Z0-9\-_]+).*?#(?P=rTerm)#"
"(?:[ ,\t]*\n?)",
re.S | re.M)
9 years ago
def applyTermsTemplate(self, textTemplate, nameTemplate):
""" Применяет условия, к условным блокам текста
"""
9 years ago
def function(text):
"""Функция обработки функций в заголовке"""
return self.applyFuncTemplate(text, nameTemplate)
def searchBlock(s):
resS = self.reBlock.search(s)
if resS:
funcblock = resS.group()
resS = self._reTermBloc.search(textTemplateTmp[:resS.end()])
if not resS:
raise TemplatesError(
"Wrong conditional block: %s" % funcblock)
return resS
textTemplateTmp = textTemplate
resS = searchBlock(textTemplateTmp)
while resS:
mark = resS.group(0)
body = resS.group("body")
end = resS.group("end")
notbody = ""
elseblock = "#!%s#" % resS.group("rTerm")
if elseblock in body:
data = re.split("\n?%s\n?" % elseblock, body)
body = data[0]
notbody = "".join(data[1:]) + end
body = body + end
parent = resS.group("func")
if not parent:
parent = ""
9 years ago
term = resS.group("rTerm") + parent + \
resS.group("lTerm")
if self._equalTerm(term, _("invalid template content: ") + \
nameTemplate, function):
textTemplateTmp = textTemplateTmp.replace(mark, body)
else:
textTemplateTmp = textTemplateTmp.replace(mark, notbody)
resS = searchBlock(textTemplateTmp)
return textTemplateTmp
def getNeedTemplate(self, fileTemplate):
"""Применяем правила к названию файла"""
9 years ago
dirP, fileP = os.path.split(fileTemplate)
if fileP:
spFile = fileP.split("?")
9 years ago
if len(spFile) > 1:
flagTrue = False
for term in spFile[1:]:
9 years ago
if self._equalTerm(term, _("invalid template name: ") + \
fileTemplate):
flagTrue = True
break
if flagTrue:
return True
else:
return False
else:
return True
else:
9 years ago
self.setError(_("invalid template name: ") + str(fileTemplate))
return False
def getTitle(self, comment, commentList, configPath=""):
"""Выдает заголовок шаблона ( версия и.т.д)"""
origConfigPath = PkgContents.reCfg.sub("/", configPath)
if self._baseDir != "/":
lenBaseDir = len(self._baseDir)
commentList = [x[lenBaseDir:]
if x.startswith(self._baseDir)
else x for x in commentList]
if configPath and self.protectPaths:
for protectPath in self.protectPaths:
14 years ago
if self._baseDir != "/":
lenBaseDir = len(self._baseDir)
9 years ago
if len(configPath) > lenBaseDir and \
configPath[:lenBaseDir] == self._baseDir:
14 years ago
configPath = configPath[lenBaseDir:]
if configPath.startswith(protectPath + "/"):
if not any(origConfigPath.endswith(x) for x in
("/calculate.env", "/ini.env", "/custom")):
commentList = commentList + \
[self.titleEnd % {
'conf_path': origConfigPath}]
break
if comment:
commentFirst = comment
commentInsert = comment
commentLast = comment
flagList = False
# В случае открывающего и закрывающего комментария
3 years ago
if type(comment) == tuple and len(comment) == 2:
commentFirst = comment[0]
commentInsert = ""
commentLast = comment[1]
flagList = True
if flagList:
self._titleBody = commentFirst + "\n"
else:
self._titleBody = commentFirst + self.__titleHead + "\n"
z = 0
flagFirst = True
9 years ago
for com in list(self._titleList) + [""] * (len(commentList)):
if com:
if flagFirst:
9 years ago
self._titleBody += commentInsert + " " + com + " " + \
self.programVersion + "\n"
flagFirst = False
else:
self._titleBody += commentInsert + " " + com + "\n"
else:
9 years ago
self._titleBody += commentInsert + " " + \
commentList[z] + "\n"
z += 1
if flagList:
9 years ago
self._titleBody += commentLast + "\n"
else:
self._titleBody += commentLast + self.__titleHead + "\n"
return self._titleBody
else:
return ""
9 years ago
def changeMergePackage(self, package):
return True
def numberAllTemplates(self, number):
"""Количество шаблонов
Вызов происходит перед наложением шаблонов
в момент вызова в number находится количество обрабатываемых файлов
Наследуемая функция
Используется для отображения прогресса при наложениии шаблонов
"""
return True
def numberProcessTemplates(self, number):
"""Номер текущего обрабатываемого шаблона
Вызов происходит при наложении шаблона
в момент вызова в number находится номер обрабатываемого шаблона
Наследуемая функция
Используется для отображения прогресса при наложениии шаблонов
"""
return True
11 years ago
def templateModify(self):
12 years ago
"""
Files which created by apping templates
"""
return True
9 years ago
def fixNameFileConfig(self, origfilename):
12 years ago
"""Support ._cfg0000 files for postinst"""
9 years ago
# if self.objVar.Get('cl_ebuild_phase') != 'postinst':
# return origfilename
9 years ago
directory, filename = os.path.split(origfilename)
for i in range(0, 9999):
12 years ago
if not os.path.exists(os.path.join(directory,
9 years ago
"._cfg%04d_%s" % (i, filename))):
12 years ago
if i:
filename = os.path.join(directory,
9 years ago
"._cfg%04d_%s" % (i - 1, filename))
#if not os.path.exists(origfilename):
# return origfilename
9 years ago
# origstat = os.stat(origfilename)[stat.ST_CTIME]
# newstat = os.stat(filename)[stat.ST_CTIME]
self.configMode = T_CFG
return filename
12 years ago
return origfilename
return origfilename
def getHeaderText(self, text, binary=False):
textLines = text.splitlines()
paramLine = ""
if textLines:
textLine = textLines[0]
reg = "\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$" if not binary \
else b"\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$"
rePar = re.compile(reg, re.I)
reP = rePar.search(textLine)
if reP:
reg = r"\A([^\\\n]*\\\n)+[^\n]*\n*" if not binary \
else rb"\A([^\\\n]*\\\n)+[^\n]*\n*"
reLns = re.compile(reg, re.M)
reLs = reLns.search(text)
if reLs:
paramLine = text[reP.end():reLs.end()]
if binary:
paramLine = paramLine.decode("UTF-8")
9 years ago
paramLine = paramLine.replace("\\", " ")
else:
paramLine = textLine[reP.end():]
if binary:
paramLine = paramLine.decode("UTF-8")
return paramLine
def getTemplateDirs(self, dirsTemplates):
"""Check template variable cl_name in first directories and files"""
14 years ago
skipDirs = []
skipTemplates = []
debug = False
for dirsTemplate in dirsTemplates:
filesAndDirs = [os.path.join(dirsTemplate, x) for x in listDirectory(dirsTemplate)]
for dirFile in filesAndDirs:
if os.path.isdir(dirFile):
flagDir = True
9 years ago
templatePath = os.path.join(dirFile, self.templDirNameFile)
if not os.path.isfile(templatePath):
skipDirs.append(dirFile)
continue
else:
flagDir = False
templatePath = dirFile
if os.path.isfile(templatePath):
if self.getFileType(templatePath) == "bin":
skipTemplates.append(dirFile)
else:
with open(templatePath, "r") as f:
textTemplate = f.read()
if textTemplate:
headerLine = self.getHeaderText(textTemplate)
if headerLine:
if not debug and \
9 years ago
not "cl_name==" in headerLine and \
not "ac_" in headerLine:
if flagDir:
skipDirs.append(dirFile)
else:
skipTemplates.append(dirFile)
else:
if flagDir:
skipDirs.append(dirFile)
else:
skipTemplates.append(dirFile)
else:
skipTemplates.append(dirFile)
if skipDirs or skipTemplates:
# print warning
self.printWARNING(_("No conditions for checking the value of "
"an action variable"))
skipDirTemplates = []
for skipDir in skipDirs:
9 years ago
skipTempl = os.path.join(skipDir, self.templDirNameFile)
if os.path.isfile(skipTempl):
skipDirTemplates.append(skipTempl)
if skipTemplates or skipDirTemplates:
11 years ago
self.printWARNING(_("Skipped templates:"))
for skipTemplate in skipTemplates + skipDirTemplates:
9 years ago
self.printWARNING(" " * 6 + skipTemplate)
if skipDirs:
11 years ago
self.printWARNING(_("Skipped directories:"))
for skipDir in skipDirs:
9 years ago
self.printWARNING(" " * 6 + skipDir)
11 years ago
self.printWARNING("")
self.printWARNING(_("Headers of directory templates and headers "
9 years ago
"of files on the first level should include "
"an action variable"))
11 years ago
self.printWARNING(_("Example:"))
self.printWARNING("# Calculate ac_install_merge==on")
return skipDirs + skipTemplates
def lock_package(self, pkg, fuser=None):
pkg = pkg.partition(":")[0]
if pkg not in self._locked_packages:
category, _, pkg = pkg.partition("/")
pkglockfile = ("/var/calculate/tmp/portage/"
"{}/.{}.calculate_lockfile".format(category, pkg))
ipcfile = ("/var/db/pkg/"
"{}/.{}*.portage_lockfile".format(category, pkg))
if os.path.exists(pkglockfile):
fuser = fuser or FUser()
if any(fuser.search(ipcfile)):
return False
l = Locker(fn=pkglockfile, timeout=0)
if l.acquire():
self._locked_packages[pkg] = l
return True
return False
return True
def unlock_packages(self):
for pkg, l in self._locked_packages.items():
if l:
l.remove()
self._locked_packages = {}
@catch_no_space_left
@post_unlock_packages
9 years ago
def applyTemplates(self, progress=True, rerun=True):
"""Применяет шаблоны к конфигурационным файлам"""
def createDictTemplates(path, prefix, dictTemplates):
"""Создает словарь {"директория":"кол-во шаблонов" ...}
и считает общее количество шаблонов
"""
# Количество шаблонов
self.allTemplates += 1
dirTemplate = os.path.split(path)[0]
9 years ago
while True:
if dirTemplate in dictTemplates.keys():
dictTemplates[dirTemplate] += 1
else:
dictTemplates[dirTemplate] = 1
if dirTemplate == prefix:
break
dirTemplate = os.path.split(dirTemplate)[0]
return dictTemplates
self.clearErrors()
12 years ago
self.clearWarnings()
if not self.objVar.defined("cl_template_path_use"):
self.setError(_("undefined variable: ") + "cl_template_path_use")
return False
dirsTemplates = [
os.path.realpath(x) for x in self.objVar.Get("cl_template_path_use")]
# Созданные директории
self.createdDirs = []
# Примененные файлы
self.filesApply = []
# Номер применяемого шаблона
self.numberProcessTempl = 0
# Словарь директорий с количеством файлов шаблонов
self.dictTemplates = {}
# Количество шаблонов
self.allTemplates = 0
14 years ago
# Установка по умолчанию аттрибутов для функциии шаблонов ini()
# Время доступа к конфигурационному файлу функции шаблона ini()
14 years ago
self.functObj.timeIni = -1
# Первоначальный словарь переменных для ini()
14 years ago
self.functObj.prevDictIni = {}
# Текущий словарь переменных для ini()
14 years ago
self.functObj.currDictIni = {}
self.functObj.currentBelong = ""
self.functObj.currentBelongSlot = ""
self.functObj.currentAction = HParams.ActionType.Merge
14 years ago
# Словарь времен модификации env файлов для ini()
self.functObj.timeConfigsIni = {}
if self._servDir:
tmpDirsTemplates = []
for dirP in dirsTemplates:
dirTempl = dirP + self._servDir
if os.access(dirTempl, os.F_OK):
# Если директория существует
tmpDirsTemplates.append(dirTempl)
dirsTemplates = tmpDirsTemplates
14 years ago
scanObj = scanDirectory()
9 years ago
scanObj.processingFile = lambda x, y: createDictTemplates(x, y,
self.dictTemplates)
# Считаем количество шаблонов
dirsTemplatesExists = [x for x in dirsTemplates if os.path.exists(x)]
if not dirsTemplatesExists and not self.cltObj:
9 years ago
return self.createdDirs, self.filesApply
# check cl_name in first template dirs and files
skipTemplates = self.getTemplateDirs(dirsTemplatesExists)
9 years ago
# if not os.environ.get("EBUILD_PHASE","") and progress:
# for dirTemplate in dirsTemplatesExists:
# scanObj.scanningDirectory(dirTemplate)
# Считаем количество шаблонов clt
if self.cltObj:
# Считаем количество шаблонов clt
self.cltObj.countsNumberTemplates()
# не считать количество файлов в объекте self.cltObj
self.cltObj.checkNumberTemplate = False
# начальный номер clt шаблона
self.cltObj.numberProcessTempl = self.allTemplates
# метод показывающий номер clt шаблона
self.cltObj.numberProcessTemplates = self.numberProcessTemplates
12 years ago
# метод показывающий номер clt шаблона
self.cltObj.templateModify = self.templateModify
# общее количество шаблонов
self.allTemplates += self.cltObj.allTemplates
self.cltObj.allTemplates = self.allTemplates
self.numberAllTemplates(self.allTemplates)
# Обрабатываем шаблоны
locationPath = dict(self.objVar.ZipVars('main.cl_template_path',
9 years ago
'main.cl_template_location'))
14 years ago
for dirTemplate in dirsTemplatesExists:
self.objVar.Set('cl_pass_location',
locationPath.get(dirTemplate, dirTemplate),
force=True)
if self.scanningTemplates(dirTemplate,
skipTemplates=skipTemplates) is False:
11 years ago
break
9 years ago
if self.cltObj:
self.objVar.Set('cl_pass_location', 'clt', True)
# Созданные директории
self.cltObj.createdDirs = self.createdDirs
# Примененные файлы
self.cltObj.filesApply = self.filesApply
# Словарь директорий с количеством файлов шаблонов
self.cltObj.dictTemplates = self.dictTemplates
# Количество шаблонов
self.cltObj.allTemplates = self.allTemplates
# Установка по умолчанию аттрибутов для функциии шаблонов ini()
# Время доступа к конфигурационному файлу функции шаблона ini()
self.cltObj.functObj = self.functObj
self.cltObj.protectedFiles = self.protectedFiles
# Метод применения функций к шаблонам
self.cltObj.applyFuncTemplate = self.functObj.applyFuncTemplate
# Словарь примененных файлов шаблонов
self.cltObj.dictProcessedTemplates = self.dictProcessedTemplates
self.cltObj.changedFiles = self.changedFiles
self.cltObj.autoUpdateFiles = self.autoUpdateFiles
self.cltObj.autoUpdateDirs = self.autoUpdateDirs
14 years ago
if self.cltFilter:
14 years ago
# Шаблоны + .clt которые будут применены
self.cltObj.filterApplyTemplates = {}
if self.objVar.Get('cl_merge_set') == "on":
for pkg in self.objVar.Get('cl_merge_pkg'):
if not pkg:
continue
atom = list(sorted(getInstalledAtom(pkg)))
if atom:
pkgContents = PkgContents("{CATEGORY}/{PF}".format(
**atom[-1]))
for filename in pkgContents.content.keys():
if not filename in self.cltObj.filterApplyTemplates:
9 years ago
self.cltObj.filterApplyTemplates[
filename] = []
self.cltObj.filterApplyTemplates[
filename].append(pkg)
for filename, pkgs in self.changedFiles.data.items():
filename = PkgContents.reCfg.sub("/", filename)
if not filename in self.cltObj.filterApplyTemplates:
9 years ago
self.cltObj.filterApplyTemplates[filename] = []
pkgs = [x for x in [z[0] for z in pkgs]
if x not in self.cltObj.filterApplyTemplates[filename]]
self.cltObj.filterApplyTemplates[filename].extend(pkgs)
old_mod = self.objVar.defaultModule
try:
self.objVar.defaultModule = "install"
self.cltObj.applyTemplatesClt()
finally:
self.objVar.defaultModule = old_mod
9 years ago
if ((self.objVar.Get('cl_merge_pkg') or
self.objVar.Get('cl_action') in (
"sync", "domain", "server_setup",
9 years ago
"undomain")) and
self.objVar.Get('cl_merge_pkg_new')):
skip_pkglist = []
if self.objVar.Get('cl_ebuild_phase'):
new_pkglist = []
for pkgn in self.objVar.Get('cl_merge_pkg_new'):
if not pkgn:
continue
if self.lock_package(pkgn):
new_pkglist.append(pkgn)
else:
skip_pkglist.append(pkgn)
self.objVar.Set('cl_merge_pkg_new', new_pkglist, force=True)
else:
new_pkglist = self.objVar.Get('cl_merge_pkg_new')
if new_pkglist:
self.objVar.Set('cl_root_path',
self.objVar.Get('cl_root_path_next'), force=True)
self.recalculateBaseDir()
self.objVar.Set('cl_merge_pkg_pass', list(
set(self.objVar.Get('cl_merge_pkg_pass')) |
set(self.objVar.Get('cl_merge_pkg')) |
set(skip_pkglist) |
set(self.objVar.Get('cl_merge_pkg_new'))), force=True)
self.objVar.Set('cl_merge_pkg',
self.objVar.Get('cl_merge_pkg_new'), force=True)
self.objVar.Set('cl_merge_pkg_new', [], force=True)
createdDirs = self.createdDirs
filesApply = self.filesApply
self.changeMergePackage(self.objVar.Get('cl_merge_pkg'))
self.applyTemplates(rerun=False)
createdDirs.extend(self.createdDirs)
filesApply.extend(self.filesApply)
self.filesApply = filesApply
self.createdDirs = createdDirs
9 years ago
if rerun:
if self.cltObj:
self.queueExecute.extend(self.cltObj.queueExecute)
9 years ago
for processor, text, nameTemplate in self.queueExecute:
if not self.executeTemplate(text, processor):
self.setError(_("Failed to execute") + _(": ") +
nameTemplate)
return False
self.queueExecute = []
self.filesApply = list(set(self.filesApply))
if (self.objVar.Get('cl_root_path') == '/' and
self.objVar.Get('cl_chroot_path') == '/'):
post_script = []
if any("/etc/env.d" in x for x in self.filesApply):
post_script.append(
"LANG=C /usr/sbin/env-update --no-ldconfig")
post_script.append("source /etc/profile")
root_type = self.objVar.Get('install.os_install_root_type')
if (root_type != "livecd" and
any("/etc/locale.gen" in x for x in self.filesApply)):
post_script.append("/usr/sbin/locale-gen &>/dev/null")
self.executeTemplate("\n".join(post_script), "/bin/bash")
if self.objVar.Get('cl_protect_use_set') == 'on':
self.updateProtectedFiles()
if self.objVar.Get('cl_verbose_set') == 'on' and self.filesApply:
self.verboseOutput([x for x in self.filesApply if not x.endswith('/ini.env')])
9 years ago
self.objVar.Set('cl_merge_pkg_pass', [], force=True)
self.objVar.Set('cl_merge_pkg_new', [], force=True)
self.objVar.Set('cl_merge_pkg', [], force=True)
return self.createdDirs, self.filesApply
def verboseOutput(self, filesApply):
"""
Verbose output applied templates
"""
if not filesApply:
return
9 years ago
self.printWARNING(_("Calculate Utilities have changed files") + _(":"))
reGrey = re.compile(r"\._cfg\d{4}_")
11 years ago
rootPath = self.objVar.Get('cl_root_path')
for fn in sorted(list(set(filesApply))):
11 years ago
if rootPath != '/' and self.objVar.Get('cl_action') == 'patch' and \
9 years ago
fn.startswith(rootPath):
fn = fn[len(rootPath) + 1:]
if reGrey.search(fn):
9 years ago
self.printSUCCESS("&nbsp;" * 5 + \
"<font color=\"dark gray\">%s</font>" % fn)
else:
9 years ago
self.printSUCCESS("&nbsp;" * 5 + fn)
def updateProtectedFiles(self):
"""
Update ._cfg0000 files
"""
11 years ago
if self.objVar.Get('cl_ebuild_phase') == 'compile':
return
chrootPath = self.objVar.Get('cl_chroot_path')
cfgs = getCfgFiles(self.objVar.Get('cl_config_protect'),
prefix=chrootPath)
reverse_cfgs = {y[0][1]: x for x, y in cfgs.items()}
autoUpdateDict = {}
get_digest = lambda x: hashlib.md5(readFile(x, binary=True)).hexdigest()
9 years ago
for pkg in list(set(filter(None, list(self.changedFiles.getPkgs()) +
self.objVar.Get('cl_merge_pkg')))):
atom = list(sorted(getInstalledAtom(pkg, prefix=chrootPath)))
if atom:
pkgContents = PkgContents("{CATEGORY}/{PF}".format(
**atom[-1]), prefix=chrootPath)
protected = []
checked_map = {}
9 years ago
for filename, action in self.changedFiles.getPkgFiles(pkg):
origFn = pkgContents.origFileName(filename)
if origFn in self.protectedFiles:
pkgContents.removeObject(filename)
protected.append(origFn)
continue
if action in (ChangedFiles.FILE_MODIFIED,
ChangedFiles.DIR_CREATED,
ChangedFiles.DIR_EXISTS):
orig_filename = reverse_cfgs.get(filename, None)
if orig_filename:
checked_map[orig_filename] = (
get_digest(filename) == get_digest(
orig_filename))
# не давать править CONTENTS
if (orig_filename is None or
not checked_map[orig_filename]):
pkgContents.addObject(filename)
elif action in (ChangedFiles.FILE_REMOVED,
ChangedFiles.DIR_REMOVED):
pkgContents.removeObject(filename)
files = set([pathJoin(chrootPath, x) for x
in pkgContents.content.keys()] + protected)
if (self.objVar.Get('cl_dispatch_conf') != 'usenew' and
9 years ago
self.objVar.Get('cl_autoupdate_set') != "on"):
notUpdate = files - set(self.autoUpdateFiles)
files &= set(self.autoUpdateFiles)
9 years ago
for filename in list(notUpdate & set(cfgs.keys())):
equal = checked_map.get(
filename,
get_digest(filename) == get_digest(
cfgs[filename][0][1]))
if equal:
files.add(filename)
9 years ago
for filename in list(files & set(cfgs.keys())):
# get ctime from orig filename
9 years ago
# if os.path.exists(filename):
# ctime = os.stat(filename).st_ctime
9 years ago
# else:
# ctime = 0
# if orig filename older that .cfg
cfgs[filename].sort(reverse=True)
9 years ago
# if ctime < cfgs[filename][0][0]:
try:
with open(filename, 'w') as f:
f.write(readFile(cfgs[filename][0][1]))
self.copy_mod_own(cfgs[filename][0][1], filename)
except Exception as e:
self.printERROR(str(e))
self.printWARNING(
_("Failed to copy {ffrom} to {fto}").format(
9 years ago
ffrom=cfgs[filename][0][1], fto=filename))
continue
autoUpdateDict[cfgs[filename][0][1]] = filename
9 years ago
for mtime, fn in cfgs[filename]:
try:
if os.path.exists(fn):
os.unlink(fn)
9 years ago
except OSError:
self.printWARNING(_("Failed to remove %s") % fn)
try:
pkgContents.writeContents()
9 years ago
except IOError:
self.printWARNING(_("Failed to modify %s contents") % pkg)
self.filesApply = [autoUpdateDict.get(x, x) for x in self.filesApply]
if [x for x in self.filesApply if "._cfg" in x]:
if self.objVar.Get('cl_ebuild_phase') != '':
self.printWARNING(_("Some config files need updating. "
9 years ago
"Perform run dispatch-conf."))
11 years ago
if self.dispatchConf and \
9 years ago
self.objVar.Get(
'cl_dispatch_conf') == 'dispatch' and \
self.objVar.Get('cl_ebuild_phase') == '':
self.dispatchConf(self.filesApply)
def scanningTemplates(self, scanDir, prefix=None, flagDir=False,
9 years ago
optDir=None, skipTemplates=()):
"""Сканирование и обработка шаблонов в директории scanDir"""
9 years ago
if optDir is None:
# ключи: HParams.OptDir.{Path,Skip,Autoupdate}
9 years ago
optDir = {}
ret = True
##scanDir == '/var/db/repos/calculate/profiles/templates/3.6/2_ac_install_merge/media-sound/pulseaudio/daemon.conf'
if not prefix:
prefix = os.path.realpath(scanDir)
if not flagDir:
# проверка корневой директории
retDir = self.processingDirectory(scanDir, scanDir, optDir)
if retDir is None:
return None
elif retDir is False:
return False
9 years ago
pathDir, objHead = retDir
optDir[HParams.OptDir.Path] = pathDir
if not objHead is True:
if objHead.typeAppend == HParams.AppendParams.Skip:
# Установка опции пропуска директории
optDir[HParams.OptDir.Skip] = True
if (HParams.Autoupdate in objHead.params or
9 years ago
self.objVar.Get('cl_autoupdate_set') == 'on'):
optDir[HParams.OptDir.Autoupdate] = True
if flagDir or stat.S_ISDIR(os.lstat(str(scanDir))[stat.ST_MODE]):
9 years ago
if not os.access(scanDir, os.R_OK | os.X_OK):
self.printWARNING(_("Failed to read templates directory %s") %
scanDir)
return False
for fileOrDir in sorted(listDirectory(scanDir)):
9 years ago
absPath = os.path.join(scanDir, fileOrDir)
if skipTemplates and absPath in skipTemplates:
9 years ago
continue
stInfo = os.lstat(str(absPath))
statInfo = stInfo[stat.ST_MODE]
12 years ago
prevModule = self.objVar.defaultModule
prevBelong = self.functObj.currentBelong
prevBelongSlot = self.functObj.currentBelongSlot
prevAction = self.functObj.currentAction
12 years ago
try:
if stat.S_ISREG(statInfo):
12 years ago
if not self.processingFile(absPath, prefix, optDir):
ret = False
11 years ago
continue
12 years ago
elif stat.S_ISDIR(statInfo):
# Обработка директории
retDir = self.processingDirectory(absPath, prefix,
optDir)
if retDir is None:
continue
elif retDir is False:
ret = False
break
# Опции следующей директории
optNextDir = {}
9 years ago
pathDir, objHead = retDir
optNextDir[HParams.OptDir.Path] = pathDir
if objHead is not True:
if objHead.typeAppend == HParams.AppendParams.Skip:
12 years ago
# Установка опции пропуска директории
optNextDir[HParams.OptDir.Skip] = True
if (HParams.Autoupdate in objHead.params or
9 years ago
self.objVar.Get(
'cl_autoupdate_set') == 'on'):
optNextDir[HParams.OptDir.Autoupdate] = True
12 years ago
ret = self.scanningTemplates(absPath, prefix, True,
optNextDir)
if objHead is not True:
if has_any(objHead.params, HParams.ServiceControl):
self.doServiceControl(objHead.params)
12 years ago
if ret is False:
break
except TemplatesError as e:
self.clearErrors()
if self.critical:
raise
else:
self.printWARNING(str(e))
12 years ago
finally:
self.objVar.defaultModule = prevModule
self.functObj.currentBelong = prevBelong
self.functObj.currentBelongSlot = prevBelongSlot
self.functObj.currentAction = prevAction
return ret
def processingFile(self, path, prefix, optFile):
"""Обработка в случае шаблона файла"""
self.numberProcessTempl += 1
self.numberProcessTemplates(self.numberProcessTempl)
# Пропуск шаблонов директорий
if self.templDirNameFile == os.path.split(path)[1]:
return True
14 years ago
# Проверка на переменные в названии файла
if not self.getNeedTemplate(path):
if self.getError():
return False
14 years ago
return True
if self.getError():
return False
nameFileConfig = path.partition(prefix)[2]
# файл в системе без условий
nameFileConfig = "/".join((x.split("?")[0] for x in nameFileConfig.split("/")))
14 years ago
# Записываем в переменную обрабатываемый файл
self.objVar.Set("cl_pass_file", os.path.basename(nameFileConfig))
self.headerParams = None
#debug these templates:
#2_ac_install_merge/xfce-base/thunar/uca.xml (ELEMENT goes in before header for some reason (check add comment))
14 years ago
filesApl = self.joinTemplate(path, nameFileConfig, optFile)
if self.headerParams:
if has_any(self.headerParams, HParams.ServiceControl):
self.doServiceControl(self.headerParams)
14 years ago
if self.getError():
return False
if filesApl:
14 years ago
# Настоящее имя конфигурационного файла
nameFileConfig = filesApl[0]
# Пишем время модификации *.env файлов
if nameFileConfig.endswith(".env"):
nameEnvFile = os.path.basename(nameFileConfig)
self.functObj.timeConfigsIni[nameEnvFile] = float(time.time())
14 years ago
self.filesApply += filesApl
if filesApl:
self._addFile(filesApl)
return True
def processingDirectory(self, path, prefix, opt):
"""Обработка в случае директории если возвращаем None то пропуск дир."""
if path.endswith("/.git"):
return None
# Файл шаблона директории
9 years ago
if not os.access(path, os.R_OK | os.X_OK):
self.printWARNING(_("Failed to read templates directory %s") % path)
return None
dirInfoFile = os.path.join(path, self.templDirNameFile)
newDir = pathJoin(self._baseDir, path.partition(prefix)[2])
newDir = "/".join((x.split("?")[0]) for x in newDir.split("/"))
# Применяем шаблон
9 years ago
pathDir, objHeadDir, createdDirs = \
self.getApplyHeadDir(newDir, dirInfoFile, opt)
14 years ago
if createdDirs:
self.createdDirs += createdDirs
if os.path.isfile(pathDir):
11 years ago
self.printWARNING(_("{dirpath} is a file").format(dirpath=pathDir))
self.printWARNING(
_("templates in {tempath} are skipped").format(tempath=path))
return None
if objHeadDir:
14 years ago
return pathDir, objHeadDir
else:
if self.getError():
return False
# Добавление количества файлов в пропущенной директории
if path in self.dictTemplates.keys():
self.numberProcessTempl += self.dictTemplates[path]
return None
9 years ago
def setRebuildVersion(self, prev_ver):
if "_rc73" in prev_ver:
return prev_ver
ver_nor = prev_ver.partition("-")[0]
# rc даже после уже существующего гарантирует, что версия будет
# считаться ниже
3 years ago
#reRc = re.compile(r"(.*rc)(\d+)(.*)")
#rc_match = reRc.search(ver_nor)
#if rc_match:
# rc_num = max(0, int(rc_match.group(2)) - 1)
# return "%s%d%s" % (rc_match.group(1), rc_num, rc_match.group(3))
return "%s_rc73" % ver_nor
def _processRebuild(self, params, templateDirFile):
"""
Обработка параметра rebuild=
:param params:
:param templateDirFile:
:return:
"""
if HParams.Rebuild in params:
rebuild_packages = params[HParams.Rebuild].split(',')
chroot_path = self.objVar.Get('cl_chroot_path')
for atom in rebuild_packages:
for pkg in getInstalledAtom(
atom, prefix=chroot_path):
ver = pkg["PVR"]
new_ver = self.setRebuildVersion(ver)
if ver != new_ver:
try:
fn = pathJoin(chroot_path, "var/db/pkg",
"%s-%s" % (pkg["CATEGORY/PN"],
pkg["PVR"]))
new_fn = pathJoin(chroot_path, "var/db/pkg",
"%s-%s" % (pkg["CATEGORY/PN"],
new_ver))
shutil.copytree(fn, new_fn, symlinks=True)
shutil.rmtree(fn)
except (OSError, IOError) as e:
self.printWARNING(
_("Failed to change version of %s") % str(pkg))
9 years ago
def _processMergePostmerge(self, params, templateDirFile):
"""Обработка параметров merge= , postmerge="""
if HParams.Merge in params:
mergePkgs = params[HParams.Merge].split(',')
if self.objVar.Get('cl_action') == "config":
self.printWARNING(
_("Config action is not support '%s' parameter")
% HParams.Merge )
return
else:
mergePkgs = []
if HParams.PostMerge in params:
postmergePkgs = params[HParams.PostMerge].split(',')
if self.objVar.Get('cl_action') == "config":
self.printWARNING(
_("Config action is not support '%s' parameter")
% HParams.PostMerge )
return
else:
postmergePkgs = []
if mergePkgs or postmergePkgs:
if self.objVar.Get('cl_ebuild_phase') == 'postinst':
for pkg in postmergePkgs:
if pkg not in self.objVar.Get('cl_merge_pkg_pass'):
self.objVar.Get('cl_merge_pkg_pass').append(pkg)
if pkg not in self.postmergePkgs:
try:
9 years ago
with open(self.postmergeFile, "a") as f:
f.write("%s\n" % pkg)
self.postmergePkgs.append(pkg)
9 years ago
except OSError:
self.printWARNING(
9 years ago
_("Failed to reconfigure package %s") % pkg)
else:
mergePkgs = mergePkgs + postmergePkgs
for pkg in mergePkgs:
curlistset = set(self.objVar.Get('cl_merge_pkg_new') +
self.objVar.Get('cl_merge_pkg_pass') +
self.objVar.Get('cl_merge_pkg'))
if ":" not in pkg:
curlistset = {x.partition(":")[0] for x in curlistset
if x}
if pkg not in curlistset:
self.objVar.Get('cl_merge_pkg_new').append(pkg)
def checkVfat(self, fn):
if self.mounts is None:
self.mounts = Mounts()
if self.mounts.getBy(self.mounts.TYPE, where=self.mounts.DIR,
_in=fn) in ("vfat", "ntfs-3g", "ntfs"):
return True
return False
def checkOsError(self, e, fn):
3 years ago
if hasattr(e, 'errno') and e.errno == errno.EPERM:
if self.checkVfat(fn):
return True
3 years ago
if hasattr(e, 'errno') and e.errno == errno.EACCES and \
"var/calculate/remote" in fn:
return True
return False
def setUidGidError(self, fn, uid, gid, tfn=None):
"""
Установить ошибку связанную со сменой UID и GID файла
"""
import pwd, grp
try:
userName = pwd.getpwuid(uid).pw_name
except (TypeError, KeyError):
userName = str(uid)
try:
groupName = grp.getgrgid(gid).gr_name
except (TypeError, KeyError):
groupName = str(gid)
owner = userName + ":" + groupName
if tfn:
self.setError(_("Failed to apply template file %s") % tfn)
self.setError(_("error") + " " + "'%s %s %s'" % (
HParams.ChangeOwner, owner, fn))
def setModeError(self, fn, mode, tfn):
"""
Установить ошибку связанную со сменой доступа к файлу
"""
self.setError(_("Failed to apply template file %s") % tfn)
self.setError(_("error") + " " +
"'%s %s %s'" % (
HParams.ChangeMode, str(oct(mode)), fn))
def chownConfDir(self, nameDirConfig, uid, gid, nameFileTemplate):
"""Изменение владельца конфигурационной директории"""
try:
os.chown(nameDirConfig, uid, gid)
except (OSError, Exception) as e:
if self.checkOsError(e, nameDirConfig):
return True
self.setUidGidError(
nameDirConfig, uid, gid, nameFileTemplate)
return False
return True
def chmodConfDir(self, nameDirConfig, mode, nameFileTemplate):
"""Изменения режима доступа конфигурационного файла"""
try:
os.chmod(nameDirConfig, mode)
except (OSError, Exception) as e:
if self.checkOsError(e, nameDirConfig):
return True
self.setModeError(nameDirConfig, mode, nameFileTemplate)
return False
return True
def getApplyHeadDir(self, newDir, templateDirFile, optDir):
"""Применяет шаблон к директории (права, владелец, и.т. д)"""
def function(text):
"""Функция обработки функций в заголовке"""
return self.applyFuncTemplate(text, templateDirFile)
applyDir = newDir
# Родительская директория
if optDir.get(HParams.OptDir.Path):
path = optDir[HParams.OptDir.Path]
else:
if applyDir == self._baseDir:
path = os.path.dirname(self._baseDir)
else:
path = os.path.split(applyDir)[1]
path = pathJoin(self._baseDir, path)
if not os.path.exists(templateDirFile):
if applyDir != self._baseDir:
applyDir = os.path.join(path, os.path.split(applyDir)[1])
# Фильтрация шаблонов по названию директории
9 years ago
realPath = os.path.join("/", applyDir.partition(self._baseDir)[2])
if realPath in self.dirsFilter:
9 years ago
return "", False, []
14 years ago
# Создаем директорию если необходимо
14 years ago
crDirs = self.createDir(applyDir, False, self.uid, self.gid)
if not crDirs:
9 years ago
return "", False, []
if HParams.OptDir.Autoupdate in optDir:
self.autoUpdateDirs.append(applyDir)
14 years ago
if crDirs is True:
9 years ago
return applyDir, True, []
14 years ago
else:
9 years ago
return applyDir, True, crDirs
try:
self.objVar.Set("cl_pass_file",
os.path.basename(os.path.dirname(templateDirFile)))
with open(templateDirFile) as FD:
textTemplate = FD.readline().rstrip()
buf = textTemplate
while buf and textTemplate.endswith('\\'):
buf = FD.readline()
textTemplate = "%s %s" % (textTemplate[:-1], buf.rstrip())
9 years ago
except IOError:
self.setError(_("Failed to open the template") + _(": ") +
9 years ago
templateDirFile)
return "", False, []
12 years ago
headerLine = self.getHeaderText(textTemplate)
if headerLine:
envparam = "%s=" % HParams.Environ
moduleParam = [x for x in headerLine.split() if x.startswith(envparam)]
12 years ago
if moduleParam:
self.objVar.defaultModule = moduleParam[0].partition('=')[2]
try:
9 years ago
importlib.import_module(
"calculate.%s.variables" % self.objVar.defaultModule)
except (ImportError, AttributeError):
return "", False, []
# Заменяем переменные на их значения
# textTemplate = self.applyVarsTemplate(textTemplate, templateDirFile)
14 years ago
# Заменяем функции на их значения
# textTemplate = self.applyFuncTemplate(textTemplate, templateDirFile)
# Обработка заголовка
9 years ago
objHead = dirHeader(templateDirFile, textTemplate, self.objVar,
function, templateObj=self)
signs = {'ac_install_patch==on': HParams.ActionType.Patch,
'ac_desktop_profile==on': HParams.ActionType.Profile}
for sign in signs:
if sign in textTemplate:
self.functObj.currentAction = signs[sign]
break
14 years ago
# Директория с профилями не будет применена
if not objHead.headerTerm:
if objHead.getError():
self.setError(_("Incorrect template") + _(": ") +
templateDirFile)
9 years ago
return "", False, []
# add packeges for reconfigure
self._processMergePostmerge(objHead.params, templateDirFile)
self._processRebuild(objHead.params, templateDirFile)
# Пропускаем директорию
if objHead.typeAppend == HParams.AppendParams.Skip:
applyDir = path
9 years ago
return applyDir, objHead, []
# Изменяем название родительской директории
if HParams.Path in objHead.params:
path = objHead.params[HParams.Path]
if path and path[0] == "~":
# Получаем путь с заменой ~ на директорию пользователя
path = os.path.join(self.homeDir,
9 years ago
path.partition("/")[2], "")[:-1]
elif not path or path and path[0] != "/":
self.setError(
(_("Wrong value '%s' in the template") % HParams.Path) +
_(": ") + templateDirFile)
9 years ago
return "", False, []
else:
path = pathJoin(self._baseDir, path)
# Изменяем название директории
if HParams.Name in objHead.params:
nameDir = objHead.params[HParams.Name]
if "/" in nameDir or nameDir == ".." or nameDir == ".":
self.setError(
(_("Wrong value '%s' in the template") % HParams.Name) +
_(": ") + templateDirFile)
9 years ago
return "", False, []
# Новый путь к директории
applyDir = pathJoin(path, nameDir)
else:
applyDir = pathJoin(path, os.path.split(applyDir)[1])
# Фильтрация шаблонов по названию директории
9 years ago
realPath = os.path.join("/", applyDir.partition(self._baseDir)[2])
if realPath in self.dirsFilter:
9 years ago
return "", False, []
if HParams.DirectoryLink in objHead.params:
if objHead.typeAppend not in HParams.AppendParams.LinkDirCompatible:
self.setError(
_("Option '%(opt)s' should be used with %(appends)s only") %
{'opt': HParams.DirectoryLink,
'appends': ",".join(
"%s=%s" % (HParams.Append, x)
for x in HParams.AppendParams.LinkDirCompatible)
})
return "", False, []
# Удаляем директорию
if objHead.typeAppend == HParams.AppendParams.Remove:
if os.path.isdir(applyDir):
9 years ago
self.changedFiles.addObj(applyDir, ChangedFiles.DIR_REMOVED,
self.functObj.currentBelong,
self.functObj.currentBelongSlot)
# удаляем директорию
try:
14 years ago
removeDir(applyDir)
9 years ago
except OSError:
self.setError(_("Failed to delete the directory: ") + \
applyDir)
return "", False, []
# Очищаем директорию
if objHead.typeAppend == HParams.AppendParams.Clear:
if os.path.isdir(applyDir):
for rmPath in os.listdir(applyDir):
removePath = pathJoin(applyDir, rmPath)
if os.path.isdir(removePath):
# удаляем директорию
try:
removeDir(removePath)
9 years ago
except OSError:
12 years ago
self.setError(
9 years ago
_("Failed to delete the directory: ") + \
removePath)
else:
try:
os.unlink(removePath)
9 years ago
except OSError:
12 years ago
self.setError(
_("Failed to delete: ") + removePath)
9 years ago
return "", False, []
14 years ago
# Созданные директории
createdDirs = []
# chmod - изменяем права
mode = None
if HParams.ChangeMode in objHead.params:
mode = self.__octToInt(objHead.params[HParams.ChangeMode])
if mode:
if not os.path.exists(applyDir):
14 years ago
crDirs = self.createDir(applyDir, mode, self.uid, self.gid)
if not crDirs:
9 years ago
return "", False, []
14 years ago
if not crDirs is True:
createdDirs += crDirs
else:
self.chmodConfDir(applyDir, mode, templateDirFile)
else:
self.setError(
(_("Wrong value '%s' in the template")
% HParams.ChangeMode) + _(": ") + templateDirFile)
9 years ago
return "", False, []
# chown - изменяем владельца и группу
owner_uid, owner_gid = None, None
if HParams.ChangeOwner in objHead.params:
owner = objHead.params[HParams.ChangeOwner]
if owner:
9 years ago
if ":" in owner:
strUid, strGid = owner.split(":")
if strUid.isdigit():
owner_uid = int(strUid)
else:
owner_uid = self.getUidFromPasswd(strUid)
import pwd
9 years ago
try:
if owner_uid is None:
owner_uid = pwd.getpwnam(strUid).pw_uid
except (KeyError, TypeError):
self.setError(_("No such user on the system: ")
+ strUid)
self.setError(
(_("Wrong value '%s' in the template")
% HParams.ChangeOwner) + _(": ") + templateDirFile)
return "", False, []
if strGid.isdigit():
owner_gid = int(strGid)
else:
owner_gid = self.getGidFromGroup(strGid)
import grp
try:
if owner_gid is None:
owner_gid = grp.getgrnam(strGid).gr_gid
except (KeyError, TypeError):
self.setError(_("Group not found on the system: ")
+ strGid)
self.setError(
(_("Wrong value '%s' in the template")
% HParams.ChangeOwner) + _(": ") + templateDirFile)
return "", False, []
if not os.path.exists(applyDir):
crDirs = self.createDir(applyDir, False, owner_uid,
owner_gid)
14 years ago
if not crDirs:
9 years ago
return "", False, []
14 years ago
if not crDirs is True:
createdDirs += crDirs
else:
if not self.chownConfDir(applyDir, owner_uid, owner_gid,
templateDirFile):
9 years ago
return "", False, []
else:
self.setError(
(_("Wrong value '%s' in the template")
% HParams.ChangeOwner) + _(": ") + templateDirFile)
9 years ago
return "", False, []
else:
self.setError(
(_("Wrong value '%s' in the template")
% HParams.ChangeOwner) + _(": ") + templateDirFile)
9 years ago
return "", False, []
14 years ago
else:
# Устанавливаем владельцем директории, пользователя по умолчанию
# (переменная шаблона ur_login)
if os.path.exists(applyDir):
9 years ago
self.changedFiles.addObj(applyDir, ChangedFiles.DIR_EXISTS,
self.functObj.currentBelong,
self.functObj.currentBelongSlot)
14 years ago
tUid, tGid = getModeFile(applyDir, mode="owner")
if (self.uid, self.gid) != (tUid, tGid):
if not self.chownConfDir(applyDir, self.uid, self.gid,
templateDirFile):
9 years ago
return "", False, []
14 years ago
else:
9 years ago
self.changedFiles.addObj(applyDir, ChangedFiles.DIR_CREATED,
self.functObj.currentBelong,
self.functObj.currentBelongSlot)
14 years ago
crDirs = self.createDir(applyDir, False, self.uid, self.gid)
if not crDirs:
9 years ago
return "", False, []
if crDirs is not True:
14 years ago
createdDirs += crDirs
if HParams.DirectoryLink in objHead.params:
templateFile = objHead.params[HParams.DirectoryLink]
templateFile = pathJoin(self._baseDir, templateFile)
if not os.path.isdir(templateFile):
8 years ago
self.setError(_("Source path %s is not a directory")
8 years ago
% templateFile)
return "", False, []
try:
if objHead.typeAppend == HParams.AppendParams.Replace:
for fn in listDirectory(applyDir, fullPath=True):
if os.path.isdir(fn):
shutil.rmtree(fn)
elif os.path.isfile(fn) or os.path.islink(fn):
os.unlink(fn)
for fn in listDirectory(templateFile, fullPath=True):
applyFn = os.path.join(applyDir, os.path.basename(fn))
if os.path.isfile(fn):
shutil.copy2(fn, applyFn)
elif os.path.islink(fn):
os.symlink(os.readlink(fn), applyFn)
elif os.path.isdir(fn):
dir_sync(fn, applyFn)
except (IOError, OSError) as e:
8 years ago
self.setError(_("Failed to synchronize directory "
"{dn}: {error}").format(dn=templateFile,
error=str(e)))
return "", False, []
14 years ago
if not objHead:
applyDir = ""
if applyDir:
if ((HParams.OptDir.Autoupdate in optDir or
HParams.Autoupdate in objHead.params) and
not self.objVar.Get('cl_merge_pkg_pass')):
self.autoUpdateDirs.append(applyDir)
9 years ago
return applyDir, objHead, createdDirs
9 years ago
def getUidFromPasswd(self, strUid):
"""Get uid by username from chroot passwd file"""
9 years ago
passwdFile = os.path.join(self._baseDir, 'etc/passwd')
if os.path.exists(passwdFile):
with open(passwdFile, 'r') as f:
mapUid = dict([x for x in [y.split(':')[0:3:2] for y
in f if not y.startswith('#')]
if x and len(x) > 1 and x[0] and x[1]])
if strUid in mapUid:
return int(mapUid[strUid])
return None
9 years ago
def getGidFromGroup(self, strGid):
"""Get gid by groupname from chroot group file"""
9 years ago
groupFile = os.path.join(self._baseDir, 'etc/group')
if os.path.exists(groupFile):
with open(groupFile, 'r') as f:
mapGid = dict([x for x in [y.split(':')[0:3:2] for y
in f if not y.startswith('#')]
if x and len(x) > 1 and x[0] and x[1]])
if strGid in mapGid:
return int(mapGid[strGid])
return None
9 years ago
def checkOnNewConfigName(self, pathFile):
"""
Check on need update and return pathFile
"""
# if file in PROTECT_MASK or not in PROTECT
chrootPath = self.objVar.Get('cl_chroot_path')
if not [x for x in [pathJoin(chrootPath, y) for y in self.objVar.Get('cl_config_protect')] if pathFile.startswith(x)] or \
[x for x in [pathJoin(chrootPath, y) for y in self.objVar.Get('cl_config_protect_mask')] if pathFile.startswith(x)]:
return pathFile
# if file was already modified by templates
if pathFile in self.changedFiles.data.keys():
return pathFile
# if using already created ._cfg file
if self.configMode != T_ORIGIN:
return pathFile
# not current package file
pkg = self.functObj.currentBelong
slot = self.functObj.currentBelongSlot
if not pkg:
if not self.allContents:
fillContents(self.allContents,
9 years ago
self.objVar.Get('cl_config_protect'),
prefix=self.objVar.Get('cl_chroot_path'))
origName = pathFile if chrootPath == '/' \
9 years ago
else pathFile[len(chrootPath):]
if origName in self.allContents:
pkg = self.allContents[origName]
else:
return pathFile
if slot:
pkgslot = "{}:{}".format(pkg,slot)
else:
pkgslot = pkg
atom = list(sorted(getInstalledAtom(pkgslot, prefix=chrootPath)))
if not atom:
return pathFile
if checkContents("{CATEGORY}/{PF}".format(**atom[-1]),
9 years ago
pathFile,
prefix=chrootPath,
reservedFile='/var/lib/calculate/-CONTENTS-{PN}'.format(
**atom[-1]) \
if self.objVar.Get('cl_ebuild_phase') == 'postinst' \
else None):
9 years ago
return pathFile
real_filename = os.path.basename(pathFile)
real_dirname = os.path.dirname(pathFile)
self.configMode = T_NEWCFG
9 years ago
return os.path.join(real_dirname, "._cfg0000_%s" % real_filename)
def chownConfFile(self, nameFileConfig, uid, gid, nameFileTemplate,
checkExists=True):
"""Изменение владельца конфигурационного файла"""
try:
if checkExists and not os.path.exists(nameFileConfig):
# Создание файла
open(nameFileConfig, "w").close()
os.lchown(nameFileConfig, uid, gid)
except (OSError, Exception) as e:
if self.checkOsError(e, nameFileConfig):
return True
self.setUidGidError(
nameFileConfig, uid, gid, nameFileTemplate)
return False
return True
def chmodConfFile(self, nameFileConfig, mode, nameFileTemplate,
checkExists=True):
"""Изменения режима доступа конфигурационного файла"""
try:
if checkExists and not os.path.exists(nameFileConfig):
# Создание файла
open(nameFileConfig, "w").close()
os.chmod(nameFileConfig, mode)
except (OSError, Exception) as e:
if self.checkOsError(e, nameFileConfig):
return True
self.setModeError(nameFileConfig, mode, nameFileTemplate)
return False
return True
def getApplyHeadTemplate(self, nameFileTemplate, nameFileConfig,
9 years ago
templateFileType, optFile):
"""Применяет заголовок к шаблону (права, владелец, и.т. д)"""
9 years ago
def function(text):
"""Функция обработки функций в заголовке"""
9 years ago
return self.applyFuncTemplate(text, nameFileTemplate)
14 years ago
def preReturn(pathProg):
"""Действия перед выходом из метода"""
if pathProg:
os.chdir(pathProg)
self.closeFiles()
pathProg = ""
self.executeType = None
# Файлы в системе к которым были применены шаблоны
14 years ago
# В случае бинарного типа файла читаем шаблон
if templateFileType == "bin":
self.nameFileTemplate = os.path.abspath(nameFileTemplate)
14 years ago
self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
if not self.F_TEMPL:
self.setError(_("Failed to open the template") + _(": ") +
9 years ago
self.nameFileTemplate)
return [], False
self.textTemplate, ___ = try_decode_utf8(self.F_TEMPL.read())
14 years ago
self.closeTemplFile()
14 years ago
objHeadNew = fileHeader(nameFileTemplate, self.textTemplate, False,
9 years ago
templateFileType, objVar=self.objVar,
function=function, templateObj=self)
14 years ago
# файл шаблона не будет применен
if not objHeadNew.headerTerm:
14 years ago
if objHeadNew.getError():
self.setError(_("Incorrect template") + _(": ") +
9 years ago
nameFileTemplate)
return [], False
else:
self.headerParams = objHeadNew.params
# add packeges for reconfigure
self._processMergePostmerge(objHeadNew.params, nameFileTemplate)
self._processRebuild(objHeadNew.params, nameFileTemplate)
# Родительская директория
path = optFile[HParams.OptDir.Path]
# Изменяем название родительской директории
if HParams.Path in objHeadNew.params:
path = objHeadNew.params[HParams.Path]
if path and path[0] == "~":
# Получаем путь с заменой ~ на директорию пользователя
path = os.path.join(
self.homeDir, path.partition("/")[2], "")[:-1]
elif not path or path and path[0] != "/":
self.setError(
(_("Wrong value '%s' in the template") % HParams.Path) +
_(": ") + nameFileTemplate)
9 years ago
return [], False
else:
path = pathJoin(self._baseDir, path)
# Путь к оригинальному файлу - pathOldFile
# Изменяем путь к оригинальному файлу
if HParams.Name in objHeadNew.params:
nameFile = objHeadNew.params[HParams.Name]
if "/" in nameFile or nameFile == ".." or nameFile == ".":
self.setError(
(_("Wrong value '%s' in the template") % HParams.Name) +
_(": ") + nameFileTemplate)
9 years ago
return [], False
# Новый путь к оригинальному файлу
9 years ago
pathOldFile = pathJoin(path, nameFile)
else:
9 years ago
pathOldFile = pathJoin(path, os.path.split(nameFileConfig)[1])
pathOrigFile = pathOldFile
self.nameFileConfigOrig = pathOrigFile
if self.objVar.Get('cl_protect_use_set') == 'on':
pathOldFile = self.fixNameFileConfig(pathOldFile)
pathOldFile = self.checkOnNewConfigName(pathOldFile)
# буффер для использование в link=
newBuffer = None
applyFiles = [pathOldFile]
# Фильтрация шаблонов по названию файла
9 years ago
realPath = os.path.join("/", pathOldFile.partition(self._baseDir)[2])
if realPath in self.filesFilter:
9 years ago
return [], False
14 years ago
typeAppendTemplate = objHeadNew.typeAppend
9 years ago
# Параметр exec
if (HParams.RunPost in objHeadNew.params or
HParams.RunNow in objHeadNew.params):
if HParams.RunPost in objHeadNew.params:
paramName = HParams.RunPost
self.executeType = HParams.ExecuteType.Post
else:
paramName = HParams.RunNow
self.executeType = HParams.ExecuteType.Now
execPath = objHeadNew.params[paramName]
9 years ago
if not os.access(execPath, os.X_OK):
self.setError(
_("Wrong value '%s' in the template") % paramName +
_(": ") + nameFileTemplate)
self.setError(_("Failed to execute %s") % execPath)
return [], False
if typeAppendTemplate == HParams.AppendParams.Join:
8 years ago
self.setError(
8 years ago
(_("Wrong value '{var}={val}' in template").format
8 years ago
(var=HParams.Append, val=HParams.AppendParams.Join)) +
_(": ") + nameFileTemplate)
9 years ago
return [], False
# Очищаем оригинальный файл
if typeAppendTemplate == HParams.AppendParams.Clear:
try:
with open(pathOldFile, "w") as f:
f.truncate(0)
9 years ago
except IOError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to clear the file") + _(": ") +
pathOldFile)
9 years ago
return applyFiles, False
# Удаляем оригинальный файл
if typeAppendTemplate == HParams.AppendParams.Remove:
if HParams.Force in objHeadNew.params:
pathOldFile = pathOrigFile
self.configMode = T_ORIGIN
try:
if os.path.islink(pathOldFile):
# удаляем ссылку
try:
os.unlink(pathOldFile)
9 years ago
return applyFiles, False
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the link") + _(": ") +
pathOldFile)
9 years ago
return [], False
if os.path.isfile(pathOldFile) and self.configMode == T_ORIGIN:
# удаляем файл
try:
os.remove(pathOldFile)
9 years ago
return applyFiles, False
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the file") + _(": ") +
pathOldFile)
9 years ago
return [], False
finally:
9 years ago
pattern = "%s/._cfg????_%s" % (os.path.dirname(pathOrigFile),
os.path.basename(pathOrigFile))
for fn in glob.glob(pattern):
try:
os.unlink(fn)
9 years ago
except OSError:
pass
if self.functObj.currentBelong:
self.changedFiles.addObj(pathOrigFile,
ChangedFiles.FILE_REMOVED,
self.functObj.currentBelong,
self.functObj.currentBelongSlot)
9 years ago
return [], False
# Пропускаем обработку шаблона
elif typeAppendTemplate == HParams.AppendParams.Skip:
9 years ago
return [], False
# Создаем директорию для файла если ее нет
if not os.path.exists(path):
if not self.createDir(path):
9 years ago
return [], False
# создаём пустой файл если его нет для sqlite
if objHeadNew.fileType in HParams.Formats.Modificator:
try:
if not os.path.exists(pathOrigFile):
with open(pathOrigFile, "w") as f:
f.truncate(0)
except IOError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to create the file") + _(": ") +
pathOrigFile)
# В случае force
if (HParams.Force in objHeadNew.params and
objHeadNew.fileType not in HParams.Formats.Executable):
if os.path.islink(pathOldFile):
# удаляем ссылку
9 years ago
newBuffer = ""
try:
os.unlink(pathOldFile)
9 years ago
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the link") + _(": ") +
pathOldFile)
9 years ago
return [], False
if os.path.isfile(pathOldFile):
# удаляем файл
9 years ago
newBuffer = ""
try:
os.remove(pathOldFile)
9 years ago
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the file") + _(": ") +
pathOldFile)
9 years ago
return [], False
flagSymlink = False
# Если есть параметр mirror
if (HParams.Mirror in objHeadNew.params and
objHeadNew.fileType not in HParams.Formats.Executable):
if HParams.Link in objHeadNew.params:
templateFile = objHeadNew.params[HParams.Link]
if templateFile and templateFile[0] == "~":
# Получаем директорию пользователя
templateFile = os.path.join(
self.homeDir, templateFile.partition("/")[2], "")[:-1]
templateFile = pathJoin(self._baseDir, templateFile)
if (not os.path.exists(templateFile) or
not objHeadNew.params[HParams.Link]):
if os.path.exists(pathOldFile):
try:
os.remove(pathOldFile)
9 years ago
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
9 years ago
self.setError(
_("Failed to delete the file") + _(": ") +
pathOldFile)
return [], False
elif not os.path.exists(pathOldFile):
9 years ago
return [], False
# Если есть указатель на файл шаблона (link)
if (HParams.Link in objHeadNew.params and
objHeadNew.fileType not in HParams.Formats.Executable and
HParams.Symbolic not in objHeadNew.params):
templateFile = objHeadNew.params[HParams.Link]
if templateFile and templateFile[0] == "~":
# Получаем директорию пользователя
9 years ago
templateFile = os.path.join(
self.homeDir, templateFile.partition("/")[2], "")[:-1]
templateFile = pathJoin(self._baseDir, templateFile)
foundTemplateFile = os.path.exists(templateFile)
9 years ago
buff = None
fMode, fUid, fGid = None, None, None
if foundTemplateFile and objHeadNew.params[HParams.Link]:
try:
F_CONF = self.openTemplFile(templateFile)
9 years ago
if not F_CONF:
raise IOError
buff, ___ = try_decode_utf8(F_CONF.read())
F_CONF.close()
fMode, fUid, fGid = getModeFile(templateFile)
9 years ago
except (OSError, IOError):
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to open the file") + _(": ") +
templateFile)
9 years ago
return [], False
if os.path.exists(pathOldFile):
9 years ago
newBuffer = ""
try:
os.remove(pathOldFile)
9 years ago
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the file") + _(": ") +
pathOldFile)
9 years ago
return [], False
if buff is not None:
14 years ago
try:
mode = "wb+" if isinstance(buff, bytes) else "w+"
with open(pathOldFile, mode) as FD:
newBuffer = buff
FD.write(buff)
9 years ago
except IOError:
self.setError(_("Template error") + _(": ") +
14 years ago
nameFileTemplate)
9 years ago
self.setError(_("Failed to create the file") + " '%s'" \
% pathOldFile)
return [], False
oMode = getModeFile(pathOldFile, mode="mode")
14 years ago
# Если права не совпадают, меняем права
if fMode != oMode:
if not self.chmodConfFile(
pathOldFile, fMode, nameFileTemplate,
checkExists=False):
9 years ago
return [], False
# Если символическая ссылка
9 years ago
prevOldFile = None
if HParams.Symbolic in objHeadNew.params:
prevOldFile = pathOldFile
pathOldFile = objHeadNew.params[HParams.Link]
flagSymlink = True
if not pathOldFile:
raise TemplatesError(
_("Missed source link in template '%s'")
9 years ago
% str(nameFileTemplate))
if not "/" == pathOldFile[0]:
pathLink = os.path.split(os.path.abspath(prevOldFile))[0]
pathProg = os.getcwd()
try:
os.chdir(pathLink)
9 years ago
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
12 years ago
self.setError(
9 years ago
_("Failed to change the current directory to") + \
" " + pathLink)
return [], False
# chmod - изменяем права
if HParams.ChangeMode in objHeadNew.params:
mode = self.__octToInt(objHeadNew.params[HParams.ChangeMode])
if mode:
if not self.chmodConfFile(pathOldFile, mode, nameFileTemplate):
preReturn(pathProg)
9 years ago
return [], False
else:
self.setError(
(_("Wrong value '%s' in the template")
% HParams.ChangeMode) + _(": ") + nameFileTemplate)
preReturn(pathProg)
9 years ago
return [], False
# chown - изменяем владельца и группу
if HParams.ChangeOwner in objHeadNew.params:
owner = objHeadNew.params[HParams.ChangeOwner]
if owner:
9 years ago
if ":" in owner:
strUid, strGid = owner.split(":")
if strUid.isdigit():
uid = int(strUid)
else:
uid = self.getUidFromPasswd(strUid)
import pwd
9 years ago
try:
if uid is None:
uid = pwd.getpwnam(strUid).pw_uid
9 years ago
except (KeyError, TypeError):
12 years ago
self.setError(_("No such user on the system: ") +
strUid)
self.setError((_("Wrong value '%s' in the template")
% HParams.ChangeOwner) + _(": ")
+ nameFileTemplate)
preReturn(pathProg)
9 years ago
return [], False
if strGid.isdigit():
gid = int(strGid)
else:
gid = self.getGidFromGroup(strGid)
try:
if gid is None:
import grp
9 years ago
gid = grp.getgrnam(strGid).gr_gid
9 years ago
except (KeyError, TypeError):
12 years ago
self.setError(_("Group not found on the system: ") +
strGid)
self.setError((_("Wrong value '%s' in the template")
% HParams.ChangeOwner) + _(": ")
+ nameFileTemplate)
preReturn(pathProg)
9 years ago
return [], False
# Изменяем владельца файла
if not self.chownConfFile(pathOldFile, uid, gid,
nameFileTemplate):
preReturn(pathProg)
9 years ago
return [], False
else:
self.setError((_("Wrong value '%s' in the template")
% HParams.ChangeOwner) + _(": ")
+ nameFileTemplate)
preReturn(pathProg)
9 years ago
return [], False
else:
self.setError((_("Wrong value '%s' in the template")
% HParams.ChangeOwner) + _(": ")
+ nameFileTemplate)
preReturn(pathProg)
9 years ago
return [], False
if not flagSymlink:
9 years ago
self.openFiles(nameFileTemplate, pathOldFile, objHeadNew.fileType,
newBuffer)
if self.getError():
9 years ago
return [], False
if HParams.ChangeOwner not in objHeadNew.params:
14 years ago
# Устанавливаем владельцем конфигурационного файла,
# пользователя по умолчанию (переменная шаблона ur_login)
14 years ago
if os.path.exists(pathOldFile):
tUid, tGid = getModeFile(pathOldFile, mode="owner")
if (self.uid, self.gid) != (tUid, tGid):
# Изменяем владельца файла
if not self.chownConfFile(
pathOldFile, self.uid, self.gid, nameFileTemplate,
checkExists=False):
preReturn(pathProg)
9 years ago
return [], False
if flagSymlink:
if os.path.exists(prevOldFile) or os.path.islink(prevOldFile):
try:
if os.path.islink(prevOldFile):
# если ссылка то удаляем её
os.unlink(prevOldFile)
else:
# иначе удаляем файл
os.remove(prevOldFile)
9 years ago
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the file") + _(": ") +
prevOldFile)
preReturn(pathProg)
9 years ago
return [], False
if not "/" == pathOldFile[0]:
9 years ago
applyFiles = [
prevOldFile] # ,os.path.join(pathLink,pathOldFile)]
else:
9 years ago
applyFiles = [prevOldFile] # ,pathOldFile]
try:
os.symlink(pathOldFile, prevOldFile)
9 years ago
except OSError:
self.setError(_("Template error") + _(": ") + nameFileTemplate)
self.setError(_("Failed to create a symbolic link") + _(": ") +
9 years ago
"%s -> %s" % (prevOldFile, pathOldFile))
preReturn(pathProg)
9 years ago
return [], False
14 years ago
if not objHeadNew.body.strip():
preReturn(pathProg)
if HParams.Protected in objHeadNew.params:
self.protectedFiles += applyFiles
9 years ago
return applyFiles, False
else:
applyFiles = [pathOldFile]
preReturn(pathProg)
if HParams.Protected in objHeadNew.params:
self.protectedFiles += applyFiles
if ((HParams.OptDir.Autoupdate in optFile
or HParams.Autoupdate in objHeadNew.params) and
not self.objVar.Get('cl_merge_pkg_pass')):
9 years ago
reCfg = re.compile(r"/._cfg\d{4}_", re.S)
self.autoUpdateFiles += [reCfg.sub('/', x) for x in applyFiles]
if pathOldFile not in self.dictProcessedTemplates:
self.dictProcessedTemplates[pathOldFile] = []
self.dictProcessedTemplates[pathOldFile].append(nameFileTemplate)
# Если файлы заменяются не нужно их обрабатывать дальше
if (HParams.AppendParams.Replace == typeAppendTemplate and
HParams.Symbolic not in objHeadNew.params and
HParams.Link in objHeadNew.params):
return applyFiles, False
9 years ago
return applyFiles, objHeadNew
def doServiceControl(self, params):
"""
Выполнить действие над сервисом
:param params: параметры заголовка шаблонов
:return:
"""
command_action_map = {
HParams.RestartService: "restart",
HParams.StopService: "stop",
HParams.StartService: "start"
}
command_action_messages = {
8 years ago
HParams.RestartService: _("Service %s has been restarted"),
HParams.StopService: _("Service %s has been stopped"),
HParams.StartService: _("Service %s has been started")
}
command_action_error = {
HParams.RestartService: _("Failed to restart %s service"),
HParams.StopService: _("Failed to stop %s service"),
HParams.StartService: _("Failed to start %s service")
}
for param in HParams.ServiceControl:
if param in params:
service_list = (x for x in params[param].split(',') if x)
command_action = command_action_map[param]
for service in service_list:
try:
p = process("/etc/init.d/%s" % service, command_action)
if p.success():
self.printSUCCESS(
command_action_messages[param] % service)
else:
self.printERROR(
command_action_error[param] % service)
for line in p.readerr().strip().split('\n'):
self.printERROR(line)
except FilesError as e:
self.printERROR(
command_action_error[param] % service)
self.printERROR(str(e))
9 years ago
def createNewClass(self, name, bases, attrs=None):
"""Создает объект нового класса
createNewClass(self, name, bases, attrs)
name - имя класса - str,
bases - cписок наследуемых классов - (tuple),
attrs - аттрибуты класса - {dict}
"""
9 years ago
if attrs is None:
attrs = {}
class newMethod():
9 years ago
# Объединяем конфигурации
def join(self, newObj):
if newObj.__class__.__name__ == self.__class__.__name__:
9 years ago
if hasattr(self, "docObj"):
self.docObj.joinDoc(newObj.doc)
# Пост обработка
9 years ago
if hasattr(self, "postXML"):
self.postXML()
9 years ago
attrsNew = {"configName": name}
if attrs:
9 years ago
attrsNew.update(attrs)
newCl = type(name, bases + (newMethod, object,), attrsNew)
return newCl
def fileIsUtf(self, fileName, data=None):
"""Проверяет файл на кодировку UTF-8"""
if os.path.isfile(fileName):
if data is None:
with open(os.path.abspath(fileName), 'rb') as FD:
data = FD.read(1) + FD.read()
try:
if(not isinstance(data, str)):
data.decode("UTF-8")
9 years ago
except UnicodeDecodeError:
return False
return True
return False
9 years ago
def joinTemplate(self, nameFileTemplate, nameFileConfig, optFile=None):
"""Объединения шаблона и конф. файла
14 years ago
join(nameFileTemplate, nameFileConfig, ListOptTitle)
Объединение шаблона nameFileTemplate и конф. файла nameFileConfig,
ListOptTitle - список строк которые добавятся в заголовок
optFile = опции для шаблона
"""
9 years ago
if optFile is None:
optFile = {}
# Выполняем условия для блока текста а так-же заменяем переменные
14 years ago
self.nameFileTemplate = os.path.abspath(nameFileTemplate)
14 years ago
self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
origTextTemplate, file_is_unicode = try_decode_utf8(self.F_TEMPL.read())
self.textTemplate = origTextTemplate
self.configMode = T_ORIGIN
14 years ago
self.closeTemplFile()
14 years ago
# Флаг копирования шаблона в конфигурационный файл
flagCopyTemplate = True
# Тип шаблона бинарный или текстовый
if self.textTemplate[:11] == "# Calculate":
templateFileType = "text"
else:
templateFileType = self.getTemplateType()
if templateFileType == "text" and not file_is_unicode:
#go home getTemplateType, you're drunk
templateFileType = "bin"
elif templateFileType == "bin" and file_is_unicode:
#probably svg file
self.textTemplate = self.textTemplate.encode("UTF-8")
headerLine = self.getHeaderText(self.textTemplate, binary = templateFileType == "bin")
12 years ago
if headerLine:
envparam = "%s=" % HParams.Environ
moduleParam = [x for x in headerLine.split() if x.startswith(envparam)]
12 years ago
if moduleParam:
self.objVar.defaultModule = moduleParam[0].partition('=')[2]
try:
9 years ago
importlib.import_module(
"calculate.%s.variables" % self.objVar.defaultModule)
except (ImportError, AttributeError) as e:
#DEBUG
# print(e)
return []
12 years ago
if not optFile:
9 years ago
optFile = {"path": os.path.split(nameFileConfig)[0]}
filesApply, objHeadNew = self.getApplyHeadTemplate(nameFileTemplate,
9 years ago
nameFileConfig,
templateFileType,
optFile)
if not objHeadNew:
return filesApply
# if filesApply and not list(filter(lambda x: "calculate/ini.env" in x,
# filesApply)):
if filesApply and not any(["calculate/ini.env" in x for x in filesApply]):
9 years ago
self.templateModify()
if templateFileType != "bin":
# Вычисляем условные блоки
objHeadNew.body = self.applyTermsTemplate(objHeadNew.body,
nameFileTemplate)
# Заменяем переменные на их значения
objHeadNew.body = self.applyVarsTemplate(objHeadNew.body,
nameFileTemplate)
flagCopyTemplate = False
# Вычисляем функции
objHeadNew.body = self.applyFuncTemplate(objHeadNew.body,
9 years ago
nameFileTemplate)
14 years ago
# Настоящее имя конфигурационного файла
nameFileConfig = filesApply[0]
# Флаг - кодировка с бинарными примесями у файла шаблона включаем при
# условии текстового файла и кодировки отличной от UTF-8
flagNotUtf8New = False
9 years ago
# Флаг - кодировка с бинарными примесями у оригинального файла
flagNotUtf8Old = False
14 years ago
if not flagCopyTemplate:
# проверяем кодировку шаблона
if not self.fileIsUtf(nameFileTemplate, data=origTextTemplate):
flagNotUtf8New = True
if not (HParams.Link in objHeadNew.params and
HParams.Symbolic in objHeadNew.params):
# проверяем кодировку оригинального файла
14 years ago
if not self.fileIsUtf(nameFileConfig):
flagNotUtf8Old = True
14 years ago
self.textTemplate = objHeadNew.body
# Список примененных шаблонов
ListOptTitle = []
if nameFileConfig in self.dictProcessedTemplates:
ListOptTitle = self.dictProcessedTemplates[nameFileConfig]
# Титл конфигурационного файла
title = ""
if ListOptTitle:
title = self.getTitle(objHeadNew.comment, ListOptTitle,
configPath=nameFileConfig)
objHeadOld = False
if objHeadNew.comment:
14 years ago
objHeadOld = fileHeader(nameFileConfig, self.textConfig,
objHeadNew.comment)
elif (objHeadNew.fileType and
objHeadNew.typeAppend in (HParams.AppendParams.Before,
HParams.AppendParams.After)):
14 years ago
configFileType = self.getFileType(nameFileConfig)
objHeadOld = fileHeader(nameFileConfig, self.textConfig,
fileType=configFileType)
# Строка вызова скрипта (#!/bin/bash ...)
execStr = ""
if objHeadNew.execStr:
execStr = objHeadNew.execStr
14 years ago
elif objHeadOld and objHeadOld.execStr:
execStr = objHeadOld.execStr
if objHeadNew.fileType != 'patch':
wrongOpt = [x for x in (HParams.Multiline, HParams.DotAll)
if x in objHeadNew.params]
if wrongOpt:
9 years ago
self.setError(
_("Option %s should be used for format=patch only")
% wrongOpt[0])
return None
if objHeadNew.fileType != 'dconf':
wrongOpt = [x for x in (HParams.DConf,)
if x in objHeadNew.params]
if wrongOpt:
9 years ago
self.setError(
_("Option %s should be used for format=dconf only")
% wrongOpt[0])
return None
if objHeadNew.fileType != 'backgrounds':
wrongOpt = [x for x in (HParams.Convert, HParams.Stretch)
if x in objHeadNew.params]
if wrongOpt:
self.setError(
_("Option %s should be used for format=backgrounds only")
% wrongOpt[0])
return None
if objHeadNew.fileType:
14 years ago
formatTemplate = objHeadNew.fileType
typeAppendTemplate = objHeadNew.typeAppend
if formatTemplate in chain(("patch",), HParams.Formats.Executable):
if typeAppendTemplate != HParams.AppendParams.Patch:
9 years ago
self.setError(
8 years ago
_("Wrong option '%(param)s=%(type)s' "
"in template %(file)s")
% {"param": HParams.Append,
"type": typeAppendTemplate,
9 years ago
"file": nameFileTemplate})
return None
# создаем объект формата шаблона
objTempl = self.formatFactory.createObject(
formatTemplate, self.textTemplate)
if formatTemplate == 'patch':
if HParams.Multiline in objHeadNew.params:
objTempl.setMultiline()
if HParams.DotAll in objHeadNew.params:
objTempl.setDotall()
if formatTemplate == 'dconf':
if HParams.DConf in objHeadNew.params:
objTempl.setPath(objHeadNew.params[HParams.DConf])
objTempl.setUser(self.objVar.Get('ur_login'))
if formatTemplate == 'backgrounds':
root_path = self.objVar.Get('cl_chroot_path')
if root_path != '/':
objTempl.setRootPath(root_path)
if HParams.Convert in objHeadNew.params:
objTempl.setConvert(objHeadNew.params[HParams.Convert])
if HParams.Link in objHeadNew.params:
objTempl.setSource(objHeadNew.params[HParams.Link])
if HParams.Mirror in objHeadNew.params:
objTempl.setMirror()
if HParams.Stretch in objHeadNew.params:
objTempl.setStretch(True)
if (HParams.Name in objHeadNew.params and
not objHeadNew.params[HParams.Name]):
objTempl.setPrefix("")
if not objTempl:
9 years ago
self.setError(
8 years ago
_("Wrong header parameter 'format=%s' "
"in template")
9 years ago
% formatTemplate + " " + nameFileTemplate)
return None
if objHeadOld and objHeadOld.body:
self.textConfig = objHeadOld.body
# обработка конфигурационного файла
objTempl.printWARNING = self.printWARNING
self.textTemplate = objTempl.processingFile(
self.textConfig, pathJoin(self.objVar.Get('cl_chroot_path'),
self.objVar.Get('cl_root_path')),
self.nameFileConfigOrig
)
error = objTempl.getError()
if error:
self.printERROR(error.strip())
if (formatTemplate in HParams.Formats.Executable and
formatTemplate != "diff"):
raise TemplatesError(
(_("Failed to use %s ") % formatTemplate) +
nameFileTemplate)
if (self.objVar.Get('cl_ebuild_phase') == 'compile' and
self.objVar.Get('cl_template_wrong_patch') == 'break'):
raise CriticalError(_("Failed to use patch ") +
nameFileTemplate)
raise TemplatesError(_("Failed to use patch ") +
9 years ago
nameFileTemplate)
elif (formatTemplate == 'diff' and
self.objVar.Get('cl_verbose_set') == "on"):
#TODO fix transl
self.printSUCCESS(_("Appling patch") + " " +
9 years ago
os.path.basename(nameFileTemplate))
self.textConfig = self.add_comment(
execStr, title, self.textTemplate)
if formatTemplate in HParams.Formats.Executable:
return objTempl.changed_files
11 years ago
else:
self.saveConfFile()
if HParams.RunNow in objHeadNew.params:
if not self.executeTemplate(
self.textConfig, objHeadNew.params[HParams.RunNow]):
self.setError(_("Failed to execute") + _(": ") +
nameFileTemplate)
9 years ago
return None
return None
if HParams.RunPost not in objHeadNew.params:
return filesApply
else:
return None
# Создаем объект в случае параметра format в заголовке
if ((typeAppendTemplate == HParams.AppendParams.Replace or
typeAppendTemplate == HParams.AppendParams.Before or
typeAppendTemplate == HParams.AppendParams.After) and
not (formatTemplate == "bin" or formatTemplate == "raw")):
# Преобразовываем бинарные файлы
9 years ago
objTxtCoder = None
if flagNotUtf8New:
objTxtCoder = utfBin()
14 years ago
self.textTemplate = objTxtCoder.encode(self.textTemplate)
# создаем объект формата шаблона
objTemplNew = self.formatFactory.createObject(
formatTemplate, self.textTemplate)
if not objTemplNew:
8 years ago
self.setError(
8 years ago
_("Wrong header parameter '{var}={val}' "
"in template").format(
8 years ago
var=HParams.Format, val=formatTemplate)
+ " " + nameFileTemplate)
9 years ago
return None
14 years ago
if "xml_" in formatTemplate:
if objTemplNew.getError():
9 years ago
self.setError(_("Wrong template") + _(": ") +
nameFileTemplate)
9 years ago
return None
14 years ago
# Имя файла внутри xml xfce конфигурационных файлов
9 years ago
nameRootNode = \
nameFileConfig.rpartition("/")[2].split(".")[0]
objTemplNew.setNameBodyNode(nameRootNode)
# Объект Документ
docObj = objTemplNew.docObj
# Удаление комментариев из документа
docObj.removeComment(docObj.getNodeBody())
# Добавление необходимых переводов строк
docObj.insertBRtoBody(docObj.getNodeBody())
# Добавление необходимых разделителей между областями
docObj.insertBeforeSepAreas(docObj.getNodeBody())
# Пост обработка
if 'postXML' in dir(objTemplNew):
objTemplNew.postXML()
# Получение текстового файла из XML документа
self.textTemplate = objTemplNew.getConfig()
# Если не UTF-8 производим преобразование
9 years ago
if objTxtCoder:
14 years ago
self.textTemplate = objTxtCoder.decode(self.textTemplate)
# Титл для объединения
if ListOptTitle:
title = self.getTitle(objTemplNew._comment,
ListOptTitle,
configPath=nameFileConfig)
# Замена
if typeAppendTemplate == HParams.AppendParams.Replace:
14 years ago
if "xml_" in formatTemplate:
14 years ago
data = self.textTemplate.split("\n")
9 years ago
data.insert(1, title)
14 years ago
self.textConfig = "\n".join(data)
else:
self.textConfig = self.add_comment(
objHeadNew.execStr, title, self.textTemplate)
9 years ago
14 years ago
self.saveConfFile()
if HParams.RunNow in objHeadNew.params:
if not self.executeTemplate(
self.textConfig,
objHeadNew.params[HParams.RunNow]):
9 years ago
self.setError(_("Failed to execute") + _(": ") + \
nameFileTemplate)
9 years ago
return None
return None
if HParams.RunPost not in objHeadNew.params:
return filesApply
else:
return None
# Вверху
elif typeAppendTemplate == HParams.AppendParams.Before:
14 years ago
if "xml_" in formatTemplate:
9 years ago
self.setError(
8 years ago
_("Wrong option '{var}={val}' in template {fn}").format(
var=HParams.Append, val=HParams.AppendParams.Before,
fn=nameFileTemplate))
9 years ago
return None
if objHeadOld and objHeadOld.body:
14 years ago
self.textConfig = objHeadOld.body
if self.textTemplate and self.textTemplate[-1] == "\n":
14 years ago
tmpTemplate = self.textTemplate + self.textConfig
else:
14 years ago
tmpTemplate = self.textTemplate + "\n" + self.textConfig
self.textConfig = self.add_comment(execStr, title, tmpTemplate)
14 years ago
self.saveConfFile()
if HParams.RunNow in objHeadNew.params:
if not self.executeTemplate(
self.textConfig, objHeadNew.params[HParams.RunNow]):
9 years ago
self.setError(_("Failed to execute") + _(": ") +
nameFileTemplate)
9 years ago
return None
return None
if HParams.RunPost not in objHeadNew.params:
return filesApply
else:
return None
# Внизу
elif typeAppendTemplate == HParams.AppendParams.After:
14 years ago
if "xml_" in formatTemplate:
9 years ago
self.setError(
8 years ago
_("Wrong option '{var}={val}' in template {fn}").format(
var=HParams.Append, val=HParams.AppendParams.After,
fn=nameFileTemplate))
9 years ago
return None
if objHeadOld and objHeadOld.body:
14 years ago
self.textConfig = objHeadOld.body
if not self.textTemplate or self.textTemplate[-1] == "\n":
14 years ago
tmpTemplate = self.textConfig + self.textTemplate
else:
14 years ago
tmpTemplate = self.textConfig + "\n" + self.textTemplate
self.textConfig = self.add_comment(execStr, title, tmpTemplate)
14 years ago
self.saveConfFile()
if HParams.RunNow in objHeadNew.params:
if not self.executeTemplate(
self.textConfig, objHeadNew.params[HParams.RunNow]):
9 years ago
self.setError(_("Failed to execute") + _(": ") +
nameFileTemplate)
9 years ago
return None
return None
if HParams.RunPost not in objHeadNew.params:
return filesApply
else:
return None
# Объединение
elif typeAppendTemplate == HParams.AppendParams.Join:
9 years ago
objTxtCoder = None
if flagNotUtf8New:
objTxtCoder = utfBin()
14 years ago
self.textTemplate = objTxtCoder.encode(self.textTemplate)
9 years ago
if formatTemplate == "raw":
self.setError(
8 years ago
_("Wrong header parameter '{var}={val}' "
"in template").format(var=HParams.Append,
8 years ago
val=typeAppendTemplate) +
" " + nameFileTemplate)
9 years ago
return None
# создаем объект формата шаблона
objTemplNew = self.formatFactory.createObject(
formatTemplate, self.textTemplate)
if not objTemplNew:
9 years ago
self.setError(
8 years ago
_("Wrong header parameter '{var}={val}' in "
"template").format(var=HParams.Format,
8 years ago
val=formatTemplate) + " "
+ nameFileTemplate)
9 years ago
return None
14 years ago
if "xml_" in formatTemplate:
if objTemplNew.getError():
9 years ago
self.setError(_("Wrong template") + _(": ") + \
nameFileTemplate)
return None
nameRootNode = nameFileConfig.rpartition("/")[2].split(".")[0]
objTemplNew.setNameBodyNode(nameRootNode)
# Титл для объединения
if ListOptTitle:
title = self.getTitle(objTemplNew._comment,
ListOptTitle,
configPath=nameFileConfig)
# В случае пустого конфигурационного файла
reNoClean = re.compile("[^\s]", re.M)
9 years ago
if not self.textConfig or \
not reNoClean.search(self.textConfig):
14 years ago
self.textConfig = ""
14 years ago
objHeadOld = fileHeader(nameFileConfig, self.textConfig,
objTemplNew._comment)
if objHeadOld.body:
14 years ago
self.textConfig = objHeadOld.body
else:
14 years ago
self.textConfig = ""
if flagNotUtf8Old:
objTxtCoder = utfBin()
14 years ago
self.textConfig = objTxtCoder.encode(self.textConfig)
# создаем объект формата шаблона для конфигурационного файла
objTemplOld = self.formatFactory.createObject(
formatTemplate, self.textConfig)
if not objTemplOld:
9 years ago
self.setError(_("Error in template %s") % nameFileConfig)
return None
14 years ago
if "xml_" in formatTemplate:
if objTemplOld.getError():
9 years ago
self.setError(_("Wrong template") + _(": ") +
nameFileConfig)
return None
nameRootNode = nameFileConfig.rpartition("/")[2].split(".")[
0]
objTemplOld.setNameBodyNode(nameRootNode)
objTemplOld.join(objTemplNew)
14 years ago
if "xml_" in formatTemplate:
if objTemplOld.getError():
9 years ago
self.setError(_("Wrong template") + _(": ") + \
nameFileTemplate)
return None
data = objTemplOld.getConfig().split("\n")
9 years ago
data.insert(1, title)
14 years ago
self.textConfig = "\n".join(data)
else:
self.textConfig = self.add_comment(
execStr, title, objTemplOld.getConfig())
# Декодируем если кодировка не UTF-8
9 years ago
if objTxtCoder:
14 years ago
self.textTemplate = objTxtCoder.decode(self.textTemplate)
self.textConfig = objTxtCoder.decode(self.textConfig)
self.saveConfFile()
if HParams.RunNow in objHeadNew.params:
if not self.executeTemplate(
self.textConfig, objHeadNew.params[HParams.RunNow]):
9 years ago
self.setError(_("Failed to execute") + _(": ") + \
nameFileTemplate)
9 years ago
return None
return None
if HParams.RunPost not in objHeadNew.params:
return filesApply
else:
return None
else:
self.setError(_("Wrong template option (type append)")
9 years ago
+ _(": ") + typeAppendTemplate)
return None
else:
12 years ago
self.setError(_("Template type not found: ") + nameFileTemplate)
9 years ago
return None
def add_comment(self, execStr, comment, body):
"""
Сформировать выходной файл с учётом строки выполнения, комментария и
содержимого конфига
:param execStr:
:param comment:
:param body:
:return:
"""
if len(execStr) == 0 and len(comment) == 0:
return body
if comment.startswith("<!--") and body.startswith('<?xml'):
header, body = body.partition("\n")[::2]
body = header + "\n" + comment + body
else:
body = comment + body
if execStr:
if isinstance(body, bytes):
execStr = execStr.encode("UTF-8")
return execStr + body
return body
9 years ago
class scanDirectoryClt(_error):
"""Класс для cканирования директорий с файлами .clt"""
# Расширение файла шаблона
extFileTemplate = ".clt"
lenExtFileTemplate = len(extFileTemplate)
9 years ago
filterApplyTemplates = {}
reHeader = re.compile(r"\s*#\s*calculate\s*", re.I)
critical = False
def printWARNING(self, s):
raise NotImplemented()
9 years ago
def __init__(self, objVar=None):
12 years ago
if objVar:
self.objVar = objVar
9 years ago
def processingFile(self, path, prefix, optFile=None):
"""Обработка в случае файла"""
return True
9 years ago
def hasBelong(self, filename):
"""
Change belong function
"""
with open(filename, 'r') as f:
s = f.readline()
if self.reHeader.search(s):
while s:
if "belong(" in s or "merge(" in s:
return True
if not s.strip().endswith('\\'):
break
s = f.readline()
return False
12 years ago
def scanningTemplates(self, scanDir, prefix=None, flagDir=False,
9 years ago
objVar=None):
"""Сканирование и обработка шаблонов в директории scanDir (CLT)"""
12 years ago
if not objVar:
objVar = self.objVar
if not prefix:
prefix = os.path.realpath(scanDir)
if flagDir or stat.S_ISDIR(os.lstat(str(scanDir))[stat.ST_MODE]):
for fileOrDir in sorted(listDirectory(scanDir)):
try:
absPath = os.path.join(scanDir, fileOrDir)
stInfo = os.lstat(str(absPath))
statInfo = stInfo[stat.ST_MODE]
if fileOrDir.endswith(self.extFileTemplate) and \
stat.S_ISREG(statInfo):
if (not self.filterApplyTemplates and
objVar.Get('cl_merge_set') == 'off' or
self.filterApplyTemplates and
absPath[:-self.lenExtFileTemplate] in
self.filterApplyTemplates.keys() or
self.hasBelong(absPath)):
prevDefault = objVar.defaultModule
if not self.processingFile(absPath, prefix):
return False
objVar.defaultModule = prevDefault
elif stat.S_ISDIR(statInfo):
if not self.scanningTemplates(absPath, prefix, True):
11 years ago
return False
except TemplatesError as e:
self.clearErrors()
if self.critical:
raise
else:
self.printWARNING(str(e))
return True
9 years ago
class templateClt(scanDirectoryClt, Template):
"""Класс для обработки шаблонов c расширением .clt"""
def __init__(self, objVar, postmergePkgs, **kwargs):
self.checkNumberTemplate = True
9 years ago
Template.__init__(self, objVar, cltObj=False, **kwargs)
self.postmergePkgs = postmergePkgs
12 years ago
applyPackages = ["calculate-core"]
self.flagApplyTemplates = False
if self.objVar.Get("cl_name") in applyPackages:
self.flagApplyTemplates = True
# Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
self._chrootDir = os.path.normpath(self.objVar.Get("cl_chroot_path"))
14 years ago
def applyTemplate(self, path):
"""Применение отдельного .clt шаблона"""
if not self.flagApplyTemplates:
return True
14 years ago
return self.processingFile(path, "")
14 years ago
9 years ago
def processingFile(self, path, prefix, optFile=None):
"""Обработка в случае шаблона файла clt"""
self.numberProcessTempl += 1
self.numberProcessTemplates(self.numberProcessTempl)
# Пропуск шаблонов директорий scanningTemplates
if self.templDirNameFile == os.path.split(path)[1]:
return True
self.functObj.currentBelong = ""
self.functObj.currentBelongSlot = ""
# Проверка на переменные в названии файла
if not self.getNeedTemplate(path):
if self.getError():
return False
return True
if self.getError():
return False
if prefix and prefix[-1] == "/":
prefix = prefix[:-1]
if prefix and path.startswith(prefix):
nameFileConfig = path.partition(prefix)[2]
else:
nameFileConfig = path
nameFileConfig = nameFileConfig[:-self.lenExtFileTemplate]
origFileName = nameFileConfig
nameFileConfig = pathJoin(self._baseDir, nameFileConfig)
# файл в системе без условий
nameFileConfig = "/".join((x.split("?")[0] for x in nameFileConfig.split("/")))
# Записываем в переменную обрабатываемый файл
self.objVar.Set("cl_pass_file", os.path.basename(nameFileConfig))
self.headerParams = None
filesApl = self.joinTemplate(path, nameFileConfig)
if self.headerParams:
if has_any(self.headerParams, HParams.ServiceControl):
self.doServiceControl(self.headerParams)
if self.getError():
return False
if filesApl:
if self.functObj.currentBelong:
self._addFile(filesApl)
else:
if origFileName in self.filterApplyTemplates:
for pkg in self.filterApplyTemplates[origFileName]:
9 years ago
self._addFile(filesApl, pkg=pkg)
else:
if not self.allContents:
fillContents(self.allContents,
9 years ago
self.objVar.Get('cl_config_protect'),
prefix=self.objVar.Get('cl_chroot_path'))
for fn in filesApl:
9 years ago
fn_orig = PkgContents.reCfg.sub('/', fn)
if self.objVar.Get('cl_chroot_path') != '/':
fn_orig = \
fn_orig[len(self.objVar.Get('cl_chroot_path')):]
if fn_orig in self.allContents:
9 years ago
self._addFile([fn], pkg=self.allContents[fn_orig])
14 years ago
# Настоящее имя конфигурационного файла
nameFileConfig = filesApl[0]
# Пишем время модификации *.env файлов
14 years ago
if nameFileConfig.endswith(".env"):
nameEnvFile = os.path.basename(nameFileConfig)
self.functObj.timeConfigsIni[nameEnvFile] = float(time.time())
self.filesApply += filesApl
return nameFileConfig
else:
return True
9 years ago
def countsNumberTemplates(self, dirsTemplates=()):
"""Считаем количество шаблонов"""
9 years ago
def createDictTemplates(path, prefix, dictTemplates):
"""Создает словарь {"директория":"кол-во шаблонов" ...}
и считает общее количество шаблонов
"""
# Количество шаблонов
self.allTemplates += 1
dirTemplate = os.path.split(path)[0]
9 years ago
while True:
if dirTemplate in dictTemplates.keys():
dictTemplates[dirTemplate] += 1
else:
dictTemplates[dirTemplate] = 1
if dirTemplate == prefix:
break
dirTemplate = os.path.split(dirTemplate)[0]
return dictTemplates
if not dirsTemplates:
dirsTemplates = list(self.objVar.Get("cl_template_clt_path"))
dirsTemplates.sort()
12 years ago
scanObj = scanDirectoryClt(objVar=self.objVar)
9 years ago
scanObj.processingFile = lambda x, y: createDictTemplates(x, y,
self.dictTemplates)
# Считаем количество шаблонов
for dirTemplate in dirsTemplates:
scanObj.scanningTemplates(dirTemplate, "/")
9 years ago
def applyTemplatesClt(self, cltPath=None):
"""Применяет шаблоны к конфигурационным файлам"""
if not self.flagApplyTemplates:
9 years ago
return [], []
if cltPath is None and \
9 years ago
not self.objVar.defined("cl_template_clt_path"):
12 years ago
self.setError(_("undefined variable: ") + "cl_template_clt_path")
return False
if cltPath is None:
dirsTemplates = self.objVar.Get("cl_template_clt_path")
else:
dirsTemplates = cltPath
dirsTemplates = list(dirsTemplates)
dirsTemplates.sort()
if self.checkNumberTemplate:
# Созданные директории
self.createdDirs = []
# Примененные файлы
self.filesApply = []
# Номер применяемог шаблона
self.numberProcessTempl = 0
# Словарь директорий с количеством файлов шаблонов
self.dictTemplates = {}
# Количество шаблонов
self.allTemplates = 0
# Установка по умолчанию аттрибутов для функциии шаблонов ini()
# Время доступа к конфигурационному файлу функции шаблона ini()
self.functObj.timeIni = -1
# Первоначальный словарь переменных для ini()
self.functObj.prevDictIni = {}
# Текущий словарь переменных для ini()
self.functObj.currDictIni = {}
# Словарь времен модификации env файлов для ini()
self.functObj.timeConfigsIni = {}
# Считаем количество шаблонов
self.countsNumberTemplates(dirsTemplates=dirsTemplates)
self.numberAllTemplates(self.allTemplates)
12 years ago
# default module
self.defaultModule = "main"
# Обрабатываем шаблоны
for dirTemplate in dirsTemplates:
if self.scanningTemplates(dirTemplate, self._chrootDir) is False:
11 years ago
break
9 years ago
return self.createdDirs, self.filesApply
class ProgressTemplate(Template):
"""
Progress template for wsdl interface
"""
9 years ago
def __init__(self, setValueCallback, *args, **kwargs):
Template.__init__(self, *args, **kwargs)
self.setValueCallback = setValueCallback
self.value = None
12 years ago
self.firstValue = True
def numberAllTemplates(self, number):
self.maximum = number
return True
9 years ago
def numberProcessTemplates(self, number):
maximum = self.maximum or 1
value = number * 100 // maximum
if value != self.value:
9 years ago
self.setValueCallback(min(100, max(0, value)))
self.value = value
return True
12 years ago
11 years ago
def templateModify(self):
if self.firstValue and hasattr(self, "onFirstValue"):
12 years ago
self.onFirstValue()
self.firstValue = False