You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
calculate-utils-3-lib/pym/calculate/lib/cl_template.py

5507 lines
245 KiB

9 years ago
# -*- coding: utf-8 -*-
# Copyright 2008-2016 Mir Calculate. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
import os
import stat
import re
import importlib
9 years ago
from calculate.lib.cl_xml import xmlShare
import types
import random
import string
import time
import glob
import hashlib
import codecs
from fnmatch import fnmatch
from math import sqrt
from itertools import *
from collections import OrderedDict
from operator import lt, le, eq, ne, ge, gt
9 years ago
from utils.common import _error, _warning, getTupleVersion, getPortageUidGid
from utils.text import _u
from utils.portage import (isPkgInstalled, reVerSplitToPV, EmergeLog,
EmergeLogPackageTask, getPkgUses)
9 years ago
from utils.content import PkgContents, checkContents, getCfgFiles, fillContents
from utils.files import (getModeFile, listDirectory, removeDir, typeFile,
scanDirectory,
pathJoin, readFile, readLinesFile, process, Mounts)
from datavars import DataVarsError
from calculate.lib.configparser import ConfigParser, NoSectionError
from calculate.lib.cl_lang import setLocalTranslate, RegexpLocalization
9 years ago
_ = lambda x: x
setLocalTranslate('cl_lib3', sys.modules[__name__])
9 years ago
PORTAGEUID, PORTAGEGID = getPortageUidGid()
11 years ago
9 years ago
class TemplatesError(Exception):
"""
Error on templates appling
"""
9 years ago
def catch_no_space_left(f):
def wrapper(*args, **kw):
try:
9 years ago
return f(*args, **kw)
except IOError as e:
if e.errno == 28:
raise TemplatesError(_("No space left on device"))
raise
9 years ago
return wrapper
9 years ago
class _shareTermsFunction(object):
"""Общие аттрибуты для классов _terms и templateFunctions"""
# Символы допустимые в скобках функции шаблона
9 years ago
_reFunctionArgvInSquareBrackets = ("a-zA-Z0-9_:;<>=\!\|\{\}\^\$\?\(\)\[\]\-"
"\+\,\*\/\.\'\"~\\\\ ")
_reFunctionArgvText = "[%s]" % _reFunctionArgvInSquareBrackets
# регулярное выражение для поиска функции в шаблоне
9 years ago
_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)
# Регулярное выражение для названия переменной
9 years ago
_reRightName = re.compile("^(?:[a-z_\-]+\.)?(?:[a-zA-Z0-9_\-]+)$")
# Регулярное выражение для сравниваемого значения
_reDenyValue = re.compile("[^0-9a-zA-Z_/\.-]")
# латинские буквы в нижнем регистре
_letters = list(string.ascii_lowercase)
9 years ago
# использует из других объектов
objVar = None
def _splitVersion(self, strVersion):
"""
Split version. Version, addition letter, list suffixes with version,
revision.
Examples:
12 years ago
3.0.0_beta2
("3.0.0_beta2","",[],"")
3.0.0_beta2-r1
("3.0.0_beta2","",[],"r1")
3.0.0_beta2a-r1
("3.0.0_beta2","a",[],"r1")
3.0.0_beta2a_rc1-r1
("3.0.0_beta2","a",[("rc","1")],"r1")
3.0.0_beta2a_rc1_p20111212-r1
("3.0.0_beta2","a",[("rc1","1"),("p","20111212")],"r1")
"""
# get revision from version
strWorkVersion, spl, rVersion = strVersion.rpartition("-")
if rVersion == strVersion:
strWorkVersion = rVersion
rVersion = ""
suffixes = []
# get suffixes from version
while "_" in strWorkVersion:
# 2.3_p45 ('2.3','_','p43')
# 2.3_rc4_p45 ('2.3_rc4','_','p43')
strWorkVersion, spl, suffix = strWorkVersion.rpartition("_")
suffSplList = filter(lambda x: suffix.startswith(x),
self._suffixDict.keys())
if suffSplList:
suffSpl = suffSplList[0]
lenSuffSpl = len(suffSpl)
suffixVersion = suffix[lenSuffSpl:]
9 years ago
suffixes.append((suffSpl, suffixVersion))
letters = ""
numberVersion = strWorkVersion
if numberVersion and numberVersion[-1:] in self._letters:
letters = numberVersion[-1:]
numberVersion = numberVersion[:-1]
return numberVersion, letters, suffixes, rVersion
def _notVersion(self, strVersion):
"""strVersion is not version - True"""
9 years ago
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
9 years ago
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):
"""Конвертирование номеров версий для корректного сравнения
"""
9 years ago
def fillZero(elemA, elemB):
9 years ago
# elemA, elemB = elemA[], elemB[]
if len(elemA) > len(elemB):
9 years ago
maxElemB = len(elemB) - 1
for i in range(len(elemA)):
if i > maxElemB:
elemB.append("0")
else:
9 years ago
maxElemA = len(elemA) - 1
for i in range(len(elemB)):
if i > maxElemA:
elemA.append("0")
for i in range(len(elemB)):
lenA = len(elemA[i])
lenB = len(elemB[i])
if lenA == lenB:
pass
elif lenA > lenB:
res = lenA - lenB
for z in range(res):
elemB[i] = "0" + elemB[i]
elif lenB > lenA:
res = lenB - lenA
for z in range(res):
elemA[i] = "0" + elemA[i]
9 years ago
def fillSuffix(elemA, elemB, sA, svA, sB, svB):
if str(sA) or str(sB):
9 years ago
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)
9 years ago
# Version, letters, suffix, suffixVersion, rVersion
vA, lA, ssA, rvA = self._splitVersion(verA)
vB, lB, ssB, rvB = self._splitVersion(verB)
elemA = vA.split(".")
elemB = vB.split(".")
fillZero(elemA, elemB)
if lA or lB:
lA, lB = map(lambda x: x if x else '0', (lA, lB))
elemA.append(lA)
elemB.append(lB)
# dereferencing suffix in suffixes list
9 years ago
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:
9 years ago
sB, svB = ssB.pop()
else:
9 years ago
sB, svB = "", ""
fillSuffix(elemA, elemB, suffix, sufVer, sB, svB)
while ssB:
9 years ago
sB, svB = ssB.pop()
fillSuffix(elemA, elemB, "", "", sB, svB)
if rvA or rvB:
rvA, rvB = map(lambda x: [x[1:]], (rvA, rvB))
fillZero(rvA, rvB)
elemA += rvA
elemB += rvB
9 years ago
return ".".join(elemA), ".".join(elemB)
9 years ago
def _equalTerm(self, term, textError, function=None):
"""Вычисление логических выражений для условий
Для корректной работы в классе который наследует этот класс
должен быть объявлен аттрибут self.objVar
(объект для работы с переменными)
function - функция для для обработки функций в заголовке блока
"""
9 years ago
rpl = lambda x: x.replace("@@", " ")
trm = {"&&": "@@and@@", "||": "@@or@@"}
dictRuleFunc = OrderedDict((("==", eq), ("!=", ne),
(">=", ge), ("<=", le),
(">", gt), ("<", lt)))
rule = dictRuleFunc.keys()
listEqual = []
for k in trm.keys():
if k in term:
9 years ago
term = term.replace(k, trm[k])
trs = term.split("@@")
14 years ago
listSplitOr = []
if "or" in trs:
lst = []
for t in trs:
if t != "or":
lst.append(t)
else:
14 years ago
listSplitOr.append(lst)
lst = []
if lst:
listSplitOr.append(lst)
else:
listSplitOr = [trs]
for trsAnd in listSplitOr:
listEqual = []
for t in trsAnd:
def search_rule(t, rule, prefix=""):
for sepF in rule:
if sepF in t:
vals = list(t.partition(sepF)[::2])
if vals[0].endswith("\\"):
9 years ago
return search_rule(vals[1], rule,
prefix="%s%s%s" % (
prefix, vals[0], sepF))
return True, sepF, ["%s%s" % (prefix, vals[0]),
vals[1]]
return False, None, []
flagRule, sepF, vals = search_rule(t, rule)
14 years ago
if flagRule:
9 years ago
# проверка на допустимость названия переменной
14 years ago
flagFunction = False
12 years ago
if not self._reRightName.search(vals[0]):
9 years ago
# проверка на допустимость функции
14 years ago
flagError = True
9 years ago
if callable(function):
14 years ago
searchFunct = self._reFunction.search(vals[0])
if searchFunct:
flagError = False
flagFunction = True
if flagError:
9 years ago
self.setError(
"'%s'" % rpl(term) + " " + _("incorrect"))
14 years ago
self.setError(textError)
return False
9 years ago
# проверка на допустимость значения
14 years ago
if self._reDenyValue.search(vals[1]):
9 years ago
self.setError("'%s'" % rpl(term) + " " + _("incorrect"))
self.setError(textError)
return False
14 years ago
flagIntTypeVar = None
9 years ago
if flagFunction and callable(function):
valVars = function("#-%s-#" % vals[0])
14 years ago
if valVars is False:
9 years ago
self.setError(
"'%s'" % rpl(term) + " " + _("incorrect"))
14 years ago
self.setError(textError)
return False
9 years ago
if "load" == searchFunct.group(1) and \
re.search("\(\s*num\s*,", vals[0]):
14 years ago
if valVars:
try:
valVars = int(valVars)
9 years ago
except ValueError:
self.setError("'%s'" % rpl(term) + " " +
_("incorrect"))
14 years ago
self.setError(textError)
return False
flagIntTypeVar = True
else:
flagIntTypeVar = False
else:
9 years ago
if valVars == "" and \
not self._notVersion(vals[1]):
valVars = "0"
elif vals[1] == "" and \
not self._notVersion(valVars):
vals[1] = "0"
else:
14 years ago
try:
14 years ago
valVars = self.objVar.Get(vals[0])
varTable = self.objVar.Get('cl_used_action')
9 years ago
varTable.append((vals[0], vals[1]))
if not valVars:
valVars = ""
except DataVarsError, e:
raise TemplatesError("{header}\n{body}".format(
9 years ago
header=textError, body=str(e)))
14 years ago
# Номера версий для ini
flagNotIniFunct = True
# Два значения не пусты
flagNotEmptyVals = not (valVars == "" and vals[1] == "")
9 years ago
if flagFunction and flagNotEmptyVals and \
searchFunct.group(1) == "ini":
14 years ago
# Проверка значения на версию
9 years ago
if not self._notVersion(valVars) and \
not self._notVersion(vals[1]):
verFile, verVar = self._convertVers(vals[1],
valVars)
res = dictRuleFunc[sepF](verVar, verFile)
14 years ago
if res:
listEqual.append(True)
else:
listEqual.append(False)
break
14 years ago
flagNotIniFunct = False
# Cравниваем номера версий
if flagNotIniFunct:
9 years ago
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]))):
14 years ago
# Проверка значения на версию
if self._notVersion(vals[1]):
9 years ago
self.setError("'%s'" % rpl(term) + " " + \
_("incorrect"))
12 years ago
self.setError(
_("This value is not a version"))
14 years ago
return False
# Проверка значения функции на версию
if self._notVersion(valVars):
9 years ago
self.setError("'%s'" % rpl(term) + " " + \
_("incorrect"))
9 years ago
self.setError(
12 years ago
_("The function value is not a version"))
return False
9 years ago
verFile, verVar = self._convertVers(vals[1],
valVars)
res = dictRuleFunc[sepF](verVar, verFile)
if res:
listEqual.append(True)
else:
listEqual.append(False)
break
else:
14 years ago
if flagIntTypeVar is None:
flagIntTypeVar = True
try:
valVars = int(valVars)
except (TypeError, ValueError):
14 years ago
flagIntTypeVar = False
if flagIntTypeVar:
if not vals[1].strip():
14 years ago
vals[1] = 0
try:
valFile = int(vals[1])
valVar = valVars
res = dictRuleFunc[sepF](valVar, valFile)
if res:
listEqual.append(True)
else:
listEqual.append(False)
break
9 years ago
except ValueError:
flagIntTypeVar = False
if not flagIntTypeVar:
14 years ago
if sepF == "!=" or sepF == "==":
if not vals[1].strip():
vals[1] = ""
valFile = vals[1]
valVar = valVars
res = dictRuleFunc[sepF](valVar, valFile)
14 years ago
if res:
listEqual.append(True)
else:
listEqual.append(False)
break
else:
14 years ago
if not flagNotEmptyVals:
listEqual.append(False)
break
14 years ago
else:
9 years ago
self.setError("'%s'" % rpl(term) + " " \
+ _("incorrect"))
14 years ago
self.setError(textError)
return False
else:
if t == "and":
if listEqual == [] or False in listEqual:
listEqual = [False]
break
14 years ago
else:
listEqual = [True]
else:
9 years ago
self.setError("'%s'" % rpl(term) + " " + _("incorrect"))
14 years ago
self.setError(textError)
return False
if not (listEqual == [] or False in listEqual):
break
if listEqual == [] or False in listEqual:
return False
return True
def splitParLine(self, linePar):
9 years ago
"""
Split params line
"""
def splitQuote(listPar, quoteSymbol):
9 years ago
listTerm = map(lambda x: x + quoteSymbol, ("=", ">", "<"))
flagQ = False
mass = []
v = ""
for i in listPar:
9 years ago
if i.count(quoteSymbol) == 1:
if flagQ and i.endswith(quoteSymbol):
v = v + " " + i
mass.append(v)
v = ""
flagQ = False
elif filter(lambda x: x in i, listTerm):
flagQ = True
v = i
else:
9 years ago
mass.append(i)
elif flagQ:
v = v + " " + i
else:
mass.append(i)
9 years ago
foundPar = list(set(mass) - set(listPar))
return not flagQ, filter(lambda x: not x in foundPar,
mass), foundPar
9 years ago
listPar = re.split("\s+", linePar)
flagFoundQ = "'" in linePar
flagFoundQQ = '"' in linePar
if flagFoundQ and flagFoundQQ:
9 years ago
flagQ, listSplQPar, listFoundQPar = splitQuote(listPar, "'")
if flagQ:
flagQQ, listSplQQPar, listFoundQQPar = splitQuote(listSplQPar,
'"')
if flagQQ:
listPar = listSplQQPar + listFoundQPar + listFoundQQPar
elif flagFoundQQ:
9 years ago
flagQQ, listSplQQPar, listFoundQQPar = splitQuote(listPar, '"')
if flagQQ:
listPar = listSplQQPar + listFoundQQPar
elif flagFoundQ:
9 years ago
flagQ, listSplQPar, listFoundQPar = splitQuote(listPar, "'")
if flagQ:
listPar = listSplQPar + listFoundQPar
if flagFoundQ:
listQPar = []
for par in listPar:
9 years ago
if par.endswith("'") and par.count("'") > 1:
listQPar.append(par[:-1].replace("='", "="))
else:
listQPar.append(par)
listPar = listQPar
if flagFoundQQ:
listQQPar = []
for par in listPar:
9 years ago
if par.endswith('"') and par.count('"') > 1:
listQQPar.append(par[:-1].replace('="', '='))
else:
listQQPar.append(par)
listPar = listQQPar
return listPar
9 years ago
class fileHeader(_terms):
"""Обработка заголовков шаблонов и конфигурационных файлов
"""
# Допустимые параметры заголовка
9 years ago
allowParam = ["format", "dotall", "multiline",
"comment", "append", "force", "dconf",
"link", "mirror", "symbolic", "chmod", "chown", "name",
9 years ago
"path", "autoupdate", "protected", "run", "exec", "merge",
"module", "env", "postmerge"]
# Тип шаблона
fileType = ""
# Тип вставки шаблона
typeAppend = ""
# Возможные типы вставки шаблонов
9 years ago
_fileAppend = "join", "before", "after", "replace", "remove", "skip", \
"patch", "clear"
# Интерпретатор (#!/bin/bash) (#!/usr/bin/python)
execStr = ""
# Символ комментария
comment = False
# Выражение для поиска строки интерпретатора
9 years ago
reExecStr = re.compile("^(#!.+\s)", re.M)
# условные операторы
terms = ('>', '<', '==', '!=', '>=', '<=')
# параметры без значения
listParNotVal = ("multiline", "dotall", "symbolic", "force", "mirror",
"autoupdate", "protected")
# Результат вычисления условия в заголовке
headerTerm = True
9 years ago
def __init__(self, templateName, text, comment=None, fileType=False,
objVar=False, function=None, templateObj=None):
self.body = text
# Объект с переменными
9 years ago
self.objVar = objVar
# Параметры описанные в заголовке файла шаблона
self.params = {}
# некорректные параметры
incorrectParams = []
14 years ago
# Поиск строки запустка (#!/bin/bash и.т. д)
9 years ago
if comment or fileType != "bin":
14 years ago
reExecRes = self.reExecStr.search(self.body)
if reExecRes:
self.execStr = self.body[reExecRes.start():reExecRes.end()]
9 years ago
self.body = self.body[:reExecRes.start()] + \
self.body[reExecRes.end():]
# Удаление Заголовка Calculate
if comment:
titleFirst = "Modified"
# В случае текста XML
9 years ago
if isinstance(comment, tuple) and len(comment) == 2:
reCalcHeader = \
re.compile("\s*%s\s+%s.+\s+(.+\n)+%s\s?" \
% (comment[0], titleFirst, comment[1]),
re.M | re.I)
reS = reCalcHeader.search(self.body)
if reS:
9 years ago
self.body = self.body[:reS.start()] + self.body[reS.end():]
else:
9 years ago
reCalcHeader = re.compile(
"\s*%s\-+\s+%s\s+%s.+\s+(%s.+\s+)+%s\-+\s?" \
% (comment, comment, titleFirst, comment, comment),
re.M | re.I)
reS = reCalcHeader.search(self.body)
if reS:
self.body = self.body[reS.end():]
9 years ago
if fileType is not False:
if fileType == "bin":
self.params["format"] = fileType
self.fileType = self._getType()
self.typeAppend = self._getAppend()
else:
textLines = self.body.splitlines()
if textLines:
textLine = textLines[0]
9 years ago
rePar = re.compile(
"\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$", re.I)
reP = rePar.search(textLine)
if reP:
9 years ago
reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*", re.M)
reLs = reLns.search(self.body)
if reLs:
reL = reLs
paramLine = self.body[reP.end():reLs.end()]
9 years ago
paramLine = paramLine.replace("\\", " ")
else:
reLn = re.compile("\n")
reL = reLn.search(self.body)
paramLine = textLine[reP.end():]
if reL:
self.body = self.body[reL.end():]
else:
self.body = ""
9 years ago
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
9 years ago
errorMsg = _("Incorrect template") + \
_(
": ") + templateName + "\n" + \
_(
"template header not valid") + \
_(": ") + i
if function:
14 years ago
rezTerm = self._equalTerm(i,
errorMsg,
function)
else:
14 years ago
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():
9 years ago
incorrectParams = {i}
elif len(par) == 2:
self.params[par[0]] = par[1]
if par[0] == "env":
try:
9 years ago
importlib.import_module(
"calculate.%s.variables"
9 years ago
% par[1])
except (ImportError,
9 years ago
AttributeError):
self.headerTerm = False
self.comment = self._getComment()
self.fileType = self._getType()
14 years ago
typeAppend = self._getAppend()
if typeAppend:
self.typeAppend = typeAppend
else:
self.headerTerm = False
9 years ago
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:
9 years ago
self.execStr = "#!%s\n" % self.params['exec']
if 'run' in self.params:
9 years ago
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
9 years ago
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):
"""Выдать тип добавления файла"""
14 years ago
if self.params.has_key("append"):
if self.params["append"] in self._fileAppend:
return self.params["append"]
else:
return False
else:
9 years ago
if self.fileType != "raw" and self.fileType != "bin" and \
self.fileType != "":
11 years ago
if "format" in self.params and self.params["format"] in \
9 years ago
("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"):
9 years ago
return "<!--", "-->"
else:
return self.params["comment"]
else:
return False
class dirHeader(_terms):
"""Обработка заголовков шаблонов директорий
"""
# Допустимые параметры заголовка
12 years ago
allowParam = ["append", "chmod", "chown", "name", "path", "autoupdate",
9 years ago
"module", "env", "merge", "postmerge"]
# Тип вставки шаблона
typeAppend = ""
14 years ago
# Возможные типы вставки шаблонов
_fileAppend = "join", "remove", "skip", "clear"
14 years ago
# условные операторы
terms = ('>', '<', '==', '!=', '>=', '<=')
14 years ago
# параметры без значения
listParNotVal = ("symbolic", "force", "autoupdate")
14 years ago
# Результат вычисления условия в заголовке
headerTerm = True
9 years ago
def __init__(self, templateName, text, objVar=False, function=None):
self.body = text
# Объект с переменными
9 years ago
self.objVar = objVar
# Параметры описанные в заголовке файла шаблона
self.params = {}
# некорректные параметры
incorrectParams = set([])
textLines = text.splitlines()
flagErrorBody = False
if textLines:
textLine = textLines[0]
9 years ago
rePar = re.compile(
"\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$", re.I)
reP = rePar.search(textLine)
if reP:
9 years ago
reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*", re.M)
reLs = reLns.search(text)
if reLs:
reL = reLs
paramLine = text[reP.end():reLs.end()]
9 years ago
paramLine = paramLine.replace("\\", " ")
else:
reLn = re.compile("\n")
reL = reLn.search(text)
paramLine = textLine[reP.end():]
if reL:
self.body = text[reL.end():]
else:
self.body = ""
if self.body.strip():
self.headerTerm = False
9 years ago
self.setError(_("incorrect text in the template: '%s'")
9 years ago
% self.body)
flagErrorBody = True
if not flagErrorBody:
paramList = self.splitParLine(paramLine)
if paramList:
for i in paramList:
foundTerm = False
for term in self.terms:
if term in i:
foundTerm = True
errorMsg = (_("Incorrect template") +
9 years ago
_(": ") + templateName + "\n" +
9 years ago
_("template header not valid")
+ _(": ") + i)
if function:
14 years ago
rezTerm = self._equalTerm(i, errorMsg,
function)
else:
14 years ago
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():
9 years ago
incorrectParams = {i}
elif len(par) == 2:
self.params[par[0]] = par[1]
if par[0] == "env":
try:
9 years ago
importlib.import_module(
"calculate.%s.variables" %
par[1])
except (ImportError, AttributeError):
self.headerTerm = False
12 years ago
self.objVar.defaultModule = \
self.params['env']
typeAppend = self._getAppend()
if typeAppend:
self.typeAppend = typeAppend
else:
self.headerTerm = False
9 years ago
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
9 years ago
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"
9 years ago
class blocText(object):
"""Разбиваем текст на блоки"""
9 years ago
def splitTxtToBloc(self, text, openTxtBloc, closeTxtBloc,
commentTxtBloc, sepField):
"""Делит текст на блоки (без заголовков)
openTxtBloc - регулярное выражение для начала блока
closeTxtBloc - регулярное выражение для конца блока
commentTxtBloc - регулярное выражение - комментарий
возвращает блоки текста
"""
blocs = []
level = 0
# Нахождение нескольких блоков в строке
# разделители линий, разделителями могут быть ("","\n")
sepsLines = []
# линии
txtLines = []
# Исходные строки
txtLinesSrc = text.splitlines()
for line in txtLinesSrc:
lineTmpA = line
closeBl = False
txtLinesTmp = []
commentSpl = commentTxtBloc.split(line)
9 years ago
textLine = None
commentLine = None
if commentSpl[0].strip():
closeBl = True
if len(commentSpl) > 1:
commentBl = commentTxtBloc.search(line)
9 years ago
textLine = commentSpl[0]
commentLine = line[commentBl.start(0):]
lineTmpA = textLine
9 years ago
while closeBl:
closeBl = sepField.search(lineTmpA)
if closeBl:
lineTmpB = lineTmpA[closeBl.end(0):]
txtLinesTmp.append(lineTmpA[:closeBl.end(0)])
lineTmpA = lineTmpB
if lineTmpA.strip():
txtLinesTmp.append(lineTmpA)
# Если есть значение и комментарий в строке
9 years ago
if textLine is not None:
for l in txtLinesTmp:
txtLines.append(l)
sepsLines.append("")
if not txtLinesTmp:
txtLines.append(textLine)
sepsLines.append("")
txtLines.append(commentLine)
sepsLines.append("\n")
# Если есть несколько блоков в строке
9 years ago
elif len(txtLinesTmp) > 1 and txtLinesTmp[1].strip():
lenTmpLines = len(txtLinesTmp)
for l in range(lenTmpLines):
txtLines.append(txtLinesTmp[l])
9 years ago
if l == lenTmpLines - 1:
sepsLines.append("\n")
else:
sepsLines.append("")
# Cтрока не преобразована
else:
txtLines.append(line)
sepsLines.append("\n")
# разбивание на блоки
z = 0
bl = ""
for i in txtLines:
if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(i):
level += len(openTxtBloc.split(i)) - 1
if commentTxtBloc.split(i)[0].strip() and closeTxtBloc.search(i):
level -= len(closeTxtBloc.split(i)) - 1
bl += i + sepsLines[z]
if level == 0:
if bl:
blocs.append(bl)
bl = ""
z += 1
# cоздание блоков с элементами не входящими в блоки
realBlocs = []
z = 0
bl = ""
for i in blocs:
txtLines = i.splitlines()
if len(txtLines) > 0:
line = txtLines[0]
else:
line = i
if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(line):
if bl:
realBlocs.append(bl)
bl = ""
realBlocs.append(i)
else:
bl += i
z += 1
if bl:
realBlocs.append(bl)
if level == 0:
if text and text[-1] != "\n":
tmpBlocs = realBlocs.pop()
tmpBlocs = tmpBlocs[:-1]
realBlocs.append(tmpBlocs)
return realBlocs
else:
return []
def findArea(self, text, reTextHeader, reTextArea, numGroupArea=0):
""" Делит текст на области (с заголовками)
reTextHeader - регулярное выражение для заголовка области
reTextArea - регулярное выражение для всей области
numGroupArea - номер групы результата поиска по регулярному выражению
по всей области
возвращает два списка: первый - заголовки, второй - тела областей без
заголоков
"""
# Заголовки областей
headersArea = []
# Тексты областей без заголовков
textBodyArea = []
r = reTextArea.search(text)
if not r:
headersArea.append("")
textBodyArea.append(text)
9 years ago
return headersArea, textBodyArea
txtWr = text
while r:
textArea = r.group(numGroupArea)
txtSpl = txtWr.split(textArea)
9 years ago
area = txtSpl[0]
txtWr = txtSpl[1]
if area:
headersArea.append("")
textBodyArea.append(area)
res = reTextHeader.search(textArea)
header = textArea[:res.end()]
body = textArea[res.end():]
headersArea.append(header)
textBodyArea.append(body)
if txtWr:
r = reTextArea.search(txtWr)
else:
r = False
if txtWr:
headersArea.append("")
textBodyArea.append(txtWr)
9 years ago
return headersArea, textBodyArea
def findBloc(self, text, captionTxtBloc, bodyTxtBloc):
""" Делит текст на блоки (с заголовками)
captionTxtBloc - регулярное выражение для заголовка блока
bodyTxtBloc - регулярное выражение для тела блока
возвращает два списка: первый - заголовки, второй - тела блоков
"""
# Заголовки блоков
headersTxt = []
# Тексты блоков
blocsTxt = []
r = captionTxtBloc.search(text)
if r:
headersTxt.append(r.group(0))
txtSpl = text.partition(r.group(0))
9 years ago
blocTxt = txtSpl[0]
txtWr = txtSpl[2]
rb = bodyTxtBloc.search(blocTxt)
if not blocTxt:
blocsTxt.append(blocTxt)
if rb:
blocsTxt.append(rb.group(0))
9 years ago
while r:
r = captionTxtBloc.search(txtWr)
if r:
headersTxt.append(r.group(0))
txtSpl = txtWr.partition(r.group(0))
9 years ago
blocTxt = txtSpl[0]
txtWr = txtSpl[2]
rb = bodyTxtBloc.search(blocTxt)
if rb:
blocsTxt.append(rb.group(0))
else:
blocsTxt.append(txtWr)
if headersTxt and blocsTxt:
9 years ago
if len(headersTxt) > len(blocsTxt):
blocsTxt.insert(0, "")
elif len(headersTxt) < len(blocsTxt):
headersTxt.insert(0, "")
if len(headersTxt) != len(blocsTxt):
return False
9 years ago
return headersTxt, blocsTxt
else:
return False
class _file(_error):
"""
9 years ago
Класс для работы с файлами
"""
configMode = None
def printWARNING(self, s):
raise NotImplemented()
def __init__(self):
14 years ago
# Имя файла конфигурационного файла
self.nameFileConfig = ""
14 years ago
# Содержимое конфигурационного файла
14 years ago
self.textConfig = ""
# Имя файла шаблона
self.nameFileTemplate = ""
14 years ago
# Содержимое шаблона
14 years ago
self.textTemplate = ""
# Дескриптор файла шаблона
9 years ago
self.F_TEMPL = None
14 years ago
# Дескриптор файла конфигурационного файла
9 years ago
self.F_CONF = None
# тип запускаемого шаблона
self.executeType = None
# список скриптов на запуск
self.queueExecute = []
14 years ago
def saveConfFile(self):
"""Записать конфигурацию"""
if not self.textConfig:
self.textConfig = self.textTemplate
14 years ago
if self.F_CONF:
try:
9 years ago
self.F_CONF.truncate(0)
self.F_CONF.seek(0)
14 years ago
self.F_CONF.write(self.textConfig)
9 years ago
except IOError:
12 years ago
self.setError(_("unable to open the file:")
9 years ago
+ self.nameFileConfig)
return False
14 years ago
self.F_CONF.flush()
return True
elif self.executeType == "exec":
processor = self.textConfig.partition("\n")[0]
if processor.startswith("#!"):
9 years ago
self.queueExecute.append((processor[2:], self.textConfig,
self.nameFileTemplate))
else:
12 years ago
self.setError(_("unable to execute '%s'")
9 years ago
+ self.textConfig)
return False
14 years ago
def openTemplFile(self, nameFileTemplate):
"""Открыть файл шаблона"""
try:
14 years ago
F_TEMPL = open(nameFileTemplate, "r")
9 years ago
except IOError:
12 years ago
self.setError(_("unable to open the file:")
9 years ago
+ nameFileTemplate)
return False
14 years ago
return F_TEMPL
14 years ago
def closeTemplFile(self):
if self.F_TEMPL:
self.F_TEMPL.close()
9 years ago
self.F_TEMPL = None
def __closeOldFile(self):
14 years ago
if self.F_CONF:
self.F_CONF.close()
9 years ago
self.F_CONF = None
14 years ago
def __openConfFile(self, nameFileConfig):
14 years ago
"""Отктрыть конфигурационный файл"""
try:
14 years ago
if os.path.islink(nameFileConfig):
# если ссылка то удаляем её
14 years ago
os.unlink(nameFileConfig)
9 years ago
F_CONF = open(nameFileConfig, "r+")
except (IOError, OSError):
try:
if os.path.isdir(nameFileConfig):
11 years ago
self.printWARNING(_("unable to open the directory as file:")
9 years ago
+ nameFileConfig)
return False
14 years ago
F_CONF = open(nameFileConfig, "w+")
9 years ago
except (IOError, OSError):
12 years ago
self.setError(_("unable to open the file:")
9 years ago
+ nameFileConfig)
return False
14 years ago
return F_CONF
def openFiles(self, nameFileTemplate, nameFileConfig, typeFormat=None,
9 years ago
newBuffer=None):
"""Открывает шаблон и конфигурационный файл"""
14 years ago
self.textConfig = ""
self.textTemplate = ""
self.closeFiles()
9 years ago
self.F_TEMPL = None
self.F_CONF = None
14 years ago
self.nameFileConfig = os.path.abspath(nameFileConfig)
self.nameFileTemplate = os.path.abspath(nameFileTemplate)
self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
if not self.executeType and typeFormat not in ("diff", "dconf"):
self.F_CONF = self.__openConfFile(self.nameFileConfig)
14 years ago
if self.F_TEMPL and self.F_CONF:
self.textTemplate = self.F_TEMPL.read()
if self.configMode == T_NEWCFG:
9 years ago
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):
"""Закрытие файлов"""
14 years ago
self.closeTemplFile()
self.__closeOldFile()
9 years ago
class utfBin(object):
"""Класс для преобразования в utf-8
преобразование бинарного или смеси бинарного и utf-8 кода в utf-8 и
обратное преобразование
методы класса encode и decode
"""
9 years ago
def _retUTF(self, char):
byte = ord(char)
9 years ago
if byte <= 127:
return '_ch_', 1
elif byte <= 191:
return '_nb_', 1
elif byte <= 223:
return '_fb_', 2
elif byte <= 239:
return '_fb_', 3
elif byte <= 247:
return '_fb_', 4
else:
9 years ago
return '_er_', 1
def _sumbUtf(self, symbols, lenTail):
if not symbols:
9 years ago
return False, 0
lenSymb = len(symbols)
if lenSymb >= 4:
l = 4
elif lenSymb >= 3:
l = 3
elif lenSymb >= 2:
l = 2
else:
if symbols[0] == '_ch_':
9 years ago
return True, 1
else:
9 years ago
return False, 1
result = False
9 years ago
i_ = 0
for i in range(l):
9 years ago
i_ = i
if i == 0 and symbols[i] != '_fb_':
break
elif i > 0 and symbols[i] != '_nb_':
9 years ago
break
if lenTail > 1 and lenTail != i_:
return False, 1
if i_ > 0:
result = True
9 years ago
return result, i_
def _intToChar(self, x):
he = hex(x)[2:]
9 years ago
ret = None
exec ("ret = '\\x%s'" % he)
return ret
def _hexToChar(self, he):
9 years ago
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)
9 years ago
i += 1
while 1:
if utf[ind] == '_fb_':
9 years ago
res, l = self._sumbUtf(utf[ind:], lenUtf[ind])
if res is False:
indErr.append(ind)
9 years ago
if l > 0:
ind += l
if ind >= len(utf):
break
else:
if utf[ind] != '_ch_':
indErr.append(ind)
9 years ago
ind += 1
if ind >= len(utf):
break
if indErr:
lenIndErr = len(indErr)
block = []
blocks = []
if lenIndErr > 1:
i = 1
while 1:
if i == 1:
9 years ago
block.append(indErr[i - 1])
if indErr[i] - indErr[i - 1] == 1:
block.append(indErr[i])
else:
if block:
blocks.append(block)
9 years ago
block = [indErr[i]]
i += 1
if i >= lenIndErr:
break
else:
block.append(indErr[0])
if block:
blocks.append(block)
listErr = []
for block in blocks:
string = ""
9 years ago
last_elem = None
for elem in block:
string += hex(ord(text[elem]))[-2:]
9 years ago
last_elem = elem
if last_elem is not None:
listErr.append((block[0], "__hex__?%s?__hex__" % string,
last_elem))
textOut = text
deltaInd = 0
for erEl in listErr:
startInd = erEl[0] + deltaInd
endInd = erEl[2] + 1 + deltaInd
textOut = textOut[:startInd] + erEl[1] + textOut[endInd:]
9 years ago
deltaInd += len(erEl[1]) - (erEl[2] - erEl[0] + 1)
# if i == 1:
# break
# i += 1
return textOut
def decode(self, text):
"""Декодирует UTF-8 в смешанный формат"""
varStart = "__hex__\?"
varEnd = "\?__hex__"
# -1 Это экранирование '?' которое тоже считается
9 years ago
deltVarStart = len(varStart) - 1
deltVarEnd = len(varEnd) - 1
reVar = re.compile("%s[a-f0-9]+%s" % (varStart, varEnd), re.M)
resS = reVar.search(text)
textTemplateTmp = text
while resS:
mark = textTemplateTmp[resS.start():resS.end()]
hexString = mark[deltVarStart:-deltVarEnd]
i = 0
stringInsert = ""
hexCode = ""
for ch in hexString:
9 years ago
if i >= 1:
hexCode += ch
stringInsert += self._hexToChar(hexCode)
hexCode = ""
i = 0
else:
hexCode += ch
i += 1
textTemplateTmp = textTemplateTmp.replace(mark, stringInsert)
resS = reVar.search(textTemplateTmp)
return textTemplateTmp
9 years ago
class templateFormat(object):
"""Методы получения классов и объектов форматов шаблонов"""
# Импортированные классы поддерживаемых форматов шаблонов
importFormats = {}
9 years ago
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:
9 years ago
classFormat = getattr(__import__("calculate.lib.format.%s" %
nameClassTemplate,
globals(), locals(),
[nameClassTemplate]),
nameClassTemplate)
except (ImportError, AttributeError):
9 years ago
# Создаем объект из self.newObjProt с помощью
# метаклассов
if nameClassTemplate in self.newObjProt:
# Прототип класса
nameProt = self.newObjProt[nameClassTemplate]
if nameProt in self.importFormats:
classProt = self.importFormats[nameProt]
else:
try:
classProt = getattr(
9 years ago
__import__("calculate.lib.format.%s" % nameProt,
globals(), locals(),
[nameProt]),
nameProt)
except (ImportError, AttributeError):
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)
9 years ago
if callable(classFormat):
return classFormat(textTemplate)
else:
return False
9 years ago
class _shareTemplate(object):
"""Общие аттрибуты для классов шаблонов"""
# Метка начала переменной
varStart = "#-"
# Метка конца переменной
varEnd = "-#"
_deltVarStart = len(varStart)
_deltVarEnd = len(varEnd)
9 years ago
objVar = None
def getDataUser(self, groupsInfo=False):
14 years ago
"""Получить информацию о пользователе"""
userName = self.objVar.Get("ur_login")
if not userName:
userName = "root"
import pwd
9 years ago
14 years ago
try:
pwdObj = pwd.getpwnam(userName)
uid = pwdObj.pw_uid
gid = pwdObj.pw_gid
homeDir = self.objVar.Get('ur_home_path')
except Exception:
9 years ago
raise TemplatesError(_("User %s not found") % str(userName))
if groupsInfo:
import grp
9 years ago
try:
groupName = grp.getgrgid(gid).gr_name
except Exception:
9 years ago
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
14 years ago
return uid, gid, homeDir
9 years ago
12 years ago
class templateFunction(_error, _warning, _shareTemplate, _shareTermsFunction):
"""Класс для функций шаблонов"""
# Словарь установленных программ {"имя программы":[версии]}
installProg = {}
# Cписок просканированных категорий установленных программ
installCategory = []
# Флаг сканирования всех установленных программ
flagAllPkgScan = False
# Список названий функций шаблона
namesTemplateFunction = []
# Словарь {название функции шаблона: функция шаблона, ...}
templateFunction = {}
# Регулярное выражение для сложения
sNum = re.compile("\-[^\-\+]+|[^\-\+]+")
# Регулярное выражение для умножениея и деления
9 years ago
sMD = re.compile("[^\-\+\*/]+")
# директория установленных программ
_basePkgDir = "/var/db/pkg"
basePkgDir = _basePkgDir
# кэш для проверки наличия пакета в портежах
cachePortdir = {}
# стек глобальных переменных
stackGlobalVars = []
# регулярное выражение для поиска версии
reFindVer = re.compile("(?<=-)(?:\d+)(?:(?:\.\d+)*)"
"(?:[a-z]?)(?:(?:_(?:pre|p|beta|alpha|rc)\d*)*)"
"(?:-r\d+)?$")
reEmptyLoad = re.compile("^\s*$|^\s*;|^\s*#")
# Имя обрабатываемого шаблона
nameTemplate = ""
# Текст функции шаблона
functText = ""
# regular for discard sort number and version
reData = re.compile(r"^(?:\d+-)?(.+?)(?:-(?:|always|\d+|\d(?:\d|\.|pre|_"
9 years ago
"|-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)
9 years ago
return "%s/%s" % (category, pkgName)
currentBelong = ""
11 years ago
alreadyInformed = []
def __init__(self, objVar):
# Если не определен словарь функций шаблона
# import services api
if not self.templateFunction:
# префикс функций шаблона
pref = "func"
# cписок [(название функции, функция), ...]
9 years ago
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
9 years ago
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):
14 years ago
from convertenv import convertEnv
9 years ago
self.convObj = convertEnv()
def recalculateBaseDir(self):
"""Recalculate basedir and homedir"""
# Директория другой системы
self._chrootDir = self.objVar.Get("cl_chroot_path")
# Изменение директории к базе пакетов
self.basePkgDir = pathJoin(self._chrootDir, self._basePkgDir)
self.basePkgDir = os.path.normpath(self.basePkgDir)
# Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
9 years ago
self._baseDir = pathJoin(self._chrootDir,
self.objVar.Get("cl_root_path"))
self._baseDir = os.path.normpath(self._baseDir)
9 years ago
self.uid, self.gid, self.homeDir, self.groups = \
self.getDataUser(groupsInfo=True)
# Домашняя директория, плюс базовая директория
self.homeDir = pathJoin(self._baseDir, self.homeDir)
# path to configuration file for ini() function
# if action is desktop configuration, then path in user directory
# else config file place in /etc/calculate
if self.objVar.Get('cl_action') == "desktop":
self.pathConfigIni = os.path.join(self.homeDir, ".calculate")
self.modeConfigIni = 0640
else:
9 years ago
self.pathConfigIni = pathJoin(self._chrootDir, '/etc/calculate')
self.modeConfigIni = 0644
9 years ago
self.fileConfigIni = os.path.join(self.pathConfigIni, "ini.env")
# TODO: debug block
9 years ago
# 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:
9 years ago
strNum = self.multAndDiv(strNum, localVars)
num = 0
try:
num = int(strNum)
9 years ago
except ValueError:
minus = False
if strNum[:1] == "-":
minus = True
strNum = strNum[1:]
if localVars.has_key(strNum):
try:
num = int(localVars[strNum])
9 years ago
except ValueError:
raise self.raiseErrTemplate(
_("error: variable %s is not integer") %
str(strNum))
elif self.objVar.exists(strNum):
try:
num = int(self.objVar.Get(strNum))
9 years ago
except ValueError:
raise self.raiseErrTemplate(
_("error: variable %s is not integer") %
str(strNum))
else:
9 years ago
raise self.raiseErrTemplate(
_("error: local variable %s not defined") %
str(strNum))
if minus:
num = -num
strNumers.append(num)
return sum(strNumers)
9 years ago
raise self.raiseErrTemplate(_("error: template term %s, incorrect data") \
% str(term))
def multAndDiv(self, term, localVars):
"""Метод для умножения и деления"""
termTmp = term
varsLocal = self.sMD.findall(term)
for var in varsLocal:
flagVarTxt = True
try:
int(var)
9 years ago
except ValueError:
flagVarTxt = False
if flagVarTxt:
continue
varReplace = str(self.equalTerm(var, localVars))
9 years ago
termTmp = termTmp.replace(var, varReplace)
ret = eval(termTmp)
return ret
9 years ago
def funcSum(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона, вычисляет функцию sum()"""
9 years ago
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 = ""
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
elif len(terms) == 3:
if terms[1].strip():
replaceInt = self.equalTerm(terms[1], localVars)
replace = str(replaceInt)
else:
replace = ""
9 years ago
localVars[nameLocVar] = self.equalTerm(terms[2], localVars)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
else:
9 years ago
raise self.raiseErrTemplate()
return textTemplateTmp
12 years ago
def funcExists(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона exists(),
проверяет существование файла, если существует выдает '1'
если второй параметр root, то проверка осуществляется от корня.
"""
terms = map(lambda x: x.strip(), funArgv.split(","))
if len(terms) > 2:
9 years ago
raise self.raiseErrTemplate()
fileName = terms[0]
flagNotRootFS = True
if len(terms) == 2:
if terms[1] == "root":
flagNotRootFS = False
else:
9 years ago
raise self.raiseErrTemplate(
12 years ago
_("The second argument of the function is not 'root'"))
if fileName[0] == "~":
# Получаем директорию пользователя
fileName = os.path.join(self.homeDir,
9 years ago
fileName.partition("/")[2], "")[:-1]
elif fileName[0] != "/":
9 years ago
raise self.raiseErrTemplate(_("wrong path '%s'") % fileName)
else:
if flagNotRootFS:
fileName = pathJoin(self._baseDir, fileName)
replace = ""
if os.path.exists(fileName):
replace = "1"
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcLoad(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона load(),
если файл существует читает из файла локальную переменную
если один параметр - выводит значение локальной переменной
"""
terms = funArgv.split(",")
if terms:
lenTerms = len(terms)
9 years ago
if not terms[0].strip() or \
(lenTerms == 2 and not terms[1].strip()) or \
(lenTerms == 3 and not terms[2].strip()) or \
lenTerms > 3:
raise self.raiseErrTemplate()
else:
9 years ago
raise self.raiseErrTemplate()
flagNotRootFS = True
if lenTerms == 3:
9 years ago
if terms[2] == "root":
flagNotRootFS = False
else:
9 years ago
raise self.raiseErrTemplate(
12 years ago
_("The third argument of the function is not 'root'"))
if lenTerms >= 2:
9 years ago
if not terms[0] in ["ver", "num", "char", "key", "empty"]:
raise self.raiseErrTemplate(
12 years ago
_("the first argument of the function is neither 'ver'"
12 years ago
" or 'num' or 'char' or 'empty'"))
if lenTerms == 1:
fileName = terms[0].strip()
else:
fileName = terms[1].strip()
# Если домашняя директория
if fileName[0] == "~":
# Получаем директорию пользователя
fileName = os.path.join(self.homeDir,
9 years ago
fileName.partition("/")[2], "")[:-1]
elif fileName[0] != "/":
9 years ago
raise self.raiseErrTemplate(_("wrong path '%s'") % fileName)
else:
if flagNotRootFS:
9 years ago
fileName = pathJoin(self._baseDir, fileName)
replace = ""
if os.path.exists(fileName):
replace = readFile(fileName).strip()
if replace and lenTerms >= 2 and terms[0] == "empty":
9 years ago
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"
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
9 years ago
def sharePkg(self, pkgs, force=False):
"""
Update packages from pkgs list
"""
9 years ago
for pkgname, category, ver, slot in pkgs:
fullname = "%s/%s" % (category, pkgname)
if not fullname in self.installProg or \
9 years ago
type(self.installProg[fullname]) != dict:
self.installProg[fullname] = self.installProg[pkgname] = {}
if force or not slot in self.installProg[fullname]:
self.installProg[fullname][slot] = ver
return self.installProg
9 years ago
def getInstallPkgGentoo(self, category=""):
pkgs = []
filterFunc = lambda x: "SLOT" == x
9 years ago
def getFilesDir(pkgs, dirname, names):
9 years ago
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().partition('/')[0]
9 years ago
pkgname, spl, rev = pkgname.rpartition("-")
if rev.startswith('r'):
pkgname, spl, ver = pkgname.rpartition("-")
9 years ago
ver = "%s-%s" % (ver, rev)
else:
ver = rev
9 years ago
pkgs.append((pkgname, category, ver, slot))
return True
9 years ago
os.path.walk(os.path.join(self.basePkgDir, category),
getFilesDir, pkgs)
return self.sharePkg(pkgs)
9 years ago
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:
9 years ago
return versions.get(slot, "")
if len(versions) == 1:
return versions.values()[0]
else:
9 years ago
return versions[max(versions.keys(), key=getTupleVersion)]
else:
return ""
12 years ago
def funcPkg(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона pkg(), выдает номер версии программы"""
# Название программы
9 years ago
nameProg = funArgv.replace(" ", "")
if not nameProg:
nameProg = self.get_pkgname_by_filename(self.nameTemplate)
# Замена функции в тексте шаблона
if "/" in nameProg:
category, spl, nameProg = nameProg.partition("/")
nameProg, spl, uses = nameProg.partition('[')
nameProg, spl, slot = nameProg.partition(":")
if uses:
uses = uses.rstrip("]")
if not category in self.installCategory:
self.getInstallPkgGentoo(category=category)
12 years ago
self.installCategory.append(category)
replace = self.pkg(nameProg, slot=slot or None)
if replace and uses:
9 years ago
pkg_use, pkg_iuse = getPkgUses("%s/%s" % (category, nameProg),
replace, prefix=self.objVar.Get(
'cl_chroot_path'))
for use in filter(None, uses.split(',')):
if (use[0] == "-" and use[1:] in pkg_use or
9 years ago
use[0] != "-" and use not in pkg_use):
replace = ""
break
else:
if not self.flagAllPkgScan:
self.getInstallPkgGentoo()
templateFunction.flagAllPkgScan = True
9 years ago
nameProg, spl, slot = nameProg.partition(":")
replace = self.pkg(nameProg,
slot=slot)
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcKernel(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Функция kernel(...), выдает значение опции конфига ядра (y,m,)
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
if not terms[0].strip() or len(terms) != 1:
raise self.raiseErrTemplate()
kernel_opt = terms[0].upper()
if kernel_opt.startswith("CONFIG_"):
9 years ago
raise self.raiseErrTemplate(
_("the option name should not starts with CONFIG_"))
kernel_config = self.objVar.Get('install.os_install_kernel_config')
9 years ago
find_str = "CONFIG_%s" % kernel_opt
replace = ""
for line in kernel_config:
if find_str in line:
9 years ago
if "%s=" % find_str in line:
key, op, value = line.partition("=")
replace = value.strip("'\"")
break
9 years ago
elif "%s is not set" % find_str in line:
break
textTemplateTmp = (textTemplateTmp[:resS.start()] + replace +
9 years ago
textTemplateTmp[resS.end():])
return textTemplateTmp
def funcGrep(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Функция grep (...), выдает значение из файла по регулярному выражению
"""
9 years ago
fname, op, regpattern = funArgv.replace(" ", "").partition(",")
regpattern = regpattern.replace("(?\<", "(?<")
regpattern = self._replace_hex(regpattern)
if not fname or not regpattern:
9 years ago
raise self.raiseErrTemplate()
try:
reg = re.compile(regpattern)
9 years ago
except re.error:
raise self.raiseErrTemplate(_("Wrong regular expression"))
if fname[0] == "~":
# Получаем директорию пользователя
fname = os.path.join(self.homeDir,
9 years ago
fname.partition("/")[2], "")[:-1]
fname = pathJoin(self.objVar.Get('cl_chroot_path'), fname)
fileContent = readFile(fname)
match_data = reg.search(fileContent)
if match_data:
md_groups = match_data.groups()
if md_groups:
replace = md_groups[0] or ""
else:
replace = match_data.group()
else:
replace = ""
9 years ago
return (
textTemplateTmp[:resS.start()] + replace + textTemplateTmp[
resS.end():])
12 years ago
def funcRnd(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона rnd(), выдает строку случайных символов
первый аргумент:
'num' - числа,
'pas' - цифры и буквы
'uuid' - цифры и строчные буквы a-f
второй аргумент:
количество символов
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
if not terms[0].strip() or \
(len(terms) == 2 and not terms[1].strip()) or \
len(terms) != 2:
raise self.raiseErrTemplate()
fArgvNames = {'num': string.digits,
'pas': string.ascii_letters + string.digits,
'uuid': string.ascii_lowercase[:6] + string.digits}
if not terms[0] in fArgvNames:
9 years ago
raise self.raiseErrTemplate(
_("the first argument of the function must "
12 years ago
"be 'num', 'pas' or 'uuid'"))
try:
lenStr = int(terms[1])
9 years ago
except (ValueError, IndexError, TypeError):
lenStr = 0
raise self.raiseErrTemplate(
12 years ago
_("the second argument of the function is not a number"))
choiceStr = fArgvNames[terms[0]]
replace = ''.join([random.choice(choiceStr) for i in xrange(lenStr)])
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcCase(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона case(), выдает переменную в определенном регистре
первый аргумент:
'upper' - верхний регистр,
'lower' - нижний регистр,
'capitalize' - первая буква в верхнем регистре
второй аргумент:
название переменной
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
if not terms[0].strip() or \
(len(terms) == 2 and not terms[1].strip()) or len(terms) != 2:
raise self.raiseErrTemplate()
fArgvNames = ['upper', 'lower', 'capitalize']
if not terms[0] in fArgvNames:
9 years ago
raise self.raiseErrTemplate(_("the first argument of the function"
" is neither 'upper' or 'lower' or"
" 'capitalize'"))
try:
12 years ago
strValue = self.objVar.Get(terms[1])
if not strValue:
strValue = ""
else:
strValue = str(strValue)
except Exception:
raise TemplatesError(
9 years ago
_("error in template %s") % self.nameTemplate + "\n" +
_("error: variable %s not found") % str(terms[1]))
replace = ""
9 years ago
strValue = _u(strValue)
if terms[0] == 'upper':
replace = strValue.upper()
elif terms[0] == 'lower':
replace = strValue.lower()
elif terms[0] == 'capitalize':
replace = strValue.capitalize()
if replace:
replace = replace.encode("UTF-8")
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcIn(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Function in for check value in variable
"""
terms = funArgv.replace(" ", "").split(",")
12 years ago
# Название локальной переменной
nameLocVar = terms[0]
try:
value = self.objVar.Get(nameLocVar)
if type(value) in (list, tuple):
terms = terms[1:]
if any(x in terms for x in value):
replace = "1"
else:
replace = ""
12 years ago
else:
if value in terms[1:]:
replace = "1"
else:
replace = ""
9 years ago
except Exception:
raise self.raiseErrTemplate(_("error: variable %s does not exist") \
% str(nameLocVar))
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
12 years ago
return textTemplateTmp
12 years ago
def funcPush(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""локальная функция записывает значение переменной
в стек глобальных переменных
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
# Название локальной переменной
nameLocVar = terms[0]
9 years ago
value = ""
if nameLocVar in localVars.keys():
9 years ago
flagFoundVar = True
value = localVars[nameLocVar]
else:
try:
9 years ago
value = self.objVar.Get(nameLocVar)
flagFoundVar = True
9 years ago
except Exception:
flagFoundVar = False
if flagFoundVar:
# Если переменная существует
if len(terms) == 1:
self.stackGlobalVars.append(str(value))
else:
9 years ago
raise self.raiseErrTemplate(_("error: variable %s exists") \
% str(nameLocVar))
else:
# Если переменная не существует
if len(terms) == 1:
9 years ago
raise self.raiseErrTemplate(
_("error: variable %s does not exist") \
% str(nameLocVar))
elif len(terms) == 2:
value = terms[1].strip()
self.stackGlobalVars.append(str(value))
localVars[nameLocVar] = value
else:
9 years ago
raise self.raiseErrTemplate()
replace = ""
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcPop(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""локальная функция получает значение
из стека глобальных переменных и присваивает локальной переменной
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
# Название локальной переменной
nameLocVar = terms[0]
if len(terms) == 1:
if self.stackGlobalVars:
localVars[nameLocVar] = self.stackGlobalVars.pop()
else:
9 years ago
raise self.raiseErrTemplate(
12 years ago
_("error: global variables stack empty"))
else:
9 years ago
raise self.raiseErrTemplate()
replace = ""
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
9 years ago
def funcPrint(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
11 years ago
"""
Вывод успешного сообщения
"""
self.printSUCCESS(_(funArgv))
textTemplateTmp = textTemplateTmp[:resS.start()] + \
9 years ago
textTemplateTmp[resS.end():]
11 years ago
return textTemplateTmp
9 years ago
def funcWarning(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
11 years ago
"""
Вывод сообщения с предупреждением
"""
self.printWARNING(_(funArgv))
textTemplateTmp = textTemplateTmp[:resS.start()] + \
9 years ago
textTemplateTmp[resS.end():]
11 years ago
return textTemplateTmp
9 years ago
def funcError(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
11 years ago
"""
Вывод сообщения с ошибкой
"""
self.printERROR(_(funArgv))
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + \
textTemplateTmp[resS.end():]
return textTemplateTmp
11 years ago
def getElogTimestamp(self):
# Получаем время модификации конфигурационного файла
curTime = self.getTimeFile(self.fileConfigIni)
nameLocVar = "update.timestamp"
if self.timeIni != curTime:
# читаем переменные из файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
9 years ago
self.currDictIni = {}
11 years ago
self.currDictIni.update(self.prevDictIni)
self.timeIni = self.getTimeFile(self.fileConfigIni)
if nameLocVar in self.currDictIni.keys():
if self.currDictIni[nameLocVar] is None:
return 0
else:
val = self.currDictIni[nameLocVar].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 "0"
9 years ago
def funcElog(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
11 years ago
"""Function for work with emerge.log"""
funArgv = funArgv.strip()
9 years ago
rePkg = re.compile(r'\) Merging (?:Binary )?\((\S+)::', re.S)
11 years ago
replace = ""
if funArgv:
lastTimestamp = self.getElogTimestamp()
for line in reversed(list(readLinesFile(self.elogFile))):
9 years ago
timestamp, op, info = line.partition(':')
11 years ago
if timestamp.isdigit() and lastTimestamp and \
9 years ago
int(timestamp) < lastTimestamp:
break
11 years ago
match = rePkg.search(info)
if match and match.group(1).startswith(funArgv):
pkgInfo = reVerSplitToPV(match.group(1))
if "{CATEGORY}/{PN}".format(**pkgInfo) == funArgv:
replace = pkgInfo['PVR']
break
else:
replace = self.getLastElog()
11 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
9 years ago
textTemplateTmp[resS.end():]
return textTemplateTmp
@classmethod
def splash_cmd(cls, splash_type):
cmd_map = {
'splashutils': "splash=silent,theme:calculate console=tty1",
'plymouth': "splash",
}
return cmd_map.get(splash_type, "verbose")
9 years ago
def funcLivemenu(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
def generateSubmenu(data):
base_dn = self.objVar.Get('builder.cl_builder_flash_path')
9 years ago
for id, label, iso, vmlinuz_orig, vmlinuz, initrd_orig, initrd, \
xorg, drivers, splash in data:
splash = self.splash_cmd(splash)
yield ("{id};\n{label};\n/boot/{kernel};\n"
"root=live iso-scan/filename={iso};\n"
"/boot/{initrd};\n"
"init=/linuxrc rd.live.squashimg=livecd.squashfs "
"{splash} "
"nodevfs quiet noresume;\n".format(
id=id, label=label, kernel=vmlinuz, initrd=initrd,
splash=splash, iso=iso[len(base_dn):]
))
def generateXorg(data):
for id, label, iso, vmlinuz_orig, vmlinuz, initrd_orig, initrd, \
xorg, drivers, splash in data:
if xorg == "on":
yield id
def generateVideo(data):
for id, label, iso, vmlinuz_orig, vmlinuz, initrd_orig, initrd, \
xorg, drivers, splash in data:
if drivers == "on":
yield id
data = 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():]
11 years ago
return textTemplateTmp
def loadVarsIni(self, iniFileName):
""" Читает файл fileName
создает и заполняет переменные на основе этого файла
Используеться совместно c funcIni
"""
localVarsIni = {}
# получить объект ini файла
config = ConfigParser(strict=False)
config.read(iniFileName, encoding="utf-8")
# получаем все секции из конфигурационного файла
allsect = config.sections()
if not allsect:
return localVarsIni
# Заполняем переменные для funcIni
for sect in allsect:
for name, valueVar in config.items(sect, raw=True):
9 years ago
nameVar = "%s.%s" % (sect, name)
localVarsIni[nameVar] = valueVar
return localVarsIni
def getTimeFile(self, fileName):
# Получаем время модификации файла
14 years ago
nameEnvFile = os.path.split(fileName)[1]
if nameEnvFile in self.timeConfigsIni:
return self.timeConfigsIni[nameEnvFile]
return 0
def funcWallpaper(self, funArgv, resS, localVars, textTemplateTmp,
nameTemp):
"""
Получить наиболее близкое к заданному разрешение из списка обоев
"""
terms = funArgv.replace(" ", "").split(",")
if len(terms) != 2:
9 years ago
raise self.raiseErrTemplate(_("funtion takes only two parameters"))
resol, wpath = terms
if not resol:
resol = "1024x768"
re_resol = re.compile("^(\d+)x(\d+)(-\d+(@\d+)?)?$")
resol = re_resol.match(resol)
if not resol:
9 years ago
raise self.raiseErrTemplate(
_("the first parameter must be the resolution"))
re_resol = re.compile(".*?(\d+)x(\d+).*")
wpath = pathJoin(self._baseDir, wpath)
9 years ago
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))
9 years ago
gep = sqrt(height ** 2 + width ** 2)
k = float(width) / float(height)
if res:
# наиболее подходящее разрешение:
# минимальная разность между пропорциями (отношение ширины к высоте)
# минимальная разность между размерами (гепотенуза)
near_res = min(res,
9 years ago
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 + \
9 years ago
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcIni(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""локальная функция записывает и считывает значение переменной
из ini файла ~./calculate/ini.env
"""
# Создаем директорию
if not os.path.exists(self.pathConfigIni):
os.makedirs(self.pathConfigIni)
14 years ago
os.chown(self.pathConfigIni, self.uid, self.gid)
termsRaw = funArgv.split(",")
flagFirst = True
terms = []
for term in termsRaw:
if flagFirst:
9 years ago
terms.append(term.replace(" ", ""))
flagFirst = False
else:
val = term.strip()
# Флаг (не найдены кавычки)
flagNotFoundQuote = True
9 years ago
for el in ('"', "'"):
if val.startswith(el) and val.endswith(el):
terms.append(val[1:-1])
flagNotFoundQuote = False
break
if flagNotFoundQuote:
if not val:
terms.append(None)
else:
terms.append(val)
# Название локальной переменной
nameLocVar = terms[0]
namesVar = nameLocVar.split(".")
if len(namesVar) == 1:
9 years ago
nameLocVar = "main.%s" % nameLocVar
elif len(namesVar) > 2:
raise self.raiseErrTemplate()
replace = ""
# Получаем время модификации конфигурационного файла
curTime = self.getTimeFile(self.fileConfigIni)
if len(terms) == 1:
if self.timeIni != curTime:
# читаем переменные из файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
9 years ago
self.currDictIni = {}
self.currDictIni.update(self.prevDictIni)
self.timeIni = self.getTimeFile(self.fileConfigIni)
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)
9 years ago
self.currDictIni = {}
self.currDictIni.update(self.prevDictIni)
self.timeIni = self.getTimeFile(self.fileConfigIni)
# Значение локальной переменной
valueLocVar = terms[1]
self.currDictIni[nameLocVar] = valueLocVar
elif len(terms) == 3:
9 years ago
if not terms[2] in ['url', 'purl', 'unicode']:
raise self.raiseErrTemplate(
12 years ago
_("the third argument of the function is neither "
12 years ago
"'url' or 'purl' or 'unicode'"))
if terms[1]:
9 years ago
raise self.raiseErrTemplate()
if self.timeIni != curTime:
# читаем переменные из файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
9 years ago
self.currDictIni = {}
self.currDictIni.update(self.prevDictIni)
self.timeIni = self.getTimeFile(self.fileConfigIni)
if nameLocVar in self.currDictIni.keys():
unicodeValue = self.currDictIni[nameLocVar]
if unicodeValue is None:
unicodeValue = ""
if terms[2] in ('url', 'purl'):
9 years ago
replace = unicodeValue.encode("UTF-8"). \
__repr__()[1:-1].replace('\\x', '%'). \
replace(' ', '%20')
if terms[2] == 'purl':
9 years ago
replace = replace.replace('/', '%2f')
elif terms[2] == 'unicode':
replace = unicodeValue.__repr__()[2:-1]
else:
9 years ago
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})',
9 years ago
lambda x: chr(int(x.group(1), 16)), text)
12 years ago
def funcReplace(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""локальная функция заменяет в значении переменной old на new
replace(old, new, name_var_template)
одинарные и двойные кавычки должны быть обязательно использованы
в первых двух аргументах old и new
"test\ntest" - преобразование строки (строка с переводом)
'test\ntest' - без преобразования (одна строка)
"""
9 years ago
def getStrArgv(terms):
"""Определяет в двойных или одинарных кавычках параметры
Результат [(тип, аргумент),...] [("double", arg1).]
"""
listArgv = []
for term in terms:
if term.startswith('"') and term.endswith('"'):
replTerms = [(r"\'", "'"), (r'\"', '"'), (r'\n', '\n'),
(r'\r', '\r'),
(r'\t', '\t'), (r"\\", "\\")]
textArgv = term[1:-1]
for replTerm in replTerms:
textArgv = textArgv.replace(*replTerm)
textArgv = self._replace_hex(textArgv)
listArgv.append(textArgv)
elif term.startswith("'") and term.endswith("'"):
listArgv.append(term[1:-1])
else:
9 years ago
raise self.raiseErrTemplate()
return listArgv
terms = map(lambda x: x.strip(), funArgv.split(","))
if len(terms) != 3:
9 years ago
raise self.raiseErrTemplate()
listArgv = getStrArgv(terms[:2])
old = listArgv[0]
new = listArgv[1]
nameVar = terms[2]
# Получаем значение переменной
if nameVar in localVars:
value = str(localVars[nameVar])
else:
try:
value = str(self.objVar.Get(nameVar))
9 years ago
except Exception:
raise self.raiseErrTemplate(
_("template variable '%s' not found") \
% str(nameVar))
replace = value.replace(old, new)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcEnv(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона env(), выдает значение переменной из env файлов
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
if len(terms) != 1:
9 years ago
raise self.raiseErrTemplate()
nameVar = terms[0]
if nameVar in self.valuesVarEnv:
replace = self.valuesVarEnv[nameVar]
else:
# Получаем значение из env файлов
value = self.objVar.getIniVar(nameVar)
if value is False:
9 years ago
raise self.raiseErrTemplate(self.getError())
self.valuesVarEnv[nameVar] = value
replace = value
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcServer(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона info(), выдает значение опций сервиса
из /var/calculate/remote/calculate.env
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
if len(terms) == 0 or len(terms) > 2:
raise self.raiseErrTemplate()
nameLocalVar = ""
9 years ago
if len(terms) == 2:
if not terms[1]:
9 years ago
raise self.raiseErrTemplate()
nameLocalVar = terms[1]
14 years ago
textLine = terms[0]
vals = textLine.split(".")
9 years ago
if len(vals) != 2:
raise self.raiseErrTemplate()
14 years ago
if filter(lambda x: not x.strip(), vals):
9 years ago
raise self.raiseErrTemplate()
14 years ago
service, option = vals
if not service or not option:
9 years ago
raise self.raiseErrTemplate()
if not self.optionsInfo:
# файл /var/calculate/remote/server.env
envFile = self.objVar.Get("cl_env_server_path")
# получаем словарь всех информационных переменных
if self.convObj:
optInfo = self.convObj.convert()
else:
12 years ago
optInfo = self.objVar.getRemoteInfo(envFile)
if optInfo is False:
9 years ago
raise self.raiseErrTemplate()
if optInfo:
self.optionsInfo = optInfo
replace = ''
if service in self.optionsInfo and option in self.optionsInfo[service]:
value = self.optionsInfo[service][option]
if nameLocalVar:
localVars[nameLocalVar] = value
else:
replace = value
14 years ago
elif nameLocalVar:
localVars[nameLocalVar] = ""
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcGroups(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона groups(),
проверяет нахождение пользователя в группах, если находится выдает '1'
"""
terms = map(lambda x: x.strip(), funArgv.split(","))
groupNames = set(terms)
userGroups = set(self.groups)
replace = ""
if groupNames & userGroups:
replace = "1"
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcBelong(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
11 years ago
self.printWARNING(_("Function '{funcname}' used by {template} "
"is deprecated and will be removed in the future"
9 years ago
).format(funcname="belong", template=nameTemp))
replace = ""
9 years ago
return textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
12 years ago
def funcMerge(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Belong function use value in first arg and compare it
12 years ago
for all values in cl_merge_pkg.
If cl_merge_pkg empty or first arg <=cl_belogn_pkg
then "1" else ""
"""
9 years ago
def uniq_warning(message):
hashMessage = hashlib.md5(message).digest()
if not hashMessage in self.alreadyInformed:
self.printWARNING(message)
self.alreadyInformed.append(hashMessage)
def check_skip(pkgName):
9 years ago
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(
9 years ago
data=",".join(data),
var_name=skip_data_varname))
else:
pkg, location = data
if fnmatch(pkgName, pkg) and (location == "*"
9 years ago
or location == pass_location):
return True
return False
9 years ago
terms = funArgv.replace(" ", "").split(",")
if len(terms) != 1:
9 years ago
raise self.raiseErrTemplate()
funcPkg = terms[0]
if not funcPkg:
funcPkg = self.get_pkgname_by_filename(self.nameTemplate)
self.currentBelong = funcPkg
11 years ago
if self.objVar.Get('cl_action') == 'patch':
9 years ago
if funcPkg == "%s/%s" % (
self.objVar.Get('core.cl_core_pkg_category'),
self.objVar.Get('core.cl_core_pkg_name')):
11 years ago
replace = self.objVar.Get('core.cl_core_pkg_version')
if check_skip(funcPkg):
replace = ""
11 years ago
else:
replace = ""
else:
11 years ago
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 = ""
9 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcList(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона list().
Если первый аргумент является именем локальной или глобальной
переменной и значение переменной является списком, выдает
элемент списка по второму аргументу индексу.
Первый элемент имеет индекс 0
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
# У функции должно быть два аргумента
if len(terms) != 2:
9 years ago
raise self.raiseErrTemplate()
# Название локальной или глобальной переменной
nameLocVar = terms[0]
strIndex = terms[1]
try:
try:
9 years ago
intIndex = int(strIndex)
except ValueError:
raise TemplatesError(_("'%s' is not a number") % strIndex)
if nameLocVar in localVars.keys():
value = localVars[nameLocVar]
else:
try:
value = self.objVar.Get(nameLocVar)
except Exception:
raise TemplatesError(_("error: variable %s does not exist")
% str(nameLocVar))
if not type(value) in (list, tuple):
# Значение переменной не список или кортеж
raise TemplatesError(_("value of %s is not a list or a tuple")
% str(nameLocVar))
if len(value) > intIndex:
replace = str(value[intIndex])
else:
replace = ""
9 years ago
return textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
except TemplatesError as e:
raise self.raiseErrTemplate(str(e))
12 years ago
def funcDisk(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона disk().
Первый аргумент ищется в значении переменной os_disk_install
(значение os_install_disk_mount -
список точек монтирования при установке)
второй аргумент используется для поиска в переменной
os_disk_второй_аргумент (значение os_disk_второй_аргумент - список)
В os_install_disk_mount ищется первый аргумент, находим его индекс
результат - элемент cписка из os_disk_второй_аргумент с этим индексом
"""
9 years ago
terms = funArgv.replace(" ", "").split(",")
# У функции должно быть два аргумента
if len(terms) != 2:
9 years ago
raise self.raiseErrTemplate()
# Название глобальной переменной
mountPoint = terms[0]
lastElementVar = terms[1]
9 years ago
if not mountPoint or mountPoint[:1] != "/":
raise self.raiseErrTemplate(_("wrong %s") % lastElementVar)
12 years ago
nameVar = "install.os_install_disk_mount"
try:
try:
9 years ago
valueVar = self.objVar.Get(nameVar)
except Exception:
raise TemplatesError(
_("error: variable %s does not exist") % nameVar)
nameElementVar = "install.os_install_disk_%s" % lastElementVar
try:
valueElementVar = self.objVar.Get(nameElementVar)
except Exception:
# Если переменная не существует
nameElementVar = "install.os_disk_%s" % lastElementVar
try:
valueElementVar = self.objVar.Get(nameElementVar)
except Exception:
raise TemplatesError(_("wrong %s") % lastElementVar + "\n" +
_("error: variable %s does not exist")
% nameElementVar)
for k, v in ((nameVar, valueVar),
(nameElementVar, valueElementVar)):
if not type(v) in (list, tuple):
# Значение переменной не список или кортеж
raise TemplatesError(
_("value of %s is not a list or a tuple") % k)
if len(valueVar) != len(valueElementVar):
raise TemplatesError(
_("%(name)s does not match %(nameElement)s in size")
% {'name': nameVar, 'nameElement': nameElementVar})
index = None
for num, mPoint in enumerate(valueVar):
9 years ago
if mountPoint == mPoint:
index = num
break
9 years ago
if index is None:
for num, mPoint in enumerate(valueVar):
if "/" == mPoint:
index = num
break
if index is None:
raise TemplatesError(
_("mount point '/' or '/%s' not found "
" in the value of variable os_disk_install") % mountPoint)
replace = valueElementVar[index]
return textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
except TemplatesError as e:
raise self.raiseErrTemplate(str(e))
12 years ago
def funcModule(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона module(), выдает значение аттрибута api.
аргумент:
путь_к_атрибуту - путь к аттрибуту
возможные пути:
имя_пакета.var.имя_переменной - получаем значение переменной
имя_пакета.имя_метода_api - выполнение метода, получение результата
all.имя_метода_api - выполнение метода для всех пакетов с api
"""
return textTemplateTmp
9 years ago
def raiseErrTemplate(self, message=""):
"""Возвращает ошибки при обработке функций шаблона"""
if message:
9 years ago
message = "%s\n" % message
else:
message = ""
9 years ago
return TemplatesError(
_("error in template %s") % self.nameTemplate + "\n" + \
_("error, template term '%s'") % str(self.functText) + \
" " + message)
def applyFuncTemplate(self, textTemplate, nameTemplate):
"""Применяет функции к тексту шаблона"""
# Локальные переменные
localVars = {}
# Имя обрабатываемого шаблона
self.nameTemplate = nameTemplate
# Регулярное выражение для поиска функции в шаблоне
reFunc = self._reFunc
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]
9 years ago
funcName, spl, funcEnd = self.functText.partition("(")
if funcName in self.namesTemplateFunction:
# аргументы функции - '(' аргументы ')'
funArgv = funcEnd.rpartition(")")[0]
# вызов функции шаблона
textTemplateTmp = self.templateFunction[funcName](self, funArgv,
9 years ago
resS,
localVars,
textTemplateTmp,
nameTemplate)
resS = reFunc.search(textTemplateTmp)
if funcName == "ini":
if "," in funArgv:
writeIniFunc = True
flagIniFunc = True
else:
9 years ago
raise self.raiseErrTemplate(
_("function of templates '%s' not found") \
% str(self.functText))
if flagIniFunc:
# Очистка файла в случае его ошибочного чтения
if not self.prevDictIni and os.path.exists(self.fileConfigIni):
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")
9 years ago
comment_block = "\n".join(takewhile(lambda x: x.startswith("#"),
readLinesFile(
self.fileConfigIni)))
for k, v in self.currDictIni.items():
if "." in k:
sect, op, k = k.rpartition('.')
if v is None:
if config.has_section(sect):
config.remove_option(sect, k)
else:
if not config.has_section(sect):
config.add_section(sect)
config[sect][k] = v
for section in filter(lambda x: not config[x],
config.sections()):
config.remove_section(section)
with codecs.open(self.fileConfigIni, 'wb',
'utf-8', 'ignore') as f:
if comment_block:
f.write(comment_block)
f.write('\n\n')
config.write(f)
try:
oMode = getModeFile(self.fileConfigIni, mode="mode")
if oMode != self.modeConfigIni:
os.chmod(self.fileConfigIni, self.modeConfigIni)
9 years ago
except OSError:
pass
# читаем переменные из файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
self.currDictIni.update(self.prevDictIni)
self.timeConfigsIni[self.fileConfigIni] = float(time.time())
self.timeIni = self.getTimeFile(self.fileConfigIni)
# Меняем владельца в случае необходимости
if writeIniFunc and os.path.exists(self.fileConfigIni):
14 years ago
uid, gid = getModeFile(self.fileConfigIni, "owner")
if self.uid not in (uid, PORTAGEUID) or \
self.gid not in (gid, PORTAGEGID):
try:
os.chown(self.fileConfigIni, self.uid, self.gid)
9 years ago
except OSError:
self.setError(_("error") + " " +
"'chown %d:%d %s'" % (self.uid, self.gid,
self.fileConfigIni))
return textTemplateTmp
9 years ago
class ChangedFiles:
"""
Object which contains modified files and package
"""
9 years ago
FILE_MODIFIED, FILE_REMOVED, DIR_CREATED, DIR_REMOVED, DIR_EXISTS = 0, 1, 2, 3, 4
def __init__(self):
self.data = {}
self.pkgs = set()
9 years ago
def _createEntry(self, fn):
if not fn in self.data:
self.data[fn] = []
9 years ago
def addObj(self, filename, action, pkg):
self._createEntry(filename)
9 years ago
self.data[filename].append((pkg, action))
self.pkgs.add(pkg)
def getPkgs(self):
return self.pkgs
9 years ago
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)
9 years ago
T_ORIGIN, T_CFG, T_NEWCFG = 0, 1, 2
9 years ago
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(),
9 years ago
os.environ["CONFIG_PROTECT"].split(
" "))
protectPaths = map(lambda x: os.path.normpath(x), protectPaths)
@classmethod
9 years ago
def removeComment(cls, text):
re_comment = re.compile('(?:<!--|[{symb}]-*)\n'
9 years ago
'[{symb}]? {modified} .*\n'
'[{symb}]? {processed}\n'
'([{symb}]? /.*\n'
')+(?:[{symb}]? {endtitle}.*\n)?'
9 years ago
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
9 years ago
def __init__(self, objVar, servDir=False, dirsFilter=(), filesFilter=(),
cltObj=True, cltFilter=True, printWarning=True,
9 years ago
printSUCCESS=lambda x: x, printWARNING=lambda x: x,
printERROR=lambda x: x, askConfirm=lambda x: x,
userProfile=False, dispatchConf=None):
# совместимость с вызовами из модулей предыдущих версий
self.translator = RegexpLocalization("cl_templates3")
if userProfile and objVar:
9 years ago
objVar.Set('cl_protect_use_set', 'off', force=True)
self.protectPaths = objVar.Get('cl_config_protect')
self.dispatchConf = dispatchConf
self.changedFiles = ChangedFiles()
self.printSUCCESS = printSUCCESS
self.printERROR = printERROR
self.postmergePkgs = []
self.postmergeFile = "/var/lib/calculate/-postmerge"
self.bHasError = False
11 years ago
if printERROR:
def newSetError(s):
self.printERROR(s)
self.bHasError = True
9 years ago
self.setError = newSetError
self.printWARNING = printWARNING
11 years ago
self.askConfirm = askConfirm
self.cltObj = None
self.functObj = None
self.mounts = None
# Предупреждения
9 years ago
# self.warning = []
# Печатать ли предупреждения о корневых шаблонах без cl_name==pkg
self.printWarning = printWarning
# Необрабатываемые директории
self.dirsFilter = dirsFilter
# Необрабатываемые файлы
self.filesFilter = filesFilter
_file.__init__(self)
# Словарь для создания объектов новых классов по образцу
9 years ago
self.newObjProt = {'proftpd': 'apache'}
# Заголовок title
self.__titleHead = "--------------------------------------\
----------------------------------------"
self._titleBody = ""
9 years ago
self._reVar = re.compile(
"%s(?:[a-z0-9_]+\.)?[a-zA-Z0-9_-]+%s" % (self.varStart,
self.varEnd), re.M)
# Условия
12 years ago
self._reTermBloc = re.compile(
9 years ago
"#\?(?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)
9 years ago
self._servDir = servDir
if self._servDir:
if self._servDir[0] != "/":
self._servDir = "/" + self._servDir
if self._servDir[-1] != "/":
self._servDir += "/"
self._servDir = os.path.split(self._servDir)[0]
# Созданные директории
self.createdDirs = []
# Примененные файлы
self.filesApply = []
# номер обрабатываемого файла
self.numberProcessTempl = 0
# имя текущей программы
_nameProgram = self.objVar.Get("cl_name").capitalize()
# версия текущей программы
_versionProgram = self.objVar.Get("cl_ver")
# имя и версия текущей программы
9 years ago
self.programVersion = "%s %s" % (_nameProgram, _versionProgram)
# Словарь директорий с количеством файлов шаблонов
self.dictTemplates = {}
# Общее количество шаблонов
self.allTemplates = 0
# Объект функций шаблона
self.functObj = templateFunction(self.objVar)
self.functObj.printSUCCESS = self.printSUCCESS
self.functObj.printWARNING = self.printWARNING
self.functObj.printERROR = self.printERROR
11 years ago
if self.printERROR:
self.functObj.setError = self.printERROR
11 years ago
self.functObj.askConfirm = self.askConfirm
# Метод применения функций к шаблонам
self.applyFuncTemplate = self.functObj.applyFuncTemplate
14 years ago
# Объект для определения типа файла шаблона
self.typeFileObj = typeFile()
# Глобальный словарь обработанных шаблонов файлов
# {путь к конф. файлу:[имена шаблонов] ...}
self.dictProcessedTemplates = {}
if cltObj is True:
# Объект templateClt
9 years ago
self.cltObj = templateClt(self.objVar, self.postmergePkgs,
printSUCCESS=self.printSUCCESS,
printERROR=self.printERROR,
printWARNING=self.printWARNING,
askConfirm=self.askConfirm)
elif cltObj:
# Объект templateClt
self.cltObj = cltObj
else:
# Объект templateClt
9 years ago
self.cltObj = None
14 years ago
# Фильтровать ли шаблоны clt по конфигурационным файлам обычных шаблонов
self.cltFilter = cltFilter
# autoupdate файлы
self.autoUpdateFiles = []
self.autoUpdateDirs = []
self.protectedFiles = self.objVar.Get('main.cl_env_path') + \
9 years ago
[self.functObj.fileConfigIni]
# список выполненных файлов
self.executedFiles = []
def recalculateBaseDir(self):
"""Recalculate basedir and homedir"""
# Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
self._baseDir = pathJoin(self.objVar.Get("cl_chroot_path"),
self.objVar.Get("cl_root_path"))
self._baseDir = os.path.normpath(self._baseDir)
self.uid, self.gid, self.homeDir = self.getDataUser()
# Домашняя директория, плюс базовая директория
self.homeDir = pathJoin(self._baseDir, self.homeDir)
if self.cltObj:
self.cltObj.recalculateBaseDir()
if self.functObj:
self.functObj.recalculateBaseDir()
9 years ago
def _addFile(self, filesApl, pkg=None):
"""
Add files to ChangedFiles
"""
for fn in filesApl:
if os.path.exists(fn):
9 years ago
self.changedFiles.addObj(fn, ChangedFiles.FILE_MODIFIED,
pkg or self.functObj.currentBelong)
else:
9 years ago
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():
9 years ago
self.executedFiles.append((code, execPath))
if p.readerr():
for line in p.readerr().split('\n'):
if line:
line = self.translator.translate(line)
11 years ago
self.printWARNING(line.strip())
return True
else:
if p.readerr():
for line in p.readerr().split('\n'):
if line:
line = self.translator.translate(line)
11 years ago
self.printERROR(line.strip())
return False
def __octToInt(self, strOct):
"""Преобразование восьмеричного в целое (ввод строка, вывод число)"""
if strOct:
try:
res = string.atoi(strOct, 8)
except ValueError:
12 years ago
self.setError(_("Invalid oct value: ") + str(strOct))
return False
return res
else:
14 years ago
self.setError(_("Empty oct value"))
return False
14 years ago
def getTemplateType(self):
"""выдать тип шаблона (text, bin)"""
14 years ago
return self.getFileType(self.nameFileTemplate)
def getFileType(self, fileName):
"""выдать тип файла (text, bin)"""
isBin = self.typeFileObj.isBinary(fileName)
14 years ago
if isBin is True:
typeTemplate = "bin"
elif isBin is False:
typeTemplate = "text"
else:
14 years ago
self.setError(_("ERROR") + ": getFileType()")
14 years ago
self.setError(isBin)
return False
return typeTemplate
def createDir(self, dirName, mode=False, uid=False, gid=False):
"""Создает директорию"""
if os.access(dirName, os.F_OK):
14 years ago
return True
else:
dMode = False
prevDir, tmpSubdir = os.path.split(dirName)
createDirs = []
while not os.access(prevDir, os.F_OK) and prevDir:
createDirs.append(prevDir)
prevDir = os.path.split(prevDir)[0]
try:
9 years ago
dUid, dGid = getModeFile(prevDir, "owner")
except OSError:
12 years ago
self.setError(_("No access to the directory: ") + prevDir)
return False
if not mode is False:
dMode = mode
if not uid is False:
dUid = uid
if not gid is False:
dGid = gid
createDirs.reverse()
for nameDir in createDirs:
try:
if dMode:
os.mkdir(nameDir, dMode)
os.chmod(nameDir, dMode)
else:
os.mkdir(nameDir)
self.chownConfDir(nameDir, dUid, dGid, None)
9 years ago
except OSError:
12 years ago
self.setError(_("Failed to create the directory: ")
9 years ago
+ nameDir)
return False
try:
if dMode:
os.mkdir(dirName, dMode)
os.chmod(dirName, dMode)
else:
os.mkdir(dirName)
self.chownConfDir(dirName, dUid, dGid, None)
createDirs.append(dirName)
9 years ago
except OSError:
12 years ago
self.setError(_("Failed to create the directory: ")
9 years ago
+ dirName)
return False
return createDirs
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:
9 years ago
varValue = self.objVar.serialize(t,
self.objVar.Get(varName))
else:
varValue = self.objVar.Get(varName)
12 years ago
if not varValue:
varValue = ""
else:
varValue = str(varValue)
except DataVarsError, e:
9 years ago
raise TemplatesError(_("error in template %s") % nameTemplate
+ "\n" + str(e))
textTemplateTmp = textTemplateTmp.replace(mark, varValue)
resS = self._reVar.search(textTemplateTmp)
return textTemplateTmp
9 years ago
def applyTermsTemplate(self, textTemplate, nameTemplate):
""" Применяет условия, к условным блокам текста
"""
9 years ago
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 = ""
9 years ago
term = resS.group("rTerm") + parent + \
resS.group("lTerm")
if self._equalTerm(term, _("invalid template content: ") + \
nameTemplate, function):
textTemplateTmp = textTemplateTmp.replace(mark, body + end)
else:
textTemplateTmp = textTemplateTmp.replace(mark, "")
resS = self._reTermBloc.search(textTemplateTmp)
return textTemplateTmp
def getNeedTemplate(self, fileTemplate):
"""Применяем правила к названию файла"""
9 years ago
dirP, fileP = os.path.split(fileTemplate)
if fileP:
spFile = fileP.split("?")
9 years ago
if len(spFile) > 1:
flagTrue = False
for term in spFile[1:]:
9 years ago
if self._equalTerm(term, _("invalid template name: ") + \
fileTemplate):
flagTrue = True
break
if flagTrue:
return True
else:
return False
else:
return True
else:
9 years ago
self.setError(_("invalid template name: ") + str(fileTemplate))
return False
def getTitle(self, comment, commentList, configPath=""):
"""Выдает заголовок шаблона ( версия и.т.д)"""
if configPath and self.protectPaths:
flagFoundPath = False
for protectPath in self.protectPaths:
14 years ago
if self._baseDir != "/":
lenBaseDir = len(self._baseDir)
9 years ago
if len(configPath) > lenBaseDir and \
configPath[:lenBaseDir] == self._baseDir:
14 years ago
configPath = configPath[lenBaseDir:]
if configPath.startswith(protectPath + "/"):
flagFoundPath = True
break
if flagFoundPath:
9 years ago
origConfigPath = PkgContents.reCfg.sub("/", configPath)
if self._baseDir != "/":
lenBaseDir = len(self._baseDir)
commentList = [x[lenBaseDir:]
if x.startswith(self._baseDir)
else x for x in commentList]
if not any(origConfigPath.endswith(x) for x in
("/calculate.env", "/ini.env", "/custom")):
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
9 years ago
for com in list(self._titleList) + [""] * (len(commentList)):
if com:
if flagFirst:
9 years ago
self._titleBody += commentInsert + " " + com + " " + \
self.programVersion + "\n"
flagFirst = False
else:
self._titleBody += commentInsert + " " + com + "\n"
else:
9 years ago
self._titleBody += commentInsert + " " + \
commentList[z] + "\n"
z += 1
if flagList:
9 years ago
self._titleBody += commentLast + "\n"
else:
self._titleBody += commentLast + self.__titleHead + "\n"
return self._titleBody
else:
return ""
9 years ago
def changeMergePackage(self, package):
return True
def numberAllTemplates(self, number):
"""Количество шаблонов
Вызов происходит перед наложением шаблонов
в момент вызова в number находится количество обрабатываемых файлов
Наследуемая функция
Используется для отображения прогресса при наложениии шаблонов
"""
return True
def numberProcessTemplates(self, number):
"""Номер текущего обрабатываемого шаблона
Вызов происходит при наложении шаблона
в момент вызова в number находится номер обрабатываемого шаблона
Наследуемая функция
Используется для отображения прогресса при наложениии шаблонов
"""
return True
11 years ago
def templateModify(self):
12 years ago
"""
Files which created by apping templates
"""
return True
9 years ago
def fixNameFileConfig(self, origfilename):
12 years ago
"""Support ._cfg0000 files for postinst"""
9 years ago
# if self.objVar.Get('cl_ebuild_phase') != 'postinst':
# return origfilename
9 years ago
directory, filename = os.path.split(origfilename)
for i in range(0, 9999):
12 years ago
if not os.path.exists(os.path.join(directory,
9 years ago
"._cfg%04d_%s" % (i, filename))):
12 years ago
if i:
filename = os.path.join(directory,
9 years ago
"._cfg%04d_%s" % (i - 1, filename))
if not os.path.exists(origfilename):
return origfilename
9 years ago
# origstat = os.stat(origfilename)[stat.ST_CTIME]
# newstat = os.stat(filename)[stat.ST_CTIME]
self.configMode = T_CFG
return filename
12 years ago
return origfilename
return origfilename
def getHeaderText(self, text):
textLines = text.splitlines()
paramLine = ""
if textLines:
textLine = textLines[0]
9 years ago
rePar = re.compile(
"\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$", re.I)
reP = rePar.search(textLine)
if reP:
9 years ago
reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*", re.M)
reLs = reLns.search(text)
if reLs:
paramLine = text[reP.end():reLs.end()]
9 years ago
paramLine = paramLine.replace("\\", " ")
else:
paramLine = textLine[reP.end():]
return paramLine
def getTemplateDirs(self, dirsTemplates):
"""Check template variable cl_name in first directories and files"""
14 years ago
skipDirs = []
skipTemplates = []
debug = False
for dirsTemplate in dirsTemplates:
9 years ago
filesAndDirs = map(lambda x: os.path.join(dirsTemplate, x),
listDirectory(dirsTemplate))
for dirFile in filesAndDirs:
if os.path.isdir(dirFile):
flagDir = True
9 years ago
templatePath = os.path.join(dirFile, self.templDirNameFile)
if not os.path.isfile(templatePath):
skipDirs.append(dirFile)
continue
else:
flagDir = False
templatePath = dirFile
if os.path.isfile(templatePath):
if self.getFileType(templatePath) == "bin":
skipTemplates.append(dirFile)
else:
textTemplate = open(templatePath).read()
if textTemplate:
headerLine = self.getHeaderText(textTemplate)
if headerLine:
if not debug and \
9 years ago
not "cl_name==" in headerLine and \
not "ac_" in headerLine:
if flagDir:
skipDirs.append(dirFile)
else:
skipTemplates.append(dirFile)
else:
if flagDir:
skipDirs.append(dirFile)
else:
skipTemplates.append(dirFile)
else:
skipTemplates.append(dirFile)
if skipDirs or skipTemplates:
# print warning
self.printWARNING(_("No conditions for checking the value of "
"an action variable"))
skipDirTemplates = []
for skipDir in skipDirs:
9 years ago
skipTempl = os.path.join(skipDir, self.templDirNameFile)
if os.path.isfile(skipTempl):
skipDirTemplates.append(skipTempl)
if skipTemplates or skipDirTemplates:
11 years ago
self.printWARNING(_("Skipped templates:"))
for skipTemplate in skipTemplates + skipDirTemplates:
9 years ago
self.printWARNING(" " * 6 + skipTemplate)
if skipDirs:
11 years ago
self.printWARNING(_("Skipped directories:"))
for skipDir in skipDirs:
9 years ago
self.printWARNING(" " * 6 + skipDir)
11 years ago
self.printWARNING("")
self.printWARNING(_("Headers of directory templates and headers "
9 years ago
"of files on the first level should include "
"an action variable"))
11 years ago
self.printWARNING(_("Example:"))
self.printWARNING("# Calculate ac_install_merge==on")
return skipDirs + skipTemplates
@catch_no_space_left
9 years ago
def applyTemplates(self, progress=True, rerun=True):
"""Применяет шаблоны к конфигурационным файлам"""
def createDictTemplates(path, prefix, dictTemplates):
"""Создает словарь {"директория":"кол-во шаблонов" ...}
и считает общее количество шаблонов
"""
# Количество шаблонов
self.allTemplates += 1
dirTemplate = os.path.split(path)[0]
9 years ago
while True:
if dirTemplate in dictTemplates.keys():
dictTemplates[dirTemplate] += 1
else:
dictTemplates[dirTemplate] = 1
if dirTemplate == prefix:
break
dirTemplate = os.path.split(dirTemplate)[0]
return dictTemplates
self.clearErrors()
12 years ago
self.clearWarnings()
if not self.objVar.defined("cl_template_path_use"):
self.setError(_("undefined variable: ") + "cl_template_path_use")
return False
dirsTemplates = self.objVar.Get("cl_template_path_use")
# Созданные директории
self.createdDirs = []
# Примененные файлы
self.filesApply = []
# Номер применяемого шаблона
self.numberProcessTempl = 0
# Словарь директорий с количеством файлов шаблонов
self.dictTemplates = {}
# Количество шаблонов
self.allTemplates = 0
14 years ago
# Установка по умолчанию аттрибутов для функциии шаблонов ini()
# Время доступа к конфигурационному файлу функции шаблона ini()
14 years ago
self.functObj.timeIni = -1
# Первоначальный словарь переменных для ini()
14 years ago
self.functObj.prevDictIni = {}
# Текущий словарь переменных для ini()
14 years ago
self.functObj.currDictIni = {}
self.functObj.currentBelong = ""
self.functObj.currentAction = "merge"
14 years ago
# Словарь времен модификации env файлов для ini()
self.functObj.timeConfigsIni = {}
if self._servDir:
tmpDirsTemplates = []
for dirP in dirsTemplates:
dirTempl = dirP + self._servDir
if os.access(dirTempl, os.F_OK):
# Если директория существует
tmpDirsTemplates.append(dirTempl)
dirsTemplates = tmpDirsTemplates
14 years ago
scanObj = scanDirectory()
9 years ago
scanObj.processingFile = lambda x, y: createDictTemplates(x, y,
self.dictTemplates)
# Считаем количество шаблонов
14 years ago
dirsTemplatesExists = filter(lambda x: os.path.exists(x), dirsTemplates)
if not dirsTemplatesExists and not self.cltObj:
9 years ago
return self.createdDirs, self.filesApply
# check cl_name in first template dirs and files
skipTemplates = self.getTemplateDirs(dirsTemplatesExists)
9 years ago
# if not os.environ.get("EBUILD_PHASE","") and progress:
# for dirTemplate in dirsTemplatesExists:
# scanObj.scanningDirectory(dirTemplate)
# Считаем количество шаблонов clt
if self.cltObj:
# Считаем количество шаблонов clt
self.cltObj.countsNumberTemplates()
# не считать количество файлов в объекте self.cltObj
self.cltObj.checkNumberTemplate = False
# начальный номер clt шаблона
self.cltObj.numberProcessTempl = self.allTemplates
# метод показывающий номер clt шаблона
self.cltObj.numberProcessTemplates = self.numberProcessTemplates
12 years ago
# метод показывающий номер clt шаблона
self.cltObj.templateModify = self.templateModify
# общее количество шаблонов
self.allTemplates += self.cltObj.allTemplates
self.cltObj.allTemplates = self.allTemplates
self.numberAllTemplates(self.allTemplates)
# Обрабатываем шаблоны
locationPath = dict(self.objVar.ZipVars('main.cl_template_path',
9 years ago
'main.cl_template_location'))
14 years ago
for dirTemplate in dirsTemplatesExists:
self.objVar.Set('cl_pass_location',
locationPath.get(dirTemplate, dirTemplate),
force=True)
if self.scanningTemplates(dirTemplate,
skipTemplates=skipTemplates) is False:
11 years ago
break
9 years ago
if self.cltObj:
self.objVar.Set('cl_pass_location', 'clt', True)
# Созданные директории
self.cltObj.createdDirs = self.createdDirs
# Примененные файлы
self.cltObj.filesApply = self.filesApply
# Словарь директорий с количеством файлов шаблонов
self.cltObj.dictTemplates = self.dictTemplates
# Количество шаблонов
self.cltObj.allTemplates = self.allTemplates
# Установка по умолчанию аттрибутов для функциии шаблонов ini()
# Время доступа к конфигурационному файлу функции шаблона ini()
self.cltObj.functObj = self.functObj
self.cltObj.protectedFiles = self.protectedFiles
# Метод применения функций к шаблонам
self.cltObj.applyFuncTemplate = self.functObj.applyFuncTemplate
# Словарь примененных файлов шаблонов
self.cltObj.dictProcessedTemplates = self.dictProcessedTemplates
self.cltObj.changedFiles = self.changedFiles
self.cltObj.autoUpdateFiles = self.autoUpdateFiles
self.cltObj.autoUpdateDirs = self.autoUpdateDirs
14 years ago
if self.cltFilter:
14 years ago
# Шаблоны + .clt которые будут применены
self.cltObj.filterApplyTemplates = {}
if self.objVar.Get('cl_merge_set') == "on":
for pkg in self.objVar.Get('cl_merge_pkg'):
if not pkg:
continue
category = isPkgInstalled(pkg)
if category:
pkgContents = PkgContents("{CATEGORY}/{PF}".format(
9 years ago
**category[0]))
for filename in pkgContents.content.keys():
if not filename in self.cltObj.filterApplyTemplates:
9 years ago
self.cltObj.filterApplyTemplates[
filename] = []
self.cltObj.filterApplyTemplates[
filename].append(pkg)
for filename, pkgs in self.changedFiles.data.items():
filename = PkgContents.reCfg.sub("/", filename)
if not filename in self.cltObj.filterApplyTemplates:
9 years ago
self.cltObj.filterApplyTemplates[filename] = []
pkgs = filter(
lambda x: x not in
self.cltObj.filterApplyTemplates[filename],
9 years ago
map(lambda x: x[0], pkgs))
self.cltObj.filterApplyTemplates[filename].extend(pkgs)
9 years ago
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',
9 years ago
self.objVar.Get('cl_root_path_next'), force=True)
self.recalculateBaseDir()
9 years ago
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)
12 years ago
self.objVar.Set('cl_merge_pkg',
9 years ago
self.objVar.Get('cl_merge_pkg_new'), force=True)
self.objVar.Set('cl_merge_pkg_new', [], force=True)
createdDirs = self.createdDirs
filesApply = self.filesApply
12 years ago
self.changeMergePackage(self.objVar.Get('cl_merge_pkg'))
11 years ago
self.applyTemplates(rerun=False)
createdDirs.extend(self.createdDirs)
filesApply.extend(self.filesApply)
self.filesApply = filesApply
self.createdDirs = createdDirs
9 years ago
if rerun:
if self.cltObj:
self.queueExecute.extend(self.cltObj.queueExecute)
9 years ago
for processor, text, nameTemplate in self.queueExecute:
if not self.executeTemplate(text, processor):
self.setError(_("Failed to execute") + _(": ") +
nameTemplate)
return False
self.queueExecute = []
self.filesApply = list(set(self.filesApply))
if (self.objVar.Get('cl_root_path') == '/' and
self.objVar.Get('cl_chroot_path') == '/'):
post_script = []
if any("/etc/env.d" in x for x in self.filesApply):
post_script.append(
"LANG=C /usr/sbin/env-update --no-ldconfig")
post_script.append("source /etc/profile")
root_type = self.objVar.Get('install.os_install_root_type')
if (root_type != "livecd" and
any("/etc/locale.gen" in x for x in self.filesApply)):
post_script.append("/usr/sbin/locale-gen &>/dev/null")
self.executeTemplate("\n".join(post_script), "/bin/bash")
if self.objVar.Get('cl_protect_use_set') == 'on':
self.updateProtectedFiles()
if self.objVar.Get('cl_verbose_set') == 'on' and \
9 years ago
self.filesApply:
self.verboseOutput(
9 years ago
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
9 years ago
self.printWARNING(_("Calculate Utilities have changed files") + _(":"))
reGrey = re.compile(r"\._cfg\d{4}_")
11 years ago
rootPath = self.objVar.Get('cl_root_path')
for fn in sorted(list(set(filesApply))):
11 years ago
if rootPath != '/' and self.objVar.Get('cl_action') == 'patch' and \
9 years ago
fn.startswith(rootPath):
fn = fn[len(rootPath) + 1:]
if reGrey.search(fn):
9 years ago
self.printSUCCESS("&nbsp;" * 5 + \
"<font color=\"dark gray\">%s</font>" % fn)
else:
9 years ago
self.printSUCCESS("&nbsp;" * 5 + fn)
def updateProtectedFiles(self):
"""
Update ._cfg0000 files
"""
11 years ago
if self.objVar.Get('cl_ebuild_phase') == 'compile':
return
chrootPath = self.objVar.Get('cl_chroot_path')
cfgs = getCfgFiles(self.objVar.Get('cl_config_protect'),
prefix=chrootPath)
autoUpdateDict = {}
9 years ago
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(
9 years ago
**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)
9 years ago
files = set(map(lambda x: pathJoin(chrootPath, x),
pkgContents.content.keys()))
if (self.objVar.Get('cl_dispatch_conf') != 'usenew' and
9 years ago
self.objVar.Get('cl_autoupdate_set') != "on"):
notUpdate = files - set(self.autoUpdateFiles)
files &= set(self.autoUpdateFiles)
9 years ago
for filename in list(notUpdate & set(cfgs.keys())):
if hashlib.md5(readFile(filename)).hexdigest() == \
9 years ago
hashlib.md5(readFile(
cfgs[filename][0][1])).hexdigest():
files.add(filename)
9 years ago
for filename in list(files & set(cfgs.keys())):
# get ctime from orig filename
9 years ago
# if os.path.exists(filename):
# ctime = os.stat(filename).st_ctime
9 years ago
# else:
# ctime = 0
# if orig filename older that .cfg
cfgs[filename].sort(reverse=True)
9 years ago
# if ctime < cfgs[filename][0][0]:
try:
9 years ago
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(
9 years ago
ffrom=cfgs[filename][0][1], fto=filename))
continue
autoUpdateDict[cfgs[filename][0][1]] = filename
9 years ago
for mtime, fn in cfgs[filename]:
try:
os.unlink(fn)
9 years ago
except OSError:
self.printWARNING(_("Failed to remove %s") % fn)
try:
pkgContents.writeContents()
9 years ago
except IOError:
self.printWARNING(_("Failed to modify %s contents") % pkg)
self.filesApply = 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. "
9 years ago
"Perform run dispatch-conf."))
11 years ago
if self.dispatchConf and \
9 years ago
self.objVar.Get(
'cl_dispatch_conf') == 'dispatch' and \
self.objVar.Get('cl_ebuild_phase') == '':
self.dispatchConf(self.filesApply)
def scanningTemplates(self, scanDir, prefix=None, flagDir=False,
9 years ago
optDir=None, skipTemplates=()):
"""Сканирование и обработка шаблонов в директории scanDir"""
9 years ago
if optDir is None:
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
9 years ago
pathDir, objHead = retDir
optDir["path"] = pathDir
if not objHead is True:
if objHead.typeAppend == "skip":
# Установка опции пропуска директории
optDir["skip"] = True
if ("autoupdate" in objHead.params or
9 years ago
self.objVar.Get('cl_autoupdate_set') == 'on'):
optDir["autoupdate"] = True
if flagDir or stat.S_ISDIR(os.lstat(str(scanDir))[stat.ST_MODE]):
9 years ago
if not os.access(scanDir, os.R_OK | os.X_OK):
self.printWARNING(_("Failed to read templates directory %s") %
scanDir)
return False
for fileOrDir in sorted(listDirectory(scanDir)):
9 years ago
absPath = os.path.join(scanDir, fileOrDir)
if skipTemplates and absPath in skipTemplates:
9 years ago
continue
stInfo = os.lstat(str(absPath))
statInfo = stInfo[stat.ST_MODE]
12 years ago
prevModule = self.objVar.defaultModule
prevBelong = self.functObj.currentBelong
prevAction = self.functObj.currentAction
12 years ago
try:
if stat.S_ISREG(statInfo):
if not self.processingFile(absPath, prefix, optDir):
ret = False
11 years ago
continue
12 years ago
elif stat.S_ISDIR(statInfo):
# Обработка директории
retDir = self.processingDirectory(absPath, prefix,
optDir)
if retDir is None:
continue
elif retDir is False:
ret = False
break
# Опции следующей директории
optNextDir = {}
9 years ago
pathDir, objHead = retDir
12 years ago
optNextDir["path"] = pathDir
if not objHead is True:
if objHead.typeAppend == "skip":
# Установка опции пропуска директории
optNextDir["skip"] = True
if ("autoupdate" in objHead.params or
9 years ago
self.objVar.Get(
'cl_autoupdate_set') == 'on'):
12 years ago
optNextDir["autoupdate"] = True
ret = self.scanningTemplates(absPath, prefix, True,
optNextDir)
if ret is False:
break
except TemplatesError as e:
self.clearErrors()
self.printWARNING(str(e))
12 years ago
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
14 years ago
# Проверка на переменные в названии файла
if not self.getNeedTemplate(path):
if self.getError():
return False
14 years ago
return True
if self.getError():
return False
nameFileConfig = path.partition(prefix)[2]
# файл в системе без условий
9 years ago
nameFileConfig = "/".join(map(lambda x: x.split("?")[0],
nameFileConfig.split("/")))
14 years ago
# Записываем в переменную обрабатываемый файл
9 years ago
self.objVar.Set("cl_pass_file", nameFileConfig)
14 years ago
filesApl = self.joinTemplate(path, nameFileConfig, optFile)
14 years ago
if self.getError():
return False
if filesApl:
14 years ago
# Настоящее имя конфигурационного файла
nameFileConfig = filesApl[0]
# Пишем время модификации *.env файлов
if nameFileConfig.endswith(".env"):
nameEnvFile = os.path.basename(nameFileConfig)
self.functObj.timeConfigsIni[nameEnvFile] = float(time.time())
14 years ago
self.filesApply += filesApl
if filesApl:
self._addFile(filesApl)
return True
def processingDirectory(self, path, prefix, opt):
"""Обработка в случае директории если возвращаем None то пропуск дир."""
# Файл шаблона директории
9 years ago
if not os.access(path, os.R_OK | os.X_OK):
self.printWARNING(_("Failed to read templates directory %s") % path)
return None
dirInfoFile = os.path.join(path, self.templDirNameFile)
newDir = pathJoin(self._baseDir, path.partition(prefix)[2])
9 years ago
newDir = "/".join(map(lambda x: x.split("?")[0], newDir.split("/")))
# Применяем шаблон
9 years ago
pathDir, objHeadDir, createdDirs = \
self.getApplyHeadDir(newDir, dirInfoFile, opt)
14 years ago
if createdDirs:
self.createdDirs += createdDirs
if os.path.isfile(pathDir):
11 years ago
self.printWARNING(_("{dirpath} is a file").format(dirpath=pathDir))
self.printWARNING(_("templates in {tempath} are skipped"
9 years ago
).format(tempath=path))
return None
if objHeadDir:
14 years ago
return pathDir, objHeadDir
else:
if self.getError():
return False
# Добавление количества файлов в пропущенной директории
if path in self.dictTemplates.keys():
self.numberProcessTempl += self.dictTemplates[path]
return None
9 years ago
def _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:
9 years ago
with open(self.postmergeFile, "a") as f:
f.write("%s\n" % pkg)
self.postmergePkgs.append(pkg)
9 years ago
except OSError:
self.printWARNING(
9 years ago
_("Failed to reconfigure package %s") % pkg)
else:
mergePkgs = mergePkgs + postmergePkgs
for pkg in mergePkgs:
if not pkg in self.objVar.Get('cl_merge_pkg_new') and \
9 years ago
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 checkVfat(self, fn):
if self.mounts is None:
self.mounts = Mounts()
if self.mounts.getBy(self.mounts.TYPE, where=self.mounts.DIR,
_in=fn) in ("vfat", "ntfs-3g", "ntfs"):
return True
return False
def checkOsError(self, e, fn):
if hasattr(e, 'errno') and e.errno == os.errno.EPERM:
if self.checkVfat(fn):
return True
if hasattr(e, 'errno') and e.errno == os.errno.EACCES and \
"var/calculate/remote" in fn:
return True
return False
def setUidGidError(self, fn, uid, gid, tfn=None):
"""
Установить ошибку связанную со сменой UID и GID файла
"""
import pwd, grp
try:
userName = pwd.getpwuid(uid).pw_name
except (TypeError, KeyError):
userName = str(uid)
try:
groupName = grp.getgrgid(gid).gr_name
except (TypeError, KeyError):
groupName = str(gid)
owner = userName + ":" + groupName
if tfn:
self.setError(_("Failed to apply template file %s") % tfn)
self.setError(_("error") + " " + "'chown %s %s'" % (owner, fn))
def setModeError(self, fn, mode, tfn):
"""
Установить ошибку связанную со сменой доступа к файлу
"""
self.setError(_("Failed to apply template file %s") % tfn)
self.setError(_("error") + " " +
"'chmod %s %s'" % (str(oct(mode)), fn))
def chownConfDir(self, nameDirConfig, uid, gid, nameFileTemplate):
"""Изменение владельца конфигурационной директории"""
try:
os.chown(nameDirConfig, uid, gid)
except (OSError, Exception) as e:
if self.checkOsError(e, nameDirConfig):
return True
self.setUidGidError(
nameDirConfig, uid, gid, nameFileTemplate)
return False
return True
def chmodConfDir(self, nameDirConfig, mode, nameFileTemplate):
"""Изменения режима доступа конфигурационного файла"""
try:
os.chmod(nameDirConfig, mode)
except (OSError, Exception) as e:
if self.checkOsError(e, nameDirConfig):
return True
self.setModeError(nameDirConfig, mode, nameFileTemplate)
return False
return True
def getApplyHeadDir(self, newDir, templateDirFile, optDir):
"""Применяет шаблон к директории (права, владелец, и.т. д)"""
def function(text):
"""Функция обработки функций в заголовке"""
return self.applyFuncTemplate(text, templateDirFile)
applyDir = newDir
# Родительская директория
if optDir.get("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])
# Фильтрация шаблонов по названию директории
9 years ago
realPath = os.path.join("/", applyDir.partition(self._baseDir)[2])
if realPath in self.dirsFilter:
9 years ago
return "", False, []
14 years ago
# Создаем директорию если необходимо
14 years ago
crDirs = self.createDir(applyDir, False, self.uid, self.gid)
if not crDirs:
9 years ago
return "", False, []
if "autoupdate" in optDir:
self.autoUpdateDirs.append(applyDir)
14 years ago
if crDirs is True:
9 years ago
return applyDir, True, []
14 years ago
else:
9 years ago
return applyDir, True, crDirs
try:
FD = open(templateDirFile)
textTemplate = FD.readline().rstrip()
buf = textTemplate
while buf and textTemplate.endswith('\\'):
buf = FD.readline()
9 years ago
textTemplate = "%s %s" % (textTemplate[:-1], buf.rstrip())
FD.close()
9 years ago
except IOError:
self.setError(_("Failed to open the template") + _(": ") +
9 years ago
templateDirFile)
return "", False, []
12 years ago
headerLine = self.getHeaderText(textTemplate)
if headerLine:
9 years ago
moduleParam = filter(lambda x: x.startswith('env='),
headerLine.split())
12 years ago
if moduleParam:
self.objVar.defaultModule = moduleParam[0].partition('=')[2]
try:
9 years ago
importlib.import_module(
"calculate.%s.variables" % self.objVar.defaultModule)
except (ImportError, AttributeError):
return "", False, []
# Заменяем переменные на их значения
textTemplate = self.applyVarsTemplate(textTemplate, templateDirFile)
14 years ago
# Заменяем функции на их значения
textTemplate = self.applyFuncTemplate(textTemplate, templateDirFile)
# Обработка заголовка
9 years ago
objHead = dirHeader(templateDirFile, textTemplate, self.objVar,
function)
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
14 years ago
# Директория с профилями не будет применена
if not objHead.headerTerm:
if objHead.getError():
self.setError(_("Incorrect template") + _(": ") +
templateDirFile)
9 years ago
return "", False, []
# add packeges for reconfigure
self._processMergePostmerge(objHead.params, templateDirFile)
# Пропускаем директорию
if objHead.typeAppend == "skip":
applyDir = path
9 years ago
return applyDir, objHead, []
# Изменяем название родительской директории
9 years ago
if "path" in objHead.params:
path = objHead.params['path']
if path and path[0] == "~":
# Получаем путь с заменой ~ на директорию пользователя
path = os.path.join(self.homeDir,
9 years ago
path.partition("/")[2], "")[:-1]
elif not path or path and path[0] != "/":
self.setError(_("Wrong value 'path' in the template") +
_(": ") + templateDirFile)
9 years ago
return "", False, []
else:
path = pathJoin(self._baseDir, path)
# Изменяем название директории
9 years ago
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)
9 years ago
return "", False, []
# Новый путь к директории
applyDir = pathJoin(path, nameDir)
else:
applyDir = pathJoin(path, os.path.split(applyDir)[1])
# Фильтрация шаблонов по названию директории
9 years ago
realPath = os.path.join("/", applyDir.partition(self._baseDir)[2])
if realPath in self.dirsFilter:
9 years ago
return "", False, []
# Удаляем директорию
if objHead.typeAppend == "remove":
if os.path.isdir(applyDir):
9 years ago
self.changedFiles.addObj(applyDir, ChangedFiles.DIR_REMOVED,
self.functObj.currentBelong)
# удаляем директорию
try:
14 years ago
removeDir(applyDir)
9 years ago
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)
9 years ago
except OSError:
12 years ago
self.setError(
9 years ago
_("Failed to delete the directory: ") + \
removePath)
else:
try:
os.unlink(removePath)
9 years ago
except OSError:
12 years ago
self.setError(
_("Failed to delete: ") + removePath)
9 years ago
return "", False, []
14 years ago
# Созданные директории
createdDirs = []
# chmod - изменяем права
if "chmod" in objHead.params:
mode = self.__octToInt(objHead.params['chmod'])
if mode:
if not os.path.exists(applyDir):
14 years ago
crDirs = self.createDir(applyDir, mode, self.uid, self.gid)
if not crDirs:
9 years ago
return "", False, []
14 years ago
if not crDirs is True:
createdDirs += crDirs
else:
self.chmodConfDir(applyDir, mode, templateDirFile)
else:
self.setError(_("Wrong value 'chmod' in the template") +
_(": ") + templateDirFile)
9 years ago
return "", False, []
# chown - изменяем владельца и группу
if "chown" in objHead.params:
owner = objHead.params['chown']
if owner:
9 years ago
if ":" in owner:
strUid, strGid = owner.split(":")
import pwd
9 years ago
try:
uid = pwd.getpwnam(strUid).pw_uid
9 years ago
except (KeyError, TypeError):
12 years ago
self.setError(_("No such user on the system: ")
9 years ago
+ strUid)
self.setError(_("Wrong value 'chown' in the template") +
_(": ") + templateDirFile)
9 years ago
return "", False, []
try:
import grp
9 years ago
gid = grp.getgrnam(strGid).gr_gid
9 years ago
except (KeyError, TypeError):
12 years ago
self.setError(_("Group not found on the system: ")
9 years ago
+ strGid)
12 years ago
self.setError(
_("Wrong value 'chown' in the template") +
_(": ") + templateDirFile)
9 years ago
return "", False, []
if not os.path.exists(applyDir):
14 years ago
crDirs = self.createDir(applyDir, False, uid, gid)
if not crDirs:
9 years ago
return "", False, []
14 years ago
if not crDirs is True:
createdDirs += crDirs
else:
if not self.chownConfDir(applyDir, uid, gid,
templateDirFile):
9 years ago
return "", False, []
else:
self.setError(_("Wrong value 'chown' in the template") +
_(": ") + templateDirFile)
9 years ago
return "", False, []
else:
12 years ago
self.setError(_("Wrong value 'chown' in the template") +
_(": ") + templateDirFile)
9 years ago
return "", False, []
14 years ago
else:
# Устанавливаем владельцем директории, пользователя по умолчанию
# (переменная шаблона ur_login)
if os.path.exists(applyDir):
9 years ago
self.changedFiles.addObj(applyDir, ChangedFiles.DIR_EXISTS,
self.functObj.currentBelong)
14 years ago
tUid, tGid = getModeFile(applyDir, mode="owner")
if (self.uid, self.gid) != (tUid, tGid):
if not self.chownConfDir(applyDir, self.uid, self.gid,
templateDirFile):
9 years ago
return "", False, []
14 years ago
else:
9 years ago
self.changedFiles.addObj(applyDir, ChangedFiles.DIR_CREATED,
self.functObj.currentBelong)
14 years ago
crDirs = self.createDir(applyDir, False, self.uid, self.gid)
if not crDirs:
9 years ago
return "", False, []
14 years ago
if not crDirs is True:
createdDirs += crDirs
if not objHead:
applyDir = ""
if applyDir:
9 years ago
if ("autoupdate" in optDir or "autoupdate" in objHead.params) and \
12 years ago
not self.objVar.Get('cl_merge_pkg_pass'):
self.autoUpdateDirs.append(applyDir)
9 years ago
return applyDir, objHead, createdDirs
9 years ago
def getUidFromPasswd(self, strUid):
"""Get uid by username from chroot passwd file"""
9 years ago
passwdFile = os.path.join(self._baseDir, 'etc/passwd')
if os.path.exists(passwdFile):
mapUid = dict(
9 years ago
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
9 years ago
def getGidFromGroup(self, strGid):
"""Get gid by groupname from chroot group file"""
9 years ago
groupFile = os.path.join(self._baseDir, 'etc/group')
if os.path.exists(groupFile):
mapGid = dict(
9 years ago
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
9 years ago
def checkOnNewConfigName(self, pathFile):
"""
Check on need update and return pathFile
"""
# if file in PROTECT_MASK or not in PROTECT
chrootPath = self.objVar.Get('cl_chroot_path')
if not filter(pathFile.startswith,
9 years ago
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,
9 years ago
self.objVar.Get('cl_config_protect'),
prefix=self.objVar.Get('cl_chroot_path'))
origName = pathFile if chrootPath == '/' \
9 years ago
else pathFile[len(chrootPath):]
if origName in self.allContents:
pkg = self.allContents[origName]
else:
return pathFile
9 years ago
pkg = isPkgInstalled(pkg, sortByVersion=True, prefix=chrootPath)
if not pkg:
return pathFile
if checkContents("{CATEGORY}/{PF}".format(**pkg[-1]),
9 years ago
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
9 years ago
return os.path.join(real_dirname, "._cfg0000_%s" % real_filename)
def chownConfFile(self, nameFileConfig, uid, gid, nameFileTemplate,
checkExists=True):
"""Изменение владельца конфигурационного файла"""
try:
if checkExists and not os.path.exists(nameFileConfig):
# Создание файла
FD = open(nameFileConfig, "w")
FD.close()
os.lchown(nameFileConfig, uid, gid)
except (OSError, Exception) as e:
if self.checkOsError(e, nameFileConfig):
return True
self.setUidGidError(
nameFileConfig, uid, gid, nameFileTemplate)
return False
return True
def chmodConfFile(self, nameFileConfig, mode, nameFileTemplate,
checkExists=True):
"""Изменения режима доступа конфигурационного файла"""
try:
if checkExists and not os.path.exists(nameFileConfig):
# Создание файла
FD = open(nameFileConfig, "w")
FD.close()
os.chmod(nameFileConfig, mode)
except (OSError, Exception) as e:
if self.checkOsError(e, nameFileConfig):
return True
self.setModeError(nameFileConfig, mode, nameFileTemplate)
return False
return True
def getApplyHeadTemplate(self, nameFileTemplate, nameFileConfig,
9 years ago
templateFileType, optFile):
"""Применяет заголовок к шаблону (права, владелец, и.т. д)"""
9 years ago
def function(text):
"""Функция обработки функций в заголовке"""
9 years ago
return self.applyFuncTemplate(text, nameFileTemplate)
14 years ago
def preReturn(pathProg):
"""Действия перед выходом из метода"""
if pathProg:
os.chdir(pathProg)
self.closeFiles()
pathProg = ""
self.executeType = None
# Файлы в системе к которым были применены шаблоны
14 years ago
# В случае бинарного типа файла читаем шаблон
if templateFileType == "bin":
self.nameFileTemplate = os.path.abspath(nameFileTemplate)
14 years ago
self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
if not self.F_TEMPL:
self.setError(_("Failed to open the template") + _(": ") +
9 years ago
self.nameFileTemplate)
return [], False
14 years ago
self.textTemplate = self.F_TEMPL.read()
self.closeTemplFile()
14 years ago
objHeadNew = fileHeader(nameFileTemplate, self.textTemplate, False,
9 years ago
templateFileType, objVar=self.objVar,
function=function, templateObj=self)
14 years ago
# файл шаблона не будет применен
if not objHeadNew.headerTerm:
14 years ago
if objHeadNew.getError():
self.setError(_("Incorrect template") + _(": ") +
9 years ago
nameFileTemplate)
return [], False
# add packeges for reconfigure
self._processMergePostmerge(objHeadNew.params, nameFileTemplate)
# Родительская директория
path = optFile["path"]
# Изменяем название родительской директории
9 years ago
if "path" in objHeadNew.params:
path = objHeadNew.params['path']
if path and path[0] == "~":
# Получаем путь с заменой ~ на директорию пользователя
9 years ago
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)
9 years ago
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)
9 years ago
return [], False
# Новый путь к оригинальному файлу
9 years ago
pathOldFile = pathJoin(path, nameFile)
else:
9 years ago
pathOldFile = pathJoin(path, os.path.split(nameFileConfig)[1])
pathOrigFile = pathOldFile
if self.objVar.Get('cl_protect_use_set') == 'on':
pathOldFile = self.fixNameFileConfig(pathOldFile)
pathOldFile = self.checkOnNewConfigName(pathOldFile)
# буффер для использование в link=
newBuffer = None
applyFiles = [pathOldFile]
# Фильтрация шаблонов по названию файла
9 years ago
realPath = os.path.join("/", pathOldFile.partition(self._baseDir)[2])
if realPath in self.filesFilter:
9 years ago
return [], False
14 years ago
typeAppendTemplate = objHeadNew.typeAppend
9 years ago
# Параметр exec
9 years ago
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]
9 years ago
if not os.access(execPath, os.X_OK):
self.setError(
_("Wrong value '%s' in the template") % paramName +
_(": ") + nameFileTemplate)
self.setError(_("Failed to execute %s") % execPath)
return [], False
if typeAppendTemplate == "join":
12 years ago
self.setError(_("Wrong value 'append=join' in the template") +
_(": ") + nameFileTemplate)
9 years ago
return [], False
# Очищаем оригинальный файл
if typeAppendTemplate == "clear":
try:
open(pathOldFile, "w").truncate(0)
9 years ago
except IOError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to clear the file") + _(": ") +
pathOldFile)
9 years ago
return applyFiles, False
# Удаляем оригинальный файл
14 years ago
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)
9 years ago
return applyFiles, False
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the link") + _(": ") +
pathOldFile)
9 years ago
return [], False
if os.path.isfile(pathOldFile) and self.configMode == T_ORIGIN:
# удаляем файл
try:
os.remove(pathOldFile)
9 years ago
return applyFiles, False
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the file") + _(": ") +
pathOldFile)
9 years ago
return [], False
finally:
9 years ago
pattern = "%s/._cfg????_%s" % (os.path.dirname(pathOrigFile),
os.path.basename(pathOrigFile))
for fn in glob.glob(pattern):
try:
os.unlink(fn)
9 years ago
except OSError:
pass
if self.functObj.currentBelong:
self.changedFiles.addObj(pathOrigFile,
ChangedFiles.FILE_REMOVED,
self.functObj.currentBelong)
9 years ago
return [], False
# Пропускаем обработку шаблона
14 years ago
elif typeAppendTemplate == "skip":
9 years ago
return [], False
# Создаем директорию для файла если ее нет
if not os.path.exists(path):
if not self.createDir(path):
9 years ago
return [], False
# В случае force
if objHeadNew.params.has_key("force"):
if os.path.islink(pathOldFile):
# удаляем ссылку
9 years ago
newBuffer = ""
try:
os.unlink(pathOldFile)
9 years ago
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the link") + _(": ") +
pathOldFile)
9 years ago
return [], False
if os.path.isfile(pathOldFile):
# удаляем файл
9 years ago
newBuffer = ""
try:
os.remove(pathOldFile)
9 years ago
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the file") + _(": ") +
pathOldFile)
9 years ago
return [], False
flagSymlink = False
# Если есть параметр mirror
if 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,
9 years ago
templateFile.partition("/")[2],
"")[:-1]
templateFile = pathJoin(self._baseDir, templateFile)
if not os.path.exists(templateFile):
if os.path.exists(pathOldFile):
try:
os.remove(pathOldFile)
9 years ago
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
9 years ago
self.setError(
_("Failed to delete the file") + _(": ") +
pathOldFile)
return [], False
elif not os.path.exists(pathOldFile):
9 years ago
return [], False
# Если есть указатель на файл шаблона (link)
9 years ago
if objHeadNew.params.has_key("link") and \
not objHeadNew.params.has_key("symbolic"):
templateFile = objHeadNew.params['link']
if templateFile and templateFile[0] == "~":
# Получаем директорию пользователя
9 years ago
templateFile = os.path.join(
self.homeDir, templateFile.partition("/")[2], "")[:-1]
templateFile = pathJoin(self._baseDir, templateFile)
foundTemplateFile = os.path.exists(templateFile)
9 years ago
buff = None
fMode, fUid, fGid = None, None, None
if foundTemplateFile:
try:
F_CONF = self.openTemplFile(templateFile)
9 years ago
if not F_CONF:
raise IOError
buff = F_CONF.read()
F_CONF.close()
fMode, fUid, fGid = getModeFile(templateFile)
9 years ago
except (OSError, IOError):
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to open the file") + _(": ") +
templateFile)
9 years ago
return [], False
if os.path.exists(pathOldFile):
9 years ago
newBuffer = ""
try:
os.remove(pathOldFile)
9 years ago
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the file") + _(": ") +
pathOldFile)
9 years ago
return [], False
if buff is not None:
14 years ago
try:
9 years ago
FD = open(pathOldFile, "w+")
newBuffer = buff
14 years ago
FD.write(buff)
FD.close()
9 years ago
except IOError:
self.setError(_("Template error") + _(": ") +
14 years ago
nameFileTemplate)
9 years ago
self.setError(_("Failed to create the file") + " '%s'" \
% pathOldFile)
return [], False
oMode = getModeFile(pathOldFile, mode="mode")
14 years ago
# Если права не совпадают, меняем права
if fMode != oMode:
if not self.chmodConfFile(
pathOldFile, fMode, nameFileTemplate,
checkExists=False):
9 years ago
return [], False
# Если символическая ссылка
9 years ago
prevOldFile = None
if objHeadNew.params.has_key("symbolic"):
prevOldFile = pathOldFile
pathOldFile = objHeadNew.params['link']
flagSymlink = True
if not pathOldFile:
raise TemplatesError(
_("Missed source link in template '%s'")
9 years ago
% str(nameFileTemplate))
if not "/" == pathOldFile[0]:
pathLink = os.path.split(os.path.abspath(prevOldFile))[0]
pathProg = os.getcwd()
try:
os.chdir(pathLink)
9 years ago
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
12 years ago
self.setError(
9 years ago
_("Failed to change the current directory to") + \
" " + pathLink)
return [], False
# chmod - изменяем права
if objHeadNew.params.has_key("chmod"):
mode = self.__octToInt(objHeadNew.params['chmod'])
if mode:
if not self.chmodConfFile(pathOldFile, mode, nameFileTemplate):
preReturn(pathProg)
9 years ago
return [], False
else:
self.setError(_("Wrong value 'chmod' in the template") +
_(": ") + nameFileTemplate)
preReturn(pathProg)
9 years ago
return [], False
# chown - изменяем владельца и группу
if objHeadNew.params.has_key("chown"):
owner = objHeadNew.params['chown']
if owner:
9 years ago
if ":" in owner:
strUid, strGid = owner.split(":")
if strUid.isdigit():
uid = int(strUid)
else:
uid = self.getUidFromPasswd(strUid)
import pwd
9 years ago
try:
if uid is None:
uid = pwd.getpwnam(strUid).pw_uid
9 years ago
except (KeyError, TypeError):
12 years ago
self.setError(_("No such user on the system: ") +
strUid)
12 years ago
self.setError(
_("Wrong value 'chown' in the template") +
_(": ") + nameFileTemplate)
preReturn(pathProg)
9 years ago
return [], False
if strGid.isdigit():
gid = int(strGid)
else:
gid = self.getGidFromGroup(strGid)
try:
if gid is None:
import grp
9 years ago
gid = grp.getgrnam(strGid).gr_gid
9 years ago
except (KeyError, TypeError):
12 years ago
self.setError(_("Group not found on the system: ") +
strGid)
12 years ago
self.setError(
_("Wrong value 'chown' in the template") +
_(": ") + nameFileTemplate)
preReturn(pathProg)
9 years ago
return [], False
# Изменяем владельца файла
if not self.chownConfFile(pathOldFile, uid, gid,
nameFileTemplate):
preReturn(pathProg)
9 years ago
return [], False
else:
12 years ago
self.setError(_("Wrong value 'chown' in the template") +
_(": ") + nameFileTemplate)
preReturn(pathProg)
9 years ago
return [], False
else:
self.setError(_("Wrong value 'chown' in the template") +
_(": ") + nameFileTemplate)
preReturn(pathProg)
9 years ago
return [], False
if not flagSymlink:
9 years ago
self.openFiles(nameFileTemplate, pathOldFile, objHeadNew.fileType,
newBuffer)
if self.getError():
9 years ago
return [], False
14 years ago
if not objHeadNew.params.has_key("chown"):
# Устанавливаем владельцем конфигурационного файла,
# пользователя по умолчанию (переменная шаблона ur_login)
14 years ago
if os.path.exists(pathOldFile):
tUid, tGid = getModeFile(pathOldFile, mode="owner")
if (self.uid, self.gid) != (tUid, tGid):
# Изменяем владельца файла
if not self.chownConfFile(
pathOldFile, self.uid, self.gid, nameFileTemplate,
checkExists=False):
preReturn(pathProg)
9 years ago
return [], False
if flagSymlink:
if os.path.exists(prevOldFile) or os.path.islink(prevOldFile):
try:
if os.path.islink(prevOldFile):
# если ссылка то удаляем её
os.unlink(prevOldFile)
else:
# иначе удаляем файл
os.remove(prevOldFile)
9 years ago
except OSError:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the file") + _(": ") +
prevOldFile)
preReturn(pathProg)
9 years ago
return [], False
if not "/" == pathOldFile[0]:
9 years ago
applyFiles = [
prevOldFile] # ,os.path.join(pathLink,pathOldFile)]
else:
9 years ago
applyFiles = [prevOldFile] # ,pathOldFile]
try:
os.symlink(pathOldFile, prevOldFile)
9 years ago
except OSError:
self.setError(_("Template error") + _(": ") + \
nameFileTemplate)
self.setError(_("Failed to create a symbolic link") + _(": ") + \
"%s -> %s" % (prevOldFile, pathOldFile))
preReturn(pathProg)
9 years ago
return [], False
14 years ago
if not objHeadNew.body.strip():
preReturn(pathProg)
if "protected" in objHeadNew.params:
self.protectedFiles += applyFiles
9 years ago
return applyFiles, False
else:
applyFiles = [pathOldFile]
if pathProg:
os.chdir(pathProg)
# Если файлы заменяются не нужно их обрабатывать дальше
9 years ago
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)
9 years ago
if ("autoupdate" in optFile or "autoupdate" in objHeadNew.params) \
12 years ago
and not self.objVar.Get('cl_merge_pkg_pass'):
9 years ago
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
9 years ago
return applyFiles, objHeadNew
9 years ago
def createNewClass(self, name, bases, attrs=None):
"""Создает объект нового класса
createNewClass(self, name, bases, attrs)
name - имя класса - str,
bases - cписок наследуемых классов - (tuple),
attrs - аттрибуты класса - {dict}
"""
9 years ago
if attrs is None:
attrs = {}
class newMethod(object):
# Объединяем конфигурации
def join(self, newObj):
if newObj.__class__.__name__ == self.__class__.__name__:
9 years ago
if hasattr(self, "docObj"):
self.docObj.joinDoc(newObj.doc)
# Пост обработка
9 years ago
if hasattr(self, "postXML"):
self.postXML()
9 years ago
attrsNew = {"configName": name}
if attrs:
9 years ago
attrsNew.update(attrs)
newCl = type(name, bases + (newMethod, object,), attrsNew)
return newCl
def fileIsUtf(self, fileName):
"""Проверяет файл на кодировку UTF-8"""
if os.path.isfile(fileName):
9 years ago
FD = open(os.path.abspath(fileName), 'r')
newTemplate = FD.read(1) + FD.read()
FD.close()
try:
newTemplate.decode("UTF-8")
9 years ago
except UnicodeDecodeError:
return False
return True
return False
9 years ago
def joinTemplate(self, nameFileTemplate, nameFileConfig, optFile=None):
"""Объединения шаблона и конф. файла
14 years ago
join(nameFileTemplate, nameFileConfig, ListOptTitle)
Объединение шаблона nameFileTemplate и конф. файла nameFileConfig,
ListOptTitle - список строк которые добавятся в заголовок
optFile = опции для шаблона
"""
9 years ago
if optFile is None:
optFile = {}
# Выполняем условия для блока текста а так-же заменяем переменные
14 years ago
self.nameFileTemplate = os.path.abspath(nameFileTemplate)
14 years ago
self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
self.textTemplate = self.F_TEMPL.read()
self.configMode = T_ORIGIN
14 years ago
self.closeTemplFile()
14 years ago
# Флаг копирования шаблона в конфигурационный файл
flagCopyTemplate = True
# Тип шаблона бинарный или текстовый
if self.textTemplate[:11] == "# Calculate":
templateFileType = "text"
else:
templateFileType = self.getTemplateType()
12 years ago
headerLine = self.getHeaderText(self.textTemplate)
if headerLine:
9 years ago
moduleParam = filter(lambda x: x.startswith('env='),
headerLine.split())
12 years ago
if moduleParam:
self.objVar.defaultModule = moduleParam[0].partition('=')[2]
try:
9 years ago
importlib.import_module(
"calculate.%s.variables" % self.objVar.defaultModule)
except (ImportError, AttributeError):
return []
12 years ago
14 years ago
if templateFileType != "bin":
# Заменяем переменные на их значения
14 years ago
self.textTemplate = self.applyVarsTemplate(self.textTemplate,
9 years ago
nameFileTemplate)
14 years ago
flagCopyTemplate = False
if not optFile:
9 years ago
optFile = {"path": os.path.split(nameFileConfig)[0]}
filesApply, objHeadNew = self.getApplyHeadTemplate(nameFileTemplate,
9 years ago
nameFileConfig,
templateFileType,
optFile)
if not objHeadNew:
return filesApply
9 years ago
if filesApply and not filter(lambda x: "calculate/ini.env" in x,
filesApply):
self.templateModify()
if templateFileType != "bin":
# Вычисляем условные блоки
objHeadNew.body = self.applyTermsTemplate(objHeadNew.body,
9 years ago
nameFileTemplate)
# Вычисляем функции
objHeadNew.body = self.applyFuncTemplate(objHeadNew.body,
9 years ago
nameFileTemplate)
14 years ago
# Настоящее имя конфигурационного файла
nameFileConfig = filesApply[0]
# Флаг - кодировка с бинарными примесями у файла шаблона включаем при
# условии текстового файла и кодировки отличной от UTF-8
flagNotUtf8New = False
9 years ago
# Флаг - кодировка с бинарными примесями у оригинального файла
flagNotUtf8Old = False
14 years ago
if not flagCopyTemplate:
# проверяем кодировку шаблона
14 years ago
if not self.fileIsUtf(nameFileTemplate):
flagNotUtf8New = True
9 years ago
if not (objHeadNew.params.has_key("link") and
objHeadNew.params.has_key("symbolic")):
# проверяем кодировку оригинального файла
14 years ago
if not self.fileIsUtf(nameFileConfig):
flagNotUtf8Old = True
14 years ago
self.textTemplate = objHeadNew.body
# Список примененных шаблонов
ListOptTitle = []
if nameFileConfig in self.dictProcessedTemplates:
ListOptTitle = self.dictProcessedTemplates[nameFileConfig]
# Титл конфигурационного файла
title = ""
if ListOptTitle:
title = self.getTitle(objHeadNew.comment, ListOptTitle,
configPath=nameFileConfig)
title = title.encode("UTF-8")
objHeadOld = False
if objHeadNew.comment:
14 years ago
objHeadOld = fileHeader(nameFileConfig, self.textConfig,
objHeadNew.comment)
9 years ago
elif objHeadNew.fileType and \
objHeadNew.typeAppend in ("before", "after"):
14 years ago
configFileType = self.getFileType(nameFileConfig)
objHeadOld = fileHeader(nameFileConfig, self.textConfig,
fileType=configFileType)
# Строка вызова скрипта (#!/bin/bash ...)
execStr = ""
if objHeadNew.execStr:
execStr = objHeadNew.execStr
14 years ago
elif objHeadOld and objHeadOld.execStr:
execStr = objHeadOld.execStr
if objHeadNew.fileType != 'patch':
9 years ago
wrongOpt = [x for x in ("multiline", "dotall")
if objHeadNew.params.has_key(x)]
if wrongOpt:
9 years ago
self.setError(
_("Option %s should be used for format=patch only")
% wrongOpt[0])
return None
if objHeadNew.fileType != 'dconf':
wrongOpt = [x for x in ("dconf",)
if objHeadNew.params.has_key(x)]
if wrongOpt:
9 years ago
self.setError(
_("Option %s should be used for format=dconf only")
% wrongOpt[0])
return None
if objHeadNew.fileType:
14 years ago
formatTemplate = objHeadNew.fileType
typeAppendTemplate = objHeadNew.typeAppend
9 years ago
if formatTemplate in ("patch", "diff", "dconf"):
if typeAppendTemplate != "patch":
9 years ago
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()
9 years ago
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:
9 years ago
self.setError(
12 years ago
_("Incorrect header parameter format=%s "
9 years ago
"in the template") \
% formatTemplate + " " + nameFileTemplate)
return None
if objHeadOld and objHeadOld.body:
self.textConfig = objHeadOld.body
# обработка конфигурационного файла
11 years ago
self.textTemplate = objTempl.processingFile(self.textConfig,
9 years ago
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 ") + \
9 years ago
nameFileTemplate)
11 years ago
raise TemplatesError(_("Failed to use patch ") + \
9 years ago
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
11 years ago
if formatTemplate in ("diff",):
return objTempl.patchFiles
elif formatTemplate in ("dconf",):
return []
11 years ago
else:
self.saveConfFile()
9 years ago
if 'run' in objHeadNew.params:
if not self.executeTemplate(self.textConfig,
objHeadNew.params['run']):
9 years ago
self.setError(_("Wrong template") + _(": ") + \
nameFileTemplate)
9 years ago
self.setError(_("Failed to execute") + _(": ") + \
self.nameFileConfig)
9 years ago
return None
return None
return filesApply if 'exec' not in objHeadNew.params else None
# Создаем объект в случае параметра format в заголовке
9 years ago
if (typeAppendTemplate == "replace" or
typeAppendTemplate == "before" or
typeAppendTemplate == "after") and \
not (formatTemplate == "bin" or
formatTemplate == "raw"):
# Преобразовываем бинарные файлы
9 years ago
objTxtCoder = None
if flagNotUtf8New:
objTxtCoder = utfBin()
14 years ago
self.textTemplate = objTxtCoder.encode(self.textTemplate)
# создаем объект формата шаблона
14 years ago
objTemplNew = self.getFormatObj(formatTemplate,
14 years ago
self.textTemplate)
if not objTemplNew:
9 years ago
self.setError(_("Incorrect header parameter format=%s "
"in the template")
% formatTemplate + " " + nameFileTemplate)
return None
14 years ago
if "xml_" in formatTemplate:
if objTemplNew.getError():
9 years ago
self.setError(_("Wrong template") + _(": ") +
nameFileTemplate)
9 years ago
return None
14 years ago
# Имя файла внутри xml xfce конфигурационных файлов
9 years ago
nameRootNode = \
nameFileConfig.rpartition("/")[2].split(".")[0]
objTemplNew.setNameBodyNode(nameRootNode)
# Объект Документ
docObj = objTemplNew.docObj
# Удаление комментариев из документа
docObj.removeComment(docObj.getNodeBody())
# Добавление необходимых переводов строк
docObj.insertBRtoBody(docObj.getNodeBody())
# Добавление необходимых разделителей между областями
docObj.insertBeforeSepAreas(docObj.getNodeBody())
# Пост обработка
if 'postXML' in dir(objTemplNew):
objTemplNew.postXML()
# Получение текстового файла из XML документа
14 years ago
self.textTemplate = objTemplNew.getConfig().encode("UTF-8")
# Если не UTF-8 производим преобразование
9 years ago
if objTxtCoder:
14 years ago
self.textTemplate = objTxtCoder.decode(self.textTemplate)
# Титл для объединения
if ListOptTitle:
title = self.getTitle(objTemplNew._comment,
ListOptTitle,
configPath=nameFileConfig)
title = title.encode("UTF-8")
# Замена
14 years ago
if typeAppendTemplate == "replace":
if "xml_" in formatTemplate:
14 years ago
data = self.textTemplate.split("\n")
9 years ago
data.insert(1, title)
14 years ago
self.textConfig = "\n".join(data)
else:
if objHeadNew.execStr:
9 years ago
self.textConfig = objHeadNew.execStr + title + \
14 years ago
self.textTemplate
else:
14 years ago
self.textConfig = title + self.textTemplate
9 years ago
14 years ago
self.saveConfFile()
9 years ago
if 'run' in objHeadNew.params:
if not self.executeTemplate(self.textConfig,
objHeadNew.params['run']):
9 years ago
self.setError(_("Wrong template") + _(": ") + \
nameFileTemplate)
9 years ago
self.setError(_("Failed to execute") + _(": ") + \
self.nameFileConfig)
9 years ago
return None
return None
return filesApply if not 'exec' in objHeadNew.params else None
# Вверху
14 years ago
elif typeAppendTemplate == "before":
if "xml_" in formatTemplate:
9 years ago
self.setError(
_("Wrong option append=before in template %s")
% nameFileTemplate)
return None
if objHeadOld and objHeadOld.body:
14 years ago
self.textConfig = objHeadOld.body
if self.textTemplate and self.textTemplate[-1] == "\n":
14 years ago
tmpTemplate = self.textTemplate + self.textConfig
else:
14 years ago
tmpTemplate = self.textTemplate + "\n" + self.textConfig
if execStr:
self.textConfig = execStr + title + tmpTemplate
else:
14 years ago
self.textConfig = title + tmpTemplate
14 years ago
self.saveConfFile()
9 years ago
if 'run' in objHeadNew.params:
if not self.executeTemplate(self.textConfig,
objHeadNew.params['run']):
9 years ago
self.setError(_("Wrong template") + _(": ") +
nameFileTemplate)
9 years ago
self.setError(_("Failed to execute") + _(": ") +
self.nameFileConfig)
9 years ago
return None
return None
return filesApply if 'exec' not in objHeadNew.params else None
# Внизу
14 years ago
elif typeAppendTemplate == "after":
if "xml_" in formatTemplate:
9 years ago
self.setError(
_("Wrong option append=after in template %s")
% nameFileTemplate)
return None
if objHeadOld and objHeadOld.body:
14 years ago
self.textConfig = objHeadOld.body
if self.textTemplate[-1] == "\n":
tmpTemplate = self.textConfig + self.textTemplate
else:
14 years ago
tmpTemplate = self.textConfig + "\n" + self.textTemplate
if execStr:
self.textConfig = execStr + title + tmpTemplate
else:
14 years ago
self.textConfig = title + tmpTemplate
self.saveConfFile()
9 years ago
if 'run' in objHeadNew.params:
if not self.executeTemplate(self.textConfig,
objHeadNew.params['run']):
9 years ago
self.setError(_("Wrong template") + _(": ") +
nameFileTemplate)
9 years ago
self.setError(_("Failed to execute") + _(": ") +
self.nameFileConfig)
9 years ago
return None
return None
return filesApply if 'exec' not in objHeadNew.params else None
# Объединение
14 years ago
elif typeAppendTemplate == "join":
9 years ago
objTxtCoder = None
if flagNotUtf8New:
objTxtCoder = utfBin()
14 years ago
self.textTemplate = objTxtCoder.encode(self.textTemplate)
9 years ago
if formatTemplate == "raw":
self.setError(
12 years ago
_("Incorrect header parameter append=%s "
9 years ago
"in the template")
% typeAppendTemplate + " " + nameFileTemplate)
return None
# создаем объект формата шаблона
14 years ago
objTemplNew = self.getFormatObj(formatTemplate,
14 years ago
self.textTemplate)
if not objTemplNew:
9 years ago
self.setError(
12 years ago
_("Incorrect header parameter format=%s in "
9 years ago
"the template")
% formatTemplate + " " + nameFileTemplate)
return None
14 years ago
if "xml_" in formatTemplate:
if objTemplNew.getError():
9 years ago
self.setError(_("Wrong template") + _(": ") + \
nameFileTemplate)
return None
nameRootNode = nameFileConfig.rpartition("/")[2].split(".")[
0]
objTemplNew.setNameBodyNode(nameRootNode)
# Титл для объединения
if ListOptTitle:
title = self.getTitle(objTemplNew._comment,
ListOptTitle,
configPath=nameFileConfig)
title = title.encode("UTF-8")
# В случае пустого конфигурационного файла
9 years ago
reNoClean = re.compile("[^\s]", re.M)
if not self.textConfig or \
not reNoClean.search(self.textConfig):
14 years ago
self.textConfig = ""
14 years ago
objHeadOld = fileHeader(nameFileConfig, self.textConfig,
objTemplNew._comment)
if objHeadOld.body:
14 years ago
self.textConfig = objHeadOld.body
else:
14 years ago
self.textConfig = ""
if flagNotUtf8Old:
objTxtCoder = utfBin()
14 years ago
self.textConfig = objTxtCoder.encode(self.textConfig)
# создаем объект формата шаблона для конфигурационного файла
14 years ago
objTemplOld = self.getFormatObj(formatTemplate,
14 years ago
self.textConfig)
if not objTemplOld:
9 years ago
self.setError(_("Error in template %s") % nameFileConfig)
return None
14 years ago
if "xml_" in formatTemplate:
if objTemplOld.getError():
9 years ago
self.setError(_("Wrong template") + _(": ") +
nameFileConfig)
return None
nameRootNode = nameFileConfig.rpartition("/")[2].split(".")[
0]
objTemplOld.setNameBodyNode(nameRootNode)
objTemplOld.join(objTemplNew)
14 years ago
if "xml_" in formatTemplate:
if objTemplOld.getError():
9 years ago
self.setError(_("Wrong template") + _(": ") + \
nameFileTemplate)
return None
data = objTemplOld.getConfig().encode("UTF-8").split("\n")
9 years ago
data.insert(1, title)
14 years ago
self.textConfig = "\n".join(data)
else:
if execStr:
9 years ago
self.textConfig = execStr + title + \
objTemplOld.getConfig().encode(
"UTF-8")
else:
9 years ago
self.textConfig = title + \
objTemplOld.getConfig().encode(
"UTF-8")
# Декодируем если кодировка не UTF-8
9 years ago
if objTxtCoder:
14 years ago
self.textTemplate = objTxtCoder.decode(self.textTemplate)
self.textConfig = objTxtCoder.decode(self.textConfig)
self.saveConfFile()
9 years ago
if 'run' in objHeadNew.params:
if not self.executeTemplate(self.textConfig,
objHeadNew.params['run']):
9 years ago
self.setError(_("Wrong template") + _(": ") + \
nameFileTemplate)
9 years ago
self.setError(_("Failed to execute") + _(": ") + \
self.nameFileConfig)
9 years ago
return None
return None
return filesApply if not 'exec' in objHeadNew.params else None
else:
self.setError(_("Wrong template option (type append)")
9 years ago
+ _(": ") + typeAppendTemplate)
return None
else:
12 years ago
self.setError(_("Template type not found: ") + nameFileTemplate)
9 years ago
return None
9 years ago
class scanDirectoryClt(_error):
"""Класс для cканирования директорий с файлами .clt"""
# Расширение файла шаблона
extFileTemplate = ".clt"
lenExtFileTemplate = len(extFileTemplate)
9 years ago
filterApplyTemplates = {}
reHeader = re.compile(r"\s*#\s*calculate\s*", re.I)
def printWARNING(self, s):
raise NotImplemented()
9 years ago
def __init__(self, objVar=None):
12 years ago
if objVar:
self.objVar = objVar
9 years ago
def processingFile(self, path, prefix, optFile=None):
"""Обработка в случае файла"""
return True
9 years ago
def hasBelong(self, filename):
"""
Change belong function
"""
9 years ago
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
12 years ago
def scanningTemplates(self, scanDir, prefix=None, flagDir=False,
9 years ago
objVar=None):
"""Сканирование и обработка шаблонов в директории scanDir"""
12 years ago
if not objVar:
objVar = self.objVar
if not prefix:
prefix = os.path.realpath(scanDir)
if flagDir or stat.S_ISDIR(os.lstat(str(scanDir))[stat.ST_MODE]):
for fileOrDir in sorted(listDirectory(scanDir)):
try:
absPath = os.path.join(scanDir, fileOrDir)
stInfo = os.lstat(str(absPath))
statInfo = stInfo[stat.ST_MODE]
if fileOrDir.endswith(self.extFileTemplate) and \
stat.S_ISREG(statInfo):
if (not self.filterApplyTemplates and
objVar.Get('cl_merge_set') == 'off' or
self.filterApplyTemplates and
absPath[:-self.lenExtFileTemplate] in
self.filterApplyTemplates.keys() or
self.hasBelong(absPath)):
prevDefault = objVar.defaultModule
if not self.processingFile(absPath, prefix):
return False
objVar.defaultModule = prevDefault
elif stat.S_ISDIR(statInfo):
if not self.scanningTemplates(absPath, prefix, True):
11 years ago
return False
except TemplatesError as e:
self.clearErrors()
self.printWARNING(str(e))
return True
9 years ago
class templateClt(scanDirectoryClt, Template):
"""Класс для обработки шаблонов c расширением .clt"""
def __init__(self, objVar, postmergePkgs, **kwargs):
self.checkNumberTemplate = True
9 years ago
Template.__init__(self, objVar, cltObj=False, **kwargs)
self.postmergePkgs = postmergePkgs
12 years ago
applyPackages = ["calculate-core"]
self.flagApplyTemplates = False
if self.objVar.Get("cl_name") in applyPackages:
self.flagApplyTemplates = True
# Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
self._chrootDir = os.path.normpath(self.objVar.Get("cl_chroot_path"))
14 years ago
def applyTemplate(self, path):
"""Применение отдельного .clt шаблона"""
if not self.flagApplyTemplates:
return True
14 years ago
return self.processingFile(path, "")
14 years ago
9 years ago
def processingFile(self, path, prefix, optFile=None):
"""Обработка в случае шаблона файла clt"""
self.numberProcessTempl += 1
self.numberProcessTemplates(self.numberProcessTempl)
# Пропуск шаблонов директорийscanningTemplates
if self.templDirNameFile == os.path.split(path)[1]:
return True
self.functObj.currentBelong = ""
# Проверка на переменные в названии файла
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)
# файл в системе без условий
9 years ago
nameFileConfig = "/".join(map(lambda x: x.split("?")[0],
nameFileConfig.split("/")))
# Записываем в переменную обрабатываемый файл
9 years ago
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]:
9 years ago
self._addFile(filesApl, pkg=pkg)
else:
if not self.allContents:
fillContents(self.allContents,
9 years ago
self.objVar.Get('cl_config_protect'),
prefix=self.objVar.Get('cl_chroot_path'))
for fn in filesApl:
9 years ago
fn_orig = PkgContents.reCfg.sub('/', fn)
if self.objVar.Get('cl_chroot_path') != '/':
fn_orig = \
fn_orig[len(self.objVar.Get('cl_chroot_path')):]
if fn_orig in self.allContents:
9 years ago
self._addFile([fn], pkg=self.allContents[fn_orig])
14 years ago
# Настоящее имя конфигурационного файла
nameFileConfig = filesApl[0]
# Пишем время модификации *.env файлов
14 years ago
if nameFileConfig.endswith(".env"):
nameEnvFile = os.path.basename(nameFileConfig)
self.functObj.timeConfigsIni[nameEnvFile] = float(time.time())
self.filesApply += filesApl
return nameFileConfig
else:
return True
9 years ago
def countsNumberTemplates(self, dirsTemplates=()):
"""Считаем количество шаблонов"""
9 years ago
def createDictTemplates(path, prefix, dictTemplates):
"""Создает словарь {"директория":"кол-во шаблонов" ...}
и считает общее количество шаблонов
"""
# Количество шаблонов
self.allTemplates += 1
dirTemplate = os.path.split(path)[0]
9 years ago
while True:
if dirTemplate in dictTemplates.keys():
dictTemplates[dirTemplate] += 1
else:
dictTemplates[dirTemplate] = 1
if dirTemplate == prefix:
break
dirTemplate = os.path.split(dirTemplate)[0]
return dictTemplates
if not dirsTemplates:
dirsTemplates = self.objVar.Get("cl_template_clt_path")
dirsTemplates.sort()
12 years ago
scanObj = scanDirectoryClt(objVar=self.objVar)
9 years ago
scanObj.processingFile = lambda x, y: createDictTemplates(x, y,
self.dictTemplates)
# Считаем количество шаблонов
for dirTemplate in dirsTemplates:
scanObj.scanningTemplates(dirTemplate, "/")
9 years ago
def applyTemplatesClt(self, cltPath=None):
"""Применяет шаблоны к конфигурационным файлам"""
if not self.flagApplyTemplates:
9 years ago
return [], []
if cltPath is None and \
9 years ago
not self.objVar.defined("cl_template_clt_path"):
12 years ago
self.setError(_("undefined variable: ") + "cl_template_clt_path")
return False
if cltPath is None:
dirsTemplates = self.objVar.Get("cl_template_clt_path")
else:
dirsTemplates = cltPath
dirsTemplates.sort()
if self.checkNumberTemplate:
# Созданные директории
self.createdDirs = []
# Примененные файлы
self.filesApply = []
# Номер применяемого шаблона
self.numberProcessTempl = 0
# Словарь директорий с количеством файлов шаблонов
self.dictTemplates = {}
# Количество шаблонов
self.allTemplates = 0
# Установка по умолчанию аттрибутов для функциии шаблонов ini()
# Время доступа к конфигурационному файлу функции шаблона ini()
self.functObj.timeIni = -1
# Первоначальный словарь переменных для ini()
self.functObj.prevDictIni = {}
# Текущий словарь переменных для ini()
self.functObj.currDictIni = {}
# Словарь времен модификации env файлов для ini()
self.functObj.timeConfigsIni = {}
# Считаем количество шаблонов
self.countsNumberTemplates(dirsTemplates=dirsTemplates)
self.numberAllTemplates(self.allTemplates)
12 years ago
# default module
self.defaultModule = "main"
# Обрабатываем шаблоны
for dirTemplate in dirsTemplates:
if self.scanningTemplates(dirTemplate, self._chrootDir) is False:
11 years ago
break
9 years ago
return self.createdDirs, self.filesApply
class ProgressTemplate(Template):
"""
Progress template for wsdl interface
"""
9 years ago
def __init__(self, setValueCallback, *args, **kwargs):
Template.__init__(self, *args, **kwargs)
self.setValueCallback = setValueCallback
self.value = None
12 years ago
self.firstValue = True
def numberAllTemplates(self, number):
self.maximum = number
return True
9 years ago
def numberProcessTemplates(self, number):
maximum = self.maximum or 1
9 years ago
value = number * 100 / maximum
if value != self.value:
9 years ago
self.setValueCallback(min(100, max(0, value)))
self.value = value
return True
12 years ago
11 years ago
def templateModify(self):
if self.firstValue and hasattr(self, "onFirstValue"):
12 years ago
self.onFirstValue()
self.firstValue = False
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):
9 years ago
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()