#-*- coding: utf-8 -*- # Copyright 2008-2010 Mir 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 from cl_ldap import ldapFun # Переопределение exit import cl_overriding from cl_utils import _error, _toUNICODE, getModeFile, removeDir, typeFile,\ scanDirectory, convertStrListDict 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\.]|^$") # Регулярное выражение для названия переменной _reDenyName = re.compile("[^a-zA-Z0-9\_\-]") # Регулярное выражение для сравниваемого значения _reDenyValue = re.compile("[^0-9a-zA-Z_\.-]") def _convertVers(self, verA, verB): """Конвертирование номеров версий для корректного сравнения """ elemA = verA.split(".") elemB = verB.split(".") 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] return (".".join(elemA), ".".join(elemB)) def _equalTerm(self, term, textError, function=False): """Вычисление логических выражений для условий Для корректной работы в классе который наследует этот класс должен быть объявлен аттрибут self.objVar (объект для работы с переменными) function - функция для для обработки функций в заголовке блока """ trm = {"&&":" and ","||":" or "} rule = ["==", "!=", ">=", "<=", ">", "<"] listEqual = [] for k in trm.keys(): if k in term: term = term.replace(k,trm[k]) trs = term.split(" ") flagOR = False for t in trs: flagRule = False for sepF in rule: if sepF in t: flagRule = True vals = t.split(sepF) break if not flagRule: flagLog = False for k in trm.values(): if k.strip() == t: flagLog = True break if not flagLog: self.setError("'%s'"%term + " " + _("incorrect")) self.setError(textError) return False else: # если and if k == " and ": flagOR = False if listEqual == [] or False in listEqual: listEqual = [] break else: listEqual = [True] # если or else: if flagOR: continue if False in listEqual: listEqual = [] else: listEqual = [True] flagOR = True else: if flagOR: continue #проверка на допустимость названия переменной 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'"%term + " " + _("incorrect")) self.setError(textError) return False #проверка на допустимость значения if self._reDenyValue.search(vals[1]): self.setError("'%s'"%term + " " + _("incorrect")) self.setError(textError) return False flagIntTypeVar = None if flagFunction: valVars = function("#-%s-#"%vals[0]) if valVars is False: self.setError("'%s'"%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'"%term + " " + \ _("incorrect")) self.setError(textError) return False flagIntTypeVar = True else: flagIntTypeVar = False else: if valVars == "" and\ not self._re_not_Version.search(vals[1]): valVars = "0" elif vals[1] == "" and\ not self._re_not_Version.search(valVars): vals[1] = "0" else: try: valVars = self.objVar.Get(vals[0]) except self.objVar.DataVarsError, e: print textError print 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._re_not_Version.search(valVars) and\ not self._re_not_Version.search(vals[1]): verFile, verVar = self._convertVers(vals[1],valVars) exec(\ "res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")") if res: listEqual.append(True) else: listEqual.append(False) 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._re_not_Version.search(vals[1]): self.setError("'%s'"%term + " " + _("incorrect")) self.setError(_("Value is not version")) return False # Проверка значения функции на версию if self._re_not_Version.search(valVars): self.setError("'%s'"%term + " " + _("incorrect")) self.setError(_("Value function is not version")) return False verFile, verVar = self._convertVers(vals[1],valVars) exec("res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")") if res: listEqual.append(True) else: listEqual.append(False) 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'"%term +" " +_("incorrect")) self.setError(textError) return False valVar = valVars exec("res=(%d%s%d)"%(valVar,sepF,valFile)) if res: listEqual.append(True) else: listEqual.append(False) else: if sepF == "!=" or sepF == "==": if not vals[1].strip(): vals[1] = "" valFile = vals[1] valVar = valVars exec(\ "res=("+'"""'+valVar+'"""'+sepF+"'"+valFile+\ "'"+")") if res: listEqual.append(True) else: listEqual.append(False) else: if not flagNotEmptyVals: listEqual.append(False) else: self.setError("'%s'"%term + " "\ + _("incorrect")) self.setError(textError) return False if listEqual == [] or False in listEqual: return False return True #exec("res=(%s)"%("".join(listEqual))) #return res class fileHeader(_terms): """Обработка заголовков шаблонов и конфигурационных файлов """ # Допустимые параметры заголовка allowParam = ["format", "format_conf", "comment", "append", "force", "link", "mirror", "symbolic", "chmod", "chown", "name", "path"] # Тип шаблона fileType = "" # Тип вставки шаблона typeAppend = "" # Возможные типы вставки шаблонов _fileAppend = "join", "before", "after", "replace", "remove", "skip" # Интерпретатор (#!/bin/bash) (#!/usr/bin/python) execStr = "" # Символ комментария comment = False # Выражение для поиска строки интерпретатора reExecStr = re.compile("^#!.+\s*",re.I) # условные операторы terms = ('>', '<', '==', '!=', '>=', '<=') # параметры без значения listParNotVal = ("symbolic", "force", "mirror") # Результат вычисления условия в заголовке headerTerm = True def __init__(self, templateName, text, comment=False, fileType=False, objVar=False, function=False): self.body = text # Объект с переменными self.objVar=objVar # Параметры описанные в заголовке файла шаблона self.params = {} # некорректные параметры incorrectParams = set([]) # Удаление Заголовка 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(text) if reS: self.body = text[:reS.start()]+text[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(text) if reS: self.body = text[reS.end():] if fileType != False: if fileType=="bin": self.params["format"] = fileType self.fileType = self._getType() self.typeAppend = self._getAppend() else: textLines = text.splitlines() if textLines: textLine = textLines[0] rePar = re.compile("\s*#\s*calculate\s+",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 = "" paramList = re.split("\s+",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"+\ _("header template 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() self.typeAppend = self._getAppend() reExecRes = self.reExecStr.search(self.body) if reExecRes: self.execStr = self.body[reExecRes.start():reExecRes.end()] self.body = self.body[reExecRes.end():] 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 _getType(self): """Выдать тип файла""" if self.params.has_key("format"): return self.params["format"] else: return "raw" def _getAppend(self): """Выдать тип добавления файла""" if self.params.has_key("append") and self.params["append"] in\ self._fileAppend: return self.params["append"] else: if self.fileType != "raw" and self.fileType != "bin" and\ self.fileType != "": self.params["append"] = "join" return "join" self.params["append"] = "replace" return "replace" def _getComment(self): """Выдать символ комментария файла""" if self.params.has_key("comment"): return self.params["comment"] else: return False class dirHeader(_terms): """Обработка заголовков шаблонов директорий """ # Допустимые параметры заголовка allowParam = ["append", "chmod", "chown", "name", "path"] # Тип вставки шаблона typeAppend = "" # Возможные типы вставки шаблонов _fileAppend = "join", "remove", "skip" # условные операторы terms = ('>', '<', '==', '!=', '>=', '<=') # параметры без значения listParNotVal = ("symbolic", "force") # Результат вычисления условия в заголовке 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+",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 = re.split("\s+",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"+\ _("header template 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.typeAppend = self._getAppend() 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") and self.params["append"] in\ self._fileAppend: return self.params["append"] 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 #print parentNode.toprettyxml() if parentNode: fieldsVal = xpath.Evaluate(\ "child::field[attribute::type='seplist'][child::name='%s'] "\ %(nameField), parentNode) #print nameField 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.split(r.group(0)) blocTxt = txtSpl[0] txtWr = txtSpl[1] 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.split(r.group(0)) blocTxt = txtSpl[0] txtWr = txtSpl[1] 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: print _("Can not found user %s")%str(userName) cl_overriding.exit(1) if groupsInfo: import grp try: groupName = grp.getgrgid(gid).gr_name except: print _("Can not found group id %s")%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("[^\-\+\*\/]+") # стек глобальных переменных stackGlobalVars = [] # директория установленных программ basePkgDir = "/var/db/pkg" # регулярное выражение для поиска версии reFindVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*") # Имя обрабатываемого шаблона nameTemplate = "" # Текст функции шаблона functText = "" def __init__(self, objVar): # Если не определен словарь функций шаблона #print "dict", templateFunction.__dict__.items() 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 # Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д self._baseDir = self.objVar.Get("cl_root_path") 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 = os.path.join(self._baseDir, self.homeDir[1:]) # Путь к конфигурационному файлу для ini() self.pathConfigIni = os.path.join(self.homeDir, ".calculate") 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() print _("error var %s not int")%str(strNum) cl_overriding.exit(1) elif self.objVar.exists(strNum): try: num = int(self.objVar.Get(strNum)) except: self.printErrTemplate() print _("error var %s not int")%str(strNum) cl_overriding.exit(1) else: self.printErrTemplate() print _("error local var %s not defined")\ %str(strNum) cl_overriding.exit(1) if minus: num = -num strNumers.append(num) return sum(strNumers) self.printErrTemplate() print _("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' """ terms = map(lambda x: x.strip(), funArgv.split(",")) if len(terms) !=1: self.printErrTemplate() cl_overriding.exit(1) fileName = terms[0] if fileName[0] == "~": # Получаем директорию пользователя fileName = os.path.join(self.homeDir, fileName.partition("/")[2],"")[:-1] elif fileName[0] != "/": path = os.path.split(nameSystemFile)[0] fileName=os.path.join(path,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 not terms or not terms[0].strip() or\ (len(terms)==2 and not terms[1].strip()) or\ len(terms)>2: self.printErrTemplate() cl_overriding.exit(1) if len(terms) == 2: if not terms[0] in ["ver","num","char","key"]: self.printErrTemplate() print _("first argument function is not 'ver' or 'num' or \ 'char'") cl_overriding.exit(1) if len(terms) == 1: fileName = terms[0].strip() # Если домашняя директория if fileName[0] == "~": # Получаем директорию пользователя fileName = os.path.join(self.homeDir, fileName.partition("/")[2],"")[:-1] elif fileName[0] != "/": path = os.path.split(nameSystemFile)[0] fileName=os.path.join(path,fileName) else: fileName = terms[1].strip() # Если домашняя директория if fileName[0] == "~": # Получаем директорию пользователя fileName = os.path.join(self.homeDir, fileName.partition("/")[2],"")[:-1] elif fileName[1] != "/": path = os.path.split(nameSystemFile)[0] fileName=os.path.join(path,fileName) replace = "" if os.path.exists(fileName): FD = open(fileName) replace = FD.read().strip() FD.close if not replace and len(terms) == 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' - цифры и буквы второй аргумент: количество символов """ 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','pas'] if not terms[0] in fArgvNames: self.printErrTemplate() print _("first argument function is not 'num' or 'pas'") cl_overriding.exit(1) try: lenStr = int(terms[1]) except: self.printErrTemplate() print _("two argument function is not number") cl_overriding.exit(1) if terms[0] == fArgvNames[0]: replace=''.join([random.choice(string.digits)\ for i in xrange(lenStr)]) elif terms[0] == fArgvNames[1]: replace=''.join([random.choice(string.ascii_letters + \ string.digits) for i in xrange(lenStr)]) else: self.printErrTemplate() cl_overriding.exit(1) 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() print _("first argument function is not 'upper' or 'lower' or\ 'capitalize'") cl_overriding.exit(1) try: strValue = str(self.objVar.Get(terms[1])) except: print _("error in template %s")%self.nameTemplate print _("error var %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() print _("error var %s exists")%str(nameLocVar) cl_overriding.exit(1) else: # Если переменная не существует if len(terms) == 1: self.printErrTemplate() print _("error var %s not exists")%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() print _("error, gloval 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: 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.update(self.prevDictIni) self.timeIni = self.getTimeFile(self.fileConfigIni) if nameLocVar in self.currDictIni.keys(): replace = self.currDictIni[nameLocVar] elif len(terms) == 2: if self.timeIni != curTime: # читаем переменные из файла self.prevDictIni = self.loadVarsIni(self.fileConfigIni) self.currDictIni.update(self.prevDictIni) self.timeIni = self.getTimeFile(self.fileConfigIni) # Значение локальной переменной valueLocVar = terms[1] self.currDictIni[nameLocVar] = valueLocVar 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() print _("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: print 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): """Функция шаблона belongs(). В случае установки переменной 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: print _("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 printErrTemplate(self): """Печать ошибки при обработке функций шаблона""" print _("error in template %s")%self.nameTemplate print _("error template term '%s'")%str(self.functText) def applyFuncTemplate(self, textTemplate, nameTemplate, nameSystemFile): """Применяет функции к тексту шаблона""" # Локальные переменные 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() print _("can not found template function '%s'")\ %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) # секции будущего конфигурационного файла 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: 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, xmlShare, templateFormat, _shareTemplate): """Класс для работы с шаблонами На вход 2 параметра: объект хранения переменных, имя сервиса - не обязательный параметр """ # Название файла шаблона директории templDirNameFile = ".calculate_directory" # Расширение файла шаблона extFileTemplate = ".clt" lenExtFileTemplate = len(extFileTemplate) def __init__(self, objVar, servDir=False, dirsFilter=[], filesFilter=[]): # Необрабатываемые директории self.dirsFilter = dirsFilter # Необрабатываемые файлы self.filesFilter = filesFilter _file.__init__(self) # Словарь для создания объектов новых классов по образцу self.newObjProt = {'proftpd':'apache'} # Заголовок title self.__titleHead = "--------------------------------------\ ----------------------------------------" self._titleBody = "" self._titleList = (_("Modified"), _("Processed 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 = self.objVar.Get("cl_root_path") # Последняя часть директории шаблона (имя сервиса: 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 = os.path.join(self._baseDir, self.homeDir[1:]) # Глобальный словарь обработанных шаблонов файлов # {путь к конф. файлу:[имена шаблонов] ...} self.dictProcessedTemplates = {} # Преобразование восьмеричного в целое (ввод строка, вывод число) def __octToInt(self, strOct): if strOct: try: exec("res =" + "0" + strOct) except: self.setError(_("Not valid oct value: ") + str(strOct)) return False return res else: self.setError(_("Empty oct value")) return False def getTemplateType(self): """выдать тип шаблона (text, bin)""" isBin = self.typeFileObj.isBinary(self.nameFileTemplate) typeTemplate = "bin" if isBin is True: typeTemplate = "bin" elif isBin is False: typeTemplate = "text" else: self.setError(_("ERROR") + ": getTemplateType()") 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 [dirName] 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(_("Not access dir: " ) + 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) else: os.mkdir(nameDir) os.chown(nameDir, dUid, dGid) except: self.setError(_("Can not create dir: " ) + nameDir) return False try: if dMode: os.mkdir(dirName, dMode) else: os.mkdir(dirName) os.chown(dirName, dUid, dGid) createDirs.append(dirName) except: self.setError(_("Can not create dir: " ) + 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: print _("error in template %s")%nameTemplate print e cl_overriding.exit(1) textTemplateTmp = textTemplateTmp.replace(mark, varValue) resS = self._reVar.search(textTemplateTmp) return textTemplateTmp def applyTermsTemplate(self,textTemplate,nameTemplate,nameSystemFile=False): """ Применяет условия, к условным блокам текста """ textTerm = "" resS = self._reTermBloc.search(textTemplate) textTemplateTmp = textTemplate def function(text): """Функция обработки функций в заголовке""" return self.applyFuncTemplate(text, nameTemplate, nameSystemFile) if nameSystemFile: 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, _("content template not valid: ")+\ nameTemplate, function): textTemplateTmp = textTemplateTmp.replace(mark, body+end) else: textTemplateTmp = textTemplateTmp.replace(mark, "") resS = self._reTermBloc.search(textTemplateTmp) else: while resS: mark = resS.group(0) body = resS.group("body") end = resS.group("end") term = resS.group("rTerm") + resS.group("lTerm") if self._equalTerm(term, _("content template not valid: ")+\ nameTemplate): 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, _("name template not valid: ")+\ fileTemplate): flagTrue = True break if flagTrue: return True else: return False else: return True else: self.setError(_("name template not valid: ")+ str(fileTemplate)) return False def getTitle(self, comment, commentList): """Выдает заголовок шаблона ( версия и.т.д)""" 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 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(_("not defined Var: ") + "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) for dirTemplate in dirsTemplatesExists: scanObj.scanningDirectory(dirTemplate) self.numberAllTemplates(self.allTemplates) # Обрабатываем шаблоны for dirTemplate in dirsTemplatesExists: if self.scanningTemplates(dirTemplate) is False: return False return (self.createdDirs, self.filesApply) def scanningTemplates(self, scanDir, prefix=None, flagDir=False, optDir={}): """Сканирование и обработка шаблонов в директории scanDir""" ret = True if not prefix: prefix = os.path.join(scanDir,"")[:-1] 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 and objHead.typeAppend == "skip": # Установка опции пропуска директории optDir["skip"] = 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) 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 and objHead.typeAppend == "skip": # Установка опции пропуска директории optNextDir["skip"] = 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) # Пишем время модификации *.env файлов if nameFileConfig.endswith(".env"): nameEnvFile = os.path.split(nameFileConfig)[1] self.functObj.timeConfigsIni[nameEnvFile] = float(time.time()) filesApl = self.joinTemplate(path, nameFileConfig, optFile) if self.getError(): return False if filesApl: self.filesApply += filesApl pathTemplate, nameTemplate = os.path.split(nameFileConfig) return {"path":pathTemplate, "name":nameTemplate} def processingDirectory(self, path, prefix, opt): """Обработка в случае директории если возвращаем None то пропуск дир.""" # Файл шаблона директории dirInfoFile = os.path.join(path, self.templDirNameFile) newDir = os.path.join(self._baseDir, path.partition(prefix)[2][1:]) newDir = "/".join(map(lambda x:x.split("?")[0], newDir.split("/"))) # Применяем шаблон pathDir, objHeadDir = self.__getApplyHeadDir(newDir, dirInfoFile, opt) if objHeadDir: self.createdDirs += [pathDir] else: if self.getError(): return False # Добавление количества файлов в пропущенной директории if path in self.dictTemplates.keys(): self.numberProcessTempl += self.dictTemplates[path] return None return pathDir, objHeadDir def __getApplyHeadDir(self, newDir, templateDirFile, optDir): """Применяет шаблон к директории (права, владелец, и.т. д)""" def function(text): """Функция обработки функций в заголовке""" return self.applyFuncTemplate(text, newDir, 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: path = os.path.split(applyDir)[1] path = os.path.join(self._baseDir, path[1:]) if not os.path.exists(templateDirFile): 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 (applyDir, False) # Создаем директорию если необходимо if not self.createDir(applyDir, False, self.uid, self.gid): return False return (applyDir, True) try: FD = open(templateDirFile) textTemplate = FD.read() FD.close() except: self.setError(_("Error open template") + ": " +\ templateDirFile) return (applyDir, False) # Заменяем переменные на их значения textTemplate = self.applyVarsTemplate(textTemplate, templateDirFile) # Заменяем функции на их значения textTemplate = self.applyFuncTemplate(textTemplate, templateDirFile, applyDir) # Обработка заголовка objHead = dirHeader(templateDirFile,textTemplate,self.objVar,function) # Директория с профилями не будет применена if not objHead.headerTerm: if objHead.getError(): self.setError(_("Incorrect template") + ": " +\ templateDirFile) return (applyDir, 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(_("False value 'path' in template") + ": " +\ templateDirFile) return (applyDir, False) else: path = os.path.join(self._baseDir, path[1:]) # Изменяем название директории if "name" in objHead.params: nameDir = objHead.params['name'] if "/" in nameDir or nameDir == ".." or nameDir == ".": self.setError(_("False value 'name' in template") + ": " +\ templateDirFile) return (applyDir, False) # Новый путь к директории applyDir = os.path.join(path, nameDir) else: 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 (applyDir, False) # Удаляем директорию if objHead.typeAppend == "remove": if os.path.isdir(applyDir): # удаляем директорию try: removeDir(applyDir) except: self.setError(_("Can not delete dir: " ) +\ applyDir) return (applyDir, False) # chmod - изменяем права if "chmod" in objHead.params: mode = self.__octToInt(objHead.params['chmod']) if mode: if not os.path.exists(applyDir): if not self.createDir(applyDir, mode): return False else: os.chmod(applyDir, mode) else: self.setError(_("False value 'chmod' in template") + ": " +\ templateDirFile) return (applyDir, False) # chown - изменяем владельца и группу if "chown" in objHead.params: owner = objHead.params['chown'] if owner: if ":" in owner: strUid, strGid = owner.split(":") import pwd try: uid = pwd.getpwnam(strUid).pw_uid except: self.setError(_("Not user in this system: ") + strUid) self.setError(_("False value 'chown' in template")+\ ": " + templateDirFile) return (applyDir, False) try: import grp gid = grp.getgrnam(strGid).gr_gid except: self.setError(_("Not group in this system: ")+strGid) self.setError(_("False value 'chown' in template") +\ ": "+ templateDirFile) return (applyDir, False) if not os.path.exists(applyDir): if not self.createDir(applyDir, False, uid, gid): return (applyDir, False) else: if not chownConfDir(applyDir, uid, gid, templateDirFile): return (applyDir, False) else: self.setError(_("False value 'chown' in template") + ": " +\ templateDirFile) return (applyDir, False) else: self.setError(_("False value 'chown' in template") + ": " +\ templateDirFile) return (applyDir, 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 (applyDir, False) else: if not self.createDir(applyDir, False, self.uid, self.gid): return False return (applyDir, objHead) def __getApplyHeadTemplate(self, nameFileTemplate, nameFileConfig, templateFileType, optFile): """Применяет заголовок к шаблону (права, владелец, и.т. д)""" def function(text): """Функция обработки функций в заголовке""" return self.applyFuncTemplate(text,nameFileTemplate,nameFileConfig) def renameConfFileCLT(nameFileConfig): """Изменение название файла templ.conf.clt на templ.conf""" if nameFileConfig.endswith(self.extFileTemplate): return nameFileConfig[:-self.lenExtFileTemplate] return nameFileConfig 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() # Файлы в системе к которым были применены шаблоны applyFiles = [nameFileConfig] # В случае бинарного типа файла читаем шаблон if templateFileType == "bin": self.nameFileTemplate = os.path.abspath(nameFileTemplate) self.F_TEMPL = self.openTemplFile(self.nameFileTemplate) 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 (applyFiles, False) pathProg = "" # Родительская директория 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(_("False value 'path' in template") + ": " +\ nameFileTemplate) return (applyFiles, False) else: path = os.path.join(self._baseDir, path[1:]) # Путь к оригинальному файлу - pathOldFile # Изменяем путь к оригинальному файлу if objHeadNew.params.has_key("name"): nameFile = objHeadNew.params['name'] if "/" in nameFile or nameFile == ".." or nameFile == ".": self.setError(_("False value 'name' in template") + ": " +\ nameFileTemplate) return (applyFiles, False) # Новый путь к оригинальному файлу pathOldFile = os.path.join(path,nameFile) else: pathOldFile = os.path.join(path,os.path.split(nameFileConfig)[1]) pathOldFile = renameConfFileCLT(pathOldFile) applyFiles = [pathOldFile] # Фильтрация шаблонов по названию файла realPath = os.path.join("/",pathOldFile.partition(self._baseDir)[2]) if realPath in self.filesFilter: return (applyFiles, False) typeAppendTemplate = objHeadNew.typeAppend # Удаляем оригинальный файл if typeAppendTemplate == "remove": if os.path.islink(pathOldFile): # удаляем ссылку try: os.unlink(pathOldFile) except: self.setError(_("Error in template") + ": " +\ nameFileTemplate) self.setError(_("Can not delete link") + ": " +\ pathOldFile) if os.path.isfile(pathOldFile): # удаляем файл try: os.remove(pathOldFile) except: self.setError(_("Error in template") + ": " +\ nameFileTemplate) self.setError(_("Can not delete file") + ": " +\ pathOldFile) return (applyFiles, False) # Пропускаем обработку шаблона elif typeAppendTemplate == "skip": return (applyFiles, False) # Создаем директорию для файла если ее нет if not os.path.exists(path): if not self.createDir(path): return (applyFiles, False) # В случае force if objHeadNew.params.has_key("force"): if os.path.islink(pathOldFile): # удаляем ссылку try: os.unlink(pathOldFile) except: self.setError(_("Error in template") + ": " +\ nameFileTemplate) self.setError(_("Can not delete link") + ": " +\ pathOldFile) return (applyFiles, False) if os.path.isfile(pathOldFile): # удаляем файл try: os.remove(pathOldFile) except: self.setError(_("Error in template") + ": " +\ nameFileTemplate) self.setError(_("Can not delete file") + ": " +\ pathOldFile) return (applyFiles, False) flagSymlink = False flagForce = False # Если есть параметр mirror if objHeadNew.params.has_key("mirror"): if objHeadNew.params.has_key("link"): templateFile = objHeadNew.params['link'] if not os.path.exists(templateFile): if os.path.exists(pathOldFile): try: os.remove(pathOldFile) except: self.setError(_("Error in template") + ": " +\ nameFileTemplate) self.setError(_("Can not delete file") + ": " +\ pathOldFile) return (applyFiles, False) elif not os.path.exists(pathOldFile): return (applyFiles, False) # Если есть указатель на файл шаблона (link) if objHeadNew.params.has_key("link") and\ not objHeadNew.params.has_key("symbolic"): templateFile = objHeadNew.params['link'] 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(_("Error in template") + ": " +\ nameFileTemplate) self.setError(_("Can not open file") + ": " +\ templateFile) return (applyFiles, False) if os.path.exists(pathOldFile): try: os.remove(pathOldFile) except: self.setError(_("Error in template") + ": " +\ nameFileTemplate) self.setError(_("Can not delete file") + ": " +\ pathOldFile) return (applyFiles, False) if foundTemplateFile: try: FD = open(pathOldFile, "w+") FD.write(buff) FD.close() except: self.setError(_("Error in template") + ": " +\ nameFileTemplate) self.setError(_("Can not create file") + " '%s'"\ %pathOldFile) return (applyFiles, False) oMode = getModeFile(pathOldFile, mode="mode") # Если права не совпадают, меняем права if fMode != oMode: if not chmodConfFile(pathOldFile, fMode, nameFileTemplate, checkExists=False): return (applyFiles, 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(_("Error in template") + ": " +\ nameFileTemplate) self.setError(_("Can not change the current directory to")+\ " " + pathLink) return (applyFiles, False) # chmod - изменяем права if objHeadNew.params.has_key("chmod"): mode = self.__octToInt(objHeadNew.params['chmod']) if mode: if not chmodConfFile(pathOldFile, mode, nameFileTemplate): return (applyFiles, False) else: self.setError(_("False value 'chmod' in template") + ": " +\ nameFileTemplate) return (applyFiles, False) # chown - изменяем владельца и группу if objHeadNew.params.has_key("chown"): owner = objHeadNew.params['chown'] if owner: if ":" in owner: strUid, strGid = owner.split(":") import pwd try: uid = pwd.getpwnam(strUid).pw_uid except: self.setError(_("Not user in this system: ") + strUid) self.setError(_("False value 'chown' in template") +\ ": "+ nameFileTemplate) return (applyFiles, False) try: import grp gid = grp.getgrnam(strGid).gr_gid except: self.setError(_("Not group in this system: ")+strGid) self.setError(_("False value 'chown' in template") +\ ": "+ nameFileTemplate) return (applyFiles, False) # Изменяем владельца файла if not chownConfFile(pathOldFile,uid,gid,nameFileTemplate): return (applyFiles, False) else: self.setError(_("False value 'chown' in template") + ": " +\ nameFileTemplate) return (applyFiles, False) else: self.setError(_("False value 'chown' in template") + ": " +\ nameFileTemplate) return (applyFiles, False) self.openFiles(nameFileTemplate, pathOldFile) if not objHeadNew.params.has_key("chown"): # Устанавливаем владельцем конфигурационного файла, # пользователя по умолчанию (переменная шаблона ur_login) tUid, tGid = getModeFile(pathOldFile, mode="owner") if (self.uid, self.gid) != (tUid, tGid): # Изменяем владельца файла if not chownConfFile(pathOldFile, self.uid, self.gid, nameFileTemplate, checkExists=False): return (applyFiles, 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(_("Error in template") + ": " +\ nameFileTemplate) self.setError(_("Can not delete file") + ": " +\ prevOldFile) return (applyFiles, False) if not "/" == pathOldFile[0]: applyFiles = [prevOldFile,os.path.join(pathLink,pathOldFile)] else: applyFiles = [prevOldFile,pathOldFile] try: os.symlink(pathOldFile, prevOldFile) except: self.setError(_("Error in template") + ": " +\ nameFileTemplate) self.setError(_("Can not create symbolic link") + " :" +\ "%s -> %s"%(prevOldFile, pathOldFile)) return (applyFiles, False) if not objHeadNew.body.strip(): 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"): return (applyFiles, False) if not pathOldFile in self.dictProcessedTemplates: self.dictProcessedTemplates[pathOldFile] = [] self.dictProcessedTemplates[pathOldFile].append(nameFileTemplate) 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, nameFileConfig) #print "|%s|" %(self.textTemplate) # Заменяем переменные на их значения self.textTemplate = self.applyVarsTemplate(self.textTemplate, nameFileTemplate) # Вычисляем функции self.textTemplate = self.applyFuncTemplate(self.textTemplate, nameFileTemplate, nameFileConfig) flagCopyTemplate = False 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) title = title.encode("UTF-8") objHeadOld = False if objHeadNew.comment: objHeadOld = fileHeader(nameFileConfig, self.textConfig, objHeadNew.comment) if objHeadNew.fileType: formatTemplate = objHeadNew.fileType typeAppendTemplate = objHeadNew.typeAppend # Создаем объект в случае параметра 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 template")\ %formatTemplate + " " + nameFileTemplate) return False if "xml_" in formatTemplate: if objTemplNew.getError(): self.setError(_("False 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) 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() return filesApply # Впереди elif typeAppendTemplate == "before": if "xml_" in formatTemplate: self.setError(\ _("False option append=before in template %s")\ %nameFileTemplate) return False if objHeadOld and objHeadOld.body: self.textConfig = objHeadOld.body if self.textTemplate[-1] == "\n": tmpTemplate = self.textTemplate + self.textConfig else: tmpTemplate = self.textTemplate + "\n" + self.textConfig if objHeadNew.execStr: self.textConfig = objHeadNew.execStr + title + tmpTemplate elif objHeadOld.execStr: self.textConfig = objHeadOld.execStr + title + tmpTemplate else: self.textConfig = title + tmpTemplate #print self.textConfig self.saveConfFile() return filesApply # Cзади elif typeAppendTemplate == "after": if "xml_" in formatTemplate: self.setError(\ _("False 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 objHeadNew.execStr: self.textConfig = objHeadNew.execStr + title + tmpTemplate elif objHeadOld.execStr: self.textConfig = objHeadOld.execStr + title + tmpTemplate else: self.textConfig = title + tmpTemplate self.saveConfFile() return filesApply # Объединение elif typeAppendTemplate == "join": 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 template")\ %formatTemplate + " " + nameFileTemplate) return False if "xml_" in formatTemplate: if objTemplNew.getError(): self.setError(_("False template") + ": " +\ nameFileTemplate) return False nameRootNode=nameFileConfig.rpartition("/")[2].split(".")[0] objTemplNew.setNameBodyNode(nameRootNode) # Титл для объединения if ListOptTitle: title = self.getTitle(objTemplNew._comment, ListOptTitle) title = title.encode("UTF-8") # В случае пустого конфигурационного файла reNoClean = re.compile("[^\s]",re.M) if not self.textConfig or\ not reNoClean.search(self.textConfig): self.textConfig = "" #if objHeadNew.execStr: #self.textConfig = objHeadNew.execStr + \ #title + objTemplNew.getConfig().encode("UTF-8") #else: #self.textConfig = title +\ #objTemplNew.getConfig().encode("UTF-8") #self.saveConfFile() #return True 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(_("False template") + ": " +\ nameFileConfig) return False nameRootNode=nameFileConfig.rpartition("/")[2].split(".")[0] objTemplOld.setNameBodyNode(nameRootNode) #print "#%s#" %(objTemplOld.docObj.body.toprettyxml()) #print "#%s#" %(objTemplNew.docObj.body.toprettyxml()) objTemplOld.join(objTemplNew) #print objTemplOld.doc.toprettyxml() #print objTemplNew.doc.toprettyxml() if "xml_" in formatTemplate: if objTemplOld.getError(): self.setError(_("False template") + ": " +\ nameFileTemplate) return False data = objTemplOld.getConfig().encode("UTF-8").split("\n") data.insert(1,title) self.textConfig = "\n".join(data) else: if objHeadNew.execStr: self.textConfig = objHeadNew.execStr + title +\ objTemplOld.getConfig().encode("UTF-8") elif objHeadOld.execStr: self.textConfig = objHeadOld.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() return filesApply else: self.setError(_("False (type append) template") + ": " +\ typeAppendTemplate) return False else: self.setError(_("Type template not found: ") + nameFileTemplate) return False return filesApply class iniParser(_error, templateFormat): """Класс для работы с ini файлами """ def __init__(self, iniFile): # название ini файла self.iniFile = iniFile # права создаваемого ini-файла self.mode = 0640 # Cоответствует ли формат файла нужному self.checkIni = None def setMode(self, mode): """установка прав создаваемого ini-файла""" self.mode = mode def openIniFile(self): if not os.access(self.iniFile, os.R_OK): return "" FD = open(self.iniFile, "r") textIni = FD.read() FD.close() return textIni def writeIniFile(self, txtConfig): if not os.path.exists(self.iniFile): try: # Создание файла FD = open(self.iniFile, "w+") os.chmod(self.iniFile, self.mode) except: self.setError(_("Unable to create file") + ": " + self.iniFile) return False else: try: FD = open(self.iniFile, "r+") except: self.setError(_("Unable to open file") + ": " + self.iniFile) return False FD.truncate(0) FD.seek(0) FD.write(txtConfig) FD.close() return True def setVar(self, strHeader, dictVar): """Заменяет или добавляет область и переменные Добавляет область в ini-файл или объединяет с существующей strHeader - имя области dictVar - словарь переменных """ textIni = self.openIniFile() 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(_("In the file %s (format - 'plasma'), \ write the variable in the format 'samba'")\ %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): """Является ли файл пустым""" if not textIni.strip(): return True else: return False 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 format file") + ": " + \ 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 = 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() 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(_("In the file %s (format - 'plasma'), \ get the variable in the format 'samba'")\ %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() 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(_("In the file %s (format - 'plasma'), \ get all variables in the format 'samba'")\ %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() 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