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

6909 lines
302 KiB

#-*- coding: utf-8 -*-
# Copyright 2008-2013 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from contextlib import contextmanager
import sys
import os
import stat
import re
import errno
import xml.dom.minidom as minidom
import xml
import importlib
if hasattr(xml,"use_pyxml"):
xml.use_pyxml()
from xml import xpath
import subprocess
import types
import random
import string
import time
import glob
import hashlib
14 years ago
import fcntl
from fnmatch import fnmatch
from math import sqrt
from itertools import *
from collections import OrderedDict
# < <= == != >= >
from operator import lt, le, eq, ne, ge, gt
from utils.common import _error, _warning,getTupleVersion,getPortageUidGid
from utils.text import _toUNICODE, convertStrListDict, MultiReplace
from utils.portage import (isPkgInstalled,reVerSplitToPV,EmergeLog,
EmergeLogPackageTask, getPkgUses)
from utils.content import PkgContents,checkContents,getCfgFiles,fillContents
from utils.files import (getModeFile, listDirectory,removeDir, typeFile,
scanDirectory,timeout,
pathJoin,readFile,readLinesFile,process,STDOUT)
from datavars import DataVarsError
from calculate.lib.configparser import ConfigParser, NoSectionError
from calculate.lib.cl_lang import setLocalTranslate, RegexpLocalization
setLocalTranslate('cl_lib3',sys.modules[__name__])
PORTAGEUID,PORTAGEGID = getPortageUidGid()
12 years ago
class TemplatesInterrupt(Exception):
"""
Interrupt templates appling
"""
EXIT,ABORT=1,2
def __init__(self,*args):
self.message = args[0]
self.args = args
def __str__(self):
return str(self.message)
def isExit(self): return self.isInterrupt() and self.args[1] == self.EXIT
def isAbort(self): return self.isInterrupt() and self.args[1] == self.ABORT
def status(self): return self.args[1] if self.isInterrupt() else 0
def isInterrupt(self): return len(self.args)>1
12 years ago
class TemplatesError(TemplatesInterrupt):
"""
Error on templates appling
"""
class _shareTermsFunction:
"""Общие аттрибуты для классов _terms и templateFunctions"""
# Символы допустимые в скобках функции шаблона
_reFunctionArgvInSquareBrackets = "a-zA-Z0-9_:;<>=\!\|\{\}\^\$\?\(\)\[\]\-\+\,\*\/\.\'\"~\\\\ "
_reFunctionArgvText = "[%s]"%_reFunctionArgvInSquareBrackets
# регулярное выражение для поиска функции в шаблоне
_reFunctionText = "([a-zA-Z0-9\_\-]+)\((%s+|)\)" %_reFunctionArgvText
class _terms(_error, _shareTermsFunction):
"""Вычисление условий применяемых в шаблонах
"""
# регулярное выражение для поиска функции в шаблоне
_reFunction = re.compile(_shareTermsFunction._reFunctionText)
# регулярное выражение для не версии
_re_not_Version = re.compile("[^0-9\.]")
# регулярное выражение не номер
_re_not_Number = re.compile("[^0-9]")
_suffixDict = {"pre": -2, "p": 0, "alpha": -4, "beta": -3, "rc": -1}
_lenSuffixDict = len(_suffixDict)
# Регулярное выражение для названия переменной
12 years ago
_reRightName = re.compile("^(?:[a-z\_\-]+\.)?(?:[a-zA-Z0-9\_\-]+)$")
# Регулярное выражение для сравниваемого значения
_reDenyValue = re.compile("[^0-9a-zA-Z_/\.-]")
# латинские буквы в нижнем регистре
_letters = list(string.ascii_lowercase)
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:]
suffixes.append((suffSpl,suffixVersion))
letters = ""
numberVersion = strWorkVersion
if numberVersion and numberVersion[-1:] in self._letters:
letters = numberVersion[-1:]
numberVersion = numberVersion[:-1]
return numberVersion, letters, suffixes, rVersion
def _notVersion(self, strVersion):
"""strVersion is not version - True"""
numberVersion, letters, suffixes, rVersion =\
self._splitVersion(strVersion)
if not numberVersion.strip():
return True
if self._re_not_Version.search(numberVersion):
return True
if letters and not letters in self._letters:
return True
for suffix,suffixVersion in suffixes:
if suffixVersion and self._re_not_Number.search(suffixVersion):
return True
if rVersion:
if rVersion[0] != "r" or len(rVersion) == 1:
return True
if self._re_not_Number.search(rVersion[1:]):
return True
return False
def _convertVers(self, verA, verB):
"""Конвертирование номеров версий для корректного сравнения
"""
def fillZero(elemA, elemB):
#elemA, elemB = elemA[], elemB[]
if len(elemA) > len(elemB):
maxElemB = len(elemB)-1
for i in range(len(elemA)):
if i > maxElemB:
elemB.append("0")
else:
maxElemA = len(elemA)-1
for i in range(len(elemB)):
if i > maxElemA:
elemA.append("0")
for i in range(len(elemB)):
lenA = len(elemA[i])
lenB = len(elemB[i])
if lenA == lenB:
pass
elif lenA > lenB:
res = lenA - lenB
for z in range(res):
elemB[i] = "0" + elemB[i]
elif lenB > lenA:
res = lenB - lenA
for z in range(res):
elemA[i] = "0" + elemA[i]
def fillSuffix(elemA,elemB,sA,svA,sB,svB):
if str(sA) or str(sB):
svA, svB = map(lambda x: [x] if x else ['0'], (svA, svB))
fillZero(svA, svB)
sA, sB = map(lambda x: x if x else 0, (sA, sB))
elemA.append(str(self._lenSuffixDict + sA))
elemA.extend(svA)
elemB.append(str(self._lenSuffixDict + sB))
elemB.extend(svB)
#Version, letters, suffix, suffixVersion, rVersion
vA, lA, ssA, rvA = self._splitVersion(verA)
vB, lB, ssB, rvB = self._splitVersion(verB)
elemA = vA.split(".")
elemB = vB.split(".")
fillZero(elemA, elemB)
if lA or lB:
lA, lB = map(lambda x: x if x else '0', (lA, lB))
elemA.append(lA)
elemB.append(lB)
# dereferencing suffix in suffixes list
ssA = map(lambda x:(self._suffixDict.get(x[0],0),x[1]),ssA)
ssB = map(lambda x:(self._suffixDict.get(x[0],0),x[1]),ssB)
for suffix,sufVer in reversed(ssA):
if ssB:
sB,svB = ssB.pop()
else:
sB,svB = "",""
fillSuffix(elemA,elemB,suffix,sufVer,sB,svB)
while ssB:
sB,svB = ssB.pop()
fillSuffix(elemA,elemB,"","",sB,svB)
if rvA or rvB:
rvA, rvB = map(lambda x: [x[1:]], (rvA, rvB))
fillZero(rvA, rvB)
elemA += rvA
elemB += rvB
return (".".join(elemA), ".".join(elemB))
def _equalTerm(self, term, textError, function=False):
"""Вычисление логических выражений для условий
Для корректной работы в классе который наследует этот класс
должен быть объявлен аттрибут self.objVar
(объект для работы с переменными)
function - функция для для обработки функций в заголовке блока
"""
rpl = lambda x: x.replace("@@"," ")
trm = {"&&":"@@and@@","||":"@@or@@"}
dictRuleFunc = OrderedDict((("==",eq), ("!=",ne),
(">=",ge), ("<=",le),
(">",gt), ("<",lt)))
rule = dictRuleFunc.keys()
listEqual = []
for k in trm.keys():
if k in term:
term = term.replace(k,trm[k])
trs = term.split("@@")
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:
flagRule = False
def search_rule(t, rule, prefix=""):
for sepF in rule:
if sepF in t:
vals = list(t.partition(sepF)[::2])
if vals[0].endswith("\\"):
return search_rule(vals[1], rule, prefix="%s%s%s"%(prefix,vals[0],sepF))
return (True, sepF, ["%s%s"%(prefix,vals[0]), vals[1]])
return (False, None, [])
flagRule, sepF, vals = search_rule(t, rule)
14 years ago
if flagRule:
#проверка на допустимость названия переменной
flagFunction = False
12 years ago
if not self._reRightName.search(vals[0]):
14 years ago
#проверка на допустимость функции
flagError = True
if function:
searchFunct = self._reFunction.search(vals[0])
if searchFunct:
flagError = False
flagFunction = True
if flagError:
self.setError("'%s'"%rpl(term)+" "+ _("incorrect"))
14 years ago
self.setError(textError)
return False
#проверка на допустимость значения
if self._reDenyValue.search(vals[1]):
self.setError("'%s'"%rpl(term) + " " + _("incorrect"))
self.setError(textError)
return False
14 years ago
flagIntTypeVar = None
if flagFunction:
valVars = function("#-%s-#"%vals[0])
if valVars is False:
self.setError("'%s'"%rpl(term)+" "+ _("incorrect"))
14 years ago
self.setError(textError)
return False
14 years ago
if "load" == searchFunct.group(1) and\
re.search("\(\s*num\s*,",vals[0]):
if valVars:
try:
valVars = int(valVars)
except:
self.setError("'%s'"%rpl(term) + " " + \
14 years ago
_("incorrect"))
self.setError(textError)
return False
flagIntTypeVar = True
else:
flagIntTypeVar = False
else:
14 years ago
if valVars == "" and\
not self._notVersion(vals[1]):
14 years ago
valVars = "0"
elif vals[1] == "" and\
not self._notVersion(valVars):
14 years ago
vals[1] = "0"
else:
14 years ago
try:
valVars = self.objVar.Get(vals[0])
varTable = self.objVar.Get('cl_used_action')
varTable.append((vals[0],vals[1]))
if not valVars:
valVars = ""
except DataVarsError, e:
raise TemplatesError("{header}\n{body}".format(
header=textError,body=str(e)))
14 years ago
# Номера версий для ini
flagNotIniFunct = True
# Два значения не пусты
flagNotEmptyVals = not (valVars == "" and vals[1] == "")
if flagFunction and flagNotEmptyVals and\
searchFunct.group(1) == "ini":
# Проверка значения на версию
if not self._notVersion(valVars) and\
not self._notVersion(vals[1]):
14 years ago
verFile, verVar = self._convertVers(vals[1],valVars)
res = dictRuleFunc[sepF](verVar,verFile)
14 years ago
if res:
listEqual.append(True)
else:
listEqual.append(False)
break
14 years ago
flagNotIniFunct = False
# Cравниваем номера версий
if flagNotIniFunct:
if flagNotEmptyVals and\
("_ver" in vals[0] or\
11 years ago
(flagFunction and searchFunct.group(1) in \
("pkg","merge")) or\
14 years ago
(flagFunction and searchFunct.group(1)=="load" and\
re.search("\(\s*ver\s*,",vals[0]))):
# Проверка значения на версию
if self._notVersion(vals[1]):
self.setError("'%s'"%rpl(term)+" "+\
_("incorrect"))
12 years ago
self.setError(
_("This value is not a version"))
14 years ago
return False
# Проверка значения функции на версию
if self._notVersion(valVars):
self.setError("'%s'"%rpl(term)+" "+\
_("incorrect"))
14 years ago
self.setError(\
12 years ago
_("The function value is not a version"))
return False
14 years ago
verFile, verVar = self._convertVers(vals[1],valVars)
res = dictRuleFunc[sepF](verVar,verFile)
if res:
listEqual.append(True)
else:
listEqual.append(False)
break
14 years ago
flagNotIniFunct = False
else:
14 years ago
if flagIntTypeVar is None:
flagIntTypeVar = True
try:
valVars = int(valVars)
except:
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
14 years ago
except:
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:
self.setError("'%s'"%rpl(term) + " "\
14 years ago
+ _("incorrect"))
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:
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):
'''Split params line'''
def splitQuote(listPar, quoteSymbol):
listTerm = map(lambda x: x+quoteSymbol, ("=",">","<"))
flagQ = False
mass = []
v = ""
for i in listPar:
if i.count(quoteSymbol)==1:
if flagQ and i.endswith(quoteSymbol):
v = v + " " + i
mass.append(v)
v = ""
flagQ = False
elif filter(lambda x: x in i, listTerm):
flagQ = True
v = i
else:
mass.append(i)
elif flagQ:
v = v + " " + i
else:
mass.append(i)
foundPar = list(set(mass)-set(listPar))
return not flagQ, filter(lambda x: not x in foundPar, mass),foundPar
listPar = re.split("\s+",linePar)
flagFoundQ = "'" in linePar
flagFoundQQ = '"' in linePar
if flagFoundQ and flagFoundQQ:
flagQ, listSplQPar, listFoundQPar = splitQuote(listPar, "'")
if flagQ:
flagQQ, listSplQQPar, listFoundQQPar = splitQuote(listSplQPar,
'"')
if flagQQ:
listPar = listSplQQPar + listFoundQPar + listFoundQQPar
elif flagFoundQQ:
flagQQ, listSplQQPar, listFoundQQPar = splitQuote(listPar, '"')
if flagQQ:
listPar = listSplQQPar + listFoundQQPar
elif flagFoundQ:
flagQ, listSplQPar, listFoundQPar = splitQuote(listPar, "'")
if flagQ:
listPar = listSplQPar + listFoundQPar
if flagFoundQ:
listQPar = []
for par in listPar:
if par.endswith("'") and par.count("'")>1:
listQPar.append(par[:-1].replace("='","="))
else:
listQPar.append(par)
listPar = listQPar
if flagFoundQQ:
listQQPar = []
for par in listPar:
if par.endswith('"') and par.count('"')>1:
listQQPar.append(par[:-1].replace('="','='))
else:
listQQPar.append(par)
listPar = listQQPar
return listPar
class fileHeader(_terms):
"""Обработка заголовков шаблонов и конфигурационных файлов
"""
# Допустимые параметры заголовка
allowParam = ["format","dotall","multiline",
"comment", "append", "force","dconfpath",
"link", "mirror", "symbolic", "chmod", "chown", "name",
"path", "autoupdate","protected", "run","exec","merge",
"module","env","postmerge"]
# Тип шаблона
fileType = ""
# Тип вставки шаблона
typeAppend = ""
# Возможные типы вставки шаблонов
_fileAppend = "join", "before", "after", "replace", "remove", "skip",\
"patch", "clear"
# Интерпретатор (#!/bin/bash) (#!/usr/bin/python)
execStr = ""
# Символ комментария
comment = False
# Выражение для поиска строки интерпретатора
reExecStr = re.compile("^(#!.+\s)",re.M)
# условные операторы
terms = ('>', '<', '==', '!=', '>=', '<=')
# параметры без значения
listParNotVal = ("multiline", "dotall", "symbolic", "force", "mirror",
"autoupdate", "protected")
# Результат вычисления условия в заголовке
headerTerm = True
14 years ago
def __init__(self, templateName, text, comment=False, fileType=False,
objVar=False, function=False, templateObj=None):
self.body = text
# Объект с переменными
self.objVar=objVar
# Параметры описанные в заголовке файла шаблона
self.params = {}
# некорректные параметры
incorrectParams = []
14 years ago
# Поиск строки запустка (#!/bin/bash и.т. д)
if comment or fileType!="bin":
14 years ago
reExecRes = self.reExecStr.search(self.body)
if reExecRes:
self.execStr = self.body[reExecRes.start():reExecRes.end()]
self.body = self.body[:reExecRes.start()] +\
self.body[reExecRes.end():]
# Удаление Заголовка Calculate
if comment:
titleFirst = "Modified"
# В случае текста XML
if type(comment) == types.TupleType and len(comment) == 2:
reCalcHeader =\
re.compile("\s*%s\s+%s.+\s+(.+\n)+%s\s?"\
%(comment[0], titleFirst, comment[1]),re.M|re.I)
reS = reCalcHeader.search(self.body)
if reS:
self.body = self.body[:reS.start()]+self.body[reS.end():]
else:
reCalcHeader = re.compile(\
"\s*%s\-+\s+%s\s+%s.+\s+(%s.+\s+)+%s\-+\s?"\
%(comment, comment, titleFirst ,comment,comment),
re.M|re.I)
reS = reCalcHeader.search(self.body)
if reS:
self.body = self.body[reS.end():]
if fileType != False:
if fileType=="bin":
self.params["format"] = fileType
self.fileType = self._getType()
self.typeAppend = self._getAppend()
else:
textLines = self.body.splitlines()
if textLines:
textLine = textLines[0]
rePar = re.compile(\
"\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$", re.I)
reP = rePar.search(textLine)
if reP:
reL = False
reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
reLs = reLns.search(self.body)
if reLs:
reL = reLs
paramLine = self.body[reP.end():reLs.end()]
paramLine = paramLine.replace("\\"," ")
else:
reLn = re.compile("\n")
reL = reLn.search(self.body)
paramLine = textLine[reP.end():]
if reL:
self.body = self.body[reL.end():]
else:
self.body = ""
paramLine = templateObj.applyFuncTemplate(paramLine,templateName)
paramList = self.splitParLine(paramLine)
if paramList:
for i in paramList:
foundTerm = False
for term in self.terms:
if term in i:
foundTerm = True
14 years ago
errorMsg = _("Incorrect template") +\
_(": ") + templateName +"\n"+\
12 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():
incorrectParams = set([i])
elif len(par) == 2:
self.params[par[0]] = par[1]
if par[0] == "env":
try:
varModule = \
importlib.import_module(
"calculate.%s.variables"
%par[1])
except (ImportError,
AttributeError),e:
self.headerTerm = False
self.comment = self._getComment()
self.fileType = self._getType()
14 years ago
typeAppend = self._getAppend()
if typeAppend:
self.typeAppend = typeAppend
else:
self.headerTerm = False
self.setError(_("incorrect header parameter: '%s'")\
%"append=%s"%self.params["append"])
if any(x in self.params for x in ('exec','run')):
if 'exec' in self.params:
self.execStr = "#!%s\n"%self.params['exec']
if 'run' in self.params:
self.execStr = "#!%s\n"%self.params['run']
if "python" in self.execStr:
self.execStr += "# -*- coding: utf-8 -*-\n"
if not incorrectParams and self.params:
incorrectParams = set(self.params.keys()) - set(self.allowParam)
if incorrectParams:
self.headerTerm = False
self.setError(_("incorrect header parameter: '%s'")\
14 years ago
%" ".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:
if self.fileType != "raw" and self.fileType != "bin" and\
self.fileType != "":
11 years ago
if "format" in self.params and self.params["format"] in \
("patch","diff", "dconf"):
self.params["append"] = "patch"
return "patch"
self.params["append"] = "join"
return "join"
self.params["append"] = "replace"
return "replace"
def _getComment(self):
"""Выдать символ комментария файла"""
if self.params.has_key("comment"):
if self.params["comment"] in ("xml", "XML"):
return ("<!--","-->")
else:
return self.params["comment"]
else:
return False
class dirHeader(_terms):
"""Обработка заголовков шаблонов директорий
"""
# Допустимые параметры заголовка
12 years ago
allowParam = ["append", "chmod", "chown", "name", "path", "autoupdate",
"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
14 years ago
def __init__(self, templateName, text, objVar=False, function=False):
self.body = text
# Объект с переменными
self.objVar=objVar
# Параметры описанные в заголовке файла шаблона
self.params = {}
# некорректные параметры
incorrectParams = set([])
textLines = text.splitlines()
flagErrorBody = False
if textLines:
textLine = textLines[0]
rePar = re.compile(\
"\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$",re.I)
reP = rePar.search(textLine)
if reP:
reL = False
reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
reLs = reLns.search(text)
if reLs:
reL = reLs
paramLine = text[reP.end():reLs.end()]
paramLine = paramLine.replace("\\"," ")
else:
reLn = re.compile("\n")
reL = reLn.search(text)
paramLine = textLine[reP.end():]
if reL:
self.body = text[reL.end():]
else:
self.body = ""
if self.body.strip():
self.headerTerm = False
self.setError(_("incorrect text in the template: '%s'")\
14 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") +
_(": ") + 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():
incorrectParams = set([i])
elif len(par) == 2:
self.params[par[0]] = par[1]
if par[0] == "env":
try:
varModule = \
importlib.import_module(
"calculate.%s.variables"%par[1])
except (ImportError,AttributeError),e:
self.headerTerm = False
12 years ago
self.objVar.defaultModule = \
self.params['env']
typeAppend = self._getAppend()
if typeAppend:
self.typeAppend = typeAppend
else:
self.headerTerm = False
self.setError(_("incorrect header parameter: '%s'")\
%"append=%s"%self.params["append"])
if not flagErrorBody:
if not incorrectParams:
incorrectParams = set(self.params.keys()) - set(self.allowParam)
if incorrectParams:
self.headerTerm = False
self.setError(_("incorrect header parameter: '%s'")\
14 years ago
%" ".join(list(incorrectParams)))
def _getAppend(self):
"""Выдать тип добавления директории"""
if self.params.has_key("append"):
if self.params["append"] in self._fileAppend:
return self.params["append"]
else:
return False
else:
return "join"
class objShare:
"""Общий клас для объектов, наследуем
"""
def createFieldTerm(self, name, value, quote, docObj):
"""Создание поля переменная - значение
при создании поля проверяется первый символ названия переменной
и добавляется тег action
"!" - <action>drop</action> удаляет
"+" - <action>join</action> добавляет
"-" - <action>replace</action> заменяет
"""
fieldAction = False
if name:
if name[0] == "!" or name[0] == "-" or name[0] == "+":
qnt = self.removeSymbolTerm(quote)
fieldXML = docObj.createField("var",[qnt],
name[1:], [value],
False, False)
if name[0] == "!":
fieldAction = "drop"
elif name[0] == "+":
fieldXML.setAttribute("type", "seplist")
fieldAction = "join"
else:
fieldXML = docObj.createField("var",
[quote.replace("\n","")],
name, [value],
False, False)
else:
fieldXML = docObj.createField("var",
[quote.replace("\n","")],
name, [value],
False, False)
if fieldAction:
docObj.setActionField(fieldXML, fieldAction)
return fieldXML
def removeSymbolTerm(self, text):
"""Удаляет первый символ названия переменной в строке
Если первый встречающийся символ с начала строки
'+', '-', '!' то он из этой строки будет удален,
если перед этим символом были пробельные символы,
то они будут сохранены, так-же если в строке есть символ
перевода строки он будет удален.
"""
reTerm = re.compile("^[ \t]*(\!|\+|\-)")
textNS = text.replace("\n","")
res = reTerm.search(textNS)
if res:
textNS = textNS[res.start():res.end()-1] + textNS[res.end():]
return textNS
12 years ago
def getConfig(self,joinChar=""):
"""Выдает конфигурационный файл"""
listConfigTxt = []
childNodes = self.docObj.getNodeBody().childNodes
for node in childNodes:
if node.nodeType == node.ELEMENT_NODE:
if node.tagName == "field":
listConfigTxt.append(self.docObj.getQuoteField(node))
elif node.tagName == "area":
self.docObj.xmlToText([node], listConfigTxt)
12 years ago
return joinChar.join(listConfigTxt)
def splitToFields(self, txtBloc):
"""Разбиваем текст на поля (объекты) которые имеют следующие аттрибуты
self.name - если переменная то имя переменной
self.value - если у переменной есть значение то значение переменной
self.comment - если комментарий то текст комментария
self.br - если перевод строки то текст перед переводом из пробелов
Результат список объектов полей
"""
finBloc = "\n"
if txtBloc[-1] != "\n":
finBloc = ""
linesBlocTmp = txtBloc.splitlines()
linesBloc = []
brBloc = []
z = 0
lenLines = len(linesBlocTmp)
for i in linesBlocTmp:
if self.reComment.split(i)[0]:
findCooment = self.reComment.search(i)
comment = False
par = i
if findCooment:
par = i[:findCooment.start()]
comment = i[findCooment.start():]
fields = self.reSepFields.split(par)
lenFields = len(fields)
if lenFields>1:
for fi in range(lenFields-1):
linesBloc.append(fields[fi]+ self.sepFields)
if fi == lenFields-2:
if comment:
brBloc.append("")
else:
if (lenLines-1)== z:
brBloc.append(finBloc)
else:
brBloc.append("\n")
else:
brBloc.append("")
if comment:
linesBloc.append(comment)
if (lenLines-1)== z:
brBloc.append(finBloc)
else:
brBloc.append("\n")
else:
linesBloc.append(i)
if (lenLines-1)== z:
brBloc.append(finBloc)
else:
brBloc.append("\n")
else:
linesBloc.append(i)
if (lenLines-1)== z:
brBloc.append(finBloc)
else:
brBloc.append("\n")
z +=1
fields = self.setDataField(linesBloc, brBloc)
return fields
class xmlShare:
"""Общий класс для объектов XML, наследуем
"""
def _createElement(self, doc, tagName, text="", attributes={}):
"""Создание нового XML элемента"""
element = doc.createElement(tagName)
if text:
txtNode = doc.createTextNode(_toUNICODE(text))
element.appendChild(txtNode)
for attr in attributes.keys():
attribute = doc.createAttribute(attr)
attribute.nodeValue = attributes[attr]
element.setAttributeNode(attribute)
return element
class xmlNode(xmlShare):
"""Класс для создания нод без аттрибутов
"""
def __init__(self):
self.node = False
def createNode(self, doc, tagName, text=""):
"""Создает XML элемент без аттрибутов"""
self.node=self._createElement(doc, tagName, text)
return self.node
def getNode(self):
return self.node
class xmlCaption:
"""Класс XML заголовок
"""
def __init__(self):
#Заголовок области XML нода
self.caption = False
def createCaption(self, doc, name, quotes, action=False):
"""Создание заголовка области"""
tmpNode = xmlNode()
self.caption = tmpNode.createNode(doc, "caption")
nameNode = tmpNode.createNode(doc, "name",name)
self.caption.appendChild(nameNode)
if action:
actNode = tmpNode.createNode(doc, "action", action)
self.caption.appendChild(actNode)
for q in quotes:
quoteNode = tmpNode.createNode(doc, "quote", q)
self.caption.appendChild(quoteNode)
return self.caption
def getCaption(self):
"""Выдает XML ноду заголовка области"""
return self.caption
class xmlField(xmlShare):
"""Класс для работы с XML полем
"""
def __init__(self):
# XML нода поле
self.field = False
def createField(self, doc, typeField, quotes, name="",
values=[],action=False):
"""Cоздание XML ноды поле"""
self.field = self._createElement(doc, "field", "", {"type":typeField})
if name:
nameNode = self._createElement(doc, "name", name)
self.field.appendChild(nameNode)
for v in values:
valueNode = self._createElement(doc, "value", v)
self.field.appendChild(valueNode)
if action:
actNode = self._createElement(doc, "action", action)
self.field.appendChild(actNode)
for q in quotes:
quoteNode = self._createElement(doc, "quote", q)
self.field.appendChild(quoteNode)
return self.field
class xmlFields:
"""Класс, в котором находится список ХМL нод field
"""
def __init__(self):
self.fields = []
def appendField(self, field):
"""Добавить XML ноду field"""
self.fields.append(field)
return self.fields
def getFields(self):
"""Выдать список XML нод"""
return self.fields
class xmlArea:
"""Класс для работы с XML областью
"""
def __init__(self):
# Область
self.area = False
def createArea(self, doc, xmlCaption, xmlFields):
"""Создание XML области"""
tmpNode = xmlNode()
self.area = tmpNode.createNode(doc, "area")
if xmlCaption and xmlCaption.getCaption():
self.area.appendChild(xmlCaption.getCaption())
if xmlFields:
fields = xmlFields.getFields()
for field in fields:
self.area.appendChild(field)
return self.area
class xmlDoc:
"""Класс для работы с XML документом
"""
def __init__(self):
# документ
self.doc = False
# главная нода
self.root = False
# тело документа
self.body = False
# Заголовок области - временный (в реальности один объект заголовок)
self.tmpCaption = False
# Поля - временные (в реальности один объект поля)
self.tmpFields = False
# Разделитель областей - по умолчанию перевод строки "\n"
self.sepAreas = False
# Разделитель разделенных списков - по умолчанию перевод строки "\n"
#self.sepSplitFields = False
def createDoc(self, typeDoc, version):
"""Создание нового документа новый документ"""
docTxt = '<?xml version="1.0" encoding="UTF-8"?><cxmlconf><head>'
docTxt += '<ver>%s</ver>'% version
docTxt += '<format>%s</format>' % typeDoc
docTxt += '</head><body></body></cxmlconf>'
self.doc = minidom.parseString(docTxt)
self.root = self.doc.documentElement
self.body = xpath.Evaluate('child::body',self.root)[0]
# установка разделителя областей
self.sepAreas = self.createField("br",[],"",[],False,False)
# установка разделителя областей разделенных списков
#self.sepSplitFields = self.createField("br",[],"",[],False,False)
return self.doc
def addField(self, field):
"""Добавляет поле во временный список
Из этого списка в дальнейшем формируется XML область
"""
if not self.tmpFields:
self.tmpFields = xmlFields()
self.tmpFields.appendField(field)
def createCaption(self, name, quotes, action=False):
"""Cоздает заголовок области
Помещает заголовок в временный артибут
Используется при создании области
"""
self.tmpCaption = xmlCaption()
return self.tmpCaption.createCaption(self.doc, name, quotes, action)
def createField(self, typeField, quotes=[], name="",
values=[] ,action=False,addTmpField=True):
"""Cоздает поле
Если установлена переменнная addTmpField
добавляет поле во временный список
"""
fieldObj = xmlField()
field = fieldObj.createField(self.doc, typeField, quotes, name,
values, action)
if addTmpField:
self.addField(field)
return field
def clearTmpFields(self):
"""Очищает временный список"""
self.tmpFields = False
def createArea(self):
"""Cоздает область
Область создается на основании временного атрибута и временного списка
"""
areaObj = xmlArea()
area = areaObj.createArea(self.doc, self.tmpCaption, self.tmpFields)
self.clearTmpCaptionAndFields()
return area
def clearTmpCaptionAndFields(self):
"""Очищает временный аттрибут и временный список"""
self.tmpCaption = False
self.tmpFields = False
def getNodeRoot(self):
"""Выдает корневую ноду"""
return self.root
def getNodeBody(self):
"""Выдает ноду body"""
return self.body
def setActionField(self, xmlField, actionTxt):
"""Устанавливает свойство action для XML поля"""
xmlActions = xpath.Evaluate('child::action',xmlField)
if xmlActions and xmlActions[0].firstChild:
xmlActions[0].firstChild.nodeValue = actionTxt
else:
nodeObj = xmlNode()
newNode = nodeObj.createNode(self.doc, "action", actionTxt)
xmlField.appendChild(newNode)
def setActionArea(self, xmlArea, actionTxt):
"""Устанавливает свойство action для XML области"""
xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
xmlCaptions = xpath.Evaluate('child::caption',xmlArea)
if xmlActions and xmlActions[0].firstChild:
xmlActions[0].firstChild.nodeValue = actionTxt
else:
if xmlCaptions:
nodeObj = xmlNode()
newNode = nodeObj.createNode(self.doc, "action", actionTxt)
xmlCaptions[0].appendChild(newNode)
def joinField(self, xmlArea, xmlNewField):
"""Объединяет XML ноду область и XML ноду поле"""
newNameField = self.getNameField(xmlNewField)
if not newNameField or not newNameField.strip():
return False
fieldsOldComp = xpath.Evaluate("child::field[child::name='%s']"\
%(newNameField), xmlArea)
# Если поле не найдено добавляем его
typeNewField = self.getTypeField(xmlNewField)
if not fieldsOldComp and typeNewField != "seplist":
if self.getActionField(xmlNewField) != "drop":
self.setActionField(xmlNewField, "append")
xmlArea.appendChild(xmlNewField)
return True
newFieldsAction = self.getActionField(xmlNewField)
newValues = self.getFieldValues(xmlNewField)
flagCompare = True
for nodeFieldOld in fieldsOldComp:
if newFieldsAction == "drop":
if nodeFieldOld.nextSibling and\
self.getTypeField(nodeFieldOld.nextSibling) == "br":
xmlArea.removeChild(nodeFieldOld.nextSibling)
elif nodeFieldOld.previousSibling and\
self.getTypeField(nodeFieldOld.previousSibling) == "br":
xmlArea.removeChild(nodeFieldOld.previousSibling)
xmlArea.removeChild(nodeFieldOld)
continue
oldValues = self.getFieldValues(nodeFieldOld)
# Сравнение значений переменной шаблона и файла
if set(newValues) != set(oldValues):
flagCompare = False
if self.getActionField(xmlNewField) == "drop":
return True
appSplLst = []
insSplLst = []
if typeNewField == "seplist":
if fieldsOldComp:
xmlOldField = fieldsOldComp[-1]
else:
xmlOldField = False
seplistNewXML = self.getSepListToField(xmlNewField)
if seplistNewXML:
for nodeSeplist in seplistNewXML:
if self.getActionField(nodeSeplist) != "drop":
if newFieldsAction == "join":
flagCompareSeplist = False
newValues = self.getFieldValues(nodeSeplist)
for nodeFieldOld in fieldsOldComp:
oldValues = self.getFieldValues(nodeFieldOld)
for newValue in newValues:
if newValue in oldValues:
flagCompareSeplist = True
break
if not flagCompareSeplist:
nextNode = xmlOldField.nextSibling
newInsNode = nodeSeplist.cloneNode(True)
self.setActionField(newInsNode,"append")
if nextNode:
appSplLst.append((newInsNode,
nextNode,
"insert"))
else:
appSplLst.append((newInsNode,
False,
"append"))
else:
newInsNode = nodeSeplist.cloneNode(True)
if self.getActionField(newInsNode) == "join":
self.setActionField(newInsNode,"append")
if xmlOldField:
insSplLst.append((newInsNode,
xmlOldField,
"insert"))
else:
insSplLst.append((newInsNode,
False,
"append"))
#xmlArea.insertBefore(\
#nodeSeplist.cloneNode(True),
#xmlOldField)
parentNode = nodeSeplist.parentNode
parentNode.removeChild(nodeSeplist)
insNodesRepl = []
for newNode, nxtNode, app in insSplLst:
flagCompareSeplist = False
newValues = self.getFieldValues(newNode)
for nodeRepl, nxtNode, app in insNodesRepl:
oldValues = self.getFieldValues(nodeRepl)
for newValue in newValues:
if newValue in oldValues:
flagCompareSeplist = True
break
if not flagCompareSeplist:
if xmlOldField:
insNodesRepl.append((newNode, nxtNode, app))
for newNode, nxtNode, app in insNodesRepl:
if app == "insert":
xmlArea.insertBefore(newNode,nxtNode)
elif app == "append":
xmlArea.appendChild(newNode)
if xmlOldField:
parentNode = xmlOldField.parentNode
if parentNode and newFieldsAction != "join":
parentNode.removeChild(xmlOldField)
for newNode, nxtNode, app in appSplLst:
if app == "insert":
xmlArea.insertBefore(newNode,nxtNode)
elif app == "append":
xmlArea.appendChild(newNode)
if not flagCompare and typeNewField != "seplist":
# Устанавливаем action=replace
self.setActionField(xmlNewField, "replace")
# Если параметры поля не сходятся заменяем поле
xmlArea.replaceChild(xmlNewField.cloneNode(True),
fieldsOldComp[-1])
if newFieldsAction == "join":
fieldsOldRemove = []
else:
fieldsOldRemove = fieldsOldComp[:-1]
for nodeFieldOld in fieldsOldRemove:
actionOldNode = self.getActionField(nodeFieldOld)
if actionOldNode == "insert" or actionOldNode == "append":
pass
else:
if nodeFieldOld.nextSibling and\
self.getTypeField(nodeFieldOld.nextSibling) == "br":
xmlArea.removeChild(nodeFieldOld.nextSibling)
xmlArea.removeChild(nodeFieldOld)
return True
def getSepListToField(self, xmlField):
"""Выдает элементы распределенного массива
Область предок поля, в этой области ищутся
элементы распределенного массива
"""
nameField = self.getNameField(xmlField)
if not nameField:
return []
parentNode = xmlField.parentNode
if parentNode:
fieldsVal = xpath.Evaluate(\
"child::field[attribute::type='seplist'][child::name='%s'] "\
%(nameField), parentNode)
return fieldsVal
else:
return []
def removeComment(self, xmlArea):
"""Удаляет комментарии в XML области"""
fieldNodes = xpath.Evaluate('descendant::field',xmlArea)
for fieldNode in fieldNodes:
if fieldNode.hasAttribute("type"):
if fieldNode.getAttribute("type") == "comment" or\
fieldNode.getAttribute("type") == "br":
parentNode = fieldNode.parentNode
parentNode.removeChild(fieldNode)
else:
if self.getActionField(fieldNode) == "drop":
pass
elif self.getActionField(fieldNode) == "join":
pass
else:
self.setActionField(fieldNode,"append")
def joinBody(self, baseBody, newBody):
"""Объединяет две области Body"""
newFields = xpath.Evaluate('child::field',newBody)
xmlNewAreas = xpath.Evaluate('child::area',newBody)
for xmlNewArea in xmlNewAreas:
self.joinArea(baseBody,xmlNewArea)
joinNewFields = xpath.Evaluate("child::field[child::action='join']"
,newBody)
self.addNewFielsOldArea(newFields, joinNewFields, baseBody)
def getRemoveNodeSepList(self, removeNodesDict, baseNode, xmNewlField):
"""Находит элементы разделенного списка
Параметры:
removeNodesDict - оварь удаляемых полей разделенного списка
формируется программой
baseNode - Нода в которой идет поиск
xmNewlField - Нода field которая проверяется на принадлежность
к разделенному списку
"""
flagNewNodeSeplist = False
if self.getTypeField(xmNewlField) == "seplist":
flagNewNodeSeplist = True
nameNewField = self.getNameField(xmNewlField)
if nameNewField:
if removeNodesDict.has_key(nameNewField):
return removeNodesDict[nameNewField]
else:
oldFields = xpath.Evaluate('child::field', baseNode)
removeNodes = []
lenOldFields = len(oldFields)
for i in range(lenOldFields):
oldNode = oldFields[i]
flagSep = self.getTypeField(oldNode) == "seplist"
if flagNewNodeSeplist:
flagSep = True
if flagSep and\
nameNewField == self.getNameField(oldNode):
removeNodes.append(oldNode)
if i+1<lenOldFields:
nextNode = oldFields[i+1]
if self.getTypeField(nextNode) == "br":
removeNodes.append(nextNode)
removeNodesDict[nameNewField] = removeNodes
return removeNodes
def addNewFielsOldArea(self, newFields, joinNewFields, xmlOldArea):
"""Добавляет новые XML поля в область шаблона"""
removeNodesDict = {}
notRemoveNodesDict = {}
for notRemNode in joinNewFields:
nameField = self.getNameField(notRemNode)
if not notRemoveNodesDict.has_key(nameField):
notRemoveNodesDict[nameField] = []
notRemoveNodesDict[nameField].append(notRemNode)
else:
notRemoveNodesDict[nameField].append(notRemNode)
notSepListField = []
sepListField = []
for nField in newFields:
if self.getRemoveNodeSepList(removeNodesDict, xmlOldArea,
nField):
sepListField.append(nField)
else:
if self.getNameField(nField):
notSepListField.append(nField)
for name in notRemoveNodesDict.keys():
if removeNodesDict.has_key(name):
removeNodesDict[name] = []
for removeNodes in removeNodesDict.values():
if removeNodes:
if self.getTypeField(removeNodes[-1]) == "seplist":
removeNodes = removeNodes[:-1]
else:
removeNodes = removeNodes[:-2]
for removeNode in removeNodes:
xmlOldArea.removeChild(removeNode)
for node in sepListField:
node.setAttribute("type", "seplist")
if not (self.getActionField(node) == "join" or\
self.getActionField(node) == "drop"):
self.setActionField(node,"insert")
self.joinField(xmlOldArea, node)
for node in notSepListField:
if self.getTypeField(node) == "seplist":
self.setActionField(node, "append")
xmlOldArea.appendChild(node)
else:
self.joinField(xmlOldArea, node)
def insertBeforeSepAreas(self, xmlArea):
"""Добавляет разделитель областей перед каждой областью"""
if not self.sepAreas:
return False
areaNodes = xpath.Evaluate('descendant::area',xmlArea)
for areaNode in areaNodes:
prevNode = areaNode.previousSibling
if prevNode:
parentNode = areaNode.parentNode
parentNode.insertBefore(self.sepAreas.cloneNode(True),
areaNode)
return True
12 years ago
def getAreaFields(self, nameArea, xmlArea, allVars=False):
"""По имени области выводит названия и значения всех переменных
поиск ведется только в 1-х потомках области xmlArea
на выход словарь переменных {имя:значение}
"""
12 years ago
namesAreaCompareAll = xpath.Evaluate(\
"child::area/child::caption[child::name='%s']" %(nameArea),
xmlArea)
12 years ago
if not namesAreaCompareAll:
return False
dictVar = {}
12 years ago
for namesAreaCompare in namesAreaCompareAll:
fields = xpath.Evaluate("child::field/child::name",
namesAreaCompare.parentNode)
for fieldName in fields:
nodeField = fieldName.parentNode
fieldValue = xpath.Evaluate("child::value",nodeField)
name = fieldName.firstChild.nodeValue
value = ""
if fieldValue and fieldValue[0].firstChild:
value = fieldValue[0].firstChild.nodeValue
dictVar[name] = value
if not allVars:
break
return dictVar
def getAreaFieldValues(self, nameArea, nameField, xmlArea):
"""По имени области и имени переменной выводит значениe переменной
поиск ведется только в 1-х потомках области xmlArea
"""
namesAreaComare = xpath.Evaluate(\
"child::area/child::caption[child::name='%s']" %(nameArea),
xmlArea)
fieldsVal = False
for areaComp in namesAreaComare:
fieldsVal = xpath.Evaluate(\
"child::field[child::name='%s'] "\
%(nameField), areaComp.parentNode)
if fieldsVal:
break
if not fieldsVal:
return False
fieldValue = xpath.Evaluate("child::value",
fieldsVal[0])
14 years ago
if not fieldValue:
return False
14 years ago
if fieldValue[0].firstChild:
14 years ago
return fieldValue[0].firstChild.nodeValue
else:
14 years ago
return ""
def getAllAreas(self):
"""Выдает все области"""
return xpath.Evaluate('descendant::area', self.body)
def getArea(self, nameArea, xmlArea):
"""По имени области находит области (первый потомок xmlArea)"""
namesAreaComare = xpath.Evaluate(\
"child::area/child::caption[child::name='%s']" %(nameArea),
xmlArea)
return map(lambda x: x.parentNode, namesAreaComare)
def joinArea(self, baseNode, xmlNewArea):
"""Объединяет область c областью Body (xmlNewArea c baseNode)"""
def appendArea(baseNode, xmlNewArea):
fieldsRemove = xpath.Evaluate(\
"descendant::field[child::action='drop']", xmlNewArea)
for rmNode in fieldsRemove:
parentNode = rmNode.parentNode
parentNode.removeChild(rmNode)
captionAreasRemove = xpath.Evaluate(\
"descendant::area/child::caption[child::action='drop']",
xmlNewArea)
for rmNodeCapt in captionAreasRemove:
rmNode = rmNodeCapt.parentNode
parentNode = rmNode.parentNode
parentNode.removeChild(rmNode)
self.setActionArea(xmlNewArea, "append")
# Добавляем разделитель областей во вложенные области
areaNodes = xpath.Evaluate('descendant::area',xmlNewArea)
for areaNode in areaNodes:
self.setActionArea(areaNode,"append")
parentNode = areaNode.parentNode
parentNode.insertBefore(self.sepAreas.cloneNode(True),
areaNode)
baseNode.appendChild(xmlNewArea)
# Добавляем разделитель областей
baseNode.insertBefore(self.sepAreas.cloneNode(True), xmlNewArea)
nodesNames = xpath.Evaluate('child::area/caption/name',baseNode)
nodesNewArea = xpath.Evaluate('child::caption/name',xmlNewArea)
if not nodesNames:
# Добавляем область
if nodesNewArea:
newAreaAction = self.getActionArea(xmlNewArea)
if not (newAreaAction == "drop" or newAreaAction == "replace"):
appendArea(baseNode, xmlNewArea)
return True
if not nodesNames or not nodesNewArea:
return False
nameArea = ""
if nodesNewArea[0].firstChild:
nameArea = nodesNewArea[0].firstChild.nodeValue.strip()
flagFindArea = False
baseNodes = []
for oName in nodesNames:
newAreaAction = self.getActionArea(xmlNewArea)
oArea = oName.parentNode.parentNode
oNameTxt = ""
if oName.firstChild:
oNameTxt = oName.firstChild.nodeValue
if nameArea == oNameTxt:
flagFindArea = True
# При использовании удаления
if newAreaAction == "drop":
prevNode = oName.parentNode.parentNode.previousSibling
removePrevNodes = []
while (prevNode) and self.getTypeField(prevNode) == "br":
removePrevNodes.append(prevNode)
prevNode = prevNode.previousSibling
for removeNode in removePrevNodes:
baseNode.removeChild(removeNode)
baseNode.removeChild(oName.parentNode.parentNode)
continue
elif newAreaAction == "replace":
oldAreaNode = oName.parentNode.parentNode
newAreaCaption = xpath.Evaluate('child::caption',
xmlNewArea)[0]
oldAreaCaption = xpath.Evaluate('child::caption',
oldAreaNode)[0]
if newAreaCaption and oldAreaCaption:
xmlNewArea.replaceChild(oldAreaCaption,newAreaCaption)
self.setActionArea(xmlNewArea,"replace")
baseNode.replaceChild(xmlNewArea,
oldAreaNode)
continue
baseNodes.append(oName.parentNode.parentNode)
newFields = xpath.Evaluate('child::field',xmlNewArea)
joinNewFields = xpath.Evaluate(\
"child::field[child::action='join']"
,xmlNewArea)
self.addNewFielsOldArea(newFields, joinNewFields, oArea)
if not flagFindArea:
# Добавляем область
if not (newAreaAction == "drop" or\
newAreaAction == "replace"):
appendArea(baseNode, xmlNewArea)
else:
tmpXmlNewAreas = xpath.Evaluate('child::area',xmlNewArea)
for na in tmpXmlNewAreas:
for bn in baseNodes:
self.joinArea(bn, na)
return True
def joinDoc(self, xmlNewDoc):
"""Объединяет два документа"""
newRootNode = xmlNewDoc.documentElement
newBodyNode = xpath.Evaluate('child::body',newRootNode)[0]
newImportBodyNode = self.doc.importNode(newBodyNode, True)
# Перед объединение области с документом
# удаляем комментарии
self.removeComment(newImportBodyNode)
self.joinBody(self.body, newImportBodyNode)
# расставляем BR
self.insertBRtoBody(self.body)
def getQuoteField(self, xmlField):
"""Выдает текст из поля"""
xmlQuotes = xpath.Evaluate('child::quote',xmlField)
br = ""
if xmlField.hasAttribute("type") and\
xmlField.getAttribute("type") == "br":
br = "\n"
if xmlQuotes:
field = xmlQuotes[0]
if field.firstChild:
return field.firstChild.nodeValue + br
return "" + br
def getFieldsArea(self, xmlArea):
"""Выдает потомков XML области"""
xmlFields = []
childNodes = xmlArea.childNodes
for node in childNodes:
if node.nodeType == node.ELEMENT_NODE:
if node.tagName == "area" or node.tagName == "field":
xmlFields.append(node)
return xmlFields
def getTypeField(self, xmlField):
"""Выдает тип поля"""
if xmlField.hasAttribute("type"):
return xmlField.getAttribute("type")
else:
return False
def getNameField(self, xmlField):
"""Выдает имя поля"""
xmlNameFields = xpath.Evaluate('child::name', xmlField)
if xmlNameFields and xmlNameFields[0].firstChild:
return xmlNameFields[0].firstChild.nodeValue
else:
return False
def getNameArea(self, xmlArea):
"""Выдает имя области"""
xmlNameAreas = xpath.Evaluate('child::caption/name', xmlArea)
if xmlNameAreas and xmlNameAreas[0].firstChild:
return xmlNameAreas[0].firstChild.nodeValue
else:
return False
def xmlToText(self, xmlAreas, text):
"""Преобразует список XML областей в текст"""
def getQuotesArea(xmlArea):
quotes = []
xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea)
for node in xmlQuotes:
if node.firstChild:
quotes.append(node.firstChild.nodeValue)
if len(quotes) == 0:
quotes.append("")
quotes.append("")
elif len(quotes) == 1:
quotes.append("")
return quotes
for i in xmlAreas:
if i.tagName == "area":
quotesI = getQuotesArea(i)
startAreaI = quotesI[0]
endAreaI = quotesI[1]
text.append(startAreaI)
xmlFieldsI = self.getFieldsArea(i)
for f in xmlFieldsI:
if f.tagName == "area":
quotesF = getQuotesArea(f)
startAreaF = quotesF[0]
endAreaF = quotesF[1]
text.append(startAreaF)
xmlFieldsF = self.getFieldsArea(f)
self.xmlToText(xmlFieldsF, text)
text.append(endAreaF)
else:
fieldF = self.getQuoteField(f)
text.append(fieldF)
text.append(endAreaI)
else:
fieldI = self.getQuoteField(i)
text.append(fieldI)
def getActionField(self, xmlField):
"""Выдает свойство action XML поля"""
xmlActions = xpath.Evaluate('child::action',xmlField)
if xmlActions and xmlActions[0].firstChild:
return xmlActions[0].firstChild.nodeValue
else:
return False
def getFieldValues(self, xmlField):
"""Выдает значения XML поля в виде массива"""
vals = []
xmlValues = xpath.Evaluate('child::value',xmlField)
if xmlValues:
for node in xmlValues:
if node.firstChild:
vals.append(node.firstChild.nodeValue)
return vals
def getActionArea(self, xmlArea):
"""Выдает свойство action XML области"""
xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
if xmlActions and xmlActions[0].firstChild:
return xmlActions[0].firstChild.nodeValue
else:
return False
def delActionNodeArea(self, xmlArea):
"""Удаляет свойство action XML области"""
xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
if xmlActions and xmlActions[0].firstChild:
parentNode = xmlActions[0].parentNode
parentNode.removeChild(xmlActions[0])
return True
else:
return False
def delActionNodeField(self, xmlField):
"""Удаляет свойство action XML поля"""
xmlActions = xpath.Evaluate('child::action',xmlField)
if xmlActions and xmlActions[0].firstChild:
parentNode = xmlActions[0].parentNode
parentNode.removeChild(xmlActions[0])
return True
else:
return False
# Создает распределенные списки
def postParserListSeplist(self, xmlArea):
"""Создает распределенные списки из элементов области"""
# Потомки
childNodes = self.getFieldsArea(xmlArea)
# содержит списки нод полей с одинаковыми именами в одной области
fieldsSeplist = {}
for node in childNodes:
if node.tagName == "area":
self.postParserListSeplist(node)
else:
fieldName = False
xmlFieldNameNodes = xpath.Evaluate('child::name',node)
if xmlFieldNameNodes and xmlFieldNameNodes[0].firstChild:
fieldName = xmlFieldNameNodes[0].firstChild.nodeValue
if fieldName:
if fieldsSeplist.has_key(fieldName):
fieldsSeplist[fieldName].append(node)
else:
fieldsSeplist[fieldName] = []
fieldsSeplist[fieldName].append(node)
for listNodes in fieldsSeplist.values():
if len(listNodes) > 1:
for node in listNodes:
node.setAttribute("type", "seplist")
def insertBRtoBody(self, xmlArea):
"""Добавляет необходимые переводы строк
"""
# Потомки
childNodes = self.getFieldsArea(xmlArea)
# нода BR
fieldXMLBr = self.createField("br",[],"",[],False, False)
# разделитель поля
fieldSplit = False
# Предыдущая нода
lastNode = False
# Cледующая нода
nextNode = False
lenChildNodes = len(childNodes)
for i in range(lenChildNodes):
node = childNodes[i]
lastTmpNode = node
# Нода area
if node.tagName == "area":
if self.getActionArea(node) == "append" or\
self.getActionArea(node) == "join":
self.delActionNodeArea(node)
if lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "br" or\
lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "comment":
indNext = i + 1
if indNext == lenChildNodes:
xmlArea.appendChild(fieldXMLBr.cloneNode(True))
else:
nextNode = childNodes[indNext]
lastTmpNode = xmlArea.insertBefore(\
fieldXMLBr.cloneNode(True),
nextNode)
else:
xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
node)
self.insertBRtoBody(node)
# Нода field
else:
if self.getActionField(node) == "append" or\
self.getActionField(node) == "join":
self.delActionNodeField(node)
if lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "br" or\
lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "comment":
indNext = i + 1
if indNext == lenChildNodes:
xmlArea.appendChild(fieldXMLBr.cloneNode(True))
else:
nextNode = childNodes[indNext]
lastTmpNode = xmlArea.insertBefore(\
fieldXMLBr.cloneNode(True),
nextNode)
else:
xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
node)
lastNode = lastTmpNode
def postParserList(self):
"""Находит подходящие XML области и делаем из них поля-массивы"""
xmlAreas = xpath.Evaluate('descendant::area', self.body)
for xmlArea in xmlAreas:
flagListXml = True
fieldValues = []
xmlFields = xpath.Evaluate('child::field',xmlArea)
if not xmlFields:
flagListXml = False
lenXmlFields = len(xmlFields)
lenBrArea = 0
for xmlField in xmlFields:
xmlNames = xpath.Evaluate('child::name',xmlField)
xmlVals = xpath.Evaluate('child::value',xmlField)
if xmlField.hasAttribute("type") and\
xmlField.getAttribute("type") == "br":
lenBrArea += 1
continue
if not xmlNames and not xmlVals:
flagListXml = False
break
if xmlNames and xmlNames[0].firstChild and\
xmlNames[0].firstChild.nodeValue:
flagListXml = False
break
if not (xmlVals and xmlVals[0].firstChild and\
xmlVals[0].firstChild.nodeValue):
flagListXml = False
break
else:
fieldValues.append(xmlVals[0].firstChild.nodeValue)
if lenXmlFields == lenBrArea:
flagListXml = False
if flagListXml:
nameNode = xpath.Evaluate('child::caption/name',xmlArea)[0]
fieldName = ""
if nameNode.firstChild:
fieldName = nameNode.firstChild.nodeValue
listArea = []
self.xmlToText([xmlArea],listArea)
fieldQuote = "".join(listArea)
fieldXMLBr = False
if fieldQuote and fieldQuote[-1] == "\n":
fieldQuote = fieldQuote[:-1]
fieldXMLBr = self.createField("br",[],"",[],False, False)
fieldXML = self.createField("list",
[fieldQuote],
fieldName, fieldValues,
False, False)
areaAction = self.getActionArea(xmlArea)
if areaAction:
self.setActionField(fieldXML, areaAction)
parentNode = xmlArea.parentNode
parentNode.insertBefore(fieldXML,xmlArea)
if fieldXMLBr:
parentNode.insertBefore(fieldXMLBr,xmlArea)
parentNode.removeChild(xmlArea)
class blocText:
"""Разбиваем текст на блоки"""
def splitTxtToBloc(self, text ,openTxtBloc,closeTxtBloc,
commentTxtBloc, sepField):
"""Делит текст на блоки (без заголовков)
openTxtBloc - регулярное выражение для начала блока
closeTxtBloc - регулярное выражение для конца блока
commentTxtBloc - регулярное выражение - комментарий
возвращает блоки текста
"""
blocs = []
level = 0
# Нахождение нескольких блоков в строке
# разделители линий, разделителями могут быть ("","\n")
sepsLines = []
# линии
txtLines = []
# Исходные строки
txtLinesSrc = text.splitlines()
for line in txtLinesSrc:
lineBR = ""
lineTmpA = line
closeBl = False
txtLinesTmp = []
commentSpl = commentTxtBloc.split(line)
flagCommentLine = False
if commentSpl[0].strip():
closeBl = True
if len(commentSpl) > 1:
commentBl = commentTxtBloc.search(line)
textLine =commentSpl[0]
commentLine = line[commentBl.start(0):]
lineTmpA = textLine
flagCommentLine = True
while (closeBl):
closeBl = sepField.search(lineTmpA)
if closeBl:
lineTmpB = lineTmpA[closeBl.end(0):]
txtLinesTmp.append(lineTmpA[:closeBl.end(0)])
lineTmpA = lineTmpB
if lineTmpA.strip():
txtLinesTmp.append(lineTmpA)
# Если есть значение и комментарий в строке
if flagCommentLine:
for l in txtLinesTmp:
txtLines.append(l)
sepsLines.append("")
if not txtLinesTmp:
txtLines.append(textLine)
sepsLines.append("")
txtLines.append(commentLine)
sepsLines.append("\n")
# Если есть несколько блоков в строке
elif len(txtLinesTmp)>1 and txtLinesTmp[1].strip():
lenTmpLines = len(txtLinesTmp)
for l in range(lenTmpLines):
txtLines.append(txtLinesTmp[l])
if l == lenTmpLines-1:
sepsLines.append("\n")
else:
sepsLines.append("")
# Cтрока не преобразована
else:
txtLines.append(line)
sepsLines.append("\n")
# разбивание на блоки
z = 0
bl = ""
for i in txtLines:
if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(i):
level += len(openTxtBloc.split(i)) - 1
if commentTxtBloc.split(i)[0].strip() and closeTxtBloc.search(i):
level -= len(closeTxtBloc.split(i)) - 1
bl += i + sepsLines[z]
if level == 0:
if bl:
blocs.append(bl)
bl = ""
z += 1
# cоздание блоков с элементами не входящими в блоки
realBlocs = []
z = 0
bl = ""
for i in blocs:
txtLines = i.splitlines()
if len(txtLines) > 0:
line = txtLines[0]
else:
line = i
if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(line):
if bl:
realBlocs.append(bl)
bl = ""
realBlocs.append(i)
else:
bl += i
z += 1
if bl:
realBlocs.append(bl)
bl = ""
if level == 0:
if text and text[-1] != "\n":
tmpBlocs = realBlocs.pop()
tmpBlocs = tmpBlocs[:-1]
realBlocs.append(tmpBlocs)
return realBlocs
else:
return []
def findArea(self, text, reTextHeader, reTextArea, numGroupArea=0):
""" Делит текст на области (с заголовками)
reTextHeader - регулярное выражение для заголовка области
reTextArea - регулярное выражение для всей области
numGroupArea - номер групы результата поиска по регулярному выражению
по всей области
возвращает два списка: первый - заголовки, второй - тела областей без
заголоков
"""
# Заголовки областей
headersArea = []
# Тексты областей без заголовков
textBodyArea = []
r = reTextArea.search(text)
if not r:
headersArea.append("")
textBodyArea.append(text)
return (headersArea, textBodyArea)
txtWr = text
while r:
textArea = r.group(numGroupArea)
txtSpl = txtWr.split(textArea)
area = txtSpl[0]
txtWr = txtSpl[1]
if area:
headersArea.append("")
textBodyArea.append(area)
res = reTextHeader.search(textArea)
header = textArea[:res.end()]
body = textArea[res.end():]
headersArea.append(header)
textBodyArea.append(body)
if txtWr:
r = reTextArea.search(txtWr)
else:
r = False
if txtWr:
headersArea.append("")
textBodyArea.append(txtWr)
return (headersArea, textBodyArea)
def findBloc(self, text, captionTxtBloc, bodyTxtBloc):
""" Делит текст на блоки (с заголовками)
captionTxtBloc - регулярное выражение для заголовка блока
bodyTxtBloc - регулярное выражение для тела блока
возвращает два списка: первый - заголовки, второй - тела блоков
"""
# Заголовки блоков
headersTxt = []
# Тексты блоков
blocsTxt = []
r = captionTxtBloc.search(text)
if r:
headersTxt.append(r.group(0))
txtSpl = text.partition(r.group(0))
blocTxt = txtSpl[0]
txtWr = txtSpl[2]
rb = bodyTxtBloc.search(blocTxt)
if not blocTxt:
blocsTxt.append(blocTxt)
if rb:
blocsTxt.append(rb.group(0))
while (r):
r = captionTxtBloc.search(txtWr)
if r:
headersTxt.append(r.group(0))
txtSpl = txtWr.partition(r.group(0))
blocTxt = txtSpl[0]
txtWr = txtSpl[2]
rb = bodyTxtBloc.search(blocTxt)
if rb:
blocsTxt.append(rb.group(0))
else:
blocsTxt.append(txtWr)
if headersTxt and blocsTxt:
if len(headersTxt)>len(blocsTxt):
blocsTxt.insert(0,"")
elif len(headersTxt)<len(blocsTxt):
headersTxt.insert(0,"")
if len(headersTxt)!=len(blocsTxt):
return False
return (headersTxt, blocsTxt)
else:
return False
class _file(_error):
"""Класс для работы с файлами
"""
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 = ""
# Дескриптор файла шаблона
self.F_TEMPL = False
# Дескриптор файла конфигурационного файла
self.F_CONF = False
# тип запускаемого шаблона
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:
self.F_CONF.truncate(0)
self.F_CONF.seek(0)
try:
14 years ago
self.F_CONF.write(self.textConfig)
except:
12 years ago
self.setError(_("unable to open the file:")
+ 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("#!"):
self.queueExecute.append((processor[2:],self.textConfig,
self.nameFileTemplate))
else:
12 years ago
self.setError(_("unable to execute '%s'")
+ self.textConfig)
return False
14 years ago
def openTemplFile(self, nameFileTemplate):
"""Открыть файл шаблона"""
14 years ago
F_TEMPL = False
try:
14 years ago
F_TEMPL = open(nameFileTemplate, "r")
except:
12 years ago
self.setError(_("unable to open the file:")
+ nameFileTemplate)
return False
14 years ago
return F_TEMPL
14 years ago
def closeTemplFile(self):
if self.F_TEMPL:
self.F_TEMPL.close()
self.F_TEMPL = False
def __closeOldFile(self):
14 years ago
if self.F_CONF:
self.F_CONF.close()
self.F_CONF = False
14 years ago
def __openConfFile(self, nameFileConfig):
14 years ago
"""Отктрыть конфигурационный файл"""
14 years ago
F_CONF = False
try:
14 years ago
if os.path.islink(nameFileConfig):
# если ссылка то удаляем её
14 years ago
os.unlink(nameFileConfig)
F_CONF = open (nameFileConfig, "r+")
except:
try:
if os.path.isdir(nameFileConfig):
12 years ago
self.printWARNING(_("unable to open the directory as file:")
+ nameFileConfig)
return False
14 years ago
F_CONF = open(nameFileConfig, "w+")
except:
12 years ago
self.setError(_("unable to open the file:")
+ nameFileConfig)
return False
14 years ago
return F_CONF
def openFiles(self, nameFileTemplate, nameFileConfig, typeFormat=None,
newBuffer=None):
"""Открывает шаблон и конфигурационный файл"""
14 years ago
self.textConfig = ""
self.textTemplate = ""
self.closeFiles()
14 years ago
self.F_TEMPL = False
self.F_CONF = False
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:
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()
class utfBin:
"""Класс для преобразования в utf-8
преобразование бинарного или смеси бинарного и utf-8 кода в utf-8 и
обратное преобразование
методы класса encode и decode
"""
def _retUTF(self, char):
byte = ord(char)
if byte<=127:
return ('_ch_',1)
elif byte<=191:
return ('_nb_',1)
elif byte<=223:
return ('_fb_',2)
elif byte<=239:
return ('_fb_',3)
elif byte<=247:
return ('_fb_',4)
else:
return ('_er_',1)
def _sumbUtf(self, symbols, lenTail):
if not symbols:
return (False,0)
lenSymb = len(symbols)
if lenSymb >= 4:
l = 4
elif lenSymb >= 3:
l = 3
elif lenSymb >= 2:
l = 2
else:
if symbols[0] == '_ch_':
return (True,1)
else:
return (False,1)
result = False
for i in range(l):
if i == 0 and symbols[i] != '_fb_':
break
elif i > 0 and symbols[i] != '_nb_':
break
if lenTail>1 and lenTail != i:
return (False,1)
if i > 0:
result = True
return (result, i)
def _intToChar(self, x):
he = hex(x)[2:]
exec("ret = '\\x%s'" %he)
return ret
def _hexToChar(self, he):
exec("ret = '\\x%s'" %he)
return ret
def encode(self, text):
"""Кодирует смешанный формат в UTF-8"""
ind = 0
l = 0
utf = []
lenUtf = []
indErr = []
i = 0
for ch in text:
r, l = self._retUTF(ch)
utf.append(r)
lenUtf.append(l)
i+=1
while 1:
if utf[ind] == '_fb_':
res, l = self._sumbUtf(utf[ind:],lenUtf[ind])
if res is False:
indErr.append(ind)
if l>0:
ind +=l
if ind >= len(utf):
break
else:
if utf[ind] != '_ch_':
indErr.append(ind)
ind +=1
if ind >= len(utf):
break
if indErr:
lenIndErr = len(indErr)
block = []
blocks = []
if lenIndErr > 1:
i = 1
while 1:
if i == 1:
block.append(indErr[i-1])
if indErr[i] - indErr[i-1] == 1:
block.append(indErr[i])
else:
if block:
blocks.append(block)
block = []
block.append(indErr[i])
i +=1
if i >= lenIndErr:
break
else:
block.append(indErr[0])
if block:
blocks.append(block)
listErr = []
for block in blocks:
string = ""
for elem in block:
string += hex(ord(text[elem]))[-2:]
listErr.append((block[0],"__hex__?%s?__hex__" %string,elem))
textOut = text
deltaInd = 0
for erEl in listErr:
startInd = erEl[0] + deltaInd
endInd = erEl[2] + 1 + deltaInd
textOut = textOut[:startInd] + erEl[1] + textOut[endInd:]
deltaInd += len(erEl[1])-(erEl[2]-erEl[0]+1)
#if i == 1:
#break
#i += 1
return textOut
def decode(self, text):
"""Декодирует UTF-8 в смешанный формат"""
varStart = "__hex__\?"
varEnd = "\?__hex__"
# -1 Это экранирование '?' которое тоже считается
deltVarStart = len(varStart)-1
deltVarEnd = len(varEnd)-1
reVar = re.compile(("%s[a-f0-9]+%s")%(varStart,varEnd),re.M)
resS = reVar.search(text)
textTemplateTmp = text
while resS:
mark = textTemplateTmp[resS.start():resS.end()]
hexString = mark[deltVarStart:-deltVarEnd]
i = 0
stringInsert = ""
hexCode = ""
for ch in hexString:
if i>=1:
hexCode += ch
stringInsert += self._hexToChar(hexCode)
hexCode = ""
i = 0
else:
hexCode += ch
i += 1
textTemplateTmp = textTemplateTmp.replace(mark, stringInsert)
resS = reVar.search(textTemplateTmp)
return textTemplateTmp
class templateFormat(object):
"""Методы получения классов и объектов форматов шаблонов"""
# Импортированные классы поддерживаемых форматов шаблонов
importFormats = {}
def getClassObj(self, nameClassTemplate):
"""Создает класс шаблона по имени"""
if nameClassTemplate in self.importFormats:
classFormat = self.importFormats[nameClassTemplate]
else:
try:
classFormat = getattr(__import__("calculate.lib.format.%s"%
nameClassTemplate,
globals(), locals(),
[nameClassTemplate]),
nameClassTemplate)
except (ImportError, AttributeError):
#Создаем объект из self.newObjProt с помощью
# метаклассов
if nameClassTemplate in self.newObjProt:
# Прототип класса
nameProt = self.newObjProt[nameClassTemplate]
if nameProt in self.importFormats:
classProt = self.importFormats[nameProt]
else:
try:
classProt = getattr(
__import__("calculate.lib.format.%s"%nameProt,
globals(), locals(),
[nameProt]),
nameProt)
except (ImportError, AttributeError):
return False
self.importFormats[nameProt] = classProt
classFormat = self.createNewClass(nameClassTemplate,
(classProt,))
else:
return False
self.importFormats[nameClassTemplate] = classFormat
return classFormat
def getFormatObj(self, formatTemplate, textTemplate):
"""Создание объекта формата шаблона.
Объект создается на основании формата шаблона и текста шаблона"""
classFormat = self.getClassObj(formatTemplate)
if classFormat:
return classFormat(textTemplate)
else:
return False
class _shareTemplate:
"""Общие аттрибуты для классов шаблонов"""
# Метка начала переменной
varStart = "#-"
# Метка конца переменной
varEnd = "-#"
_deltVarStart = len(varStart)
_deltVarEnd = len(varEnd)
def getDataUser(self, groupsInfo=False):
14 years ago
"""Получить информацию о пользователе"""
userName = self.objVar.Get("ur_login")
if not userName:
userName = "root"
import pwd
try:
pwdObj = pwd.getpwnam(userName)
uid = pwdObj.pw_uid
gid = pwdObj.pw_gid
homeDir = self.objVar.Get('ur_home_path')
14 years ago
except:
12 years ago
raise TemplatesError(_("User %s not found")%str(userName))
if groupsInfo:
import grp
try:
groupName = grp.getgrgid(gid).gr_name
except:
12 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
12 years ago
class templateFunction(_error, _warning, _shareTemplate, _shareTermsFunction):
"""Класс для функций шаблонов"""
# Словарь установленных программ {"имя программы":[версии]}
installProg = {}
# Cписок просканированных категорий установленных программ
installCategory = []
# Флаг сканирования всех установленных программ
flagAllPkgScan = False
# Список названий функций шаблона
namesTemplateFunction = []
# Словарь {название функции шаблона: функция шаблона, ...}
templateFunction = {}
# Регулярное выражение для сложения
sNum = re.compile("\-[^\-\+]+|[^\-\+]+")
# Регулярное выражение для умножениея и деления
sMD = re.compile("[^\-\+\*\/]+")
# директория установленных программ
basePkgDir = "/var/db/pkg"
# кэш для проверки наличия пакета в портежах
cachePortdir = {}
# стек глобальных переменных
stackGlobalVars = []
# регулярное выражение для поиска версии
reFindVer = re.compile("(?<=-)(?:\d+)(?:(?:\.\d+)*)"
"(?:[a-z]?)(?:(?:_(?:pre|p|beta|alpha|rc)\d*)*)"
"(?:-r\d+)?$")
reEmptyLoad = re.compile("^\s*$|^\s*;|^\s*#")
# Имя обрабатываемого шаблона
nameTemplate = ""
# Текст функции шаблона
functText = ""
# regular for discard sort number and version
reData = re.compile(r"^(?:\d+-)?(.+?)(?:-(?:|always|\d+|\d(?:\d|\.|pre|_"
"|-always|alpha|beta|pre|rc|[a-z][^a-z])*[a-z]?)(?:"
"-r\d+)?)?$",re.S)
@classmethod
def get_pkgname_by_filename(cls, fn):
fileName = os.path.split(fn)[1]
if fileName == '.calculate_directory':
parentDir = os.path.dirname(fn)
parentDir, pkgName = os.path.split(parentDir)
else:
parentDir, pkgName = os.path.split(fn)
category = os.path.split(parentDir)[1]
# reg for discard version and sort number
pkgName = cls.reData.search(pkgName).group(1)
category = cls.reData.search(category).group(1)
return "%s/%s"%(category,pkgName)
currentBelong = ""
11 years ago
alreadyInformed = []
def __init__(self, objVar):
# Если не определен словарь функций шаблона
# import services api
if not self.templateFunction:
# префикс функций шаблона
pref = "func"
# cписок [(название функции, функция), ...]
dictFunc = filter(lambda x: x[0].startswith(pref) and\
hasattr(x[1],"__call__"),
self.__class__.__dict__.items())
# удаляем у названия функции префикс и переводим остаток названия
# в нижний регистр
dictFunc = map(lambda x: (x[0][len(pref):].lower(), x[1]), dictFunc)
# Формируем словарь функций шаблона
self.templateFunction.update(dictFunc)
# Формируем список функций шаблона
for nameFunction in self.templateFunction.keys():
self.namesTemplateFunction.append(nameFunction)
# Объект хранения переменных
self.objVar = objVar
self._reFunc = re.compile(("%s%s%s")\
%(self.varStart,self._reFunctionText,self.varEnd),re.M)
# Аттрибуты для функции шаблона ini()
# Первоначальный словарь переменных для ini()
self.prevDictIni = {}
# Текущий словарь переменных для ini()
self.currDictIni = {}
# Время модификации конфигурационного файла для ini()
self.timeIni = -1
self.recalculateBaseDir()
# Словарь времен модификации env файлов
self.timeConfigsIni = {}
# Словарь хранения переменых полученных функцией env() из env файлов
self.valuesVarEnv = {}
# Словарь хранения опций для функции info()
self.optionsInfo = {}
# файл параметров сервисов
envFile = self.objVar.Get("cl_env_server_path")
# объект конвертирования из старого remote env файла
self.convObj = False
if os.access(envFile, os.R_OK):
self.convObj = False
elif os.access("/var/calculate/remote/calculate.env", os.R_OK):
14 years ago
from convertenv import convertEnv
self.convObj = convertEnv()
def recalculateBaseDir(self):
"""Recalculate basedir and homedir"""
# Директория другой системы
self._chrootDir = self.objVar.Get("cl_chroot_path")
if self._chrootDir != '/':
# Изменение директории к базе пакетов
self.basePkgDir = pathJoin(self._chrootDir, self.basePkgDir)
self.basePkgDir = os.path.normpath(self.basePkgDir)
# Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
self._baseDir=pathJoin(self._chrootDir,self.objVar.Get("cl_root_path"))
self._baseDir = os.path.normpath(self._baseDir)
self.uid, self.gid, self.homeDir, self.groups =\
self.getDataUser(groupsInfo=True)
# Домашняя директория, плюс базовая директория
self.homeDir = pathJoin(self._baseDir, self.homeDir)
# path to configuration file for ini() function
# if action is desktop configuration, then path in user directory
# else config file place in /etc/calculate
if self.objVar.Get('cl_action') == "desktop":
self.pathConfigIni = os.path.join(self.homeDir, ".calculate")
self.modeConfigIni = 0640
else:
self.pathConfigIni = pathJoin(self._chrootDir,'/etc/calculate')
self.modeConfigIni = 0644
self.fileConfigIni = os.path.join(self.pathConfigIni,"ini.env")
def equalTerm(self, term, localVars):
"""Метод для вычисления выражения"""
terms = self.sNum.findall(term)
if terms:
strNumers = []
for n in terms:
strNum = n.strip()
if "*" in strNum or "/" in strNum:
strNum = self.multAndDiv(strNum,localVars)
try:
num = int(strNum)
except:
minus = False
if strNum[:1] == "-":
minus = True
strNum = strNum[1:]
if localVars.has_key(strNum):
try:
num = int(localVars[strNum])
except:
self.raiseErrTemplate(
_("error: variable %s is not integer")%
str(strNum))
elif self.objVar.exists(strNum):
try:
num = int(self.objVar.Get(strNum))
except:
self.raiseErrTemplate(
_("error: variable %s is not integer")%
str(strNum))
else:
self.raiseErrTemplate(
_("error: local variable %s not defined")%
str(strNum))
if minus:
num = -num
strNumers.append(num)
return sum(strNumers)
self.raiseErrTemplate(_("error: template term %s, incorrect data")\
%str(term))
def multAndDiv(self, term, localVars):
"""Метод для умножения и деления"""
termTmp = term
varsLocal = self.sMD.findall(term)
for var in varsLocal:
flagVarTxt = True
try:
int(var)
except:
flagVarTxt = False
if flagVarTxt:
continue
varReplace = str(self.equalTerm(var, localVars))
termTmp = termTmp.replace(var,varReplace)
ret = eval(termTmp)
return ret
12 years ago
def funcSum(self, funArgv, resS, localVars, textTemplateTmp,nameTemp):
"""Функция шаблона, вычисляет функцию sum()"""
terms = funArgv.replace(" ","").split(",")
# Название локальной переменной
nameLocVar = terms[0]
if not localVars.has_key(nameLocVar):
localVars[nameLocVar] = 0
if len(terms) == 2:
if terms[1].strip():
localVars[nameLocVar] = self.equalTerm(terms[1], localVars)
replace = str(localVars[nameLocVar])
else:
replace = ""
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
elif len(terms) == 3:
if terms[1].strip():
replaceInt = self.equalTerm(terms[1], localVars)
replace = str(replaceInt)
else:
replace = ""
localVars[nameLocVar] = self.equalTerm(terms[2], localVars)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
else:
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:
self.raiseErrTemplate()
fileName = terms[0]
flagNotRootFS = True
if len(terms) == 2:
if terms[1] == "root":
flagNotRootFS = False
else:
self.raiseErrTemplate(
12 years ago
_("The second argument of the function is not 'root'"))
if fileName[0] == "~":
# Получаем директорию пользователя
fileName = os.path.join(self.homeDir,
fileName.partition("/")[2],"")[:-1]
elif fileName[0] != "/":
self.raiseErrTemplate(_("wrong path '%s'")%fileName)
else:
if flagNotRootFS:
fileName = pathJoin(self._baseDir, fileName)
replace = ""
if os.path.exists(fileName):
replace = "1"
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcLoad(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона load(),
если файл существует читает из файла локальную переменную
если один параметр - выводит значение локальной переменной
"""
terms = funArgv.split(",")
if terms:
lenTerms = len(terms)
if not terms[0].strip() or\
(lenTerms==2 and not terms[1].strip()) or\
(lenTerms==3 and not terms[2].strip()) or\
lenTerms>3:
self.raiseErrTemplate()
else:
self.raiseErrTemplate()
flagNotRootFS = True
if lenTerms == 3:
if terms[2] =="root":
flagNotRootFS = False
else:
self.raiseErrTemplate(
12 years ago
_("The third argument of the function is not 'root'"))
if lenTerms >= 2:
if not terms[0] in ["ver","num","char","key","empty"]:
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,
fileName.partition("/")[2],"")[:-1]
elif fileName[0] != "/":
self.raiseErrTemplate(_("wrong path '%s'")%fileName)
else:
if flagNotRootFS:
fileName = pathJoin(self._baseDir,fileName)
replace = ""
if os.path.exists(fileName):
replace = readFile(fileName).strip()
if replace and lenTerms >= 2 and terms[0] == "empty":
replace ="\n".join(filter(lambda x: not self.reEmptyLoad.search(x),
replace.split("\n")))
if not replace and lenTerms >= 2 and terms[0] in ["ver","num"]:
replace = "0"
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def sharePkg(self,pkgs,force=False):
"""
Update packages from pkgs list
"""
for pkgname,category,ver,slot in pkgs:
fullname = "%s/%s"%(category,pkgname)
if not fullname in self.installProg or \
type(self.installProg[fullname]) != dict:
self.installProg[fullname] = self.installProg[pkgname] = {}
if force or not slot in self.installProg[fullname]:
self.installProg[fullname][slot] = ver
return self.installProg
def getInstallPkgGentoo(self,category=""):
pkgs = []
filterFunc = "SLOT".__eq__
def getFilesDir(pkgs, dirname, names):
for nameFile in filter(filterFunc,names):
absNameFile = os.path.join(dirname,nameFile)
category,spl,pkgname = dirname.rpartition('/')
dbpkg,spl,category = category.rpartition('/')
slot = readFile(absNameFile).strip()
pkgname,spl,rev = pkgname.rpartition("-")
if rev.startswith('r'):
pkgname, spl, ver = pkgname.rpartition("-")
ver = "%s-%s"%(ver,rev)
else:
ver = rev
pkgs.append((pkgname,category,ver,slot))
return True
os.path.walk(os.path.join(self.basePkgDir,category),
getFilesDir, pkgs)
return self.sharePkg(pkgs)
def pkg(self,nameProg,slot=None):
if len(self.installProg) > 0:
if type(self.installProg.values()[0]) != dict:
self.installProg.clear()
self.getInstallPkgGentoo()
if nameProg in self.installProg:
versions = self.installProg[nameProg]
if slot:
return versions.get(slot,"")
if len(versions) == 1:
return versions.values()[0]
else:
return versions[max(versions.keys(),key=getTupleVersion)]
else:
return ""
12 years ago
def funcPkg(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона pkg(), выдает номер версии программы"""
# Название программы
nameProg = funArgv.replace(" ","")
if not nameProg:
nameProg = self.get_pkgname_by_filename(self.nameTemplate)
# Замена функции в тексте шаблона
replace = ""
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:
pkg_use, pkg_iuse = getPkgUses("%s/%s"%(category, nameProg),
replace, prefix=self.objVar.Get('cl_chroot_path'))
for use in filter(None,uses.split(',')):
if (use[0] == "-" and use[1:] in pkg_use or
use[0] != "-" and use not in pkg_use):
replace = ""
break
else:
if not self.flagAllPkgScan:
self.getInstallPkgGentoo()
templateFunction.flagAllPkgScan = True
nameProg,spl,slot = nameProg.partition(":")
replace = self.pkg(nameProg,
slot=slot)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcKernel(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Функция kernel(...), выдает значение опции конфига ядра (y,m,)
"""
terms = funArgv.replace(" ","").split(",")
if not terms[0].strip() or len(terms)!=1:
self.raiseErrTemplate()
kernel_opt = terms[0].upper()
if kernel_opt.startswith("CONFIG_"):
self.raiseErrTemplate(
_("the option name should not starts with CONFIG_"))
kernel_config = self.objVar.Get('install.os_install_kernel_config')
find_str = "CONFIG_%s"%kernel_opt
replace = ""
for line in kernel_config:
if find_str in line:
if "%s="%find_str in line:
key, op, value = line.partition("=")
replace = value.strip("'\"")
break
elif "%s is not set"%find_str in line:
break
textTemplateTmp = (textTemplateTmp[:resS.start()] + replace +
textTemplateTmp[resS.end():])
return textTemplateTmp
def funcGrep(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Функция grep (...), выдает значение из файла по регулярному выражению
"""
fname, op, regpattern = funArgv.replace(" ","").partition(",")
regpattern = regpattern.replace("(?\<","(?<")
regpattern = self._replace_hex(regpattern)
if not fname or not regpattern:
self.raiseErrTemplate()
try:
reg = re.compile(regpattern)
except re.error as e:
self.raiseErrTemplate(_("Wrong regular expression"))
if fname[0] == "~":
# Получаем директорию пользователя
fname = os.path.join(self.homeDir,
fname.partition("/")[2],"")[:-1]
fname = pathJoin(self.objVar.Get('cl_chroot_path'),fname)
fileContent = readFile(fname)
match_data = reg.search(fileContent)
if match_data:
md_groups = match_data.groups()
if md_groups:
replace = md_groups[0] or ""
else:
replace = match_data.group()
else:
replace = ""
return (textTemplateTmp[:resS.start()] + replace + textTemplateTmp[resS.end():])
12 years ago
def funcRnd(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона rnd(), выдает строку случайных символов
первый аргумент:
'num' - числа,
'pas' - цифры и буквы
'uuid' - цифры и строчные буквы a-f
второй аргумент:
количество символов
"""
terms = funArgv.replace(" ","").split(",")
if not terms[0].strip() or\
(len(terms)==2 and not terms[1].strip()) or\
len(terms)!=2:
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:
self.raiseErrTemplate(
_("the first argument of the function must "
12 years ago
"be 'num', 'pas' or 'uuid'"))
try:
lenStr = int(terms[1])
except:
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)])
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' - первая буква в верхнем регистре
второй аргумент:
название переменной
"""
terms = funArgv.replace(" ","").split(",")
if not terms[0].strip() or\
(len(terms)==2 and not terms[1].strip()) or len(terms)!=2:
self.raiseErrTemplate()
fArgvNames = ['upper','lower','capitalize']
if not terms[0] in fArgvNames:
12 years ago
self.raiseErrTemplate(_("the first argument of the function"
12 years ago
" is neither 'upper' or 'lower' or"
12 years ago
" 'capitalize'"))
try:
12 years ago
strValue = self.objVar.Get(terms[1])
if not strValue:
strValue = ""
else:
strValue = str(strValue)
except:
raise TemplatesError(
_("error in template %s")%self.nameTemplate + "\n" +
_("error: variable %s not found")%str(terms[1]))
replace = ""
strValue = _toUNICODE(strValue)
if terms[0] == 'upper':
replace = strValue.upper()
elif terms[0] == 'lower':
replace = strValue.lower()
elif terms[0] == 'capitalize':
replace = strValue.capitalize()
if replace:
replace = replace.encode("UTF-8")
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
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]
flagFoundVar = False
try:
value = self.objVar.Get(nameLocVar)
12 years ago
flagFoundVar = True
except:
pass
if flagFoundVar:
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 = ""
12 years ago
else:
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):
"""локальная функция записывает значение переменной
в стек глобальных переменных
"""
terms = funArgv.replace(" ","").split(",")
# Название локальной переменной
nameLocVar = terms[0]
flagFoundVar = False
if nameLocVar in localVars.keys():
flagFoundVar = True
value = localVars[nameLocVar]
else:
try:
value = self.objVar.Get(nameLocVar)
flagFoundVar = True
except:
pass
if flagFoundVar:
# Если переменная существует
if len(terms) == 1:
self.stackGlobalVars.append(str(value))
else:
12 years ago
self.raiseErrTemplate(_("error: variable %s exists")\
%str(nameLocVar))
else:
# Если переменная не существует
if len(terms) == 1:
12 years ago
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:
self.raiseErrTemplate()
replace = ""
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcPop(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""локальная функция получает значение
из стека глобальных переменных и присваивает локальной переменной
"""
terms = funArgv.replace(" ","").split(",")
# Название локальной переменной
nameLocVar = terms[0]
if len(terms) == 1:
if self.stackGlobalVars:
localVars[nameLocVar] = self.stackGlobalVars.pop()
else:
self.raiseErrTemplate(
12 years ago
_("error: global variables stack empty"))
else:
self.raiseErrTemplate()
replace = ""
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcPrint(self,funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Вывод успешного сообщения
"""
self.printSUCCESS(_(funArgv))
textTemplateTmp = textTemplateTmp[:resS.start()] + \
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcWarning(self,funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Вывод сообщения с предупреждением
"""
self.printWARNING(_(funArgv))
textTemplateTmp = textTemplateTmp[:resS.start()] + \
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcError(self,funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
Вывод сообщения с ошибкой
"""
self.printERROR(_(funArgv))
textTemplateTmp = textTemplateTmp[:resS.start()] + \
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcExit(self,funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
11 years ago
Good exit
12 years ago
"""
# TODO: need remove
return textTemplateTmp
12 years ago
self.printSUCCESS(_(funArgv))
11 years ago
raise TemplatesInterrupt(_("Execution of templates was stopped"),
TemplatesInterrupt.EXIT)
12 years ago
def funcBreak(self,funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""
11 years ago
Bad exit
12 years ago
"""
# TODO: need remove
return textTemplateTmp
12 years ago
self.printERROR(_(funArgv))
11 years ago
raise TemplatesInterrupt(_("Execution of templates was "
"interrupted with an error"),
12 years ago
TemplatesInterrupt.ABORT)
def getElogTimestamp(self):
# Получаем время модификации конфигурационного файла
curTime = self.getTimeFile(self.fileConfigIni)
nameLocVar = "update.timestamp"
if self.timeIni != curTime:
# читаем переменные из файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
self.currDictIni= {}
self.currDictIni.update(self.prevDictIni)
self.timeIni = self.getTimeFile(self.fileConfigIni)
if nameLocVar in self.currDictIni.keys():
if self.currDictIni[nameLocVar] is None:
return 0
else:
val = self.currDictIni[nameLocVar].encode("UTF-8")
if val.isdigit():
return int(val)
return 0
elogFile = '/var/log/emerge.log'
@classmethod
def getLastElog(cls):
# get last timestamp (of ::completed emerge)
entry = EmergeLog(EmergeLogPackageTask()).get_last_time()
if entry:
return entry.partition(":")[0]
else:
return ""
12 years ago
def funcElog(self,funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Function for work with emerge.log"""
funArgv = funArgv.strip()
rePkg = re.compile(r'\) Merging (?:Binary )?\((\S+)::',re.S)
12 years ago
replace = ""
if funArgv:
lastTimestamp = self.getElogTimestamp()
skip = True
for line in reversed(list(readLinesFile(self.elogFile))):
12 years ago
timestamp,op,info = line.partition(':')
if timestamp.isdigit() and lastTimestamp and \
int(timestamp) < lastTimestamp:
break
match = rePkg.search(info)
if match and match.group(1).startswith(funArgv):
pkgInfo = reVerSplitToPV(match.group(1))
if "{CATEGORY}/{PN}".format(**pkgInfo) == funArgv:
replace = pkgInfo['PVR']
break
else:
replace = self.getLastElog()
12 years ago
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcConfirm(self,funArgv, resS, localVars, textTemplateTmp, nameTemp):
# TODO: need remove
return textTemplateTmp
12 years ago
res = self.askConfirm(_(funArgv))
textTemplateTmp = textTemplateTmp[:resS.start()] + res + \
textTemplateTmp[resS.end():]
return textTemplateTmp
def loadVarsIni(self, iniFileName):
""" Читает файл fileName
создает и заполняет переменные на основе этого файла
Используеться совместно c funcIni
"""
localVarsIni = {}
# получить объект ini файла
config = ConfigParser(strict=False)
config.read(iniFileName, encoding="utf-8")
# получаем все секции из конфигурационного файла
allsect = config.sections()
if not allsect:
return localVarsIni
# Заполняем переменные для funcIni
for sect in allsect:
for name, valueVar in config.items(sect, raw=True):
nameVar = "%s.%s"%(sect,name)
localVarsIni[nameVar] = valueVar
return localVarsIni
def getTimeFile(self, fileName):
# Получаем время модификации файла
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:
self.raiseErrTemplate(_("funtion takes only two parameters"))
resol, wpath = terms
re_resol = re.compile("^(\d+)x(\d+)$")
resol = re_resol.match(resol)
if not resol:
self.raiseErrTemplate(
_("the first parameter must be the resolution"))
re_resol = re.compile(".*?(\d+)x(\d+).*")
wpath = pathJoin(self._baseDir, wpath)
res = map(lambda x:(int(x.group(1)),int(x.group(2)),x.group()),
filter(None,
map(re_resol.search,
listDirectory(wpath))))
width = int(resol.group(1))
height = int(resol.group(2))
gep = sqrt(height**2+width**2)
k = float(width)/float(height)
if res:
# наиболее подходящее разрешение:
# минимальная разность между пропорциями (отношение ширины к высоте)
# минимальная разность между размерами (гепотенуза)
near_res = min(res,
key=lambda x:(abs(x[0]/float(x[1])-k),
abs(gep-sqrt(x[0]**2+x[1]**2))))
replace = near_res[2]
else:
replace = ""
textTemplateTmp = textTemplateTmp[:resS.start()] + replace + \
textTemplateTmp[resS.end():]
return textTemplateTmp
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:
terms.append(term.replace(" ",""))
flagFirst = False
else:
val = term.strip()
# Флаг (не найдены кавычки)
flagNotFoundQuote = True
for el in ('"',"'"):
if val.startswith(el) and val.endswith(el):
terms.append(val[1:-1])
flagNotFoundQuote = False
break
if flagNotFoundQuote:
if not val:
terms.append(None)
else:
terms.append(val)
# Название локальной переменной
nameLocVar = terms[0]
namesVar = nameLocVar.split(".")
if len(namesVar) == 1:
nameLocVar = "main.%s"%nameLocVar
elif len(namesVar)>2:
self.raiseErrTemplate()
replace = ""
# Получаем время модификации конфигурационного файла
curTime = self.getTimeFile(self.fileConfigIni)
if len(terms) == 1:
if self.timeIni != curTime:
# читаем переменные из файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
self.currDictIni= {}
self.currDictIni.update(self.prevDictIni)
self.timeIni = self.getTimeFile(self.fileConfigIni)
if nameLocVar in self.currDictIni.keys():
if self.currDictIni[nameLocVar] is None:
replace = ""
else:
replace = self.currDictIni[nameLocVar].encode("UTF-8")
elif len(terms) == 2:
if self.timeIni != curTime:
# читаем переменные из файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
self.currDictIni= {}
self.currDictIni.update(self.prevDictIni)
self.timeIni = self.getTimeFile(self.fileConfigIni)
# Значение локальной переменной
valueLocVar = terms[1]
self.currDictIni[nameLocVar] = valueLocVar
elif len(terms) == 3:
if not terms[2] in ['url','purl','unicode']:
12 years ago
self.raiseErrTemplate(
12 years ago
_("the third argument of the function is neither "
12 years ago
"'url' or 'purl' or 'unicode'"))
if terms[1]:
self.raiseErrTemplate()
if self.timeIni != curTime:
# читаем переменные из файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
self.currDictIni= {}
self.currDictIni.update(self.prevDictIni)
self.timeIni = self.getTimeFile(self.fileConfigIni)
if nameLocVar in self.currDictIni.keys():
unicodeValue = self.currDictIni[nameLocVar]
if unicodeValue is None:
unicodeValue = ""
if terms[2] in ('url', 'purl'):
replace = unicodeValue.encode("UTF-8").\
__repr__()[1:-1].replace('\\x','%').\
replace(' ','%20')
if terms[2] == 'purl':
replace = replace.replace('/','%2f')
elif terms[2] == 'unicode':
replace = unicodeValue.__repr__()[2:-1]
else:
self.raiseErrTemplate()
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return (textTemplateTmp)
def _replace_hex(self, text):
"""
Заменить в строке комбинацию \\x00 на символ
"""
return re.sub(r'\\x([0-9a-fA-F]{2})',
lambda x:chr(int(x.group(1),16)), text)
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' - без преобразования (одна строка)
"""
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:
self.raiseErrTemplate()
return listArgv
terms = map(lambda x: x.strip(), funArgv.split(","))
if len(terms) != 3:
self.raiseErrTemplate()
listArgv = getStrArgv(terms[:2])
old = listArgv[0]
new = listArgv[1]
nameVar = terms[2]
# Получаем значение переменной
if nameVar in localVars:
value = str(localVars[nameVar])
else:
try:
value = str(self.objVar.Get(nameVar))
except:
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 файлов
"""
terms = funArgv.replace(" ","").split(",")
if len(terms) != 1:
self.raiseErrTemplate()
nameVar = terms[0]
replace = ''
if nameVar in self.valuesVarEnv:
replace = self.valuesVarEnv[nameVar]
else:
# Получаем значение из env файлов
value = self.objVar.getIniVar(nameVar)
if value is False:
self.raiseErrTemplate(self.getError())
self.valuesVarEnv[nameVar] = value
replace = value
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
"""
terms = funArgv.replace(" ","").split(",")
if len(terms)==0 or len(terms)>2:
self.raiseErrTemplate()
nameLocalVar = ""
if len(terms)==2:
if not terms[1]:
self.raiseErrTemplate()
nameLocalVar = terms[1]
14 years ago
textLine = terms[0]
vals = textLine.split(".")
14 years ago
if len(vals)!= 2:
self.raiseErrTemplate()
14 years ago
if filter(lambda x: not x.strip(), vals):
self.raiseErrTemplate()
14 years ago
service, option = vals
if not service or not option:
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:
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] = ""
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"
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcBelong(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
12 years ago
self.printWARNING(_("Function '{funcname}' used by {template} "
"is deprecated and will be removed in the future"
).format(funcname="belong",template=nameTemp))
replace = ""
return textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
def checkCorrectPkgName(self,package):
"""
Check pkg name (in /var/db/pkg,/usr/portage,/var/lib/layman/calculate
and other overlays)
"""
return True
category,spl,pkgname = package.partition('/')
pkgname, spl, slot = pkgname.partition(":")
# check installed package in system
if not category in self.installCategory:
self.getInstallPkgGentoo(category=category)
self.installCategory.append(category)
if self.pkg("%s/%s"%(category,pkgname), slot=slot or None):
return True
# check package in portage and calculate,overlay
def queuePortdir():
yield "/usr/portage"
calculate = "/var/lib/layman/calculate"
yield calculate
for portdir in filter(lambda x:x!=calculate,
self.objVar.Get('cl_portdir_overlay')):
yield portdir
for portdir in queuePortdir():
if not portdir in self.cachePortdir:
lPortdir = len(portdir)+1
self.cachePortdir[portdir] = list(set(
map(lambda x:x[lPortdir:].rpartition('/')[0],
glob.glob("%s/*/*/*.ebuild"%portdir))))
if package in self.cachePortdir[portdir]:
return True
else:
if portdir == "/usr/portage" and \
len(self.cachePortdir[portdir]) < 30:
#raise TemplatesError(_("Ebuild files are not found in portage"))
return True
if not "portage/update" in self.cachePortdir:
updateFiles = sorted(listDirectory('/usr/portage/profiles/updates'),
key=lambda x:tuple(reversed(x.split('Q-'))),reverse=True)
if updateFiles:
self.cachePortdir["portage/update"] = \
map(lambda x:x.split(' ')[1],
filter(lambda x:x.startswith('move '),
readLinesFile(os.path.join('/usr/portage/profiles/updates',
updateFiles[0]))))
if "portage/update" in self.cachePortdir and \
package in self.cachePortdir["portage/update"]:
self.printWARNING(_("Package {frompkg} was renamed").format(frompkg=package))
return True
return False
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 ""
"""
def uniq_warning(message):
hashMessage = hashlib.md5(message).digest()
if not hashMessage in self.alreadyInformed:
self.printWARNING(message)
self.alreadyInformed.append(hashMessage)
def check_skip(pkgName):
skip_data_varname = 'cl_setup_skip_%s'%self.currentAction
skip_data = self.objVar.Get(skip_data_varname)
pass_location = self.objVar.Get('cl_pass_location')
if any(skip_data):
for data in skip_data:
if len(data) != 2:
uniq_warning(
_("Wrong entry '{data}' for {var_name}").format(
data=",".join(data),var_name=skip_data_varname))
else:
pkg, location = data
if fnmatch(pkgName, pkg) and (location == "*"
or location == pass_location):
return True
return False
terms = funArgv.replace(" ","").split(",")
if len(terms) != 1:
self.raiseErrTemplate()
funcPkg = terms[0]
if not funcPkg:
funcPkg = self.get_pkgname_by_filename(self.nameTemplate)
try:
if not self.checkCorrectPkgName(funcPkg):
uniq_warning(_("Package {pkgName} specified in the merge() into "
"{templName} template is not found").format(
pkgName=funcPkg,templName=self.nameTemplate))
return textTemplateTmp[:resS.start()] + \
textTemplateTmp[resS.end():]
except TemplatesError as e:
self.printWARNING(str(e))
self.currentBelong = funcPkg
11 years ago
if self.objVar.Get('cl_action') == 'patch':
if funcPkg == "%s/%s"%(self.objVar.Get('core.cl_core_pkg_category'),
self.objVar.Get('core.cl_core_pkg_name')):
replace = self.objVar.Get('core.cl_core_pkg_version')
if check_skip(funcPkg):
replace = ""
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 = ""
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcList(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона list().
Если первый аргумент является именем локальной или глобальной
переменной и значение переменной является списком, выдает
элемент списка по второму аргументу индексу.
Первый элемент имеет индекс 0
"""
terms = funArgv.replace(" ","").split(",")
# У функции должно быть два аргумента
if len(terms) != 2:
self.raiseErrTemplate()
# Название локальной или глобальной переменной
nameLocVar = terms[0]
strIndex = terms[1]
try:
intIndex = int(strIndex)
except:
self.raiseErrTemplate(_("'%s' is not a number")%strIndex)
flagFoundVar = False
if nameLocVar in localVars.keys():
flagFoundVar = True
value = localVars[nameLocVar]
else:
try:
value = self.objVar.Get(nameLocVar)
flagFoundVar = True
except:
pass
if not flagFoundVar:
# Если переменная не существует
12 years ago
self.raiseErrTemplate(_("error: variable %s does not exist")\
%str(nameLocVar))
if not type(value) in (list,tuple):
# Значение переменной не список или кортеж
12 years ago
self.raiseErrTemplate(_("value of %s is not a list or a tuple")\
%str(nameLocVar))
try:
if len(value) > intIndex:
replace = str(value[intIndex])
else:
replace = ""
except:
12 years ago
self.raiseErrTemplate(_("wrong %s")%strIndex)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
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_второй_аргумент с этим индексом
"""
terms = funArgv.replace(" ","").split(",")
# У функции должно быть два аргумента
if len(terms) != 2:
self.raiseErrTemplate()
# Название глобальной переменной
mountPoint = terms[0]
lastElementVar = terms[1]
if not mountPoint or mountPoint[:1] !="/":
12 years ago
self.raiseErrTemplate(_("wrong %s")%lastElementVar)
12 years ago
nameVar = "install.os_install_disk_mount"
try:
valueVar = self.objVar.Get(nameVar)
except:
# Если переменная не существует
self.raiseErrTemplate(
12 years ago
_("error: variable %s does not exist")%nameVar)
12 years ago
nameElementVar = "install.os_install_disk_%s"%lastElementVar
try:
valueElementVar = self.objVar.Get(nameElementVar)
except:
# Если переменная не существует
12 years ago
nameElementVar = "install.os_disk_%s"%lastElementVar
try:
valueElementVar = self.objVar.Get(nameElementVar)
except:
12 years ago
self.raiseErrTemplate(_("wrong %s")%lastElementVar+"\n"+
12 years ago
_("error: variable %s does not exist")\
%nameElementVar)
if not type(valueVar) in (list,tuple):
# Значение переменной не список или кортеж
12 years ago
self.raiseErrTemplate(_("value of %s is not a list or a tuple")\
%nameVar)
if not type(valueElementVar) in (list,tuple):
# Значение переменной не список или кортеж
12 years ago
self.raiseErrTemplate(_("value of %s is not a list or a tuple")\
%nameElementVar)
if len(valueVar) != len(valueElementVar):
self.raiseErrTemplate(
12 years ago
_("%(name)s does not match %(nameElement)s in size")\
14 years ago
%{'name':nameVar, 'nameElement':nameElementVar})
index = None
for num, mPoint in enumerate(valueVar):
if mountPoint == mPoint:
index = num
break
if index is None:
for num, mPoint in enumerate(valueVar):
if "/" == mPoint:
index = num
break
if index is None:
12 years ago
self.raiseErrTemplate(_("mount point '/' or '/%s' not found "
12 years ago
" in the value of variable os_disk_install")
12 years ago
%mountPoint)
replace = valueElementVar[index]
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
12 years ago
def funcModule(self, funArgv, resS, localVars, textTemplateTmp, nameTemp):
"""Функция шаблона module(), выдает значение аттрибута api.
аргумент:
путь_к_атрибуту - путь к аттрибуту
возможные пути:
имя_пакета.var.имя_переменной - получаем значение переменной
имя_пакета.имя_метода_api - выполнение метода, получение результата
all.имя_метода_api - выполнение метода для всех пакетов с api
"""
return textTemplateTmp
def raiseErrTemplate(self,message=""):
"""Возвращает ошибки при обработке функций шаблона"""
if message:
message = "%s\n"%message
else:
message = ""
raise TemplatesError(
_("error in template %s")%self.nameTemplate + "\n" + \
12 years ago
_("error, template term '%s'")%str(self.functText) + \
" " + message)
def applyFuncTemplate(self, textTemplate, nameTemplate):
"""Применяет функции к тексту шаблона"""
# Локальные переменные
localVars = {}
# Имя обрабатываемого шаблона
self.nameTemplate = nameTemplate
# Регулярное выражение для поиска функции в шаблоне
reFunc = self._reFunc
resS = reFunc.search(textTemplate)
textTemplateTmp = textTemplate
flagIniFunc = False
writeIniFunc = False
while resS:
mark = textTemplateTmp[resS.start():resS.end()]
self.functText = mark[self._deltVarStart:-self._deltVarEnd]
funcName, spl, funcEnd = self.functText.partition("(")
if funcName in self.namesTemplateFunction:
# аргументы функции - '(' аргументы ')'
funArgv = funcEnd.rpartition(")")[0]
# вызов функции шаблона
textTemplateTmp = self.templateFunction[funcName](self, funArgv,
resS, localVars,
12 years ago
textTemplateTmp,
nameTemplate)
resS = reFunc.search(textTemplateTmp)
if funcName == "ini":
if "," in funArgv:
writeIniFunc = True
flagIniFunc = True
else:
self.raiseErrTemplate(
12 years ago
_("function of templates '%s' not found")\
%str(self.functText))
if flagIniFunc:
# Очистка файла в случае его ошибочного чтения
if not self.prevDictIni and os.path.exists(self.fileConfigIni):
FD = open(self.fileConfigIni, "r+")
FD.truncate(0)
FD.seek(0)
FD.close()
# Если конф. файл модифицирован шаблоном
curTime = self.getTimeFile(self.fileConfigIni)
if curTime != self.timeIni:
# Считаем переменные из конф. файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
self.currDictIni.update(self.prevDictIni)
self.timeIni = curTime
# Если словари переменных не совпадают
if self.prevDictIni != self.currDictIni:
# Запишем переменные в конфигурационный файл
# Создание объекта парсера
config = ConfigParser(strict=False)
config.read(self.fileConfigIni, encoding="utf-8")
comment_block = "\n".join(takewhile(lambda x:x.startswith("#"),
readLinesFile(self.fileConfigIni)))
for k, v in self.currDictIni.items():
if "." in k:
sect, op, k = k.rpartition('.')
if v is None:
if config.has_section(sect):
config.remove_option(sect, k)
else:
if not config.has_section(sect):
config.add_section(sect)
config[sect][k] = v
for section in filter(lambda x: not config[x],
config.sections()):
config.remove_section(section)
with open(self.fileConfigIni,'wb') as f:
if comment_block:
f.write(comment_block)
f.write('\n\n')
config.write(f)
try:
oMode = getModeFile(self.fileConfigIni, mode="mode")
if oMode != self.modeConfigIni:
os.chmod(self.fileConfigIni, self.modeConfigIni)
except Exception:
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 not self.uid in (uid,PORTAGEUID) or \
not self.gid in (gid,PORTAGEGID):
try:
os.chown(self.fileConfigIni, self.uid, self.gid)
except OSError as e:
self.setError(_("error") + " " +\
"'chown %d:%d %s'"%(self.uid, self.gid,
self.fileConfigIni))
return textTemplateTmp
class ChangedFiles:
"""
Object which contains modified files and package
"""
FILE_MODIFIED,FILE_REMOVED,DIR_CREATED,DIR_REMOVED,DIR_EXISTS = 0,1,2,3,4
def __init__(self):
self.data = {}
self.pkgs = set()
def _createEntry(self,fn):
if not fn in self.data:
self.data[fn] = []
def addObj(self,filename,action,pkg):
self._createEntry(filename)
self.data[filename].append((pkg,action))
self.pkgs.add(pkg)
def getPkgs(self):
return self.pkgs
def getPkgFiles(self,pkg):
return map(lambda x:(x[0],x[1][0][1]),
filter(lambda x:x[1],
map(lambda x:(x[0],filter(lambda x:x[0] == pkg,x[1])),self.data.items())))
# modes work with configuration file
# T_ORIGIN - work with original config file
# T_CFG - work with last ._cfg file
# T_NEWCFG - new content has difference with (create new ._cfg file)
T_ORIGIN, T_CFG, T_NEWCFG = 0,1,2
class Template(_file,_terms,_warning,xmlShare,templateFormat,_shareTemplate):
"""Класс для работы с шаблонами
На вход 2 параметра: объект хранения переменных, имя сервиса - не
обязательный параметр
"""
# Название файла шаблона директории
templDirNameFile = ".calculate_directory"
_titleList = ("Modified", "Processed template files" + ":")
titleEnd = "For modify this file, create %(conf_path)s.clt template."
protectPaths = []
allContents = {}
if "CONFIG_PROTECT" in os.environ:
protectPaths = ["/etc"] + filter(lambda x: x.strip(),
os.environ["CONFIG_PROTECT"].split(" "))
protectPaths = map(lambda x: os.path.normpath(x), protectPaths)
@classmethod
def removeComment(cls,text):
comment_symb = '#"'
re_comment = re.compile('(?:<!--|[{symb}]-*)\n'
'[{symb}]? {modified} .*\n'
'[{symb}]? {processed}\n'
'([{symb}]? /.*\n'
')+[{symb}]? {endtitle}.*\n'
r'(-->|[{symb}]-*)\n'.format(
modified=cls._titleList[0],
processed=cls._titleList[1],
endtitle=cls.titleEnd%{'conf_path':'.*'},
symb='"#'
))
return re_comment.sub('',text)
def hasError(self):
return self.getError() or self.bHasError
def __init__(self, objVar, servDir=False, dirsFilter=[], filesFilter=[],
cltObj=True, cltFilter=True, printWarning=True,
printSUCCESS=lambda x:x,printWARNING=lambda x:x,
printERROR=lambda x:x,askConfirm=lambda x:x,
userProfile=False,dispatchConf=None):
# совместимость с вызовами из модулей предыдущих версий
self.translator = RegexpLocalization("cl_templates3")
if userProfile and objVar:
objVar.Set('cl_protect_use_set','off',force=True)
self.protectPaths = objVar.Get('cl_config_protect')
self.dispatchConf = dispatchConf
self.changedFiles = ChangedFiles()
self.printSUCCESS = printSUCCESS
self.printERROR = printERROR
self.postmergePkgs = []
self.postmergeFile = "/var/lib/calculate/-postmerge"
self.bHasError = False
11 years ago
if printERROR:
def newSetError(s):
self.printERROR(s)
self.bHasError = True
self.setError = newSetError
self.printWARNING = printWARNING
12 years ago
self.askConfirm = askConfirm
self.stop = 0
self.cltObj = None
self.functObj = None
# Предупреждения
12 years ago
#self.warning = []
# Печатать ли предупреждения о корневых шаблонах без cl_name==pkg
self.printWarning = printWarning
# Необрабатываемые директории
self.dirsFilter = dirsFilter
# Необрабатываемые файлы
self.filesFilter = filesFilter
_file.__init__(self)
# Словарь для создания объектов новых классов по образцу
self.newObjProt = {'proftpd':'apache'}
# Заголовок title
self.__titleHead = "--------------------------------------\
----------------------------------------"
self._titleBody = ""
12 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(
"#\?(?P<rTerm>(?:[a-z0-9_]+\.)?[a-zA-Z0-9\-_]+)\
(?P<func>\((%s+|)\))?\
(?P<lTerm>[\>\<\=\!\&\|]+\
[\>\<\=\!\|\&\(\)%s]*)#\
\n*(?P<body>.+?)\n*#(?P=rTerm)#(?P<end>[ ,\t]*\n?)"\
%(self._reFunctionArgvText, self._reFunctionArgvInSquareBrackets),
re.M|re.S)
# Объект с переменными
self.objVar = objVar
self.recalculateBaseDir()
# Последняя часть директории шаблона (имя сервиса: samba, mail)
self._servDir = servDir
if self._servDir:
if self._servDir[0] != "/":
self._servDir = "/" + self._servDir
if self._servDir[-1] != "/":
self._servDir += "/"
self._servDir = os.path.split(self._servDir)[0]
# Созданные директории
self.createdDirs = []
# Примененные файлы
self.filesApply = []
# номер обрабатываемого файла
self.numberProcessTempl = 0
# имя текущей программы
_nameProgram = self.objVar.Get("cl_name").capitalize()
# версия текущей программы
_versionProgram = self.objVar.Get("cl_ver")
# имя и версия текущей программы
self.programVersion = "%s %s"%(_nameProgram, _versionProgram)
# Словарь директорий с количеством файлов шаблонов
self.dictTemplates = {}
# Общее количество шаблонов
self.allTemplates = 0
# Объект функций шаблона
self.functObj = templateFunction(self.objVar)
self.functObj.printSUCCESS = self.printSUCCESS
self.functObj.printWARNING = self.printWARNING
self.functObj.printERROR = self.printERROR
11 years ago
if self.printERROR:
self.functObj.setError = self.printERROR
12 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
self.cltObj = templateClt(self.objVar,self.postmergePkgs,
printSUCCESS=self.printSUCCESS,
printERROR=self.printERROR,
12 years ago
printWARNING=self.printWARNING,
askConfirm=self.askConfirm)
elif cltObj:
# Объект templateClt
self.cltObj = cltObj
else:
# Объект templateClt
self.cltObj = False
14 years ago
# Фильтровать ли шаблоны clt по конфигурационным файлам обычных шаблонов
self.cltFilter = cltFilter
# autoupdate файлы
self.autoUpdateFiles = []
self.autoUpdateDirs = []
self.protectedFiles = self.objVar.Get('main.cl_env_path') + \
[self.functObj.fileConfigIni]
# список выполненных файлов
self.executedFiles = []
def recalculateBaseDir(self):
"""Recalculate basedir and homedir"""
# Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
self._baseDir = pathJoin(self.objVar.Get("cl_chroot_path"),
self.objVar.Get("cl_root_path"))
self._baseDir = os.path.normpath(self._baseDir)
self.uid, self.gid, self.homeDir = self.getDataUser()
# Домашняя директория, плюс базовая директория
self.homeDir = pathJoin(self._baseDir, self.homeDir)
if self.cltObj:
self.cltObj.recalculateBaseDir()
if self.functObj:
self.functObj.recalculateBaseDir()
def _addFile(self,filesApl,pkg=None):
"""
Add files to ChangedFiles
"""
for fn in filesApl:
if os.path.exists(fn):
self.changedFiles.addObj(fn,ChangedFiles.FILE_MODIFIED,
pkg or self.functObj.currentBelong)
else:
self.changedFiles.addObj(fn,ChangedFiles.FILE_REMOVED,
pkg or self.functObj.currentBelong)
def executeTemplate(self, code, execPath):
"""Execute template"""
p = process(execPath,lang=self.objVar.Get('os_locale_locale'),
envdict=dict(os.environ))
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)
12 years ago
self.printSUCCESS(line.strip())
p.pipe.wait()
if p.success():
self.executedFiles.append((code,execPath))
if p.readerr():
for line in p.readerr().split('\n'):
if line:
line = self.translator.translate(line)
12 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)
12 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
typeTemplate = "bin"
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:
14 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)
os.chown(nameDir, dUid, dGid)
except:
12 years ago
self.setError(_("Failed to create the directory: ")
+ nameDir)
return False
try:
if dMode:
os.mkdir(dirName, dMode)
os.chmod(dirName, dMode)
else:
os.mkdir(dirName)
os.chown(dirName, dUid, dGid)
createDirs.append(dirName)
except:
12 years ago
self.setError(_("Failed to create the directory: ")
+ dirName)
14 years ago
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]
varValue = ""
try:
12 years ago
varValue = self.objVar.Get(varName)
if not varValue:
varValue = ""
else:
varValue = str(varValue)
except DataVarsError, e:
raise TemplatesError(_("error in template %s")%nameTemplate
+ "\n" + str(e))
textTemplateTmp = textTemplateTmp.replace(mark, varValue)
resS = self._reVar.search(textTemplateTmp)
return textTemplateTmp
def applyTermsTemplate(self,textTemplate,nameTemplate):
""" Применяет условия, к условным блокам текста
"""
def function(text):
"""Функция обработки функций в заголовке"""
return self.applyFuncTemplate(text, nameTemplate)
textTerm = ""
resS = self._reTermBloc.search(textTemplate)
textTemplateTmp = textTemplate
while resS:
mark = resS.group(0)
body = resS.group("body")
end = resS.group("end")
parent = resS.group("func")
if not parent:
parent = ""
term = resS.group("rTerm") + parent +\
resS.group("lTerm")
12 years ago
if self._equalTerm(term, _("invalid template content: ")+\
nameTemplate, function):
textTemplateTmp = textTemplateTmp.replace(mark, body+end)
else:
textTemplateTmp = textTemplateTmp.replace(mark, "")
resS = self._reTermBloc.search(textTemplateTmp)
return textTemplateTmp
def getNeedTemplate(self, fileTemplate):
"""Применяем правила к названию файла"""
dirP,fileP = os.path.split(fileTemplate)
if fileP:
spFile = fileP.split("?")
realFileName = spFile[0]
if len(spFile)>1:
flagTrue = False
for term in spFile[1:]:
12 years ago
if self._equalTerm(term, _("invalid template name: ")+\
fileTemplate):
flagTrue = True
break
if flagTrue:
return True
else:
return False
else:
return True
else:
12 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)
if len(configPath)>lenBaseDir and\
configPath[:lenBaseDir] == self._baseDir:
configPath = configPath[lenBaseDir:]
if configPath.startswith(protectPath + "/"):
flagFoundPath = True
break
if flagFoundPath:
origConfigPath = PkgContents.reCfg.sub("/",configPath)
commentList = commentList +\
[self.titleEnd%{'conf_path':origConfigPath}]
if comment:
commentFirst = comment
commentInsert = comment
commentLast = comment
flagList = False
# В случае открывающего и закрывающего комментария
if type(comment) == types.TupleType and len(comment) == 2:
commentFirst = comment[0]
commentInsert = ""
commentLast = comment[1]
flagList = True
if flagList:
self._titleBody = commentFirst + "\n"
else:
self._titleBody = commentFirst + self.__titleHead + "\n"
z = 0
flagFirst = True
for com in list(self._titleList) + [""]*(len(commentList)):
if com:
if flagFirst:
self._titleBody += commentInsert + " " + com + " "+\
self.programVersion + "\n"
flagFirst = False
else:
self._titleBody += commentInsert + " " + com + "\n"
else:
self._titleBody += commentInsert + " " +\
commentList[z] + "\n"
z += 1
if flagList:
self._titleBody += commentLast +"\n"
else:
self._titleBody += commentLast + self.__titleHead + "\n"
return self._titleBody
else:
return ""
def changeMergePackage(self,package):
return True
def numberAllTemplates(self, number):
"""Количество шаблонов
Вызов происходит перед наложением шаблонов
в момент вызова в number находится количество обрабатываемых файлов
Наследуемая функция
Используется для отображения прогресса при наложениии шаблонов
"""
return True
def numberProcessTemplates(self, number):
"""Номер текущего обрабатываемого шаблона
Вызов происходит при наложении шаблона
в момент вызова в number находится номер обрабатываемого шаблона
Наследуемая функция
Используется для отображения прогресса при наложениии шаблонов
"""
return True
11 years ago
def templateModify(self):
12 years ago
"""
Files which created by apping templates
"""
return True
12 years ago
def fixNameFileConfig(self,origfilename):
"""Support ._cfg0000 files for postinst"""
#if self.objVar.Get('cl_ebuild_phase') != 'postinst':
# return origfilename
12 years ago
directory,filename = os.path.split(origfilename)
i = 0
for i in range(0,9999):
if not os.path.exists(os.path.join(directory,
"._cfg%04d_%s"%(i,filename))):
if i:
filename = os.path.join(directory,
"._cfg%04d_%s"%(i-1,filename))
if not os.path.exists(origfilename):
return origfilename
#origstat = os.stat(origfilename)[stat.ST_CTIME]
#newstat = os.stat(filename)[stat.ST_CTIME]
self.configMode = T_CFG
return filename
12 years ago
return origfilename
return origfilename
def getHeaderText(self, text):
textLines = text.splitlines()
paramLine = ""
if textLines:
textLine = textLines[0]
rePar = re.compile(\
"\s*#\s*calculate\s+\\\\?|\s*#\s*calculate\\\\?$",re.I)
reP = rePar.search(textLine)
if reP:
reL = False
reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
reLs = reLns.search(text)
if reLs:
reL = reLs
paramLine = text[reP.end():reLs.end()]
paramLine = paramLine.replace("\\"," ")
else:
reLn = re.compile("\n")
reL = reLn.search(text)
paramLine = textLine[reP.end():]
return paramLine
def getTemplateDirs(self, dirsTemplates):
"""Check template variable cl_name in first directories and files"""
14 years ago
skipDirs = []
skipTemplates = []
debug = False
for dirsTemplate in dirsTemplates:
filesAndDirs = map(lambda x: os.path.join(dirsTemplate,x),
listDirectory(dirsTemplate))
for dirFile in filesAndDirs:
if os.path.isdir(dirFile):
flagDir = True
templatePath = os.path.join(dirFile,self.templDirNameFile)
if not os.path.isfile(templatePath):
skipDirs.append(dirFile)
continue
else:
flagDir = False
templatePath = dirFile
if os.path.isfile(templatePath):
if self.getFileType(templatePath) == "bin":
skipTemplates.append(dirFile)
else:
textTemplate = open(templatePath).read()
if textTemplate:
headerLine = self.getHeaderText(textTemplate)
if headerLine:
if not debug and \
not "cl_name==" in headerLine and \
not "ac_" in headerLine:
if flagDir:
skipDirs.append(dirFile)
else:
skipTemplates.append(dirFile)
else:
if flagDir:
skipDirs.append(dirFile)
else:
skipTemplates.append(dirFile)
else:
skipTemplates.append(dirFile)
if skipDirs or skipTemplates:
# print warning
from cl_print import color_print
self.printWARNING(_("No conditions for checking the value of "
"an action variable"))
skipDirTemplates = []
for skipDir in skipDirs:
skipTempl = os.path.join(skipDir,self.templDirNameFile)
if os.path.isfile(skipTempl):
skipDirTemplates.append(skipTempl)
if skipTemplates or skipDirTemplates:
11 years ago
self.printWARNING(_("Skipped templates:"))
for skipTemplate in skipTemplates + skipDirTemplates:
11 years ago
self.printWARNING(" "*6 + skipTemplate)
if skipDirs:
11 years ago
self.printWARNING(_("Skipped directories:"))
for skipDir in skipDirs:
11 years ago
self.printWARNING(" "*6 + skipDir)
self.printWARNING("")
self.printWARNING(_("Headers of directory templates and headers "
"of files on the first level should include "
"an action variable"))
11 years ago
self.printWARNING(_("Example:"))
self.printWARNING("# Calculate ac_install_merge==on")
return skipDirs + skipTemplates
12 years ago
def applyTemplates(self,progress=True,rerun=True):
"""Применяет шаблоны к конфигурационным файлам"""
def createDictTemplates(path, prefix, dictTemplates):
"""Создает словарь {"директория":"кол-во шаблонов" ...}
и считает общее количество шаблонов
"""
# Количество шаблонов
self.allTemplates += 1
dirTemplate = os.path.split(path)[0]
while(True):
if dirTemplate in dictTemplates.keys():
dictTemplates[dirTemplate] += 1
else:
dictTemplates[dirTemplate] = 1
if dirTemplate == prefix:
break
dirTemplate = os.path.split(dirTemplate)[0]
return dictTemplates
self.clearErrors()
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()
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:
14 years ago
return (self.createdDirs, self.filesApply)
# check cl_name in first template dirs and files
skipTemplates = self.getTemplateDirs(dirsTemplatesExists)
#if not os.environ.get("EBUILD_PHASE","") and progress:
# for dirTemplate in dirsTemplatesExists:
# scanObj.scanningDirectory(dirTemplate)
# Считаем количество шаблонов clt
if self.cltObj:
# Считаем количество шаблонов clt
self.cltObj.countsNumberTemplates()
# не считать количество файлов в объекте self.cltObj
self.cltObj.checkNumberTemplate = False
# начальный номер clt шаблона
self.cltObj.numberProcessTempl = self.allTemplates
# метод показывающий номер clt шаблона
self.cltObj.numberProcessTemplates = self.numberProcessTemplates
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',
'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:
12 years ago
break
if self.cltObj and not self.stop:
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(
**category[0]))
for filename in pkgContents.content.keys():
if not filename in self.cltObj.filterApplyTemplates:
self.cltObj.filterApplyTemplates[filename] = []
self.cltObj.filterApplyTemplates[filename].append(pkg)
for filename,pkgs in self.changedFiles.data.items():
filename = PkgContents.reCfg.sub("/",filename)
if not filename in self.cltObj.filterApplyTemplates:
self.cltObj.filterApplyTemplates[filename] = []
pkgs = filter(lambda x:not x in \
self.cltObj.filterApplyTemplates[filename],
map(lambda x:x[0],pkgs))
self.cltObj.filterApplyTemplates[filename].extend(pkgs)
12 years ago
self.cltObj.applyTemplates()
self.stop = self.stop or self.cltObj.stop
if not self.stop and ((self.objVar.Get('cl_merge_pkg') or \
self.objVar.Get('cl_action') in ("sync","domain","undomain")) and \
12 years ago
self.objVar.Get('cl_merge_pkg_new')):
self.objVar.Set('cl_root_path',
self.objVar.Get('cl_root_path_next'),force=True)
self.recalculateBaseDir()
12 years ago
self.objVar.Set('cl_merge_pkg_pass',list(
set(self.objVar.Get('cl_merge_pkg_pass'))|
12 years ago
set(self.objVar.Get('cl_merge_pkg'))|
12 years ago
set(self.objVar.Get('cl_merge_pkg_new'))),force=True)
self.objVar.Set('cl_merge_pkg',
self.objVar.Get('cl_merge_pkg_new'),force=True)
self.objVar.Set('cl_merge_pkg_new',[],force=True)
createdDirs = self.createdDirs
filesApply = self.filesApply
12 years ago
self.changeMergePackage(self.objVar.Get('cl_merge_pkg'))
12 years ago
self.applyTemplates(rerun=False)
createdDirs.extend(self.createdDirs)
filesApply.extend(self.filesApply)
self.filesApply = filesApply
self.createdDirs = createdDirs
12 years ago
if rerun and self.stop != TemplatesInterrupt.ABORT:
if self.cltObj:
self.queueExecute.extend(self.cltObj.queueExecute)
for processor,text,nameTemplate in self.queueExecute:
if not self.executeTemplate(text,processor):
self.setError(_("Failed to execute") + _(": ") +
nameTemplate)
return False
self.queueExecute = []
self.filesApply = list(set(self.filesApply))
if self.objVar.Get('cl_protect_use_set') == 'on':
self.updateProtectedFiles()
if self.objVar.Get('cl_verbose_set') == 'on' and \
self.filesApply:
self.verboseOutput(
filter(lambda x:not x.endswith('/ini.env'),
self.filesApply))
self.objVar.Set('cl_merge_pkg_pass',[],force=True)
self.objVar.Set('cl_merge_pkg_new',[],force=True)
self.objVar.Set('cl_merge_pkg',[],force=True)
return (self.createdDirs, self.filesApply)
def verboseOutput(self,filesApply):
"""
Verbose output applied templates
"""
if not filesApply:
return
self.printWARNING(_("Calculate Utilities have changed files")+_(":"))
reGrey = re.compile(r"\._cfg\d{4}_")
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 \
fn.startswith(rootPath):
fn = fn[len(rootPath)+1:]
if reGrey.search(fn):
self.printSUCCESS("&nbsp;"*5 + \
"<font color=\"dark gray\">%s</font>"%fn)
else:
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 = {}
for pkg in list(set(filter(None,list(self.changedFiles.getPkgs())+
self.objVar.Get('cl_merge_pkg')))):
category = isPkgInstalled(pkg,prefix=chrootPath)
if category:
pkgContents = PkgContents("{CATEGORY}/{PF}".format(
**category[0]),prefix=chrootPath)
for filename,action in self.changedFiles.getPkgFiles(pkg):
if filename in self.protectedFiles:
pkgContents.removeObject(filename)
continue
if action in (ChangedFiles.FILE_MODIFIED,
ChangedFiles.DIR_CREATED,
ChangedFiles.DIR_EXISTS):
pkgContents.addObject(filename)
elif action in (ChangedFiles.FILE_REMOVED,
ChangedFiles.DIR_REMOVED):
pkgContents.removeObject(filename)
files = set(map(lambda x:pathJoin(chrootPath,x),
pkgContents.content.keys()))
if (self.objVar.Get('cl_dispatch_conf') != 'usenew' and
self.objVar.Get('cl_autoupdate_set') != "on"):
notUpdate = files - set(self.autoUpdateFiles)
files &= set(self.autoUpdateFiles)
for filename in list(notUpdate&set(cfgs.keys())):
if hashlib.md5(readFile(filename)).hexdigest() == \
hashlib.md5(readFile(
cfgs[filename][0][1])).hexdigest():
files.add(filename)
for filename in list(files&set(cfgs.keys())):
# get ctime from orig filename
#if os.path.exists(filename):
# ctime = os.stat(filename).st_ctime
#else:
# ctime = 0
# if orig filename older that .cfg
cfgs[filename].sort(reverse=True)
#if ctime < cfgs[filename][0][0]:
try:
open(filename,'w').write(
readFile(cfgs[filename][0][1]))
except Exception as e:
self.printERROR(str(e))
self.printWARNING(
_("Failed to copy {ffrom} to {fto}").format(
ffrom=cfgs[filename][0][1],fto=filename))
continue
autoUpdateDict[cfgs[filename][0][1]] = filename
for mtime,fn in cfgs[filename]:
try:
os.unlink(fn)
except Exception as e:
self.printWARNING(_("Failed to remove %s")%fn)
try:
pkgContents.writeContents()
except IOError as e:
self.printWARNING(_("Failed to modify %s contents")%pkg)
self.filesApply = map(lambda x:autoUpdateDict.get(x,x),self.filesApply)
if filter(lambda x:"._cfg" in x, self.filesApply):
if self.objVar.Get('cl_ebuild_phase') != '':
self.printWARNING(_("Some config files need updating. "
"Perform run dispatch-conf."))
11 years ago
if self.dispatchConf and \
self.objVar.Get('cl_dispatch_conf') == 'dispatch' and \
self.objVar.Get('cl_ebuild_phase') == '':
self.dispatchConf(self.filesApply)
def scanningTemplates(self, scanDir, prefix=None, flagDir=False,
optDir={}, skipTemplates=[]):
"""Сканирование и обработка шаблонов в директории scanDir"""
ret = True
if not prefix:
prefix = os.path.realpath(scanDir)
if not flagDir:
# проверка корневой директории
retDir = self.processingDirectory(scanDir, scanDir, optDir)
if retDir is None:
return None
elif retDir is False:
return False
pathDir, objHead = retDir
optDir["path"] = pathDir
if not objHead is True:
if objHead.typeAppend == "skip":
# Установка опции пропуска директории
optDir["skip"] = True
if ("autoupdate" in objHead.params or
self.objVar.Get('cl_autoupdate_set') == 'on'):
optDir["autoupdate"] = True
if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]):
if not os.access(scanDir,os.R_OK|os.X_OK):
self.printWARNING(_("Failed to read templates directory %s")%
scanDir)
return False
for fileOrDir in sorted(listDirectory(scanDir)):
absPath = os.path.join(scanDir,fileOrDir)
if skipTemplates and absPath in skipTemplates:
continue
stInfo = os.lstat(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 = {}
pathDir, objHead = retDir
optNextDir["path"] = pathDir
if not objHead is True:
if objHead.typeAppend == "skip":
# Установка опции пропуска директории
optNextDir["skip"] = True
if ("autoupdate" in objHead.params or
self.objVar.Get('cl_autoupdate_set') == 'on'):
12 years ago
optNextDir["autoupdate"] = True
ret = self.scanningTemplates(absPath, prefix, True,
optNextDir)
if ret is False:
break
12 years ago
except TemplatesInterrupt as e:
if e.isInterrupt():
self.stop = e.status()
return False
else:
11 years ago
self.clearErrors()
12 years ago
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]
# файл в системе без условий
nameFileConfig = "/".join(map(lambda x:x.split("?")[0],\
nameFileConfig.split("/")))
# Записываем в переменную обрабатываемый файл
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 то пропуск дир."""
# Файл шаблона директории
if not os.access(path,os.R_OK|os.X_OK):
self.printWARNING(_("Failed to read templates directory %s")%path)
return None
dirInfoFile = os.path.join(path, self.templDirNameFile)
newDir = pathJoin(self._baseDir, path.partition(prefix)[2])
newDir = "/".join(map(lambda x:x.split("?")[0], newDir.split("/")))
# Применяем шаблон
14 years ago
pathDir, objHeadDir, createdDirs =\
self.getApplyHeadDir(newDir, dirInfoFile, opt)
14 years ago
if createdDirs:
self.createdDirs += createdDirs
if os.path.isfile(pathDir):
12 years ago
self.printWARNING(_("{dirpath} is a file").format(dirpath=pathDir))
self.printWARNING(_("templates in {tempath} are skipped"
).format(tempath=path))
return None
if objHeadDir:
14 years ago
return pathDir, objHeadDir
else:
if self.getError():
return False
# Добавление количества файлов в пропущенной директории
if path in self.dictTemplates.keys():
self.numberProcessTempl += self.dictTemplates[path]
return None
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:
for wrongPkg in (x for x in mergePkgs + postmergePkgs \
if not self.functObj.checkCorrectPkgName(x)):
self.printWARNING(
_("Wrong package '%s' for 'merge' in the template")%
wrongPkg + _(": ") + templateDirFile)
if self.objVar.Get('cl_ebuild_phase') == 'postinst':
for pkg in postmergePkgs:
if not pkg in self.objVar.Get('cl_merge_pkg_pass'):
self.objVar.Get('cl_merge_pkg_pass').append(pkg)
if not pkg in self.postmergePkgs:
try:
with open(self.postmergeFile,"a") as f:
f.write("%s\n"%pkg)
self.postmergePkgs.append(pkg)
except:
self.printWARNING(
10 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 \
not pkg in self.objVar.Get('cl_merge_pkg_pass') and \
not pkg in self.objVar.Get('cl_merge_pkg'):
self.objVar.Get('cl_merge_pkg_new').append(pkg)
def getApplyHeadDir(self, newDir, templateDirFile, optDir):
"""Применяет шаблон к директории (права, владелец, и.т. д)"""
def function(text):
"""Функция обработки функций в заголовке"""
return self.applyFuncTemplate(text, templateDirFile)
def chownConfDir(nameDirConfig, uid, gid, nameFileTemplate):
"""Изменение владельца конфигурационной директории"""
try:
14 years ago
os.chown(nameDirConfig, uid, gid)
except Exception as e:
if hasattr(e,'errno') and e.errno == 13 and \
"var/calculate/remote" in nameDirConfig:
return True
import pwd, grp
try:
userName = pwd.getpwuid(uid).pw_name
except:
userName = str(uid)
try:
groupName = grp.getgrgid(gid).gr_name
except:
groupName = str(gid)
owner = userName + ":" + groupName
self.setError(_("Failed to apply template file %s")\
%nameFileTemplate)
self.setError(_("error") + " " +\
14 years ago
"'chown %s %s'"%(owner, nameDirConfig))
return False
return True
applyDir = newDir
# Родительская директория
if optDir.get("path"):
path = optDir["path"]
else:
if applyDir == self._baseDir:
path = os.path.dirname(self._baseDir)
else:
path = os.path.split(applyDir)[1]
path = pathJoin(self._baseDir, path)
if not os.path.exists(templateDirFile):
if applyDir != self._baseDir:
applyDir = os.path.join(path, os.path.split(applyDir)[1])
# Фильтрация шаблонов по названию директории
realPath = os.path.join("/",applyDir.partition(self._baseDir)[2])
if realPath in self.dirsFilter:
14 years ago
return ("", False, [])
14 years ago
# Создаем директорию если необходимо
14 years ago
crDirs = self.createDir(applyDir, False, self.uid, self.gid)
if not crDirs:
return ("", False, [])
if "autoupdate" in optDir:
self.autoUpdateDirs.append(applyDir)
14 years ago
if crDirs is True:
return (applyDir, True, [])
else:
return (applyDir, True, crDirs)
try:
FD = open(templateDirFile)
textTemplate = FD.readline().rstrip()
buf = textTemplate
while buf and textTemplate.endswith('\\'):
buf = FD.readline()
textTemplate = "%s %s"%(textTemplate[:-1],buf.rstrip())
FD.close()
except:
self.setError(_("Failed to open the template") + _(": ") +
templateDirFile)
14 years ago
return ("", False, [])
12 years ago
headerLine = self.getHeaderText(textTemplate)
if headerLine:
moduleParam = filter(lambda x:x.startswith('env='),
12 years ago
headerLine.split())
if moduleParam:
self.objVar.defaultModule = moduleParam[0].partition('=')[2]
try:
varModule = importlib.import_module(
"calculate.%s.variables"%self.objVar.defaultModule)
except (ImportError, AttributeError),e:
return ("", False, [])
# Заменяем переменные на их значения
textTemplate = self.applyVarsTemplate(textTemplate, templateDirFile)
14 years ago
# Заменяем функции на их значения
textTemplate = self.applyFuncTemplate(textTemplate, templateDirFile)
# Обработка заголовка
14 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)
14 years ago
return ("", False, [])
# add packeges for reconfigure
self._processMergePostmerge(objHead.params, templateDirFile)
# Пропускаем директорию
if objHead.typeAppend == "skip":
applyDir = path
14 years ago
return (applyDir, objHead, [])
# Изменяем название родительской директории
if "path" in objHead.params:
path = objHead.params['path']
if path and path[0] == "~":
# Получаем путь с заменой ~ на директорию пользователя
path = os.path.join(self.homeDir,
path.partition("/")[2],"")[:-1]
elif not path or path and path[0] != "/":
self.setError(_("Wrong value 'path' in the template") +
_(": ") + templateDirFile)
14 years ago
return ("", False, [])
else:
path = pathJoin(self._baseDir, path)
# Изменяем название директории
if "name" in objHead.params:
nameDir = objHead.params['name']
if "/" in nameDir or nameDir == ".." or nameDir == ".":
self.setError(_("Wrong value 'name' in the template") +
_(": ") + templateDirFile)
14 years ago
return ("", False, [])
# Новый путь к директории
applyDir = pathJoin(path, nameDir)
else:
applyDir = pathJoin(path, os.path.split(applyDir)[1])
# Фильтрация шаблонов по названию директории
realPath = os.path.join("/",applyDir.partition(self._baseDir)[2])
if realPath in self.dirsFilter:
14 years ago
return ("", False, [])
# Удаляем директорию
if objHead.typeAppend == "remove":
if os.path.isdir(applyDir):
self.changedFiles.addObj(applyDir,ChangedFiles.DIR_REMOVED,
self.functObj.currentBelong)
# удаляем директорию
try:
14 years ago
removeDir(applyDir)
except:
12 years ago
self.setError(_("Failed to delete the directory: ") +\
applyDir)
14 years ago
return ("", False, [])
# Очищаем директорию
if objHead.typeAppend == "clear":
if os.path.isdir(applyDir):
for rmPath in os.listdir(applyDir):
removePath = pathJoin(applyDir, rmPath)
if os.path.isdir(removePath):
# удаляем директорию
try:
removeDir(removePath)
except:
12 years ago
self.setError(
_("Failed to delete the directory: ") +\
removePath)
else:
try:
os.unlink(removePath)
except:
12 years ago
self.setError(
_("Failed to delete: ") + removePath)
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:
return ("", False, [])
if not crDirs is True:
createdDirs += crDirs
else:
try:
os.chmod(applyDir, mode)
except:
10 years ago
self.setError(_("Failed to change the mode for "
"the directory: ") +applyDir)
else:
self.setError(_("Wrong value 'chmod' in the template") +
_(": ") + templateDirFile)
14 years ago
return ("", False, [])
# chown - изменяем владельца и группу
if "chown" in objHead.params:
owner = objHead.params['chown']
if owner:
if ":" in owner:
strUid, strGid = owner.split(":")
import pwd
uid = self.getUidFromPasswd(strUid)
try:
uid = pwd.getpwnam(strUid).pw_uid
except:
12 years ago
self.setError(_("No such user on the system: ")
+ strUid)
self.setError(_("Wrong value 'chown' in the template")+
_(": ") + templateDirFile)
14 years ago
return ("", False, [])
gid = self.getGidFromGroup(strGid)
try:
import grp
gid = grp.getgrnam(strGid).gr_gid
except:
12 years ago
self.setError(_("Group not found on the system: ")
+strGid)
self.setError(
_("Wrong value 'chown' in the template") +
_(": ") + templateDirFile)
14 years ago
return ("", False, [])
if not os.path.exists(applyDir):
14 years ago
crDirs = self.createDir(applyDir, False, uid, gid)
if not crDirs:
return ("", False, [])
if not crDirs is True:
createdDirs += crDirs
else:
if not chownConfDir(applyDir, uid, gid,
templateDirFile):
14 years ago
return ("", False, [])
else:
self.setError(_("Wrong value 'chown' in the template") +
_(": ") + templateDirFile)
14 years ago
return ("", False, [])
else:
12 years ago
self.setError(_("Wrong value 'chown' in the template") +
_(": ") + templateDirFile)
14 years ago
return ("", False, [])
14 years ago
else:
# Устанавливаем владельцем директории, пользователя по умолчанию
# (переменная шаблона ur_login)
if os.path.exists(applyDir):
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 chownConfDir(applyDir, self.uid, self.gid,
templateDirFile):
14 years ago
return ("", False, [])
14 years ago
else:
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:
return ("", False, [])
if not crDirs is True:
createdDirs += crDirs
if not objHead:
applyDir = ""
if applyDir:
if ("autoupdate" in optDir or "autoupdate" in objHead.params ) and \
12 years ago
not self.objVar.Get('cl_merge_pkg_pass'):
self.autoUpdateDirs.append(applyDir)
14 years ago
return (applyDir, objHead, createdDirs)
def getUidFromPasswd(self,strUid):
"""Get uid by username from chroot passwd file"""
passwdFile = os.path.join(self._baseDir,'etc/passwd')
if os.path.exists(passwdFile):
mapUid = dict(
filter(lambda x:x and len(x)>1 and x[0] and x[1],
map(lambda x:x.split(':')[0:3:2],
filter(lambda x:not x.startswith('#'),
open(passwdFile,'r')))))
if strUid in mapUid:
return int(mapUid[strUid])
return None
def getGidFromGroup(self,strGid):
"""Get gid by groupname from chroot group file"""
groupFile = os.path.join(self._baseDir,'etc/group')
if os.path.exists(groupFile):
mapGid = dict(
filter(lambda x:x and len(x)>1 and x[0] and x[1],
map(lambda x:x.split(':')[0:3:2],
filter(lambda x:not x.startswith('#'),
open(groupFile,'r')))))
if strGid in mapGid:
return int(mapGid[strGid])
return None
def checkOnNewConfigName(self,pathFile):
"""
Check on need update and return pathFile
"""
# if file in PROTECT_MASK or not in PROTECT
chrootPath = self.objVar.Get('cl_chroot_path')
if not filter(pathFile.startswith,
map(lambda x:pathJoin(chrootPath,x),
self.objVar.Get('cl_config_protect'))) or \
filter(pathFile.startswith,
map(lambda x:pathJoin(chrootPath,x),
self.objVar.Get('cl_config_protect_mask'))):
return pathFile
# if file was already modified by templates
if pathFile in self.changedFiles.data.keys():
return pathFile
# if using already created ._cfg file
if self.configMode != T_ORIGIN:
return pathFile
# not current package file
pkg = self.functObj.currentBelong
if not pkg:
if not self.allContents:
fillContents(self.allContents,
self.objVar.Get('cl_config_protect'),
prefix=self.objVar.Get('cl_chroot_path'))
origName = pathFile if chrootPath == '/' \
else pathFile[len(chrootPath):]
if origName in self.allContents:
pkg = self.allContents[origName]
else:
return pathFile
pkg = isPkgInstalled(pkg,sortByVersion=True,prefix=chrootPath)
if not pkg:
return pathFile
if checkContents("{CATEGORY}/{PF}".format(**pkg[-1]),
pathFile,
prefix=chrootPath,
reservedFile='/var/lib/calculate/-CONTENTS-{PN}'.format(**pkg[-1]) \
if self.objVar.Get('cl_ebuild_phase') == 'postinst' \
else None):
return pathFile
real_filename = os.path.basename(pathFile)
real_dirname = os.path.dirname(pathFile)
self.configMode = T_NEWCFG
return os.path.join(real_dirname,"._cfg0000_%s"%real_filename)
def getApplyHeadTemplate(self, nameFileTemplate, nameFileConfig,
14 years ago
templateFileType, optFile):
"""Применяет заголовок к шаблону (права, владелец, и.т. д)"""
def function(text):
"""Функция обработки функций в заголовке"""
return self.applyFuncTemplate(text,nameFileTemplate)
14 years ago
def preReturn(pathProg):
"""Действия перед выходом из метода"""
if pathProg:
os.chdir(pathProg)
def chownConfFile(nameFileConfig, uid, gid, nameFileTemplate,
checkExists=True):
"""Изменение владельца конфигурационного файла"""
try:
if checkExists and not os.path.exists(nameFileConfig):
# Создание файла
FD = open(nameFileConfig, "w")
FD.close()
os.lchown(nameFileConfig, uid, gid)
except Exception as e:
if hasattr(e,'errno') and e.errno == 13 and \
"var/calculate/remote" in nameFileConfig:
return True
import pwd, grp
try:
userName = pwd.getpwuid(uid).pw_name
except:
userName = str(uid)
try:
groupName = grp.getgrgid(gid).gr_name
except:
groupName = str(gid)
owner = userName + ":" + groupName
self.setError(_("Failed to apply template file %s")\
%nameFileTemplate)
self.setError(_("error") + " " +\
"'chown %s %s'"%(owner, nameFileConfig))
return False
return True
def chmodConfFile(nameFileConfig, mode, nameFileTemplate,
checkExists=True):
"""Изменения режима доступа конфигурационного файла"""
try:
if checkExists and not os.path.exists(pathOldFile):
# Создание файла
FD = open(nameFileConfig, "w")
FD.close()
os.chmod(nameFileConfig, mode)
except Exception as e:
if hasattr(e,'errno') and e.errno == 13 and \
"var/calculate/remote" in nameFileConfig:
return True
self.setError(_("Failed to apply template file %s")\
%nameFileTemplate)
self.setError(\
_("error") + " " +\
"'chmod %s %s'"%(str(oct(mode)), nameFileConfig))
return False
return True
self.closeFiles()
pathProg = ""
self.executeType = None
# Файлы в системе к которым были применены шаблоны
14 years ago
applyFiles = [nameFileConfig]
# В случае бинарного типа файла читаем шаблон
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") + _(": ") +
self.nameFileTemplate)
return False
14 years ago
self.textTemplate = self.F_TEMPL.read()
self.closeTemplFile()
14 years ago
objHeadNew = fileHeader(nameFileTemplate, self.textTemplate, False,
14 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") + _(": ") +
14 years ago
nameFileTemplate)
14 years ago
return ([], False)
# add packeges for reconfigure
self._processMergePostmerge(objHeadNew.params, nameFileTemplate)
# Родительская директория
path = optFile["path"]
# Изменяем название родительской директории
if "path" in objHeadNew.params:
path = objHeadNew.params['path']
if path and path[0] == "~":
# Получаем путь с заменой ~ на директорию пользователя
path = os.path.join(self.homeDir,path.partition("/")[2],"")[:-1]
elif not path or path and path[0] != "/":
self.setError(_("Wrong value 'path' in the template") +
_(": ") + nameFileTemplate)
14 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)
14 years ago
return ([], False)
# Новый путь к оригинальному файлу
pathOldFile = pathJoin(path,nameFile)
else:
pathOldFile = pathJoin(path,os.path.split(nameFileConfig)[1])
pathOrigFile = pathOldFile
if self.objVar.Get('cl_protect_use_set') == 'on':
pathOldFile = self.fixNameFileConfig(pathOldFile)
pathOldFile = self.checkOnNewConfigName(pathOldFile)
# буффер для использование в link=
newBuffer = None
applyFiles = [pathOldFile]
# Фильтрация шаблонов по названию файла
realPath = os.path.join("/",pathOldFile.partition(self._baseDir)[2])
if realPath in self.filesFilter:
14 years ago
return ([], False)
14 years ago
typeAppendTemplate = objHeadNew.typeAppend
# Параметр exec
if "exec" in objHeadNew.params or "run" in objHeadNew.params:
if "exec" in objHeadNew.params:
paramName = "exec"
else:
paramName = "run"
self.executeType = paramName
execPath = objHeadNew.params[paramName]
if not os.access(execPath,os.X_OK):
self.setError(_("Wrong value '%s' in the template")%paramName +
_(": ") + nameFileTemplate)
12 years ago
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)
return ([], False)
# Очищаем оригинальный файл
if typeAppendTemplate == "clear":
try:
open(pathOldFile, "w").truncate(0)
newBuffer = ""
except:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to clear the file") + _(": ") +
pathOldFile)
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)
return (applyFiles, False)
except:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the link") + _(": ") +
pathOldFile)
return ([], False)
if os.path.isfile(pathOldFile) and self.configMode == T_ORIGIN:
# удаляем файл
try:
os.remove(pathOldFile)
return (applyFiles, False)
except:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the file") + _(": ") +
pathOldFile)
return ([], False)
finally:
pattern = "%s/._cfg????_%s"%(os.path.dirname(pathOrigFile),
os.path.basename(pathOrigFile))
for fn in glob.glob(pattern):
try:
os.unlink(fn)
except:
pass
if self.functObj.currentBelong:
self.changedFiles.addObj(pathOrigFile,
ChangedFiles.FILE_REMOVED,
self.functObj.currentBelong)
return ([], False)
# Пропускаем обработку шаблона
14 years ago
elif typeAppendTemplate == "skip":
14 years ago
return ([], False)
# Создаем директорию для файла если ее нет
if not os.path.exists(path):
if not self.createDir(path):
14 years ago
return ([], False)
# В случае force
if objHeadNew.params.has_key("force"):
if os.path.islink(pathOldFile):
# удаляем ссылку
try:
newBuffer = ""
os.unlink(pathOldFile)
except:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the link") + _(": ") +
pathOldFile)
14 years ago
return ([], False)
if os.path.isfile(pathOldFile):
# удаляем файл
try:
newBuffer = ""
os.remove(pathOldFile)
except:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the file") + _(": ") +
pathOldFile)
14 years ago
return ([], False)
flagSymlink = False
flagForce = False
# Если есть параметр mirror
if objHeadNew.params.has_key("mirror"):
if objHeadNew.params.has_key("link"):
templateFile = objHeadNew.params['link']
if templateFile and templateFile[0] == "~":
# Получаем директорию пользователя
templateFile = os.path.join(self.homeDir,
templateFile.partition("/")[2],"")[:-1]
templateFile = pathJoin(self._baseDir, templateFile)
if not os.path.exists(templateFile):
if os.path.exists(pathOldFile):
try:
newBuffer = ""
os.remove(pathOldFile)
except:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the file") + _(": ") +
pathOldFile)
14 years ago
return ([], False)
elif not os.path.exists(pathOldFile):
14 years ago
return ([], False)
# Если есть указатель на файл шаблона (link)
if objHeadNew.params.has_key("link") and\
not objHeadNew.params.has_key("symbolic"):
templateFile = objHeadNew.params['link']
if templateFile and templateFile[0] == "~":
# Получаем директорию пользователя
templateFile = os.path.join(self.homeDir,
templateFile.partition("/")[2],"")[:-1]
templateFile = pathJoin(self._baseDir, templateFile)
foundTemplateFile = os.path.exists(templateFile)
if foundTemplateFile:
try:
F_CONF = self.openTemplFile(templateFile)
buff = F_CONF.read()
F_CONF.close()
fMode, fUid, fGid = getModeFile(templateFile)
except:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to open the file") + _(": ") +
templateFile)
14 years ago
return ([], False)
if os.path.exists(pathOldFile):
try:
newBuffer = ""
os.remove(pathOldFile)
except:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the file") + _(": ") +
pathOldFile)
14 years ago
return ([], False)
if foundTemplateFile:
14 years ago
try:
FD = open(pathOldFile, "w+")
newBuffer = buff
14 years ago
FD.write(buff)
FD.close()
except:
self.setError(_("Template error") + _(": ") +
14 years ago
nameFileTemplate)
12 years ago
self.setError(_("Failed to create the file") + " '%s'"\
14 years ago
%pathOldFile)
14 years ago
return ([], False)
oMode = getModeFile(pathOldFile, mode="mode")
14 years ago
# Если права не совпадают, меняем права
if fMode != oMode:
if not chmodConfFile(pathOldFile, fMode, nameFileTemplate,
checkExists=False):
14 years ago
return ([], False)
# Если символическая ссылка
if objHeadNew.params.has_key("symbolic"):
prevOldFile = pathOldFile
pathOldFile = objHeadNew.params['link']
flagSymlink = True
if not pathOldFile:
raise TemplatesError(
_("Missed source link in template '%s'")
%str(nameFileTemplate))
if not "/" == pathOldFile[0]:
pathLink = os.path.split(os.path.abspath(prevOldFile))[0]
pathProg = os.getcwd()
try:
os.chdir(pathLink)
except:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
12 years ago
self.setError(
_("Failed to change the current directory to")+\
" " + pathLink)
14 years ago
return ([], False)
# chmod - изменяем права
if objHeadNew.params.has_key("chmod"):
mode = self.__octToInt(objHeadNew.params['chmod'])
if mode:
if not chmodConfFile(pathOldFile, mode, nameFileTemplate):
preReturn(pathProg)
14 years ago
return ([], False)
else:
self.setError(_("Wrong value 'chmod' in the template") +
_(": ") + nameFileTemplate)
preReturn(pathProg)
14 years ago
return ([], False)
# chown - изменяем владельца и группу
if objHeadNew.params.has_key("chown"):
owner = objHeadNew.params['chown']
if owner:
if ":" in owner:
strUid, strGid = owner.split(":")
if strUid.isdigit():
uid = int(strUid)
else:
uid = self.getUidFromPasswd(strUid)
import pwd
try:
if uid is None:
uid = pwd.getpwnam(strUid).pw_uid
except:
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)
return ([], False)
if strGid.isdigit():
gid = int(strGid)
else:
gid = self.getGidFromGroup(strGid)
try:
if gid is None:
import grp
gid = grp.getgrnam(strGid).gr_gid
except:
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)
return ([], False)
# Изменяем владельца файла
if not chownConfFile(pathOldFile,uid,gid,nameFileTemplate):
preReturn(pathProg)
14 years ago
return ([], False)
else:
12 years ago
self.setError(_("Wrong value 'chown' in the template") +
_(": ") + nameFileTemplate)
preReturn(pathProg)
14 years ago
return ([], False)
else:
self.setError(_("Wrong value 'chown' in the template") +
_(": ") + nameFileTemplate)
preReturn(pathProg)
14 years ago
return ([], False)
if not flagSymlink:
self.openFiles(nameFileTemplate, pathOldFile,objHeadNew.fileType,
newBuffer)
if self.getError():
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 chownConfFile(pathOldFile, self.uid, self.gid,
nameFileTemplate, checkExists=False):
preReturn(pathProg)
return ([], False)
if flagSymlink:
if os.path.exists(prevOldFile) or os.path.islink(prevOldFile):
try:
if os.path.islink(prevOldFile):
# если ссылка то удаляем её
os.unlink(prevOldFile)
else:
# иначе удаляем файл
os.remove(prevOldFile)
except:
self.setError(_("Template error") + _(": ") +
nameFileTemplate)
self.setError(_("Failed to delete the file") + _(": ") +
prevOldFile)
preReturn(pathProg)
14 years ago
return ([], False)
if not "/" == pathOldFile[0]:
applyFiles = [prevOldFile]#,os.path.join(pathLink,pathOldFile)]
else:
applyFiles = [prevOldFile]#,pathOldFile]
try:
os.symlink(pathOldFile, prevOldFile)
except:
self.setError(_("Template error") + _(": ") +\
nameFileTemplate)
self.setError(_("Failed to create a symbolic link") + _(": ") +\
"%s -> %s"%(prevOldFile, pathOldFile))
preReturn(pathProg)
14 years ago
return ([], False)
14 years ago
if not objHeadNew.body.strip():
preReturn(pathProg)
if "protected" in objHeadNew.params:
self.protectedFiles += applyFiles
14 years ago
return (applyFiles, False)
else:
applyFiles = [pathOldFile]
if pathProg:
os.chdir(pathProg)
# Если файлы заменяются не нужно их обрабатывать дальше
14 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)
if ( "autoupdate" in optFile or "autoupdate" in objHeadNew.params ) \
12 years ago
and not self.objVar.Get('cl_merge_pkg_pass'):
reCfg = re.compile(r"/._cfg\d{4}_",re.S)
self.autoUpdateFiles += map(lambda x:reCfg.sub('/',x),applyFiles)
if "protected" in objHeadNew.params:
self.protectedFiles += applyFiles
return (applyFiles, objHeadNew)
def createNewClass(self, name, bases, attrs={}):
"""Создает объект нового класса
createNewClass(self, name, bases, attrs)
name - имя класса - str,
bases - cписок наследуемых классов - (tuple),
attrs - аттрибуты класса - {dict}
"""
class newMethod:
#Объединяем конфигурации
def join(self, newObj):
if newObj.__class__.__name__ == self.__class__.__name__:
self.docObj.joinDoc(newObj.doc)
# Пост обработка
if 'postXML' in dir(self):
self.postXML()
attrsNew = {}
attrsNew["configName"] = name
if attrs:
for key in attrs.keys():
attrsNew[key] = attrs[key]
newCl = type(name, bases + (newMethod, object,), attrsNew)
return newCl
def fileIsUtf(self, fileName):
"""Проверяет файл на кодировку UTF-8"""
if os.path.isfile(fileName):
FD = open(os.path.abspath(fileName),'r')
newTemplate = FD.read(1)+FD.read()
FD.close()
try:
newTemplate.decode("UTF-8")
except:
return False
return True
return False
def joinTemplate(self, nameFileTemplate, nameFileConfig, optFile={}):
"""Объединения шаблона и конф. файла
14 years ago
join(nameFileTemplate, nameFileConfig, ListOptTitle)
Объединение шаблона nameFileTemplate и конф. файла nameFileConfig,
ListOptTitle - список строк которые добавятся в заголовок
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:
moduleParam = filter(lambda x:x.startswith('env='),
12 years ago
headerLine.split())
if moduleParam:
self.objVar.defaultModule = moduleParam[0].partition('=')[2]
try:
varModule = importlib.import_module(
"calculate.%s.variables"%self.objVar.defaultModule)
except (ImportError, AttributeError),e:
return []
12 years ago
14 years ago
if templateFileType != "bin":
# Заменяем переменные на их значения
14 years ago
self.textTemplate = self.applyVarsTemplate(self.textTemplate,
14 years ago
nameFileTemplate)
flagCopyTemplate = False
if not optFile:
optFile = {"path":os.path.split(nameFileConfig)[0]}
filesApply, objHeadNew = self.getApplyHeadTemplate(nameFileTemplate,
14 years ago
nameFileConfig,
templateFileType,
optFile)
if not objHeadNew:
return filesApply
if filesApply and not filter(lambda x:"calculate/ini.env" in x,
filesApply):
self.templateModify()
if templateFileType != "bin":
# Вычисляем условные блоки
objHeadNew.body = self.applyTermsTemplate(objHeadNew.body,
nameFileTemplate)
# Вычисляем функции
objHeadNew.body = self.applyFuncTemplate(objHeadNew.body,
nameFileTemplate)
14 years ago
# Настоящее имя конфигурационного файла
nameFileConfig = filesApply[0]
# Флаг - кодировка с бинарными примесями у файла шаблона включаем при
# условии текстового файла и кодировки отличной от UTF-8
flagNotUtf8New = False
# Флаг - кодировка с бинарными примесями у оригинального файла
flagNotUtf8Old = False
14 years ago
if not flagCopyTemplate:
# проверяем кодировку шаблона
14 years ago
if not self.fileIsUtf(nameFileTemplate):
flagNotUtf8New = True
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)
14 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':
wrongOpt = [x for x in ("multiline","dotall")
if objHeadNew.params.has_key(x)]
if wrongOpt:
self.setError(\
_("Option %s should be used for format=patch only")\
%wrongOpt[0])
return False
if objHeadNew.fileType != 'dconf':
wrongOpt = [x for x in ("dconfpath",)
if objHeadNew.params.has_key(x)]
if wrongOpt:
self.setError(\
_("Option %s should be used for format=dconf only")\
%wrongOpt[0])
return False
if objHeadNew.fileType:
14 years ago
formatTemplate = objHeadNew.fileType
typeAppendTemplate = objHeadNew.typeAppend
if formatTemplate in ("patch","diff", "dconf"):
if typeAppendTemplate != "patch":
self.setError(\
12 years ago
_("Wrong option append=%(type)s in template %(file)s")\
%{"type":typeAppendTemplate,"file":nameFileTemplate})
return False
# создаем объект формата шаблона
objTempl = self.getFormatObj(formatTemplate, self.textTemplate)
if formatTemplate == 'patch':
if objHeadNew.params.has_key("multiline"):
objTempl.setMultiline()
if objHeadNew.params.has_key("dotall"):
objTempl.setDotall()
if formatTemplate == 'dconf':
if "dconfpath" in objHeadNew.params:
objTempl.setPath(objHeadNew.params['dconfpath'])
objTempl.setUser(self.objVar.Get('ur_login'))
if not objTempl:
self.setError(\
12 years ago
_("Incorrect header parameter format=%s "
"in the template")\
%formatTemplate + " " + nameFileTemplate)
return False
if objHeadOld and objHeadOld.body:
self.textConfig = objHeadOld.body
# обработка конфигурационного файла
11 years ago
self.textTemplate = objTempl.processingFile(self.textConfig,
pathJoin(self.objVar.Get('cl_chroot_path'),
self.objVar.Get('cl_root_path')))
error = objTempl.getError()
if error:
if formatTemplate == "dconf":
self.printERROR(error.strip())
raise TemplatesError(_("Failed to use dconf ") + \
nameFileTemplate)
11 years ago
raise TemplatesError(_("Failed to use patch ") + \
nameFileTemplate)
elif (formatTemplate == 'diff' and
self.objVar.Get('cl_verbose_set') == "on"):
self.printSUCCESS(_("Appling patch")+ " " + \
11 years ago
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()
if 'run' in objHeadNew.params:
if not self.executeTemplate(self.textConfig,
objHeadNew.params['run']):
self.setError(_("Wrong template") + _(": ") +\
nameFileTemplate)
self.setError(_("Failed to execute") + _(": ") +\
self.nameFileConfig)
return False
return False
return filesApply if not 'exec' in objHeadNew.params else False
# Создаем объект в случае параметра format в заголовке
14 years ago
if (typeAppendTemplate == "replace" or\
typeAppendTemplate == "before" or\
typeAppendTemplate == "after") and\
not (formatTemplate == "bin" or\
formatTemplate == "raw"):
# Преобразовываем бинарные файлы
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:
14 years ago
self.setError(\
12 years ago
_("Incorrect header parameter format=%s "
"in the template")\
14 years ago
%formatTemplate + " " + nameFileTemplate)
return False
14 years ago
if "xml_" in formatTemplate:
if objTemplNew.getError():
self.setError(_("Wrong template") + _(": ") +\
nameFileTemplate)
return False
14 years ago
# Имя файла внутри xml xfce конфигурационных файлов
14 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 производим преобразование
if flagNotUtf8New:
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")
data.insert(1,title)
14 years ago
self.textConfig = "\n".join(data)
else:
if objHeadNew.execStr:
14 years ago
self.textConfig = objHeadNew.execStr+title+\
self.textTemplate
else:
14 years ago
self.textConfig = title + self.textTemplate
14 years ago
self.saveConfFile()
if 'run' in objHeadNew.params:
if not self.executeTemplate(self.textConfig,
objHeadNew.params['run']):
self.setError(_("Wrong template") + _(": ") +\
nameFileTemplate)
self.setError(_("Failed to execute") + _(": ") +\
self.nameFileConfig)
return False
return False
return filesApply if not 'exec' in objHeadNew.params else False
# Вверху
14 years ago
elif typeAppendTemplate == "before":
if "xml_" in formatTemplate:
14 years ago
self.setError(\
12 years ago
_("Wrong option append=before in template %s")\
14 years ago
%nameFileTemplate)
return False
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()
if 'run' in objHeadNew.params:
if not self.executeTemplate(self.textConfig,
objHeadNew.params['run']):
self.setError(_("Wrong template") + _(": ") +\
nameFileTemplate)
self.setError(_("Failed to execute") + _(": ") +\
self.nameFileConfig)
return False
return False
return filesApply if not 'exec' in objHeadNew.params else False
# Внизу
14 years ago
elif typeAppendTemplate == "after":
if "xml_" in formatTemplate:
14 years ago
self.setError(\
12 years ago
_("Wrong option append=after in template %s")\
14 years ago
%nameFileTemplate)
return False
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()
if 'run' in objHeadNew.params:
if not self.executeTemplate(self.textConfig,
objHeadNew.params['run']):
self.setError(_("Wrong template") + _(": ") +\
nameFileTemplate)
self.setError(_("Failed to execute") + _(": ") +\
self.nameFileConfig)
return False
return False
return filesApply if not 'exec' in objHeadNew.params else False
# Объединение
14 years ago
elif typeAppendTemplate == "join":
if flagNotUtf8New:
objTxtCoder = utfBin()
14 years ago
self.textTemplate = objTxtCoder.encode(self.textTemplate)
14 years ago
if formatTemplate =="raw":
self.setError(\
12 years ago
_("Incorrect header parameter append=%s "
"in the template")\
14 years ago
%typeAppendTemplate + " " + nameFileTemplate)
return False
# создаем объект формата шаблона
14 years ago
objTemplNew = self.getFormatObj(formatTemplate,
14 years ago
self.textTemplate)
if not objTemplNew:
14 years ago
self.setError(\
12 years ago
_("Incorrect header parameter format=%s in "
"the template")\
14 years ago
%formatTemplate + " " + nameFileTemplate)
return False
14 years ago
if "xml_" in formatTemplate:
if objTemplNew.getError():
self.setError(_("Wrong template") + _(": ") +\
nameFileTemplate)
return False
14 years ago
nameRootNode=nameFileConfig.rpartition("/")[2].split(".")[0]
objTemplNew.setNameBodyNode(nameRootNode)
# Титл для объединения
if ListOptTitle:
title = self.getTitle(objTemplNew._comment,
ListOptTitle,
configPath=nameFileConfig)
title = title.encode("UTF-8")
# В случае пустого конфигурационного файла
reNoClean = re.compile("[^\s]",re.M)
14 years ago
if not self.textConfig or\
not reNoClean.search(self.textConfig):
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:
14 years ago
self.setError(_("Error in template %s") %nameFileConfig)
return False
14 years ago
if "xml_" in formatTemplate:
if objTemplOld.getError():
self.setError(_("Wrong template") + _(": ") +\
nameFileConfig)
return False
14 years ago
nameRootNode=nameFileConfig.rpartition("/")[2].split(".")[0]
objTemplOld.setNameBodyNode(nameRootNode)
objTemplOld.join(objTemplNew)
14 years ago
if "xml_" in formatTemplate:
if objTemplOld.getError():
self.setError(_("Wrong template") + _(": ") +\
nameFileTemplate)
return False
data = objTemplOld.getConfig().encode("UTF-8").split("\n")
data.insert(1,title)
14 years ago
self.textConfig = "\n".join(data)
else:
if execStr:
self.textConfig = execStr + title +\
objTemplOld.getConfig().encode("UTF-8")
else:
14 years ago
self.textConfig = title +\
objTemplOld.getConfig().encode("UTF-8")
# Декодируем если кодировка не UTF-8
if flagNotUtf8New or flagNotUtf8Old:
14 years ago
self.textTemplate = objTxtCoder.decode(self.textTemplate)
self.textConfig = objTxtCoder.decode(self.textConfig)
self.saveConfFile()
if 'run' in objHeadNew.params:
if not self.executeTemplate(self.textConfig,
objHeadNew.params['run']):
self.setError(_("Wrong template") + _(": ") +\
nameFileTemplate)
self.setError(_("Failed to execute") + _(": ") +\
self.nameFileConfig)
return False
return False
return filesApply if not 'exec' in objHeadNew.params else False
else:
self.setError(_("Wrong template option (type append)")
+ _(": ") + typeAppendTemplate)
return False
else:
12 years ago
self.setError(_("Template type not found: ") + nameFileTemplate)
return False
return filesApply
class scanDirectoryClt:
"""Класс для cканирования директорий с файлами .clt"""
# Расширение файла шаблона
extFileTemplate = ".clt"
lenExtFileTemplate = len(extFileTemplate)
filterApplyTemplates = []
reHeader = re.compile(r"\s*#\s*calculate\s*", re.I)
12 years ago
def __init__(self,objVar=None):
if objVar:
self.objVar = objVar
def processingFile(self, path, prefix):
"""Обработка в случае файла"""
return True
def hasBelong(self,filename):
"""
Change belong function
"""
f = open(filename,'r')
s = f.readline()
if self.reHeader.search(s):
while s:
if "belong(" in s or "merge(" in s:
return True
if not s.strip().endswith('\\'):
break
s = f.readline()
return False
12 years ago
def scanningTemplates(self, scanDir, prefix=None, flagDir=False,
objVar=None):
"""Сканирование и обработка шаблонов в директории scanDir"""
ret = True
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(scanDir)[stat.ST_MODE]):
for fileOrDir in sorted(listDirectory(scanDir)):
try:
absPath = os.path.join(scanDir,fileOrDir)
stInfo = os.lstat(absPath)
statInfo = stInfo[stat.ST_MODE]
if fileOrDir.endswith(self.extFileTemplate) and\
stat.S_ISREG(statInfo):
if not self.filterApplyTemplates and \
self.objVar.Get('cl_merge_set') == 'off' or \
self.filterApplyTemplates and \
absPath[:-self.lenExtFileTemplate] in\
self.filterApplyTemplates.keys() or self.hasBelong(absPath):
prevDefault = self.objVar.defaultModule
if not self.processingFile(absPath, prefix):
12 years ago
return False
self.objVar.defaultModule = prevDefault
elif stat.S_ISDIR(statInfo):
12 years ago
if not self.scanningTemplates(absPath, prefix, True):
return False
except TemplatesInterrupt as e:
if e.isInterrupt():
self.stop = e.status()
return False
else:
11 years ago
self.clearErrors()
12 years ago
self.printWARNING(str(e))
return True
class templateClt(scanDirectoryClt, Template):
"""Класс для обработки шаблонов c расширением .clt"""
def __init__(self, objVar, postmergePkgs, **kwargs):
self.checkNumberTemplate = True
Template.__init__(self, objVar, cltObj=False,**kwargs)
self.postmergePkgs = postmergePkgs
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
def processingFile(self, path, prefix):
"""Обработка в случае шаблона файла"""
self.numberProcessTempl += 1
self.numberProcessTemplates(self.numberProcessTempl)
# Пропуск шаблонов директорийscanningTemplates
if self.templDirNameFile == os.path.split(path)[1]:
return True
self.functObj.currentBelong = ""
# Проверка на переменные в названии файла
if not self.getNeedTemplate(path):
if self.getError():
return False
return True
if self.getError():
return False
if prefix and prefix[-1] == "/":
prefix = prefix[:-1]
if prefix and path.startswith(prefix):
nameFileConfig = path.partition(prefix)[2]
else:
nameFileConfig = path
nameFileConfig = nameFileConfig[:-self.lenExtFileTemplate]
origFileName = nameFileConfig
nameFileConfig = pathJoin(self._baseDir, nameFileConfig)
# файл в системе без условий
nameFileConfig = "/".join(map(lambda x:x.split("?")[0],\
nameFileConfig.split("/")))
# Записываем в переменную обрабатываемый файл
self.objVar.Set("cl_pass_file",nameFileConfig)
filesApl = self.joinTemplate(path, nameFileConfig)
if self.getError():
return False
if filesApl:
if self.functObj.currentBelong:
self._addFile(filesApl)
else:
if origFileName in self.filterApplyTemplates:
for pkg in self.filterApplyTemplates[origFileName]:
self._addFile(filesApl,pkg=pkg)
else:
if not self.allContents:
fillContents(self.allContents,
self.objVar.Get('cl_config_protect'),
prefix=self.objVar.Get('cl_chroot_path'))
for fn in filesApl:
fn_orig = PkgContents.reCfg.sub('/',fn)
if self.objVar.Get('cl_chroot_path') != '/':
fn_orig = \
fn_orig[len(self.objVar.Get('cl_chroot_path')):]
if fn_orig in self.allContents:
self._addFile([fn],pkg=self.allContents[fn_orig])
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
def countsNumberTemplates(self, dirsTemplates=[]):
"""Считаем количество шаблонов"""
def createDictTemplates(path, prefix, dictTemplates):
"""Создает словарь {"директория":"кол-во шаблонов" ...}
и считает общее количество шаблонов
"""
# Количество шаблонов
self.allTemplates += 1
dirTemplate = os.path.split(path)[0]
while(True):
if dirTemplate in dictTemplates.keys():
dictTemplates[dirTemplate] += 1
else:
dictTemplates[dirTemplate] = 1
if dirTemplate == prefix:
break
dirTemplate = os.path.split(dirTemplate)[0]
return dictTemplates
if not dirsTemplates:
dirsTemplates = self.objVar.Get("cl_template_clt_path")
dirsTemplates.sort()
12 years ago
scanObj = scanDirectoryClt(objVar=self.objVar)
scanObj.processingFile = lambda x,y: createDictTemplates(x, y,\
self.dictTemplates)
# Считаем количество шаблонов
for dirTemplate in dirsTemplates:
scanObj.scanningTemplates(dirTemplate, "/")
def applyTemplates(self,cltPath=None):
"""Применяет шаблоны к конфигурационным файлам"""
if not self.flagApplyTemplates:
return ([],[])
if cltPath is None and \
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:
12 years ago
break
return (self.createdDirs, self.filesApply)
class iniParser(_error, templateFormat):
"""Класс для работы с ini файлами
"""
12 years ago
def __init__(self, iniFile=None,text=None):
# название ini файла
self.iniFile = iniFile or ""
# права создаваемого ini-файла
self.mode = 0640
# Cоответствует ли формат файла нужному
self.checkIni = None
14 years ago
self.FD = None
self.readOnly = False
12 years ago
self.text = text
self.locked = False
12 years ago
def joinText(self, iniObj, xmlNewDoc):
"""Объединяет два документа"""
newRootNode = xmlNewDoc.documentElement
newBodyNode = xpath.Evaluate('child::body',newRootNode)[0]
newImportBodyNode = iniObj.doc.importNode(newBodyNode, True)
iniObj.docObj.joinBody(iniObj.docObj.body, newImportBodyNode)
#iniObj.docObj.insertBRtoBody(iniObj.docObj.body)
def setMode(self, mode):
"""установка прав создаваемого ini-файла"""
self.mode = mode
def lockfile(self,fd,fn,timeout=5):
"""
Блокировка файла с таймаутом
"""
if self.locked:
return True
for i in range(0,timeout):
try:
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
return True
except IOError,e:
if e.errno != errno.EAGAIN:
raise e
time.sleep(1)
else:
raise TemplatesError(_("Lock timeout of %s")%fn)
@property
def iniFile_lock(self):
return self.iniFile+".lock~"
def wait_global_lock(self, timeout=10):
lockfn = self.iniFile_lock
for i in range(0,timeout):
if self.locked or not os.path.exists(lockfn):
break
time.sleep(1)
@contextmanager
def lock(self):
lockfn = self.iniFile_lock
lockf = open(lockfn, "w+")
self.lockfile(lockf.fileno(), lockfn)
self.locked = True
try:
yield
finally:
self.locked = False
os.unlink(lockfn)
def _open(self, mode):
self.wait_global_lock()
return open(self.iniFile, mode)
def openIniFile(self):
12 years ago
if not self.text is None:
return self.text
if not os.access(self.iniFile, os.R_OK):
return ""
self.FD = self._open("r")
self.lockfile(self.FD.fileno(),self.iniFile)
textIni = self.FD.read()
return textIni
def openRWIniFile(self):
if not os.access(self.iniFile, os.R_OK):
return ""
try:
self.FD = self._open("r+")
except (IOError, OSError), e:
self.FD = self._open("r")
self.readOnly = True
self.lockfile(self.FD.fileno(), self.iniFile)
14 years ago
textIni = self.FD.read()
return textIni
def writeIniFile(self, txtConfig):
if self.readOnly:
12 years ago
self.setError(_("Failed to write to file")
+ _(": ") + self.iniFile)
return False
if not os.path.exists(self.iniFile):
14 years ago
try:
# Создание файла
self.FD = self._open("w+")
self.lockfile(self.FD.fileno(), self.iniFile)
14 years ago
os.chmod(self.iniFile, self.mode)
except:
12 years ago
self.setError(_("Failed to create the file") +
_(": ") + self.iniFile)
14 years ago
return False
14 years ago
if not self.FD:
12 years ago
self.setError(_("Failed to write to file")
+ _(": ") + self.iniFile)
14 years ago
return False
14 years ago
self.FD.truncate(0)
self.FD.seek(0)
self.FD.write(txtConfig)
self.FD.close()
14 years ago
self.FD = None
14 years ago
return True
def setVar(self, strHeader, dictVar):
"""Заменяет или добавляет область и переменные
Добавляет область в ini-файл или объединяет с существующей
strHeader - имя области
dictVar - словарь переменных
"""
textIni = self.openRWIniFile()
nameFomat = self.checkIniFile(textIni)
if not nameFomat:
return False
if type(strHeader) in (tuple, list):
# формат plasma
classObj = self.getClassObj("plasma")
else:
if nameFomat == "plasma":
12 years ago
self.setError(_("Trying to write a variable of 'samba' "
12 years ago
"format to file %s ('plasma' format)")\
%self.iniFile)
return False
# формат samba
classObj = self.getClassObj("samba")
# создаем объект
# и записываем в него содержимое ini-файла
objIni = classObj(textIni)
# создаем текст из строки заголовка и
# словаря переменных области
txtConfig = objIni.createTxtConfig(strHeader, dictVar)
# создаем объект и записываем в него текст
objIniAdd = classObj(txtConfig)
# объединяем объекты для получения результирующего текста
objIni.join(objIniAdd)
# получаем текст
txtConfig = objIni.getConfig().encode("UTF-8")
# записываем его в ini файл
14 years ago
if not self.writeIniFile(txtConfig):
return False
return True
def isEmptyFile(self, textIni):
"""Если файл пустой или содержит только комментарии - False
иначе - True
"""
if textIni.strip():
if filter(lambda x: x.strip(),
map(lambda x:x[0].split(";")[0],
map(lambda x: x.split("#"),
textIni.splitlines()))):
return False
else:
return True
else:
return True
def checkIniFile(self, textIni):
"""Проверка на правильность формата файла"""
14 years ago
if self.checkIni is None:
# Ошибка
if textIni == False:
self.checkIni = False
return False
self.checkIni = "samba"
# В файле есть данные
if not self.isEmptyFile(textIni):
try:
objIni = self.getClassObj("plasma")(textIni)
except:
self.setError(_("Incorrect file format") + _(": ") + \
self.iniFile)
self.checkIni = False
return self.checkIni
allAreas = objIni.docObj.getAllAreas()
for xmlArea in allAreas:
parentNode = xmlArea.parentNode
if parentNode and parentNode.tagName == "area":
self.checkIni = "plasma"
break
if self.checkIni == "samba":
objIni = self.getClassObj("samba")(textIni)
xmlBody = objIni.docObj.getNodeBody()
if not xmlBody.firstChild:
self.checkIni = False
return self.checkIni
def delVar(self, strHeader, nameVar):
"""Удаляем переменную из ini файла"""
delNameVar = "!%s" %(nameVar)
dictVar = {delNameVar:"del"}
res = self.setVar(strHeader, dictVar)
return res
def delArea(self, strHeader):
"""Удаляем область из ini файла"""
if type(strHeader) in (tuple, list):
# Формат plasma
delStrHeader = list(strHeader[:])
delStrHeader[-1] = "!%s"%delStrHeader[-1]
else:
# Формат samba
delStrHeader = "!%s" %(strHeader)
dictVar = {"del":"del"}
res = self.setVar(delStrHeader, dictVar)
return res
14 years ago
def getVar(self, strHeader, nameVar, checkExistVar=False):
"""Получаем значение переменной из ini-файла"""
textIni = self.openIniFile()
14 years ago
if self.FD:
self.FD.close()
self.FD = None
nameFomat = self.checkIniFile(textIni)
if not nameFomat:
return False
formatPlasma = False
if type(strHeader) in (tuple, list):
# формат plasma
classObj = self.getClassObj("plasma")
formatPlasma = True
else:
if nameFomat == "plasma":
12 years ago
self.setError(_("Trying to fetch a variable of 'samba' "
12 years ago
"format from file %s ('plasma' format)")\
%self.iniFile)
return False
# формат samba
classObj = self.getClassObj("samba")
# создаем объект и записываем в него содержимое ini-файла
objIni = classObj(textIni)
# получаем ноду body
xmlBody = objIni.docObj.getNodeBody()
flagFound, xmlBody = self.getLastNode(objIni, xmlBody, strHeader,
formatPlasma)
if flagFound and xmlBody:
if formatPlasma:
strHeader = strHeader[-1]
# находим в области переменную
res = objIni.docObj.getAreaFieldValues(strHeader, nameVar, xmlBody)
else:
res = False
14 years ago
if checkExistVar:
if res is False:
return False, ""
else:
return True, res
else:
14 years ago
if res is False:
return ""
else:
return res
def getLastNode(self, objIni, xmlBody, strHeader, formatPlasma):
"""Ищет область в XML в которой область с переменными"""
flagFound = True
14 years ago
if not strHeader:
flagFound = False
return flagFound,xmlBody
lenStrHeader = len(strHeader)
if formatPlasma and lenStrHeader>0:
xmlAreas = [xmlBody]
for i in xrange(lenStrHeader-1):
flagFound = False
for xmlArea in xmlAreas:
xmlAreas = objIni.docObj.getArea(strHeader[i], xmlArea)
if xmlAreas:
flagFound = True
break
if xmlAreas:
xmlBody = xmlAreas[0]
return flagFound,xmlBody
def getAreaVars(self, strHeader):
"""Получаем все переменнные области из ini-файла"""
textIni = self.openIniFile()
14 years ago
if self.FD:
self.FD.close()
self.FD = None
nameFomat = self.checkIniFile(textIni)
if not nameFomat:
return False
formatPlasma = False
if type(strHeader) in (tuple, list):
# формат plasma
classObj = self.getClassObj("plasma")
formatPlasma = True
else:
if nameFomat == "plasma":
12 years ago
self.setError(_("Trying to fetch a variable of 'samba' "
12 years ago
"format from file %s ('plasma' format)")\
%self.iniFile)
return False
# формат samba
classObj = self.getClassObj("samba")
# создаем объект типа samba и записываем в него содержимое ini-файла
objIni = classObj(textIni)
# получаем ноду body
xmlBody = objIni.docObj.getNodeBody()
flagFound, xmlBody = self.getLastNode(objIni, xmlBody, strHeader,
formatPlasma)
if flagFound and xmlBody:
if formatPlasma:
strHeader = strHeader[-1]
# если находим область то выдаем словарем все переменные иначе False
12 years ago
res = objIni.docObj.getAreaFields(strHeader, xmlBody, allVars=True)
else:
res = False
if res is False:
return {}
else:
return res
def getAllSectionNames(self):
"""Получаем все имена секций определенных в ini файле
Если формат ini файла plasma то имя секции -
имена нескольких секций через запятую
"""
textIni = self.openIniFile()
14 years ago
if self.FD:
self.FD.close()
self.FD = None
nameFomat = self.checkIniFile(textIni)
if not nameFomat:
return False
if nameFomat == "samba":
# создаем объект типа samba и записываем в него содержимое ini-файла
objIni = self.getClassObj("samba")(textIni)
elif nameFomat == "plasma":
# создаем объект типа plasma и записываем в него содержимое
# ini-файла
objIni = self.getClassObj("plasma")(textIni)
else:
return []
xmlNodes = objIni.docObj.getAllAreas()
# Имена секций ini файла
namesSection = []
if nameFomat == "plasma":
for xmlNode in xmlNodes:
nSect = objIni.docObj.getNameArea(xmlNode)
if nSect:
namesSect = [nSect]
parentNode = xmlNode.parentNode
while parentNode != objIni.docObj.body:
nameSect = objIni.docObj.getNameArea(parentNode)
if nameSect:
namesSect.append(nameSect)
parentNode = parentNode.parentNode
else:
return []
namesSection.append(",".join(reversed(namesSect)))
elif nameFomat == "samba":
# получаем ноду body
for xmlNode in xmlNodes:
nSect = objIni.docObj.getNameArea(xmlNode)
if nSect:
namesSection.append(nSect)
return namesSection
class ProgressTemplate(Template):
"""
Progress template for wsdl interface
"""
def __init__(self, setValueCallback, *args, **kwargs):
Template.__init__(self, *args, **kwargs)
self.setValueCallback = setValueCallback
self.value = None
12 years ago
self.firstValue = True
def numberAllTemplates(self, number):
self.maximum = number
return True
def numberProcessTemplates(self,number):
maximum = self.maximum or 1
value = number * 100 / maximum;
if value != self.value:
self.setValueCallback(min(100,max(0,value)))
self.value = value
return True
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'
def __init__(self):
self.config = ConfigParser(strict=False)
self.config.read(self.inifile, encoding="utf-8")
def getVar(self, section, varname):
return self.config.get(section,varname,raw=True, fallback="")
def delVar(self, section, varname):
try:
self.config.remove_option(section, varname)
for section in filter(lambda x: not self.config[x],
self.config.sections()):
self.config.remove_section(section)
self.__write()
except NoSectionError:
pass
def __write(self):
comment_block = "\n".join(takewhile(lambda x:x.startswith("#"),
readLinesFile(self.inifile)))
with open(self.inifile, 'wb') as f:
if comment_block:
f.write(comment_block)
f.write('\n\n')
self.config.write(f)
def setVar(self, section, var_dict):
if not self.config.has_section(section):
self.config.add_section(section)
for k, v in var_dict.items():
self.config.set(section, k, v)
self.__write()