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

3507 lines
144 KiB

#-*- 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")
# Объект с переменными
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
"!" - <action>drop</action> удаляет
"+" - <action>join</action> добавляет
"-" - <action>replace</action> заменяет
"""
fieldAction = False
if name:
if name[0] == "!" or name[0] == "-" or name[0] == "+":
qnt = self.removeSymbolTerm(quote)
fieldXML = docObj.createField("var",[qnt],
name[1:], [value],
False, False)
if name[0] == "!":
fieldAction = "drop"
elif name[0] == "+":
fieldXML.setAttribute("type", "seplist")
fieldAction = "join"
else:
fieldXML = docObj.createField("var",
[quote.replace("\n","")],
name, [value],
False, False)
else:
fieldXML = docObj.createField("var",
[quote.replace("\n","")],
name, [value],
False, False)
if fieldAction:
docObj.setActionField(fieldXML, fieldAction)
return fieldXML
def removeSymbolTerm(self, text):
"""Удаляет первый символ названия переменной в строке
Если первый встречающийся символ с начала строки
'+', '-', '!' то он из этой строки будет удален,
если перед этим символом были пробельные символы,
то они будут сохранены, так-же если в строке есть символ
перевода строки он будет удален.
"""
reTerm = re.compile("^[ \t]*(\!|\+|\-)")
textNS = text.replace("\n","")
res = reTerm.search(textNS)
if res:
textNS = textNS[res.start():res.end()-1] + textNS[res.end():]
return textNS
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 = '<?xml version="1.0" encoding="UTF-8"?><cxmlconf><head>'
docTxt += '<ver>%s</ver>'% version
docTxt += '<format>%s</format>' % typeDoc
docTxt += '</head><body></body></cxmlconf>'
self.doc = 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 - оварь удаляемых полей разделенного списка
формируется программой
baseNode - Нода в которой идет поиск
xmNewlField - Нода field которая проверяется на принадлежность
к разделенному списку
"""
flagNewNodeSeplist = False
if self.getTypeField(xmNewlField) == "seplist":
flagNewNodeSeplist = True
nameNewField = self.getNameField(xmNewlField)
if nameNewField:
if removeNodesDict.has_key(nameNewField):
return removeNodesDict[nameNewField]
else:
oldFields = xpath.Evaluate('child::field', baseNode)
removeNodes = []
lenOldFields = len(oldFields)
for i in range(lenOldFields):
oldNode = oldFields[i]
flagSep = self.getTypeField(oldNode) == "seplist"
if flagNewNodeSeplist:
flagSep = True
if flagSep and\
nameNewField == self.getNameField(oldNode):
removeNodes.append(oldNode)
if i+1<lenOldFields:
nextNode = oldFields[i+1]
if self.getTypeField(nextNode) == "br":
removeNodes.append(nextNode)
removeNodesDict[nameNewField] = removeNodes
return removeNodes
def addNewFielsOldArea(self, newFields, joinNewFields, xmlOldArea):
"""Добавляет новые XML поля в область профиля"""
removeNodesDict = {}
notRemoveNodesDict = {}
for notRemNode in joinNewFields:
nameField = self.getNameField(notRemNode)
if not notRemoveNodesDict.has_key(nameField):
notRemoveNodesDict[nameField] = []
notRemoveNodesDict[nameField].append(notRemNode)
else:
notRemoveNodesDict[nameField].append(notRemNode)
notSepListField = []
sepListField = []
for nField in newFields:
if self.getRemoveNodeSepList(removeNodesDict, xmlOldArea,
nField):
sepListField.append(nField)
else:
if self.getNameField(nField):
notSepListField.append(nField)
for name in notRemoveNodesDict.keys():
if removeNodesDict.has_key(name):
removeNodesDict[name] = []
for removeNodes in removeNodesDict.values():
if removeNodes:
if self.getTypeField(removeNodes[-1]) == "seplist":
removeNodes = removeNodes[:-1]
else:
removeNodes = removeNodes[:-2]
for removeNode in removeNodes:
xmlOldArea.removeChild(removeNode)
for node in sepListField:
node.setAttribute("type", "seplist")
if not (self.getActionField(node) == "join" or\
self.getActionField(node) == "drop"):
self.setActionField(node,"insert")
self.joinField(xmlOldArea, node)
#else:
#self.setActionField(node, "append")
#baseBody.appendChild(node)
for node in notSepListField:
if self.getTypeField(node) == "seplist":
#if removeNodesDict.has_key(self.getNameField(node)):
#print removeNodesDict[self.getNameField(node)]
self.setActionField(node, "append")
xmlOldArea.appendChild(node)
else:
self.joinField(xmlOldArea, node)
def insertBeforeSepAreas(self, xmlArea):
"""Добавляет разделитель областей перед каждой областью"""
if not self.sepAreas:
return False
areaNodes = xpath.Evaluate('descendant::area',xmlArea)
for areaNode in areaNodes:
prevNode = areaNode.previousSibling
if prevNode:
parentNode = areaNode.parentNode
parentNode.insertBefore(self.sepAreas.cloneNode(True),
areaNode)
return True
def getAreaFields(self, nameArea, xmlArea):
"""По имени области выводит названия и значения всех переменных
поиск ведется только в 1-х потомках области xmlArea
на выход словарь переменных {имя:значение}
"""
namesAreaComare = xpath.Evaluate(\
"child::area/child::caption[child::name='%s']" %(nameArea),
xmlArea)
if not namesAreaComare:
return False
fields = xpath.Evaluate("child::field/child::name",
namesAreaComare[0].parentNode)
dictVar = {}
for fieldName in fields:
nodeField = fieldName.parentNode
fieldValue = xpath.Evaluate("child::value",nodeField)
name = fieldName.firstChild.nodeValue
value = ""
if fieldValue:
value = fieldValue[0].firstChild.nodeValue
dictVar[name] = value
return dictVar
def getAreaFieldValues(self, nameArea, nameField, xmlArea):
"""По имени области и имени переменной выводит значениe переменной
поиск ведется только в 1-х потомках области xmlArea
"""
namesAreaComare = xpath.Evaluate(\
"child::area/child::caption[child::name='%s']" %(nameArea),
xmlArea)
fieldsVal = False
for areaComp in namesAreaComare:
fieldsVal = xpath.Evaluate(\
"child::field[child::name='%s'] "\
%(nameField), areaComp.parentNode)
if fieldsVal:
break
if not fieldsVal:
return False
fieldValue = xpath.Evaluate("child::value",
fieldsVal[0])
return fieldValue[0].firstChild.nodeValue
def joinArea(self, baseNode, xmlNewArea):
"""Объединяет область c областью Body (xmlNewArea c baseNode)"""
def appendArea(baseNode, xmlNewArea):
fieldsRemove = xpath.Evaluate(\
"descendant::field[child::action='drop']", xmlNewArea)
for rmNode in fieldsRemove:
parentNode = rmNode.parentNode
parentNode.removeChild(rmNode)
captionAreasRemove = xpath.Evaluate(\
"descendant::area/child::caption[child::action='drop']",
xmlNewArea)
for rmNodeCapt in captionAreasRemove:
rmNode = rmNodeCapt.parentNode
parentNode = rmNode.parentNode
parentNode.removeChild(rmNode)
self.setActionArea(xmlNewArea, "append")
# Добавляем разделитель областей во вложенные области
areaNodes = xpath.Evaluate('descendant::area',xmlNewArea)
for areaNode in areaNodes:
self.setActionArea(areaNode,"append")
parentNode = areaNode.parentNode
parentNode.insertBefore(self.sepAreas.cloneNode(True),
areaNode)
baseNode.appendChild(xmlNewArea)
# Добавляем разделитель областей
baseNode.insertBefore(self.sepAreas.cloneNode(True), xmlNewArea)
nodesNames = xpath.Evaluate('child::area/caption/name',baseNode)
nodesNewArea = xpath.Evaluate('child::caption/name',xmlNewArea)
if not nodesNames:
# Добавляем область
if nodesNewArea:
newAreaAction = self.getActionArea(xmlNewArea)
if not (newAreaAction == "drop" or newAreaAction == "replace"):
appendArea(baseNode, xmlNewArea)
return True
if not nodesNames or not nodesNewArea:
return False
nameArea = ""
if nodesNewArea[0].firstChild:
nameArea = nodesNewArea[0].firstChild.nodeValue.strip()
flagFindArea = False
baseNodes = []
for oName in nodesNames:
newAreaAction = self.getActionArea(xmlNewArea)
oArea = oName.parentNode.parentNode
oNameTxt = ""
if oName.firstChild:
oNameTxt = oName.firstChild.nodeValue
if nameArea == oNameTxt:
flagFindArea = True
# При использовании удаления
if newAreaAction == "drop":
prevNode = oName.parentNode.parentNode.previousSibling
removePrevNodes = []
while (prevNode) and self.getTypeField(prevNode) == "br":
removePrevNodes.append(prevNode)
prevNode = prevNode.previousSibling
for removeNode in removePrevNodes:
baseNode.removeChild(removeNode)
baseNode.removeChild(oName.parentNode.parentNode)
continue
elif newAreaAction == "replace":
oldAreaNode = oName.parentNode.parentNode
newAreaCaption = xpath.Evaluate('child::caption',
xmlNewArea)[0]
oldAreaCaption = xpath.Evaluate('child::caption',
oldAreaNode)[0]
if newAreaCaption and oldAreaCaption:
xmlNewArea.replaceChild(oldAreaCaption,newAreaCaption)
self.setActionArea(xmlNewArea,"replace")
baseNode.replaceChild(xmlNewArea,
oldAreaNode)
continue
baseNodes.append(oName.parentNode.parentNode)
newFields = xpath.Evaluate('child::field',xmlNewArea)
joinNewFields = xpath.Evaluate(\
"child::field[child::action='join']"
,xmlNewArea)
self.addNewFielsOldArea(newFields, joinNewFields, oArea)
if not flagFindArea:
# Добавляем область
if not (newAreaAction == "drop" or\
newAreaAction == "replace"):
appendArea(baseNode, xmlNewArea)
else:
tmpXmlNewAreas = xpath.Evaluate('child::area',xmlNewArea)
for na in tmpXmlNewAreas:
for bn in baseNodes:
self.joinArea(bn, na)
return True
def joinDoc(self, xmlNewDoc):
"""Объединяет два документа"""
newRootNode = xmlNewDoc.documentElement
newBodyNode = xpath.Evaluate('child::body',newRootNode)[0]
newImportBodyNode = self.doc.importNode(newBodyNode, True)
# Перед объединение области с документом
# удаляем комментарии
self.removeComment(newImportBodyNode)
self.joinBody(self.body, newImportBodyNode)
# расставляем BR
self.insertBRtoBody(self.body)
def getQuoteField(self, xmlField):
"""Выдает текст из поля"""
xmlQuotes = xpath.Evaluate('child::quote',xmlField)
br = ""
if xmlField.hasAttribute("type") and\
xmlField.getAttribute("type") == "br":
br = "\n"
if xmlQuotes:
field = xmlQuotes[0]
if field.firstChild:
return field.firstChild.nodeValue + br
return "" + br
def getFieldsArea(self, xmlArea):
"""Выдает потомков XML области"""
xmlFields = []
childNodes = xmlArea.childNodes
for node in childNodes:
if node.nodeType == node.ELEMENT_NODE:
if node.tagName == "area" or node.tagName == "field":
xmlFields.append(node)
return xmlFields
def getTypeField(self, xmlField):
"""Выдает тип поля"""
if xmlField.hasAttribute("type"):
return xmlField.getAttribute("type")
else:
return False
def getNameField(self, xmlField):
"""Выдает имя поля"""
xmlNameFields = xpath.Evaluate('child::name', xmlField)
if xmlNameFields and xmlNameFields[0].firstChild:
return xmlNameFields[0].firstChild.nodeValue
else:
return False
def getNameArea(self, xmlArea):
"""Выдает имя области"""
xmlNameAreas = xpath.Evaluate('child::caption/name', xmlArea)
if xmlNameAreas and xmlNameAreas[0].firstChild:
return xmlNameAreas[0].firstChild.nodeValue
else:
return False
def xmlToText(self, xmlAreas, text):
"""Преобразует список XML областей в текст"""
def getQuotesArea(xmlArea):
quotes = []
xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea)
for node in xmlQuotes:
if node.firstChild:
quotes.append(node.firstChild.nodeValue)
if len(quotes) == 0:
quotes.append("")
quotes.append("")
elif len(quotes) == 1:
quotes.append("")
return quotes
for i in xmlAreas:
if i.tagName == "area":
quotesI = getQuotesArea(i)
startAreaI = quotesI[0]
endAreaI = quotesI[1]
text.append(startAreaI)
xmlFieldsI = self.getFieldsArea(i)
for f in xmlFieldsI:
if f.tagName == "area":
quotesF = getQuotesArea(f)
startAreaF = quotesF[0]
endAreaF = quotesF[1]
text.append(startAreaF)
xmlFieldsF = self.getFieldsArea(f)
self.xmlToText(xmlFieldsF, text)
text.append(endAreaF)
else:
fieldF = self.getQuoteField(f)
text.append(fieldF)
text.append(endAreaI)
else:
fieldI = self.getQuoteField(i)
text.append(fieldI)
def getActionField(self, xmlField):
"""Выдает свойство action XML поля"""
xmlActions = xpath.Evaluate('child::action',xmlField)
if xmlActions and xmlActions[0].firstChild:
return xmlActions[0].firstChild.nodeValue
else:
return False
def getFieldValues(self, xmlField):
"""Выдает значения XML поля в виде массива"""
vals = []
xmlValues = xpath.Evaluate('child::value',xmlField)
if xmlValues:
for node in xmlValues:
if node.firstChild:
vals.append(node.firstChild.nodeValue)
return vals
def getActionArea(self, xmlArea):
"""Выдает свойство action XML области"""
xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
if xmlActions and xmlActions[0].firstChild:
return xmlActions[0].firstChild.nodeValue
else:
return False
def delActionNodeArea(self, xmlArea):
"""Удаляет свойство action XML области"""
xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
if xmlActions and xmlActions[0].firstChild:
parentNode = xmlActions[0].parentNode
parentNode.removeChild(xmlActions[0])
return True
else:
return False
def delActionNodeField(self, xmlField):
"""Удаляет свойство action XML поля"""
xmlActions = xpath.Evaluate('child::action',xmlField)
if xmlActions and xmlActions[0].firstChild:
parentNode = xmlActions[0].parentNode
parentNode.removeChild(xmlActions[0])
return True
else:
return False
# Создает распределенные списки
def postParserListSeplist(self, xmlArea):
"""Создает распределенные списки из элементов области"""
# Потомки
childNodes = self.getFieldsArea(xmlArea)
# содержит списки нод полей с одинаковыми именами в одной области
fieldsSeplist = {}
for node in childNodes:
if node.tagName == "area":
self.postParserListSeplist(node)
else:
fieldName = False
xmlFieldNameNodes = xpath.Evaluate('child::name',node)
if xmlFieldNameNodes and xmlFieldNameNodes[0].firstChild:
fieldName = xmlFieldNameNodes[0].firstChild.nodeValue
if fieldName:
if fieldsSeplist.has_key(fieldName):
fieldsSeplist[fieldName].append(node)
else:
fieldsSeplist[fieldName] = []
fieldsSeplist[fieldName].append(node)
for listNodes in fieldsSeplist.values():
if len(listNodes) > 1:
for node in listNodes:
node.setAttribute("type", "seplist")
def insertBRtoBody(self, xmlArea):
"""Добавляет необходимые переводы строк
"""
# Потомки
childNodes = self.getFieldsArea(xmlArea)
# нода BR
fieldXMLBr = self.createField("br",[],"",[],False, False)
# разделитель поля
fieldSplit = False
# Предыдущая нода
lastNode = False
# Cледующая нода
nextNode = False
lenChildNodes = len(childNodes)
for i in range(lenChildNodes):
node = childNodes[i]
lastTmpNode = node
# Нода area
if node.tagName == "area":
if self.getActionArea(node) == "append" or\
self.getActionArea(node) == "join":
self.delActionNodeArea(node)
if lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "br" or\
lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "comment":
indNext = i + 1
if indNext == lenChildNodes:
xmlArea.appendChild(fieldXMLBr.cloneNode(True))
else:
nextNode = childNodes[indNext]
lastTmpNode = xmlArea.insertBefore(\
fieldXMLBr.cloneNode(True),
nextNode)
else:
xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
node)
self.insertBRtoBody(node)
# Нода field
else:
if self.getActionField(node) == "append" or\
self.getActionField(node) == "join":
self.delActionNodeField(node)
if lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "br" or\
lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "comment":
indNext = i + 1
if indNext == lenChildNodes:
xmlArea.appendChild(fieldXMLBr.cloneNode(True))
else:
nextNode = childNodes[indNext]
lastTmpNode = xmlArea.insertBefore(\
fieldXMLBr.cloneNode(True),
nextNode)
else:
xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
node)
lastNode = lastTmpNode
def postParserList(self):
"""Находит подходящие XML области и делаем из них поля-массивы"""
xmlAreas = xpath.Evaluate('descendant::area', self.body)
for xmlArea in xmlAreas:
flagListXml = True
fieldValues = []
xmlFields = xpath.Evaluate('child::field',xmlArea)
if not xmlFields:
flagListXml = False
lenXmlFields = len(xmlFields)
lenBrArea = 0
for xmlField in xmlFields:
xmlNames = xpath.Evaluate('child::name',xmlField)
xmlVals = xpath.Evaluate('child::value',xmlField)
if xmlField.hasAttribute("type") and\
xmlField.getAttribute("type") == "br":
lenBrArea += 1
continue
if not xmlNames and not xmlVals:
flagListXml = False
break
if xmlNames and xmlNames[0].firstChild and\
xmlNames[0].firstChild.nodeValue:
flagListXml = False
break
if not (xmlVals and xmlVals[0].firstChild and\
xmlVals[0].firstChild.nodeValue):
flagListXml = False
break
else:
fieldValues.append(xmlVals[0].firstChild.nodeValue)
if lenXmlFields == lenBrArea:
flagListXml = False
if flagListXml:
nameNode = xpath.Evaluate('child::caption/name',xmlArea)[0]
fieldName = ""
if nameNode.firstChild:
fieldName = nameNode.firstChild.nodeValue
listArea = []
self.xmlToText([xmlArea],listArea)
fieldQuote = "".join(listArea)
fieldXMLBr = False
if fieldQuote and fieldQuote[-1] == "\n":
fieldQuote = fieldQuote[:-1]
fieldXMLBr = self.createField("br",[],"",[],False, False)
fieldXML = self.createField("list",
[fieldQuote],
fieldName, fieldValues,
False, False)
areaAction = self.getActionArea(xmlArea)
if areaAction:
self.setActionField(fieldXML, areaAction)
parentNode = xmlArea.parentNode
parentNode.insertBefore(fieldXML,xmlArea)
if fieldXMLBr:
parentNode.insertBefore(fieldXMLBr,xmlArea)
parentNode.removeChild(xmlArea)
class blocText:
"""Разбиваем текст на блоки"""
def splitTxtToBloc(self, text ,openTxtBloc,closeTxtBloc,
commentTxtBloc, sepField):
"""Делит текст на блоки (без заголовков)
openTxtBloc - регулярное выражение для начала блока
closeTxtBloc - регулярное выражение для конца блока
commentTxtBloc - регулярное выражение - комментарий
возвращает блоки текста
"""
blocs = []
level = 0
# Нахождение нескольких блоков в строке
# разделители линий, разделителями могут быть ("","\n")
sepsLines = []
# линии
txtLines = []
# Исходные строки
txtLinesSrc = text.splitlines()
for line in txtLinesSrc:
lineBR = ""
lineTmpA = line
closeBl = False
txtLinesTmp = []
commentSpl = commentTxtBloc.split(line)
flagCommentLine = False
if commentSpl[0].strip():
closeBl = True
if len(commentSpl) > 1:
commentBl = commentTxtBloc.search(line)
textLine =commentSpl[0]
commentLine = line[commentBl.start(0):]
lineTmpA = textLine
flagCommentLine = True
while (closeBl):
closeBl = sepField.search(lineTmpA)
if closeBl:
lineTmpB = lineTmpA[closeBl.end(0):]
txtLinesTmp.append(lineTmpA[:closeBl.end(0)])
lineTmpA = lineTmpB
if lineTmpA.strip():
txtLinesTmp.append(lineTmpA)
# Если есть значение и комментарий в строке
if flagCommentLine:
for l in txtLinesTmp:
txtLines.append(l)
sepsLines.append("")
if not txtLinesTmp:
txtLines.append(textLine)
sepsLines.append("")
txtLines.append(commentLine)
sepsLines.append("\n")
# Если есть несколько блоков в строке
elif len(txtLinesTmp)>1 and txtLinesTmp[1].strip():
lenTmpLines = len(txtLinesTmp)
for l in range(lenTmpLines):
txtLines.append(txtLinesTmp[l])
if l == lenTmpLines-1:
sepsLines.append("\n")
else:
sepsLines.append("")
# Cтрока не преобразована
else:
txtLines.append(line)
sepsLines.append("\n")
# разбивание на блоки
z = 0
bl = ""
for i in txtLines:
if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(i):
level += len(openTxtBloc.split(i)) - 1
if commentTxtBloc.split(i)[0].strip() and closeTxtBloc.search(i):
level -= len(closeTxtBloc.split(i)) - 1
bl += i + sepsLines[z]
if level == 0:
if bl:
blocs.append(bl)
bl = ""
z += 1
# cоздание блоков с элементами не входящими в блоки
realBlocs = []
z = 0
bl = ""
for i in blocs:
txtLines = i.splitlines()
if len(txtLines) > 0:
line = txtLines[0]
else:
line = i
if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(line):
if bl:
realBlocs.append(bl)
bl = ""
realBlocs.append(i)
else:
bl += i
z += 1
if bl:
realBlocs.append(bl)
bl = ""
if level == 0:
if text and text[-1] != "\n":
tmpBlocs = realBlocs.pop()
tmpBlocs = tmpBlocs[:-1]
realBlocs.append(tmpBlocs)
return realBlocs
else:
return []
def findArea(self, text, reTextHeader, reTextArea, numGroupArea=0):
""" Делит текст на области (с заголовками)
reTextHeader - регулярное выражение для заголовка области
reTextArea - регулярное выражение для всей области
numGroupArea - номер групы результата поиска по регулярному выражению
по всей области
возвращает два списка: первый - заголовки, второй - тела областей без
заголоков
"""
# Заголовки областей
headersArea = []
# Тексты областей без заголовков
textBodyArea = []
r = reTextArea.search(text)
if not r:
headersArea.append("")
textBodyArea.append(text)
return (headersArea, textBodyArea)
txtWr = text
while r:
textArea = r.group(numGroupArea)
txtSpl = txtWr.split(textArea)
area = txtSpl[0]
txtWr = txtSpl[1]
if area:
headersArea.append("")
textBodyArea.append(area)
res = reTextHeader.search(textArea)
header = textArea[:res.end()]
body = textArea[res.end():]
headersArea.append(header)
textBodyArea.append(body)
if txtWr:
r = reTextArea.search(txtWr)
else:
r = False
if txtWr:
headersArea.append("")
textBodyArea.append(txtWr)
return (headersArea, textBodyArea)
def findBloc(self, text, captionTxtBloc, bodyTxtBloc):
""" Делит текст на блоки (с заголовками)
captionTxtBloc - регулярное выражение для заголовка блока
bodyTxtBloc - регулярное выражение для тела блока
возвращает два списка: первый - заголовки, второй - тела блоков
"""
# Заголовки блоков
headersTxt = []
# Тексты блоков
blocsTxt = []
r = captionTxtBloc.search(text)
if r:
headersTxt.append(r.group(0))
txtSpl = text.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)<len(blocsTxt):
headersTxt.insert(0,"")
if len(headersTxt)!=len(blocsTxt):
return False
return (headersTxt, blocsTxt)
else:
return False
class _file(_error):
"""Класс для работы с файлами
"""
def __init__(self):
# Имя файла старого профиля
self.nameFileOld = ""
# Старый профиль
self.oldProfile = ""
# Имя файла нового профиля
self.nameFileNew = ""
# Новый профиль
self.newProfile = ""
# Дескриптор файла нового профиля
self.FN = False
# Дескриптор файла старого профиля
self.FO = False
# Владелец и режим доступа файла профиля
self._mode = False
self._uid = False
self._gid = False
self.openNewFile = self.__openNewFile
self.absFileName = self.__absFileName
self.closeNewFile =self.__closeNewFile
def getFileType(self, profile="New"):
"""выдать тип файла (text, bin)
"""
if self.nameFileNew:
nameFile = self.nameFileNew
if profile=="Old" and self.nameFileOld:
nameFile = self.nameFileOld
fout, fin = popen2.popen2("file %s"%(nameFile))
fin.close()
textLine = fout.readline()
fout.readlines()
fout.close()
if textLine:
listTextLine = textLine.split(":")
if len(listTextLine) == 2:
if "text" in listTextLine[1]:
return "text"
else:
return "bin"
return ""
def createDir(self, baseProfDir, profDir, baseDirMv):
"""Создает директорию
результат вычитания из profDir baseProfDir
плюс baseDirMv
"""
if baseDirMv and not os.access(baseDirMv, os.F_OK):
os.makedirs(baseDirMv)
baseDir = baseProfDir;
if baseProfDir[-1] == "/":
baseDir = baseProfDir[:-1]
dirMv = profDir.split(baseDir)[1]
listDirMv = dirMv.split("/")
lenListDirMv = len(listDirMv) - 2
if lenListDirMv >= 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)
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<rTerm>[a-zA-Z0-9\-_]+)\
(?P<lTerm>[\>\<\=\!\&\|]+\
[a-zA-Z0-9\>\<\=\!\|\&\-_\.]+)#\
\n*(?P<body>.+?)\n*#(?P=rTerm)#(?P<end>[ ,\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)
for dirObj in dirObjs:
# сортируем файлы по названию
if dirObj.files:
dirObj.files.sort()
for dirProfile in dirObj.dirs:
self.createDir(dirObj.baseDir, dirProfile, self._baseDir)
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))
else:
if self.getError():
print self.getError()
return False
self.closeFiles()
return True
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
# Если есть указатель на файл профиля (link)
if objHeadNew.params.has_key("link"):
#prevOldFile = oldFile
profileFile = objHeadNew.params['link']
FO = self.openNewFile(profileFile)
buff = FO.read()
FO.close()
if os.path.exists(oldFile):
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()
# Если символическая ссылка
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 named(objShare):
"""Класс для обработки конфигурационного файла типа named
"""
_comment = "//"
configName = "named"
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
"!" - <action>drop</action>
"-" - <action>replace</action>
"""
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, namedObj):
"""Объединяем конфигурации"""
if isinstance(namedObj, named):
self.docObj.joinDoc(namedObj.doc)
class apache(named):
"""Класс для обработки конфигурационного файла типа 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(named):
"""Класс для обработки конфигурационного файла типа 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):
named.__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)