#-*- coding: utf-8 -*- # Copyright 2008-2010 Calculate Ltd. http://www.calculate-linux.org # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys import os import stat import re import xml.dom.minidom from xml import xpath import subprocess import types import random import string import time import glob import fcntl # < <= == != >= > from operator import lt, le, eq, ne, ge, gt # Переопределение exit import cl_overriding from cl_utils import _error, _warning, _toUNICODE, getModeFile, removeDir,\ typeFile, scanDirectory, convertStrListDict, pathJoin import cl_lang tr = cl_lang.lang() tr.setLocalDomain('cl_lib') tr.setLanguage(sys.modules[__name__]) 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) # Регулярное выражение для названия переменной _reDenyName = re.compile("[^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: 2.2.27 ("2.2.27","",[],"") 2.2.27-r1 ("2.2.27","",[],"r1") 2.2.27a-r1 ("2.2.27","a",[],"r1") 2.2.27a_rc1-r1 ("2.2.27","a",[("rc","1")],"r1") 2.2.27a_rc1_p20111212-r1 ("2.2.27","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 = {"==":eq, "!=":ne, ">=":ge, "<=":le, ">":gt, "<":lt} rule = dictRuleFunc.keys() listEqual = [] for k in trm.keys(): if k in term: term = term.replace(k,trm[k]) trs = term.split("@@") listSplitOr = [] if "or" in trs: lst = [] for t in trs: if t != "or": lst.append(t) else: listSplitOr.append(lst) lst = [] if lst: listSplitOr.append(lst) else: listSplitOr = [trs] for trsAnd in listSplitOr: listEqual = [] for t in trsAnd: flagRule = False for sepF in rule: if sepF in t: flagRule = True vals = t.split(sepF) break if flagRule: #проверка на допустимость названия переменной flagFunction = False if self._reDenyName.search(vals[0]): #проверка на допустимость функции flagError = True if function: searchFunct = self._reFunction.search(vals[0]) if searchFunct: flagError = False flagFunction = True if flagError: self.setError("'%s'"%rpl(term)+" "+ _("incorrect")) self.setError(textError) return False #проверка на допустимость значения if self._reDenyValue.search(vals[1]): self.setError("'%s'"%rpl(term) + " " + _("incorrect")) self.setError(textError) return False flagIntTypeVar = None if flagFunction: valVars = function("#-%s-#"%vals[0]) if valVars is False: self.setError("'%s'"%rpl(term)+" "+ _("incorrect")) self.setError(textError) return False if "load" == searchFunct.group(1) and\ re.search("\(\s*num\s*,",vals[0]): if valVars: try: valVars = int(valVars) except: self.setError("'%s'"%rpl(term) + " " + \ _("incorrect")) self.setError(textError) return False flagIntTypeVar = True else: flagIntTypeVar = False else: if valVars == "" and\ not self._notVersion(vals[1]): valVars = "0" elif vals[1] == "" and\ not self._notVersion(valVars): vals[1] = "0" else: try: valVars = self.objVar.Get(vals[0]) except self.objVar.DataVarsError, e: cl_overriding.printERROR(textError) cl_overriding.printERROR(e) cl_overriding.exit(1) # Номера версий для ini flagNotIniFunct = True # Два значения не пусты flagNotEmptyVals = not (valVars == "" and vals[1] == "") if flagFunction and flagNotEmptyVals and\ searchFunct.group(1) == "ini": # Проверка значения на версию if not self._notVersion(valVars) and\ not self._notVersion(vals[1]): verFile, verVar = self._convertVers(vals[1],valVars) res = dictRuleFunc[sepF](verVar,verFile) if res: listEqual.append(True) else: listEqual.append(False) break flagNotIniFunct = False # Cравниваем номера версий if flagNotIniFunct: if flagNotEmptyVals and\ ("_ver" in vals[0] or\ (flagFunction and searchFunct.group(1)=="pkg") or\ (flagFunction and searchFunct.group(1)=="load" and\ re.search("\(\s*ver\s*,",vals[0]))): # Проверка значения на версию if self._notVersion(vals[1]): self.setError("'%s'"%rpl(term)+" "+\ _("incorrect")) self.setError(_("Value is not version")) return False # Проверка значения функции на версию if self._notVersion(valVars): self.setError("'%s'"%rpl(term)+" "+\ _("incorrect")) self.setError(\ _("Function value is not version")) return False verFile, verVar = self._convertVers(vals[1],valVars) res = dictRuleFunc[sepF](verVar,verFile) if res: listEqual.append(True) else: listEqual.append(False) break flagNotIniFunct = False else: if flagIntTypeVar is None: flagIntTypeVar = True try: valVars = int(valVars) except: flagIntTypeVar = False if flagIntTypeVar: if not vals[1].strip(): vals[1] = 0 try: valFile = int(vals[1]) except: self.setError("'%s'"%rpl(term) +" "+\ _("incorrect")) self.setError(textError) return False valVar = valVars res = dictRuleFunc[sepF](valVar, valFile) if res: listEqual.append(True) else: listEqual.append(False) break else: if sepF == "!=" or sepF == "==": if not vals[1].strip(): vals[1] = "" valFile = vals[1] valVar = valVars res = dictRuleFunc[sepF](valVar, valFile) if res: listEqual.append(True) else: listEqual.append(False) break else: if not flagNotEmptyVals: listEqual.append(False) break else: self.setError("'%s'"%rpl(term) + " "\ + _("incorrect")) self.setError(textError) return False else: if t == "and": if listEqual == [] or False in listEqual: listEqual = [False] break else: listEqual = [True] else: self.setError("'%s'"%rpl(term) + " " + _("incorrect")) self.setError(textError) return False if not (listEqual == [] or False in listEqual): break if listEqual == [] or False in listEqual: return False return True def splitParLine(self, linePar): '''Split params line''' def splitQuote(listPar, quoteSymbol): listTerm = map(lambda x: x+quoteSymbol, ("=",">","<")) flagQ = False mass = [] v = "" for i in listPar: if i.count(quoteSymbol)==1: if flagQ and i.endswith(quoteSymbol): v = v + " " + i mass.append(v) v = "" flagQ = False elif filter(lambda x: x in i, listTerm): flagQ = True v = i else: mass.append(i) elif flagQ: v = v + " " + i else: mass.append(i) foundPar = list(set(mass)-set(listPar)) return not flagQ, filter(lambda x: not x in foundPar, mass),foundPar listPar = re.split("\s+",linePar) flagFoundQ = "'" in linePar flagFoundQQ = '"' in linePar if flagFoundQ and flagFoundQQ: flagQ, listSplQPar, listFoundQPar = splitQuote(listPar, "'") if flagQ: flagQQ, listSplQQPar, listFoundQQPar = splitQuote(listSplQPar, '"') if flagQQ: listPar = listSplQQPar + listFoundQPar + listFoundQQPar elif flagFoundQQ: flagQQ, listSplQQPar, listFoundQQPar = splitQuote(listPar, '"') if flagQQ: listPar = listSplQQPar + listFoundQQPar elif flagFoundQ: flagQ, listSplQPar, listFoundQPar = splitQuote(listPar, "'") if flagQ: listPar = listSplQPar + listFoundQPar if flagFoundQ: listQPar = [] for par in listPar: if par.endswith("'"): listQPar.append(par.replace("'","")) else: listQPar.append(par) listPar = listQPar if flagFoundQQ: listQQPar = [] for par in listPar: if par.endswith('"'): listQQPar.append(par.replace('"','')) else: listQQPar.append(par) listPar = listQQPar return listPar class fileHeader(_terms): """Обработка заголовков шаблонов и конфигурационных файлов """ # Допустимые параметры заголовка allowParam = ["format", "format_conf", "comment", "append", "force", "link", "mirror", "symbolic", "chmod", "chown", "name", "path", "autoupdate", "exec"] # Тип шаблона 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 = ("symbolic", "force", "mirror", "autoupdate") # Результат вычисления условия в заголовке headerTerm = True def __init__(self, templateName, text, comment=False, fileType=False, objVar=False, function=False): self.body = text # Объект с переменными self.objVar=objVar # Параметры описанные в заголовке файла шаблона self.params = {} # некорректные параметры incorrectParams = [] # Поиск строки запустка (#!/bin/bash и.т. д) if comment or fileType!="bin": reExecRes = self.reExecStr.search(self.body) if reExecRes: self.execStr = self.body[reExecRes.start():reExecRes.end()] self.body = self.body[:reExecRes.start()] +\ self.body[reExecRes.end():] # Удаление Заголовка Calculate if comment: titleFirst = "Modified" # В случае текста XML if 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 = "" paramList = self.splitParLine(paramLine) if paramList: for i in paramList: foundTerm = False for term in self.terms: if term in i: foundTerm = True errorMsg = _("Incorrect template") +\ ": "+ templateName +"\n"+\ _("template header not valid")+\ ": "+ i if function: rezTerm = self._equalTerm(i, errorMsg, function) else: rezTerm = self._equalTerm(i, errorMsg) if not rezTerm: self.headerTerm = False break if not foundTerm: par = i.split("=") if len(par) == 1: if i in self.listParNotVal: self.params[i] = "True" else: if i.strip(): incorrectParams = set([i]) elif len(par) == 2: self.params[par[0]] = par[1] self.comment = self._getComment() self.fileType = self._getType() typeAppend = self._getAppend() if typeAppend: self.typeAppend = typeAppend else: self.headerTerm = False self.setError(_("incorrect header parameters - '%s'")\ %"append=%s"%self.params["append"]) if 'exec' in self.params: self.execStr = "#!%s"%self.params['exec'] if not incorrectParams and self.params: incorrectParams = set(self.params.keys()) - set(self.allowParam) if incorrectParams: self.headerTerm = False self.setError(_("incorrect header parameters - '%s'")\ %" ".join(list(incorrectParams))) def _getType(self): """Выдать тип файла""" if "format" in self.params: return self.params["format"] else: return "raw" def _getAppend(self): """Выдать тип добавления файла""" if self.params.has_key("append"): if self.params["append"] in self._fileAppend: return self.params["append"] else: return False else: if self.fileType != "raw" and self.fileType != "bin" and\ self.fileType != "": if "format" in self.params and self.params["format"] == "patch": self.params["append"] = "patch" return "patch" self.params["append"] = "join" return "join" self.params["append"] = "replace" return "replace" def _getComment(self): """Выдать символ комментария файла""" if self.params.has_key("comment"): if self.params["comment"] in ("xml", "XML"): return ("") else: return self.params["comment"] else: return False class dirHeader(_terms): """Обработка заголовков шаблонов директорий """ # Допустимые параметры заголовка allowParam = ["append", "chmod", "chown", "name", "path", "autoupdate"] # Тип вставки шаблона typeAppend = "" # Возможные типы вставки шаблонов _fileAppend = "join", "remove", "skip", "clear" # условные операторы terms = ('>', '<', '==', '!=', '>=', '<=') # параметры без значения listParNotVal = ("symbolic", "force", "autoupdate") # Результат вычисления условия в заголовке headerTerm = True 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 template: '%s'")\ %self.body) flagErrorBody = True if not flagErrorBody: paramList = self.splitParLine(paramLine) if paramList: for i in paramList: foundTerm = False for term in self.terms: if term in i: foundTerm = True errorMsg = _("Incorrect template") +\ ": "+ templateName +"\n"+\ _("template header not valid")+ ": "+ i if function: rezTerm = self._equalTerm(i, errorMsg, function) else: rezTerm = self._equalTerm(i, errorMsg) if not rezTerm: self.headerTerm = False break if not foundTerm: par = i.split("=") if len(par) == 1: if i in self.listParNotVal: self.params[i] = "True" else: if i.strip(): incorrectParams = set([i]) elif len(par) == 2: self.params[par[0]] = par[1] typeAppend = self._getAppend() if typeAppend: self.typeAppend = typeAppend else: self.headerTerm = False self.setError(_("incorrect header parameters - '%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 parameters - '%s'")\ %" ".join(list(incorrectParams))) def _getAppend(self): """Выдать тип добавления директории""" if self.params.has_key("append"): if self.params["append"] in self._fileAppend: return self.params["append"] else: return False else: return "join" class objShare: """Общий клас для объектов, наследуем """ def createFieldTerm(self, name, value, quote, docObj): """Создание поля переменная - значение при создании поля проверяется первый символ названия переменной и добавляется тег action "!" - drop удаляет "+" - join добавляет "-" - replace заменяет """ 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 def getConfig(self): """Выдает конфигурационный файл""" 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) return "".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 = '' docTxt += '%s'% version docTxt += '%s' % typeDoc docTxt += '' self.doc = xml.dom.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 - Cловарь удаляемых полей разделенного списка формируется программой 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 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)= 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: """Методы получения классов и объектов форматов шаблонов""" # Импортированные классы поддерживаемых форматов шаблонов importFormats = {} def getClassObj(self, nameClassTemplate): """Создает класс шаблона по имени""" if nameClassTemplate in self.importFormats: classFormat = self.importFormats[nameClassTemplate] else: try: classFormat = getattr(__import__("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__("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): """Получить информацию о пользователе""" 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 = pwdObj.pw_dir except: cl_overriding.printERROR(_("User %s not found")%str(userName)) cl_overriding.exit(1) if groupsInfo: import grp try: groupName = grp.getgrgid(gid).gr_name except: cl_overriding.printERROR(\ _("Id of group %s not found")%str(gid)) cl_overriding.exit(1) groupsNames = map(lambda x: x.gr_name,\ filter(lambda x: userName in x.gr_mem, grp.getgrall())) groupsNames = [groupName] + groupsNames return uid, gid, homeDir, groupsNames return uid, gid, homeDir class templateFunction(_error, _shareTemplate, _shareTermsFunction): """Класс для функций шаблонов""" # Словарь установленных программ {"имя программы":[версии]} installProg = {} # Cписок просканированных категорий установленных программ installCategory = [] # Флаг сканирования всех установленных программ flagAllPkgScan = False # Список названий функций шаблона namesTemplateFunction = [] # Словарь {название функции шаблона: функция шаблона, ...} templateFunction = {} # Регулярное выражение для сложения sNum = re.compile("\-[^\-\+]+|[^\-\+]+") # Регулярное выражение для умножениея и деления sMD = re.compile("[^\-\+\*\/]+") # директория установленных программ basePkgDir = "/var/db/pkg" # стек глобальных переменных stackGlobalVars = [] # регулярное выражение для поиска версии reFindVer = re.compile("(?<=-)(?:\d+)(?:(?:\.\d+)*)" "(?:[a-z]?)(?:(?:_(?:pre|p|beta|alpha|rc)\d*)*)" "(?:-r\d+)?$") reEmptyLoad = re.compile("^\s*$|^\s*;|^\s*#") # Имя обрабатываемого шаблона nameTemplate = "" # Текст функции шаблона functText = "" def __init__(self, objVar): # Если не определен словарь функций шаблона # import services api from cl_api import packagesAPI, APIError self.packagesAPI = packagesAPI self.APIError = APIError 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._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._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.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") # Словарь времен модификации env файлов self.timeConfigsIni = {} # Словарь хранения переменых полученных функцией env() из env файлов self.valuesVarEnv = {} # Словарь хранения опций для функции info() self.optionsInfo = {} # файл параметров сервисов envFile = self.objVar.Get("cl_env_server_path") # объект конвертирования из старого remote env файла self.convObj = False if os.access(envFile, os.R_OK): self.convObj = False elif os.access("/var/calculate/remote/calculate.env", os.R_OK): from convertenv import convertEnv self.convObj = convertEnv() def 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.printErrTemplate() cl_overriding.printERROR(\ _("error, variable %s not a number")% str(strNum)) cl_overriding.exit(1) elif self.objVar.exists(strNum): try: num = int(self.objVar.Get(strNum)) except: self.printErrTemplate() cl_overriding.printERROR(\ _("error, variable %s not a number")% str(strNum)) cl_overriding.exit(1) else: self.printErrTemplate() cl_overriding.printERROR(\ _("error, local variable %s is not defined")% str(strNum)) cl_overriding.exit(1) if minus: num = -num strNumers.append(num) return sum(strNumers) self.printErrTemplate() cl_overriding.printERROR(_("error, template term %s, incorrect data")\ %str(term)) cl_overriding.exit(1) 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 def funcSum(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона, вычисляет функцию 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.printErrTemplate() cl_overriding.exit(1) return textTemplateTmp def funcExists(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона exists(), проверяет существование файла, если существует выдает '1' если второй параметр root, то проверка осуществляется от корня. """ terms = map(lambda x: x.strip(), funArgv.split(",")) if len(terms) > 2: self.printErrTemplate() cl_overriding.exit(1) fileName = terms[0] flagNotRootFS = True if len(terms) == 2: if terms[1] == "root": flagNotRootFS = False else: self.printErrTemplate() cl_overriding.printERROR(\ _("The second argument of the function is not 'root'")) cl_overriding.exit(1) if fileName[0] == "~": # Получаем директорию пользователя fileName = os.path.join(self.homeDir, fileName.partition("/")[2],"")[:-1] elif fileName[0] != "/": self.printErrTemplate() cl_overriding.printERROR(_("wrong path '%s'")%fileName) cl_overriding.exit(1) else: if flagNotRootFS: fileName = pathJoin(self._baseDir, fileName) replace = "" if os.path.exists(fileName): replace = "1" textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return textTemplateTmp def funcLoad(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона 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.printErrTemplate() cl_overriding.exit(1) else: self.printErrTemplate() cl_overriding.exit(1) flagNotRootFS = True if lenTerms == 3: if terms[2] =="root": flagNotRootFS = False else: self.printErrTemplate() cl_overriding.printERROR(\ _("The third argument of the function is not 'root'")) cl_overriding.exit(1) if lenTerms >= 2: if not terms[0] in ["ver","num","char","key","empty"]: self.printErrTemplate() cl_overriding.printERROR(\ _("the first argument of the function is not " "'ver' or 'num' or 'char' or 'empty'")) cl_overriding.exit(1) 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.printErrTemplate() cl_overriding.printERROR(_("wrong path '%s'")%fileName) cl_overriding.exit(1) else: if flagNotRootFS: fileName = pathJoin(self._baseDir,fileName) replace = "" if os.path.exists(fileName): FD = open(fileName) replace = FD.read().strip() FD.close 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): """Получение имен и номеров версий программ""" pkgs.sort() installProg = {} for pkg in pkgs: findVer = self.reFindVer.search(pkg) if findVer: version = findVer.group() name = pkg.split(version)[0][:-1] if name in installProg: installProg[name].append(version) else: installProg[name] = [version] return installProg def getInstallPkgGentoo(self): """Выдает словарь инсталлированных программ и номеров версий""" pkgs = [] def getFilesDir(pkgs, dirname, names): for nameFile in names: absNameFile = os.path.join(dirname,nameFile) if os.path.isdir(absNameFile): tail = absNameFile.split(self.basePkgDir) if len(tail)==2: tail = tail[1].split('/') if len(tail)==3 and tail[1]!='virtual': pkgs.append(tail[2]) return True os.path.walk(self.basePkgDir,getFilesDir, pkgs) return self.sharePkg(pkgs) def pkg(self, nameProg, installProg): """Выдает установленные версии по имени программы""" if nameProg in installProg: return installProg[nameProg][-1] else: return "" def funcPkg(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона pkg(), выдает номер версии программы""" # Название программы nameProg = funArgv.replace(" ","") # Замена функции в тексте шаблона replace = "" if "/" in nameProg: if nameProg in self.installProg: replace = self.pkg(nameProg, self.installProg) else: category, spl, nProg = nameProg.partition("/") if not category in self.installCategory: self.installCategory.append(category) pathCategory = os.path.join(self.basePkgDir, category) if os.path.exists(pathCategory): pkgs = os.listdir(pathCategory) pkgs = map(lambda x: os.path.join(category,x), pkgs) installProg = self.sharePkg(pkgs) replace = self.pkg(nameProg, installProg) self.installProg.update(installProg) else: if not self.flagAllPkgScan: installProg = self.getInstallPkgGentoo() self.installProg.update(installProg) templateFunction.flagAllPkgScan = True replace = self.pkg(nameProg, self.installProg) textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return textTemplateTmp def funcRnd(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона 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.printErrTemplate() cl_overriding.exit(1) fArgvNames = {'num':string.digits, 'pas':string.ascii_letters + string.digits, 'uuid':string.ascii_lowercase[:6] + string.digits} if not terms[0] in fArgvNames: self.printErrTemplate() cl_overriding.printERROR(\ _("the first argument of the function " "must be 'num','pas' or 'uuid'")) cl_overriding.exit(1) try: lenStr = int(terms[1]) except: self.printErrTemplate() cl_overriding.printERROR(\ _("the second argument of the function is not a number")) cl_overriding.exit(1) choiceStr = fArgvNames[terms[0]] replace = ''.join([random.choice(choiceStr) for i in xrange(lenStr)]) textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return textTemplateTmp def funcCase(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона 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.printErrTemplate() cl_overriding.exit(1) fArgvNames = ['upper','lower','capitalize'] if not terms[0] in fArgvNames: self.printErrTemplate() cl_overriding.printERROR(_("the first argument of the function is " "not 'upper' or 'lower' or 'capitalize'")) cl_overriding.exit(1) try: strValue = str(self.objVar.Get(terms[1])) except: cl_overriding.printERROR(_("error in template %s")\ %self.nameTemplate) cl_overriding.printERROR(_("error, variable %s not found")% str(terms[1])) cl_overriding.exit(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 def funcPush(self, funArgv, resS, localVars, textTemplateTmp): """локальная функция записывает значение переменной в стек глобальных переменных """ 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: self.printErrTemplate() cl_overriding.printERROR(_("error, variable %s exists")\ %str(nameLocVar)) cl_overriding.exit(1) else: # Если переменная не существует if len(terms) == 1: self.printErrTemplate() cl_overriding.printERROR(_("error, variable %s does not exist")\ %str(nameLocVar)) cl_overriding.exit(1) elif len(terms) == 2: value = terms[1].strip() self.stackGlobalVars.append(str(value)) localVars[nameLocVar] = value else: self.printErrTemplate() cl_overriding.exit(1) replace = "" textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return textTemplateTmp def funcPop(self, funArgv, resS, localVars, textTemplateTmp): """локальная функция получает значение из стека глобальных переменных и присваивает локальной переменной """ terms = funArgv.replace(" ","").split(",") # Название локальной переменной nameLocVar = terms[0] if len(terms) == 1: if self.stackGlobalVars: localVars[nameLocVar] = self.stackGlobalVars.pop() else: self.printErrTemplate() cl_overriding.printERROR(\ _("error, global variables stack is empty")) cl_overriding.exit(1) else: self.printErrTemplate() cl_overriding.exit(1) replace = "" textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return textTemplateTmp def loadVarsIni(self, iniFileName): """ Читает файл fileName создает и заполняет переменные на основе этого файла Используеться совместно c funcIni """ localVarsIni = {} # получить объект ini файла config = iniParser(iniFileName) # получаем все секции из конфигурационного файла allsect = config.getAllSectionNames() if not allsect: if self.getError(): # Очистка ошибки _error.error = [] return localVarsIni # Заполняем переменные для funcIni for sect in allsect: sectVars = config.getAreaVars(sect) for name in sectVars.keys(): nameVar = "%s.%s"%(sect,name) valueVar = sectVars[name] localVarsIni[nameVar] = valueVar return localVarsIni def getTimeFile(self, fileName): # Получаем время модификации файла nameEnvFile = os.path.split(fileName)[1] if nameEnvFile in self.timeConfigsIni: return self.timeConfigsIni[nameEnvFile] return 0 def funcIni(self, funArgv, resS, localVars, textTemplateTmp): """локальная функция записывает и считывает значение переменной из ini файла ~./calculate/ini.env """ # Создаем директорию if not os.path.exists(self.pathConfigIni): os.makedirs(self.pathConfigIni) os.chown(self.pathConfigIni, self.uid, self.gid) termsRaw = funArgv.split(",") flagFirst = True terms = [] for term in termsRaw: if flagFirst: terms.append(term.replace(" ","")) flagFirst = False else: val = term.strip() # Флаг (не найдены кавычки) flagNotFoundQuote = True for el in ('"',"'"): if val.startswith(el) and val.endswith(el): terms.append(val[1:-1]) flagNotFoundQuote = False break if flagNotFoundQuote: if not val: terms.append(None) else: terms.append(val) # Название локальной переменной nameLocVar = terms[0] namesVar = nameLocVar.split(".") if len(namesVar) == 1: nameLocVar = "main.%s"%nameLocVar elif len(namesVar)>2: self.printErrTemplate() cl_overriding.exit(1) 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']: self.printErrTemplate() cl_overriding.printERROR(_("the third argument of the function" " is not 'url' or 'purl' or 'unicode'")) cl_overriding.exit(1) if terms[1]: self.printErrTemplate() cl_overriding.exit(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(): 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.printErrTemplate() cl_overriding.exit(1) textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return (textTemplateTmp) def funcReplace(self, funArgv, resS, localVars, textTemplateTmp): """локальная функция заменяет в значении переменной 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) listArgv.append(textArgv) elif term.startswith("'") and term.endswith("'"): listArgv.append(term[1:-1]) else: self.printErrTemplate() cl_overriding.exit(1) return listArgv terms = map(lambda x: x.strip(), funArgv.split(",")) if len(terms) != 3: self.printErrTemplate() cl_overriding.exit(1) 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.printErrTemplate() cl_overriding.printERROR(_("not found template variable '%s'")\ %str(nameVar)) cl_overriding.exit(1) replace = value.replace(old,new) textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return textTemplateTmp def funcEnv(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона env(), выдает значение переменной из env файлов """ terms = funArgv.replace(" ","").split(",") if len(terms) != 1: self.printErrTemplate() cl_overriding.exit(1) 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.printErrTemplate() errMsg = self.getError() if errMsg: cl_overriding.printERROR(errMsg) cl_overriding.exit(1) self.valuesVarEnv[nameVar] = value replace = value textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return textTemplateTmp def funcServer(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона info(), выдает значение опций сервиса из /var/calculate/remote/calculate.env """ terms = funArgv.replace(" ","").split(",") if len(terms)==0 or len(terms)>2: self.printErrTemplate() cl_overriding.exit(1) nameLocalVar = "" if len(terms)==2: if not terms[1]: self.printErrTemplate() cl_overriding.exit(1) nameLocalVar = terms[1] textLine = terms[0] vals = textLine.split(".") if len(vals)!= 2: self.printErrTemplate() cl_overriding.exit(1) if filter(lambda x: not x.strip(), vals): self.printErrTemplate() cl_overriding.exit(1) service, option = vals if not service or not option: self.printErrTemplate() cl_overriding.exit(1) if not self.optionsInfo: # файл /var/calculate/remote/server.env envFile = self.objVar.Get("cl_env_server_path") # получаем словарь всех информационных переменных if self.convObj: optInfo = self.convObj.convert() else: optInfo = self.objVar.GetRemoteInfo(envFile) if optInfo is False: self.printErrTemplate() cl_overriding.exit(1) if optInfo: self.optionsInfo = optInfo replace = '' if service in self.optionsInfo and option in self.optionsInfo[service]: value = self.optionsInfo[service][option] if nameLocalVar: localVars[nameLocalVar] = value else: replace = value elif nameLocalVar: localVars[nameLocalVar] = "" textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return textTemplateTmp def funcGroups(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона groups(), проверяет нахождение пользователя в группах, если находится выдает '1' """ terms = map(lambda x: x.strip(), funArgv.split(",")) groupNames = set(terms) userGroups = set(self.groups) replace = "" if groupNames & userGroups: replace = "1" textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return textTemplateTmp def funcBelong(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона belong(). В случае установки переменной os_belongs_pkg=имя пакета, и совпадения имени пакета в переменной и имени пакета в функции выдает "1" иначе "" Если переменная os_belongs_pkg пуста выдает "1" """ terms = funArgv.replace(" ","").split(",") if len(terms) != 1: self.printErrTemplate() cl_overriding.exit(1) funcPkg = terms[0] if not funcPkg: funcPkg = os.path.split(os.path.dirname(self.nameTemplate))[1] if not funcPkg: cl_overriding.printERROR(_("incorrect template path")) self.printErrTemplate() cl_overriding.exit(1) pkg = self.objVar.Get("cl_belong_pkg") replace = "" if pkg: if pkg == funcPkg: replace = "1" else: replace = "1" textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return textTemplateTmp def funcList(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона list(). Если первый аргумент является именем локальной или глобальной переменной и значение переменной является списком, выдает элемент списка по второму аргументу индексу. Первый элемент имеет индекс 0 """ terms = funArgv.replace(" ","").split(",") # У функции должно быть два аргумента if len(terms) != 2: self.printErrTemplate() cl_overriding.exit(1) # Название локальной или глобальной переменной nameLocVar = terms[0] strIndex = terms[1] try: intIndex = int(strIndex) except: cl_overriding.printERROR(_("'%s' is not a number")%strIndex) self.printErrTemplate() cl_overriding.exit(1) 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: # Если переменная не существует cl_overriding.printERROR(_("error, variable %s does not exist")\ %str(nameLocVar)) self.printErrTemplate() cl_overriding.exit(1) if not type(value) in (list,tuple): # Значение переменной не список или кортеж cl_overriding.printERROR(_("value of %s is not a list or a tuple")\ %str(nameLocVar)) self.printErrTemplate() cl_overriding.exit(1) try: if len(value) > intIndex: replace = str(value[intIndex]) else: replace = "" except: cl_overriding.printERROR(_("wrong %s")%strIndex) self.printErrTemplate() cl_overriding.exit(1) textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return textTemplateTmp def funcDisk(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона 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.printErrTemplate() cl_overriding.exit(1) # Название глобальной переменной mountPoint = terms[0] lastElementVar = terms[1] if not mountPoint or mountPoint[:1] !="/": cl_overriding.printERROR(_("wrong %s")%lastElementVar) self.printErrTemplate() cl_overriding.exit(1) nameVar = "os_install_disk_mount" try: valueVar = self.objVar.Get(nameVar) except: # Если переменная не существует cl_overriding.printERROR(_("error, variable %s does not exist")% nameVar) self.printErrTemplate() cl_overriding.exit(1) nameElementVar = "os_install_disk_%s"%lastElementVar try: valueElementVar = self.objVar.Get(nameElementVar) except: # Если переменная не существует nameElementVar = "os_disk_%s"%lastElementVar try: valueElementVar = self.objVar.Get(nameElementVar) except: cl_overriding.printERROR(_("wrong %s")%lastElementVar) cl_overriding.printERROR(_("error, variable %s does not exist")\ %nameElementVar) self.printErrTemplate() cl_overriding.exit(1) if not type(valueVar) in (list,tuple): # Значение переменной не список или кортеж cl_overriding.printERROR(_("value of %s is not a list or a tuple")\ %nameVar) self.printErrTemplate() cl_overriding.exit(1) if not type(valueElementVar) in (list,tuple): # Значение переменной не список или кортеж cl_overriding.printERROR(_("value of %s is not a list or a tuple")\ %nameElementVar) self.printErrTemplate() cl_overriding.exit(1) if len(valueVar) != len(valueElementVar): cl_overriding.printERROR(\ _("size %(name)s is not equal to the size of %(nameElement)s")\ %{'name':nameVar, 'nameElement':nameElementVar}) self.printErrTemplate() cl_overriding.exit(1) 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: cl_overriding.printERROR(_("mount point '\\' or '\\%s' not found " "in the value of variable os_disk_install")%mountPoint) self.printErrTemplate() cl_overriding.exit(1) replace = valueElementVar[index] textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return textTemplateTmp def funcModule(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона module(), выдает значение аттрибута api. аргумент: путь_к_атрибуту - путь к аттрибуту возможные пути: имя_пакета.var.имя_переменной - получаем значение переменной имя_пакета.имя_метода_api - выполнение метода, получение результата all.имя_метода_api - выполнение метода для всех пакетов с api """ terms = funArgv.replace(" ","").split(",") if len(terms)!=1: self.printErrTemplate() cl_overriding.exit(1) pathObj = terms[0] if not '.' in pathObj: self.printErrTemplate() cl_overriding.exit(1) pkgApiObj = self.packagesAPI() try: value = eval('pkgApiObj.%s'%pathObj) except self.APIError, e: cl_overriding.printERROR(str(e)) self.printErrTemplate() cl_overriding.exit(1) except Exception, e: value = "" if value is True: replace = '1' elif value in (False, None): replace = '' else: replace = str(value) textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return textTemplateTmp def printErrTemplate(self): """Печать ошибки при обработке функций шаблона""" cl_overriding.printERROR(_("error in template %s")%self.nameTemplate) cl_overriding.printERROR(_("error, template term '%s'")\ %str(self.functText)) def applyFuncTemplate(self, textTemplate, nameTemplate): """Применяет функции к тексту шаблона""" # Локальные переменные localVars = {} # Имя обрабатываемого шаблона self.nameTemplate = nameTemplate # Регулярное выражение для поиска функции в шаблоне reFunc = self._reFunc resS = reFunc.search(textTemplate) textTemplateTmp = textTemplate flagIniFunc = False while resS: mark = textTemplateTmp[resS.start():resS.end()] self.functText = mark[self._deltVarStart:-self._deltVarEnd] funcName, spl, funcEnd = self.functText.partition("(") if funcName in self.namesTemplateFunction: # аргументы функции - '(' аргументы ')' funArgv = funcEnd.rpartition(")")[0] # вызов функции шаблона textTemplateTmp = self.templateFunction[funcName](self, funArgv, resS, localVars, textTemplateTmp) resS = reFunc.search(textTemplateTmp) if funcName == "ini": flagIniFunc = True else: self.printErrTemplate() cl_overriding.printERROR(\ _("function of templates '%s' not found")\ %str(self.functText)) cl_overriding.exit(1) 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 = iniParser(self.fileConfigIni) # set specified mode for ini file config.setMode(self.modeConfigIni) # секции будущего конфигурационного файла sects = list(set(map(lambda x: x.split(".")[0],\ self.currDictIni.keys()))) # запись переменных в файл for sect in sects: dictVar = {} for varName in self.currDictIni.keys(): if varName.startswith("%s."%sect): nameVar = varName.rpartition(".")[2] valueVar = self.currDictIni[varName] if valueVar is None: config.delVar(sect,nameVar) else: dictVar[nameVar] = valueVar if dictVar: # Запись переменных в секцию config.setVar(sect, dictVar) # читаем переменные из файла 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 os.path.exists(self.fileConfigIni): uid, gid = getModeFile(self.fileConfigIni, "owner") if self.uid!=uid or self.gid!=gid: os.chown(self.fileConfigIni, self.uid, self.gid) return textTemplateTmp class template(_file,_terms,_warning,xmlShare,templateFormat,_shareTemplate): """Класс для работы с шаблонами На вход 2 параметра: объект хранения переменных, имя сервиса - не обязательный параметр """ # Название файла шаблона директории templDirNameFile = ".calculate_directory" titleEnd = "For modify this file, create %(conf_path)s.clt template." protectPaths = [] 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) def __init__(self, objVar, servDir=False, dirsFilter=[], filesFilter=[], cltObj=True, cltFilter=True, printWarning=True): # Предупреждения self.warning = [] # Печатать ли предупреждения о корневых шаблонах без cl_name==pkg self.printWarning = printWarning # Необрабатываемые директории self.dirsFilter = dirsFilter # Необрабатываемые файлы self.filesFilter = filesFilter _file.__init__(self) # Словарь для создания объектов новых классов по образцу self.newObjProt = {'proftpd':'apache'} # Заголовок title self.__titleHead = "--------------------------------------\ ----------------------------------------" self._titleBody = "" self._titleList = ("Modified", "Processing template files" + ":") self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")%(self.varStart, self.varEnd),re.M) # Условия self._reTermBloc = re.compile("#\?(?P[a-zA-Z0-9\-_]+)\ (?P\((%s+|)\))?\ (?P[\>\<\=\!\&\|]+\ [\>\<\=\!\|\&\(\)%s]*)#\ \n*(?P.+?)\n*#(?P=rTerm)#(?P[ ,\t]*\n?)"\ %(self._reFunctionArgvText, self._reFunctionArgvInSquareBrackets), re.M|re.S) # Объект с переменными self.objVar = objVar # Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д self._baseDir = pathJoin(self.objVar.Get("cl_chroot_path"), self.objVar.Get("cl_root_path")) self._baseDir = os.path.normpath(self._baseDir) # Последняя часть директории шаблона (имя сервиса: 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.applyFuncTemplate = self.functObj.applyFuncTemplate # Объект для определения типа файла шаблона self.typeFileObj = typeFile() self.uid, self.gid, self.homeDir = self.getDataUser() # Домашняя директория, плюс базовая директория self.homeDir = pathJoin(self._baseDir, self.homeDir) # Глобальный словарь обработанных шаблонов файлов # {путь к конф. файлу:[имена шаблонов] ...} self.dictProcessedTemplates = {} if cltObj is True: # Объект templateClt self.cltObj = templateClt(self.objVar) elif cltObj: # Объект templateClt self.cltObj = cltObj else: # Объект templateClt self.cltObj = False # Фильтровать ли шаблоны clt по конфигурационным файлам обычных шаблонов self.cltFilter = cltFilter # autoupdate файлы self.autoUpdateFiles = [] self.autoUpdateDirs = [] # список выполненных файлов self.executedFiles = [] def executeTemplate(self, path, execPath): """Execute template""" if os.system("""{interpreter} {cmdfile}""".format( interpreter=execPath, cmdfile=path)) == 0: self.executedFiles.append((path,execPath)) return True else: return False def __octToInt(self, strOct): """Преобразование восьмеричного в целое (ввод строка, вывод число)""" if strOct: try: res = string.atoi(strOct, 8) except ValueError: self.setError(_("Invalid oct value: ") + str(strOct)) return False return res else: self.setError(_("Empty oct value")) return False def getTemplateType(self): """выдать тип шаблона (text, bin)""" return self.getFileType(self.nameFileTemplate) def getFileType(self, fileName): """выдать тип файла (text, bin)""" isBin = self.typeFileObj.isBinary(fileName) typeTemplate = "bin" if isBin is True: typeTemplate = "bin" elif isBin is False: typeTemplate = "text" else: self.setError(_("ERROR") + ": getFileType()") self.setError(isBin) return False return typeTemplate def createDir(self, dirName, mode=False, uid=False, gid=False): """Создает директорию""" if os.access(dirName, os.F_OK): return True else: dMode = False prevDir, tmpSubdir = os.path.split(dirName) createDirs = [] while not os.access(prevDir, os.F_OK) and prevDir: createDirs.append(prevDir) prevDir = os.path.split(prevDir)[0] try: dUid,dGid = getModeFile(prevDir,"owner") except OSError: self.setError(_("No access to the directory: " ) + prevDir) return False if not mode is False: dMode = mode if not uid is False: dUid = uid if not gid is False: dGid = gid createDirs.reverse() for nameDir in createDirs: try: if dMode: os.mkdir(nameDir, dMode) os.chmod(nameDir, dMode) else: os.mkdir(nameDir) os.chown(nameDir, dUid, dGid) except: 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: self.setError(_("Failed to create the directory: " ) + dirName) return False return createDirs def applyVarsTemplate(self, textTemplate, nameTemplate): """ Заменяет переменные на их значения """ resS = self._reVar.search(textTemplate) textTemplateTmp = textTemplate while resS: mark = textTemplateTmp[resS.start():resS.end()] varName = mark[self._deltVarStart:-self._deltVarEnd] varValue = "" try: varValue = str(self.objVar.Get(varName)) except self.objVar.DataVarsError, e: cl_overriding.printERROR(_("error in template %s")%nameTemplate) cl_overriding.printERROR(e) cl_overriding.exit(1) 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") 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:]: if self._equalTerm(term, _("invalid template name: ")+\ fileTemplate): flagTrue = True break if flagTrue: return True else: return False else: return True else: self.setError(_("invalid template name: ")+ str(fileTemplate)) return False def getTitle(self, comment, commentList, configPath=""): """Выдает заголовок шаблона ( версия и.т.д)""" if configPath and self.protectPaths: flagFoundPath = False for protectPath in self.protectPaths: if self._baseDir != "/": lenBaseDir = len(self._baseDir) if len(configPath)>lenBaseDir and\ configPath[:lenBaseDir] == self._baseDir: configPath = configPath[lenBaseDir:] if configPath.startswith(protectPath + "/"): flagFoundPath = True break if flagFoundPath: commentList = commentList +\ [self.titleEnd%{'conf_path':configPath}] 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 numberAllTemplates(self, number): """Количество шаблонов Вызов происходит перед наложением шаблонов в момент вызова в number находится количество обрабатываемых файлов Наследуемая функция Используется для отображения прогресса при наложениии шаблонов """ return True def numberProcessTemplates(self, number): """Номер текущего обрабатываемого шаблона Вызов происходит при наложении шаблона в момент вызова в number находится номер обрабатываемого шаблона Наследуемая функция Используется для отображения прогресса при наложениии шаблонов """ return True 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""" skipDirs = [] skipTemplates = [] for dirsTemplate in dirsTemplates: filesAndDirs = map(lambda x: os.path.join(dirsTemplate,x), os.listdir(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 "cl_name==" 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 printObj = color_print() setWARNING = lambda x: self.setWarning(x) and\ self.printWarning and\ printObj.printWARNING(x) setWARNING(_("No conditions of checking the value of " "variable 'cl_name'")) skipDirTemplates = [] for skipDir in skipDirs: skipTempl = os.path.join(skipDir,self.templDirNameFile) if os.path.isfile(skipTempl): skipDirTemplates.append(skipTempl) if skipTemplates or skipDirTemplates: setWARNING(_("Skipped templates:")) for skipTemplate in skipTemplates + skipDirTemplates: setWARNING(" "*6 + skipTemplate) if skipDirs: setWARNING(_("Skipped directories:")) for skipDir in skipDirs: setWARNING(" "*6 + skipDir) setWARNING("") setWARNING(_("Headers of directory templates and headers of files " "on the first level should include 'cl_name' variable.")) setWARNING(_("Example:")) setWARNING("# Calculate cl_name==calculate-install") return skipDirs + skipTemplates def applyTemplates(self): """Применяет шаблоны к конфигурационным файлам""" 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 self.objVar.defined("cl_template_path"): self.setError(_("undefined variable: ") + "cl_template_path") return False dirsTemplates = self.objVar.Get("cl_template_path") dirsTemplates.sort() # Созданные директории 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 = {} if self._servDir: tmpDirsTemplates = [] for dirP in dirsTemplates: dirTempl = dirP + self._servDir if os.access(dirTempl, os.F_OK): # Если директория существует tmpDirsTemplates.append(dirTempl) dirsTemplates = tmpDirsTemplates scanObj = scanDirectory() scanObj.processingFile = lambda x,y: createDictTemplates(x, y,\ self.dictTemplates) # Считаем количество шаблонов dirsTemplatesExists = filter(lambda x: os.path.exists(x), dirsTemplates) if not dirsTemplatesExists: self.setError(_("No such template directories") +\ ": %s"%", ".join(map(lambda x: "'%s'"%x ,dirsTemplates))) return (self.createdDirs, self.filesApply) # check cl_name in first template dirs and files skipTemplates = self.getTemplateDirs(dirsTemplatesExists) 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 # общее количество шаблонов self.allTemplates += self.cltObj.allTemplates self.cltObj.allTemplates = self.allTemplates self.numberAllTemplates(self.allTemplates) # Обрабатываем шаблоны for dirTemplate in dirsTemplatesExists: if self.scanningTemplates(dirTemplate, skipTemplates=skipTemplates) is False: return False if self.cltObj: # Созданные директории 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.dictProcessedTemplates = self.dictProcessedTemplates self.cltObj.autoUpdateFiles = self.autoUpdateFiles self.cltObj.autoUpdateDirs = self.autoUpdateDirs if self.cltFilter: # Шаблоны + .clt которые будут применены self.cltObj.filterApplyTemplates +=\ map(lambda x: pathJoin('/', x.partition(self._baseDir)[2]), self.dictProcessedTemplates.keys()) if not self.cltObj.applyTemplates(): return False return (self.createdDirs, 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: optDir["autoupdate"] = True if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]): for fileOrDir in sorted(os.listdir(scanDir)): absPath = os.path.join(scanDir,fileOrDir) if skipTemplates and absPath in skipTemplates: continue stInfo = os.lstat(absPath) statInfo = stInfo[stat.ST_MODE] if stat.S_ISREG(statInfo): if not self.processingFile(absPath, prefix, optDir): ret = False break 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: optNextDir["autoupdate"] = True ret = self.scanningTemplates(absPath, prefix, True, optNextDir) if ret is False: break return ret def processingFile(self, path, prefix, optFile): """Обработка в случае шаблона файла""" self.numberProcessTempl += 1 self.numberProcessTemplates(self.numberProcessTempl) # Пропуск шаблонов директорий if self.templDirNameFile == os.path.split(path)[1]: return True # Проверка на переменные в названии файла if not self.getNeedTemplate(path): if self.getError(): return False return True if self.getError(): return False nameFileConfig = path.partition(prefix)[2] # файл в системе без условий nameFileConfig = "/".join(map(lambda x:x.split("?")[0],\ nameFileConfig.split("/"))) # Записываем в переменную обрабатываемый файл self.objVar.Set("cl_pass_file",nameFileConfig) filesApl = self.joinTemplate(path, nameFileConfig, optFile) if self.getError(): return False if filesApl: # Настоящее имя конфигурационного файла nameFileConfig = filesApl[0] # Пишем время модификации *.env файлов if nameFileConfig.endswith(".env"): nameEnvFile = os.path.basename(nameFileConfig) self.functObj.timeConfigsIni[nameEnvFile] = float(time.time()) self.filesApply += filesApl return True def processingDirectory(self, path, prefix, opt): """Обработка в случае директории если возвращаем None то пропуск дир.""" # Файл шаблона директории dirInfoFile = os.path.join(path, self.templDirNameFile) newDir = pathJoin(self._baseDir, path.partition(prefix)[2]) newDir = "/".join(map(lambda x:x.split("?")[0], newDir.split("/"))) # Применяем шаблон pathDir, objHeadDir, createdDirs =\ self.getApplyHeadDir(newDir, dirInfoFile, opt) if createdDirs: self.createdDirs += createdDirs if objHeadDir: return pathDir, objHeadDir else: if self.getError(): return False # Добавление количества файлов в пропущенной директории if path in self.dictTemplates.keys(): self.numberProcessTempl += self.dictTemplates[path] return None def getApplyHeadDir(self, newDir, templateDirFile, optDir): """Применяет шаблон к директории (права, владелец, и.т. д)""" def function(text): """Функция обработки функций в заголовке""" return self.applyFuncTemplate(text, templateDirFile) def chownConfDir(nameDirConfig, uid, gid, nameFileTemplate): """Изменение владельца конфигурационной директории""" try: os.chown(nameDirConfig, uid, gid) except: 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, nameDirConfig)) return False return True applyDir = newDir # Родительская директория if optDir.get("path"): path = optDir["path"] else: if applyDir == self._baseDir: path = os.path.dirname(self._baseDir) else: path = os.path.split(applyDir)[1] path = pathJoin(self._baseDir, path) if not os.path.exists(templateDirFile): if applyDir != self._baseDir: applyDir = os.path.join(path, os.path.split(applyDir)[1]) # Фильтрация шаблонов по названию директории realPath = os.path.join("/",applyDir.partition(self._baseDir)[2]) if realPath in self.dirsFilter: return ("", False, []) # Создаем директорию если необходимо crDirs = self.createDir(applyDir, False, self.uid, self.gid) if not crDirs: return ("", False, []) if "autoupdate" in optDir: self.autoUpdateDirs.append(applyDir) if crDirs is True: return (applyDir, True, []) else: return (applyDir, True, crDirs) try: FD = open(templateDirFile) textTemplate = FD.read() FD.close() except: self.setError(_("Error in opening template") + ": " +\ templateDirFile) return ("", False, []) # Заменяем переменные на их значения textTemplate = self.applyVarsTemplate(textTemplate, templateDirFile) # Заменяем функции на их значения textTemplate = self.applyFuncTemplate(textTemplate, templateDirFile) # Обработка заголовка objHead = dirHeader(templateDirFile,textTemplate,self.objVar,function) # Директория с профилями не будет применена if not objHead.headerTerm: if objHead.getError(): self.setError(_("Incorrect template") + ": " +\ templateDirFile) return ("", False, []) # Пропускаем директорию if objHead.typeAppend == "skip": applyDir = path return (applyDir, objHead, []) # Изменяем название родительской директории if "path" in objHead.params: path = objHead.params['path'] if path and path[0] == "~": # Получаем путь с заменой ~ на директорию пользователя path = os.path.join(self.homeDir, path.partition("/")[2],"")[:-1] elif not path or path and path[0] != "/": self.setError(_("Wrong value 'path' in the template") + ": " +\ templateDirFile) return ("", False, []) else: path = pathJoin(self._baseDir, path) # Изменяем название директории if "name" in objHead.params: nameDir = objHead.params['name'] if "/" in nameDir or nameDir == ".." or nameDir == ".": self.setError(_("Wrong value 'name' in the template") + ": " +\ templateDirFile) return ("", False, []) # Новый путь к директории applyDir = pathJoin(path, nameDir) else: applyDir = pathJoin(path, os.path.split(applyDir)[1]) # Фильтрация шаблонов по названию директории realPath = os.path.join("/",applyDir.partition(self._baseDir)[2]) if realPath in self.dirsFilter: return ("", False, []) # Удаляем директорию if objHead.typeAppend == "remove": if os.path.isdir(applyDir): # удаляем директорию try: removeDir(applyDir) except: self.setError(_("Failed to delete the directory: " ) +\ applyDir) return ("", False, []) # Очищаем директорию if objHead.typeAppend == "clear": if os.path.isdir(applyDir): for rmPath in os.listdir(applyDir): removePath = pathJoin(applyDir, rmPath) if os.path.isdir(removePath): # удаляем директорию try: removeDir(removePath) except: self.setError( _("Failed to delete the directory: ") +\ removePath) else: try: os.unlink(removePath) except: self.setError(_("Failed to delete: " ) + removePath) return ("", False, []) # Созданные директории createdDirs = [] # chmod - изменяем права if "chmod" in objHead.params: mode = self.__octToInt(objHead.params['chmod']) if mode: if not os.path.exists(applyDir): crDirs = self.createDir(applyDir, mode, self.uid, self.gid) if not crDirs: return ("", False, []) if not crDirs is True: createdDirs += crDirs else: os.chmod(applyDir, mode) else: self.setError(_("Wrong value 'chmod' in the template") + ": " +\ templateDirFile) return ("", False, []) # chown - изменяем владельца и группу if "chown" in objHead.params: owner = objHead.params['chown'] if owner: if ":" in owner: strUid, strGid = owner.split(":") import pwd uid = self.getUidFromPasswd(strUid) try: uid = pwd.getpwnam(strUid).pw_uid except: self.setError(_("No such user on the system: ") + strUid) self.setError(_("Wrong value 'chown' in the template")+\ ": " + templateDirFile) return ("", False, []) gid = self.getGidFromGroup(strGid) try: import grp gid = grp.getgrnam(strGid).gr_gid except: self.setError(_("Group not found on the system: ") +strGid) self.setError(_("Wrong value 'chown' in the template")+\ ": "+ templateDirFile) return ("", False, []) if not os.path.exists(applyDir): crDirs = self.createDir(applyDir, False, uid, gid) if not crDirs: return ("", False, []) if not crDirs is True: createdDirs += crDirs else: if not chownConfDir(applyDir, uid, gid, templateDirFile): return ("", False, []) else: self.setError(_("Wrong value 'chown' in the template") + ": " + templateDirFile) return ("", False, []) else: self.setError(_("Wrong value 'chown' in the template") + ": " +\ templateDirFile) return ("", False, []) else: # Устанавливаем владельцем директории, пользователя по умолчанию # (переменная шаблона ur_login) if os.path.exists(applyDir): tUid, tGid = getModeFile(applyDir, mode="owner") if (self.uid, self.gid) != (tUid, tGid): if not chownConfDir(applyDir, self.uid, self.gid, templateDirFile): return ("", False, []) else: 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: self.autoUpdateDirs.append(applyDir) return (applyDir, objHead, createdDirs) def getUidFromPasswd(self,strUid): """Get uid by username from chroot passwd file""" passwdFile = os.path.join(self._baseDir,'etc/passwd') if os.path.exists(passwdFile): mapUid = dict( filter(lambda x:x[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[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 getApplyHeadTemplate(self, nameFileTemplate, nameFileConfig, templateFileType, optFile): """Применяет заголовок к шаблону (права, владелец, и.т. д)""" def function(text): """Функция обработки функций в заголовке""" return self.applyFuncTemplate(text,nameFileTemplate) def preReturn(pathProg): """Действия перед выходом из метода""" if pathProg: os.chdir(pathProg) def chownConfFile(nameFileConfig, uid, gid, nameFileTemplate, checkExists=True): """Изменение владельца конфигурационного файла""" try: if checkExists and not os.path.exists(nameFileConfig): # Создание файла FD = open(nameFileConfig, "w") FD.close() os.chown(nameFileConfig, uid, gid) except: 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: 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 = "" # Файлы в системе к которым были применены шаблоны applyFiles = [nameFileConfig] # В случае бинарного типа файла читаем шаблон if templateFileType == "bin": self.nameFileTemplate = os.path.abspath(nameFileTemplate) self.F_TEMPL = self.openTemplFile(self.nameFileTemplate) if not self.F_TEMPL: self.setError(_("Error in opening template") + ": " +\ templateDirFile) return False self.textTemplate = self.F_TEMPL.read() self.closeTemplFile() objHeadNew = fileHeader(nameFileTemplate, self.textTemplate, False, templateFileType ,objVar=self.objVar, function=function) # файл шаблона не будет применен if not objHeadNew.headerTerm: if objHeadNew.getError(): self.setError(_("Incorrect template") + ": " +\ nameFileTemplate) return ([], False) # Родительская директория path = optFile["path"] # Изменяем название родительской директории if "path" in objHeadNew.params: path = objHeadNew.params['path'] if path and path[0] == "~": # Получаем путь с заменой ~ на директорию пользователя path = os.path.join(self.homeDir,path.partition("/")[2],"")[:-1] elif not path or path and path[0] != "/": self.setError(_("Wrong value 'path' in the template") + ": " +\ nameFileTemplate) return ([], False) else: path = pathJoin(self._baseDir, path) # Путь к оригинальному файлу - pathOldFile # Изменяем путь к оригинальному файлу if objHeadNew.params.has_key("name"): nameFile = objHeadNew.params['name'] if "/" in nameFile or nameFile == ".." or nameFile == ".": self.setError(_("Wrong value 'name' in the template") + ": " +\ nameFileTemplate) return ([], False) # Новый путь к оригинальному файлу pathOldFile = pathJoin(path,nameFile) else: pathOldFile = pathJoin(path,os.path.split(nameFileConfig)[1]) applyFiles = [pathOldFile] # Фильтрация шаблонов по названию файла realPath = os.path.join("/",pathOldFile.partition(self._baseDir)[2]) if realPath in self.filesFilter: return ([], False) typeAppendTemplate = objHeadNew.typeAppend # Параметр exec if "exec" in objHeadNew.params: execPath = objHeadNew.params['exec'] if not os.access(execPath,os.X_OK): self.setError(_("Wrong value 'exec' in the template") + ": " +\ nameFileTemplate) self.setError(_("Failed to execute %s") %execPath) return ([], False) if typeAppendTemplate == "join": self.setError(_("Wrong value 'append=join' in the template") +\ ": " + nameFileTemplate) return ([], False) # Очищаем оригинальный файл if typeAppendTemplate == "clear": try: open(pathOldFile, "w").truncate(0) except: self.setError(_("Template error") + ": " +\ nameFileTemplate) self.setError(_("Failed to clear the file") + ": " +\ pathOldFile) return (applyFiles, False) # Удаляем оригинальный файл if typeAppendTemplate == "remove": if os.path.islink(pathOldFile): # удаляем ссылку try: os.unlink(pathOldFile) except: self.setError(_("Template error") + ": " +\ nameFileTemplate) self.setError(_("Failed to delete the link") + ": " +\ pathOldFile) return ([], False) if os.path.isfile(pathOldFile): # удаляем файл try: os.remove(pathOldFile) except: self.setError(_("Template error") + ": " +\ nameFileTemplate) self.setError(_("Failed to delete the file") + ": " +\ pathOldFile) return ([], False) return (applyFiles, False) # Пропускаем обработку шаблона elif typeAppendTemplate == "skip": return ([], False) # Создаем директорию для файла если ее нет if not os.path.exists(path): if not self.createDir(path): return ([], False) # В случае force if objHeadNew.params.has_key("force"): if os.path.islink(pathOldFile): # удаляем ссылку try: os.unlink(pathOldFile) except: self.setError(_("Template error") + ": " +\ nameFileTemplate) self.setError(_("Failed to delete the link") + ": " +\ pathOldFile) return ([], False) if os.path.isfile(pathOldFile): # удаляем файл try: os.remove(pathOldFile) except: self.setError(_("Template error") + ": " +\ nameFileTemplate) self.setError(_("Failed to delete the file") + ": " +\ pathOldFile) return ([], False) flagSymlink = False flagForce = False # Если есть параметр mirror if objHeadNew.params.has_key("mirror"): if objHeadNew.params.has_key("link"): templateFile = objHeadNew.params['link'] templateFile = pathJoin(self._baseDir, templateFile) if not os.path.exists(templateFile): if os.path.exists(pathOldFile): try: os.remove(pathOldFile) except: self.setError(_("Template error") + ": " +\ nameFileTemplate) self.setError(_("Failed to delete the file") + \ ": " + pathOldFile) return ([], False) elif not os.path.exists(pathOldFile): return ([], False) # Если есть указатель на файл шаблона (link) if objHeadNew.params.has_key("link") and\ not objHeadNew.params.has_key("symbolic"): templateFile = objHeadNew.params['link'] 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) return ([], False) if os.path.exists(pathOldFile): try: os.remove(pathOldFile) except: self.setError(_("Template error") + ": " +\ nameFileTemplate) self.setError(_("Failed to delete the file") + ": " +\ pathOldFile) return ([], False) if foundTemplateFile: try: FD = open(pathOldFile, "w+") FD.write(buff) FD.close() except: self.setError(_("Template error") + ": " +\ nameFileTemplate) self.setError(_("Failed to create the file") + " '%s'"\ %pathOldFile) return ([], False) oMode = getModeFile(pathOldFile, mode="mode") # Если права не совпадают, меняем права if fMode != oMode: if not chmodConfFile(pathOldFile, fMode, nameFileTemplate, checkExists=False): return ([], False) # Если символическая ссылка if objHeadNew.params.has_key("symbolic"): prevOldFile = pathOldFile pathOldFile = objHeadNew.params['link'] flagSymlink = True 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) self.setError( _("Failed to change the current directory to")+\ " " + pathLink) return ([], False) # chmod - изменяем права if objHeadNew.params.has_key("chmod"): mode = self.__octToInt(objHeadNew.params['chmod']) if mode: if not chmodConfFile(pathOldFile, mode, nameFileTemplate): preReturn(pathProg) return ([], False) else: self.setError(_("Wrong value 'chmod' in the template") + ": " +\ nameFileTemplate) preReturn(pathProg) return ([], False) # chown - изменяем владельца и группу if objHeadNew.params.has_key("chown"): owner = objHeadNew.params['chown'] if owner: if ":" in owner: strUid, strGid = owner.split(":") if strUid.isdigit(): uid = int(strUid) else: uid = self.getUidFromPasswd(strUid) import pwd try: if uid is None: uid = pwd.getpwnam(strUid).pw_uid except: self.setError(_("No such user on the system: ") + strUid) self.setError( _("Wrong value 'chown' in the template") + ": "+ nameFileTemplate) preReturn(pathProg) return ([], False) if strGid.isdigit(): gid = int(strGid) else: gid = self.getGidFromGroup(strGid) try: if gid is None: import grp gid = grp.getgrnam(strGid).gr_gid except: self.setError(_("Group not found on the system: ") + strGid) self.setError( _("Wrong value 'chown' in the template") + ": "+ nameFileTemplate) preReturn(pathProg) return ([], False) # Изменяем владельца файла if not chownConfFile(pathOldFile,uid,gid,nameFileTemplate): preReturn(pathProg) return ([], False) else: self.setError(_("Wrong value 'chown' in the template") + ": " + nameFileTemplate) preReturn(pathProg) return ([], False) else: self.setError(_("Wrong value 'chown' in the template") + ": " +\ nameFileTemplate) preReturn(pathProg) return ([], False) if not flagSymlink: self.openFiles(nameFileTemplate, pathOldFile) if self.getError(): return ([], False) if not objHeadNew.params.has_key("chown"): # Устанавливаем владельцем конфигурационного файла, # пользователя по умолчанию (переменная шаблона ur_login) if os.path.exists(pathOldFile): tUid, tGid = getModeFile(pathOldFile, mode="owner") if (self.uid, self.gid) != (tUid, tGid): # Изменяем владельца файла if not chownConfFile(pathOldFile, self.uid, self.gid, nameFileTemplate, checkExists=False): preReturn(pathProg) return ([], False) if flagSymlink: if os.path.exists(prevOldFile) or os.path.islink(prevOldFile): try: if os.path.islink(prevOldFile): # если ссылка то удаляем её os.unlink(prevOldFile) else: # иначе удаляем файл os.remove(prevOldFile) except: self.setError(_("Template error") + ": " +\ nameFileTemplate) self.setError(_("Failed to delete the file") + ": " +\ prevOldFile) preReturn(pathProg) return ([], False) if not "/" == pathOldFile[0]: applyFiles = [prevOldFile]#,os.path.join(pathLink,pathOldFile)] else: applyFiles = [prevOldFile]#,pathOldFile] try: os.symlink(pathOldFile, prevOldFile) except: self.setError(_("Template error") + ": " +\ nameFileTemplate) self.setError(_("Failed to create a symbolic link") + " :" +\ "%s -> %s"%(prevOldFile, pathOldFile)) preReturn(pathProg) return ([], False) if not objHeadNew.body.strip(): preReturn(pathProg) return (applyFiles, False) else: applyFiles = [pathOldFile] if pathProg: os.chdir(pathProg) # Если файлы заменяются не нужно их обрабатывать дальше if typeAppendTemplate == "replace" and\ not objHeadNew.params.has_key("symbolic") and\ objHeadNew.params.has_key("link"): preReturn(pathProg) return ([], 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: self.autoUpdateFiles += 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.exists(fileName): FD = open(os.path.abspath(fileName)) newTemplate = FD.read() FD.close() try: newTemplate.decode("UTF-8") except: return False return True def joinTemplate(self, nameFileTemplate, nameFileConfig, optFile={}): """Объединения шаблона и конф. файла join(nameFileTemplate, nameFileConfig, ListOptTitle) Объединение шаблона nameFileTemplate и конф. файла nameFileConfig, ListOptTitle - список строк которые добавятся в заголовок optFile = опции для шаблона """ # Выполняем условия для блока текста а так-же заменяем переменные self.nameFileTemplate = os.path.abspath(nameFileTemplate) self.F_TEMPL = self.openTemplFile(self.nameFileTemplate) self.textTemplate = self.F_TEMPL.read() self.closeTemplFile() # Флаг копирования шаблона в конфигурационный файл flagCopyTemplate = True # Тип шаблона бинарный или текстовый templateFileType = self.getTemplateType() if templateFileType != "bin": # Вычисляем условные блоки self.textTemplate = self.applyTermsTemplate(self.textTemplate, nameFileTemplate) # Заменяем переменные на их значения self.textTemplate = self.applyVarsTemplate(self.textTemplate, nameFileTemplate) # Вычисляем функции self.textTemplate = self.applyFuncTemplate(self.textTemplate, nameFileTemplate) flagCopyTemplate = False if not optFile: optFile = {"path":os.path.split(nameFileConfig)[0]} filesApply, objHeadNew = self.getApplyHeadTemplate(nameFileTemplate, nameFileConfig, templateFileType, optFile) if not objHeadNew: return filesApply # Настоящее имя конфигурационного файла nameFileConfig = filesApply[0] # Флаг - кодировка с бинарными примесями у файла шаблона включаем при # условии текстового файла и кодировки отличной от UTF-8 flagNotUtf8New = False # Флаг - кодировка с бинарными примесями у оригинального файла flagNotUtf8Old = False if not flagCopyTemplate: # проверяем кодировку шаблона if not self.fileIsUtf(nameFileTemplate): flagNotUtf8New = True if not (objHeadNew.params.has_key("link") and\ objHeadNew.params.has_key("symbolic")): # проверяем кодировку оригинального файла if not self.fileIsUtf(nameFileConfig): flagNotUtf8Old = True self.textTemplate = objHeadNew.body # Список примененных шаблонов ListOptTitle = [] if nameFileConfig in self.dictProcessedTemplates: ListOptTitle = self.dictProcessedTemplates[nameFileConfig] # Титл конфигурационного файла title = "" if ListOptTitle: title = self.getTitle(objHeadNew.comment, ListOptTitle, configPath=nameFileConfig) title = title.encode("UTF-8") objHeadOld = False if objHeadNew.comment: objHeadOld = fileHeader(nameFileConfig, self.textConfig, objHeadNew.comment) elif objHeadNew.fileType and\ objHeadNew.typeAppend in ("before", "after"): configFileType = self.getFileType(nameFileConfig) objHeadOld = fileHeader(nameFileConfig, self.textConfig, fileType=configFileType) # Строка вызова скрипта (#!/bin/bash ...) execStr = "" if objHeadNew.execStr: execStr = objHeadNew.execStr elif objHeadOld and objHeadOld.execStr: execStr = objHeadOld.execStr if objHeadNew.fileType: formatTemplate = objHeadNew.fileType typeAppendTemplate = objHeadNew.typeAppend if formatTemplate == "patch": if typeAppendTemplate != "patch": self.setError(\ _("Wrong option append=%(type)s in template %(file)s")\ %{"type":typeAppendTemplate,"file":nameFileTemplate}) return False # создаем объект формата шаблона objTempl = self.getFormatObj(formatTemplate, self.textTemplate) if not objTempl: self.setError(\ _("Incorrect header parmeter format=%s in the template")\ %formatTemplate + " " + nameFileTemplate) return False if objHeadOld and objHeadOld.body: self.textConfig = objHeadOld.body # обработка конфигурационного файла self.textTemplate = objTempl.processingFile(self.textConfig) if objTempl.getError(): self.setError(_("Wrong template") + ": " +\ nameFileTemplate) return False if execStr: self.textConfig = execStr + title + self.textTemplate else: self.textConfig = title + self.textTemplate self.saveConfFile() if 'exec' in objHeadNew.params: if not self.executeTemplate(self.nameFileConfig, objHeadNew.params['exec']): self.setError(_("Wrong template") + ": " +\ nameFileTemplate) self.setError(_("Failed to execute") + ": " +\ self.nameFileConfig) return False return False return filesApply # Создаем объект в случае параметра format в заголовке if (typeAppendTemplate == "replace" or\ typeAppendTemplate == "before" or\ typeAppendTemplate == "after") and\ not (formatTemplate == "bin" or\ formatTemplate == "raw"): # Преобразовываем бинарные файлы if flagNotUtf8New: objTxtCoder = utfBin() self.textTemplate = objTxtCoder.encode(self.textTemplate) # создаем объект формата шаблона objTemplNew = self.getFormatObj(formatTemplate, self.textTemplate) if not objTemplNew: self.setError(\ _("Incorrect header parmeter format=%s in the template")\ %formatTemplate + " " + nameFileTemplate) return False if "xml_" in formatTemplate: if objTemplNew.getError(): self.setError(_("Wrong template") + ": " +\ nameFileTemplate) return False # Имя файла внутри xml xfce конфигурационных файлов nameRootNode=nameFileConfig.rpartition("/")[2].split(".")[0] objTemplNew.setNameBodyNode(nameRootNode) # Объект Документ docObj = objTemplNew.docObj # Удаление комментариев из документа docObj.removeComment(docObj.getNodeBody()) # Добавление необходимых переводов строк docObj.insertBRtoBody(docObj.getNodeBody()) # Добавление необходимых разделителей между областями docObj.insertBeforeSepAreas(docObj.getNodeBody()) # Пост обработка if 'postXML' in dir(objTemplNew): objTemplNew.postXML() # Получение текстового файла из XML документа self.textTemplate = objTemplNew.getConfig().encode("UTF-8") # Если не UTF-8 производим преобразование if flagNotUtf8New: self.textTemplate = objTxtCoder.decode(self.textTemplate) # Титл для объединения if ListOptTitle: title = self.getTitle(objTemplNew._comment, ListOptTitle, configPath=nameFileConfig) title = title.encode("UTF-8") # Замена if typeAppendTemplate == "replace": if "xml_" in formatTemplate: data = self.textTemplate.split("\n") data.insert(1,title) self.textConfig = "\n".join(data) else: if objHeadNew.execStr: self.textConfig = objHeadNew.execStr+title+\ self.textTemplate else: self.textConfig = title + self.textTemplate self.saveConfFile() if 'exec' in objHeadNew.params: if not self.executeTemplate(self.nameFileConfig, objHeadNew.params['exec']): self.setError(_("Wrong template") + ": " +\ nameFileTemplate) self.setError(_("Failed to execute") + ": " +\ self.nameFileConfig) return False return False return filesApply # Вверху elif typeAppendTemplate == "before": if "xml_" in formatTemplate: self.setError(\ _("Wrong option append=before in template %s")\ %nameFileTemplate) return False if objHeadOld and objHeadOld.body: self.textConfig = objHeadOld.body if self.textTemplate and self.textTemplate[-1] == "\n": tmpTemplate = self.textTemplate + self.textConfig else: tmpTemplate = self.textTemplate + "\n" + self.textConfig if execStr: self.textConfig = execStr + title + tmpTemplate else: self.textConfig = title + tmpTemplate self.saveConfFile() if 'exec' in objHeadNew.params: if not self.executeTemplate(self.nameFileConfig, objHeadNew.params['exec']): self.setError(_("Wrong template") + ": " +\ nameFileTemplate) self.setError(_("Failed to execute") + ": " +\ self.nameFileConfig) return False return False return filesApply # Внизу elif typeAppendTemplate == "after": if "xml_" in formatTemplate: self.setError(\ _("Wrong option append=after in template %s")\ %nameFileTemplate) return False if objHeadOld and objHeadOld.body: self.textConfig = objHeadOld.body if self.textTemplate[-1] == "\n": tmpTemplate = self.textConfig + self.textTemplate else: tmpTemplate = self.textConfig + "\n" + self.textTemplate if execStr: self.textConfig = execStr + title + tmpTemplate else: self.textConfig = title + tmpTemplate self.saveConfFile() if 'exec' in objHeadNew.params: if not self.executeTemplate(self.nameFileConfig, objHeadNew.params['exec']): self.setError(_("Wrong template") + ": " +\ nameFileTemplate) self.setError(_("Failed to execute") + ": " +\ self.nameFileConfig) return False return False return filesApply # Объединение elif typeAppendTemplate == "join": if flagNotUtf8New: objTxtCoder = utfBin() self.textTemplate = objTxtCoder.encode(self.textTemplate) if formatTemplate =="raw": self.setError(\ _("Incorrect header parmeter append=%s in the template")\ %typeAppendTemplate + " " + nameFileTemplate) return False # создаем объект формата шаблона objTemplNew = self.getFormatObj(formatTemplate, self.textTemplate) if not objTemplNew: self.setError(\ _("Incorrect header parmeter format=%s in the template")\ %formatTemplate + " " + nameFileTemplate) return False if "xml_" in formatTemplate: if objTemplNew.getError(): self.setError(_("Wrong template") + ": " +\ nameFileTemplate) return False nameRootNode=nameFileConfig.rpartition("/")[2].split(".")[0] objTemplNew.setNameBodyNode(nameRootNode) # Титл для объединения if ListOptTitle: title = self.getTitle(objTemplNew._comment, ListOptTitle, configPath=nameFileConfig) title = title.encode("UTF-8") # В случае пустого конфигурационного файла reNoClean = re.compile("[^\s]",re.M) if not self.textConfig or\ not reNoClean.search(self.textConfig): self.textConfig = "" objHeadOld = fileHeader(nameFileConfig, self.textConfig, objTemplNew._comment) if objHeadOld.body: self.textConfig = objHeadOld.body else: self.textConfig = "" if flagNotUtf8Old: objTxtCoder = utfBin() self.textConfig = objTxtCoder.encode(self.textConfig) # создаем объект формата шаблона для конфигурационного файла objTemplOld = self.getFormatObj(formatTemplate, self.textConfig) if not objTemplOld: self.setError(_("Error in template %s") %nameFileConfig) return False if "xml_" in formatTemplate: if objTemplOld.getError(): self.setError(_("Wrong template") + ": " +\ nameFileConfig) return False nameRootNode=nameFileConfig.rpartition("/")[2].split(".")[0] objTemplOld.setNameBodyNode(nameRootNode) objTemplOld.join(objTemplNew) if "xml_" in formatTemplate: if objTemplOld.getError(): self.setError(_("Wrong template") + ": " +\ nameFileTemplate) return False data = objTemplOld.getConfig().encode("UTF-8").split("\n") data.insert(1,title) self.textConfig = "\n".join(data) else: if execStr: self.textConfig = execStr + title +\ objTemplOld.getConfig().encode("UTF-8") else: self.textConfig = title +\ objTemplOld.getConfig().encode("UTF-8") # Декодируем если кодировка не UTF-8 if flagNotUtf8New or flagNotUtf8Old: self.textTemplate = objTxtCoder.decode(self.textTemplate) self.textConfig = objTxtCoder.decode(self.textConfig) self.saveConfFile() if 'exec' in objHeadNew.params: if not self.executeTemplate(self.nameFileConfig, objHeadNew.params['exec']): self.setError(_("Wrong template") + ": " +\ nameFileTemplate) self.setError(_("Failed to execute") + ": " +\ self.nameFileConfig) return False return False return filesApply else: self.setError(_("Wrong (type append) template") + ": " +\ typeAppendTemplate) return False else: self.setError(_("Template type not found: ") + nameFileTemplate) return False return filesApply class scanDirectoryClt: """Класс для cканирования директорий с файлами .clt""" # Расширение файла шаблона extFileTemplate = ".clt" lenExtFileTemplate = len(extFileTemplate) filterApplyTemplates = [] def processingFile(self, path, prefix): """Обработка в случае файла""" return True def scanningTemplates(self, scanDir, prefix=None, flagDir=False): """Сканирование и обработка шаблонов в директории scanDir""" ret = True if not prefix: prefix = os.path.realpath(scanDir) if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]): for fileOrDir in sorted(os.listdir(scanDir)): 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 or\ absPath[:-self.lenExtFileTemplate] in\ self.filterApplyTemplates: if not self.processingFile(absPath, prefix): ret = False break elif stat.S_ISDIR(statInfo): ret = self.scanningTemplates(absPath, prefix, True) if ret is False: break return ret class templateClt(scanDirectoryClt, template): """Класс для обработки шаблонов c расширением .clt""" def __init__(self, objVar): self.checkNumberTemplate = True template.__init__(self, objVar, cltObj=False) applyPackages = ["calculate-install"] 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")) self._baseDir = pathJoin(self._chrootDir, self.objVar.Get("cl_root_path")) self._baseDir = os.path.normpath(self._baseDir) def applyTemplate(self, path): """Применение отдельного .clt шаблона""" if not self.flagApplyTemplates: return True return self.processingFile(path, "") def processingFile(self, path, prefix): """Обработка в случае шаблона файла""" self.numberProcessTempl += 1 self.numberProcessTemplates(self.numberProcessTempl) # Пропуск шаблонов директорийscanningTemplates if self.templDirNameFile == os.path.split(path)[1]: return True # Проверка на переменные в названии файла if not self.getNeedTemplate(path): if self.getError(): return False return True if self.getError(): return False if prefix and prefix[-1] == "/": prefix = prefix[:-1] if prefix: nameFileConfig = path.partition(prefix)[2] else: nameFileConfig = path nameFileConfig = nameFileConfig[:-self.lenExtFileTemplate] 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: # Настоящее имя конфигурационного файла nameFileConfig = filesApl[0] # Пишем время модификации *.env файлов if nameFileConfig.endswith(".env"): nameEnvFile = os.path.basename(nameFileConfig) self.functObj.timeConfigsIni[nameEnvFile] = float(time.time()) self.filesApply += filesApl return nameFileConfig else: return True def countsNumberTemplates(self, dirsTemplates=[]): """Считаем количество шаблонов""" def createDictTemplates(path, prefix, dictTemplates): """Создает словарь {"директория":"кол-во шаблонов" ...} и считает общее количество шаблонов """ # Количество шаблонов self.allTemplates += 1 dirTemplate = os.path.split(path)[0] while(True): if dirTemplate in dictTemplates.keys(): dictTemplates[dirTemplate] += 1 else: dictTemplates[dirTemplate] = 1 if dirTemplate == prefix: break dirTemplate = os.path.split(dirTemplate)[0] return dictTemplates if not dirsTemplates: dirsTemplates = self.objVar.Get("cl_template_clt_path") dirsTemplates.sort() scanObj = scanDirectoryClt() scanObj.processingFile = lambda x,y: createDictTemplates(x, y,\ self.dictTemplates) # Считаем количество шаблонов for dirTemplate in dirsTemplates: scanObj.scanningTemplates(dirTemplate, "/") def applyTemplates(self): """Применяет шаблоны к конфигурационным файлам""" if not self.flagApplyTemplates: return ([],[]) if not self.objVar.defined("cl_template_clt_path"): self.setError(_("undefined variable: ") + "cl_template_clt_path") return False dirsTemplates = self.objVar.Get("cl_template_clt_path") 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) # Обрабатываем шаблоны for dirTemplate in dirsTemplates: if self.scanningTemplates(dirTemplate, self._chrootDir) is False: return False return (self.createdDirs, self.filesApply) class iniParser(_error, templateFormat): """Класс для работы с ini файлами """ def __init__(self, iniFile): # название ini файла self.iniFile = iniFile # права создаваемого ini-файла self.mode = 0640 # Cоответствует ли формат файла нужному self.checkIni = None self.FD = None self.readOnly = False def setMode(self, mode): """установка прав создаваемого ini-файла""" self.mode = mode def openIniFile(self): if not os.access(self.iniFile, os.R_OK): return "" self.FD = open(self.iniFile, "r") fcntl.flock(self.FD.fileno(), fcntl.LOCK_EX) textIni = self.FD.read() return textIni def openRWIniFile(self): if not os.access(self.iniFile, os.R_OK): return "" try: self.FD = open(self.iniFile, "r+") except (IOError,OSError),e: self.FD = open(self.iniFile, "r") self.readOnly = True fcntl.flock(self.FD.fileno(), fcntl.LOCK_EX) textIni = self.FD.read() return textIni def writeIniFile(self, txtConfig): if self.readOnly: self.setError(_("Unable to write to the file") + ": " + self.iniFile) return False if not os.path.exists(self.iniFile): try: # Создание файла self.FD = open(self.iniFile, "w+") fcntl.flock(self.FD.fileno(), fcntl.LOCK_EX) os.chmod(self.iniFile, self.mode) except: self.setError(_("Unable to create the file") + ": " + self.iniFile) return False if not self.FD: self.setError(_("Unable to write to the file") + ": " + self.iniFile) return False self.FD.truncate(0) self.FD.seek(0) self.FD.write(txtConfig) self.FD.close() self.FD = None 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": self.setError(_("Trying to write a variable of 'samba' format" " to file %s (format - 'plasma')") %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 файл 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): """Проверка на правильность формата файла""" 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 def getVar(self, strHeader, nameVar, checkExistVar=False): """Получаем значение переменной из ini-файла""" textIni = self.openIniFile() 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": self.setError(_("Trying to fetch a variable of 'samba' format" " from file %s (format - 'plasma')")\ %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 if checkExistVar: if res is False: return False, "" else: return True, res else: if res is False: return "" else: return res def getLastNode(self, objIni, xmlBody, strHeader, formatPlasma): """Ищет область в XML в которой область с переменными""" flagFound = True 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() 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": self.setError(_("Trying to fetch all variables of 'samba' " "format from file %s (format - 'plasma')") %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 res = objIni.docObj.getAreaFields(strHeader, xmlBody) else: res = False if res is False: return {} else: return res def getAllSectionNames(self): """Получаем все имена секций определенных в ini файле Если формат ini файла plasma то имя секции - имена нескольких секций через запятую """ textIni = self.openIniFile() 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