#-*- coding: utf-8 -*- #Copyright 2008 Calculate Pack, http://www.calculate-linux.ru # # 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 cl_base import stat import re import xml.dom.minidom from xml import xpath import popen2 tr = cl_base.lang() tr.setLocalDomain('cl_lib') tr.setLanguage(sys.modules[__name__]) class _error: # Здесь ошибки, если они есть error = [] def getError(self): """Выдать ошибки""" if not self.error: return False error = "" for e in self.error: error += e + "\n" return error def setError(self, error): """Установка ошибки""" self.error.append(error) return True class _terms(_error): """Вычисление условий применяемых в профилях """ 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): """Вычисление логических выражений для условий Для корректной работы в классе который наследует этот класс должен быть объявлен аттрибут self.objVar (объект для работы с переменными) """ trm = {"&":" and ","||":" or "} rule = ["==", "!=", ">=", "<=", ">", "<"] listEqual = [] for k in trm.keys(): if k in term: term = term.replace(k,trm[k]) trs = term.split(" ") 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 (textError) return False else: listEqual.append(k) else: if self.objVar.defined(vals[0]): valVars = self.objVar.Get(vals[0]) #print valVars if not valVars: self.setError (_("empty var: ")+\ vals[0]) return False # Cравниваем номера версий if "_ver" in vals[0]: verFile, verVar = self._convertVers(vals[1],valVars) exec("res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")") if res: listEqual.append("1") else: listEqual.append("0") else: if "int" in str(type(valVars)): try: valFile = int(vals[1]) except: self.setError (textError) return False valVar = valVars exec("res=(%d%s%d)"%(valVar,sepF,valFile)) if res: listEqual.append("1") else: listEqual.append("0") else: if sepF == "!=" or sepF == "==": valFile = vals[1] valVar = valVars exec("res=("+"'"+valVar+"'"+sepF+"'"+valFile+\ "'"+")") if res: listEqual.append("1") else: listEqual.append("0") else: self.setError (textError) return False else: self.setError (_("not defined Var: ") + vals[0]) return False exec("res=(%s)"%("".join(listEqual))) return res class calcHeader(_terms): """Обработка заголовков профилей и конфигурационных файлов """ def __init__(self, text, comment=False, fileType=False, objVar=False): # Тип профиля self.fileType = "" # Тип вставки профиля self.typeAppend = "" # Возможные типы вставки профилей self._fileAppend = "join", "before", "after", "replace" self.body = text # Интерпретатор (#!/bin/bash) (#!/usr/bin/python) self.execStr = "" # Символ комментария self.comment = False # Выражение для поиска строки интерпретатора self.reExecStr = re.compile("^#!.+\s*",re.I) # условные операторы self.terms = ('>', '<', '==', '!=', '>=', '<=') # параметры без значения self.listParNotVal = ("symbolic", "force","mirror") # Объект с переменными self.objVar=objVar # Результат вычисления условия в заголовке self.headerTerm = True # Параметры описанные в заголовке файла профиля self.params = {} # Удаление Заголовка Calculate if comment: reCalcHeader =\ re.compile("\s*%s\-+\s+%s.+Calculate.+\s+%s.+\s+%s\-+\s?"%(\ comment, comment, 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[: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: for term in self.terms: if term in i: if not self._equalTerm(i,\ _("content profile not valid: ") + \ i): self.headerTerm = False break else: par = i.split("=") if len(par) == 1: for parNotVal in \ self.listParNotVal: if i == parNotVal: self.params[parNotVal] =\ "True" elif len(par) == 2: self.params[par[0]] = par[1] self.fileType = self._getType() self.typeAppend = self._getAppend() self.comment = self._getComment() reExecRes = self.reExecStr.search(self.body) if reExecRes: self.execStr = self.body[reExecRes.start():reExecRes.end()] self.body = self.body[reExecRes.end():] 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 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(self._toUNICODE(text)) element.appendChild(txtNode) for attr in attributes.keys(): attribute = doc.createAttribute(attr) attribute.nodeValue = attributes[attr] element.setAttributeNode(attribute) return element def _toUNICODE(self,val): """перевод текста в юникод""" if 'unicode' in "%s" %(type(val)): return val else: return val.decode('UTF-8') 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 #if not self.getActionField(nodeFieldOld): #self.setActionField(nodeFieldOld,"insert") #else: #self.setActionField(nodeFieldOld,"append") oldValues = self.getFieldValues(nodeFieldOld) for newValue in newValues: if not (newValue in oldValues): flagCompare = False break 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)= 0: for i in range(lenListDirMv,-1,-1): z = i + 2 dirTest = baseDirMv + "/".join(listDirMv[:z]) if os.access(dirTest, os.F_OK): break start = i end = lenListDirMv + 1 for k in range(start,end): z = k + 2 dirTest = "/".join(listDirMv[:z]) dirTestMv = baseDirMv + dirTest if not os.access(dirTestMv, os.F_OK): dirTestProf = baseProfDir + dirTest try: mode,uid,gid = self.getModeFile(dirTestProf) except OSError: self.setError (_("not access dir:" ) + profDir) return False os.mkdir(dirTestMv, mode) os.chown(dirTestMv, uid,gid) createDirs.append(dirTestMv) return createDirs def scanDirs(self, profilesDirs): """Сканирует дерево каталогов выдает два списка: директории, файлы""" dirs = [] class dirProf: def __init__(self): self.baseDir = False self.dirs = [] self.files = [] self.links = [] def getFilesDir(dirP, dirname,names): for nameFile in names: absNameFile = dirname + "/" + nameFile if os.path.islink(absNameFile): dest = absNameFile src = os.readlink(absNameFile) dirP.links.append((src,dest)) elif os.path.isfile(absNameFile): dirP.files.append(absNameFile) elif os.path.isdir(absNameFile): dirP.dirs.append(absNameFile) for profileDir in profilesDirs: if profileDir: dirP = dirProf() dirP.baseDir = profileDir dirs.append(dirP) os.path.walk(profileDir,getFilesDir, dirP) return dirs def __absFileName(self, nameFile): """Вычисление пути к файлу""" pathList = nameFile.split("/") chortNameFile = pathList.pop() absPath = os.path.abspath("/".join(pathList)) File = absPath + "/" + chortNameFile return File def saveOldFile(self): """Записать конфигурацию""" if self.FO: self.FO.truncate(0) self.FO.seek(0) if not self.oldProfile: self.oldProfile = self.newProfile try: self.FO.write(self.oldProfile) except: self.setError (_("not open file:" ) + self.nameFileOld) return False return True def getModeFile(self, nameFile): """Выдает информацию о файле права файла, владелец, группа файла (777,test, group) """ fd = os.open(nameFile, os.O_RDONLY) fst = os.fstat(fd) uid = fst.st_uid gid = fst.st_gid mode = stat.S_IMODE(fst.st_mode) os.close(fd) return (mode,uid,gid) def __openNewFile(self, nameFileNew): """Открыть файл профиля""" FN = False try: FN = open (nameFileNew, "r") self._mode,self._uid,self._gid = self.getModeFile(nameFileNew) except: self.setError (_("not open file:" ) + nameFileNew) return False return FN def __closeNewFile(self): if self.FN: self.FN.close() self.FN = False def __closeOldFile(self): if self.FO: self.FO.close() self.FO = False def __openOldFile(self, nameFileOld, mode, uid, gid): """Октрыть конфигурационный файл""" FO = False try: if os.path.islink(nameFileOld): # если ссылка то удаляем её os.unlink(nameFileOld) FO = open (nameFileOld, "r+") except: try: fd = os.open(nameFileOld, os.O_CREAT) os.close(fd) os.chmod(nameFileOld, mode) os.chown(nameFileOld,uid,gid) FO = open(nameFileOld, "r+") except: self.setError (_("not open file:" ) + nameFileOld) return False return FO def openFiles(self, nameFileNew, nameFileOld): """Открывает два профайла новый и старый""" self.oldProfile = "" self.newProfile = "" self.closeFiles() self.FN = False self.FO = False self.nameFileOld = self.__absFileName(nameFileOld) self.nameFileNew = self.__absFileName(nameFileNew) self.FN = self.__openNewFile(self.nameFileNew) self.FO = self.__openOldFile(self.nameFileOld, self._mode, self._uid, self._gid) if self.FN and self.FO: self.newProfile = self.FN.read() self.oldProfile = self.FO.read() def __del__(self): self.closeFiles() def closeFiles(self): """Закрытие файлов""" self.__closeNewFile() self.__closeOldFile() class profile(_file, _terms): """Класс для работы с профилями На вход 2 параметра: объект хранения переменных, имя сервиса - не обязательный параметр """ def __init__(self, objVar, servDir=False): _file.__init__(self) # Словарь для создания объектов новых классов по образцу self.newObjProt = {'proftpd':(apache,),} # Заголовок title self.__titleHead = "--------------------------------------\ ----------------------------------------" self._titleBody = "" self._titleList = (_("Modified"), _("File of a profile")) # Метки varStart = "#-" varEnd = "-#" self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")%(varStart,varEnd),re.M) self._deltVarStart = len(varStart) self._deltVarEnd = len(varEnd) # Условия self._reTermBloc = re.compile("#\?(?P[a-zA-Z0-9\-_]+)\ (?P[\>\<\=\!\&\|]+\ [a-zA-Z0-9\>\<\=\!\|\&\-_\.]+)#\ \n*(?P.+?)\n*#(?P=rTerm)#(?P[ ,\t]*\n?)",re.M|re.S) # Объект с переменными self.objVar = objVar # Базовая директория переноса профилей "/mnt/calculate" или "/" и.т.д baseDir = self.objVar.Get("cl_root_path") #self._baseDir = os.path.split(baseDir)[0] self._baseDir = baseDir if self._baseDir == "/": self._baseDir = "" # Последняя часть директории профиля (имя сервиса: samba, mail) self._servDir = servDir if self._servDir: if self._servDir[0] != "/": self._servDir = "/" + self._servDir if self._servDir[-1] != "/": self._servDir += "/" self._servDir = os.path.split(self._servDir)[0] # Преобразование восьмеричного в целое (ввод строка, вывод число) 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 applyVarsProfile(self, textProfile): """ Заменяет переменные на их значения """ resS = self._reVar.search(textProfile) textProfileTmp = textProfile while resS: mark = textProfileTmp[resS.start():resS.end()] varName = mark[self._deltVarStart:-self._deltVarEnd] varValue = "" if self.objVar.defined(varName): varValue = str(self.objVar.Get(varName)) textProfileTmp = textProfileTmp.replace(mark, varValue) resS = self._reVar.search(textProfileTmp) return textProfileTmp def applyTermsProfile(self, textProfile, nameProfile): """ Применяет условия, к условным блокам текста """ textTerm = "" resS = self._reTermBloc.search(textProfile) textProfileTmp = textProfile 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 profile not valid: ")+\ nameProfile): textProfileTmp = textProfileTmp.replace(mark, body+end) else: textProfileTmp = textProfileTmp.replace(mark, "") resS = self._reTermBloc.search(textProfileTmp) return textProfileTmp def getNeedProfile(self, fileProfile): """Применяем правила к названию файла""" dirP,fileP = os.path.split(fileProfile) if fileP: spFile = fileP.split("?") realFileName = spFile[0] if len(spFile)>1: flagTrue = False for term in spFile[1:]: if self._equalTerm(term, _("name profile not valid: ")+\ fileProfile): flagTrue = True break if flagTrue: return True else: return False else: return True else: self.setError (_("name profile not valid: ")+ str(fileProfile)) return False def getTitle(self, comment, commentList): """Выдает заголовок профиля ( версия и.т.д)""" if comment: self._titleBody = comment + self.__titleHead + "\n" z = 0 lenCommentList = len(commentList) - 1 for com in self._titleList: if lenCommentList < z: self._titleBody += comment + " " + com + "\n" else: self._titleBody += comment+ " " + com +\ " " + commentList[z] + "\n" z += 1 self._titleBody += comment + self.__titleHead + "\n" return self._titleBody else: return "" def applyProfiles(self): """Применяет профили к конфигурационным файлам""" if not self.objVar.defined("cl_profile_path"): self.setError (_("not defined Var: ") + "cl_profile_path") return False dirsProfiles = self.objVar.Get("cl_profile_path") if self._servDir: tmpDirsProfiles = [] for dirP in dirsProfiles: dirProf = dirP + self._servDir if os.access(dirProf, os.F_OK): # Если директория существует tmpDirsProfiles.append(dirProf) else: tmpDirsProfiles.append(False) dirsProfiles = tmpDirsProfiles dirObjs = self.scanDirs(dirsProfiles) #файлы к которым были применены профили filesApply = [] #созданные директории createdDirs = [] for dirObj in dirObjs: # сортируем файлы по названию if dirObj.files: dirObj.files.sort() for dirProfile in dirObj.dirs: crDirs = self.createDir(dirObj.baseDir, dirProfile, self._baseDir) if crDirs == False: return False createdDirs += crDirs for fileProfile in dirObj.files: if self.getNeedProfile(fileProfile): if self.getError(): print self.getError() return False oldFile = fileProfile.split(dirObj.baseDir)[1] dirName,fileName = os.path.split(oldFile) fileName = fileName.split("?")[0] if dirName == "/": dirName = "" oldFile = self._baseDir + dirName + "/" + fileName listProfTitle = dirObj.baseDir.split("/")[-2:] profTitle = '"' + "/".join(listProfTitle) + '"' self.join(fileProfile, oldFile, (self.objVar.Get("cl_ver"),profTitle)) filesApply.append(oldFile) else: if self.getError(): print self.getError() return False self.closeFiles() return (createdDirs, filesApply) def __getApplyHeadProfile(self ,newFile, oldFile): """Применяет заголовок к профилю (права, владелец, и.т. д)""" self.closeFiles() if not self.newProfile: self.nameFileNew = self.absFileName(newFile) self.FN = self.openNewFile(self.nameFileNew) self.newProfile = self.FN.read() self.closeNewFile() objHeadNew = calcHeader(self.newProfile, False, self.getFileType(),objVar=self.objVar) if not objHeadNew.headerTerm: return False flagSymlink = False flagForce = False # Если есть параметр mirror if objHeadNew.params.has_key("mirror"): if objHeadNew.params.has_key("link"): profileFile = objHeadNew.params['link'] if not os.path.exists(profileFile): if os.path.exists(oldFile): os.remove(oldFile) return False elif not os.path.exists(oldFile): return False # Если есть указатель на файл профиля (link) if objHeadNew.params.has_key("link"): profileFile = objHeadNew.params['link'] foundProfileFile = os.path.exists(profileFile) if foundProfileFile: FO = self.openNewFile(profileFile) buff = FO.read() FO.close() if os.path.exists(oldFile): os.remove(oldFile) if foundProfileFile: fd = os.open(oldFile, os.O_CREAT) os.close(fd) os.chmod(oldFile, self._mode) os.chown(oldFile, self._uid, self._gid) FON = open (oldFile, "r+") FON.write(buff) FON.close() # Если символическая ссылка if objHeadNew.params.has_key("symbolic"): prevOldFile = oldFile oldFile = objHeadNew.params['link'] flagSymlink = True oldFileExists = os.path.exists(oldFile) # В случае force if objHeadNew.params.has_key("force") and oldFileExists: FO = self.openNewFile(oldFile) buff = FO.read() FO.close() os.remove(oldFile) fd = os.open(oldFile, os.O_CREAT) os.close(fd) os.chmod(oldFile, self._mode) os.chown(oldFile, self._uid, self._gid) FON = open (oldFile, "r+") FON.write(buff) FON.close() # chmod - изменяем права if objHeadNew.params.has_key("chmod"): mode = self.__octToInt(objHeadNew.params['chmod']) if mode: if not os.path.exists(oldFile): fd = os.open(oldFile, os.O_CREAT) os.close(fd) os.chmod(oldFile, mode) else: self.setError (_("False value 'chmod' in profile: " ) +\ newFile) return 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)[2] except: self.setError (_("Not user in this system: ") + strUid) self.setError (_("False value 'chown' in profile: " )+\ newFile) return False try: import grp gid = grp.getgrnam(strGid)[2] except: self.setError (_("Not group in this system: ")+strGid) self.setError (_("False value 'chown' in profile: " )+\ newFile) return False if not os.path.exists(oldFile): FO = self.openNewFile(newFile) FO.close() fd = os.open(oldFile, os.O_CREAT) os.close(fd) os.chmod(oldFile, self._mode) os.chown(oldFile, uid, gid) else: self.setError (_("False value 'chown' in profile: " ) +\ newFile) return False else: self.setError (_("False value 'chown' in profile: " ) +\ newFile) return False self.openFiles(newFile, oldFile) if flagSymlink: if os.path.exists(prevOldFile): os.remove(prevOldFile) os.symlink(oldFile, prevOldFile) return 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) 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 join(self, newFile, oldFile, ListOptTitle): """Объединения профиля и конф. файла join(newFile, oldFile, ListOptTitle) Объединение профиля newFile и конф. файла oldFile, ListOptTitle - список строк которые добавятся в заголовок """ # Выполняем условия для блока текста а так-же заменяем переменные self.newProfile = "" self.nameFileNew = self.absFileName(newFile) self.FN = self.openNewFile(self.nameFileNew) self.newProfile = self.FN.read() self.closeNewFile() if self.getFileType() != "bin": self.newProfile = self.applyTermsProfile(self.newProfile, newFile) #print "|%s|" %(self.newProfile) self.newProfile = self.applyVarsProfile(self.newProfile) objHeadNew = self.__getApplyHeadProfile(newFile, oldFile) if not objHeadNew: return True self.newProfile = objHeadNew.body #if objHeadNew.fileType != "bin": #self.newProfile = self.applyTermsProfile(self.newProfile, #newFile) #self.newProfile = self.applyVarsProfile(self.newProfile) # Титл конфигурационного файла title = "" if ListOptTitle: title = self.getTitle(objHeadNew.comment, ListOptTitle) title = title.encode("UTF-8") objHeadOld = False if objHeadNew.comment: objHeadOld = calcHeader(self.oldProfile, objHeadNew.comment) # Тестирование #print self.nameFileOld #print objHeadNew.typeAppend if objHeadNew.fileType: # Создаем объект в случае параметра format в заголовке if (objHeadNew.typeAppend == "replace" or\ objHeadNew.typeAppend == "before" or\ objHeadNew.typeAppend == "after") and\ not (objHeadNew.fileType == "bin" or\ objHeadNew.fileType == "raw"): try: exec ("objProfNew=%s(self.newProfile)"%\ (objHeadNew.fileType)) except NameError: #Создаем объект из self.newObjProt с помощью # метаклассов if self.newObjProt.has_key(objHeadNew.fileType): objProfNewCl = self.createNewClass(\ objHeadNew.fileType, self.newObjProt[objHeadNew.fileType]) objProfNew = objProfNewCl(self.newProfile) else: self.setError (\ _("False join profile for type profile: ")\ + objHeadNew.fileType + " : " +\ newFile) return False # Объект Документ docObj = objProfNew.docObj # Удаление комментариев из документа docObj.removeComment(docObj.getNodeBody()) # Добавление необходимых переводов строк docObj.insertBRtoBody(docObj.getNodeBody()) # Добавление необходимых разделителей между областями docObj.insertBeforeSepAreas(docObj.getNodeBody()) # Получение текстового файла из XML документа self.newProfile = objProfNew.getConfig().encode("UTF-8") # Титл для объединения if ListOptTitle: title = self.getTitle(objProfNew._comment, ListOptTitle) title = title.encode("UTF-8") # Замена if objHeadNew.typeAppend == "replace": if objHeadNew.execStr: self.oldProfile = objHeadNew.execStr+title+self.newProfile else: self.oldProfile = title + self.newProfile self.saveOldFile() return True # Впереди elif objHeadNew.typeAppend == "before": if objHeadOld and objHeadOld.body: self.oldProfile = objHeadOld.body if self.newProfile[-1] == "\n": tmpProfile = self.newProfile + self.oldProfile else: tmpProfile = self.newProfile + "\n" + self.oldProfile if objHeadNew.execStr: self.oldProfile = objHeadNew.execStr + title + tmpProfile elif objHeadOld.execStr: self.oldProfile = objHeadOld.execStr + title + tmpProfile else: self.oldProfile = title + tmpProfile #print self.oldProfile self.saveOldFile() return True # Cзади elif objHeadNew.typeAppend == "after": if objHeadOld and objHeadOld.body: self.oldProfile = objHeadOld.body if self.newProfile[-1] == "\n": tmpProfile = self.oldProfile + self.newProfile else: tmpProfile = self.oldProfile + "\n" + self.newProfile if objHeadNew.execStr: self.oldProfile = objHeadNew.execStr + title + tmpProfile elif objHeadOld.execStr: self.oldProfile = objHeadOld.execStr + title + tmpProfile else: self.oldProfile = title + tmpProfile self.saveOldFile() return True # Объединение elif objHeadNew.typeAppend == "join": try: exec ("objProfNew=%s(self.newProfile)"%\ (objHeadNew.fileType)) except NameError: #Создаем объект из self.newObjProt с помощью # метаклассов if self.newObjProt.has_key(objHeadNew.fileType): objProfNewCl = self.createNewClass(\ objHeadNew.fileType, self.newObjProt[objHeadNew.fileType]) objProfNew = objProfNewCl(self.newProfile) else: self.setError (\ _("False join profile for type profile: ")\ + objHeadNew.fileType + " : " +\ newFile) return False # Титл для объединения if ListOptTitle: title = self.getTitle(objProfNew._comment, ListOptTitle) title = title.encode("UTF-8") # В случае пустого конфигурационного файла reNoClean = re.compile("[^\s]",re.M) if not self.oldProfile or\ not reNoClean.search(self.oldProfile): self.oldProfile = "" #if objHeadNew.execStr: #self.oldProfile = objHeadNew.execStr + \ #title + objProfNew.getConfig().encode("UTF-8") #else: #self.oldProfile = title +\ #objProfNew.getConfig().encode("UTF-8") #self.saveOldFile() #return True objHeadOld = calcHeader(self.oldProfile, objProfNew._comment) if objHeadOld.body: self.oldProfile = objHeadOld.body else: self.oldProfile = "" if self.newObjProt.has_key(objHeadNew.fileType): objProfOldCl = self.createNewClass(\ objHeadNew.fileType, self.newObjProt[objHeadNew.fileType]) objProfOld = objProfOldCl(self.oldProfile) else: exec ("objProfOld=%s(self.oldProfile)"%\ (objHeadNew.fileType)) #print "#%s#" %(objProfOld.docObj.body.toprettyxml()) #print "#%s#" %(objProfNew.docObj.body.toprettyxml()) objProfOld.join(objProfNew) if objHeadNew.execStr: self.oldProfile = objHeadNew.execStr + title +\ objProfOld.getConfig().encode("UTF-8") elif objHeadOld.execStr: self.oldProfile = objHeadOld.execStr + title +\ objProfOld.getConfig().encode("UTF-8") else: self.oldProfile = title +\ objProfOld.getConfig().encode("UTF-8") self.saveOldFile() return True else: self.setError (_("False (type append) profile: " ) +\ objHeadNew.typeAppend) return False else: self.setError (_("Type profile not found: ") + newFile) return False class samba(objShare): """Класс для обработки конфигурационного файла типа samba """ _comment = "#" configName = "samba" configVersion = "0.1" reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n",re.M) reBody = re.compile(".+",re.M|re.S) reComment = re.compile("\s*%s.*|\s*;.*"%(_comment)) reSeparator = re.compile("\s*=\s*") sepFields = "\n" reSepFields = re.compile(sepFields) def __init__(self,text): self.text = text self.blocTextObj = blocText() self._splitToFields = self.splitToFields # Объект документ self.docObj = self._textToXML() # XML документ self.doc = self.docObj.doc def join(self, sambaObj): """Объединяем конфигурации""" if isinstance(sambaObj, samba): self.docObj.joinDoc(sambaObj.doc) # Для добавления перевода строки между областями если его нет #print self.docObj.body.toprettyxml() xmlAreas = xpath.Evaluate("child::area", self.docObj.body) for xmlArea in xmlAreas: if xmlArea.previousSibling and\ self.docObj.getTypeField(xmlArea.previousSibling) == "br": continue xmlFields = xpath.Evaluate("child::field", xmlArea) if not (xmlFields and\ (self.docObj.getTypeField(xmlFields[-1]) == "br" or\ self.docObj.getTypeField(xmlFields[-1]) == "comment")): if xmlArea.nextSibling: parentNode = xmlArea.parentNode nextNode = xmlArea.nextSibling parentNode.insertBefore(self.docObj.createField("br", [],"",[], False,False), nextNode) def setDataField(self, txtLines, endtxtLines): """Создаем список объектов с переменными""" class fieldData: def __init__(self): self.name = False self.value = False self.comment = False self.br = False fields = [] field = fieldData() z = 0 for k in txtLines: textLine = k + endtxtLines[z] z += 1 findComment = self.reComment.search(textLine) if not textLine.strip(): field.br = textLine fields.append(field) field = fieldData() elif findComment: field.comment = textLine fields.append(field) field = fieldData() else: pars = textLine.strip() nameValue = self.reSeparator.split(pars) if len(nameValue) > 2: valueList = nameValue[1:] nameValue =[nameValue[0],"=".join(valueList)] if len(nameValue) == 2: name = nameValue[0] value = nameValue[1].replace(self.sepFields,"") field.name = name.replace(" ","").replace("\t","") field.value = value field.br = textLine fields.append(field) field = fieldData() return fields def splitCleanBloc(self, txtBloc): """Делим блок на две части (переменные, пустые строки в конце)""" txtLines = txtBloc.split("\n") firstBloc = [] nextBloc = [] txtLines.reverse() z = 0 for txtLine in txtLines: if not txtLine.strip(): nextBloc.append(txtLine) else: break z += 1 txtLines.reverse() firstBloc = txtLines[:-z] nextBloc.reverse() if nextBloc: firstBloc.append("") if nextBloc and "\n".join(nextBloc): return ("\n".join(firstBloc), "\n".join(nextBloc)) else: return False def getFullAreas(self, blocs): """Делит текст на области, (Заголовок, тело) Возвращает два списка: заголовки, тела """ headsAreas = [] bodyAreas = [] if not blocs: return [] lenBlocs = len(blocs[0]) for i in range(lenBlocs): txtBloc = blocs[1][i] clean = self.splitCleanBloc(txtBloc) if clean: headsAreas.append(blocs[0][i]) bodyAreas.append(clean[0]) headsAreas.append("") bodyAreas.append(clean[1]) else: headsAreas.append(blocs[0][i]) bodyAreas.append(blocs[1][i]) return (headsAreas, bodyAreas) def createTxtConfig(self, strHeader, dictVar): """Cоздает область с заголовком создает текст конфигурационного файла в формате samba из заголовка (строка) и словаря переменных """ outTxt = "[" + strHeader + "]\n" for key in dictVar.keys(): outTxt += "%s = %s\n" %(key,dictVar[key]) return outTxt def _textToXML(self): """Преобразует текст в XML""" blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody) blocs = self.getFullAreas(blTmp) headers = [] startHeaders = [] finHeaders = [] docObj = xmlDoc() docObj.createDoc(self.configName, self.configVersion) rootNode = docObj.getNodeBody() # Если пустой текст то создаем пустой документ if not blocs: return docObj for h in blocs[0]: listfinH = h.split("]") finH = listfinH[0] if "[" in finH: startHeaders.append(finH + "]") else: startHeaders.append(finH) if len(listfinH) == 2: finHeaders.append(listfinH[1]) else: finHeaders.append("") headers.append(finH.replace("[","").replace("]","").strip()) bodys = blocs[1] z = 0 for h in headers: if not bodys[z]: z += 1 continue areaAction = False if h: if h[0] == "!": docObj.createCaption(h[1:], [startHeaders[z],""]) areaAction = "drop" elif h[0] == "-": docObj.createCaption(h[1:], [startHeaders[z],""]) areaAction = "replace" else: docObj.createCaption(h, [startHeaders[z],""]) else: docObj.createCaption(h, [startHeaders[z],""]) if "\n" in blocs[0][z]: if self.reComment.search(finHeaders[z]): docObj.createField('comment', [finHeaders[z]]) elif not finHeaders[z].strip() and\ finHeaders[z].replace("\n",""): docObj.createField('br', [finHeaders[z].replace("\n","")]) else: docObj.createField('br') fields = self._splitToFields(bodys[z]) for f in fields: if f.name != False and f.value!=False and f.br!=False: # Обработка условий для samba if f.name[0] == "!" or f.name[0] == "-" or\ f.name[0] == "+": qns = self.removeSymbolTerm(f.br) xmlField = docObj.createField("var", [qns], f.name[1:], [f.value]) if f.name[0] == "!": # Удаляемое в дальнейшем поле docObj.setActionField(xmlField, "drop") else: docObj.createField("var",[f.br.replace("\n","")], f.name, [f.value]) docObj.createField('br') elif f.comment != False: docObj.createField('comment', [f.comment]) elif f.br != False: docObj.createField('br', [f.br.replace("\n","")]) if h.strip(): area = docObj.createArea() if areaAction: docObj.setActionArea(area, areaAction) rootNode.appendChild(area) else: fieldsNodes = docObj.tmpFields.getFields() for fieldNode in fieldsNodes: rootNode.appendChild(fieldNode) docObj.clearTmpFields() z += 1 #print docObj.doc.toprettyxml() return docObj class bind(objShare): """Класс для обработки конфигурационного файла типа bind """ _comment = "//" configName = "bind" configVersion = "0.1" __openArea = "{" __closeArea = "[ \t]*\}[ \t]*;[ \t]*" sepFields = ";" reOpen = re.compile(__openArea) reClose = re.compile(__closeArea) reCloseArea = re.compile(__closeArea + "\s*\Z") reComment = re.compile("[ \t]*%s" %(_comment)) reSepFields = re.compile(sepFields) reSeparator = re.compile("[ \t]+") def __init__(self,text): self.text = text self.blocTextObj = blocText() # Объект документ self.docObj = self.textToXML() # Создаем поля-массивы self.docObj.postParserList() # XML документ self.doc = self.docObj.doc # Делим область на составные части def findOpenClose(self, text, reOpen, reClose, reComment): """Делит область на составные части начальный текстовый блок, открывающий блок, блок-тело, закрывающий блок """ firstBloc = "" startBloc = "" bodyBloc = "" endBloc = "" textLines = text.splitlines() findOpen = False if textLines: findOpen = reOpen.search(textLines[0]) openBl = reOpen.search(text) if findOpen and reComment.split(text)[0].strip(): blocA = text[openBl.end():] firstBloc = text[:openBl.start()] startBloc = text[openBl.start():openBl.end()] closeBl = reClose.search(blocA) endBloc = blocA[closeBl.start():closeBl.end()] bodyBloc = blocA[:closeBl.start()] return (firstBloc, startBloc, bodyBloc, endBloc) else: return (firstBloc, startBloc, text, endBloc) # Делим текст на области включая вложенные (areas массив областей) def splitToAllArea(self, text, areas, reOpen, reClose, reCloseArea, reComment, reSepFields): """Делит текст на области включая вложенные возвращает список объектов областей (переменная areas) """ class area: def __init__(self): self.header = False self.start = False self.fields = [] self.end = False blocs = self.blocTextObj.splitTxtToBloc(text,reOpen,reClose, reComment,reSepFields) for i in blocs: areaA = area() first,start,body,end = self.findOpenClose(i, reOpen, reCloseArea, reComment) areaA.header = first.replace(" ","").replace("\t","") areaA.start = first + start areaA.end = end if areaA.end: blocsA = self.blocTextObj.splitTxtToBloc(body,reOpen,reClose, reComment,reSepFields) if blocsA and blocsA[0] == body: areaA.fields.append(body) areas.append(areaA) else: for ar in blocsA: self.splitToAllArea(ar, areaA.fields, reOpen, reClose, reCloseArea, reComment, reSepFields) areas.append(areaA) else: areaA.fields.append(body) areas.append(areaA) return areas def setDataField(self, txtLines, endtxtLines): """Создаем список объектов с переменными""" class fieldData: def __init__(self): self.name = False self.value = False self.comment = False self.br = False fields = [] field = fieldData() z = 0 for k in txtLines: textLine = k + endtxtLines[z] z += 1 findComment = self.reComment.search(textLine) if not textLine.strip(): field.br = textLine fields.append(field) field = fieldData() elif findComment: field.comment = textLine fields.append(field) field = fieldData() else: pars = textLine.strip() nameValue = self.reSeparator.split(pars) if len (nameValue) == 1: field.name = "" field.value = textLine.replace(self.sepFields,"") field.br = textLine fields.append(field) field = fieldData() if len(nameValue) > 2: valueList = nameValue[1:] nameValue =[nameValue[0]," ".join(valueList).replace(\ self.sepFields,"")] if len(nameValue) == 2: name = nameValue[0] value = nameValue[1].replace(self.sepFields,"") field.name = name.replace(" ","").replace("\t","") field.value = value field.br = textLine fields.append(field) field = fieldData() return fields def createCaptionTerm(self, header, start, end, docObj): """Создание пустой области с заголовком при создании области проверяется первый символ заголовка и добавляется тег action "!" - drop "-" - replace """ areaAction = False if header: if header[0] == "!": docObj.createCaption(header[1:], [start, end.replace("\n","")]) areaAction = "drop" elif header[0] == "-": docObj.createCaption(header[1:], [start, end.replace("\n","")]) areaAction = "replace" else: docObj.createCaption(header, [start, end.replace("\n","")]) else: docObj.createCaption(header, [start, end.replace("\n","")]) areaXML = docObj.createArea() if areaAction: docObj.setActionArea(areaXML, areaAction) return areaXML def createXML(self, areas, rootNode, docObj): """Создаем из массивов областей XML""" for i in areas: if str(i.__class__.__name__) == "area": if i.header and i.start: areaXML = self.createCaptionTerm(i.header, i.start, i.end.replace("\n",""), docObj) else: areaXML = rootNode for f in i.fields: if str(f.__class__.__name__) == "area": if f.header and f.start: areaXMLChild = self.createCaptionTerm(f.header, f.start, f.end.replace("\n",""), docObj) self.createXML(f.fields, areaXMLChild, docObj) areaXML.appendChild(areaXMLChild) else: self.createXML(f.fields, areaXML, docObj) if "\n" in f.end: fieldXMLBr = docObj.createField("br",[], "",[], False, False) areaXML.appendChild(fieldXMLBr) else: if not f: continue fields = self.splitToFields(f) for field in fields: if field.name != False: fieldXML = self.createFieldTerm(field.name, field.value, field.br, docObj) areaXML.appendChild(fieldXML) if field.br[-1] == "\n": fieldXMLBr = docObj.createField("br",[], "",[], False, False) areaXML.appendChild(fieldXMLBr) elif field.comment != False: fieldXML = docObj.createField("comment", [field.comment], "", [], False, False) areaXML.appendChild(fieldXML) elif field.br != False: brText = field.br.replace("\n","") if brText: fieldXML = docObj.createField('br', [brText], "", [], False, False) else: fieldXML = docObj.createField('br', [], "", [], False, False) areaXML.appendChild(fieldXML) if i.header and i.start: rootNode.appendChild(areaXML) if "\n" in i.end: fieldXMLBr = docObj.createField("br",[], "",[], False, False) rootNode.appendChild(fieldXMLBr) else: fields = self.splitToFields(i) for field in fields: if field.name != False: fieldXML = self.createFieldTerm(field.name, field.value, field.br, docObj) rootNode.appendChild(fieldXML) if field.br[-1] == "\n": fieldXMLBr = docObj.createField("br",[],"", [], False, False) rootNode.appendChild(fieldXMLBr) elif field.comment != False: fieldXML = docObj.createField("comment", [field.comment], "", [], False, False) rootNode.appendChild(fieldXML) elif field.br != False: brText = field.br.replace("\n","") if brText: fieldXML = docObj.createField('br', [brText],"",[], False, False) else: fieldXML = docObj.createField('br', [], "", [], False, False) rootNode.appendChild(fieldXML) #rootNode.appendChild(areaXML) def textToXML(self): """Преобразуем текст в XML""" areas = [] if self.text.strip(): self.splitToAllArea(self.text, areas, self.reOpen, self.reClose, self.reCloseArea,self.reComment,self.reSepFields) docObj = xmlDoc() # Создание объекта документ c пустым разделителем между полями docObj.createDoc(self.configName, self.configVersion) if not areas: return docObj self.createXML(areas, docObj.getNodeBody(), docObj) return docObj def join(self, bindObj): """Объединяем конфигурации""" if isinstance(bindObj, bind): self.docObj.joinDoc(bindObj.doc) class apache(bind): """Класс для обработки конфигурационного файла типа apache """ _comment = "#" configName = "apache" configVersion = "0.1" __headerArea = "[^\<\> \t]+[ \t]+[^\<\> \t]+" __openArea = "[ \t]*\<%s\>"%(__headerArea) __closeArea = "[ \t]*\<\/[^\<\>]+\>" sepFields = "\n" reOpen = re.compile(__openArea) reClose = re.compile(__closeArea) reCloseArea = re.compile(__closeArea + "\s*\Z") reComment = re.compile("[ \t]*%s"%(_comment)) reSepFields = re.compile(sepFields) reSeparator = re.compile("[ \t]+") reHeader = re.compile(__headerArea) def __init__(self,text): self.text = text self.blocTextObj = blocText() # Объект документ self.docObj = self.textToXML() # Создаем поля-массивы self.docObj.postParserList() # Создаем поля разделенные массивы self.docObj.postParserListSeplist(self.docObj.body) # XML документ self.doc = self.docObj.doc def join(self, apacheObj): """Объединяем конфигурации""" if isinstance(apacheObj, apache): #print self.docObj.doc.toprettyxml() self.docObj.joinDoc(apacheObj.doc) # Для добавления перевода строки перед закрывающим тегом # конфигурационного файла xmlAreas = xpath.Evaluate("child::area", self.docObj.body) for xmlArea in xmlAreas: xmlFields = xpath.Evaluate("child::field", xmlArea) if not (xmlFields and\ self.docObj.getTypeField(xmlFields[-1]) == "br"): xmlArea.appendChild(self.docObj.createField("br", [],"",[], False,False)) # Делим область на составные части def findOpenClose(self, text, reOpen, reClose, reComment, reHeader): """Делит область на составные части начальный текстовый блок, открывающий блок, блок-тело, закрывающий блок """ firstBloc = "" startBloc = "" bodyBloc = "" endBloc = "" textLines = text.splitlines() findOpen = False if textLines: findOpen = reOpen.search(textLines[0]) openBl = reOpen.search(text) if findOpen and reComment.split(text)[0].strip(): blocA = text[openBl.end():] firstBloc = "" startBloc = text[openBl.start():openBl.end()] headBl = reHeader.search(startBloc) if headBl: firstBloc = headBl.group(0) closeBl = reClose.search(blocA) endBloc = blocA[closeBl.start():closeBl.end()] bodyBloc = blocA[:closeBl.start()] return (firstBloc, startBloc, bodyBloc, endBloc) else: return (firstBloc, startBloc, text, endBloc) # Делим текст на области включая вложенные (areas массив областей) def splitToAllArea(self, text, areas, reOpen, reClose, reCloseArea, reComment, reSepFields, reHeader): """Делит текст на области включая вложенные возвращает список объектов областей (переменная areas) """ class area: def __init__(self): self.header = False self.start = False self.fields = [] self.end = False blocs = self.blocTextObj.splitTxtToBloc(text,reOpen,reClose, reComment,reSepFields) for i in blocs: areaA = area() first,start,body,end = self.findOpenClose(i, reOpen, reCloseArea, reComment, reHeader) areaA.header = first.replace(" ","").replace("\t","") areaA.start = start areaA.end = end if areaA.end: blocsA = self.blocTextObj.splitTxtToBloc(body,reOpen,reClose, reComment,reSepFields) if blocsA and blocsA[0] == body: areaA.fields.append(body) areas.append(areaA) else: for ar in blocsA: self.splitToAllArea(ar, areaA.fields, reOpen, reClose, reCloseArea, reComment, reSepFields, reHeader) areas.append(areaA) else: areaA.fields.append(body) areas.append(areaA) def setDataField(self, txtLines, endtxtLines): """Создаем список объектов с переменными""" class fieldData: def __init__(self): self.name = False self.value = False self.comment = False self.br = False fields = [] field = fieldData() z = 0 for k in txtLines: textLine = k + endtxtLines[z] #print "#"+brBloc[z]+"#" z += 1 findComment = self.reComment.search(textLine) if not textLine.strip(): field.br = textLine fields.append(field) field = fieldData() elif findComment: field.comment = textLine fields.append(field) field = fieldData() else: pars = textLine.strip() nameValue = self.reSeparator.split(pars) if len (nameValue) == 1: field.name = "" field.value = textLine.replace(self.sepFields,"") field.br = textLine fields.append(field) field = fieldData() if len(nameValue) == 3: valueList = nameValue[2:] nameValue =["".join(nameValue[:2])," ".join(valueList)] if len(nameValue) > 3: valueList = nameValue[1:] nameValue =[nameValue[0]," ".join(valueList).replace(\ self.sepFields,"")] if len(nameValue) == 2: name = nameValue[0] value = nameValue[1].replace(self.sepFields,"") field.name = name.replace(" ","").replace("\t","") field.value = value field.br = textLine fields.append(field) field = fieldData() return fields def textToXML(self): """Преобразуем тект в XML""" areas = [] self.splitToAllArea(self.text, areas, self.reOpen, self.reClose, self.reCloseArea,self.reComment,self.reSepFields, self.reHeader) docObj = xmlDoc() # Создание объекта документ c пустым разделителем между полями docObj.createDoc(self.configName, self.configVersion) if not areas: return docObj self.createXML(areas, docObj.getNodeBody(), docObj) return docObj class postfix(apache): """Класс для обработки конфигурационного файла типа postfix """ _comment = "#" configName = "postfix" configVersion = "0.1" sepFields = "\n" reComment = re.compile("[ \t]*%s"%(_comment)) reSepFields = re.compile(sepFields) # разделитель названия и значения переменной reSeparator = re.compile("\s*=\s*") def __init__(self,text): self.text = text # Объект документ self.docObj = self.textToXML() # Создаем поля разделенные массивы self.docObj.postParserListSeplist(self.docObj.body) # XML документ self.doc = self.docObj.doc def join(self, postfixObj): """Объединяем конфигурации""" if isinstance(postfixObj, postfix): self.docObj.joinDoc(postfixObj.doc) def textToXML(self): """Преобразуем текст в XML""" class area: def __init__(self): self.header = False self.start = False self.fields = [] self.end = False areas = [] oneArea = area() oneArea.header = "" oneArea.start = "" oneArea.fields = [self.text] oneArea.end = "" areas.append(oneArea) docObj = xmlDoc() # Создание объекта документ c пустым разделителем между полями docObj.createDoc(self.configName, self.configVersion) if not areas: return docObj self.createXML(areas, docObj.getNodeBody(), docObj) return docObj def setDataField(self, txtLines, endtxtLines): """Cоздаем список объектов с переменными""" class fieldData: def __init__(self): self.name = False self.value = False self.comment = False self.br = False fields = [] field = fieldData() z = 0 for k in txtLines: textLine = k + endtxtLines[z] #print "#"+brBloc[z]+"#" z += 1 findComment = self.reComment.search(textLine) if not textLine.strip(): field.br = textLine fields.append(field) field = fieldData() elif findComment: field.comment = textLine fields.append(field) field = fieldData() else: pars = textLine.strip() nameValue = self.reSeparator.split(pars) if len (nameValue) == 1: field.name = "" field.value = textLine.replace(self.sepFields,"") field.br = textLine fields.append(field) field = fieldData() if len(nameValue) > 2: valueList = nameValue[1:] nameValue =[nameValue[0],"=".join(valueList).replace(\ self.sepFields,"")] if len(nameValue) == 2: name = nameValue[0] value = nameValue[1].replace(self.sepFields,"") field.name = name.replace(" ","").replace("\t","") field.value = value field.br = textLine fields.append(field) field = fieldData() return fields class ldap(samba): """Класс для обработки конфигурационного файла типа ldap """ _comment = "#" configName = "ldap" configVersion = "0.1" # Регулярное выражение для заголовка области reHeader = re.compile("^[\t ]*access.*\n?") # Регулярное выражения для области reArea = re.compile("^[\t ]*access[^\n]+\n(([\t ]*\ ((by|#)[^\n]*)?\n)+[\t ]*by[^\n]+\n?)",re.M|re.S) reComment = re.compile("\s*%s.*"%(_comment)) # разделитель между переменной и значением переменной reSeparator = re.compile("\s*") # разделитель полей sepFields = "\n" # регулярное выражение для разделителя полей reSepFields = re.compile(sepFields) def __init__(self,text): self.text = text self.blocTextObj = blocText() self._splitToFields = self.splitToFields # Объект документ self.docObj = self._textToXML() # Создаем поля-массивы self.docObj.postParserList() # Создаем поля разделенные массивы self.docObj.postParserListSeplist(self.docObj.body) # XML документ self.doc = self.docObj.doc def join(self, ldapObj): """Объединяем конфигурации""" if isinstance(ldapObj, ldap): self.docObj.joinDoc(ldapObj.doc) def setDataField(self, txtLines, endtxtLines): """Создаем список объектов с переменными""" class fieldData: def __init__(self): self.name = False self.value = False self.comment = False self.br = False fields = [] field = fieldData() z = 0 for k in txtLines: textLine = k + endtxtLines[z] z += 1 findComment = self.reComment.search(textLine) if not textLine.strip(): field.br = textLine fields.append(field) field = fieldData() elif findComment: field.comment = textLine fields.append(field) field = fieldData() else: pars = textLine.strip() nameValue = self.reSeparator.split(pars) if len(nameValue) > 2: valueList = nameValue[2:] nameValue =[nameValue[0]+nameValue[1]," ".join(valueList)] if len(nameValue) == 2: name = nameValue[0] value = nameValue[1].replace(self.sepFields,"") field.name = name.replace(" ","").replace("\t","") field.value = value field.br = textLine fields.append(field) field = fieldData() return fields def _textToXML(self): """Преобразует текст в XML""" blTmp = self.blocTextObj.findArea(self.text,self.reHeader,self.reArea) blocs = self.getFullAreas(blTmp) headers = [] startHeaders = [] finHeaders = [] docObj = xmlDoc() docObj.createDoc(self.configName, self.configVersion) rootNode = docObj.getNodeBody() # Если пустой текст то создаем пустой документ if not blocs: return docObj for h in blocs[0]: headers.append(h.rstrip()) bodys = blocs[1] z = 0 for h in headers: if not bodys[z]: z += 1 continue areaAction = False if h: if h[0] == "!": header = self.removeSymbolTerm(h.strip()) headerQuote = self.removeSymbolTerm(h) docObj.createCaption(header,[headerQuote,""]) areaAction = "drop" elif h[0] == "-": header = self.removeSymbolTerm(h.strip()) headerQuote = self.removeSymbolTerm(h) docObj.createCaption(header,[headerQuote,""]) areaAction = "replace" else: docObj.createCaption(h.strip(), [h.rstrip(),""]) else: docObj.createCaption(h.strip(), [h.rstrip(),""]) if "\n" in blocs[0][z]: resHead = self.reComment.search(h) if resHead: docObj.createField('comment', blocs[0][z][resHead.start():]) else: docObj.createField('br') fields = self._splitToFields(bodys[z]) for f in fields: if f.name != False and f.value!=False and f.br!=False: # Обработка условий для samba if f.name[0] == "!" or f.name[0] == "-" or\ f.name[0] == "+": qns = self.removeSymbolTerm(f.br) xmlField = docObj.createField("var", [qns], f.name[1:], [f.value]) if f.name[0] == "!": # Удаляемое в дальнейшем поле docObj.setActionField(xmlField, "drop") elif f.name[0] == "+": # Добавляем уникальное поле xmlField.setAttribute("type", "seplist") docObj.setActionField(xmlField, "join") else: docObj.createField("var",[f.br.replace("\n","")], f.name, [f.value]) docObj.createField('br') elif f.comment != False: docObj.createField('comment', [f.comment]) elif f.br != False: docObj.createField('br', [f.br.replace("\n","")]) if h.strip(): area = docObj.createArea() if areaAction: docObj.setActionArea(area, areaAction) rootNode.appendChild(area) else: fieldsNodes = docObj.tmpFields.getFields() for fieldNode in fieldsNodes: rootNode.appendChild(fieldNode) docObj.clearTmpFields() z += 1 #print docObj.doc.toprettyxml() return docObj class dovecot(bind): """Класс для обработки конфигурационного файла типа dovecot """ _comment = "#" configName = "dovecot" configVersion = "0.1" __openArea = "{" __closeArea = "[ \t]*\}[ \t]*" sepFields = "\n" reOpen = re.compile(__openArea) reClose = re.compile(__closeArea) reCloseArea = re.compile(__closeArea + "\s*\Z") reComment = re.compile("[ \t]*%s" %(_comment)) reSepFields = re.compile(sepFields) # разделитель названия и значения переменной reSeparator = re.compile("\s*=\s*") def __init__(self, text): bind.__init__(self,text) def addBrArea(self, xmlArea): """Добавляем перевод строки если его нет в конец области""" xmlFields = xpath.Evaluate("child::field", xmlArea) if xmlFields and not (\ self.docObj.getTypeField(xmlFields[-1]) == "br" or\ self.docObj.getTypeField(xmlFields[-1]) == "comment" ): xmlArea.appendChild(self.docObj.createField("br", [],"",[], False,False)) xmlAreas = xpath.Evaluate("child::area", xmlArea) for area in xmlAreas: self.addBrArea(area) def join(self, dovecotObj): """Объединяем конфигурации""" if isinstance(dovecotObj, dovecot): #print self.docObj.doc.toprettyxml() self.docObj.joinDoc(dovecotObj.doc) # Для добавления перевода строки перед закрывающим тегом # конфигурационного файла self.addBrArea(self.docObj.body) class procmail(objShare): """Класс для обработки конфигурационного файла типа procmail """ _comment = "#" configName = "procmail" configVersion = "0.1" sepFields = "\n" reComment = re.compile("[ \t]*%s" %(_comment)) reSepFields = re.compile(sepFields) # разделитель названия и значения переменной reSeparator = re.compile("=") def __init__(self, text): self.text = text self.docObj = self.textToXML() # Создаем поля-массивы self.doc = self.docObj.doc def setDataField(self, txtLines, endtxtLines): """Создаем список объектов с переменными""" class fieldData: def __init__(self): self.name = False self.value = False self.comment = False self.br = False fields = [] field = fieldData() z = 0 for k in txtLines: textLine = k + endtxtLines[z] z += 1 findComment = self.reComment.search(textLine) if not textLine.strip(): field.br = textLine fields.append(field) field = fieldData() elif findComment: field.comment = textLine fields.append(field) field = fieldData() else: pars = textLine.strip() nameValue = self.reSeparator.split(pars) if len(nameValue) == 2: name = nameValue[0] value = nameValue[1].replace(self.sepFields,"") field.name = name.replace(" ","").replace("\t","") field.value = value field.br = textLine fields.append(field) field = fieldData() return fields def textToXML(self): docObj = xmlDoc() docObj.createDoc(self.configName, self.configVersion) if self.text: nodeBody = docObj.getNodeBody() fields = self.splitToFields(self.text) for field in fields: if field.name != False: fieldXML = self.createFieldTerm(field.name, field.value, field.br, docObj) nodeBody.appendChild(fieldXML) if field.br[-1] == "\n": fieldXMLBr = docObj.createField("br",[], "",[], False, False) nodeBody.appendChild(fieldXMLBr) elif field.comment != False: fieldXML = docObj.createField("comment", [field.comment], "", [], False, False) nodeBody.appendChild(fieldXML) elif field.br != False: brText = field.br.replace("\n","") if brText: fieldXML = docObj.createField('br', [brText], "", [], False, False) else: fieldXML = docObj.createField('br', [], "", [], False, False) nodeBody.appendChild(fieldXML) return docObj def join(self, procmailObj): """Объединяем конфигурации""" if isinstance(procmailObj, procmail): #print self.docObj.doc.toprettyxml() self.docObj.joinDoc(procmailObj.doc) class kde(samba): """Класс для обработки конфигурационного файла типа kde """ _comment = "#" configName = "kde" configVersion = "0.1" reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n",re.M) reBody = re.compile(".+",re.M|re.S) reComment = re.compile("\s*%s.*"%(_comment)) reSeparator = re.compile("=") sepFields = "\n" reSepFields = re.compile(sepFields) def __init__(self,text): samba.__init__(self,text) def join(self, kdeObj): """Объединяем конфигурации""" if isinstance(kdeObj, kde): self.docObj.joinDoc(kdeObj.doc) # Для добавления перевода строки между областями если его нет #print self.docObj.body.toprettyxml() xmlAreas = xpath.Evaluate("child::area", self.docObj.body) if xmlAreas and len(xmlAreas)>1: for xmlArea in xmlAreas[-1:]: if xmlArea.previousSibling and\ self.docObj.getTypeField(xmlArea.previousSibling) == "br": continue xmlFields = xpath.Evaluate("child::field", xmlArea) if not (xmlFields and\ (self.docObj.getTypeField(xmlFields[-1])=="br" or\ self.docObj.getTypeField(xmlFields[-1])=="comment")): if xmlArea.nextSibling: parentNode = xmlArea.parentNode nextNode = xmlArea.nextSibling parentNode.insertBefore(\ self.docObj.createField("br", [],"",[], False,False), nextNode)