|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
# Copyright 2008-2015 Calculate Ltd. 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 calculate.lib.cl_xml import xmlShare
|
|
|
|
|
import types
|
|
|
|
|
import random
|
|
|
|
|
import string
|
|
|
|
|
import time
|
|
|
|
|
import glob
|
|
|
|
|
import hashlib
|
|
|
|
|
from fnmatch import fnmatch
|
|
|
|
|
from math import sqrt
|
|
|
|
|
from itertools import *
|
|
|
|
|
from collections import OrderedDict
|
|
|
|
|
from operator import lt, le, eq, ne, ge, gt
|
|
|
|
|
|
|
|
|
|
from utils.common import _error, _warning, getTupleVersion, getPortageUidGid
|
|
|
|
|
from utils.text import _u
|
|
|
|
|
from utils.portage import (isPkgInstalled, reVerSplitToPV, EmergeLog,
|
|
|
|
|
EmergeLogPackageTask, getPkgUses)
|
|
|
|
|
from utils.content import PkgContents, checkContents, getCfgFiles, fillContents
|
|
|
|
|
from utils.files import (getModeFile, listDirectory, removeDir, typeFile,
|
|
|
|
|
scanDirectory,
|
|
|
|
|
pathJoin, readFile, readLinesFile, process)
|
|
|
|
|
from datavars import DataVarsError
|
|
|
|
|
from calculate.lib.configparser import ConfigParser, NoSectionError
|
|
|
|
|
|
|
|
|
|
from calculate.lib.cl_lang import setLocalTranslate, RegexpLocalization
|
|
|
|
|
|
|
|
|
|
_ = lambda x: x
|
|
|
|
|
setLocalTranslate('cl_lib3', sys.modules[__name__])
|
|
|
|
|
|
|
|
|
|
PORTAGEUID, PORTAGEGID = getPortageUidGid()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TemplatesError(Exception):
|
|
|
|
|
"""
|
|
|
|
|
Error on templates appling
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def catch_no_space_left(f):
|
|
|
|
|
def wrapper(*args, **kw):
|
|
|
|
|
try:
|
|
|
|
|
return f(*args, **kw)
|
|
|
|
|
except IOError as e:
|
|
|
|
|
if e.errno == 28:
|
|
|
|
|
raise TemplatesError(_("No space left on device"))
|
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
return wrapper
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _shareTermsFunction(object):
|
|
|
|
|
"""Общие аттрибуты для классов _terms и templateFunctions"""
|
|
|
|
|
# Символы допустимые в скобках функции шаблона
|
|
|
|
|
_reFunctionArgvInSquareBrackets = ("a-zA-Z0-9_:;<>=\!\|\{\}\^\$\?\(\)\[\]\-"
|
|
|
|
|
"\+\,\*\/\.\'\"~\\\\ ")
|
|
|
|
|
_reFunctionArgvText = "[%s]" % _reFunctionArgvInSquareBrackets
|
|
|
|
|
# регулярное выражение для поиска функции в шаблоне
|
|
|
|
|
_reFunctionText = "([a-zA-Z0-9\_\-]+)\((%s+|)\)" % _reFunctionArgvText
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _terms(_error, _shareTermsFunction):
|
|
|
|
|
"""Вычисление условий применяемых в шаблонах
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
# регулярное выражение для поиска функции в шаблоне
|
|
|
|
|
_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)
|
|
|
|
|
|
|
|
|
|
# использует из других объектов
|
|
|
|
|
objVar = None
|
|
|
|
|
|
|
|
|
|
def _splitVersion(self, strVersion):
|
|
|
|
|
"""
|
|
|
|
|
Split version. Version, addition letter, list suffixes with version,
|
|
|
|
|
revision.
|
|
|
|
|
Examples:
|
|
|
|
|
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 = filter(lambda x: suffix.startswith(x),
|
|
|
|
|
self._suffixDict.keys())
|
|
|
|
|
if suffSplList:
|
|
|
|
|
suffSpl = suffSplList[0]
|
|
|
|
|
lenSuffSpl = len(suffSpl)
|
|
|
|
|
suffixVersion = suffix[lenSuffSpl:]
|
|
|
|
|
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 _notVersion(self, strVersion):
|
|
|
|
|
"""strVersion is not version - True"""
|
|
|
|
|
numberVersion, letters, suffixes, rVersion = \
|
|
|
|
|
self._splitVersion(strVersion)
|
|
|
|
|
if not numberVersion.strip():
|
|
|
|
|
return True
|
|
|
|
|
if self._re_not_Version.search(numberVersion):
|
|
|
|
|
return True
|
|
|
|
|
if letters and not letters in self._letters:
|
|
|
|
|
return True
|
|
|
|
|
for suffix, suffixVersion in suffixes:
|
|
|
|
|
if suffixVersion and self._re_not_Number.search(suffixVersion):
|
|
|
|
|
return True
|
|
|
|
|
if rVersion:
|
|
|
|
|
if rVersion[0] != "r" or len(rVersion) == 1:
|
|
|
|
|
return True
|
|
|
|
|
if self._re_not_Number.search(rVersion[1:]):
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def _convertVers(self, verA, verB):
|
|
|
|
|
"""Конвертирование номеров версий для корректного сравнения
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def fillZero(elemA, elemB):
|
|
|
|
|
# elemA, elemB = elemA[], elemB[]
|
|
|
|
|
if len(elemA) > len(elemB):
|
|
|
|
|
maxElemB = len(elemB) - 1
|
|
|
|
|
for i in range(len(elemA)):
|
|
|
|
|
if i > maxElemB:
|
|
|
|
|
elemB.append("0")
|
|
|
|
|
else:
|
|
|
|
|
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]
|
|
|
|
|
|
|
|
|
|
def fillSuffix(elemA, elemB, sA, svA, sB, svB):
|
|
|
|
|
if str(sA) or str(sB):
|
|
|
|
|
svA, svB = map(lambda x: [x] if x else ['0'], (svA, svB))
|
|
|
|
|
fillZero(svA, svB)
|
|
|
|
|
sA, sB = map(lambda x: x if x else 0, (sA, sB))
|
|
|
|
|
elemA.append(str(self._lenSuffixDict + sA))
|
|
|
|
|
elemA.extend(svA)
|
|
|
|
|
elemB.append(str(self._lenSuffixDict + sB))
|
|
|
|
|
elemB.extend(svB)
|
|
|
|
|
|
|
|
|
|
# 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 = map(lambda x: x if x else '0', (lA, lB))
|
|
|
|
|
elemA.append(lA)
|
|
|
|
|
elemB.append(lB)
|
|
|
|
|
|
|
|
|
|
# dereferencing suffix in suffixes list
|
|
|
|
|
ssA = map(lambda x: (self._suffixDict.get(x[0], 0), x[1]), ssA)
|
|
|
|
|
ssB = map(lambda x: (self._suffixDict.get(x[0], 0), x[1]), ssB)
|
|
|
|
|
for suffix, sufVer in reversed(ssA):
|
|
|
|
|
if ssB:
|
|
|
|
|
sB, svB = ssB.pop()
|
|
|
|
|
else:
|
|
|
|
|
sB, svB = "", ""
|
|
|
|
|
fillSuffix(elemA, elemB, suffix, sufVer, sB, svB)
|
|
|
|
|
while ssB:
|
|
|
|
|
sB, svB = ssB.pop()
|
|
|
|
|
fillSuffix(elemA, elemB, "", "", sB, svB)
|
|
|
|
|
|
|
|
|
|
if rvA or rvB:
|
|
|
|
|
rvA, rvB = map(lambda x: [x[1:]], (rvA, rvB))
|
|
|
|
|
fillZero(rvA, rvB)
|
|
|
|
|
elemA += rvA
|
|
|
|
|
elemB += rvB
|
|
|
|
|
return ".".join(elemA), ".".join(elemB)
|
|
|
|
|
|
|
|
|
|
def _equalTerm(self, term, textError, function=None):
|
|
|
|
|
"""Вычисление логических выражений для условий
|
|
|
|
|
|
|
|
|
|
Для корректной работы в классе который наследует этот класс
|
|
|
|
|
должен быть объявлен аттрибут self.objVar
|
|
|
|
|
(объект для работы с переменными)
|
|
|
|
|
function - функция для для обработки функций в заголовке блока
|
|
|
|
|
"""
|
|
|
|
|
rpl = lambda x: x.replace("@@", " ")
|
|
|
|
|
trm = {"&&": "@@and@@", "||": "@@or@@"}
|
|
|
|
|
dictRuleFunc = OrderedDict((("==", eq), ("!=", ne),
|
|
|
|
|
(">=", ge), ("<=", le),
|
|
|
|
|
(">", gt), ("<", lt)))
|
|
|
|
|
rule = dictRuleFunc.keys()
|
|
|
|
|
listEqual = []
|
|
|
|
|
for k in trm.keys():
|
|
|
|
|
if k in term:
|
|
|
|
|
term = term.replace(k, trm[k])
|
|
|
|
|
trs = term.split("@@")
|
|
|
|
|
listSplitOr = []
|
|
|
|
|
if "or" in trs:
|
|
|
|
|
lst = []
|
|
|
|
|
for t in trs:
|
|
|
|
|
if t != "or":
|
|
|
|
|
lst.append(t)
|
|
|
|
|
else:
|
|
|
|
|
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("\\"):
|
|
|
|
|
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)
|
|
|
|
|
if flagRule:
|
|
|
|
|
# проверка на допустимость названия переменной
|
|
|
|
|
flagFunction = False
|
|
|
|
|
if not self._reRightName.search(vals[0]):
|
|
|
|
|
# проверка на допустимость функции
|
|
|
|
|
flagError = True
|
|
|
|
|
if callable(function):
|
|
|
|
|
searchFunct = self._reFunction.search(vals[0])
|
|
|
|
|
if searchFunct:
|
|
|
|
|
flagError = False
|
|
|
|
|
flagFunction = True
|
|
|
|
|
if flagError:
|
|
|
|
|
self.setError(
|
|
|
|
|
"'%s'" % rpl(term) + " " + _("incorrect"))
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
# проверка на допустимость значения
|
|
|
|
|
if self._reDenyValue.search(vals[1]):
|
|
|
|
|
self.setError("'%s'" % rpl(term) + " " + _("incorrect"))
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
flagIntTypeVar = None
|
|
|
|
|
if flagFunction and callable(function):
|
|
|
|
|
valVars = function("#-%s-#" % vals[0])
|
|
|
|
|
if valVars is False:
|
|
|
|
|
self.setError(
|
|
|
|
|
"'%s'" % rpl(term) + " " + _("incorrect"))
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
if "load" == searchFunct.group(1) and \
|
|
|
|
|
re.search("\(\s*num\s*,", vals[0]):
|
|
|
|
|
if valVars:
|
|
|
|
|
try:
|
|
|
|
|
valVars = int(valVars)
|
|
|
|
|
except ValueError:
|
|
|
|
|
self.setError("'%s'" % rpl(term) + " " +
|
|
|
|
|
_("incorrect"))
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
flagIntTypeVar = True
|
|
|
|
|
else:
|
|
|
|
|
flagIntTypeVar = False
|
|
|
|
|
else:
|
|
|
|
|
if valVars == "" and \
|
|
|
|
|
not self._notVersion(vals[1]):
|
|
|
|
|
valVars = "0"
|
|
|
|
|
elif vals[1] == "" and \
|
|
|
|
|
not self._notVersion(valVars):
|
|
|
|
|
vals[1] = "0"
|
|
|
|
|
else:
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
|
|
valVars = self.objVar.Get(vals[0])
|
|
|
|
|
varTable = self.objVar.Get('cl_used_action')
|
|
|
|
|
varTable.append((vals[0], vals[1]))
|
|
|
|
|
if not valVars:
|
|
|
|
|
valVars = ""
|
|
|
|
|
except DataVarsError, e:
|
|
|
|
|
raise TemplatesError("{header}\n{body}".format(
|
|
|
|
|
header=textError, body=str(e)))
|
|
|
|
|
# Номера версий для ini
|
|
|
|
|
flagNotIniFunct = True
|
|
|
|
|
# Два значения не пусты
|
|
|
|
|
flagNotEmptyVals = not (valVars == "" and vals[1] == "")
|
|
|
|
|
if flagFunction and flagNotEmptyVals and \
|
|
|
|
|
searchFunct.group(1) == "ini":
|
|
|
|
|
# Проверка значения на версию
|
|
|
|
|
if not self._notVersion(valVars) and \
|
|
|
|
|
not self._notVersion(vals[1]):
|
|
|
|
|
verFile, verVar = self._convertVers(vals[1],
|
|
|
|
|
valVars)
|
|
|
|
|
res = dictRuleFunc[sepF](verVar, verFile)
|
|
|
|
|
if res:
|
|
|
|
|
listEqual.append(True)
|
|
|
|
|
else:
|
|
|
|
|
listEqual.append(False)
|
|
|
|
|
break
|
|
|
|
|
flagNotIniFunct = False
|
|
|
|
|
# Cравниваем номера версий
|
|
|
|
|
if flagNotIniFunct:
|
|
|
|
|
if flagNotEmptyVals and \
|
|
|
|
|
("_ver" in vals[0] or
|
|
|
|
|
(flagFunction and searchFunct.group(
|
|
|
|
|
1) in
|
|
|
|
|
("pkg", "merge")) or
|
|
|
|
|
(flagFunction and searchFunct.group(
|
|
|
|
|
1) == "load" and
|
|
|
|
|
re.search("\(\s*ver\s*,",
|
|
|
|
|
vals[0]))):
|
|
|
|
|
# Проверка значения на версию
|
|
|
|
|
if self._notVersion(vals[1]):
|
|
|
|
|
self.setError("'%s'" % rpl(term) + " " + \
|
|
|
|
|
_("incorrect"))
|
|
|
|
|
self.setError(
|
|
|
|
|
_("This value is not a version"))
|
|
|
|
|
return False
|
|
|
|
|
# Проверка значения функции на версию
|
|
|
|
|
if self._notVersion(valVars):
|
|
|
|
|
self.setError("'%s'" % rpl(term) + " " + \
|
|
|
|
|
_("incorrect"))
|
|
|
|
|
self.setError(
|
|
|
|
|
_("The function value is not a version"))
|
|
|
|
|
return False
|
|
|
|
|
verFile, verVar = self._convertVers(vals[1],
|
|
|
|
|
valVars)
|
|
|
|
|
res = dictRuleFunc[sepF](verVar, verFile)
|
|
|
|
|
if res:
|
|
|
|
|
listEqual.append(True)
|
|
|
|
|
else:
|
|
|
|
|
listEqual.append(False)
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
if flagIntTypeVar is None:
|
|
|
|
|
flagIntTypeVar = True
|
|
|
|
|
try:
|
|
|
|
|
valVars = int(valVars)
|
|
|
|
|
except ValueError:
|
|
|
|
|
flagIntTypeVar = False
|
|
|
|
|
if flagIntTypeVar:
|
|
|
|
|
if not vals[1].strip():
|
|
|
|
|
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
|
|
|
|
|
except ValueError:
|
|
|
|
|
flagIntTypeVar = False
|
|
|
|
|
if not flagIntTypeVar:
|
|
|
|
|
if sepF == "!=" or sepF == "==":
|
|
|
|
|
if not vals[1].strip():
|
|
|
|
|
vals[1] = ""
|
|
|
|
|
valFile = vals[1]
|
|
|
|
|
valVar = valVars
|
|
|
|
|
res = dictRuleFunc[sepF](valVar, valFile)
|
|
|
|
|
if res:
|
|
|
|
|
listEqual.append(True)
|
|
|
|
|
else:
|
|
|
|
|
listEqual.append(False)
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
if not flagNotEmptyVals:
|
|
|
|
|
listEqual.append(False)
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
self.setError("'%s'" % rpl(term) + " " \
|
|
|
|
|
+ _("incorrect"))
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
if t == "and":
|
|
|
|
|
if listEqual == [] or False in listEqual:
|
|
|
|
|
listEqual = [False]
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
listEqual = [True]
|
|
|
|
|
else:
|
|
|
|
|
self.setError("'%s'" % rpl(term) + " " + _("incorrect"))
|
|
|
|
|
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):
|
|
|
|
|
"""
|
|
|
|
|
Split params line
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def splitQuote(listPar, quoteSymbol):
|
|
|
|
|
listTerm = map(lambda x: x + quoteSymbol, ("=", ">", "<"))
|
|
|
|
|
flagQ = False
|
|
|
|
|
mass = []
|
|
|
|
|
v = ""
|
|
|
|
|
for i in listPar:
|
|
|
|
|
if i.count(quoteSymbol) == 1:
|
|
|
|
|
if flagQ and i.endswith(quoteSymbol):
|
|
|
|
|
v = v + " " + i
|
|
|
|
|
mass.append(v)
|
|
|
|
|
v = ""
|
|
|
|
|
flagQ = False
|
|
|
|
|
elif filter(lambda x: x in i, listTerm):
|
|
|
|
|
flagQ = True
|
|
|
|
|
v = i
|
|
|
|
|
else:
|
|
|
|
|
mass.append(i)
|
|
|
|
|
elif flagQ:
|
|
|
|
|
v = v + " " + i
|
|
|
|
|
else:
|
|
|
|
|
mass.append(i)
|
|
|
|
|
foundPar = list(set(mass) - set(listPar))
|
|
|
|
|
return not flagQ, filter(lambda x: not x in foundPar,
|
|
|
|
|
mass), foundPar
|
|
|
|
|
|
|
|
|
|
listPar = re.split("\s+", linePar)
|
|
|
|
|
flagFoundQ = "'" in linePar
|
|
|
|
|
flagFoundQQ = '"' in linePar
|
|
|
|
|
if flagFoundQ and flagFoundQQ:
|
|
|
|
|
flagQ, listSplQPar, listFoundQPar = splitQuote(listPar, "'")
|
|
|
|
|
if flagQ:
|
|
|
|
|
flagQQ, listSplQQPar, listFoundQQPar = splitQuote(listSplQPar,
|
|
|
|
|
'"')
|
|
|
|
|
if flagQQ:
|
|
|
|
|
listPar = listSplQQPar + listFoundQPar + listFoundQQPar
|
|
|
|
|
elif flagFoundQQ:
|
|
|
|
|
flagQQ, listSplQQPar, listFoundQQPar = splitQuote(listPar, '"')
|
|
|
|
|
if flagQQ:
|
|
|
|
|
listPar = listSplQQPar + listFoundQQPar
|
|
|
|
|
elif flagFoundQ:
|
|
|
|
|
flagQ, listSplQPar, listFoundQPar = splitQuote(listPar, "'")
|
|
|
|
|
if flagQ:
|
|
|
|
|
listPar = listSplQPar + listFoundQPar
|
|
|
|
|
if flagFoundQ:
|
|
|
|
|
listQPar = []
|
|
|
|
|
for par in listPar:
|
|
|
|
|
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:
|
|
|
|
|
if par.endswith('"') and par.count('"') > 1:
|
|
|
|
|
listQQPar.append(par[:-1].replace('="', '='))
|
|
|
|
|
else:
|
|
|
|
|
listQQPar.append(par)
|
|
|
|
|
listPar = listQQPar
|
|
|
|
|
return listPar
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class fileHeader(_terms):
|
|
|
|
|
"""Обработка заголовков шаблонов и конфигурационных файлов
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
# Допустимые параметры заголовка
|
|
|
|
|
allowParam = ["format", "dotall", "multiline",
|
|
|
|
|
"comment", "append", "force", "dconf",
|
|
|
|
|
"link", "mirror", "symbolic", "chmod", "chown", "name",
|
|
|
|
|
"path", "autoupdate", "protected", "run", "exec", "merge",
|
|
|
|
|
"module", "env", "postmerge"]
|
|
|
|
|
|
|
|
|
|
# Тип шаблона
|
|
|
|
|
fileType = ""
|
|
|
|
|
# Тип вставки шаблона
|
|
|
|
|
typeAppend = ""
|
|
|
|
|
# Возможные типы вставки шаблонов
|
|
|
|
|
_fileAppend = "join", "before", "after", "replace", "remove", "skip", \
|
|
|
|
|
"patch", "clear"
|
|
|
|
|
# Интерпретатор (#!/bin/bash) (#!/usr/bin/python)
|
|
|
|
|
execStr = ""
|
|
|
|
|
# Символ комментария
|
|
|
|
|
comment = False
|
|
|
|
|
# Выражение для поиска строки интерпретатора
|
|
|
|
|
reExecStr = re.compile("^(#!.+\s)", re.M)
|
|
|
|
|
# условные операторы
|
|
|
|
|
terms = ('>', '<', '==', '!=', '>=', '<=')
|
|
|
|
|
# параметры без значения
|
|
|
|
|
listParNotVal = ("multiline", "dotall", "symbolic", "force", "mirror",
|
|
|
|
|
"autoupdate", "protected")
|
|
|
|
|
# Результат вычисления условия в заголовке
|
|
|
|
|
headerTerm = True
|
|
|
|
|
|
|
|
|
|
def __init__(self, templateName, text, comment=None, fileType=False,
|
|
|
|
|
objVar=False, function=None, templateObj=None):
|
|
|
|
|
self.body = text
|
|
|
|
|
# Объект с переменными
|
|
|
|
|
self.objVar = objVar
|
|
|
|
|
# Параметры описанные в заголовке файла шаблона
|
|
|
|
|
self.params = {}
|
|
|
|
|
# некорректные параметры
|
|
|
|
|
incorrectParams = []
|
|
|
|
|
# Поиск строки запустка (#!/bin/bash и.т. д)
|
|
|
|
|
if comment or fileType != "bin":
|
|
|
|
|
reExecRes = self.reExecStr.search(self.body)
|
|
|
|
|
if reExecRes:
|
|
|
|
|
self.execStr = self.body[reExecRes.start():reExecRes.end()]
|
|
|
|
|
self.body = self.body[:reExecRes.start()] + \
|
|
|
|
|
self.body[reExecRes.end():]
|
|
|
|
|
# Удаление Заголовка Calculate
|
|
|
|
|
if comment:
|
|
|
|
|
titleFirst = "Modified"
|
|
|
|
|
# В случае текста XML
|
|
|
|
|
if isinstance(comment, tuple) and len(comment) == 2:
|
|
|
|
|
reCalcHeader = \
|
|
|
|
|
re.compile("\s*%s\s+%s.+\s+(.+\n)+%s\s?" \
|
|
|
|
|
% (comment[0], titleFirst, comment[1]),
|
|
|
|
|
re.M | re.I)
|
|
|
|
|
reS = reCalcHeader.search(self.body)
|
|
|
|
|
if reS:
|
|
|
|
|
self.body = self.body[:reS.start()] + self.body[reS.end():]
|
|
|
|
|
else:
|
|
|
|
|
reCalcHeader = re.compile(
|
|
|
|
|
"\s*%s\-+\s+%s\s+%s.+\s+(%s.+\s+)+%s\-+\s?" \
|
|
|
|
|
% (comment, comment, titleFirst, comment, comment),
|
|
|
|
|
re.M | re.I)
|
|
|
|
|
reS = reCalcHeader.search(self.body)
|
|
|
|
|
if reS:
|
|
|
|
|
self.body = self.body[reS.end():]
|
|
|
|
|
if fileType is not False:
|
|
|
|
|
if fileType == "bin":
|
|
|
|
|
self.params["format"] = fileType
|
|
|
|
|
self.fileType = self._getType()
|
|
|
|
|
self.typeAppend = self._getAppend()
|
|
|
|
|
else:
|
|
|
|
|
textLines = self.body.splitlines()
|
|
|
|
|
if textLines:
|
|
|
|
|
textLine = textLines[0]
|
|
|
|
|
rePar = re.compile(
|
|
|
|
|
"\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$", re.I)
|
|
|
|
|
reP = rePar.search(textLine)
|
|
|
|
|
if reP:
|
|
|
|
|
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()]
|
|
|
|
|
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 = ""
|
|
|
|
|
paramLine = templateObj.applyFuncTemplate(paramLine,
|
|
|
|
|
templateName)
|
|
|
|
|
paramList = self.splitParLine(paramLine)
|
|
|
|
|
if paramList:
|
|
|
|
|
for i in paramList:
|
|
|
|
|
foundTerm = False
|
|
|
|
|
for term in self.terms:
|
|
|
|
|
if term in i:
|
|
|
|
|
foundTerm = True
|
|
|
|
|
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
|
|
|
|
|
if not foundTerm:
|
|
|
|
|
par = i.split("=")
|
|
|
|
|
if len(par) == 1:
|
|
|
|
|
if i in self.listParNotVal:
|
|
|
|
|
self.params[i] = "True"
|
|
|
|
|
else:
|
|
|
|
|
if i.strip():
|
|
|
|
|
incorrectParams = {i}
|
|
|
|
|
elif len(par) == 2:
|
|
|
|
|
self.params[par[0]] = par[1]
|
|
|
|
|
if par[0] == "env":
|
|
|
|
|
try:
|
|
|
|
|
importlib.import_module(
|
|
|
|
|
"calculate.%s.variables"
|
|
|
|
|
% par[1])
|
|
|
|
|
except (ImportError,
|
|
|
|
|
AttributeError):
|
|
|
|
|
self.headerTerm = False
|
|
|
|
|
self.comment = self._getComment()
|
|
|
|
|
self.fileType = self._getType()
|
|
|
|
|
typeAppend = self._getAppend()
|
|
|
|
|
if typeAppend:
|
|
|
|
|
self.typeAppend = typeAppend
|
|
|
|
|
else:
|
|
|
|
|
self.headerTerm = False
|
|
|
|
|
self.setError(_("incorrect header parameter: '%s'") \
|
|
|
|
|
% "append=%s" % self.params["append"])
|
|
|
|
|
if any(x in self.params for x in ('exec', 'run')):
|
|
|
|
|
if 'exec' in self.params:
|
|
|
|
|
self.execStr = "#!%s\n" % self.params['exec']
|
|
|
|
|
if 'run' in self.params:
|
|
|
|
|
self.execStr = "#!%s\n" % self.params['run']
|
|
|
|
|
if "python" in self.execStr:
|
|
|
|
|
self.execStr += "# -*- coding: utf-8 -*-\n"
|
|
|
|
|
|
|
|
|
|
if not incorrectParams and self.params:
|
|
|
|
|
incorrectParams = set(self.params.keys()) - set(self.allowParam)
|
|
|
|
|
if incorrectParams:
|
|
|
|
|
self.headerTerm = False
|
|
|
|
|
self.setError(_("incorrect header parameter: '%s'") \
|
|
|
|
|
% " ".join(list(incorrectParams)))
|
|
|
|
|
|
|
|
|
|
def _getType(self):
|
|
|
|
|
"""Выдать тип файла"""
|
|
|
|
|
if "format" in self.params:
|
|
|
|
|
return self.params["format"]
|
|
|
|
|
else:
|
|
|
|
|
return "raw"
|
|
|
|
|
|
|
|
|
|
def _getAppend(self):
|
|
|
|
|
"""Выдать тип добавления файла"""
|
|
|
|
|
if self.params.has_key("append"):
|
|
|
|
|
if self.params["append"] in self._fileAppend:
|
|
|
|
|
return self.params["append"]
|
|
|
|
|
else:
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
if self.fileType != "raw" and self.fileType != "bin" and \
|
|
|
|
|
self.fileType != "":
|
|
|
|
|
if "format" in self.params and self.params["format"] in \
|
|
|
|
|
("patch", "diff", "dconf"):
|
|
|
|
|
self.params["append"] = "patch"
|
|
|
|
|
return "patch"
|
|
|
|
|
self.params["append"] = "join"
|
|
|
|
|
return "join"
|
|
|
|
|
self.params["append"] = "replace"
|
|
|
|
|
return "replace"
|
|
|
|
|
|
|
|
|
|
def _getComment(self):
|
|
|
|
|
"""Выдать символ комментария файла"""
|
|
|
|
|
if self.params.has_key("comment"):
|
|
|
|
|
if self.params["comment"] in ("xml", "XML"):
|
|
|
|
|
return "<!--", "-->"
|
|
|
|
|
else:
|
|
|
|
|
return self.params["comment"]
|
|
|
|
|
else:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class dirHeader(_terms):
|
|
|
|
|
"""Обработка заголовков шаблонов директорий
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
# Допустимые параметры заголовка
|
|
|
|
|
allowParam = ["append", "chmod", "chown", "name", "path", "autoupdate",
|
|
|
|
|
"module", "env", "merge", "postmerge"]
|
|
|
|
|
|
|
|
|
|
# Тип вставки шаблона
|
|
|
|
|
typeAppend = ""
|
|
|
|
|
|
|
|
|
|
# Возможные типы вставки шаблонов
|
|
|
|
|
_fileAppend = "join", "remove", "skip", "clear"
|
|
|
|
|
|
|
|
|
|
# условные операторы
|
|
|
|
|
terms = ('>', '<', '==', '!=', '>=', '<=')
|
|
|
|
|
|
|
|
|
|
# параметры без значения
|
|
|
|
|
listParNotVal = ("symbolic", "force", "autoupdate")
|
|
|
|
|
|
|
|
|
|
# Результат вычисления условия в заголовке
|
|
|
|
|
headerTerm = True
|
|
|
|
|
|
|
|
|
|
def __init__(self, templateName, text, objVar=False, function=None):
|
|
|
|
|
self.body = text
|
|
|
|
|
# Объект с переменными
|
|
|
|
|
self.objVar = objVar
|
|
|
|
|
# Параметры описанные в заголовке файла шаблона
|
|
|
|
|
self.params = {}
|
|
|
|
|
# некорректные параметры
|
|
|
|
|
incorrectParams = set([])
|
|
|
|
|
|
|
|
|
|
textLines = text.splitlines()
|
|
|
|
|
flagErrorBody = False
|
|
|
|
|
if textLines:
|
|
|
|
|
textLine = textLines[0]
|
|
|
|
|
rePar = re.compile(
|
|
|
|
|
"\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$", re.I)
|
|
|
|
|
reP = rePar.search(textLine)
|
|
|
|
|
if reP:
|
|
|
|
|
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
|
|
|
|
|
self.setError(_("incorrect text in the template: '%s'") \
|
|
|
|
|
% self.body)
|
|
|
|
|
flagErrorBody = True
|
|
|
|
|
if not flagErrorBody:
|
|
|
|
|
paramList = self.splitParLine(paramLine)
|
|
|
|
|
if paramList:
|
|
|
|
|
for i in paramList:
|
|
|
|
|
foundTerm = False
|
|
|
|
|
for term in self.terms:
|
|
|
|
|
if term in i:
|
|
|
|
|
foundTerm = True
|
|
|
|
|
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
|
|
|
|
|
if not foundTerm:
|
|
|
|
|
par = i.split("=")
|
|
|
|
|
if len(par) == 1:
|
|
|
|
|
if i in self.listParNotVal:
|
|
|
|
|
self.params[i] = "True"
|
|
|
|
|
else:
|
|
|
|
|
if i.strip():
|
|
|
|
|
incorrectParams = {i}
|
|
|
|
|
elif len(par) == 2:
|
|
|
|
|
self.params[par[0]] = par[1]
|
|
|
|
|
if par[0] == "env":
|
|
|
|
|
try:
|
|
|
|
|
importlib.import_module(
|
|
|
|
|
"calculate.%s.variables" %
|
|
|
|
|
par[1])
|
|
|
|
|
except (ImportError, AttributeError):
|
|
|
|
|
self.headerTerm = False
|
|
|
|
|
self.objVar.defaultModule = \
|
|
|
|
|
self.params['env']
|
|
|
|
|
typeAppend = self._getAppend()
|
|
|
|
|
if typeAppend:
|
|
|
|
|
self.typeAppend = typeAppend
|
|
|
|
|
else:
|
|
|
|
|
self.headerTerm = False
|
|
|
|
|
self.setError(_("incorrect header parameter: '%s'") \
|
|
|
|
|
% "append=%s" % self.params["append"])
|
|
|
|
|
if not flagErrorBody:
|
|
|
|
|
if not incorrectParams:
|
|
|
|
|
incorrectParams = set(self.params.keys()) - set(self.allowParam)
|
|
|
|
|
if incorrectParams:
|
|
|
|
|
self.headerTerm = False
|
|
|
|
|
self.setError(_("incorrect header parameter: '%s'") \
|
|
|
|
|
% " ".join(list(incorrectParams)))
|
|
|
|
|
|
|
|
|
|
def _getAppend(self):
|
|
|
|
|
"""Выдать тип добавления директории"""
|
|
|
|
|
if self.params.has_key("append"):
|
|
|
|
|
if self.params["append"] in self._fileAppend:
|
|
|
|
|
return self.params["append"]
|
|
|
|
|
else:
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
return "join"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class blocText(object):
|
|
|
|
|
"""Разбиваем текст на блоки"""
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
textLine = None
|
|
|
|
|
commentLine = None
|
|
|
|
|
if commentSpl[0].strip():
|
|
|
|
|
closeBl = True
|
|
|
|
|
if len(commentSpl) > 1:
|
|
|
|
|
commentBl = commentTxtBloc.search(line)
|
|
|
|
|
textLine = commentSpl[0]
|
|
|
|
|
commentLine = line[commentBl.start(0):]
|
|
|
|
|
lineTmpA = textLine
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
# Если есть значение и комментарий в строке
|
|
|
|
|
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")
|
|
|
|
|
# Если есть несколько блоков в строке
|
|
|
|
|
elif len(txtLinesTmp) > 1 and txtLinesTmp[1].strip():
|
|
|
|
|
lenTmpLines = len(txtLinesTmp)
|
|
|
|
|
for l in range(lenTmpLines):
|
|
|
|
|
txtLines.append(txtLinesTmp[l])
|
|
|
|
|
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)
|
|
|
|
|
return headersArea, textBodyArea
|
|
|
|
|
|
|
|
|
|
txtWr = text
|
|
|
|
|
while r:
|
|
|
|
|
textArea = r.group(numGroupArea)
|
|
|
|
|
txtSpl = txtWr.split(textArea)
|
|
|
|
|
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)
|
|
|
|
|
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))
|
|
|
|
|
blocTxt = txtSpl[0]
|
|
|
|
|
txtWr = txtSpl[2]
|
|
|
|
|
rb = bodyTxtBloc.search(blocTxt)
|
|
|
|
|
if not blocTxt:
|
|
|
|
|
blocsTxt.append(blocTxt)
|
|
|
|
|
if rb:
|
|
|
|
|
blocsTxt.append(rb.group(0))
|
|
|
|
|
while r:
|
|
|
|
|
r = captionTxtBloc.search(txtWr)
|
|
|
|
|
if r:
|
|
|
|
|
headersTxt.append(r.group(0))
|
|
|
|
|
txtSpl = txtWr.partition(r.group(0))
|
|
|
|
|
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:
|
|
|
|
|
if len(headersTxt) > len(blocsTxt):
|
|
|
|
|
blocsTxt.insert(0, "")
|
|
|
|
|
elif len(headersTxt) < len(blocsTxt):
|
|
|
|
|
headersTxt.insert(0, "")
|
|
|
|
|
if len(headersTxt) != len(blocsTxt):
|
|
|
|
|
return False
|
|
|
|
|
return headersTxt, blocsTxt
|
|
|
|
|
else:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _file(_error):
|
|
|
|
|
"""
|
|
|
|
|
Класс для работы с файлами
|
|
|
|
|
"""
|
|
|
|
|
configMode = None
|
|
|
|
|
|
|
|
|
|
def printWARNING(self, s):
|
|
|
|
|
raise NotImplemented()
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
# Имя файла конфигурационного файла
|
|
|
|
|
self.nameFileConfig = ""
|
|
|
|
|
# Содержимое конфигурационного файла
|
|
|
|
|
self.textConfig = ""
|
|
|
|
|
# Имя файла шаблона
|
|
|
|
|
self.nameFileTemplate = ""
|
|
|
|
|
# Содержимое шаблона
|
|
|
|
|
self.textTemplate = ""
|
|
|
|
|
# Дескриптор файла шаблона
|
|
|
|
|
self.F_TEMPL = None
|
|
|
|
|
# Дескриптор файла конфигурационного файла
|
|
|
|
|
self.F_CONF = None
|
|
|
|
|
# тип запускаемого шаблона
|
|
|
|
|
self.executeType = None
|
|
|
|
|
# список скриптов на запуск
|
|
|
|
|
self.queueExecute = []
|
|
|
|
|
|
|
|
|
|
def saveConfFile(self):
|
|
|
|
|
"""Записать конфигурацию"""
|
|
|
|
|
if not self.textConfig:
|
|
|
|
|
self.textConfig = self.textTemplate
|
|
|
|
|
if self.F_CONF:
|
|
|
|
|
try:
|
|
|
|
|
self.F_CONF.truncate(0)
|
|
|
|
|
self.F_CONF.seek(0)
|
|
|
|
|
self.F_CONF.write(self.textConfig)
|
|
|
|
|
except IOError:
|
|
|
|
|
self.setError(_("unable to open the file:")
|
|
|
|
|
+ self.nameFileConfig)
|
|
|
|
|
return False
|
|
|
|
|
self.F_CONF.flush()
|
|
|
|
|
return True
|
|
|
|
|
elif self.executeType == "exec":
|
|
|
|
|
processor = self.textConfig.partition("\n")[0]
|
|
|
|
|
if processor.startswith("#!"):
|
|
|
|
|
self.queueExecute.append((processor[2:], self.textConfig,
|
|
|
|
|
self.nameFileTemplate))
|
|
|
|
|
else:
|
|
|
|
|
self.setError(_("unable to execute '%s'")
|
|
|
|
|
+ self.textConfig)
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def openTemplFile(self, nameFileTemplate):
|
|
|
|
|
"""Открыть файл шаблона"""
|
|
|
|
|
try:
|
|
|
|
|
F_TEMPL = open(nameFileTemplate, "r")
|
|
|
|
|
except IOError:
|
|
|
|
|
self.setError(_("unable to open the file:")
|
|
|
|
|
+ nameFileTemplate)
|
|
|
|
|
return False
|
|
|
|
|
return F_TEMPL
|
|
|
|
|
|
|
|
|
|
def closeTemplFile(self):
|
|
|
|
|
if self.F_TEMPL:
|
|
|
|
|
self.F_TEMPL.close()
|
|
|
|
|
self.F_TEMPL = None
|
|
|
|
|
|
|
|
|
|
def __closeOldFile(self):
|
|
|
|
|
if self.F_CONF:
|
|
|
|
|
self.F_CONF.close()
|
|
|
|
|
self.F_CONF = None
|
|
|
|
|
|
|
|
|
|
def __openConfFile(self, nameFileConfig):
|
|
|
|
|
"""Отктрыть конфигурационный файл"""
|
|
|
|
|
try:
|
|
|
|
|
if os.path.islink(nameFileConfig):
|
|
|
|
|
# если ссылка то удаляем её
|
|
|
|
|
os.unlink(nameFileConfig)
|
|
|
|
|
F_CONF = open(nameFileConfig, "r+")
|
|
|
|
|
except (IOError, OSError):
|
|
|
|
|
try:
|
|
|
|
|
if os.path.isdir(nameFileConfig):
|
|
|
|
|
self.printWARNING(_("unable to open the directory as file:")
|
|
|
|
|
+ nameFileConfig)
|
|
|
|
|
return False
|
|
|
|
|
F_CONF = open(nameFileConfig, "w+")
|
|
|
|
|
except (IOError, OSError):
|
|
|
|
|
self.setError(_("unable to open the file:")
|
|
|
|
|
+ nameFileConfig)
|
|
|
|
|
return False
|
|
|
|
|
return F_CONF
|
|
|
|
|
|
|
|
|
|
def openFiles(self, nameFileTemplate, nameFileConfig, typeFormat=None,
|
|
|
|
|
newBuffer=None):
|
|
|
|
|
"""Открывает шаблон и конфигурационный файл"""
|
|
|
|
|
self.textConfig = ""
|
|
|
|
|
self.textTemplate = ""
|
|
|
|
|
self.closeFiles()
|
|
|
|
|
self.F_TEMPL = None
|
|
|
|
|
self.F_CONF = None
|
|
|
|
|
self.nameFileConfig = os.path.abspath(nameFileConfig)
|
|
|
|
|
self.nameFileTemplate = os.path.abspath(nameFileTemplate)
|
|
|
|
|
self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
|
|
|
|
|
if not self.executeType and typeFormat not in ("diff", "dconf"):
|
|
|
|
|
self.F_CONF = self.__openConfFile(self.nameFileConfig)
|
|
|
|
|
if self.F_TEMPL and self.F_CONF:
|
|
|
|
|
self.textTemplate = self.F_TEMPL.read()
|
|
|
|
|
if self.configMode == T_NEWCFG:
|
|
|
|
|
origConfigName = re.sub(r'/._cfg\d{4}_([^/]+)$', '/\\1',
|
|
|
|
|
self.nameFileConfig)
|
|
|
|
|
if newBuffer is None:
|
|
|
|
|
self.textConfig = readFile(origConfigName)
|
|
|
|
|
else:
|
|
|
|
|
self.textConfig = newBuffer
|
|
|
|
|
else:
|
|
|
|
|
self.textConfig = self.F_CONF.read()
|
|
|
|
|
|
|
|
|
|
def __del__(self):
|
|
|
|
|
self.closeFiles()
|
|
|
|
|
|
|
|
|
|
def closeFiles(self):
|
|
|
|
|
"""Закрытие файлов"""
|
|
|
|
|
self.closeTemplFile()
|
|
|
|
|
self.__closeOldFile()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class utfBin(object):
|
|
|
|
|
"""Класс для преобразования в utf-8
|
|
|
|
|
|
|
|
|
|
преобразование бинарного или смеси бинарного и utf-8 кода в utf-8 и
|
|
|
|
|
обратное преобразование
|
|
|
|
|
методы класса encode и decode
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def _retUTF(self, char):
|
|
|
|
|
byte = ord(char)
|
|
|
|
|
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:
|
|
|
|
|
return '_er_', 1
|
|
|
|
|
|
|
|
|
|
def _sumbUtf(self, symbols, lenTail):
|
|
|
|
|
if not symbols:
|
|
|
|
|
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_':
|
|
|
|
|
return True, 1
|
|
|
|
|
else:
|
|
|
|
|
return False, 1
|
|
|
|
|
result = False
|
|
|
|
|
i_ = 0
|
|
|
|
|
for i in range(l):
|
|
|
|
|
i_ = i
|
|
|
|
|
if i == 0 and symbols[i] != '_fb_':
|
|
|
|
|
break
|
|
|
|
|
elif i > 0 and symbols[i] != '_nb_':
|
|
|
|
|
break
|
|
|
|
|
if lenTail > 1 and lenTail != i_:
|
|
|
|
|
return False, 1
|
|
|
|
|
if i_ > 0:
|
|
|
|
|
result = True
|
|
|
|
|
return result, i_
|
|
|
|
|
|
|
|
|
|
def _intToChar(self, x):
|
|
|
|
|
he = hex(x)[2:]
|
|
|
|
|
ret = None
|
|
|
|
|
exec ("ret = '\\x%s'" % he)
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
def _hexToChar(self, he):
|
|
|
|
|
ret = None
|
|
|
|
|
exec ("ret = '\\x%s'" % he)
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
i += 1
|
|
|
|
|
while 1:
|
|
|
|
|
if utf[ind] == '_fb_':
|
|
|
|
|
res, l = self._sumbUtf(utf[ind:], lenUtf[ind])
|
|
|
|
|
if res is False:
|
|
|
|
|
indErr.append(ind)
|
|
|
|
|
if l > 0:
|
|
|
|
|
ind += l
|
|
|
|
|
if ind >= len(utf):
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
if utf[ind] != '_ch_':
|
|
|
|
|
indErr.append(ind)
|
|
|
|
|
ind += 1
|
|
|
|
|
if ind >= len(utf):
|
|
|
|
|
break
|
|
|
|
|
if indErr:
|
|
|
|
|
lenIndErr = len(indErr)
|
|
|
|
|
block = []
|
|
|
|
|
blocks = []
|
|
|
|
|
if lenIndErr > 1:
|
|
|
|
|
i = 1
|
|
|
|
|
while 1:
|
|
|
|
|
if i == 1:
|
|
|
|
|
block.append(indErr[i - 1])
|
|
|
|
|
if indErr[i] - indErr[i - 1] == 1:
|
|
|
|
|
block.append(indErr[i])
|
|
|
|
|
else:
|
|
|
|
|
if block:
|
|
|
|
|
blocks.append(block)
|
|
|
|
|
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 = ""
|
|
|
|
|
last_elem = None
|
|
|
|
|
for elem in block:
|
|
|
|
|
string += hex(ord(text[elem]))[-2:]
|
|
|
|
|
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:]
|
|
|
|
|
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 Это экранирование '?' которое тоже считается
|
|
|
|
|
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:
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class templateFormat(object):
|
|
|
|
|
"""Методы получения классов и объектов форматов шаблонов"""
|
|
|
|
|
# Импортированные классы поддерживаемых форматов шаблонов
|
|
|
|
|
importFormats = {}
|
|
|
|
|
|
|
|
|
|
newObjProt = {}
|
|
|
|
|
|
|
|
|
|
def createNewClass(self, name, bases, attrs=None):
|
|
|
|
|
raise NotImplemented()
|
|
|
|
|
|
|
|
|
|
def getClassObj(self, nameClassTemplate):
|
|
|
|
|
"""Создает класс шаблона по имени"""
|
|
|
|
|
if nameClassTemplate in self.importFormats:
|
|
|
|
|
classFormat = self.importFormats[nameClassTemplate]
|
|
|
|
|
else:
|
|
|
|
|
try:
|
|
|
|
|
classFormat = getattr(__import__("calculate.lib.format.%s" %
|
|
|
|
|
nameClassTemplate,
|
|
|
|
|
globals(), locals(),
|
|
|
|
|
[nameClassTemplate]),
|
|
|
|
|
nameClassTemplate)
|
|
|
|
|
except (ImportError, AttributeError):
|
|
|
|
|
# Создаем объект из self.newObjProt с помощью
|
|
|
|
|
# метаклассов
|
|
|
|
|
if nameClassTemplate in self.newObjProt:
|
|
|
|
|
# Прототип класса
|
|
|
|
|
nameProt = self.newObjProt[nameClassTemplate]
|
|
|
|
|
if nameProt in self.importFormats:
|
|
|
|
|
classProt = self.importFormats[nameProt]
|
|
|
|
|
else:
|
|
|
|
|
try:
|
|
|
|
|
classProt = getattr(
|
|
|
|
|
__import__("calculate.lib.format.%s" % nameProt,
|
|
|
|
|
globals(), locals(),
|
|
|
|
|
[nameProt]),
|
|
|
|
|
nameProt)
|
|
|
|
|
except (ImportError, AttributeError):
|
|
|
|
|
return False
|
|
|
|
|
self.importFormats[nameProt] = classProt
|
|
|
|
|
classFormat = self.createNewClass(nameClassTemplate,
|
|
|
|
|
(classProt,))
|
|
|
|
|
else:
|
|
|
|
|
return False
|
|
|
|
|
self.importFormats[nameClassTemplate] = classFormat
|
|
|
|
|
return classFormat
|
|
|
|
|
|
|
|
|
|
def getFormatObj(self, formatTemplate, textTemplate):
|
|
|
|
|
"""Создание объекта формата шаблона.
|
|
|
|
|
|
|
|
|
|
Объект создается на основании формата шаблона и текста шаблона"""
|
|
|
|
|
classFormat = self.getClassObj(formatTemplate)
|
|
|
|
|
if callable(classFormat):
|
|
|
|
|
return classFormat(textTemplate)
|
|
|
|
|
else:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _shareTemplate(object):
|
|
|
|
|
"""Общие аттрибуты для классов шаблонов"""
|
|
|
|
|
# Метка начала переменной
|
|
|
|
|
varStart = "#-"
|
|
|
|
|
# Метка конца переменной
|
|
|
|
|
varEnd = "-#"
|
|
|
|
|
_deltVarStart = len(varStart)
|
|
|
|
|
_deltVarEnd = len(varEnd)
|
|
|
|
|
objVar = None
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
raise TemplatesError(_("User %s not found") % str(userName))
|
|
|
|
|
if groupsInfo:
|
|
|
|
|
import grp
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
groupName = grp.getgrgid(gid).gr_name
|
|
|
|
|
except:
|
|
|
|
|
raise TemplatesError(_("Group ID %s not found") % str(gid))
|
|
|
|
|
groupsNames = map(lambda x: x.gr_name,
|
|
|
|
|
filter(lambda x: userName in x.gr_mem,
|
|
|
|
|
grp.getgrall()))
|
|
|
|
|
groupsNames = [groupName] + groupsNames
|
|
|
|
|
return uid, gid, homeDir, groupsNames
|
|
|
|
|
return uid, gid, homeDir
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class templateFunction(_error, _warning, _shareTemplate, _shareTermsFunction):
|
|
|
|
|
"""Класс для функций шаблонов"""
|
|
|
|
|
# Словарь установленных программ {"имя программы":[версии]}
|
|
|
|
|
installProg = {}
|
|
|
|
|
|
|
|
|
|
# Cписок просканированных категорий установленных программ
|
|
|
|
|
installCategory = []
|
|
|
|
|
|
|
|
|
|
# Флаг сканирования всех установленных программ
|
|
|
|
|
flagAllPkgScan = False
|
|
|
|
|
|
|
|
|
|
# Список названий функций шаблона
|
|
|
|
|
namesTemplateFunction = []
|
|
|
|
|
|
|
|
|
|
# Словарь {название функции шаблона: функция шаблона, ...}
|
|
|
|
|
templateFunction = {}
|
|
|
|
|
|
|
|
|
|
# Регулярное выражение для сложения
|
|
|
|
|
sNum = re.compile("\-[^\-\+]+|[^\-\+]+")
|
|
|
|
|
|
|
|
|
|
# Регулярное выражение для умножениея и деления
|
|
|
|
|
sMD = re.compile("[^\-\+\*/]+")
|
|
|
|
|
|
|
|
|
|
# директория установленных программ
|
|
|
|
|
basePkgDir = "/var/db/pkg"
|
|
|
|
|
|
|
|
|
|
# кэш для проверки наличия пакета в портежах
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
currentAction = "merge"
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
return "%s/%s" % (category, pkgName)
|
|
|
|
|
|
|
|
|
|
currentBelong = ""
|
|
|
|
|
alreadyInformed = []
|
|
|
|
|
|
|
|
|
|
def __init__(self, objVar):
|
|
|
|
|
# Если не определен словарь функций шаблона
|
|
|
|
|
# import services api
|
|
|
|
|
if not self.templateFunction:
|
|
|
|
|
# префикс функций шаблона
|
|
|
|
|
pref = "func"
|
|
|
|
|
# cписок [(название функции, функция), ...]
|
|
|
|
|
dictFunc = filter(lambda x: x[0].startswith(pref) and \
|
|
|
|
|
hasattr(x[1], "__call__"),
|
|
|
|
|
self.__class__.__dict__.items())
|
|
|
|
|
# удаляем у названия функции префикс и переводим остаток названия
|
|
|
|
|
# в нижний регистр
|
|
|
|
|
dictFunc = map(lambda x: (x[0][len(pref):].lower(), x[1]), dictFunc)
|
|
|
|
|
# Формируем словарь функций шаблона
|
|
|
|
|
self.templateFunction.update(dictFunc)
|
|
|
|
|
# Формируем список функций шаблона
|
|
|
|
|
for nameFunction in self.templateFunction.keys():
|
|
|
|
|
self.namesTemplateFunction.append(nameFunction)
|
|
|
|
|
# Объект хранения переменных
|
|
|
|
|
self.objVar = objVar
|
|
|
|
|
self._reFunc = re.compile("%s%s%s"
|
|
|
|
|
% (self.varStart, self._reFunctionText,
|
|
|
|
|
self.varEnd), re.M)
|
|
|
|
|
# Аттрибуты для функции шаблона 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):
|
|
|
|
|
from convertenv import convertEnv
|
|
|
|
|
|
|
|
|
|
self.convObj = convertEnv()
|
|
|
|
|
|
|
|
|
|
def recalculateBaseDir(self):
|
|
|
|
|
"""Recalculate basedir and homedir"""
|
|
|
|
|
# Директория другой системы
|
|
|
|
|
self._chrootDir = self.objVar.Get("cl_chroot_path")
|
|
|
|
|
if self._chrootDir != '/':
|
|
|
|
|
# Изменение директории к базе пакетов
|
|
|
|
|
self.basePkgDir = pathJoin(self._chrootDir, self.basePkgDir)
|
|
|
|
|
self.basePkgDir = os.path.normpath(self.basePkgDir)
|
|
|
|
|
# Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
|
|
|
|
|
self._baseDir = pathJoin(self._chrootDir,
|
|
|
|
|
self.objVar.Get("cl_root_path"))
|
|
|
|
|
self._baseDir = os.path.normpath(self._baseDir)
|
|
|
|
|
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.modeConfigIni = 0640
|
|
|
|
|
else:
|
|
|
|
|
self.pathConfigIni = pathJoin(self._chrootDir, '/etc/calculate')
|
|
|
|
|
self.modeConfigIni = 0644
|
|
|
|
|
self.fileConfigIni = os.path.join(self.pathConfigIni, "ini.env")
|
|
|
|
|
# TODO: debug block
|
|
|
|
|
# print "DEBUG", self.fileConfigIni
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
strNum = self.multAndDiv(strNum, localVars)
|
|
|
|
|
num = 0
|
|
|
|
|
try:
|
|
|
|
|
num = int(strNum)
|
|
|
|
|
except ValueError:
|
|
|
|
|
minus = False
|
|
|
|
|
if strNum[:1] == "-":
|
|
|
|
|
minus = True
|
|
|
|
|
strNum = strNum[1:]
|
|
|
|
|
if localVars.has_key(strNum):
|
|
|
|
|
try:
|
|
|
|
|
num = int(localVars[strNum])
|
|
|
|
|
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))
|
|
|
|
|
except ValueError:
|
|
|
|
|
raise self.raiseErrTemplate(
|
|
|
|
|
_("error: variable %s is not integer") %
|
|
|
|
|
str(strNum))
|
|
|
|
|
else:
|
|
|
|
|
raise self.raiseErrTemplate(
|
|
|
|
|
_("error: local variable %s not defined") %
|
|
|
|
|
str(strNum))
|
|
|
|
|
if minus:
|
|
|
|
|
num = -num
|
|
|
|
|
strNumers.append(num)
|
|
|
|
|
return sum(strNumers)
|
|
|
|
|
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)
|
|
|
|
|
except ValueError:
|
|
|
|
|
flagVarTxt = False
|
|
|
|
|
if flagVarTxt:
|
|
|
|
|
continue
|
|
|
|
|
varReplace = str(self.equalTerm(var, localVars))
|
|
|
|
|
termTmp = termTmp.replace(var, varReplace)
|
|
|
|
|
ret = eval(termTmp)
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
def funcSum(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""Функция шаблона, вычисляет функцию sum()"""
|
|
|
|
|
terms = funArgv.replace(" ", "").split(",")
|
|
|
|
|
# Название локальной переменной
|
|
|
|
|
nameLocVar = terms[0]
|
|
|
|
|
if not localVars.has_key(nameLocVar):
|
|
|
|
|
localVars[nameLocVar] = 0
|
|
|
|
|
if len(terms) == 2:
|
|
|
|
|
if terms[1].strip():
|
|
|
|
|
localVars[nameLocVar] = self.equalTerm(terms[1], localVars)
|
|
|
|
|
replace = str(localVars[nameLocVar])
|
|
|
|
|
else:
|
|
|
|
|
replace = ""
|
|
|
|
|
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 = ""
|
|
|
|
|
localVars[nameLocVar] = self.equalTerm(terms[2], localVars)
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
else:
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcExists(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""Функция шаблона exists(),
|
|
|
|
|
проверяет существование файла, если существует выдает '1'
|
|
|
|
|
если второй параметр root, то проверка осуществляется от корня.
|
|
|
|
|
"""
|
|
|
|
|
terms = map(lambda x: x.strip(), 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):
|
|
|
|
|
replace = "1"
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcLoad(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""Функция шаблона load(),
|
|
|
|
|
|
|
|
|
|
если файл существует читает из файла локальную переменную
|
|
|
|
|
если один параметр - выводит значение локальной переменной
|
|
|
|
|
"""
|
|
|
|
|
terms = funArgv.split(",")
|
|
|
|
|
if terms:
|
|
|
|
|
lenTerms = len(terms)
|
|
|
|
|
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:
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
flagNotRootFS = True
|
|
|
|
|
if lenTerms == 3:
|
|
|
|
|
if terms[2] == "root":
|
|
|
|
|
flagNotRootFS = False
|
|
|
|
|
else:
|
|
|
|
|
raise self.raiseErrTemplate(
|
|
|
|
|
_("The third argument of the function is not 'root'"))
|
|
|
|
|
if lenTerms >= 2:
|
|
|
|
|
if not terms[0] in ["ver", "num", "char", "key", "empty"]:
|
|
|
|
|
raise self.raiseErrTemplate(
|
|
|
|
|
_("the first argument of the function is neither 'ver'"
|
|
|
|
|
" 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,
|
|
|
|
|
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):
|
|
|
|
|
replace = readFile(fileName).strip()
|
|
|
|
|
if replace and lenTerms >= 2 and terms[0] == "empty":
|
|
|
|
|
replace = "\n".join(filter(lambda x: not self.reEmptyLoad.search(x),
|
|
|
|
|
replace.split("\n")))
|
|
|
|
|
if not replace and lenTerms >= 2 and terms[0] in ["ver", "num"]:
|
|
|
|
|
replace = "0"
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def sharePkg(self, pkgs, force=False):
|
|
|
|
|
"""
|
|
|
|
|
Update packages from pkgs list
|
|
|
|
|
"""
|
|
|
|
|
for pkgname, category, ver, slot in pkgs:
|
|
|
|
|
fullname = "%s/%s" % (category, pkgname)
|
|
|
|
|
if not fullname in self.installProg or \
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
def getInstallPkgGentoo(self, category=""):
|
|
|
|
|
pkgs = []
|
|
|
|
|
filterFunc = lambda x: "SLOT" == x
|
|
|
|
|
|
|
|
|
|
def getFilesDir(pkgs, dirname, names):
|
|
|
|
|
for nameFile in filter(filterFunc, names):
|
|
|
|
|
absNameFile = os.path.join(dirname, nameFile)
|
|
|
|
|
category, spl, pkgname = dirname.rpartition('/')
|
|
|
|
|
dbpkg, spl, category = category.rpartition('/')
|
|
|
|
|
slot = readFile(absNameFile).strip()
|
|
|
|
|
pkgname, spl, rev = pkgname.rpartition("-")
|
|
|
|
|
if rev.startswith('r'):
|
|
|
|
|
pkgname, spl, ver = pkgname.rpartition("-")
|
|
|
|
|
ver = "%s-%s" % (ver, rev)
|
|
|
|
|
else:
|
|
|
|
|
ver = rev
|
|
|
|
|
pkgs.append((pkgname, category, ver, slot))
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
os.path.walk(os.path.join(self.basePkgDir, category),
|
|
|
|
|
getFilesDir, pkgs)
|
|
|
|
|
return self.sharePkg(pkgs)
|
|
|
|
|
|
|
|
|
|
def pkg(self, nameProg, slot=None):
|
|
|
|
|
if len(self.installProg) > 0:
|
|
|
|
|
if type(self.installProg.values()[0]) != dict:
|
|
|
|
|
self.installProg.clear()
|
|
|
|
|
self.getInstallPkgGentoo()
|
|
|
|
|
if nameProg in self.installProg:
|
|
|
|
|
versions = self.installProg[nameProg]
|
|
|
|
|
if slot:
|
|
|
|
|
return versions.get(slot, "")
|
|
|
|
|
if len(versions) == 1:
|
|
|
|
|
return versions.values()[0]
|
|
|
|
|
else:
|
|
|
|
|
return versions[max(versions.keys(), key=getTupleVersion)]
|
|
|
|
|
else:
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
def funcPkg(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""Функция шаблона pkg(), выдает номер версии программы"""
|
|
|
|
|
# Название программы
|
|
|
|
|
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)
|
|
|
|
|
self.installCategory.append(category)
|
|
|
|
|
replace = self.pkg(nameProg, slot=slot or None)
|
|
|
|
|
if replace and uses:
|
|
|
|
|
pkg_use, pkg_iuse = getPkgUses("%s/%s" % (category, nameProg),
|
|
|
|
|
replace, prefix=self.objVar.Get(
|
|
|
|
|
'cl_chroot_path'))
|
|
|
|
|
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 = ""
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
if not self.flagAllPkgScan:
|
|
|
|
|
self.getInstallPkgGentoo()
|
|
|
|
|
templateFunction.flagAllPkgScan = True
|
|
|
|
|
nameProg, spl, slot = nameProg.partition(":")
|
|
|
|
|
replace = self.pkg(nameProg,
|
|
|
|
|
slot=slot)
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcKernel(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""
|
|
|
|
|
Функция kernel(...), выдает значение опции конфига ядра (y,m,)
|
|
|
|
|
"""
|
|
|
|
|
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_"):
|
|
|
|
|
raise self.raiseErrTemplate(
|
|
|
|
|
_("the option name should not starts with CONFIG_"))
|
|
|
|
|
kernel_config = self.objVar.Get('install.os_install_kernel_config')
|
|
|
|
|
find_str = "CONFIG_%s" % kernel_opt
|
|
|
|
|
replace = ""
|
|
|
|
|
for line in kernel_config:
|
|
|
|
|
if find_str in line:
|
|
|
|
|
if "%s=" % find_str in line:
|
|
|
|
|
key, op, value = line.partition("=")
|
|
|
|
|
replace = value.strip("'\"")
|
|
|
|
|
break
|
|
|
|
|
elif "%s is not set" % find_str in line:
|
|
|
|
|
break
|
|
|
|
|
textTemplateTmp = (textTemplateTmp[:resS.start()] + replace +
|
|
|
|
|
textTemplateTmp[resS.end():])
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcGrep(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""
|
|
|
|
|
Функция grep (...), выдает значение из файла по регулярному выражению
|
|
|
|
|
"""
|
|
|
|
|
fname, op, regpattern = funArgv.replace(" ", "").partition(",")
|
|
|
|
|
regpattern = regpattern.replace("(?\<", "(?<")
|
|
|
|
|
regpattern = self._replace_hex(regpattern)
|
|
|
|
|
if not fname or not regpattern:
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
try:
|
|
|
|
|
reg = re.compile(regpattern)
|
|
|
|
|
except re.error:
|
|
|
|
|
raise self.raiseErrTemplate(_("Wrong regular expression"))
|
|
|
|
|
if fname[0] == "~":
|
|
|
|
|
# Получаем директорию пользователя
|
|
|
|
|
fname = os.path.join(self.homeDir,
|
|
|
|
|
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 = ""
|
|
|
|
|
return (
|
|
|
|
|
textTemplateTmp[:resS.start()] + replace + textTemplateTmp[
|
|
|
|
|
resS.end():])
|
|
|
|
|
|
|
|
|
|
def funcRnd(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""Функция шаблона rnd(), выдает строку случайных символов
|
|
|
|
|
|
|
|
|
|
первый аргумент:
|
|
|
|
|
'num' - числа,
|
|
|
|
|
'pas' - цифры и буквы
|
|
|
|
|
'uuid' - цифры и строчные буквы a-f
|
|
|
|
|
второй аргумент:
|
|
|
|
|
количество символов
|
|
|
|
|
"""
|
|
|
|
|
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 = {'num': string.digits,
|
|
|
|
|
'pas': string.ascii_letters + string.digits,
|
|
|
|
|
'uuid': string.ascii_lowercase[:6] + string.digits}
|
|
|
|
|
if not terms[0] in fArgvNames:
|
|
|
|
|
raise self.raiseErrTemplate(
|
|
|
|
|
_("the first argument of the function must "
|
|
|
|
|
"be 'num', 'pas' or 'uuid'"))
|
|
|
|
|
try:
|
|
|
|
|
lenStr = int(terms[1])
|
|
|
|
|
except (ValueError, IndexError, TypeError):
|
|
|
|
|
lenStr = 0
|
|
|
|
|
raise self.raiseErrTemplate(
|
|
|
|
|
_("the second argument of the function is not a number"))
|
|
|
|
|
choiceStr = fArgvNames[terms[0]]
|
|
|
|
|
replace = ''.join([random.choice(choiceStr) for i in xrange(lenStr)])
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcCase(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""Функция шаблона case(), выдает переменную в определенном регистре
|
|
|
|
|
|
|
|
|
|
первый аргумент:
|
|
|
|
|
'upper' - верхний регистр,
|
|
|
|
|
'lower' - нижний регистр,
|
|
|
|
|
'capitalize' - первая буква в верхнем регистре
|
|
|
|
|
второй аргумент:
|
|
|
|
|
название переменной
|
|
|
|
|
"""
|
|
|
|
|
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:
|
|
|
|
|
raise self.raiseErrTemplate(_("the first argument of the function"
|
|
|
|
|
" is neither 'upper' or 'lower' or"
|
|
|
|
|
" 'capitalize'"))
|
|
|
|
|
try:
|
|
|
|
|
strValue = self.objVar.Get(terms[1])
|
|
|
|
|
if not strValue:
|
|
|
|
|
strValue = ""
|
|
|
|
|
else:
|
|
|
|
|
strValue = str(strValue)
|
|
|
|
|
except:
|
|
|
|
|
raise TemplatesError(
|
|
|
|
|
_("error in template %s") % self.nameTemplate + "\n" +
|
|
|
|
|
_("error: variable %s not found") % str(terms[1]))
|
|
|
|
|
replace = ""
|
|
|
|
|
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.encode("UTF-8")
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcIn(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""
|
|
|
|
|
Function in for check value in variable
|
|
|
|
|
"""
|
|
|
|
|
terms = funArgv.replace(" ", "").split(",")
|
|
|
|
|
# Название локальной переменной
|
|
|
|
|
nameLocVar = terms[0]
|
|
|
|
|
try:
|
|
|
|
|
value = self.objVar.Get(nameLocVar)
|
|
|
|
|
if type(value) in (list, tuple):
|
|
|
|
|
terms = terms[1:]
|
|
|
|
|
if any(x in terms for x in value):
|
|
|
|
|
replace = "1"
|
|
|
|
|
else:
|
|
|
|
|
replace = ""
|
|
|
|
|
else:
|
|
|
|
|
if value in terms[1:]:
|
|
|
|
|
replace = "1"
|
|
|
|
|
else:
|
|
|
|
|
replace = ""
|
|
|
|
|
except Exception:
|
|
|
|
|
raise self.raiseErrTemplate(_("error: variable %s does not exist") \
|
|
|
|
|
% str(nameLocVar))
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcPush(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""локальная функция записывает значение переменной
|
|
|
|
|
|
|
|
|
|
в стек глобальных переменных
|
|
|
|
|
"""
|
|
|
|
|
terms = funArgv.replace(" ", "").split(",")
|
|
|
|
|
# Название локальной переменной
|
|
|
|
|
nameLocVar = terms[0]
|
|
|
|
|
value = ""
|
|
|
|
|
if nameLocVar in localVars.keys():
|
|
|
|
|
flagFoundVar = True
|
|
|
|
|
value = localVars[nameLocVar]
|
|
|
|
|
else:
|
|
|
|
|
try:
|
|
|
|
|
value = self.objVar.Get(nameLocVar)
|
|
|
|
|
flagFoundVar = True
|
|
|
|
|
except Exception:
|
|
|
|
|
flagFoundVar = False
|
|
|
|
|
if flagFoundVar:
|
|
|
|
|
# Если переменная существует
|
|
|
|
|
if len(terms) == 1:
|
|
|
|
|
self.stackGlobalVars.append(str(value))
|
|
|
|
|
else:
|
|
|
|
|
raise self.raiseErrTemplate(_("error: variable %s exists") \
|
|
|
|
|
% str(nameLocVar))
|
|
|
|
|
else:
|
|
|
|
|
# Если переменная не существует
|
|
|
|
|
if len(terms) == 1:
|
|
|
|
|
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:
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
replace = ""
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcPop(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""локальная функция получает значение
|
|
|
|
|
|
|
|
|
|
из стека глобальных переменных и присваивает локальной переменной
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
terms = funArgv.replace(" ", "").split(",")
|
|
|
|
|
# Название локальной переменной
|
|
|
|
|
nameLocVar = terms[0]
|
|
|
|
|
if len(terms) == 1:
|
|
|
|
|
if self.stackGlobalVars:
|
|
|
|
|
localVars[nameLocVar] = self.stackGlobalVars.pop()
|
|
|
|
|
else:
|
|
|
|
|
raise self.raiseErrTemplate(
|
|
|
|
|
_("error: global variables stack empty"))
|
|
|
|
|
else:
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
replace = ""
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcPrint(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""
|
|
|
|
|
Вывод успешного сообщения
|
|
|
|
|
"""
|
|
|
|
|
self.printSUCCESS(_(funArgv))
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcWarning(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""
|
|
|
|
|
Вывод сообщения с предупреждением
|
|
|
|
|
"""
|
|
|
|
|
self.printWARNING(_(funArgv))
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcError(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""
|
|
|
|
|
Вывод сообщения с ошибкой
|
|
|
|
|
"""
|
|
|
|
|
self.printERROR(_(funArgv))
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def getElogTimestamp(self):
|
|
|
|
|
# Получаем время модификации конфигурационного файла
|
|
|
|
|
curTime = self.getTimeFile(self.fileConfigIni)
|
|
|
|
|
nameLocVar = "update.timestamp"
|
|
|
|
|
if self.timeIni != curTime:
|
|
|
|
|
# читаем переменные из файла
|
|
|
|
|
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
|
|
|
|
|
self.currDictIni = {}
|
|
|
|
|
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].encode("UTF-8")
|
|
|
|
|
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 ""
|
|
|
|
|
|
|
|
|
|
def funcElog(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""Function for work with emerge.log"""
|
|
|
|
|
funArgv = funArgv.strip()
|
|
|
|
|
rePkg = re.compile(r'\) Merging (?:Binary )?\((\S+)::', re.S)
|
|
|
|
|
replace = ""
|
|
|
|
|
if funArgv:
|
|
|
|
|
lastTimestamp = self.getElogTimestamp()
|
|
|
|
|
for line in reversed(list(readLinesFile(self.elogFile))):
|
|
|
|
|
timestamp, op, info = line.partition(':')
|
|
|
|
|
if timestamp.isdigit() and lastTimestamp and \
|
|
|
|
|
int(timestamp) < lastTimestamp:
|
|
|
|
|
break
|
|
|
|
|
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()
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcLivemenu(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
def generateSubmenu(data):
|
|
|
|
|
base_dn = self.objVar.Get('builder.cl_builder_flash_path')
|
|
|
|
|
for id, label, iso, vmlinuz_orig, vmlinuz, initrd_orig, initrd, \
|
|
|
|
|
xorg, drivers, splash in data:
|
|
|
|
|
if splash == "splashutils":
|
|
|
|
|
splash = "splash=silent,theme:calculate console=tty1"
|
|
|
|
|
elif splash == "plymouth":
|
|
|
|
|
splash = "splash"
|
|
|
|
|
else:
|
|
|
|
|
splash = "verbose"
|
|
|
|
|
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 = filter(None, self.objVar.Get('builder.cl_builder_image_data'))
|
|
|
|
|
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():]
|
|
|
|
|
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):
|
|
|
|
|
nameVar = "%s.%s" % (sect, name)
|
|
|
|
|
localVarsIni[nameVar] = valueVar
|
|
|
|
|
return localVarsIni
|
|
|
|
|
|
|
|
|
|
def getTimeFile(self, fileName):
|
|
|
|
|
# Получаем время модификации файла
|
|
|
|
|
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(",")
|
|
|
|
|
if len(terms) != 2:
|
|
|
|
|
raise self.raiseErrTemplate(_("funtion takes only two parameters"))
|
|
|
|
|
resol, wpath = terms
|
|
|
|
|
if not resol:
|
|
|
|
|
resol = "1024x768"
|
|
|
|
|
|
|
|
|
|
re_resol = re.compile("^(\d+)x(\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+).*")
|
|
|
|
|
wpath = pathJoin(self._baseDir, wpath)
|
|
|
|
|
res = map(lambda x: (int(x.group(1)), int(x.group(2)), x.group()),
|
|
|
|
|
filter(None,
|
|
|
|
|
map(re_resol.search,
|
|
|
|
|
listDirectory(wpath))))
|
|
|
|
|
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]
|
|
|
|
|
else:
|
|
|
|
|
replace = ""
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcIni(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""локальная функция записывает и считывает значение переменной
|
|
|
|
|
|
|
|
|
|
из ini файла ~./calculate/ini.env
|
|
|
|
|
"""
|
|
|
|
|
# Создаем директорию
|
|
|
|
|
if not os.path.exists(self.pathConfigIni):
|
|
|
|
|
os.makedirs(self.pathConfigIni)
|
|
|
|
|
os.chown(self.pathConfigIni, self.uid, self.gid)
|
|
|
|
|
termsRaw = funArgv.split(",")
|
|
|
|
|
flagFirst = True
|
|
|
|
|
terms = []
|
|
|
|
|
for term in termsRaw:
|
|
|
|
|
if flagFirst:
|
|
|
|
|
terms.append(term.replace(" ", ""))
|
|
|
|
|
flagFirst = False
|
|
|
|
|
else:
|
|
|
|
|
val = term.strip()
|
|
|
|
|
# Флаг (не найдены кавычки)
|
|
|
|
|
flagNotFoundQuote = True
|
|
|
|
|
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)
|
|
|
|
|
# Название локальной переменной
|
|
|
|
|
nameLocVar = terms[0]
|
|
|
|
|
namesVar = nameLocVar.split(".")
|
|
|
|
|
if len(namesVar) == 1:
|
|
|
|
|
nameLocVar = "main.%s" % nameLocVar
|
|
|
|
|
elif len(namesVar) > 2:
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
replace = ""
|
|
|
|
|
# Получаем время модификации конфигурационного файла
|
|
|
|
|
curTime = self.getTimeFile(self.fileConfigIni)
|
|
|
|
|
if len(terms) == 1:
|
|
|
|
|
if self.timeIni != curTime:
|
|
|
|
|
# читаем переменные из файла
|
|
|
|
|
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
|
|
|
|
|
self.currDictIni = {}
|
|
|
|
|
self.currDictIni.update(self.prevDictIni)
|
|
|
|
|
self.timeIni = self.getTimeFile(self.fileConfigIni)
|
|
|
|
|
if nameLocVar in self.currDictIni.keys():
|
|
|
|
|
if self.currDictIni[nameLocVar] is None:
|
|
|
|
|
replace = ""
|
|
|
|
|
else:
|
|
|
|
|
replace = self.currDictIni[nameLocVar].encode("UTF-8")
|
|
|
|
|
elif len(terms) == 2:
|
|
|
|
|
if self.timeIni != curTime:
|
|
|
|
|
# читаем переменные из файла
|
|
|
|
|
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
|
|
|
|
|
self.currDictIni = {}
|
|
|
|
|
self.currDictIni.update(self.prevDictIni)
|
|
|
|
|
self.timeIni = self.getTimeFile(self.fileConfigIni)
|
|
|
|
|
# Значение локальной переменной
|
|
|
|
|
valueLocVar = terms[1]
|
|
|
|
|
self.currDictIni[nameLocVar] = valueLocVar
|
|
|
|
|
elif len(terms) == 3:
|
|
|
|
|
if not terms[2] in ['url', 'purl', 'unicode']:
|
|
|
|
|
raise self.raiseErrTemplate(
|
|
|
|
|
_("the third argument of the function is neither "
|
|
|
|
|
"'url' or 'purl' or 'unicode'"))
|
|
|
|
|
if terms[1]:
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
if self.timeIni != curTime:
|
|
|
|
|
# читаем переменные из файла
|
|
|
|
|
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
|
|
|
|
|
self.currDictIni = {}
|
|
|
|
|
self.currDictIni.update(self.prevDictIni)
|
|
|
|
|
self.timeIni = self.getTimeFile(self.fileConfigIni)
|
|
|
|
|
if nameLocVar in self.currDictIni.keys():
|
|
|
|
|
unicodeValue = self.currDictIni[nameLocVar]
|
|
|
|
|
if unicodeValue is None:
|
|
|
|
|
unicodeValue = ""
|
|
|
|
|
if terms[2] in ('url', 'purl'):
|
|
|
|
|
replace = unicodeValue.encode("UTF-8"). \
|
|
|
|
|
__repr__()[1:-1].replace('\\x', '%'). \
|
|
|
|
|
replace(' ', '%20')
|
|
|
|
|
if terms[2] == 'purl':
|
|
|
|
|
replace = replace.replace('/', '%2f')
|
|
|
|
|
elif terms[2] == 'unicode':
|
|
|
|
|
replace = unicodeValue.__repr__()[2:-1]
|
|
|
|
|
else:
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
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})',
|
|
|
|
|
lambda x: chr(int(x.group(1), 16)), text)
|
|
|
|
|
|
|
|
|
|
def funcReplace(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""локальная функция заменяет в значении переменной old на new
|
|
|
|
|
|
|
|
|
|
replace(old, new, name_var_template)
|
|
|
|
|
|
|
|
|
|
одинарные и двойные кавычки должны быть обязательно использованы
|
|
|
|
|
в первых двух аргументах old и new
|
|
|
|
|
"test\ntest" - преобразование строки (строка с переводом)
|
|
|
|
|
'test\ntest' - без преобразования (одна строка)
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
return listArgv
|
|
|
|
|
|
|
|
|
|
terms = map(lambda x: x.strip(), funArgv.split(","))
|
|
|
|
|
if len(terms) != 3:
|
|
|
|
|
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))
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
def funcEnv(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""Функция шаблона env(), выдает значение переменной из env файлов
|
|
|
|
|
"""
|
|
|
|
|
terms = funArgv.replace(" ", "").split(",")
|
|
|
|
|
if len(terms) != 1:
|
|
|
|
|
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:
|
|
|
|
|
raise self.raiseErrTemplate(self.getError())
|
|
|
|
|
self.valuesVarEnv[nameVar] = value
|
|
|
|
|
replace = value
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcServer(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""Функция шаблона info(), выдает значение опций сервиса
|
|
|
|
|
|
|
|
|
|
из /var/calculate/remote/calculate.env
|
|
|
|
|
"""
|
|
|
|
|
terms = funArgv.replace(" ", "").split(",")
|
|
|
|
|
if len(terms) == 0 or len(terms) > 2:
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
nameLocalVar = ""
|
|
|
|
|
if len(terms) == 2:
|
|
|
|
|
if not terms[1]:
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
nameLocalVar = terms[1]
|
|
|
|
|
textLine = terms[0]
|
|
|
|
|
vals = textLine.split(".")
|
|
|
|
|
if len(vals) != 2:
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
if filter(lambda x: not x.strip(), vals):
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
service, option = vals
|
|
|
|
|
if not service or not option:
|
|
|
|
|
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:
|
|
|
|
|
optInfo = self.objVar.getRemoteInfo(envFile)
|
|
|
|
|
if optInfo is False:
|
|
|
|
|
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
|
|
|
|
|
elif nameLocalVar:
|
|
|
|
|
localVars[nameLocalVar] = ""
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcGroups(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""Функция шаблона groups(),
|
|
|
|
|
проверяет нахождение пользователя в группах, если находится выдает '1'
|
|
|
|
|
"""
|
|
|
|
|
terms = map(lambda x: x.strip(), funArgv.split(","))
|
|
|
|
|
groupNames = set(terms)
|
|
|
|
|
userGroups = set(self.groups)
|
|
|
|
|
replace = ""
|
|
|
|
|
if groupNames & userGroups:
|
|
|
|
|
replace = "1"
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcBelong(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
self.printWARNING(_("Function '{funcname}' used by {template} "
|
|
|
|
|
"is deprecated and will be removed in the future"
|
|
|
|
|
).format(funcname="belong", template=nameTemp))
|
|
|
|
|
replace = ""
|
|
|
|
|
return textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
|
|
|
|
|
def funcMerge(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""
|
|
|
|
|
Belong function use value in first arg and compare it
|
|
|
|
|
for all values in cl_merge_pkg.
|
|
|
|
|
If cl_merge_pkg empty or first arg <=cl_belogn_pkg
|
|
|
|
|
then "1" else ""
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
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):
|
|
|
|
|
skip_data_varname = 'cl_setup_skip_%s' % 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(
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
terms = funArgv.replace(" ", "").split(",")
|
|
|
|
|
if len(terms) != 1:
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
funcPkg = terms[0]
|
|
|
|
|
if not funcPkg:
|
|
|
|
|
funcPkg = self.get_pkgname_by_filename(self.nameTemplate)
|
|
|
|
|
self.currentBelong = funcPkg
|
|
|
|
|
if self.objVar.Get('cl_action') == 'patch':
|
|
|
|
|
if funcPkg == "%s/%s" % (
|
|
|
|
|
self.objVar.Get('core.cl_core_pkg_category'),
|
|
|
|
|
self.objVar.Get('core.cl_core_pkg_name')):
|
|
|
|
|
replace = self.objVar.Get('core.cl_core_pkg_version')
|
|
|
|
|
if check_skip(funcPkg):
|
|
|
|
|
replace = ""
|
|
|
|
|
else:
|
|
|
|
|
replace = ""
|
|
|
|
|
else:
|
|
|
|
|
pkg = self.objVar.Get("cl_merge_pkg")
|
|
|
|
|
replace = ""
|
|
|
|
|
if pkg:
|
|
|
|
|
if funcPkg in pkg:
|
|
|
|
|
replace = "1"
|
|
|
|
|
else:
|
|
|
|
|
replace = "1"
|
|
|
|
|
if replace == "1" and check_skip(funcPkg):
|
|
|
|
|
replace = ""
|
|
|
|
|
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def funcList(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""Функция шаблона list().
|
|
|
|
|
Если первый аргумент является именем локальной или глобальной
|
|
|
|
|
переменной и значение переменной является списком, выдает
|
|
|
|
|
элемент списка по второму аргументу индексу.
|
|
|
|
|
Первый элемент имеет индекс 0
|
|
|
|
|
"""
|
|
|
|
|
terms = funArgv.replace(" ", "").split(",")
|
|
|
|
|
# У функции должно быть два аргумента
|
|
|
|
|
if len(terms) != 2:
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
# Название локальной или глобальной переменной
|
|
|
|
|
nameLocVar = terms[0]
|
|
|
|
|
strIndex = terms[1]
|
|
|
|
|
try:
|
|
|
|
|
try:
|
|
|
|
|
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:
|
|
|
|
|
replace = str(value[intIndex])
|
|
|
|
|
else:
|
|
|
|
|
replace = ""
|
|
|
|
|
return textTemplateTmp[:resS.start()] + replace + \
|
|
|
|
|
textTemplateTmp[resS.end():]
|
|
|
|
|
except TemplatesError as e:
|
|
|
|
|
raise self.raiseErrTemplate(str(e))
|
|
|
|
|
|
|
|
|
|
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_второй_аргумент с этим индексом
|
|
|
|
|
"""
|
|
|
|
|
terms = funArgv.replace(" ", "").split(",")
|
|
|
|
|
# У функции должно быть два аргумента
|
|
|
|
|
if len(terms) != 2:
|
|
|
|
|
raise self.raiseErrTemplate()
|
|
|
|
|
# Название глобальной переменной
|
|
|
|
|
mountPoint = terms[0]
|
|
|
|
|
lastElementVar = terms[1]
|
|
|
|
|
if not mountPoint or mountPoint[:1] != "/":
|
|
|
|
|
raise self.raiseErrTemplate(_("wrong %s") % lastElementVar)
|
|
|
|
|
nameVar = "install.os_install_disk_mount"
|
|
|
|
|
try:
|
|
|
|
|
try:
|
|
|
|
|
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):
|
|
|
|
|
if mountPoint == mPoint:
|
|
|
|
|
index = num
|
|
|
|
|
break
|
|
|
|
|
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))
|
|
|
|
|
|
|
|
|
|
def funcModule(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
|
|
|
|
|
"""Функция шаблона module(), выдает значение аттрибута api.
|
|
|
|
|
|
|
|
|
|
аргумент:
|
|
|
|
|
путь_к_атрибуту - путь к аттрибуту
|
|
|
|
|
|
|
|
|
|
возможные пути:
|
|
|
|
|
имя_пакета.var.имя_переменной - получаем значение переменной
|
|
|
|
|
имя_пакета.имя_метода_api - выполнение метода, получение результата
|
|
|
|
|
all.имя_метода_api - выполнение метода для всех пакетов с api
|
|
|
|
|
"""
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def raiseErrTemplate(self, message=""):
|
|
|
|
|
"""Возвращает ошибки при обработке функций шаблона"""
|
|
|
|
|
if message:
|
|
|
|
|
message = "%s\n" % message
|
|
|
|
|
else:
|
|
|
|
|
message = ""
|
|
|
|
|
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
|
|
|
|
|
resS = reFunc.search(textTemplate)
|
|
|
|
|
textTemplateTmp = textTemplate
|
|
|
|
|
flagIniFunc = False
|
|
|
|
|
writeIniFunc = False
|
|
|
|
|
while resS:
|
|
|
|
|
mark = textTemplateTmp[resS.start():resS.end()]
|
|
|
|
|
self.functText = mark[self._deltVarStart:-self._deltVarEnd]
|
|
|
|
|
funcName, spl, funcEnd = self.functText.partition("(")
|
|
|
|
|
if funcName in self.namesTemplateFunction:
|
|
|
|
|
# аргументы функции - '(' аргументы ')'
|
|
|
|
|
funArgv = funcEnd.rpartition(")")[0]
|
|
|
|
|
# вызов функции шаблона
|
|
|
|
|
textTemplateTmp = self.templateFunction[funcName](self, funArgv,
|
|
|
|
|
resS,
|
|
|
|
|
localVars,
|
|
|
|
|
textTemplateTmp,
|
|
|
|
|
nameTemplate)
|
|
|
|
|
resS = reFunc.search(textTemplateTmp)
|
|
|
|
|
if funcName == "ini":
|
|
|
|
|
if "," in funArgv:
|
|
|
|
|
writeIniFunc = True
|
|
|
|
|
flagIniFunc = True
|
|
|
|
|
else:
|
|
|
|
|
raise self.raiseErrTemplate(
|
|
|
|
|
_("function of templates '%s' not found") \
|
|
|
|
|
% str(self.functText))
|
|
|
|
|
if flagIniFunc:
|
|
|
|
|
# Очистка файла в случае его ошибочного чтения
|
|
|
|
|
if not self.prevDictIni and os.path.exists(self.fileConfigIni):
|
|
|
|
|
FD = open(self.fileConfigIni, "r+")
|
|
|
|
|
FD.truncate(0)
|
|
|
|
|
FD.seek(0)
|
|
|
|
|
FD.close()
|
|
|
|
|
# Если конф. файл модифицирован шаблоном
|
|
|
|
|
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")
|
|
|
|
|
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 filter(lambda x: not config[x],
|
|
|
|
|
config.sections()):
|
|
|
|
|
config.remove_section(section)
|
|
|
|
|
with open(self.fileConfigIni, 'wb') 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)
|
|
|
|
|
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):
|
|
|
|
|
uid, gid = getModeFile(self.fileConfigIni, "owner")
|
|
|
|
|
if not self.uid in (uid, PORTAGEUID) or \
|
|
|
|
|
not self.gid in (gid, PORTAGEGID):
|
|
|
|
|
try:
|
|
|
|
|
os.chown(self.fileConfigIni, self.uid, self.gid)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(_("error") + " " +
|
|
|
|
|
"'chown %d:%d %s'" % (self.uid, self.gid,
|
|
|
|
|
self.fileConfigIni))
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ChangedFiles:
|
|
|
|
|
"""
|
|
|
|
|
Object which contains modified files and package
|
|
|
|
|
"""
|
|
|
|
|
FILE_MODIFIED, FILE_REMOVED, DIR_CREATED, DIR_REMOVED, DIR_EXISTS = 0, 1, 2, 3, 4
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.data = {}
|
|
|
|
|
self.pkgs = set()
|
|
|
|
|
|
|
|
|
|
def _createEntry(self, fn):
|
|
|
|
|
if not fn in self.data:
|
|
|
|
|
self.data[fn] = []
|
|
|
|
|
|
|
|
|
|
def addObj(self, filename, action, pkg):
|
|
|
|
|
self._createEntry(filename)
|
|
|
|
|
self.data[filename].append((pkg, action))
|
|
|
|
|
self.pkgs.add(pkg)
|
|
|
|
|
|
|
|
|
|
def getPkgs(self):
|
|
|
|
|
return self.pkgs
|
|
|
|
|
|
|
|
|
|
def getPkgFiles(self, pkg):
|
|
|
|
|
return map(lambda x: (x[0], x[1][0][1]),
|
|
|
|
|
filter(lambda x: x[1],
|
|
|
|
|
map(lambda x: (
|
|
|
|
|
x[0], filter(lambda x: x[0] == pkg, x[1])),
|
|
|
|
|
self.data.items())))
|
|
|
|
|
|
|
|
|
|
# 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)
|
|
|
|
|
T_ORIGIN, T_CFG, T_NEWCFG = 0, 1, 2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Template(_file, _terms, _warning, xmlShare, templateFormat,
|
|
|
|
|
_shareTemplate):
|
|
|
|
|
"""Класс для работы с шаблонами
|
|
|
|
|
|
|
|
|
|
На вход 2 параметра: объект хранения переменных, имя сервиса - не
|
|
|
|
|
обязательный параметр
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
# Название файла шаблона директории
|
|
|
|
|
templDirNameFile = ".calculate_directory"
|
|
|
|
|
_titleList = ("Modified", "Processed template files" + ":")
|
|
|
|
|
titleEnd = "For modify this file, create %(conf_path)s.clt template."
|
|
|
|
|
protectPaths = []
|
|
|
|
|
allContents = {}
|
|
|
|
|
if "CONFIG_PROTECT" in os.environ:
|
|
|
|
|
protectPaths = ["/etc"] + filter(lambda x: x.strip(),
|
|
|
|
|
os.environ["CONFIG_PROTECT"].split(
|
|
|
|
|
" "))
|
|
|
|
|
protectPaths = map(lambda x: os.path.normpath(x), protectPaths)
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def removeComment(cls, text):
|
|
|
|
|
re_comment = re.compile('(?:<!--|[{symb}]-*)\n'
|
|
|
|
|
'[{symb}]? {modified} .*\n'
|
|
|
|
|
'[{symb}]? {processed}\n'
|
|
|
|
|
'([{symb}]? /.*\n'
|
|
|
|
|
')+[{symb}]? {endtitle}.*\n'
|
|
|
|
|
r'(-->|[{symb}]-*)\n'.format(
|
|
|
|
|
modified=cls._titleList[0],
|
|
|
|
|
processed=cls._titleList[1],
|
|
|
|
|
endtitle=cls.titleEnd % {'conf_path': '.*'},
|
|
|
|
|
symb='"#'
|
|
|
|
|
))
|
|
|
|
|
return re_comment.sub('', text)
|
|
|
|
|
|
|
|
|
|
def hasError(self):
|
|
|
|
|
return self.getError() or self.bHasError
|
|
|
|
|
|
|
|
|
|
def __init__(self, objVar, servDir=False, dirsFilter=(), filesFilter=(),
|
|
|
|
|
cltObj=True, cltFilter=True, printWarning=True,
|
|
|
|
|
printSUCCESS=lambda x: x, printWARNING=lambda x: x,
|
|
|
|
|
printERROR=lambda x: x, askConfirm=lambda x: x,
|
|
|
|
|
userProfile=False, dispatchConf=None):
|
|
|
|
|
# совместимость с вызовами из модулей предыдущих версий
|
|
|
|
|
self.translator = RegexpLocalization("cl_templates3")
|
|
|
|
|
if userProfile and objVar:
|
|
|
|
|
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.printERROR = printERROR
|
|
|
|
|
self.postmergePkgs = []
|
|
|
|
|
self.postmergeFile = "/var/lib/calculate/-postmerge"
|
|
|
|
|
self.bHasError = False
|
|
|
|
|
if printERROR:
|
|
|
|
|
def newSetError(s):
|
|
|
|
|
self.printERROR(s)
|
|
|
|
|
self.bHasError = True
|
|
|
|
|
|
|
|
|
|
self.setError = newSetError
|
|
|
|
|
self.printWARNING = printWARNING
|
|
|
|
|
self.askConfirm = askConfirm
|
|
|
|
|
self.cltObj = None
|
|
|
|
|
self.functObj = None
|
|
|
|
|
# Предупреждения
|
|
|
|
|
# self.warning = []
|
|
|
|
|
# Печатать ли предупреждения о корневых шаблонах без cl_name==pkg
|
|
|
|
|
self.printWarning = printWarning
|
|
|
|
|
# Необрабатываемые директории
|
|
|
|
|
self.dirsFilter = dirsFilter
|
|
|
|
|
# Необрабатываемые файлы
|
|
|
|
|
self.filesFilter = filesFilter
|
|
|
|
|
_file.__init__(self)
|
|
|
|
|
# Словарь для создания объектов новых классов по образцу
|
|
|
|
|
self.newObjProt = {'proftpd': 'apache'}
|
|
|
|
|
# Заголовок title
|
|
|
|
|
self.__titleHead = "--------------------------------------\
|
|
|
|
|
----------------------------------------"
|
|
|
|
|
self._titleBody = ""
|
|
|
|
|
self._reVar = re.compile(
|
|
|
|
|
"%s(?:[a-z0-9_]+\.)?[a-zA-Z0-9_-]+%s" % (self.varStart,
|
|
|
|
|
self.varEnd), re.M)
|
|
|
|
|
# Условия
|
|
|
|
|
self._reTermBloc = re.compile(
|
|
|
|
|
"#\?(?P<rTerm>(?:[a-z0-9_]+\.)?[a-zA-Z0-9\-_]+)"
|
|
|
|
|
"(?P<func>\((%s+|)\))?"
|
|
|
|
|
"(?P<lTerm>[><=!&\|]+"
|
|
|
|
|
"[><=!\|&\(\)%s]*)#"
|
|
|
|
|
"\n*(?P<body>.+?)\n*#(?P=rTerm)#(?P<end>[ ,\t]*\n?)"
|
|
|
|
|
% (self._reFunctionArgvText, self._reFunctionArgvInSquareBrackets),
|
|
|
|
|
re.M | re.S)
|
|
|
|
|
# Объект с переменными
|
|
|
|
|
self.objVar = objVar
|
|
|
|
|
self.recalculateBaseDir()
|
|
|
|
|
# Последняя часть директории шаблона (имя сервиса: samba, mail)
|
|
|
|
|
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 = self.objVar.Get("cl_name").capitalize()
|
|
|
|
|
# версия текущей программы
|
|
|
|
|
_versionProgram = self.objVar.Get("cl_ver")
|
|
|
|
|
# имя и версия текущей программы
|
|
|
|
|
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
|
|
|
|
|
if self.printERROR:
|
|
|
|
|
self.functObj.setError = self.printERROR
|
|
|
|
|
self.functObj.askConfirm = self.askConfirm
|
|
|
|
|
# Метод применения функций к шаблонам
|
|
|
|
|
self.applyFuncTemplate = self.functObj.applyFuncTemplate
|
|
|
|
|
# Объект для определения типа файла шаблона
|
|
|
|
|
self.typeFileObj = typeFile()
|
|
|
|
|
# Глобальный словарь обработанных шаблонов файлов
|
|
|
|
|
# {путь к конф. файлу:[имена шаблонов] ...}
|
|
|
|
|
self.dictProcessedTemplates = {}
|
|
|
|
|
if cltObj is True:
|
|
|
|
|
# Объект templateClt
|
|
|
|
|
self.cltObj = templateClt(self.objVar, self.postmergePkgs,
|
|
|
|
|
printSUCCESS=self.printSUCCESS,
|
|
|
|
|
printERROR=self.printERROR,
|
|
|
|
|
printWARNING=self.printWARNING,
|
|
|
|
|
askConfirm=self.askConfirm)
|
|
|
|
|
elif cltObj:
|
|
|
|
|
# Объект templateClt
|
|
|
|
|
self.cltObj = cltObj
|
|
|
|
|
else:
|
|
|
|
|
# Объект templateClt
|
|
|
|
|
self.cltObj = None
|
|
|
|
|
# Фильтровать ли шаблоны clt по конфигурационным файлам обычных шаблонов
|
|
|
|
|
self.cltFilter = cltFilter
|
|
|
|
|
# autoupdate файлы
|
|
|
|
|
self.autoUpdateFiles = []
|
|
|
|
|
self.autoUpdateDirs = []
|
|
|
|
|
|
|
|
|
|
self.protectedFiles = 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()
|
|
|
|
|
|
|
|
|
|
def _addFile(self, filesApl, pkg=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)
|
|
|
|
|
else:
|
|
|
|
|
self.changedFiles.addObj(fn, ChangedFiles.FILE_REMOVED,
|
|
|
|
|
pkg or self.functObj.currentBelong)
|
|
|
|
|
|
|
|
|
|
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():
|
|
|
|
|
self.executedFiles.append((code, execPath))
|
|
|
|
|
if p.readerr():
|
|
|
|
|
for line in p.readerr().split('\n'):
|
|
|
|
|
if line:
|
|
|
|
|
line = self.translator.translate(line)
|
|
|
|
|
self.printWARNING(line.strip())
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
if p.readerr():
|
|
|
|
|
for line in p.readerr().split('\n'):
|
|
|
|
|
if line:
|
|
|
|
|
line = self.translator.translate(line)
|
|
|
|
|
self.printERROR(line.strip())
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def __octToInt(self, strOct):
|
|
|
|
|
"""Преобразование восьмеричного в целое (ввод строка, вывод число)"""
|
|
|
|
|
if strOct:
|
|
|
|
|
try:
|
|
|
|
|
res = string.atoi(strOct, 8)
|
|
|
|
|
except ValueError:
|
|
|
|
|
self.setError(_("Invalid oct value: ") + str(strOct))
|
|
|
|
|
return False
|
|
|
|
|
return res
|
|
|
|
|
else:
|
|
|
|
|
self.setError(_("Empty oct value"))
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def getTemplateType(self):
|
|
|
|
|
"""выдать тип шаблона (text, bin)"""
|
|
|
|
|
return self.getFileType(self.nameFileTemplate)
|
|
|
|
|
|
|
|
|
|
def getFileType(self, fileName):
|
|
|
|
|
"""выдать тип файла (text, bin)"""
|
|
|
|
|
isBin = self.typeFileObj.isBinary(fileName)
|
|
|
|
|
if isBin is True:
|
|
|
|
|
typeTemplate = "bin"
|
|
|
|
|
elif isBin is False:
|
|
|
|
|
typeTemplate = "text"
|
|
|
|
|
else:
|
|
|
|
|
self.setError(_("ERROR") + ": getFileType()")
|
|
|
|
|
self.setError(isBin)
|
|
|
|
|
return False
|
|
|
|
|
return typeTemplate
|
|
|
|
|
|
|
|
|
|
def createDir(self, dirName, mode=False, uid=False, gid=False):
|
|
|
|
|
"""Создает директорию"""
|
|
|
|
|
if os.access(dirName, os.F_OK):
|
|
|
|
|
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:
|
|
|
|
|
dUid, dGid = getModeFile(prevDir, "owner")
|
|
|
|
|
except OSError:
|
|
|
|
|
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)
|
|
|
|
|
os.chown(nameDir, dUid, dGid)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(_("Failed to create the directory: ")
|
|
|
|
|
+ nameDir)
|
|
|
|
|
return False
|
|
|
|
|
try:
|
|
|
|
|
if dMode:
|
|
|
|
|
os.mkdir(dirName, dMode)
|
|
|
|
|
os.chmod(dirName, dMode)
|
|
|
|
|
else:
|
|
|
|
|
os.mkdir(dirName)
|
|
|
|
|
os.chown(dirName, dUid, dGid)
|
|
|
|
|
createDirs.append(dirName)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(_("Failed to create the directory: ")
|
|
|
|
|
+ dirName)
|
|
|
|
|
return False
|
|
|
|
|
return createDirs
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
except DataVarsError, e:
|
|
|
|
|
raise TemplatesError(_("error in template %s") % nameTemplate
|
|
|
|
|
+ "\n" + str(e))
|
|
|
|
|
textTemplateTmp = textTemplateTmp.replace(mark, varValue)
|
|
|
|
|
resS = self._reVar.search(textTemplateTmp)
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def applyTermsTemplate(self, textTemplate, nameTemplate):
|
|
|
|
|
""" Применяет условия, к условным блокам текста
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def function(text):
|
|
|
|
|
"""Функция обработки функций в заголовке"""
|
|
|
|
|
return self.applyFuncTemplate(text, nameTemplate)
|
|
|
|
|
|
|
|
|
|
resS = self._reTermBloc.search(textTemplate)
|
|
|
|
|
textTemplateTmp = textTemplate
|
|
|
|
|
while resS:
|
|
|
|
|
mark = resS.group(0)
|
|
|
|
|
body = resS.group("body")
|
|
|
|
|
end = resS.group("end")
|
|
|
|
|
parent = resS.group("func")
|
|
|
|
|
if not parent:
|
|
|
|
|
parent = ""
|
|
|
|
|
term = resS.group("rTerm") + parent + \
|
|
|
|
|
resS.group("lTerm")
|
|
|
|
|
if self._equalTerm(term, _("invalid template content: ") + \
|
|
|
|
|
nameTemplate, function):
|
|
|
|
|
textTemplateTmp = textTemplateTmp.replace(mark, body + end)
|
|
|
|
|
else:
|
|
|
|
|
textTemplateTmp = textTemplateTmp.replace(mark, "")
|
|
|
|
|
resS = self._reTermBloc.search(textTemplateTmp)
|
|
|
|
|
return textTemplateTmp
|
|
|
|
|
|
|
|
|
|
def getNeedTemplate(self, fileTemplate):
|
|
|
|
|
"""Применяем правила к названию файла"""
|
|
|
|
|
dirP, fileP = os.path.split(fileTemplate)
|
|
|
|
|
if fileP:
|
|
|
|
|
spFile = fileP.split("?")
|
|
|
|
|
if len(spFile) > 1:
|
|
|
|
|
flagTrue = False
|
|
|
|
|
for term in spFile[1:]:
|
|
|
|
|
if self._equalTerm(term, _("invalid template name: ") + \
|
|
|
|
|
fileTemplate):
|
|
|
|
|
flagTrue = True
|
|
|
|
|
break
|
|
|
|
|
if flagTrue:
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
self.setError(_("invalid template name: ") + str(fileTemplate))
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def getTitle(self, comment, commentList, configPath=""):
|
|
|
|
|
"""Выдает заголовок шаблона ( версия и.т.д)"""
|
|
|
|
|
if configPath and self.protectPaths:
|
|
|
|
|
flagFoundPath = False
|
|
|
|
|
for protectPath in self.protectPaths:
|
|
|
|
|
if self._baseDir != "/":
|
|
|
|
|
lenBaseDir = len(self._baseDir)
|
|
|
|
|
if len(configPath) > lenBaseDir and \
|
|
|
|
|
configPath[:lenBaseDir] == self._baseDir:
|
|
|
|
|
configPath = configPath[lenBaseDir:]
|
|
|
|
|
if configPath.startswith(protectPath + "/"):
|
|
|
|
|
flagFoundPath = True
|
|
|
|
|
break
|
|
|
|
|
if flagFoundPath:
|
|
|
|
|
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]
|
|
|
|
|
commentList = commentList + \
|
|
|
|
|
[self.titleEnd % {'conf_path': origConfigPath}]
|
|
|
|
|
if comment:
|
|
|
|
|
commentFirst = comment
|
|
|
|
|
commentInsert = comment
|
|
|
|
|
commentLast = comment
|
|
|
|
|
flagList = False
|
|
|
|
|
# В случае открывающего и закрывающего комментария
|
|
|
|
|
if type(comment) == types.TupleType 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
|
|
|
|
|
for com in list(self._titleList) + [""] * (len(commentList)):
|
|
|
|
|
if com:
|
|
|
|
|
if flagFirst:
|
|
|
|
|
self._titleBody += commentInsert + " " + com + " " + \
|
|
|
|
|
self.programVersion + "\n"
|
|
|
|
|
flagFirst = False
|
|
|
|
|
else:
|
|
|
|
|
self._titleBody += commentInsert + " " + com + "\n"
|
|
|
|
|
else:
|
|
|
|
|
self._titleBody += commentInsert + " " + \
|
|
|
|
|
commentList[z] + "\n"
|
|
|
|
|
z += 1
|
|
|
|
|
if flagList:
|
|
|
|
|
self._titleBody += commentLast + "\n"
|
|
|
|
|
else:
|
|
|
|
|
self._titleBody += commentLast + self.__titleHead + "\n"
|
|
|
|
|
return self._titleBody
|
|
|
|
|
else:
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
def changeMergePackage(self, package):
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def numberAllTemplates(self, number):
|
|
|
|
|
"""Количество шаблонов
|
|
|
|
|
|
|
|
|
|
Вызов происходит перед наложением шаблонов
|
|
|
|
|
в момент вызова в number находится количество обрабатываемых файлов
|
|
|
|
|
Наследуемая функция
|
|
|
|
|
Используется для отображения прогресса при наложениии шаблонов
|
|
|
|
|
"""
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def numberProcessTemplates(self, number):
|
|
|
|
|
"""Номер текущего обрабатываемого шаблона
|
|
|
|
|
|
|
|
|
|
Вызов происходит при наложении шаблона
|
|
|
|
|
в момент вызова в number находится номер обрабатываемого шаблона
|
|
|
|
|
Наследуемая функция
|
|
|
|
|
Используется для отображения прогресса при наложениии шаблонов
|
|
|
|
|
"""
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def templateModify(self):
|
|
|
|
|
"""
|
|
|
|
|
Files which created by apping templates
|
|
|
|
|
"""
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def fixNameFileConfig(self, origfilename):
|
|
|
|
|
"""Support ._cfg0000 files for postinst"""
|
|
|
|
|
# if self.objVar.Get('cl_ebuild_phase') != 'postinst':
|
|
|
|
|
# return origfilename
|
|
|
|
|
directory, filename = os.path.split(origfilename)
|
|
|
|
|
for i in range(0, 9999):
|
|
|
|
|
if not os.path.exists(os.path.join(directory,
|
|
|
|
|
"._cfg%04d_%s" % (i, filename))):
|
|
|
|
|
if i:
|
|
|
|
|
filename = os.path.join(directory,
|
|
|
|
|
"._cfg%04d_%s" % (i - 1, filename))
|
|
|
|
|
if not os.path.exists(origfilename):
|
|
|
|
|
return origfilename
|
|
|
|
|
# origstat = os.stat(origfilename)[stat.ST_CTIME]
|
|
|
|
|
# newstat = os.stat(filename)[stat.ST_CTIME]
|
|
|
|
|
self.configMode = T_CFG
|
|
|
|
|
return filename
|
|
|
|
|
return origfilename
|
|
|
|
|
return origfilename
|
|
|
|
|
|
|
|
|
|
def getHeaderText(self, text):
|
|
|
|
|
textLines = text.splitlines()
|
|
|
|
|
paramLine = ""
|
|
|
|
|
if textLines:
|
|
|
|
|
textLine = textLines[0]
|
|
|
|
|
rePar = re.compile(
|
|
|
|
|
"\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$", re.I)
|
|
|
|
|
reP = rePar.search(textLine)
|
|
|
|
|
if reP:
|
|
|
|
|
reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*", re.M)
|
|
|
|
|
reLs = reLns.search(text)
|
|
|
|
|
if reLs:
|
|
|
|
|
paramLine = text[reP.end():reLs.end()]
|
|
|
|
|
paramLine = paramLine.replace("\\", " ")
|
|
|
|
|
else:
|
|
|
|
|
paramLine = textLine[reP.end():]
|
|
|
|
|
return paramLine
|
|
|
|
|
|
|
|
|
|
def getTemplateDirs(self, dirsTemplates):
|
|
|
|
|
"""Check template variable cl_name in first directories and files"""
|
|
|
|
|
skipDirs = []
|
|
|
|
|
skipTemplates = []
|
|
|
|
|
debug = False
|
|
|
|
|
for dirsTemplate in dirsTemplates:
|
|
|
|
|
filesAndDirs = map(lambda x: os.path.join(dirsTemplate, x),
|
|
|
|
|
listDirectory(dirsTemplate))
|
|
|
|
|
for dirFile in filesAndDirs:
|
|
|
|
|
if os.path.isdir(dirFile):
|
|
|
|
|
flagDir = True
|
|
|
|
|
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:
|
|
|
|
|
textTemplate = open(templatePath).read()
|
|
|
|
|
if textTemplate:
|
|
|
|
|
headerLine = self.getHeaderText(textTemplate)
|
|
|
|
|
if headerLine:
|
|
|
|
|
if not debug and \
|
|
|
|
|
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:
|
|
|
|
|
skipTempl = os.path.join(skipDir, self.templDirNameFile)
|
|
|
|
|
if os.path.isfile(skipTempl):
|
|
|
|
|
skipDirTemplates.append(skipTempl)
|
|
|
|
|
if skipTemplates or skipDirTemplates:
|
|
|
|
|
self.printWARNING(_("Skipped templates:"))
|
|
|
|
|
for skipTemplate in skipTemplates + skipDirTemplates:
|
|
|
|
|
self.printWARNING(" " * 6 + skipTemplate)
|
|
|
|
|
if skipDirs:
|
|
|
|
|
self.printWARNING(_("Skipped directories:"))
|
|
|
|
|
for skipDir in skipDirs:
|
|
|
|
|
self.printWARNING(" " * 6 + skipDir)
|
|
|
|
|
self.printWARNING("")
|
|
|
|
|
self.printWARNING(_("Headers of directory templates and headers "
|
|
|
|
|
"of files on the first level should include "
|
|
|
|
|
"an action variable"))
|
|
|
|
|
self.printWARNING(_("Example:"))
|
|
|
|
|
self.printWARNING("# Calculate ac_install_merge==on")
|
|
|
|
|
return skipDirs + skipTemplates
|
|
|
|
|
|
|
|
|
|
@catch_no_space_left
|
|
|
|
|
def applyTemplates(self, progress=True, rerun=True):
|
|
|
|
|
"""Применяет шаблоны к конфигурационным файлам"""
|
|
|
|
|
|
|
|
|
|
def createDictTemplates(path, prefix, dictTemplates):
|
|
|
|
|
"""Создает словарь {"директория":"кол-во шаблонов" ...}
|
|
|
|
|
|
|
|
|
|
и считает общее количество шаблонов
|
|
|
|
|
"""
|
|
|
|
|
# Количество шаблонов
|
|
|
|
|
self.allTemplates += 1
|
|
|
|
|
dirTemplate = os.path.split(path)[0]
|
|
|
|
|
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()
|
|
|
|
|
self.clearWarnings()
|
|
|
|
|
if not self.objVar.defined("cl_template_path_use"):
|
|
|
|
|
self.setError(_("undefined variable: ") + "cl_template_path_use")
|
|
|
|
|
return False
|
|
|
|
|
dirsTemplates = self.objVar.Get("cl_template_path_use")
|
|
|
|
|
# Созданные директории
|
|
|
|
|
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 = {}
|
|
|
|
|
self.functObj.currentBelong = ""
|
|
|
|
|
self.functObj.currentAction = "merge"
|
|
|
|
|
# Словарь времен модификации 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
|
|
|
|
|
scanObj = scanDirectory()
|
|
|
|
|
scanObj.processingFile = lambda x, y: createDictTemplates(x, y,
|
|
|
|
|
self.dictTemplates)
|
|
|
|
|
# Считаем количество шаблонов
|
|
|
|
|
dirsTemplatesExists = filter(lambda x: os.path.exists(x), dirsTemplates)
|
|
|
|
|
if not dirsTemplatesExists and not self.cltObj:
|
|
|
|
|
return self.createdDirs, self.filesApply
|
|
|
|
|
# check cl_name in first template dirs and files
|
|
|
|
|
skipTemplates = self.getTemplateDirs(dirsTemplatesExists)
|
|
|
|
|
# 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
|
|
|
|
|
# метод показывающий номер 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',
|
|
|
|
|
'main.cl_template_location'))
|
|
|
|
|
for dirTemplate in dirsTemplatesExists:
|
|
|
|
|
self.objVar.Set('cl_pass_location',
|
|
|
|
|
locationPath.get(dirTemplate, dirTemplate),
|
|
|
|
|
force=True)
|
|
|
|
|
if self.scanningTemplates(dirTemplate,
|
|
|
|
|
skipTemplates=skipTemplates) is False:
|
|
|
|
|
break
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
if self.cltFilter:
|
|
|
|
|
# Шаблоны + .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
|
|
|
|
|
category = isPkgInstalled(pkg)
|
|
|
|
|
if category:
|
|
|
|
|
pkgContents = PkgContents("{CATEGORY}/{PF}".format(
|
|
|
|
|
**category[0]))
|
|
|
|
|
for filename in pkgContents.content.keys():
|
|
|
|
|
if not filename in self.cltObj.filterApplyTemplates:
|
|
|
|
|
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:
|
|
|
|
|
self.cltObj.filterApplyTemplates[filename] = []
|
|
|
|
|
pkgs = filter(
|
|
|
|
|
lambda x: x not in
|
|
|
|
|
self.cltObj.filterApplyTemplates[filename],
|
|
|
|
|
map(lambda x: x[0], pkgs))
|
|
|
|
|
self.cltObj.filterApplyTemplates[filename].extend(pkgs)
|
|
|
|
|
self.cltObj.applyTemplatesClt()
|
|
|
|
|
if ((self.objVar.Get('cl_merge_pkg') or
|
|
|
|
|
self.objVar.Get('cl_action') in (
|
|
|
|
|
"sync", "domain",
|
|
|
|
|
"undomain")) and
|
|
|
|
|
self.objVar.Get('cl_merge_pkg_new')):
|
|
|
|
|
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(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
|
|
|
|
|
if rerun:
|
|
|
|
|
if self.cltObj:
|
|
|
|
|
self.queueExecute.extend(self.cltObj.queueExecute)
|
|
|
|
|
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_protect_use_set') == 'on':
|
|
|
|
|
self.updateProtectedFiles()
|
|
|
|
|
if self.objVar.Get('cl_verbose_set') == 'on' and \
|
|
|
|
|
self.filesApply:
|
|
|
|
|
self.verboseOutput(
|
|
|
|
|
filter(lambda x: not x.endswith('/ini.env'),
|
|
|
|
|
self.filesApply))
|
|
|
|
|
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
|
|
|
|
|
self.printWARNING(_("Calculate Utilities have changed files") + _(":"))
|
|
|
|
|
reGrey = re.compile(r"\._cfg\d{4}_")
|
|
|
|
|
rootPath = self.objVar.Get('cl_root_path')
|
|
|
|
|
for fn in sorted(list(set(filesApply))):
|
|
|
|
|
if rootPath != '/' and self.objVar.Get('cl_action') == 'patch' and \
|
|
|
|
|
fn.startswith(rootPath):
|
|
|
|
|
fn = fn[len(rootPath) + 1:]
|
|
|
|
|
if reGrey.search(fn):
|
|
|
|
|
self.printSUCCESS(" " * 5 + \
|
|
|
|
|
"<font color=\"dark gray\">%s</font>" % fn)
|
|
|
|
|
else:
|
|
|
|
|
self.printSUCCESS(" " * 5 + fn)
|
|
|
|
|
|
|
|
|
|
def updateProtectedFiles(self):
|
|
|
|
|
"""
|
|
|
|
|
Update ._cfg0000 files
|
|
|
|
|
"""
|
|
|
|
|
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)
|
|
|
|
|
autoUpdateDict = {}
|
|
|
|
|
for pkg in list(set(filter(None, list(self.changedFiles.getPkgs()) +
|
|
|
|
|
self.objVar.Get('cl_merge_pkg')))):
|
|
|
|
|
category = isPkgInstalled(pkg, prefix=chrootPath)
|
|
|
|
|
if category:
|
|
|
|
|
pkgContents = PkgContents("{CATEGORY}/{PF}".format(
|
|
|
|
|
**category[0]), prefix=chrootPath)
|
|
|
|
|
for filename, action in self.changedFiles.getPkgFiles(pkg):
|
|
|
|
|
if filename in self.protectedFiles:
|
|
|
|
|
pkgContents.removeObject(filename)
|
|
|
|
|
continue
|
|
|
|
|
if action in (ChangedFiles.FILE_MODIFIED,
|
|
|
|
|
ChangedFiles.DIR_CREATED,
|
|
|
|
|
ChangedFiles.DIR_EXISTS):
|
|
|
|
|
pkgContents.addObject(filename)
|
|
|
|
|
elif action in (ChangedFiles.FILE_REMOVED,
|
|
|
|
|
ChangedFiles.DIR_REMOVED):
|
|
|
|
|
pkgContents.removeObject(filename)
|
|
|
|
|
files = set(map(lambda x: pathJoin(chrootPath, x),
|
|
|
|
|
pkgContents.content.keys()))
|
|
|
|
|
if (self.objVar.Get('cl_dispatch_conf') != 'usenew' and
|
|
|
|
|
self.objVar.Get('cl_autoupdate_set') != "on"):
|
|
|
|
|
notUpdate = files - set(self.autoUpdateFiles)
|
|
|
|
|
files &= set(self.autoUpdateFiles)
|
|
|
|
|
for filename in list(notUpdate & set(cfgs.keys())):
|
|
|
|
|
if hashlib.md5(readFile(filename)).hexdigest() == \
|
|
|
|
|
hashlib.md5(readFile(
|
|
|
|
|
cfgs[filename][0][1])).hexdigest():
|
|
|
|
|
files.add(filename)
|
|
|
|
|
|
|
|
|
|
for filename in list(files & set(cfgs.keys())):
|
|
|
|
|
# get ctime from orig filename
|
|
|
|
|
# if os.path.exists(filename):
|
|
|
|
|
# ctime = os.stat(filename).st_ctime
|
|
|
|
|
# else:
|
|
|
|
|
# ctime = 0
|
|
|
|
|
# if orig filename older that .cfg
|
|
|
|
|
cfgs[filename].sort(reverse=True)
|
|
|
|
|
# if ctime < cfgs[filename][0][0]:
|
|
|
|
|
try:
|
|
|
|
|
open(filename, 'w').write(
|
|
|
|
|
readFile(cfgs[filename][0][1]))
|
|
|
|
|
except Exception as e:
|
|
|
|
|
self.printERROR(str(e))
|
|
|
|
|
self.printWARNING(
|
|
|
|
|
_("Failed to copy {ffrom} to {fto}").format(
|
|
|
|
|
ffrom=cfgs[filename][0][1], fto=filename))
|
|
|
|
|
continue
|
|
|
|
|
autoUpdateDict[cfgs[filename][0][1]] = filename
|
|
|
|
|
for mtime, fn in cfgs[filename]:
|
|
|
|
|
try:
|
|
|
|
|
os.unlink(fn)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.printWARNING(_("Failed to remove %s") % fn)
|
|
|
|
|
try:
|
|
|
|
|
pkgContents.writeContents()
|
|
|
|
|
except IOError:
|
|
|
|
|
self.printWARNING(_("Failed to modify %s contents") % pkg)
|
|
|
|
|
self.filesApply = map(lambda x: autoUpdateDict.get(x, x),
|
|
|
|
|
self.filesApply)
|
|
|
|
|
if filter(lambda x: "._cfg" in x, self.filesApply):
|
|
|
|
|
if self.objVar.Get('cl_ebuild_phase') != '':
|
|
|
|
|
self.printWARNING(_("Some config files need updating. "
|
|
|
|
|
"Perform run dispatch-conf."))
|
|
|
|
|
if self.dispatchConf and \
|
|
|
|
|
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,
|
|
|
|
|
optDir=None, skipTemplates=()):
|
|
|
|
|
"""Сканирование и обработка шаблонов в директории scanDir"""
|
|
|
|
|
if optDir is None:
|
|
|
|
|
optDir = {}
|
|
|
|
|
ret = True
|
|
|
|
|
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
|
|
|
|
|
pathDir, objHead = retDir
|
|
|
|
|
optDir["path"] = pathDir
|
|
|
|
|
if not objHead is True:
|
|
|
|
|
if objHead.typeAppend == "skip":
|
|
|
|
|
# Установка опции пропуска директории
|
|
|
|
|
optDir["skip"] = True
|
|
|
|
|
if ("autoupdate" in objHead.params or
|
|
|
|
|
self.objVar.Get('cl_autoupdate_set') == 'on'):
|
|
|
|
|
optDir["autoupdate"] = True
|
|
|
|
|
if flagDir or stat.S_ISDIR(os.lstat(str(scanDir))[stat.ST_MODE]):
|
|
|
|
|
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)):
|
|
|
|
|
absPath = os.path.join(scanDir, fileOrDir)
|
|
|
|
|
if skipTemplates and absPath in skipTemplates:
|
|
|
|
|
continue
|
|
|
|
|
stInfo = os.lstat(str(absPath))
|
|
|
|
|
statInfo = stInfo[stat.ST_MODE]
|
|
|
|
|
prevModule = self.objVar.defaultModule
|
|
|
|
|
prevBelong = self.functObj.currentBelong
|
|
|
|
|
prevAction = self.functObj.currentAction
|
|
|
|
|
try:
|
|
|
|
|
if stat.S_ISREG(statInfo):
|
|
|
|
|
if not self.processingFile(absPath, prefix, optDir):
|
|
|
|
|
ret = False
|
|
|
|
|
continue
|
|
|
|
|
elif stat.S_ISDIR(statInfo):
|
|
|
|
|
# Обработка директории
|
|
|
|
|
retDir = self.processingDirectory(absPath, prefix,
|
|
|
|
|
optDir)
|
|
|
|
|
if retDir is None:
|
|
|
|
|
continue
|
|
|
|
|
elif retDir is False:
|
|
|
|
|
ret = False
|
|
|
|
|
break
|
|
|
|
|
# Опции следующей директории
|
|
|
|
|
optNextDir = {}
|
|
|
|
|
pathDir, objHead = retDir
|
|
|
|
|
optNextDir["path"] = pathDir
|
|
|
|
|
if not objHead is True:
|
|
|
|
|
if objHead.typeAppend == "skip":
|
|
|
|
|
# Установка опции пропуска директории
|
|
|
|
|
optNextDir["skip"] = True
|
|
|
|
|
if ("autoupdate" in objHead.params or
|
|
|
|
|
self.objVar.Get(
|
|
|
|
|
'cl_autoupdate_set') == 'on'):
|
|
|
|
|
optNextDir["autoupdate"] = True
|
|
|
|
|
ret = self.scanningTemplates(absPath, prefix, True,
|
|
|
|
|
optNextDir)
|
|
|
|
|
if ret is False:
|
|
|
|
|
break
|
|
|
|
|
finally:
|
|
|
|
|
self.objVar.defaultModule = prevModule
|
|
|
|
|
self.functObj.currentBelong = prevBelong
|
|
|
|
|
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
|
|
|
|
|
# Проверка на переменные в названии файла
|
|
|
|
|
if not self.getNeedTemplate(path):
|
|
|
|
|
if self.getError():
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
if self.getError():
|
|
|
|
|
return False
|
|
|
|
|
nameFileConfig = path.partition(prefix)[2]
|
|
|
|
|
# файл в системе без условий
|
|
|
|
|
nameFileConfig = "/".join(map(lambda x: x.split("?")[0],
|
|
|
|
|
nameFileConfig.split("/")))
|
|
|
|
|
# Записываем в переменную обрабатываемый файл
|
|
|
|
|
self.objVar.Set("cl_pass_file", nameFileConfig)
|
|
|
|
|
filesApl = self.joinTemplate(path, nameFileConfig, optFile)
|
|
|
|
|
if self.getError():
|
|
|
|
|
return False
|
|
|
|
|
if filesApl:
|
|
|
|
|
# Настоящее имя конфигурационного файла
|
|
|
|
|
nameFileConfig = filesApl[0]
|
|
|
|
|
# Пишем время модификации *.env файлов
|
|
|
|
|
if nameFileConfig.endswith(".env"):
|
|
|
|
|
nameEnvFile = os.path.basename(nameFileConfig)
|
|
|
|
|
self.functObj.timeConfigsIni[nameEnvFile] = float(time.time())
|
|
|
|
|
self.filesApply += filesApl
|
|
|
|
|
if filesApl:
|
|
|
|
|
self._addFile(filesApl)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def processingDirectory(self, path, prefix, opt):
|
|
|
|
|
"""Обработка в случае директории если возвращаем None то пропуск дир."""
|
|
|
|
|
# Файл шаблона директории
|
|
|
|
|
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(map(lambda x: x.split("?")[0], newDir.split("/")))
|
|
|
|
|
# Применяем шаблон
|
|
|
|
|
pathDir, objHeadDir, createdDirs = \
|
|
|
|
|
self.getApplyHeadDir(newDir, dirInfoFile, opt)
|
|
|
|
|
if createdDirs:
|
|
|
|
|
self.createdDirs += createdDirs
|
|
|
|
|
if os.path.isfile(pathDir):
|
|
|
|
|
self.printWARNING(_("{dirpath} is a file").format(dirpath=pathDir))
|
|
|
|
|
self.printWARNING(_("templates in {tempath} are skipped"
|
|
|
|
|
).format(tempath=path))
|
|
|
|
|
return None
|
|
|
|
|
if objHeadDir:
|
|
|
|
|
return pathDir, objHeadDir
|
|
|
|
|
else:
|
|
|
|
|
if self.getError():
|
|
|
|
|
return False
|
|
|
|
|
# Добавление количества файлов в пропущенной директории
|
|
|
|
|
if path in self.dictTemplates.keys():
|
|
|
|
|
self.numberProcessTempl += self.dictTemplates[path]
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def _processMergePostmerge(self, params, templateDirFile):
|
|
|
|
|
"""Обработка параметров merge= , postmerge="""
|
|
|
|
|
if "merge" in params:
|
|
|
|
|
mergePkgs = params['merge'].split(',')
|
|
|
|
|
else:
|
|
|
|
|
mergePkgs = []
|
|
|
|
|
if "postmerge" in params:
|
|
|
|
|
postmergePkgs = params['postmerge'].split(',')
|
|
|
|
|
else:
|
|
|
|
|
postmergePkgs = []
|
|
|
|
|
|
|
|
|
|
if mergePkgs or postmergePkgs:
|
|
|
|
|
if self.objVar.Get('cl_ebuild_phase') == 'postinst':
|
|
|
|
|
for pkg in postmergePkgs:
|
|
|
|
|
if not pkg in self.objVar.Get('cl_merge_pkg_pass'):
|
|
|
|
|
self.objVar.Get('cl_merge_pkg_pass').append(pkg)
|
|
|
|
|
if not pkg in self.postmergePkgs:
|
|
|
|
|
try:
|
|
|
|
|
with open(self.postmergeFile, "a") as f:
|
|
|
|
|
f.write("%s\n" % pkg)
|
|
|
|
|
self.postmergePkgs.append(pkg)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.printWARNING(
|
|
|
|
|
_("Failed to reconfigure package %s") % pkg)
|
|
|
|
|
else:
|
|
|
|
|
mergePkgs = mergePkgs + postmergePkgs
|
|
|
|
|
|
|
|
|
|
for pkg in mergePkgs:
|
|
|
|
|
if not pkg in self.objVar.Get('cl_merge_pkg_new') and \
|
|
|
|
|
not pkg in self.objVar.Get('cl_merge_pkg_pass') and \
|
|
|
|
|
not pkg in self.objVar.Get('cl_merge_pkg'):
|
|
|
|
|
self.objVar.Get('cl_merge_pkg_new').append(pkg)
|
|
|
|
|
|
|
|
|
|
def getApplyHeadDir(self, newDir, templateDirFile, optDir):
|
|
|
|
|
"""Применяет шаблон к директории (права, владелец, и.т. д)"""
|
|
|
|
|
|
|
|
|
|
def function(text):
|
|
|
|
|
"""Функция обработки функций в заголовке"""
|
|
|
|
|
return self.applyFuncTemplate(text, templateDirFile)
|
|
|
|
|
|
|
|
|
|
def chownConfDir(nameDirConfig, uid, gid, nameFileTemplate):
|
|
|
|
|
"""Изменение владельца конфигурационной директории"""
|
|
|
|
|
try:
|
|
|
|
|
os.chown(nameDirConfig, uid, gid)
|
|
|
|
|
except (OSError, Exception) as e:
|
|
|
|
|
if hasattr(e, 'errno') and e.errno == 13 and \
|
|
|
|
|
"var/calculate/remote" in nameDirConfig:
|
|
|
|
|
return True
|
|
|
|
|
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
|
|
|
|
|
self.setError(_("Failed to apply template file %s") \
|
|
|
|
|
% nameFileTemplate)
|
|
|
|
|
self.setError(_("error") + " " + \
|
|
|
|
|
"'chown %s %s'" % (owner, nameDirConfig))
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
applyDir = newDir
|
|
|
|
|
|
|
|
|
|
# Родительская директория
|
|
|
|
|
if optDir.get("path"):
|
|
|
|
|
path = 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])
|
|
|
|
|
# Фильтрация шаблонов по названию директории
|
|
|
|
|
realPath = os.path.join("/", applyDir.partition(self._baseDir)[2])
|
|
|
|
|
if realPath in self.dirsFilter:
|
|
|
|
|
return "", False, []
|
|
|
|
|
# Создаем директорию если необходимо
|
|
|
|
|
crDirs = self.createDir(applyDir, False, self.uid, self.gid)
|
|
|
|
|
if not crDirs:
|
|
|
|
|
return "", False, []
|
|
|
|
|
if "autoupdate" in optDir:
|
|
|
|
|
self.autoUpdateDirs.append(applyDir)
|
|
|
|
|
if crDirs is True:
|
|
|
|
|
return applyDir, True, []
|
|
|
|
|
else:
|
|
|
|
|
return applyDir, True, crDirs
|
|
|
|
|
try:
|
|
|
|
|
FD = open(templateDirFile)
|
|
|
|
|
textTemplate = FD.readline().rstrip()
|
|
|
|
|
buf = textTemplate
|
|
|
|
|
while buf and textTemplate.endswith('\\'):
|
|
|
|
|
buf = FD.readline()
|
|
|
|
|
textTemplate = "%s %s" % (textTemplate[:-1], buf.rstrip())
|
|
|
|
|
FD.close()
|
|
|
|
|
except IOError:
|
|
|
|
|
self.setError(_("Failed to open the template") + _(": ") +
|
|
|
|
|
templateDirFile)
|
|
|
|
|
return "", False, []
|
|
|
|
|
|
|
|
|
|
headerLine = self.getHeaderText(textTemplate)
|
|
|
|
|
if headerLine:
|
|
|
|
|
moduleParam = filter(lambda x: x.startswith('env='),
|
|
|
|
|
headerLine.split())
|
|
|
|
|
if moduleParam:
|
|
|
|
|
self.objVar.defaultModule = moduleParam[0].partition('=')[2]
|
|
|
|
|
try:
|
|
|
|
|
importlib.import_module(
|
|
|
|
|
"calculate.%s.variables" % self.objVar.defaultModule)
|
|
|
|
|
except (ImportError, AttributeError):
|
|
|
|
|
return "", False, []
|
|
|
|
|
# Заменяем переменные на их значения
|
|
|
|
|
textTemplate = self.applyVarsTemplate(textTemplate, templateDirFile)
|
|
|
|
|
|
|
|
|
|
# Заменяем функции на их значения
|
|
|
|
|
textTemplate = self.applyFuncTemplate(textTemplate, templateDirFile)
|
|
|
|
|
# Обработка заголовка
|
|
|
|
|
objHead = dirHeader(templateDirFile, textTemplate, self.objVar,
|
|
|
|
|
function)
|
|
|
|
|
signs = {'ac_install_patch==on': 'patch',
|
|
|
|
|
'ac_desktop_profile==on': 'profile'}
|
|
|
|
|
for sign in signs:
|
|
|
|
|
if sign in textTemplate:
|
|
|
|
|
self.functObj.currentAction = signs[sign]
|
|
|
|
|
break
|
|
|
|
|
# Директория с профилями не будет применена
|
|
|
|
|
if not objHead.headerTerm:
|
|
|
|
|
if objHead.getError():
|
|
|
|
|
self.setError(_("Incorrect template") + _(": ") +
|
|
|
|
|
templateDirFile)
|
|
|
|
|
return "", False, []
|
|
|
|
|
|
|
|
|
|
# add packeges for reconfigure
|
|
|
|
|
self._processMergePostmerge(objHead.params, templateDirFile)
|
|
|
|
|
# Пропускаем директорию
|
|
|
|
|
if objHead.typeAppend == "skip":
|
|
|
|
|
applyDir = path
|
|
|
|
|
return applyDir, objHead, []
|
|
|
|
|
|
|
|
|
|
# Изменяем название родительской директории
|
|
|
|
|
if "path" in objHead.params:
|
|
|
|
|
path = objHead.params['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 'path' in the template") +
|
|
|
|
|
_(": ") + templateDirFile)
|
|
|
|
|
return "", False, []
|
|
|
|
|
else:
|
|
|
|
|
path = pathJoin(self._baseDir, path)
|
|
|
|
|
|
|
|
|
|
# Изменяем название директории
|
|
|
|
|
if "name" in objHead.params:
|
|
|
|
|
nameDir = objHead.params['name']
|
|
|
|
|
if "/" in nameDir or nameDir == ".." or nameDir == ".":
|
|
|
|
|
self.setError(_("Wrong value 'name' in the template") +
|
|
|
|
|
_(": ") + templateDirFile)
|
|
|
|
|
return "", False, []
|
|
|
|
|
# Новый путь к директории
|
|
|
|
|
applyDir = pathJoin(path, nameDir)
|
|
|
|
|
else:
|
|
|
|
|
applyDir = pathJoin(path, os.path.split(applyDir)[1])
|
|
|
|
|
|
|
|
|
|
# Фильтрация шаблонов по названию директории
|
|
|
|
|
realPath = os.path.join("/", applyDir.partition(self._baseDir)[2])
|
|
|
|
|
if realPath in self.dirsFilter:
|
|
|
|
|
return "", False, []
|
|
|
|
|
# Удаляем директорию
|
|
|
|
|
if objHead.typeAppend == "remove":
|
|
|
|
|
if os.path.isdir(applyDir):
|
|
|
|
|
self.changedFiles.addObj(applyDir, ChangedFiles.DIR_REMOVED,
|
|
|
|
|
self.functObj.currentBelong)
|
|
|
|
|
# удаляем директорию
|
|
|
|
|
try:
|
|
|
|
|
removeDir(applyDir)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(_("Failed to delete the directory: ") + \
|
|
|
|
|
applyDir)
|
|
|
|
|
return "", False, []
|
|
|
|
|
|
|
|
|
|
# Очищаем директорию
|
|
|
|
|
if objHead.typeAppend == "clear":
|
|
|
|
|
if os.path.isdir(applyDir):
|
|
|
|
|
for rmPath in os.listdir(applyDir):
|
|
|
|
|
removePath = pathJoin(applyDir, rmPath)
|
|
|
|
|
if os.path.isdir(removePath):
|
|
|
|
|
# удаляем директорию
|
|
|
|
|
try:
|
|
|
|
|
removeDir(removePath)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(
|
|
|
|
|
_("Failed to delete the directory: ") + \
|
|
|
|
|
removePath)
|
|
|
|
|
else:
|
|
|
|
|
try:
|
|
|
|
|
os.unlink(removePath)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(
|
|
|
|
|
_("Failed to delete: ") + removePath)
|
|
|
|
|
return "", False, []
|
|
|
|
|
|
|
|
|
|
# Созданные директории
|
|
|
|
|
createdDirs = []
|
|
|
|
|
# chmod - изменяем права
|
|
|
|
|
if "chmod" in objHead.params:
|
|
|
|
|
mode = self.__octToInt(objHead.params['chmod'])
|
|
|
|
|
if mode:
|
|
|
|
|
if not os.path.exists(applyDir):
|
|
|
|
|
crDirs = self.createDir(applyDir, mode, self.uid, self.gid)
|
|
|
|
|
if not crDirs:
|
|
|
|
|
return "", False, []
|
|
|
|
|
if not crDirs is True:
|
|
|
|
|
createdDirs += crDirs
|
|
|
|
|
else:
|
|
|
|
|
try:
|
|
|
|
|
os.chmod(applyDir, mode)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(_("Failed to change the mode for "
|
|
|
|
|
"the directory: ") + applyDir)
|
|
|
|
|
else:
|
|
|
|
|
self.setError(_("Wrong value 'chmod' in the template") +
|
|
|
|
|
_(": ") + templateDirFile)
|
|
|
|
|
return "", False, []
|
|
|
|
|
# chown - изменяем владельца и группу
|
|
|
|
|
if "chown" in objHead.params:
|
|
|
|
|
owner = objHead.params['chown']
|
|
|
|
|
if owner:
|
|
|
|
|
if ":" in owner:
|
|
|
|
|
strUid, strGid = owner.split(":")
|
|
|
|
|
import pwd
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
uid = pwd.getpwnam(strUid).pw_uid
|
|
|
|
|
except (KeyError, TypeError):
|
|
|
|
|
self.setError(_("No such user on the system: ")
|
|
|
|
|
+ strUid)
|
|
|
|
|
self.setError(_("Wrong value 'chown' in the template") +
|
|
|
|
|
_(": ") + templateDirFile)
|
|
|
|
|
return "", False, []
|
|
|
|
|
try:
|
|
|
|
|
import grp
|
|
|
|
|
|
|
|
|
|
gid = grp.getgrnam(strGid).gr_gid
|
|
|
|
|
except (KeyError, TypeError):
|
|
|
|
|
self.setError(_("Group not found on the system: ")
|
|
|
|
|
+ strGid)
|
|
|
|
|
self.setError(
|
|
|
|
|
_("Wrong value 'chown' in the template") +
|
|
|
|
|
_(": ") + templateDirFile)
|
|
|
|
|
return "", False, []
|
|
|
|
|
|
|
|
|
|
if not os.path.exists(applyDir):
|
|
|
|
|
crDirs = self.createDir(applyDir, False, uid, gid)
|
|
|
|
|
if not crDirs:
|
|
|
|
|
return "", False, []
|
|
|
|
|
if not crDirs is True:
|
|
|
|
|
createdDirs += crDirs
|
|
|
|
|
else:
|
|
|
|
|
if not chownConfDir(applyDir, uid, gid,
|
|
|
|
|
templateDirFile):
|
|
|
|
|
return "", False, []
|
|
|
|
|
else:
|
|
|
|
|
self.setError(_("Wrong value 'chown' in the template") +
|
|
|
|
|
_(": ") + templateDirFile)
|
|
|
|
|
return "", False, []
|
|
|
|
|
else:
|
|
|
|
|
self.setError(_("Wrong value 'chown' in the template") +
|
|
|
|
|
_(": ") + templateDirFile)
|
|
|
|
|
return "", False, []
|
|
|
|
|
else:
|
|
|
|
|
# Устанавливаем владельцем директории, пользователя по умолчанию
|
|
|
|
|
# (переменная шаблона ur_login)
|
|
|
|
|
if os.path.exists(applyDir):
|
|
|
|
|
self.changedFiles.addObj(applyDir, ChangedFiles.DIR_EXISTS,
|
|
|
|
|
self.functObj.currentBelong)
|
|
|
|
|
tUid, tGid = getModeFile(applyDir, mode="owner")
|
|
|
|
|
if (self.uid, self.gid) != (tUid, tGid):
|
|
|
|
|
if not chownConfDir(applyDir, self.uid, self.gid,
|
|
|
|
|
templateDirFile):
|
|
|
|
|
return "", False, []
|
|
|
|
|
else:
|
|
|
|
|
self.changedFiles.addObj(applyDir, ChangedFiles.DIR_CREATED,
|
|
|
|
|
self.functObj.currentBelong)
|
|
|
|
|
crDirs = self.createDir(applyDir, False, self.uid, self.gid)
|
|
|
|
|
if not crDirs:
|
|
|
|
|
return "", False, []
|
|
|
|
|
if not crDirs is True:
|
|
|
|
|
createdDirs += crDirs
|
|
|
|
|
if not objHead:
|
|
|
|
|
applyDir = ""
|
|
|
|
|
if applyDir:
|
|
|
|
|
if ("autoupdate" in optDir or "autoupdate" in objHead.params) and \
|
|
|
|
|
not self.objVar.Get('cl_merge_pkg_pass'):
|
|
|
|
|
self.autoUpdateDirs.append(applyDir)
|
|
|
|
|
return applyDir, objHead, createdDirs
|
|
|
|
|
|
|
|
|
|
def getUidFromPasswd(self, strUid):
|
|
|
|
|
"""Get uid by username from chroot passwd file"""
|
|
|
|
|
passwdFile = os.path.join(self._baseDir, 'etc/passwd')
|
|
|
|
|
if os.path.exists(passwdFile):
|
|
|
|
|
mapUid = dict(
|
|
|
|
|
filter(lambda x: x and len(x) > 1 and x[0] and x[1],
|
|
|
|
|
map(lambda x: x.split(':')[0:3:2],
|
|
|
|
|
filter(lambda x: not x.startswith('#'),
|
|
|
|
|
open(passwdFile, 'r')))))
|
|
|
|
|
if strUid in mapUid:
|
|
|
|
|
return int(mapUid[strUid])
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def getGidFromGroup(self, strGid):
|
|
|
|
|
"""Get gid by groupname from chroot group file"""
|
|
|
|
|
groupFile = os.path.join(self._baseDir, 'etc/group')
|
|
|
|
|
if os.path.exists(groupFile):
|
|
|
|
|
mapGid = dict(
|
|
|
|
|
filter(lambda x: x and len(x) > 1 and x[0] and x[1],
|
|
|
|
|
map(lambda x: x.split(':')[0:3:2],
|
|
|
|
|
filter(lambda x: not x.startswith('#'),
|
|
|
|
|
open(groupFile, 'r')))))
|
|
|
|
|
if strGid in mapGid:
|
|
|
|
|
return int(mapGid[strGid])
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
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 filter(pathFile.startswith,
|
|
|
|
|
map(lambda x: pathJoin(chrootPath, x),
|
|
|
|
|
self.objVar.Get('cl_config_protect'))) or \
|
|
|
|
|
filter(pathFile.startswith,
|
|
|
|
|
map(lambda x: pathJoin(chrootPath, x),
|
|
|
|
|
self.objVar.Get('cl_config_protect_mask'))):
|
|
|
|
|
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
|
|
|
|
|
if not pkg:
|
|
|
|
|
if not self.allContents:
|
|
|
|
|
fillContents(self.allContents,
|
|
|
|
|
self.objVar.Get('cl_config_protect'),
|
|
|
|
|
prefix=self.objVar.Get('cl_chroot_path'))
|
|
|
|
|
origName = pathFile if chrootPath == '/' \
|
|
|
|
|
else pathFile[len(chrootPath):]
|
|
|
|
|
if origName in self.allContents:
|
|
|
|
|
pkg = self.allContents[origName]
|
|
|
|
|
else:
|
|
|
|
|
return pathFile
|
|
|
|
|
pkg = isPkgInstalled(pkg, sortByVersion=True, prefix=chrootPath)
|
|
|
|
|
if not pkg:
|
|
|
|
|
return pathFile
|
|
|
|
|
if checkContents("{CATEGORY}/{PF}".format(**pkg[-1]),
|
|
|
|
|
pathFile,
|
|
|
|
|
prefix=chrootPath,
|
|
|
|
|
reservedFile='/var/lib/calculate/-CONTENTS-{PN}'.format(
|
|
|
|
|
**pkg[-1]) \
|
|
|
|
|
if self.objVar.Get(
|
|
|
|
|
'cl_ebuild_phase') == 'postinst' \
|
|
|
|
|
else None):
|
|
|
|
|
return pathFile
|
|
|
|
|
real_filename = os.path.basename(pathFile)
|
|
|
|
|
real_dirname = os.path.dirname(pathFile)
|
|
|
|
|
self.configMode = T_NEWCFG
|
|
|
|
|
return os.path.join(real_dirname, "._cfg0000_%s" % real_filename)
|
|
|
|
|
|
|
|
|
|
def getApplyHeadTemplate(self, nameFileTemplate, nameFileConfig,
|
|
|
|
|
templateFileType, optFile):
|
|
|
|
|
"""Применяет заголовок к шаблону (права, владелец, и.т. д)"""
|
|
|
|
|
|
|
|
|
|
def function(text):
|
|
|
|
|
"""Функция обработки функций в заголовке"""
|
|
|
|
|
return self.applyFuncTemplate(text, nameFileTemplate)
|
|
|
|
|
|
|
|
|
|
def preReturn(pathProg):
|
|
|
|
|
"""Действия перед выходом из метода"""
|
|
|
|
|
if pathProg:
|
|
|
|
|
os.chdir(pathProg)
|
|
|
|
|
|
|
|
|
|
def chownConfFile(nameFileConfig, uid, gid, nameFileTemplate,
|
|
|
|
|
checkExists=True):
|
|
|
|
|
"""Изменение владельца конфигурационного файла"""
|
|
|
|
|
try:
|
|
|
|
|
if checkExists and not os.path.exists(nameFileConfig):
|
|
|
|
|
# Создание файла
|
|
|
|
|
FD = open(nameFileConfig, "w")
|
|
|
|
|
FD.close()
|
|
|
|
|
os.lchown(nameFileConfig, uid, gid)
|
|
|
|
|
except (OSError, Exception) as e:
|
|
|
|
|
if hasattr(e, 'errno') and e.errno == 13 and \
|
|
|
|
|
"var/calculate/remote" in nameFileConfig:
|
|
|
|
|
return True
|
|
|
|
|
import pwd
|
|
|
|
|
import grp
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
userName = pwd.getpwuid(uid).pw_name
|
|
|
|
|
except (KeyError, TypeError):
|
|
|
|
|
userName = str(uid)
|
|
|
|
|
try:
|
|
|
|
|
groupName = grp.getgrgid(gid).gr_name
|
|
|
|
|
except (KeyError, TypeError):
|
|
|
|
|
groupName = str(gid)
|
|
|
|
|
owner = userName + ":" + groupName
|
|
|
|
|
self.setError(_("Failed to apply template file %s") \
|
|
|
|
|
% nameFileTemplate)
|
|
|
|
|
self.setError(_("error") + " " + \
|
|
|
|
|
"'chown %s %s'" % (owner, nameFileConfig))
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def chmodConfFile(nameFileConfig, mode, nameFileTemplate,
|
|
|
|
|
checkExists=True):
|
|
|
|
|
"""Изменения режима доступа конфигурационного файла"""
|
|
|
|
|
try:
|
|
|
|
|
if checkExists and not os.path.exists(pathOldFile):
|
|
|
|
|
# Создание файла
|
|
|
|
|
FD = open(nameFileConfig, "w")
|
|
|
|
|
FD.close()
|
|
|
|
|
os.chmod(nameFileConfig, mode)
|
|
|
|
|
except (OSError, Exception) as e:
|
|
|
|
|
if hasattr(e, 'errno') and e.errno == 13 and \
|
|
|
|
|
"var/calculate/remote" in nameFileConfig:
|
|
|
|
|
return True
|
|
|
|
|
self.setError(_("Failed to apply template file %s") \
|
|
|
|
|
% nameFileTemplate)
|
|
|
|
|
self.setError(
|
|
|
|
|
_("error") + " " +
|
|
|
|
|
"'chmod %s %s'" % (str(oct(mode)), nameFileConfig))
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
self.closeFiles()
|
|
|
|
|
pathProg = ""
|
|
|
|
|
self.executeType = None
|
|
|
|
|
# Файлы в системе к которым были применены шаблоны
|
|
|
|
|
# В случае бинарного типа файла читаем шаблон
|
|
|
|
|
if templateFileType == "bin":
|
|
|
|
|
self.nameFileTemplate = os.path.abspath(nameFileTemplate)
|
|
|
|
|
self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
|
|
|
|
|
if not self.F_TEMPL:
|
|
|
|
|
self.setError(_("Failed to open the template") + _(": ") +
|
|
|
|
|
self.nameFileTemplate)
|
|
|
|
|
return [], False
|
|
|
|
|
self.textTemplate = self.F_TEMPL.read()
|
|
|
|
|
self.closeTemplFile()
|
|
|
|
|
objHeadNew = fileHeader(nameFileTemplate, self.textTemplate, False,
|
|
|
|
|
templateFileType, objVar=self.objVar,
|
|
|
|
|
function=function, templateObj=self)
|
|
|
|
|
# файл шаблона не будет применен
|
|
|
|
|
if not objHeadNew.headerTerm:
|
|
|
|
|
if objHeadNew.getError():
|
|
|
|
|
self.setError(_("Incorrect template") + _(": ") +
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
return [], False
|
|
|
|
|
|
|
|
|
|
# add packeges for reconfigure
|
|
|
|
|
self._processMergePostmerge(objHeadNew.params, nameFileTemplate)
|
|
|
|
|
|
|
|
|
|
# Родительская директория
|
|
|
|
|
path = optFile["path"]
|
|
|
|
|
# Изменяем название родительской директории
|
|
|
|
|
if "path" in objHeadNew.params:
|
|
|
|
|
path = objHeadNew.params['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 'path' in the template") +
|
|
|
|
|
_(": ") + nameFileTemplate)
|
|
|
|
|
return [], False
|
|
|
|
|
else:
|
|
|
|
|
path = pathJoin(self._baseDir, path)
|
|
|
|
|
|
|
|
|
|
# Путь к оригинальному файлу - pathOldFile
|
|
|
|
|
# Изменяем путь к оригинальному файлу
|
|
|
|
|
if objHeadNew.params.has_key("name"):
|
|
|
|
|
nameFile = objHeadNew.params['name']
|
|
|
|
|
if "/" in nameFile or nameFile == ".." or nameFile == ".":
|
|
|
|
|
self.setError(_("Wrong value 'name' in the template") +
|
|
|
|
|
_(": ") + nameFileTemplate)
|
|
|
|
|
return [], False
|
|
|
|
|
# Новый путь к оригинальному файлу
|
|
|
|
|
pathOldFile = pathJoin(path, nameFile)
|
|
|
|
|
else:
|
|
|
|
|
pathOldFile = pathJoin(path, os.path.split(nameFileConfig)[1])
|
|
|
|
|
pathOrigFile = pathOldFile
|
|
|
|
|
if self.objVar.Get('cl_protect_use_set') == 'on':
|
|
|
|
|
pathOldFile = self.fixNameFileConfig(pathOldFile)
|
|
|
|
|
pathOldFile = self.checkOnNewConfigName(pathOldFile)
|
|
|
|
|
# буффер для использование в link=
|
|
|
|
|
newBuffer = None
|
|
|
|
|
applyFiles = [pathOldFile]
|
|
|
|
|
# Фильтрация шаблонов по названию файла
|
|
|
|
|
realPath = os.path.join("/", pathOldFile.partition(self._baseDir)[2])
|
|
|
|
|
if realPath in self.filesFilter:
|
|
|
|
|
return [], False
|
|
|
|
|
typeAppendTemplate = objHeadNew.typeAppend
|
|
|
|
|
|
|
|
|
|
# Параметр exec
|
|
|
|
|
if "exec" in objHeadNew.params or "run" in objHeadNew.params:
|
|
|
|
|
if "exec" in objHeadNew.params:
|
|
|
|
|
paramName = "exec"
|
|
|
|
|
else:
|
|
|
|
|
paramName = "run"
|
|
|
|
|
self.executeType = paramName
|
|
|
|
|
execPath = objHeadNew.params[paramName]
|
|
|
|
|
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 == "join":
|
|
|
|
|
self.setError(_("Wrong value 'append=join' in the template") +
|
|
|
|
|
_(": ") + nameFileTemplate)
|
|
|
|
|
return [], False
|
|
|
|
|
|
|
|
|
|
# Очищаем оригинальный файл
|
|
|
|
|
if typeAppendTemplate == "clear":
|
|
|
|
|
try:
|
|
|
|
|
open(pathOldFile, "w").truncate(0)
|
|
|
|
|
except IOError:
|
|
|
|
|
self.setError(_("Template error") + _(": ") +
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(_("Failed to clear the file") + _(": ") +
|
|
|
|
|
pathOldFile)
|
|
|
|
|
return applyFiles, False
|
|
|
|
|
# Удаляем оригинальный файл
|
|
|
|
|
if typeAppendTemplate == "remove":
|
|
|
|
|
if objHeadNew.params.has_key("force"):
|
|
|
|
|
pathOldFile = pathOrigFile
|
|
|
|
|
self.configMode = T_ORIGIN
|
|
|
|
|
try:
|
|
|
|
|
if os.path.islink(pathOldFile):
|
|
|
|
|
# удаляем ссылку
|
|
|
|
|
try:
|
|
|
|
|
os.unlink(pathOldFile)
|
|
|
|
|
return applyFiles, False
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(_("Template error") + _(": ") +
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(_("Failed to delete the link") + _(": ") +
|
|
|
|
|
pathOldFile)
|
|
|
|
|
return [], False
|
|
|
|
|
if os.path.isfile(pathOldFile) and self.configMode == T_ORIGIN:
|
|
|
|
|
# удаляем файл
|
|
|
|
|
try:
|
|
|
|
|
os.remove(pathOldFile)
|
|
|
|
|
return applyFiles, False
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(_("Template error") + _(": ") +
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(_("Failed to delete the file") + _(": ") +
|
|
|
|
|
pathOldFile)
|
|
|
|
|
return [], False
|
|
|
|
|
finally:
|
|
|
|
|
pattern = "%s/._cfg????_%s" % (os.path.dirname(pathOrigFile),
|
|
|
|
|
os.path.basename(pathOrigFile))
|
|
|
|
|
for fn in glob.glob(pattern):
|
|
|
|
|
try:
|
|
|
|
|
os.unlink(fn)
|
|
|
|
|
except OSError:
|
|
|
|
|
pass
|
|
|
|
|
if self.functObj.currentBelong:
|
|
|
|
|
self.changedFiles.addObj(pathOrigFile,
|
|
|
|
|
ChangedFiles.FILE_REMOVED,
|
|
|
|
|
self.functObj.currentBelong)
|
|
|
|
|
return [], False
|
|
|
|
|
# Пропускаем обработку шаблона
|
|
|
|
|
elif typeAppendTemplate == "skip":
|
|
|
|
|
return [], False
|
|
|
|
|
|
|
|
|
|
# Создаем директорию для файла если ее нет
|
|
|
|
|
if not os.path.exists(path):
|
|
|
|
|
if not self.createDir(path):
|
|
|
|
|
return [], False
|
|
|
|
|
# В случае force
|
|
|
|
|
if objHeadNew.params.has_key("force"):
|
|
|
|
|
if os.path.islink(pathOldFile):
|
|
|
|
|
# удаляем ссылку
|
|
|
|
|
newBuffer = ""
|
|
|
|
|
try:
|
|
|
|
|
os.unlink(pathOldFile)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(_("Template error") + _(": ") +
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(_("Failed to delete the link") + _(": ") +
|
|
|
|
|
pathOldFile)
|
|
|
|
|
return [], False
|
|
|
|
|
if os.path.isfile(pathOldFile):
|
|
|
|
|
# удаляем файл
|
|
|
|
|
newBuffer = ""
|
|
|
|
|
try:
|
|
|
|
|
os.remove(pathOldFile)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(_("Template error") + _(": ") +
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(_("Failed to delete the file") + _(": ") +
|
|
|
|
|
pathOldFile)
|
|
|
|
|
return [], False
|
|
|
|
|
|
|
|
|
|
flagSymlink = False
|
|
|
|
|
# Если есть параметр mirror
|
|
|
|
|
if objHeadNew.params.has_key("mirror"):
|
|
|
|
|
if objHeadNew.params.has_key("link"):
|
|
|
|
|
templateFile = objHeadNew.params['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):
|
|
|
|
|
if os.path.exists(pathOldFile):
|
|
|
|
|
try:
|
|
|
|
|
os.remove(pathOldFile)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(_("Template error") + _(": ") +
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(
|
|
|
|
|
_("Failed to delete the file") + _(": ") +
|
|
|
|
|
pathOldFile)
|
|
|
|
|
return [], False
|
|
|
|
|
elif not os.path.exists(pathOldFile):
|
|
|
|
|
return [], False
|
|
|
|
|
# Если есть указатель на файл шаблона (link)
|
|
|
|
|
if objHeadNew.params.has_key("link") and \
|
|
|
|
|
not objHeadNew.params.has_key("symbolic"):
|
|
|
|
|
templateFile = objHeadNew.params['link']
|
|
|
|
|
if templateFile and templateFile[0] == "~":
|
|
|
|
|
# Получаем директорию пользователя
|
|
|
|
|
templateFile = os.path.join(
|
|
|
|
|
self.homeDir, templateFile.partition("/")[2], "")[:-1]
|
|
|
|
|
templateFile = pathJoin(self._baseDir, templateFile)
|
|
|
|
|
foundTemplateFile = os.path.exists(templateFile)
|
|
|
|
|
buff = None
|
|
|
|
|
fMode, fUid, fGid = None, None, None
|
|
|
|
|
if foundTemplateFile:
|
|
|
|
|
try:
|
|
|
|
|
F_CONF = self.openTemplFile(templateFile)
|
|
|
|
|
if not F_CONF:
|
|
|
|
|
raise IOError
|
|
|
|
|
buff = F_CONF.read()
|
|
|
|
|
F_CONF.close()
|
|
|
|
|
fMode, fUid, fGid = getModeFile(templateFile)
|
|
|
|
|
except (OSError, IOError):
|
|
|
|
|
self.setError(_("Template error") + _(": ") +
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(_("Failed to open the file") + _(": ") +
|
|
|
|
|
templateFile)
|
|
|
|
|
return [], False
|
|
|
|
|
if os.path.exists(pathOldFile):
|
|
|
|
|
newBuffer = ""
|
|
|
|
|
try:
|
|
|
|
|
os.remove(pathOldFile)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(_("Template error") + _(": ") +
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(_("Failed to delete the file") + _(": ") +
|
|
|
|
|
pathOldFile)
|
|
|
|
|
return [], False
|
|
|
|
|
if buff is not None:
|
|
|
|
|
try:
|
|
|
|
|
FD = open(pathOldFile, "w+")
|
|
|
|
|
newBuffer = buff
|
|
|
|
|
FD.write(buff)
|
|
|
|
|
FD.close()
|
|
|
|
|
except IOError:
|
|
|
|
|
self.setError(_("Template error") + _(": ") +
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(_("Failed to create the file") + " '%s'" \
|
|
|
|
|
% pathOldFile)
|
|
|
|
|
return [], False
|
|
|
|
|
oMode = getModeFile(pathOldFile, mode="mode")
|
|
|
|
|
# Если права не совпадают, меняем права
|
|
|
|
|
if fMode != oMode:
|
|
|
|
|
if not chmodConfFile(pathOldFile, fMode, nameFileTemplate,
|
|
|
|
|
checkExists=False):
|
|
|
|
|
return [], False
|
|
|
|
|
|
|
|
|
|
# Если символическая ссылка
|
|
|
|
|
prevOldFile = None
|
|
|
|
|
if objHeadNew.params.has_key("symbolic"):
|
|
|
|
|
prevOldFile = pathOldFile
|
|
|
|
|
pathOldFile = objHeadNew.params['link']
|
|
|
|
|
flagSymlink = True
|
|
|
|
|
if not pathOldFile:
|
|
|
|
|
raise TemplatesError(
|
|
|
|
|
_("Missed source link in template '%s'")
|
|
|
|
|
% str(nameFileTemplate))
|
|
|
|
|
if not "/" == pathOldFile[0]:
|
|
|
|
|
pathLink = os.path.split(os.path.abspath(prevOldFile))[0]
|
|
|
|
|
pathProg = os.getcwd()
|
|
|
|
|
try:
|
|
|
|
|
os.chdir(pathLink)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(_("Template error") + _(": ") +
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(
|
|
|
|
|
_("Failed to change the current directory to") + \
|
|
|
|
|
" " + pathLink)
|
|
|
|
|
return [], False
|
|
|
|
|
|
|
|
|
|
# chmod - изменяем права
|
|
|
|
|
if objHeadNew.params.has_key("chmod"):
|
|
|
|
|
mode = self.__octToInt(objHeadNew.params['chmod'])
|
|
|
|
|
if mode:
|
|
|
|
|
if not chmodConfFile(pathOldFile, mode, nameFileTemplate):
|
|
|
|
|
preReturn(pathProg)
|
|
|
|
|
return [], False
|
|
|
|
|
else:
|
|
|
|
|
self.setError(_("Wrong value 'chmod' in the template") +
|
|
|
|
|
_(": ") + nameFileTemplate)
|
|
|
|
|
preReturn(pathProg)
|
|
|
|
|
return [], False
|
|
|
|
|
# chown - изменяем владельца и группу
|
|
|
|
|
if objHeadNew.params.has_key("chown"):
|
|
|
|
|
owner = objHeadNew.params['chown']
|
|
|
|
|
if owner:
|
|
|
|
|
if ":" in owner:
|
|
|
|
|
strUid, strGid = owner.split(":")
|
|
|
|
|
if strUid.isdigit():
|
|
|
|
|
uid = int(strUid)
|
|
|
|
|
else:
|
|
|
|
|
uid = self.getUidFromPasswd(strUid)
|
|
|
|
|
import pwd
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
if uid is None:
|
|
|
|
|
uid = pwd.getpwnam(strUid).pw_uid
|
|
|
|
|
except (KeyError, TypeError):
|
|
|
|
|
self.setError(_("No such user on the system: ") +
|
|
|
|
|
strUid)
|
|
|
|
|
self.setError(
|
|
|
|
|
_("Wrong value 'chown' in the template") +
|
|
|
|
|
_(": ") + nameFileTemplate)
|
|
|
|
|
preReturn(pathProg)
|
|
|
|
|
return [], False
|
|
|
|
|
if strGid.isdigit():
|
|
|
|
|
gid = int(strGid)
|
|
|
|
|
else:
|
|
|
|
|
gid = self.getGidFromGroup(strGid)
|
|
|
|
|
try:
|
|
|
|
|
if gid is None:
|
|
|
|
|
import grp
|
|
|
|
|
|
|
|
|
|
gid = grp.getgrnam(strGid).gr_gid
|
|
|
|
|
except (KeyError, TypeError):
|
|
|
|
|
self.setError(_("Group not found on the system: ") +
|
|
|
|
|
strGid)
|
|
|
|
|
self.setError(
|
|
|
|
|
_("Wrong value 'chown' in the template") +
|
|
|
|
|
_(": ") + nameFileTemplate)
|
|
|
|
|
preReturn(pathProg)
|
|
|
|
|
return [], False
|
|
|
|
|
# Изменяем владельца файла
|
|
|
|
|
if not chownConfFile(pathOldFile, uid, gid,
|
|
|
|
|
nameFileTemplate):
|
|
|
|
|
preReturn(pathProg)
|
|
|
|
|
return [], False
|
|
|
|
|
else:
|
|
|
|
|
self.setError(_("Wrong value 'chown' in the template") +
|
|
|
|
|
_(": ") + nameFileTemplate)
|
|
|
|
|
preReturn(pathProg)
|
|
|
|
|
return [], False
|
|
|
|
|
else:
|
|
|
|
|
self.setError(_("Wrong value 'chown' in the template") +
|
|
|
|
|
_(": ") + nameFileTemplate)
|
|
|
|
|
preReturn(pathProg)
|
|
|
|
|
return [], False
|
|
|
|
|
if not flagSymlink:
|
|
|
|
|
self.openFiles(nameFileTemplate, pathOldFile, objHeadNew.fileType,
|
|
|
|
|
newBuffer)
|
|
|
|
|
if self.getError():
|
|
|
|
|
return [], False
|
|
|
|
|
if not objHeadNew.params.has_key("chown"):
|
|
|
|
|
# Устанавливаем владельцем конфигурационного файла,
|
|
|
|
|
# пользователя по умолчанию (переменная шаблона ur_login)
|
|
|
|
|
if os.path.exists(pathOldFile):
|
|
|
|
|
tUid, tGid = getModeFile(pathOldFile, mode="owner")
|
|
|
|
|
if (self.uid, self.gid) != (tUid, tGid):
|
|
|
|
|
# Изменяем владельца файла
|
|
|
|
|
if not chownConfFile(pathOldFile, self.uid, self.gid,
|
|
|
|
|
nameFileTemplate, checkExists=False):
|
|
|
|
|
preReturn(pathProg)
|
|
|
|
|
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)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(_("Template error") + _(": ") +
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(_("Failed to delete the file") + _(": ") +
|
|
|
|
|
prevOldFile)
|
|
|
|
|
preReturn(pathProg)
|
|
|
|
|
return [], False
|
|
|
|
|
if not "/" == pathOldFile[0]:
|
|
|
|
|
applyFiles = [
|
|
|
|
|
prevOldFile] # ,os.path.join(pathLink,pathOldFile)]
|
|
|
|
|
else:
|
|
|
|
|
applyFiles = [prevOldFile] # ,pathOldFile]
|
|
|
|
|
try:
|
|
|
|
|
os.symlink(pathOldFile, prevOldFile)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError(_("Template error") + _(": ") + \
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(_("Failed to create a symbolic link") + _(": ") + \
|
|
|
|
|
"%s -> %s" % (prevOldFile, pathOldFile))
|
|
|
|
|
preReturn(pathProg)
|
|
|
|
|
return [], False
|
|
|
|
|
if not objHeadNew.body.strip():
|
|
|
|
|
preReturn(pathProg)
|
|
|
|
|
if "protected" in objHeadNew.params:
|
|
|
|
|
self.protectedFiles += applyFiles
|
|
|
|
|
return applyFiles, False
|
|
|
|
|
else:
|
|
|
|
|
applyFiles = [pathOldFile]
|
|
|
|
|
if pathProg:
|
|
|
|
|
os.chdir(pathProg)
|
|
|
|
|
# Если файлы заменяются не нужно их обрабатывать дальше
|
|
|
|
|
if typeAppendTemplate == "replace" and \
|
|
|
|
|
not objHeadNew.params.has_key("symbolic") and \
|
|
|
|
|
objHeadNew.params.has_key("link"):
|
|
|
|
|
preReturn(pathProg)
|
|
|
|
|
return applyFiles, False
|
|
|
|
|
if not pathOldFile in self.dictProcessedTemplates:
|
|
|
|
|
self.dictProcessedTemplates[pathOldFile] = []
|
|
|
|
|
self.dictProcessedTemplates[pathOldFile].append(nameFileTemplate)
|
|
|
|
|
preReturn(pathProg)
|
|
|
|
|
if ("autoupdate" in optFile or "autoupdate" in objHeadNew.params) \
|
|
|
|
|
and not self.objVar.Get('cl_merge_pkg_pass'):
|
|
|
|
|
reCfg = re.compile(r"/._cfg\d{4}_", re.S)
|
|
|
|
|
self.autoUpdateFiles += map(lambda x: reCfg.sub('/', x), applyFiles)
|
|
|
|
|
if "protected" in objHeadNew.params:
|
|
|
|
|
self.protectedFiles += applyFiles
|
|
|
|
|
return applyFiles, objHeadNew
|
|
|
|
|
|
|
|
|
|
def createNewClass(self, name, bases, attrs=None):
|
|
|
|
|
"""Создает объект нового класса
|
|
|
|
|
|
|
|
|
|
createNewClass(self, name, bases, attrs)
|
|
|
|
|
name - имя класса - str,
|
|
|
|
|
bases - cписок наследуемых классов - (tuple),
|
|
|
|
|
attrs - аттрибуты класса - {dict}
|
|
|
|
|
"""
|
|
|
|
|
if attrs is None:
|
|
|
|
|
attrs = {}
|
|
|
|
|
|
|
|
|
|
class newMethod(object):
|
|
|
|
|
# Объединяем конфигурации
|
|
|
|
|
def join(self, newObj):
|
|
|
|
|
if newObj.__class__.__name__ == self.__class__.__name__:
|
|
|
|
|
if hasattr(self, "docObj"):
|
|
|
|
|
self.docObj.joinDoc(newObj.doc)
|
|
|
|
|
# Пост обработка
|
|
|
|
|
if hasattr(self, "postXML"):
|
|
|
|
|
self.postXML()
|
|
|
|
|
|
|
|
|
|
attrsNew = {"configName": name}
|
|
|
|
|
if attrs:
|
|
|
|
|
attrsNew.update(attrs)
|
|
|
|
|
newCl = type(name, bases + (newMethod, object,), attrsNew)
|
|
|
|
|
return newCl
|
|
|
|
|
|
|
|
|
|
def fileIsUtf(self, fileName):
|
|
|
|
|
"""Проверяет файл на кодировку UTF-8"""
|
|
|
|
|
if os.path.isfile(fileName):
|
|
|
|
|
FD = open(os.path.abspath(fileName), 'r')
|
|
|
|
|
newTemplate = FD.read(1) + FD.read()
|
|
|
|
|
FD.close()
|
|
|
|
|
try:
|
|
|
|
|
newTemplate.decode("UTF-8")
|
|
|
|
|
except UnicodeDecodeError:
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def joinTemplate(self, nameFileTemplate, nameFileConfig, optFile=None):
|
|
|
|
|
"""Объединения шаблона и конф. файла
|
|
|
|
|
|
|
|
|
|
join(nameFileTemplate, nameFileConfig, ListOptTitle)
|
|
|
|
|
Объединение шаблона nameFileTemplate и конф. файла nameFileConfig,
|
|
|
|
|
ListOptTitle - список строк которые добавятся в заголовок
|
|
|
|
|
optFile = опции для шаблона
|
|
|
|
|
"""
|
|
|
|
|
if optFile is None:
|
|
|
|
|
optFile = {}
|
|
|
|
|
# Выполняем условия для блока текста а так-же заменяем переменные
|
|
|
|
|
self.nameFileTemplate = os.path.abspath(nameFileTemplate)
|
|
|
|
|
self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
|
|
|
|
|
self.textTemplate = self.F_TEMPL.read()
|
|
|
|
|
self.configMode = T_ORIGIN
|
|
|
|
|
self.closeTemplFile()
|
|
|
|
|
# Флаг копирования шаблона в конфигурационный файл
|
|
|
|
|
flagCopyTemplate = True
|
|
|
|
|
# Тип шаблона бинарный или текстовый
|
|
|
|
|
if self.textTemplate[:11] == "# Calculate":
|
|
|
|
|
templateFileType = "text"
|
|
|
|
|
else:
|
|
|
|
|
templateFileType = self.getTemplateType()
|
|
|
|
|
headerLine = self.getHeaderText(self.textTemplate)
|
|
|
|
|
if headerLine:
|
|
|
|
|
moduleParam = filter(lambda x: x.startswith('env='),
|
|
|
|
|
headerLine.split())
|
|
|
|
|
if moduleParam:
|
|
|
|
|
self.objVar.defaultModule = moduleParam[0].partition('=')[2]
|
|
|
|
|
try:
|
|
|
|
|
importlib.import_module(
|
|
|
|
|
"calculate.%s.variables" % self.objVar.defaultModule)
|
|
|
|
|
except (ImportError, AttributeError):
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
if templateFileType != "bin":
|
|
|
|
|
# Заменяем переменные на их значения
|
|
|
|
|
self.textTemplate = self.applyVarsTemplate(self.textTemplate,
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
flagCopyTemplate = False
|
|
|
|
|
if not optFile:
|
|
|
|
|
optFile = {"path": os.path.split(nameFileConfig)[0]}
|
|
|
|
|
filesApply, objHeadNew = self.getApplyHeadTemplate(nameFileTemplate,
|
|
|
|
|
nameFileConfig,
|
|
|
|
|
templateFileType,
|
|
|
|
|
optFile)
|
|
|
|
|
if not objHeadNew:
|
|
|
|
|
return filesApply
|
|
|
|
|
if filesApply and not filter(lambda x: "calculate/ini.env" in x,
|
|
|
|
|
filesApply):
|
|
|
|
|
self.templateModify()
|
|
|
|
|
if templateFileType != "bin":
|
|
|
|
|
# Вычисляем условные блоки
|
|
|
|
|
objHeadNew.body = self.applyTermsTemplate(objHeadNew.body,
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
# Вычисляем функции
|
|
|
|
|
objHeadNew.body = self.applyFuncTemplate(objHeadNew.body,
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
# Настоящее имя конфигурационного файла
|
|
|
|
|
nameFileConfig = filesApply[0]
|
|
|
|
|
# Флаг - кодировка с бинарными примесями у файла шаблона включаем при
|
|
|
|
|
# условии текстового файла и кодировки отличной от UTF-8
|
|
|
|
|
flagNotUtf8New = False
|
|
|
|
|
# Флаг - кодировка с бинарными примесями у оригинального файла
|
|
|
|
|
flagNotUtf8Old = False
|
|
|
|
|
if not flagCopyTemplate:
|
|
|
|
|
# проверяем кодировку шаблона
|
|
|
|
|
if not self.fileIsUtf(nameFileTemplate):
|
|
|
|
|
flagNotUtf8New = True
|
|
|
|
|
if not (objHeadNew.params.has_key("link") and
|
|
|
|
|
objHeadNew.params.has_key("symbolic")):
|
|
|
|
|
# проверяем кодировку оригинального файла
|
|
|
|
|
if not self.fileIsUtf(nameFileConfig):
|
|
|
|
|
flagNotUtf8Old = True
|
|
|
|
|
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)
|
|
|
|
|
title = title.encode("UTF-8")
|
|
|
|
|
|
|
|
|
|
objHeadOld = False
|
|
|
|
|
if objHeadNew.comment:
|
|
|
|
|
objHeadOld = fileHeader(nameFileConfig, self.textConfig,
|
|
|
|
|
objHeadNew.comment)
|
|
|
|
|
elif objHeadNew.fileType and \
|
|
|
|
|
objHeadNew.typeAppend in ("before", "after"):
|
|
|
|
|
configFileType = self.getFileType(nameFileConfig)
|
|
|
|
|
objHeadOld = fileHeader(nameFileConfig, self.textConfig,
|
|
|
|
|
fileType=configFileType)
|
|
|
|
|
# Строка вызова скрипта (#!/bin/bash ...)
|
|
|
|
|
execStr = ""
|
|
|
|
|
if objHeadNew.execStr:
|
|
|
|
|
execStr = objHeadNew.execStr
|
|
|
|
|
elif objHeadOld and objHeadOld.execStr:
|
|
|
|
|
execStr = objHeadOld.execStr
|
|
|
|
|
|
|
|
|
|
if objHeadNew.fileType != 'patch':
|
|
|
|
|
wrongOpt = [x for x in ("multiline", "dotall")
|
|
|
|
|
if objHeadNew.params.has_key(x)]
|
|
|
|
|
if wrongOpt:
|
|
|
|
|
self.setError(
|
|
|
|
|
_("Option %s should be used for format=patch only")
|
|
|
|
|
% wrongOpt[0])
|
|
|
|
|
return None
|
|
|
|
|
if objHeadNew.fileType != 'dconf':
|
|
|
|
|
wrongOpt = [x for x in ("dconf",)
|
|
|
|
|
if objHeadNew.params.has_key(x)]
|
|
|
|
|
if wrongOpt:
|
|
|
|
|
self.setError(
|
|
|
|
|
_("Option %s should be used for format=dconf only")
|
|
|
|
|
% wrongOpt[0])
|
|
|
|
|
return None
|
|
|
|
|
if objHeadNew.fileType:
|
|
|
|
|
formatTemplate = objHeadNew.fileType
|
|
|
|
|
typeAppendTemplate = objHeadNew.typeAppend
|
|
|
|
|
if formatTemplate in ("patch", "diff", "dconf"):
|
|
|
|
|
if typeAppendTemplate != "patch":
|
|
|
|
|
self.setError(
|
|
|
|
|
_("Wrong option append=%(type)s in template %(file)s")
|
|
|
|
|
% {"type": typeAppendTemplate,
|
|
|
|
|
"file": nameFileTemplate})
|
|
|
|
|
return None
|
|
|
|
|
# создаем объект формата шаблона
|
|
|
|
|
objTempl = self.getFormatObj(formatTemplate, self.textTemplate)
|
|
|
|
|
if formatTemplate == 'patch':
|
|
|
|
|
if objHeadNew.params.has_key("multiline"):
|
|
|
|
|
objTempl.setMultiline()
|
|
|
|
|
if objHeadNew.params.has_key("dotall"):
|
|
|
|
|
objTempl.setDotall()
|
|
|
|
|
if formatTemplate == 'dconf':
|
|
|
|
|
if "dconf" in objHeadNew.params:
|
|
|
|
|
objTempl.setPath(objHeadNew.params['dconf'])
|
|
|
|
|
objTempl.setUser(self.objVar.Get('ur_login'))
|
|
|
|
|
if not objTempl:
|
|
|
|
|
self.setError(
|
|
|
|
|
_("Incorrect header parameter format=%s "
|
|
|
|
|
"in the template") \
|
|
|
|
|
% formatTemplate + " " + nameFileTemplate)
|
|
|
|
|
return None
|
|
|
|
|
if objHeadOld and objHeadOld.body:
|
|
|
|
|
self.textConfig = objHeadOld.body
|
|
|
|
|
# обработка конфигурационного файла
|
|
|
|
|
self.textTemplate = objTempl.processingFile(self.textConfig,
|
|
|
|
|
pathJoin(
|
|
|
|
|
self.objVar.Get(
|
|
|
|
|
'cl_chroot_path'),
|
|
|
|
|
self.objVar.Get(
|
|
|
|
|
'cl_root_path')))
|
|
|
|
|
error = objTempl.getError()
|
|
|
|
|
if error:
|
|
|
|
|
if formatTemplate == "dconf":
|
|
|
|
|
self.printERROR(error.strip())
|
|
|
|
|
raise TemplatesError(_("Failed to use dconf ") + \
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
raise TemplatesError(_("Failed to use patch ") + \
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
elif (formatTemplate == 'diff' and
|
|
|
|
|
self.objVar.Get('cl_verbose_set') == "on"):
|
|
|
|
|
self.printSUCCESS(_("Appling patch") + " " + \
|
|
|
|
|
os.path.basename(nameFileTemplate))
|
|
|
|
|
if execStr:
|
|
|
|
|
self.textConfig = execStr + title + self.textTemplate
|
|
|
|
|
else:
|
|
|
|
|
self.textConfig = title + self.textTemplate
|
|
|
|
|
if formatTemplate in ("diff",):
|
|
|
|
|
return objTempl.patchFiles
|
|
|
|
|
elif formatTemplate in ("dconf",):
|
|
|
|
|
return []
|
|
|
|
|
else:
|
|
|
|
|
self.saveConfFile()
|
|
|
|
|
if 'run' in objHeadNew.params:
|
|
|
|
|
if not self.executeTemplate(self.textConfig,
|
|
|
|
|
objHeadNew.params['run']):
|
|
|
|
|
self.setError(_("Wrong template") + _(": ") + \
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(_("Failed to execute") + _(": ") + \
|
|
|
|
|
self.nameFileConfig)
|
|
|
|
|
return None
|
|
|
|
|
return None
|
|
|
|
|
return filesApply if 'exec' not in objHeadNew.params else None
|
|
|
|
|
# Создаем объект в случае параметра format в заголовке
|
|
|
|
|
if (typeAppendTemplate == "replace" or
|
|
|
|
|
typeAppendTemplate == "before" or
|
|
|
|
|
typeAppendTemplate == "after") and \
|
|
|
|
|
not (formatTemplate == "bin" or
|
|
|
|
|
formatTemplate == "raw"):
|
|
|
|
|
# Преобразовываем бинарные файлы
|
|
|
|
|
objTxtCoder = None
|
|
|
|
|
if flagNotUtf8New:
|
|
|
|
|
objTxtCoder = utfBin()
|
|
|
|
|
self.textTemplate = objTxtCoder.encode(self.textTemplate)
|
|
|
|
|
# создаем объект формата шаблона
|
|
|
|
|
objTemplNew = self.getFormatObj(formatTemplate,
|
|
|
|
|
self.textTemplate)
|
|
|
|
|
if not objTemplNew:
|
|
|
|
|
self.setError(_("Incorrect header parameter format=%s "
|
|
|
|
|
"in the template")
|
|
|
|
|
% formatTemplate + " " + nameFileTemplate)
|
|
|
|
|
return None
|
|
|
|
|
if "xml_" in formatTemplate:
|
|
|
|
|
if objTemplNew.getError():
|
|
|
|
|
self.setError(_("Wrong template") + _(": ") +
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
return None
|
|
|
|
|
# Имя файла внутри xml xfce конфигурационных файлов
|
|
|
|
|
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().encode("UTF-8")
|
|
|
|
|
# Если не UTF-8 производим преобразование
|
|
|
|
|
if objTxtCoder:
|
|
|
|
|
self.textTemplate = objTxtCoder.decode(self.textTemplate)
|
|
|
|
|
# Титл для объединения
|
|
|
|
|
if ListOptTitle:
|
|
|
|
|
title = self.getTitle(objTemplNew._comment,
|
|
|
|
|
ListOptTitle,
|
|
|
|
|
configPath=nameFileConfig)
|
|
|
|
|
title = title.encode("UTF-8")
|
|
|
|
|
# Замена
|
|
|
|
|
if typeAppendTemplate == "replace":
|
|
|
|
|
if "xml_" in formatTemplate:
|
|
|
|
|
data = self.textTemplate.split("\n")
|
|
|
|
|
data.insert(1, title)
|
|
|
|
|
self.textConfig = "\n".join(data)
|
|
|
|
|
else:
|
|
|
|
|
if objHeadNew.execStr:
|
|
|
|
|
self.textConfig = objHeadNew.execStr + title + \
|
|
|
|
|
self.textTemplate
|
|
|
|
|
else:
|
|
|
|
|
self.textConfig = title + self.textTemplate
|
|
|
|
|
|
|
|
|
|
self.saveConfFile()
|
|
|
|
|
if 'run' in objHeadNew.params:
|
|
|
|
|
if not self.executeTemplate(self.textConfig,
|
|
|
|
|
objHeadNew.params['run']):
|
|
|
|
|
self.setError(_("Wrong template") + _(": ") + \
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(_("Failed to execute") + _(": ") + \
|
|
|
|
|
self.nameFileConfig)
|
|
|
|
|
return None
|
|
|
|
|
return None
|
|
|
|
|
return filesApply if not 'exec' in objHeadNew.params else None
|
|
|
|
|
# Вверху
|
|
|
|
|
elif typeAppendTemplate == "before":
|
|
|
|
|
if "xml_" in formatTemplate:
|
|
|
|
|
self.setError(
|
|
|
|
|
_("Wrong option append=before in template %s")
|
|
|
|
|
% nameFileTemplate)
|
|
|
|
|
return None
|
|
|
|
|
if objHeadOld and objHeadOld.body:
|
|
|
|
|
self.textConfig = objHeadOld.body
|
|
|
|
|
if self.textTemplate and self.textTemplate[-1] == "\n":
|
|
|
|
|
tmpTemplate = self.textTemplate + self.textConfig
|
|
|
|
|
else:
|
|
|
|
|
tmpTemplate = self.textTemplate + "\n" + self.textConfig
|
|
|
|
|
if execStr:
|
|
|
|
|
self.textConfig = execStr + title + tmpTemplate
|
|
|
|
|
else:
|
|
|
|
|
self.textConfig = title + tmpTemplate
|
|
|
|
|
|
|
|
|
|
self.saveConfFile()
|
|
|
|
|
if 'run' in objHeadNew.params:
|
|
|
|
|
if not self.executeTemplate(self.textConfig,
|
|
|
|
|
objHeadNew.params['run']):
|
|
|
|
|
self.setError(_("Wrong template") + _(": ") +
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(_("Failed to execute") + _(": ") +
|
|
|
|
|
self.nameFileConfig)
|
|
|
|
|
return None
|
|
|
|
|
return None
|
|
|
|
|
return filesApply if 'exec' not in objHeadNew.params else None
|
|
|
|
|
# Внизу
|
|
|
|
|
elif typeAppendTemplate == "after":
|
|
|
|
|
if "xml_" in formatTemplate:
|
|
|
|
|
self.setError(
|
|
|
|
|
_("Wrong option append=after in template %s")
|
|
|
|
|
% nameFileTemplate)
|
|
|
|
|
return None
|
|
|
|
|
if objHeadOld and objHeadOld.body:
|
|
|
|
|
self.textConfig = objHeadOld.body
|
|
|
|
|
if self.textTemplate[-1] == "\n":
|
|
|
|
|
tmpTemplate = self.textConfig + self.textTemplate
|
|
|
|
|
else:
|
|
|
|
|
tmpTemplate = self.textConfig + "\n" + self.textTemplate
|
|
|
|
|
if execStr:
|
|
|
|
|
self.textConfig = execStr + title + tmpTemplate
|
|
|
|
|
else:
|
|
|
|
|
self.textConfig = title + tmpTemplate
|
|
|
|
|
self.saveConfFile()
|
|
|
|
|
if 'run' in objHeadNew.params:
|
|
|
|
|
if not self.executeTemplate(self.textConfig,
|
|
|
|
|
objHeadNew.params['run']):
|
|
|
|
|
self.setError(_("Wrong template") + _(": ") +
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(_("Failed to execute") + _(": ") +
|
|
|
|
|
self.nameFileConfig)
|
|
|
|
|
return None
|
|
|
|
|
return None
|
|
|
|
|
return filesApply if 'exec' not in objHeadNew.params else None
|
|
|
|
|
# Объединение
|
|
|
|
|
elif typeAppendTemplate == "join":
|
|
|
|
|
objTxtCoder = None
|
|
|
|
|
if flagNotUtf8New:
|
|
|
|
|
objTxtCoder = utfBin()
|
|
|
|
|
self.textTemplate = objTxtCoder.encode(self.textTemplate)
|
|
|
|
|
if formatTemplate == "raw":
|
|
|
|
|
self.setError(
|
|
|
|
|
_("Incorrect header parameter append=%s "
|
|
|
|
|
"in the template")
|
|
|
|
|
% typeAppendTemplate + " " + nameFileTemplate)
|
|
|
|
|
return None
|
|
|
|
|
# создаем объект формата шаблона
|
|
|
|
|
objTemplNew = self.getFormatObj(formatTemplate,
|
|
|
|
|
self.textTemplate)
|
|
|
|
|
if not objTemplNew:
|
|
|
|
|
self.setError(
|
|
|
|
|
_("Incorrect header parameter format=%s in "
|
|
|
|
|
"the template")
|
|
|
|
|
% formatTemplate + " " + nameFileTemplate)
|
|
|
|
|
return None
|
|
|
|
|
if "xml_" in formatTemplate:
|
|
|
|
|
if objTemplNew.getError():
|
|
|
|
|
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)
|
|
|
|
|
title = title.encode("UTF-8")
|
|
|
|
|
|
|
|
|
|
# В случае пустого конфигурационного файла
|
|
|
|
|
reNoClean = re.compile("[^\s]", re.M)
|
|
|
|
|
if not self.textConfig or \
|
|
|
|
|
not reNoClean.search(self.textConfig):
|
|
|
|
|
self.textConfig = ""
|
|
|
|
|
|
|
|
|
|
objHeadOld = fileHeader(nameFileConfig, self.textConfig,
|
|
|
|
|
objTemplNew._comment)
|
|
|
|
|
if objHeadOld.body:
|
|
|
|
|
self.textConfig = objHeadOld.body
|
|
|
|
|
else:
|
|
|
|
|
self.textConfig = ""
|
|
|
|
|
if flagNotUtf8Old:
|
|
|
|
|
objTxtCoder = utfBin()
|
|
|
|
|
self.textConfig = objTxtCoder.encode(self.textConfig)
|
|
|
|
|
# создаем объект формата шаблона для конфигурационного файла
|
|
|
|
|
objTemplOld = self.getFormatObj(formatTemplate,
|
|
|
|
|
self.textConfig)
|
|
|
|
|
if not objTemplOld:
|
|
|
|
|
self.setError(_("Error in template %s") % nameFileConfig)
|
|
|
|
|
return None
|
|
|
|
|
if "xml_" in formatTemplate:
|
|
|
|
|
if objTemplOld.getError():
|
|
|
|
|
self.setError(_("Wrong template") + _(": ") +
|
|
|
|
|
nameFileConfig)
|
|
|
|
|
return None
|
|
|
|
|
nameRootNode = nameFileConfig.rpartition("/")[2].split(".")[
|
|
|
|
|
0]
|
|
|
|
|
objTemplOld.setNameBodyNode(nameRootNode)
|
|
|
|
|
|
|
|
|
|
objTemplOld.join(objTemplNew)
|
|
|
|
|
if "xml_" in formatTemplate:
|
|
|
|
|
if objTemplOld.getError():
|
|
|
|
|
self.setError(_("Wrong template") + _(": ") + \
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
return None
|
|
|
|
|
data = objTemplOld.getConfig().encode("UTF-8").split("\n")
|
|
|
|
|
data.insert(1, title)
|
|
|
|
|
self.textConfig = "\n".join(data)
|
|
|
|
|
else:
|
|
|
|
|
if execStr:
|
|
|
|
|
self.textConfig = execStr + title + \
|
|
|
|
|
objTemplOld.getConfig().encode(
|
|
|
|
|
"UTF-8")
|
|
|
|
|
else:
|
|
|
|
|
self.textConfig = title + \
|
|
|
|
|
objTemplOld.getConfig().encode(
|
|
|
|
|
"UTF-8")
|
|
|
|
|
# Декодируем если кодировка не UTF-8
|
|
|
|
|
if objTxtCoder:
|
|
|
|
|
self.textTemplate = objTxtCoder.decode(self.textTemplate)
|
|
|
|
|
self.textConfig = objTxtCoder.decode(self.textConfig)
|
|
|
|
|
self.saveConfFile()
|
|
|
|
|
if 'run' in objHeadNew.params:
|
|
|
|
|
if not self.executeTemplate(self.textConfig,
|
|
|
|
|
objHeadNew.params['run']):
|
|
|
|
|
self.setError(_("Wrong template") + _(": ") + \
|
|
|
|
|
nameFileTemplate)
|
|
|
|
|
self.setError(_("Failed to execute") + _(": ") + \
|
|
|
|
|
self.nameFileConfig)
|
|
|
|
|
return None
|
|
|
|
|
return None
|
|
|
|
|
return filesApply if not 'exec' in objHeadNew.params else None
|
|
|
|
|
else:
|
|
|
|
|
self.setError(_("Wrong template option (type append)")
|
|
|
|
|
+ _(": ") + typeAppendTemplate)
|
|
|
|
|
return None
|
|
|
|
|
else:
|
|
|
|
|
self.setError(_("Template type not found: ") + nameFileTemplate)
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class scanDirectoryClt(object):
|
|
|
|
|
"""Класс для cканирования директорий с файлами .clt"""
|
|
|
|
|
|
|
|
|
|
# Расширение файла шаблона
|
|
|
|
|
extFileTemplate = ".clt"
|
|
|
|
|
lenExtFileTemplate = len(extFileTemplate)
|
|
|
|
|
filterApplyTemplates = {}
|
|
|
|
|
reHeader = re.compile(r"\s*#\s*calculate\s*", re.I)
|
|
|
|
|
|
|
|
|
|
def __init__(self, objVar=None):
|
|
|
|
|
if objVar:
|
|
|
|
|
self.objVar = objVar
|
|
|
|
|
|
|
|
|
|
def processingFile(self, path, prefix, optFile=None):
|
|
|
|
|
"""Обработка в случае файла"""
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def hasBelong(self, filename):
|
|
|
|
|
"""
|
|
|
|
|
Change belong function
|
|
|
|
|
"""
|
|
|
|
|
f = open(filename, 'r')
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
def scanningTemplates(self, scanDir, prefix=None, flagDir=False,
|
|
|
|
|
objVar=None):
|
|
|
|
|
"""Сканирование и обработка шаблонов в директории scanDir"""
|
|
|
|
|
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)):
|
|
|
|
|
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):
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class templateClt(scanDirectoryClt, Template):
|
|
|
|
|
"""Класс для обработки шаблонов c расширением .clt"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, objVar, postmergePkgs, **kwargs):
|
|
|
|
|
self.checkNumberTemplate = True
|
|
|
|
|
Template.__init__(self, objVar, cltObj=False, **kwargs)
|
|
|
|
|
self.postmergePkgs = postmergePkgs
|
|
|
|
|
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"))
|
|
|
|
|
|
|
|
|
|
def applyTemplate(self, path):
|
|
|
|
|
"""Применение отдельного .clt шаблона"""
|
|
|
|
|
if not self.flagApplyTemplates:
|
|
|
|
|
return True
|
|
|
|
|
return self.processingFile(path, "")
|
|
|
|
|
|
|
|
|
|
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 = ""
|
|
|
|
|
# Проверка на переменные в названии файла
|
|
|
|
|
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(map(lambda x: x.split("?")[0],
|
|
|
|
|
nameFileConfig.split("/")))
|
|
|
|
|
# Записываем в переменную обрабатываемый файл
|
|
|
|
|
self.objVar.Set("cl_pass_file", nameFileConfig)
|
|
|
|
|
filesApl = self.joinTemplate(path, nameFileConfig)
|
|
|
|
|
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]:
|
|
|
|
|
self._addFile(filesApl, pkg=pkg)
|
|
|
|
|
else:
|
|
|
|
|
if not self.allContents:
|
|
|
|
|
fillContents(self.allContents,
|
|
|
|
|
self.objVar.Get('cl_config_protect'),
|
|
|
|
|
prefix=self.objVar.Get('cl_chroot_path'))
|
|
|
|
|
for fn in filesApl:
|
|
|
|
|
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:
|
|
|
|
|
self._addFile([fn], pkg=self.allContents[fn_orig])
|
|
|
|
|
# Настоящее имя конфигурационного файла
|
|
|
|
|
nameFileConfig = filesApl[0]
|
|
|
|
|
# Пишем время модификации *.env файлов
|
|
|
|
|
if nameFileConfig.endswith(".env"):
|
|
|
|
|
nameEnvFile = os.path.basename(nameFileConfig)
|
|
|
|
|
self.functObj.timeConfigsIni[nameEnvFile] = float(time.time())
|
|
|
|
|
self.filesApply += filesApl
|
|
|
|
|
return nameFileConfig
|
|
|
|
|
else:
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def countsNumberTemplates(self, dirsTemplates=()):
|
|
|
|
|
"""Считаем количество шаблонов"""
|
|
|
|
|
|
|
|
|
|
def createDictTemplates(path, prefix, dictTemplates):
|
|
|
|
|
"""Создает словарь {"директория":"кол-во шаблонов" ...}
|
|
|
|
|
|
|
|
|
|
и считает общее количество шаблонов
|
|
|
|
|
"""
|
|
|
|
|
# Количество шаблонов
|
|
|
|
|
self.allTemplates += 1
|
|
|
|
|
dirTemplate = os.path.split(path)[0]
|
|
|
|
|
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 = self.objVar.Get("cl_template_clt_path")
|
|
|
|
|
dirsTemplates.sort()
|
|
|
|
|
scanObj = scanDirectoryClt(objVar=self.objVar)
|
|
|
|
|
scanObj.processingFile = lambda x, y: createDictTemplates(x, y,
|
|
|
|
|
self.dictTemplates)
|
|
|
|
|
# Считаем количество шаблонов
|
|
|
|
|
for dirTemplate in dirsTemplates:
|
|
|
|
|
scanObj.scanningTemplates(dirTemplate, "/")
|
|
|
|
|
|
|
|
|
|
def applyTemplatesClt(self, cltPath=None):
|
|
|
|
|
"""Применяет шаблоны к конфигурационным файлам"""
|
|
|
|
|
if not self.flagApplyTemplates:
|
|
|
|
|
return [], []
|
|
|
|
|
if cltPath is None and \
|
|
|
|
|
not self.objVar.defined("cl_template_clt_path"):
|
|
|
|
|
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.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)
|
|
|
|
|
# default module
|
|
|
|
|
self.defaultModule = "main"
|
|
|
|
|
# Обрабатываем шаблоны
|
|
|
|
|
for dirTemplate in dirsTemplates:
|
|
|
|
|
if self.scanningTemplates(dirTemplate, self._chrootDir) is False:
|
|
|
|
|
break
|
|
|
|
|
return self.createdDirs, self.filesApply
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ProgressTemplate(Template):
|
|
|
|
|
"""
|
|
|
|
|
Progress template for wsdl interface
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, setValueCallback, *args, **kwargs):
|
|
|
|
|
Template.__init__(self, *args, **kwargs)
|
|
|
|
|
self.setValueCallback = setValueCallback
|
|
|
|
|
self.value = None
|
|
|
|
|
self.firstValue = True
|
|
|
|
|
|
|
|
|
|
def numberAllTemplates(self, number):
|
|
|
|
|
self.maximum = number
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def numberProcessTemplates(self, number):
|
|
|
|
|
maximum = self.maximum or 1
|
|
|
|
|
value = number * 100 / maximum
|
|
|
|
|
if value != self.value:
|
|
|
|
|
self.setValueCallback(min(100, max(0, value)))
|
|
|
|
|
self.value = value
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def templateModify(self):
|
|
|
|
|
if self.firstValue and hasattr(self, "onFirstValue"):
|
|
|
|
|
self.onFirstValue()
|
|
|
|
|
self.firstValue = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SystemIni(object):
|
|
|
|
|
_inifile = '/etc/calculate/ini.env'
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def inifile(self):
|
|
|
|
|
if self.dv:
|
|
|
|
|
return pathJoin(self.dv.Get('cl_chroot_path'), self._inifile)
|
|
|
|
|
else:
|
|
|
|
|
return self._inifile
|
|
|
|
|
|
|
|
|
|
def __init__(self, dv=None):
|
|
|
|
|
self.config = ConfigParser(strict=False)
|
|
|
|
|
self.dv = dv
|
|
|
|
|
self.config.read(self.inifile, encoding="utf-8")
|
|
|
|
|
|
|
|
|
|
def getVar(self, section, varname):
|
|
|
|
|
return self.config.get(section, varname, raw=True, fallback="")
|
|
|
|
|
|
|
|
|
|
def delVar(self, section, varname):
|
|
|
|
|
try:
|
|
|
|
|
self.config.remove_option(section, varname)
|
|
|
|
|
for section in filter(lambda x: not self.config[x],
|
|
|
|
|
self.config.sections()):
|
|
|
|
|
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, 'wb') 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()
|