|
|
|
|
#-*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
#Copyright 2008 Calculate Pack, http://www.calculate-linux.org
|
|
|
|
|
#
|
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
|
#
|
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
#
|
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
|
|
import sys
|
|
|
|
|
import os
|
|
|
|
|
import cl_base
|
|
|
|
|
import stat
|
|
|
|
|
import re
|
|
|
|
|
import xml.dom.minidom
|
|
|
|
|
from xml import xpath
|
|
|
|
|
import subprocess
|
|
|
|
|
import types
|
|
|
|
|
import copy
|
|
|
|
|
import random
|
|
|
|
|
import string
|
|
|
|
|
import time
|
|
|
|
|
|
|
|
|
|
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, function=False):
|
|
|
|
|
"""Вычисление логических выражений для условий
|
|
|
|
|
|
|
|
|
|
Для корректной работы в классе который наследует этот класс
|
|
|
|
|
должен быть объявлен аттрибут self.objVar
|
|
|
|
|
(объект для работы с переменными)
|
|
|
|
|
function - функция для для обработки функций в заголовке блока
|
|
|
|
|
"""
|
|
|
|
|
trm = {"&":" and ","||":" or "}
|
|
|
|
|
rule = ["==", "!=", ">=", "<=", ">", "<"]
|
|
|
|
|
listEqual = []
|
|
|
|
|
for k in trm.keys():
|
|
|
|
|
if k in term:
|
|
|
|
|
term = term.replace(k,trm[k])
|
|
|
|
|
trs = term.split(" ")
|
|
|
|
|
for t in trs:
|
|
|
|
|
flagRule = False
|
|
|
|
|
for sepF in rule:
|
|
|
|
|
if sepF in t:
|
|
|
|
|
flagRule = True
|
|
|
|
|
vals = t.split(sepF)
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if not flagRule:
|
|
|
|
|
flagLog = False
|
|
|
|
|
for k in trm.values():
|
|
|
|
|
if k.strip() == t:
|
|
|
|
|
flagLog = True
|
|
|
|
|
break
|
|
|
|
|
if not flagLog:
|
|
|
|
|
self.setError("'%s'"%term + " " + _("incorrect"))
|
|
|
|
|
self.setError (textError)
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
listEqual.append(k)
|
|
|
|
|
else:
|
|
|
|
|
#проверка на допустимость названия переменной
|
|
|
|
|
reDenyName = re.compile("[^a-zA-Z0-9\_\-]")
|
|
|
|
|
flagFunction = False
|
|
|
|
|
if reDenyName.search(vals[0]):
|
|
|
|
|
#проверка на допустимость функции
|
|
|
|
|
flagError = True
|
|
|
|
|
if function:
|
|
|
|
|
reFunction = re.compile(\
|
|
|
|
|
"([a-zA-Z0-9\_\-]+)\([a-zA-Z0-9_\-\+\,\*\/\.]+\)")
|
|
|
|
|
searchFunct = reFunction.search(vals[0])
|
|
|
|
|
if searchFunct:
|
|
|
|
|
flagError = False
|
|
|
|
|
flagFunction = True
|
|
|
|
|
if flagError:
|
|
|
|
|
self.setError("'%s'"%term + " " + _("incorrect"))
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
#проверка на допустимость значения
|
|
|
|
|
reDenyValue = re.compile("[^0-9a-zA-Z_\.-]")
|
|
|
|
|
if reDenyValue.search(vals[1]):
|
|
|
|
|
self.setError("'%s'"%term + " " + _("incorrect"))
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
flagIntTypeVar = None
|
|
|
|
|
if flagFunction:
|
|
|
|
|
valVars = function("#-%s-#"%vals[0])
|
|
|
|
|
if valVars == "":
|
|
|
|
|
flagFunction = False
|
|
|
|
|
if valVars == False:
|
|
|
|
|
self.setError("'%s'"%term + " " + _("incorrect"))
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
if "load" == searchFunct.group(1):
|
|
|
|
|
if re.search("\(\s*num\s*,",vals[0]):
|
|
|
|
|
if valVars:
|
|
|
|
|
try:
|
|
|
|
|
valVars = int(valVars)
|
|
|
|
|
except:
|
|
|
|
|
self.setError("'%s'"%term + " " + \
|
|
|
|
|
_("incorrect"))
|
|
|
|
|
self.setError (textError)
|
|
|
|
|
return False
|
|
|
|
|
flagIntTypeVar = True
|
|
|
|
|
else:
|
|
|
|
|
flagIntTypeVar = False
|
|
|
|
|
else:
|
|
|
|
|
try:
|
|
|
|
|
valVars = self.objVar.Get(vals[0])
|
|
|
|
|
except self.objVar.DataVarsError, e:
|
|
|
|
|
print textError
|
|
|
|
|
print e
|
|
|
|
|
cl_base.exit(1)
|
|
|
|
|
# Cравниваем номера версий
|
|
|
|
|
if "_ver" in vals[0] or \
|
|
|
|
|
(flagFunction and "pkg" == searchFunct.group(1)) or\
|
|
|
|
|
(flagFunction and "load" == searchFunct.group(1) and\
|
|
|
|
|
re.search("\(\s*ver\s*,",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 flagIntTypeVar == None:
|
|
|
|
|
flagIntTypeVar = True
|
|
|
|
|
try:
|
|
|
|
|
valVars = int(valVars)
|
|
|
|
|
except:
|
|
|
|
|
flagIntTypeVar = False
|
|
|
|
|
if flagIntTypeVar:
|
|
|
|
|
if not vals[1].strip():
|
|
|
|
|
vals[1] = 0
|
|
|
|
|
try:
|
|
|
|
|
valFile = int(vals[1])
|
|
|
|
|
except:
|
|
|
|
|
self.setError("'%s'"%term + " " + _("incorrect"))
|
|
|
|
|
self.setError (textError)
|
|
|
|
|
return False
|
|
|
|
|
valVar = valVars
|
|
|
|
|
exec("res=(%d%s%d)"%(valVar,sepF,valFile))
|
|
|
|
|
if res:
|
|
|
|
|
listEqual.append("1")
|
|
|
|
|
else:
|
|
|
|
|
listEqual.append("0")
|
|
|
|
|
else:
|
|
|
|
|
if sepF == "!=" or sepF == "==":
|
|
|
|
|
if not vals[1].strip():
|
|
|
|
|
vals[1] = ""
|
|
|
|
|
valFile = vals[1]
|
|
|
|
|
valVar = valVars
|
|
|
|
|
exec("res=("+'"""'+valVar+'"""'+sepF+"'"+valFile+\
|
|
|
|
|
"'"+")")
|
|
|
|
|
if res:
|
|
|
|
|
listEqual.append("1")
|
|
|
|
|
else:
|
|
|
|
|
listEqual.append("0")
|
|
|
|
|
else:
|
|
|
|
|
if valVars == "":
|
|
|
|
|
listEqual.append("0")
|
|
|
|
|
else:
|
|
|
|
|
self.setError("'%s'"%term + " "\
|
|
|
|
|
+ _("incorrect"))
|
|
|
|
|
self.setError (textError)
|
|
|
|
|
return False
|
|
|
|
|
exec("res=(%s)"%("".join(listEqual)))
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
|
class fileHeader(_terms):
|
|
|
|
|
"""Обработка заголовков профилей и конфигурационных файлов
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
# Допустимые параметры заголовка
|
|
|
|
|
allowParam = ["format", "format_conf", "comment", "append", "force",
|
|
|
|
|
"link", "mirror", "symbolic", "chmod", "chown", "name"]
|
|
|
|
|
# Корректность заголовка
|
|
|
|
|
headerCorrect = True
|
|
|
|
|
|
|
|
|
|
# Тип профиля
|
|
|
|
|
fileType = ""
|
|
|
|
|
# Тип вставки профиля
|
|
|
|
|
typeAppend = ""
|
|
|
|
|
# Возможные типы вставки профилей
|
|
|
|
|
_fileAppend = "join", "before", "after", "replace", "remove"
|
|
|
|
|
# Интерпретатор (#!/bin/bash) (#!/usr/bin/python)
|
|
|
|
|
execStr = ""
|
|
|
|
|
# Символ комментария
|
|
|
|
|
comment = False
|
|
|
|
|
# Выражение для поиска строки интерпретатора
|
|
|
|
|
reExecStr = re.compile("^#!.+\s*",re.I)
|
|
|
|
|
# условные операторы
|
|
|
|
|
terms = ('>', '<', '==', '!=', '>=', '<=')
|
|
|
|
|
# параметры без значения
|
|
|
|
|
listParNotVal = ("symbolic", "force", "mirror")
|
|
|
|
|
# Результат вычисления условия в заголовке
|
|
|
|
|
headerTerm = True
|
|
|
|
|
# Сообщение о ошибке
|
|
|
|
|
errorMessage = ""
|
|
|
|
|
|
|
|
|
|
def __init__(self, text, comment=False, fileType=False, objVar=False,
|
|
|
|
|
function=False):
|
|
|
|
|
self.body = text
|
|
|
|
|
# Объект с переменными
|
|
|
|
|
self.objVar=objVar
|
|
|
|
|
# Параметры описанные в заголовке файла профиля
|
|
|
|
|
self.params = {}
|
|
|
|
|
# некорректные параметры
|
|
|
|
|
incorrectParams = set([])
|
|
|
|
|
# Удаление Заголовка Calculate
|
|
|
|
|
if comment:
|
|
|
|
|
# В случае текста XML
|
|
|
|
|
if type(comment) == types.TupleType and len(comment) == 2:
|
|
|
|
|
_titleList = (_("Modified"), _("File of a profile"))
|
|
|
|
|
reCalcHeader =\
|
|
|
|
|
re.compile(u"\s*%s\s+%s.+Calculate.+\s+%s.+\s+%s\s?"%(\
|
|
|
|
|
comment[0],
|
|
|
|
|
_titleList[0].decode("UTF-8"),
|
|
|
|
|
_titleList[1].decode("UTF-8"),
|
|
|
|
|
comment[1],
|
|
|
|
|
),
|
|
|
|
|
re.M|re.I|re.U)
|
|
|
|
|
textUnicode = text.decode("UTF-8")
|
|
|
|
|
reS = reCalcHeader.search(textUnicode)
|
|
|
|
|
if reS:
|
|
|
|
|
textBody = textUnicode[:reS.start()]+textUnicode[reS.end():]
|
|
|
|
|
if textBody:
|
|
|
|
|
self.body = textBody.encode("UTF-8")
|
|
|
|
|
else:
|
|
|
|
|
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[reP.end():reLs.end()]
|
|
|
|
|
paramLine = paramLine.replace("\\"," ")
|
|
|
|
|
else:
|
|
|
|
|
reLn = re.compile("\n")
|
|
|
|
|
reL = reLn.search(text)
|
|
|
|
|
paramLine = textLine[reP.end():]
|
|
|
|
|
if reL:
|
|
|
|
|
self.body = text[reL.end():]
|
|
|
|
|
else:
|
|
|
|
|
self.body = ""
|
|
|
|
|
paramList = re.split("\s+",paramLine)
|
|
|
|
|
if paramList:
|
|
|
|
|
for i in paramList:
|
|
|
|
|
foundTerm = False
|
|
|
|
|
for term in self.terms:
|
|
|
|
|
if term in i:
|
|
|
|
|
foundTerm = True
|
|
|
|
|
if function:
|
|
|
|
|
rezTerm = self._equalTerm(i,\
|
|
|
|
|
_("header profile not valid: ") + \
|
|
|
|
|
i,function)
|
|
|
|
|
else:
|
|
|
|
|
rezTerm = self._equalTerm(i,\
|
|
|
|
|
_("header profile not valid: ") + \
|
|
|
|
|
i)
|
|
|
|
|
if not rezTerm:
|
|
|
|
|
self.headerTerm = False
|
|
|
|
|
break
|
|
|
|
|
if not foundTerm:
|
|
|
|
|
par = i.split("=")
|
|
|
|
|
if len(par) == 1:
|
|
|
|
|
if i in self.listParNotVal:
|
|
|
|
|
self.params[i] = "True"
|
|
|
|
|
else:
|
|
|
|
|
if i.strip():
|
|
|
|
|
incorrectParams = set([i])
|
|
|
|
|
elif len(par) == 2:
|
|
|
|
|
self.params[par[0]] = par[1]
|
|
|
|
|
|
|
|
|
|
self.comment = self._getComment()
|
|
|
|
|
self.fileType = self._getType()
|
|
|
|
|
self.typeAppend = self._getAppend()
|
|
|
|
|
reExecRes = self.reExecStr.search(self.body)
|
|
|
|
|
if reExecRes:
|
|
|
|
|
self.execStr = self.body[reExecRes.start():reExecRes.end()]
|
|
|
|
|
self.body = self.body[reExecRes.end():]
|
|
|
|
|
if not incorrectParams:
|
|
|
|
|
incorrectParams = set(self.params.keys()) - set(self.allowParam)
|
|
|
|
|
if incorrectParams:
|
|
|
|
|
self.headerTerm = False
|
|
|
|
|
self.headerCorrect = False
|
|
|
|
|
self.errorMessage = _("incorrect header parameters - '%s'")\
|
|
|
|
|
% " ".join(list(incorrectParams))
|
|
|
|
|
|
|
|
|
|
def _getType(self):
|
|
|
|
|
"""Выдать тип файла"""
|
|
|
|
|
if self.params.has_key("format"):
|
|
|
|
|
return self.params["format"]
|
|
|
|
|
else:
|
|
|
|
|
return "raw"
|
|
|
|
|
|
|
|
|
|
def _getAppend(self):
|
|
|
|
|
"""Выдать тип добавления файла"""
|
|
|
|
|
if self.params.has_key("append") and self.params["append"] in\
|
|
|
|
|
self._fileAppend:
|
|
|
|
|
return self.params["append"]
|
|
|
|
|
else:
|
|
|
|
|
if self.fileType != "raw" and self.fileType != "bin" and\
|
|
|
|
|
self.fileType != "":
|
|
|
|
|
self.params["append"] = "join"
|
|
|
|
|
return "join"
|
|
|
|
|
self.params["append"] = "replace"
|
|
|
|
|
return "replace"
|
|
|
|
|
|
|
|
|
|
def _getComment(self):
|
|
|
|
|
"""Выдать символ комментария файла"""
|
|
|
|
|
if self.params.has_key("comment"):
|
|
|
|
|
return self.params["comment"]
|
|
|
|
|
else:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class dirHeader(_terms):
|
|
|
|
|
"""Обработка заголовков профилей директорий
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
# Допустимые параметры заголовка
|
|
|
|
|
allowParam = ["append", "chmod", "chown", "name"]
|
|
|
|
|
# Корректность заголовка
|
|
|
|
|
headerCorrect = True
|
|
|
|
|
|
|
|
|
|
# Тип вставки профиля
|
|
|
|
|
typeAppend = ""
|
|
|
|
|
# Возможные типы вставки профилей
|
|
|
|
|
_fileAppend = "join", "remove"
|
|
|
|
|
# условные операторы
|
|
|
|
|
terms = ('>', '<', '==', '!=', '>=', '<=')
|
|
|
|
|
# параметры без значения
|
|
|
|
|
listParNotVal = ("symbolic", "force")
|
|
|
|
|
# Результат вычисления условия в заголовке
|
|
|
|
|
headerTerm = True
|
|
|
|
|
# Сообщение о ошибке
|
|
|
|
|
errorMessage = ""
|
|
|
|
|
|
|
|
|
|
def __init__(self, text, objVar=False, function=False):
|
|
|
|
|
self.body = text
|
|
|
|
|
# Объект с переменными
|
|
|
|
|
self.objVar=objVar
|
|
|
|
|
# Параметры описанные в заголовке файла профиля
|
|
|
|
|
self.params = {}
|
|
|
|
|
# некорректные параметры
|
|
|
|
|
incorrectParams = set([])
|
|
|
|
|
|
|
|
|
|
textLines = text.splitlines()
|
|
|
|
|
flagErrorBody = False
|
|
|
|
|
if textLines:
|
|
|
|
|
textLine = textLines[0]
|
|
|
|
|
rePar = re.compile("\s*#\s*calculate\s+",re.I)
|
|
|
|
|
reP = rePar.search(textLine)
|
|
|
|
|
if reP:
|
|
|
|
|
reL = False
|
|
|
|
|
reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
|
|
|
|
|
reLs = reLns.search(text)
|
|
|
|
|
if reLs:
|
|
|
|
|
reL = reLs
|
|
|
|
|
paramLine = text[reP.end():reLs.end()]
|
|
|
|
|
paramLine = paramLine.replace("\\"," ")
|
|
|
|
|
else:
|
|
|
|
|
reLn = re.compile("\n")
|
|
|
|
|
reL = reLn.search(text)
|
|
|
|
|
paramLine = textLine[reP.end():]
|
|
|
|
|
if reL:
|
|
|
|
|
self.body = text[reL.end():]
|
|
|
|
|
else:
|
|
|
|
|
self.body = ""
|
|
|
|
|
if self.body.strip():
|
|
|
|
|
self.headerTerm = False
|
|
|
|
|
self.headerCorrect = False
|
|
|
|
|
self.errorMessage = _("incorrect text in profile: '%s'")\
|
|
|
|
|
%self.body
|
|
|
|
|
flagErrorBody = True
|
|
|
|
|
if not flagErrorBody:
|
|
|
|
|
paramList = re.split("\s+",paramLine)
|
|
|
|
|
if paramList:
|
|
|
|
|
for i in paramList:
|
|
|
|
|
foundTerm = False
|
|
|
|
|
for term in self.terms:
|
|
|
|
|
if term in i:
|
|
|
|
|
foundTerm = True
|
|
|
|
|
if function:
|
|
|
|
|
rezTerm = self._equalTerm(i,\
|
|
|
|
|
_("header profile not valid: ") + \
|
|
|
|
|
i,function)
|
|
|
|
|
else:
|
|
|
|
|
rezTerm = self._equalTerm(i,\
|
|
|
|
|
_("header profile not valid: ") + \
|
|
|
|
|
i)
|
|
|
|
|
if not rezTerm:
|
|
|
|
|
self.headerTerm = False
|
|
|
|
|
break
|
|
|
|
|
if not foundTerm:
|
|
|
|
|
par = i.split("=")
|
|
|
|
|
if len(par) == 1:
|
|
|
|
|
if i in self.listParNotVal:
|
|
|
|
|
self.params[i] = "True"
|
|
|
|
|
else:
|
|
|
|
|
if i.strip():
|
|
|
|
|
incorrectParams = set([i])
|
|
|
|
|
elif len(par) == 2:
|
|
|
|
|
self.params[par[0]] = par[1]
|
|
|
|
|
self.typeAppend = self._getAppend()
|
|
|
|
|
if not flagErrorBody:
|
|
|
|
|
if not incorrectParams:
|
|
|
|
|
incorrectParams = set(self.params.keys()) - set(self.allowParam)
|
|
|
|
|
if incorrectParams:
|
|
|
|
|
self.headerTerm = False
|
|
|
|
|
self.headerCorrect = False
|
|
|
|
|
self.errorMessage = _("incorrect header parameters - '%s'")\
|
|
|
|
|
% " ".join(list(incorrectParams))
|
|
|
|
|
|
|
|
|
|
def _getAppend(self):
|
|
|
|
|
"""Выдать тип добавления директории"""
|
|
|
|
|
if self.params.has_key("append") and self.params["append"] in\
|
|
|
|
|
self._fileAppend:
|
|
|
|
|
return self.params["append"]
|
|
|
|
|
else:
|
|
|
|
|
return "join"
|
|
|
|
|
|
|
|
|
|
class objShare:
|
|
|
|
|
"""Общий клас для объектов, наследуем
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def createFieldTerm(self, name, value, quote, docObj):
|
|
|
|
|
"""Создание поля переменная - значение
|
|
|
|
|
|
|
|
|
|
при создании поля проверяется первый символ названия переменной
|
|
|
|
|
и добавляется тег action
|
|
|
|
|
"!" - <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
|
|
|
|
|
oldValues = self.getFieldValues(nodeFieldOld)
|
|
|
|
|
# Сравнение значений переменной профиля и файла
|
|
|
|
|
if set(newValues) != set(oldValues):
|
|
|
|
|
flagCompare = False
|
|
|
|
|
if self.getActionField(xmlNewField) == "drop":
|
|
|
|
|
return True
|
|
|
|
|
appSplLst = []
|
|
|
|
|
insSplLst = []
|
|
|
|
|
if typeNewField == "seplist":
|
|
|
|
|
if fieldsOldComp:
|
|
|
|
|
xmlOldField = fieldsOldComp[-1]
|
|
|
|
|
else:
|
|
|
|
|
xmlOldField = False
|
|
|
|
|
seplistNewXML = self.getSepListToField(xmlNewField)
|
|
|
|
|
if seplistNewXML:
|
|
|
|
|
for nodeSeplist in seplistNewXML:
|
|
|
|
|
if self.getActionField(nodeSeplist) != "drop":
|
|
|
|
|
if newFieldsAction == "join":
|
|
|
|
|
flagCompareSeplist = False
|
|
|
|
|
newValues = self.getFieldValues(nodeSeplist)
|
|
|
|
|
for nodeFieldOld in fieldsOldComp:
|
|
|
|
|
oldValues = self.getFieldValues(nodeFieldOld)
|
|
|
|
|
for newValue in newValues:
|
|
|
|
|
if newValue in oldValues:
|
|
|
|
|
flagCompareSeplist = True
|
|
|
|
|
break
|
|
|
|
|
if not flagCompareSeplist:
|
|
|
|
|
nextNode = xmlOldField.nextSibling
|
|
|
|
|
newInsNode = nodeSeplist.cloneNode(True)
|
|
|
|
|
self.setActionField(newInsNode,"append")
|
|
|
|
|
|
|
|
|
|
if nextNode:
|
|
|
|
|
appSplLst.append((newInsNode,
|
|
|
|
|
nextNode,
|
|
|
|
|
"insert"))
|
|
|
|
|
else:
|
|
|
|
|
appSplLst.append((newInsNode,
|
|
|
|
|
False,
|
|
|
|
|
"append"))
|
|
|
|
|
else:
|
|
|
|
|
newInsNode = nodeSeplist.cloneNode(True)
|
|
|
|
|
if self.getActionField(newInsNode) == "join":
|
|
|
|
|
self.setActionField(newInsNode,"append")
|
|
|
|
|
if xmlOldField:
|
|
|
|
|
insSplLst.append((newInsNode,
|
|
|
|
|
xmlOldField,
|
|
|
|
|
"insert"))
|
|
|
|
|
else:
|
|
|
|
|
insSplLst.append((newInsNode,
|
|
|
|
|
False,
|
|
|
|
|
"append"))
|
|
|
|
|
|
|
|
|
|
#xmlArea.insertBefore(\
|
|
|
|
|
#nodeSeplist.cloneNode(True),
|
|
|
|
|
#xmlOldField)
|
|
|
|
|
|
|
|
|
|
parentNode = nodeSeplist.parentNode
|
|
|
|
|
parentNode.removeChild(nodeSeplist)
|
|
|
|
|
|
|
|
|
|
insNodesRepl = []
|
|
|
|
|
for newNode, nxtNode, app in insSplLst:
|
|
|
|
|
flagCompareSeplist = False
|
|
|
|
|
newValues = self.getFieldValues(newNode)
|
|
|
|
|
for nodeRepl, nxtNode, app in insNodesRepl:
|
|
|
|
|
oldValues = self.getFieldValues(nodeRepl)
|
|
|
|
|
for newValue in newValues:
|
|
|
|
|
if newValue in oldValues:
|
|
|
|
|
flagCompareSeplist = True
|
|
|
|
|
break
|
|
|
|
|
if not flagCompareSeplist:
|
|
|
|
|
if xmlOldField:
|
|
|
|
|
insNodesRepl.append((newNode, nxtNode, app))
|
|
|
|
|
|
|
|
|
|
for newNode, nxtNode, app in insNodesRepl:
|
|
|
|
|
if app == "insert":
|
|
|
|
|
xmlArea.insertBefore(newNode,nxtNode)
|
|
|
|
|
elif app == "append":
|
|
|
|
|
xmlArea.appendChild(newNode)
|
|
|
|
|
if xmlOldField:
|
|
|
|
|
parentNode = xmlOldField.parentNode
|
|
|
|
|
if parentNode and newFieldsAction != "join":
|
|
|
|
|
parentNode.removeChild(xmlOldField)
|
|
|
|
|
|
|
|
|
|
for newNode, nxtNode, app in appSplLst:
|
|
|
|
|
if app == "insert":
|
|
|
|
|
xmlArea.insertBefore(newNode,nxtNode)
|
|
|
|
|
elif app == "append":
|
|
|
|
|
xmlArea.appendChild(newNode)
|
|
|
|
|
|
|
|
|
|
if not flagCompare and typeNewField != "seplist":
|
|
|
|
|
# Устанавливаем action=replace
|
|
|
|
|
self.setActionField(xmlNewField, "replace")
|
|
|
|
|
# Если параметры поля не сходятся заменяем поле
|
|
|
|
|
xmlArea.replaceChild(xmlNewField.cloneNode(True),
|
|
|
|
|
fieldsOldComp[-1])
|
|
|
|
|
|
|
|
|
|
if newFieldsAction == "join":
|
|
|
|
|
fieldsOldRemove = []
|
|
|
|
|
else:
|
|
|
|
|
fieldsOldRemove = fieldsOldComp[:-1]
|
|
|
|
|
|
|
|
|
|
for nodeFieldOld in fieldsOldRemove:
|
|
|
|
|
actionOldNode = self.getActionField(nodeFieldOld)
|
|
|
|
|
if actionOldNode == "insert" or actionOldNode == "append":
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
if nodeFieldOld.nextSibling and\
|
|
|
|
|
self.getTypeField(nodeFieldOld.nextSibling) == "br":
|
|
|
|
|
xmlArea.removeChild(nodeFieldOld.nextSibling)
|
|
|
|
|
xmlArea.removeChild(nodeFieldOld)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def getSepListToField(self, xmlField):
|
|
|
|
|
"""Выдает элементы распределенного массива
|
|
|
|
|
|
|
|
|
|
Область предок поля, в этой области ищутся
|
|
|
|
|
элементы распределенного массива
|
|
|
|
|
"""
|
|
|
|
|
nameField = self.getNameField(xmlField)
|
|
|
|
|
if not nameField:
|
|
|
|
|
return []
|
|
|
|
|
parentNode = xmlField.parentNode
|
|
|
|
|
#print parentNode.toprettyxml()
|
|
|
|
|
if parentNode:
|
|
|
|
|
fieldsVal = xpath.Evaluate(\
|
|
|
|
|
"child::field[attribute::type='seplist'][child::name='%s'] "\
|
|
|
|
|
%(nameField), parentNode)
|
|
|
|
|
#print nameField
|
|
|
|
|
return fieldsVal
|
|
|
|
|
else:
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
def removeComment(self, xmlArea):
|
|
|
|
|
"""Удаляет комментарии в XML области"""
|
|
|
|
|
fieldNodes = xpath.Evaluate('descendant::field',xmlArea)
|
|
|
|
|
for fieldNode in fieldNodes:
|
|
|
|
|
if fieldNode.hasAttribute("type"):
|
|
|
|
|
if fieldNode.getAttribute("type") == "comment" or\
|
|
|
|
|
fieldNode.getAttribute("type") == "br":
|
|
|
|
|
parentNode = fieldNode.parentNode
|
|
|
|
|
parentNode.removeChild(fieldNode)
|
|
|
|
|
else:
|
|
|
|
|
if self.getActionField(fieldNode) == "drop":
|
|
|
|
|
pass
|
|
|
|
|
elif self.getActionField(fieldNode) == "join":
|
|
|
|
|
pass
|
|
|
|
|
else:
|
|
|
|
|
self.setActionField(fieldNode,"append")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def joinBody(self, baseBody, newBody):
|
|
|
|
|
"""Объединяет две области Body"""
|
|
|
|
|
newFields = xpath.Evaluate('child::field',newBody)
|
|
|
|
|
xmlNewAreas = xpath.Evaluate('child::area',newBody)
|
|
|
|
|
for xmlNewArea in xmlNewAreas:
|
|
|
|
|
self.joinArea(baseBody,xmlNewArea)
|
|
|
|
|
joinNewFields = xpath.Evaluate("child::field[child::action='join']"
|
|
|
|
|
,newBody)
|
|
|
|
|
self.addNewFielsOldArea(newFields, joinNewFields, baseBody)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def getRemoveNodeSepList(self, removeNodesDict, baseNode, xmNewlField):
|
|
|
|
|
"""Находит элементы разделенного списка
|
|
|
|
|
|
|
|
|
|
Параметры:
|
|
|
|
|
removeNodesDict - Cловарь удаляемых полей разделенного списка
|
|
|
|
|
формируется программой
|
|
|
|
|
baseNode - Нода в которой идет поиск
|
|
|
|
|
xmNewlField - Нода field которая проверяется на принадлежность
|
|
|
|
|
к разделенному списку
|
|
|
|
|
"""
|
|
|
|
|
flagNewNodeSeplist = False
|
|
|
|
|
if self.getTypeField(xmNewlField) == "seplist":
|
|
|
|
|
flagNewNodeSeplist = True
|
|
|
|
|
nameNewField = self.getNameField(xmNewlField)
|
|
|
|
|
if nameNewField:
|
|
|
|
|
if removeNodesDict.has_key(nameNewField):
|
|
|
|
|
return removeNodesDict[nameNewField]
|
|
|
|
|
else:
|
|
|
|
|
oldFields = xpath.Evaluate('child::field', baseNode)
|
|
|
|
|
removeNodes = []
|
|
|
|
|
lenOldFields = len(oldFields)
|
|
|
|
|
for i in range(lenOldFields):
|
|
|
|
|
oldNode = oldFields[i]
|
|
|
|
|
flagSep = self.getTypeField(oldNode) == "seplist"
|
|
|
|
|
if flagNewNodeSeplist:
|
|
|
|
|
flagSep = True
|
|
|
|
|
if flagSep and\
|
|
|
|
|
nameNewField == self.getNameField(oldNode):
|
|
|
|
|
removeNodes.append(oldNode)
|
|
|
|
|
if i+1<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 and fieldValue[0].firstChild:
|
|
|
|
|
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
|
|
|
|
|
sp = subprocess.Popen("file '%s'"%nameFile, stdin=subprocess.PIPE,
|
|
|
|
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
|
|
|
close_fds=True, shell=True)
|
|
|
|
|
fout, fin, ferr = (sp.stdout, sp.stdin, sp.stderr)
|
|
|
|
|
fin.close()
|
|
|
|
|
textLine = fout.readline()
|
|
|
|
|
fout.readlines()
|
|
|
|
|
fout.close()
|
|
|
|
|
retText = ""
|
|
|
|
|
if textLine:
|
|
|
|
|
listTextLine = textLine.split(":")
|
|
|
|
|
if len(listTextLine) == 2:
|
|
|
|
|
textFormats = ["text", "XML"]
|
|
|
|
|
retText = "bin"
|
|
|
|
|
fileTypeString = listTextLine[1]
|
|
|
|
|
for textFormat in textFormats:
|
|
|
|
|
if textFormat in fileTypeString:
|
|
|
|
|
retText = "text"
|
|
|
|
|
break
|
|
|
|
|
ferr.close()
|
|
|
|
|
return retText
|
|
|
|
|
|
|
|
|
|
def scanDirs(self, profilesDirs):
|
|
|
|
|
"""Сканирует дерево каталогов выдает два списка: директории, файлы"""
|
|
|
|
|
dirs = []
|
|
|
|
|
class dirProf:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.baseDir = False
|
|
|
|
|
self.dirs = []
|
|
|
|
|
self.files = []
|
|
|
|
|
self.links = []
|
|
|
|
|
self.sockets = []
|
|
|
|
|
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)
|
|
|
|
|
elif stat.S_ISSOCK(os.stat(absNameFile)[stat.ST_MODE]):
|
|
|
|
|
dirP.sockets.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 utfBin:
|
|
|
|
|
"""Класс для преобразования в utf-8
|
|
|
|
|
|
|
|
|
|
преобразование бинарного или смеси бинарного и utf-8 кода в utf-8 и
|
|
|
|
|
обратное преобразование
|
|
|
|
|
методы класса encode и decode
|
|
|
|
|
"""
|
|
|
|
|
def _retUTF(self, char):
|
|
|
|
|
byte = ord(char)
|
|
|
|
|
if byte<=127:
|
|
|
|
|
return ('_ch_',1)
|
|
|
|
|
elif byte<=191:
|
|
|
|
|
return ('_nb_',1)
|
|
|
|
|
elif byte<=223:
|
|
|
|
|
return ('_fb_',2)
|
|
|
|
|
elif byte<=239:
|
|
|
|
|
return ('_fb_',3)
|
|
|
|
|
elif byte<=247:
|
|
|
|
|
return ('_fb_',4)
|
|
|
|
|
else:
|
|
|
|
|
return ('_er_',1)
|
|
|
|
|
|
|
|
|
|
def _sumbUtf(self, symbols, lenTail):
|
|
|
|
|
if not symbols:
|
|
|
|
|
return (False,0)
|
|
|
|
|
lenSymb = len(symbols)
|
|
|
|
|
if lenSymb >= 4:
|
|
|
|
|
l = 4
|
|
|
|
|
elif lenSymb >= 3:
|
|
|
|
|
l = 3
|
|
|
|
|
elif lenSymb >= 2:
|
|
|
|
|
l = 2
|
|
|
|
|
else:
|
|
|
|
|
if symbols[0] == '_ch_':
|
|
|
|
|
return (True,1)
|
|
|
|
|
else:
|
|
|
|
|
return (False,1)
|
|
|
|
|
result = False
|
|
|
|
|
for i in range(l):
|
|
|
|
|
if i == 0 and symbols[i] != '_fb_':
|
|
|
|
|
break
|
|
|
|
|
elif i > 0 and symbols[i] != '_nb_':
|
|
|
|
|
break
|
|
|
|
|
if lenTail>1 and lenTail != i:
|
|
|
|
|
return (False,1)
|
|
|
|
|
if i > 0:
|
|
|
|
|
result = True
|
|
|
|
|
return (result, i)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _intToChar(self, x):
|
|
|
|
|
he = hex(x)[2:]
|
|
|
|
|
exec("ret = '\\x%s'" %he)
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
def _hexToChar(self, he):
|
|
|
|
|
exec("ret = '\\x%s'" %he)
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
def encode(self, text):
|
|
|
|
|
"""Кодирует смешанный формат в UTF-8"""
|
|
|
|
|
ind = 0
|
|
|
|
|
l = 0
|
|
|
|
|
utf = []
|
|
|
|
|
lenUtf = []
|
|
|
|
|
indErr = []
|
|
|
|
|
i = 0
|
|
|
|
|
for ch in text:
|
|
|
|
|
r, l = self._retUTF(ch)
|
|
|
|
|
utf.append(r)
|
|
|
|
|
lenUtf.append(l)
|
|
|
|
|
i+=1
|
|
|
|
|
while 1:
|
|
|
|
|
if utf[ind] == '_fb_':
|
|
|
|
|
res, l = self._sumbUtf(utf[ind:],lenUtf[ind])
|
|
|
|
|
if res == False:
|
|
|
|
|
indErr.append(ind)
|
|
|
|
|
if l>0:
|
|
|
|
|
ind +=l
|
|
|
|
|
if ind >= len(utf):
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
if utf[ind] != '_ch_':
|
|
|
|
|
indErr.append(ind)
|
|
|
|
|
ind +=1
|
|
|
|
|
if ind >= len(utf):
|
|
|
|
|
break
|
|
|
|
|
if indErr:
|
|
|
|
|
lenIndErr = len(indErr)
|
|
|
|
|
block = []
|
|
|
|
|
blocks = []
|
|
|
|
|
if lenIndErr > 1:
|
|
|
|
|
i = 1
|
|
|
|
|
while 1:
|
|
|
|
|
if i == 1:
|
|
|
|
|
block.append(indErr[i-1])
|
|
|
|
|
if indErr[i] - indErr[i-1] == 1:
|
|
|
|
|
block.append(indErr[i])
|
|
|
|
|
else:
|
|
|
|
|
if block:
|
|
|
|
|
blocks.append(block)
|
|
|
|
|
block = []
|
|
|
|
|
block.append(indErr[i])
|
|
|
|
|
i +=1
|
|
|
|
|
if i >= lenIndErr:
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
block.append(indErr[0])
|
|
|
|
|
if block:
|
|
|
|
|
blocks.append(block)
|
|
|
|
|
listErr = []
|
|
|
|
|
for block in blocks:
|
|
|
|
|
string = ""
|
|
|
|
|
for elem in block:
|
|
|
|
|
string += hex(ord(text[elem]))[-2:]
|
|
|
|
|
listErr.append((block[0],"__hex__?%s?__hex__" %string,elem))
|
|
|
|
|
textOut = text
|
|
|
|
|
deltaInd = 0
|
|
|
|
|
for erEl in listErr:
|
|
|
|
|
startInd = erEl[0] + deltaInd
|
|
|
|
|
endInd = erEl[2] + 1 + deltaInd
|
|
|
|
|
textOut = textOut[:startInd] + erEl[1] + textOut[endInd:]
|
|
|
|
|
deltaInd += len(erEl[1])-(erEl[2]-erEl[0]+1)
|
|
|
|
|
#if i == 1:
|
|
|
|
|
#break
|
|
|
|
|
#i += 1
|
|
|
|
|
return textOut
|
|
|
|
|
|
|
|
|
|
def decode(self, text):
|
|
|
|
|
"""Декодирует UTF-8 в смешанный формат"""
|
|
|
|
|
varStart = "__hex__\?"
|
|
|
|
|
varEnd = "\?__hex__"
|
|
|
|
|
# -1 Это экранирование '?' которое тоже считается
|
|
|
|
|
deltVarStart = len(varStart)-1
|
|
|
|
|
deltVarEnd = len(varEnd)-1
|
|
|
|
|
reVar = re.compile(("%s[a-f0-9]+%s")%(varStart,varEnd),re.M)
|
|
|
|
|
resS = reVar.search(text)
|
|
|
|
|
textProfileTmp = text
|
|
|
|
|
while resS:
|
|
|
|
|
mark = textProfileTmp[resS.start():resS.end()]
|
|
|
|
|
hexString = mark[deltVarStart:-deltVarEnd]
|
|
|
|
|
i = 0
|
|
|
|
|
stringInsert = ""
|
|
|
|
|
hexCode = ""
|
|
|
|
|
for ch in hexString:
|
|
|
|
|
if i>=1:
|
|
|
|
|
hexCode += ch
|
|
|
|
|
stringInsert += self._hexToChar(hexCode)
|
|
|
|
|
hexCode = ""
|
|
|
|
|
i = 0
|
|
|
|
|
else:
|
|
|
|
|
hexCode += ch
|
|
|
|
|
i += 1
|
|
|
|
|
textProfileTmp = textProfileTmp.replace(mark, stringInsert)
|
|
|
|
|
resS = reVar.search(textProfileTmp)
|
|
|
|
|
return textProfileTmp
|
|
|
|
|
|
|
|
|
|
class profile(_file, _terms, xmlShare):
|
|
|
|
|
"""Класс для работы с профилями
|
|
|
|
|
|
|
|
|
|
На вход 2 параметра: объект хранения переменных, имя сервиса - не
|
|
|
|
|
обязательный параметр
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
# Имена установленных программ
|
|
|
|
|
installProg = []
|
|
|
|
|
# Версии установленных программ
|
|
|
|
|
installProgVersions = []
|
|
|
|
|
|
|
|
|
|
# Название файла профиля директории
|
|
|
|
|
profDirNameFile = ".calculate_directory"
|
|
|
|
|
|
|
|
|
|
def __init__(self, objVar, servDir=False, dirsFilter=[], filesFilter=[]):
|
|
|
|
|
# Необрабатываемые директории
|
|
|
|
|
self.dirsFilter = dirsFilter
|
|
|
|
|
# Необрабатываемые файлы
|
|
|
|
|
self.filesFilter = filesFilter
|
|
|
|
|
_file.__init__(self)
|
|
|
|
|
# Словарь для создания объектов новых классов по образцу
|
|
|
|
|
self.newObjProt = {'proftpd':(apache,),}
|
|
|
|
|
# Заголовок title
|
|
|
|
|
self.__titleHead = "--------------------------------------\
|
|
|
|
|
----------------------------------------"
|
|
|
|
|
self._titleBody = ""
|
|
|
|
|
self._titleList = (_("Modified"), _("File of a profile"))
|
|
|
|
|
|
|
|
|
|
# Метки
|
|
|
|
|
varStart = "#-"
|
|
|
|
|
varEnd = "-#"
|
|
|
|
|
self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")%(varStart,varEnd),re.M)
|
|
|
|
|
self._reFunc = 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<func>\([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 removeDir(self, rmDir):
|
|
|
|
|
"""Рекурсивное удаление директории
|
|
|
|
|
|
|
|
|
|
входной параметр директория
|
|
|
|
|
"""
|
|
|
|
|
if not os.path.exists(rmDir):
|
|
|
|
|
self.printERROR(_("Not found remove dir %s") %rmDir)
|
|
|
|
|
return False
|
|
|
|
|
fileObj = _file()
|
|
|
|
|
# Сканируем директорию
|
|
|
|
|
scanObjs = fileObj.scanDirs([rmDir])
|
|
|
|
|
for socketRm in scanObjs[0].sockets:
|
|
|
|
|
# Удаляем сокеты
|
|
|
|
|
if os.path.exists(socketRm):
|
|
|
|
|
os.remove(socketRm)
|
|
|
|
|
for linkRm in scanObjs[0].links:
|
|
|
|
|
# Удаляем ссылки
|
|
|
|
|
os.unlink(linkRm[1])
|
|
|
|
|
for fileRm in scanObjs[0].files:
|
|
|
|
|
# Удаляем файлы
|
|
|
|
|
os.remove(fileRm)
|
|
|
|
|
scanObjs[0].dirs.sort(lambda x, y: cmp(len(y), len(x)))
|
|
|
|
|
for dirRm in scanObjs[0].dirs:
|
|
|
|
|
# Удаляем директории
|
|
|
|
|
os.rmdir(dirRm)
|
|
|
|
|
if rmDir:
|
|
|
|
|
os.rmdir(rmDir)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def createDir(self, baseProfDir, profDir, baseDirMv, createDir):
|
|
|
|
|
"""Создает директорию
|
|
|
|
|
|
|
|
|
|
baseDirMv + результат вычитания из profDir baseProfDir
|
|
|
|
|
createDir - создаваемая директория
|
|
|
|
|
"""
|
|
|
|
|
if baseDirMv and not os.access(baseDirMv, os.F_OK):
|
|
|
|
|
os.makedirs(baseDirMv)
|
|
|
|
|
# Созданные директории
|
|
|
|
|
createDirs = []
|
|
|
|
|
baseDir = baseProfDir
|
|
|
|
|
if baseProfDir[-1] == "/":
|
|
|
|
|
baseDir = baseProfDir[:-1]
|
|
|
|
|
# Директория в системе относительно baseDirMv без условий
|
|
|
|
|
if baseDirMv:
|
|
|
|
|
dirMvNoTerm = createDir.partition(baseDirMv)[2]
|
|
|
|
|
else:
|
|
|
|
|
dirMvNoTerm = createDir
|
|
|
|
|
# директория в системе
|
|
|
|
|
dirMv = profDir.partition(baseDir)[2]
|
|
|
|
|
if len(dirMv)>1 and dirMv[-1] == "/":
|
|
|
|
|
dirMv = dirMv[:-1]
|
|
|
|
|
## директория в системе без условий
|
|
|
|
|
#dirMvNoTerm = "/".join(map(lambda x:x.split("?")[0],\
|
|
|
|
|
#dirMv.split("/")))
|
|
|
|
|
listDirMv = dirMv.split("/")
|
|
|
|
|
listDirMvNoTerm = dirMvNoTerm.split("/")
|
|
|
|
|
if len(listDirMv) != len(listDirMvNoTerm):
|
|
|
|
|
self.setError (_("Error in profile") + " :" + profDir)
|
|
|
|
|
return False
|
|
|
|
|
genIn = listDirMv.__iter__()
|
|
|
|
|
genOut = listDirMvNoTerm.__iter__()
|
|
|
|
|
inAndOutDirs = map(lambda x: [x,genOut.next()], genIn)
|
|
|
|
|
createDirs = []
|
|
|
|
|
createDir = []
|
|
|
|
|
while (len(inAndOutDirs)>1):
|
|
|
|
|
tmpDirIn = baseDir+"/".join(map(lambda x:x[0], inAndOutDirs))
|
|
|
|
|
tmpDirOut = baseDirMv + "/".join(map(lambda x:x[1],\
|
|
|
|
|
inAndOutDirs))
|
|
|
|
|
if os.access(tmpDirOut, os.F_OK):
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
createDir.append((tmpDirIn, tmpDirOut))
|
|
|
|
|
inAndOutDirs.pop()
|
|
|
|
|
createDir.reverse()
|
|
|
|
|
for crDirIn,crDirOut in createDir:
|
|
|
|
|
try:
|
|
|
|
|
mode,uid,gid = self.getModeFile(crDirIn)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError (_("not access dir:" ) + crDirIn)
|
|
|
|
|
return False
|
|
|
|
|
createDirs.append(crDirOut)
|
|
|
|
|
os.mkdir(crDirOut, mode)
|
|
|
|
|
os.chown(crDirOut, uid, gid)
|
|
|
|
|
return createDirs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def applyVarsProfile(self, textProfile, nameProfile):
|
|
|
|
|
""" Заменяет переменные на их значения
|
|
|
|
|
"""
|
|
|
|
|
resS = self._reVar.search(textProfile)
|
|
|
|
|
textProfileTmp = textProfile
|
|
|
|
|
while resS:
|
|
|
|
|
mark = textProfileTmp[resS.start():resS.end()]
|
|
|
|
|
varName = mark[self._deltVarStart:-self._deltVarEnd]
|
|
|
|
|
varValue = ""
|
|
|
|
|
try:
|
|
|
|
|
varValue = str(self.objVar.Get(varName))
|
|
|
|
|
except self.objVar.DataVarsError, e:
|
|
|
|
|
print _("error in profile %s")%nameProfile
|
|
|
|
|
print e
|
|
|
|
|
cl_base.exit(1)
|
|
|
|
|
textProfileTmp = textProfileTmp.replace(mark, varValue)
|
|
|
|
|
resS = self._reVar.search(textProfileTmp)
|
|
|
|
|
return textProfileTmp
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def applyFuncProfile(self, textProfile, nameProfile, nameSystemFile):
|
|
|
|
|
""" Применяет функции к тексту профиля
|
|
|
|
|
"""
|
|
|
|
|
def equalTerm(term, sNum, sMD, localVars):
|
|
|
|
|
"""Локальная функция для вычисления выражения"""
|
|
|
|
|
terms = sNum.findall(term)
|
|
|
|
|
if terms:
|
|
|
|
|
strNumers = []
|
|
|
|
|
for n in terms:
|
|
|
|
|
strNum = n.strip()
|
|
|
|
|
if "*" in strNum or "/" in strNum:
|
|
|
|
|
strNum = multAndDiv(strNum,sNum,sMD,localVars)
|
|
|
|
|
try:
|
|
|
|
|
num = int(strNum)
|
|
|
|
|
except:
|
|
|
|
|
minus = False
|
|
|
|
|
if strNum[:1] == "-":
|
|
|
|
|
minus = True
|
|
|
|
|
strNum = strNum[1:]
|
|
|
|
|
if localVars.has_key(strNum):
|
|
|
|
|
num = localVars[strNum]
|
|
|
|
|
elif self.objVar.exists(strNum):
|
|
|
|
|
try:
|
|
|
|
|
num = int(self.objVar.Get(strNum))
|
|
|
|
|
except:
|
|
|
|
|
print _("error in profile %s")%nameProfile
|
|
|
|
|
print _("error var %s not int")%str(strNum)
|
|
|
|
|
cl_base.exit(1)
|
|
|
|
|
else:
|
|
|
|
|
print _("error in profile %s")%nameProfile
|
|
|
|
|
print _("error local var %s not defined")\
|
|
|
|
|
%str(strNum)
|
|
|
|
|
cl_base.exit(1)
|
|
|
|
|
if minus:
|
|
|
|
|
num =-num
|
|
|
|
|
strNumers.append(num)
|
|
|
|
|
return sum(strNumers)
|
|
|
|
|
print _("error in profile %s")%nameProfile
|
|
|
|
|
print _("error profile term %s, incorrect data")%str(term)
|
|
|
|
|
cl_base.exit(1)
|
|
|
|
|
|
|
|
|
|
def multAndDiv(term,sNum,sMD,localVars):
|
|
|
|
|
"""локальная функция для умножения и деления"""
|
|
|
|
|
termTmp = term
|
|
|
|
|
varsLocal = sMD.findall(term)
|
|
|
|
|
for var in varsLocal:
|
|
|
|
|
flagVarTxt = True
|
|
|
|
|
try:
|
|
|
|
|
int(var)
|
|
|
|
|
except:
|
|
|
|
|
flagVarTxt = False
|
|
|
|
|
if flagVarTxt:
|
|
|
|
|
continue
|
|
|
|
|
varReplace = str(equalTerm(var,sNum,sMD,localVars))
|
|
|
|
|
termTmp = termTmp.replace(var,varReplace)
|
|
|
|
|
ret = eval(termTmp)
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
def funcSum(funTxt,resS,localVars,textProfileTmp):
|
|
|
|
|
"""локальная функция вычисляет первую функцию sum() в профиле"""
|
|
|
|
|
terms = funTxt[4:-1].replace(" ","").split(",")
|
|
|
|
|
# Название локальной переменной
|
|
|
|
|
nameLocVar = terms[0]
|
|
|
|
|
if not localVars.has_key(nameLocVar):
|
|
|
|
|
localVars[nameLocVar] = 0
|
|
|
|
|
if len(terms) == 2:
|
|
|
|
|
if terms[1].strip():
|
|
|
|
|
localVars[nameLocVar] = equalTerm(terms[1],sNum,sMD,
|
|
|
|
|
localVars)
|
|
|
|
|
replace = str(localVars[nameLocVar])
|
|
|
|
|
else:
|
|
|
|
|
replace = ""
|
|
|
|
|
textProfileTmp = textProfileTmp[:resS.start()] + replace +\
|
|
|
|
|
textProfileTmp[resS.end():]
|
|
|
|
|
elif len(terms) == 3:
|
|
|
|
|
if terms[1].strip():
|
|
|
|
|
replaceInt = equalTerm(terms[1],sNum,sMD,localVars)
|
|
|
|
|
replace = str(replaceInt)
|
|
|
|
|
else:
|
|
|
|
|
replace = ""
|
|
|
|
|
localVars[nameLocVar] = equalTerm(terms[2],
|
|
|
|
|
sNum,sMD,localVars)
|
|
|
|
|
textProfileTmp = textProfileTmp[:resS.start()] + replace +\
|
|
|
|
|
textProfileTmp[resS.end():]
|
|
|
|
|
else:
|
|
|
|
|
print _("error in profile %s")%nameProfile
|
|
|
|
|
print _("error profile term %s")%str(funTxt)
|
|
|
|
|
cl_base.exit(1)
|
|
|
|
|
return textProfileTmp
|
|
|
|
|
|
|
|
|
|
def funcLoad(funTxt,resS,textProfileTmp):
|
|
|
|
|
"""если файл существует читает из файла локальную переменную
|
|
|
|
|
|
|
|
|
|
если один параметр - выводит значение локальной переменной
|
|
|
|
|
"""
|
|
|
|
|
terms = funTxt[5:-1].replace(" ","").split(",")
|
|
|
|
|
if not terms[0].strip() or\
|
|
|
|
|
(len(terms)==2 and not terms[1].strip()) or\
|
|
|
|
|
len(terms)>2:
|
|
|
|
|
print _("error in profile %s")%nameProfile
|
|
|
|
|
print _("error profile term %s")%str(funTxt)
|
|
|
|
|
cl_base.exit(1)
|
|
|
|
|
if len(terms) == 2:
|
|
|
|
|
if not terms[0] in ["ver","num","char","key"]:
|
|
|
|
|
print _("error in profile %s")%nameProfile
|
|
|
|
|
print _("error profile term %s")%str(funTxt)
|
|
|
|
|
print _("first argument function is not 'ver' or 'num' or\
|
|
|
|
|
'char'")
|
|
|
|
|
cl_base.exit(1)
|
|
|
|
|
if len(terms) == 1:
|
|
|
|
|
fileName = terms[0].strip()
|
|
|
|
|
if fileName[0] != "/":
|
|
|
|
|
path = os.path.split(nameSystemFile)[0]
|
|
|
|
|
fileName=os.path.join(path,fileName)
|
|
|
|
|
else:
|
|
|
|
|
fileName = terms[1].strip()
|
|
|
|
|
if fileName[1] != "/":
|
|
|
|
|
path = os.path.split(nameSystemFile)[0]
|
|
|
|
|
fileName=os.path.join(path,fileName)
|
|
|
|
|
replace = ""
|
|
|
|
|
if os.path.exists(fileName):
|
|
|
|
|
FD = open(fileName)
|
|
|
|
|
replace = FD.read().strip()
|
|
|
|
|
FD.close
|
|
|
|
|
if not replace and len(terms) == 2 and terms[0] in ["ver","num"]:
|
|
|
|
|
replace = "0"
|
|
|
|
|
textProfileTmp = textProfileTmp[:resS.start()] + replace +\
|
|
|
|
|
textProfileTmp[resS.end():]
|
|
|
|
|
return textProfileTmp
|
|
|
|
|
|
|
|
|
|
def getInstallPkgGentoo():
|
|
|
|
|
"""Выдает два списка, инсталлированные программы и номера версий"""
|
|
|
|
|
baseDir = "/var/db/pkg"
|
|
|
|
|
pkgs = []
|
|
|
|
|
reVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*")
|
|
|
|
|
def getFilesDir(pkgs, dirname, names):
|
|
|
|
|
for nameFile in names:
|
|
|
|
|
absNameFile = os.path.join(dirname,nameFile)
|
|
|
|
|
if os.path.isdir(absNameFile):
|
|
|
|
|
tail = absNameFile.split(baseDir)
|
|
|
|
|
if len(tail)==2:
|
|
|
|
|
tail = tail[1].split('/')
|
|
|
|
|
if len(tail)==3 and tail[1]!='virtual':
|
|
|
|
|
pkgs.append(tail[2])
|
|
|
|
|
return True
|
|
|
|
|
os.path.walk(baseDir,getFilesDir, pkgs)
|
|
|
|
|
pkgs.sort()
|
|
|
|
|
names = []
|
|
|
|
|
versions = []
|
|
|
|
|
for pkg in pkgs:
|
|
|
|
|
findVer = reVer.search(pkg)
|
|
|
|
|
if findVer:
|
|
|
|
|
ver = findVer.group()
|
|
|
|
|
versions.append(ver)
|
|
|
|
|
names.append(pkg.split(ver)[0][:-1])
|
|
|
|
|
#return pkgs
|
|
|
|
|
return names, versions
|
|
|
|
|
|
|
|
|
|
def pkg(nameProg, names, versions):
|
|
|
|
|
"""Выдает установленные версии по имени программы"""
|
|
|
|
|
i = 0
|
|
|
|
|
vers = []
|
|
|
|
|
for name in names:
|
|
|
|
|
if nameProg == name:
|
|
|
|
|
while nameProg == names[i]:
|
|
|
|
|
vers.append(versions[i])
|
|
|
|
|
i += 1
|
|
|
|
|
break
|
|
|
|
|
i += 1
|
|
|
|
|
if vers:
|
|
|
|
|
return vers[-1]
|
|
|
|
|
else:
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
def funcPkg(funTxt,resS,textProfileTmp):
|
|
|
|
|
"""локальная функция выдает номер версии программы"""
|
|
|
|
|
terms = funTxt[4:-1].replace(" ","")
|
|
|
|
|
# Название программы
|
|
|
|
|
nameProg = terms
|
|
|
|
|
if not self.installProg:
|
|
|
|
|
self.installProg,self.installProgVersions=getInstallPkgGentoo()
|
|
|
|
|
replace = pkg(nameProg,self.installProg,self.installProgVersions)
|
|
|
|
|
textProfileTmp = textProfileTmp[:resS.start()] + replace +\
|
|
|
|
|
textProfileTmp[resS.end():]
|
|
|
|
|
return textProfileTmp
|
|
|
|
|
|
|
|
|
|
def funcRnd(funTxt,resS,textProfileTmp):
|
|
|
|
|
"""локальная функция выдает строку случайных символов
|
|
|
|
|
|
|
|
|
|
первый аргумент:
|
|
|
|
|
'num' - числа,
|
|
|
|
|
'pas' - цифры и буквы
|
|
|
|
|
второй аргумент:
|
|
|
|
|
количество символов
|
|
|
|
|
"""
|
|
|
|
|
terms = funTxt[4:-1].replace(" ","").split(",")
|
|
|
|
|
if not terms[0].strip() or\
|
|
|
|
|
(len(terms)==2 and not terms[1].strip()) or\
|
|
|
|
|
len(terms)!=2:
|
|
|
|
|
print _("error in profile %s")%nameProfile
|
|
|
|
|
print _("error profile term %s")%str(funTxt)
|
|
|
|
|
cl_base.exit(1)
|
|
|
|
|
fArgvNames = ['num','pas']
|
|
|
|
|
if not terms[0] in fArgvNames:
|
|
|
|
|
print _("error in profile %s")%nameProfile
|
|
|
|
|
print _("error profile term %s")%str(funTxt)
|
|
|
|
|
print _("first argument function is not 'num' or 'pas'")
|
|
|
|
|
cl_base.exit(1)
|
|
|
|
|
try:
|
|
|
|
|
lenStr = int(terms[1])
|
|
|
|
|
except:
|
|
|
|
|
print _("error in profile %s")%nameProfile
|
|
|
|
|
print _("error profile term %s")%str(funTxt)
|
|
|
|
|
print _("two argument function is not number")
|
|
|
|
|
cl_base.exit(1)
|
|
|
|
|
if terms[0] == fArgvNames[0]:
|
|
|
|
|
replace=''.join([random.choice(string.digits)\
|
|
|
|
|
for i in xrange(lenStr)])
|
|
|
|
|
elif terms[0] == fArgvNames[1]:
|
|
|
|
|
replace=''.join([random.choice(string.ascii_letters + \
|
|
|
|
|
string.digits) for i in xrange(lenStr)])
|
|
|
|
|
else:
|
|
|
|
|
print _("error in profile %s")%nameProfile
|
|
|
|
|
print _("error profile term %s")%str(funTxt)
|
|
|
|
|
cl_base.exit(1)
|
|
|
|
|
textProfileTmp = textProfileTmp[:resS.start()] + replace +\
|
|
|
|
|
textProfileTmp[resS.end():]
|
|
|
|
|
return textProfileTmp
|
|
|
|
|
|
|
|
|
|
def funcCase(funTxt,resS,textProfileTmp):
|
|
|
|
|
"""локальная функция выдает переменную в определенном регистре
|
|
|
|
|
|
|
|
|
|
первый аргумент:
|
|
|
|
|
'upper' - верхний регистр,
|
|
|
|
|
'lower' - нижний регистр,
|
|
|
|
|
'capitalize' - первая буква в верхнем регистре
|
|
|
|
|
второй аргумент:
|
|
|
|
|
название переменной
|
|
|
|
|
"""
|
|
|
|
|
terms = funTxt[5:-1].replace(" ","").split(",")
|
|
|
|
|
if not terms[0].strip() or\
|
|
|
|
|
(len(terms)==2 and not terms[1].strip()) or len(terms)!=2:
|
|
|
|
|
print _("error in profile %s")%nameProfile
|
|
|
|
|
print _("error profile term %s")%str(funTxt)
|
|
|
|
|
cl_base.exit(1)
|
|
|
|
|
fArgvNames = ['upper','lower','capitalize']
|
|
|
|
|
if not terms[0] in fArgvNames:
|
|
|
|
|
print _("error in profile %s")%nameProfile
|
|
|
|
|
print _("error profile term %s")%str(funTxt)
|
|
|
|
|
print _("first argument function is not 'upper' or 'lower' or\
|
|
|
|
|
'capitalize'")
|
|
|
|
|
cl_base.exit(1)
|
|
|
|
|
try:
|
|
|
|
|
strValue = str(self.objVar.Get(terms[1]))
|
|
|
|
|
except:
|
|
|
|
|
print _("error in profile %s")%nameProfile
|
|
|
|
|
print _("error var %s not found")%str(terms[1])
|
|
|
|
|
cl_base.exit(1)
|
|
|
|
|
replace = ""
|
|
|
|
|
strValue = self._toUNICODE(strValue)
|
|
|
|
|
if terms[0] == 'upper':
|
|
|
|
|
replace = strValue.upper()
|
|
|
|
|
elif terms[0] == 'lower':
|
|
|
|
|
replace = strValue.lower()
|
|
|
|
|
elif terms[0] == 'capitalize':
|
|
|
|
|
replace = strValue.capitalize()
|
|
|
|
|
if replace:
|
|
|
|
|
replace = replace.encode("UTF-8")
|
|
|
|
|
textProfileTmp = textProfileTmp[:resS.start()] + replace +\
|
|
|
|
|
textProfileTmp[resS.end():]
|
|
|
|
|
return textProfileTmp
|
|
|
|
|
|
|
|
|
|
# Локальные переменные
|
|
|
|
|
localVars = {}
|
|
|
|
|
# Регулярное выражние для сложения
|
|
|
|
|
sNum = re.compile("\-[^\-\+]+|[^\-\+]+")
|
|
|
|
|
# Регулярное выражение для умножениея и деления
|
|
|
|
|
sMD = re.compile("[^\-\+\*\/]+")
|
|
|
|
|
resS = self._reFunc.search(textProfile)
|
|
|
|
|
textProfileTmp = textProfile
|
|
|
|
|
while resS:
|
|
|
|
|
mark = textProfileTmp[resS.start():resS.end()]
|
|
|
|
|
funTxt = mark[self._deltVarStart:-self._deltVarEnd]
|
|
|
|
|
# Функция sum
|
|
|
|
|
if funTxt[:4] == "sum(":
|
|
|
|
|
textProfileTmp = funcSum(funTxt,resS,localVars,textProfileTmp)
|
|
|
|
|
resS = self._reFunc.search(textProfileTmp)
|
|
|
|
|
# Функция load
|
|
|
|
|
elif funTxt[:5] == "load(":
|
|
|
|
|
textProfileTmp = funcLoad(funTxt,resS,textProfileTmp)
|
|
|
|
|
resS = self._reFunc.search(textProfileTmp)
|
|
|
|
|
elif funTxt[:4] == "pkg(":
|
|
|
|
|
textProfileTmp = funcPkg(funTxt,resS,textProfileTmp)
|
|
|
|
|
resS = self._reFunc.search(textProfileTmp)
|
|
|
|
|
elif funTxt[:4] == "rnd(":
|
|
|
|
|
textProfileTmp = funcRnd(funTxt,resS,textProfileTmp)
|
|
|
|
|
resS = self._reFunc.search(textProfileTmp)
|
|
|
|
|
elif funTxt[:5] == "case(":
|
|
|
|
|
textProfileTmp = funcCase(funTxt,resS,textProfileTmp)
|
|
|
|
|
resS = self._reFunc.search(textProfileTmp)
|
|
|
|
|
else:
|
|
|
|
|
resS = False
|
|
|
|
|
return textProfileTmp
|
|
|
|
|
|
|
|
|
|
def applyTermsProfile(self, textProfile, nameProfile, nameSystemFile=False):
|
|
|
|
|
""" Применяет условия, к условным блокам текста
|
|
|
|
|
"""
|
|
|
|
|
textTerm = ""
|
|
|
|
|
resS = self._reTermBloc.search(textProfile)
|
|
|
|
|
textProfileTmp = textProfile
|
|
|
|
|
def function(text):
|
|
|
|
|
"""Функция обработки функций в заголовке"""
|
|
|
|
|
return self.applyFuncProfile(text, nameProfile, nameSystemFile)
|
|
|
|
|
if nameSystemFile:
|
|
|
|
|
while resS:
|
|
|
|
|
mark = resS.group(0)
|
|
|
|
|
body = resS.group("body")
|
|
|
|
|
end = resS.group("end")
|
|
|
|
|
parent = resS.group("func")
|
|
|
|
|
if not parent:
|
|
|
|
|
parent = ""
|
|
|
|
|
term = resS.group("rTerm") + parent +\
|
|
|
|
|
resS.group("lTerm")
|
|
|
|
|
if self._equalTerm(term, _("content profile not valid: ")+\
|
|
|
|
|
nameProfile, function):
|
|
|
|
|
textProfileTmp = textProfileTmp.replace(mark, body+end)
|
|
|
|
|
else:
|
|
|
|
|
textProfileTmp = textProfileTmp.replace(mark, "")
|
|
|
|
|
resS = self._reTermBloc.search(textProfileTmp)
|
|
|
|
|
else:
|
|
|
|
|
while resS:
|
|
|
|
|
mark = resS.group(0)
|
|
|
|
|
body = resS.group("body")
|
|
|
|
|
end = resS.group("end")
|
|
|
|
|
term = resS.group("rTerm") + resS.group("lTerm")
|
|
|
|
|
if self._equalTerm(term, _("content 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:
|
|
|
|
|
commentFirst = comment
|
|
|
|
|
commentInsert = comment
|
|
|
|
|
commentLast = comment
|
|
|
|
|
flagList = False
|
|
|
|
|
# В случае открывающего и закрывающего комментария
|
|
|
|
|
if type(comment) == types.TupleType and len(comment) == 2:
|
|
|
|
|
commentFirst = comment[0]
|
|
|
|
|
commentInsert = ""
|
|
|
|
|
commentLast = comment[1]
|
|
|
|
|
flagList = True
|
|
|
|
|
if flagList:
|
|
|
|
|
self._titleBody = commentFirst + "\n"
|
|
|
|
|
else:
|
|
|
|
|
self._titleBody = commentFirst + self.__titleHead + "\n"
|
|
|
|
|
z = 0
|
|
|
|
|
lenCommentList = len(commentList) - 1
|
|
|
|
|
for com in self._titleList:
|
|
|
|
|
if lenCommentList < z:
|
|
|
|
|
self._titleBody += commentInsert + " " + com + "\n"
|
|
|
|
|
else:
|
|
|
|
|
self._titleBody += commentInsert + " " + com +\
|
|
|
|
|
" " + commentList[z] + "\n"
|
|
|
|
|
z += 1
|
|
|
|
|
if flagList:
|
|
|
|
|
self._titleBody += commentLast +"\n"
|
|
|
|
|
else:
|
|
|
|
|
self._titleBody += commentLast + self.__titleHead + "\n"
|
|
|
|
|
return self._titleBody
|
|
|
|
|
else:
|
|
|
|
|
return ""
|
|
|
|
|
|
|
|
|
|
def numberAllProfiles(self, number):
|
|
|
|
|
"""Количество профилей
|
|
|
|
|
|
|
|
|
|
Вызов происходит перед наложением профилей
|
|
|
|
|
в момент вызова в number находится количество обрабатываемых файлов
|
|
|
|
|
Наследуемая функция
|
|
|
|
|
Используется для отображения прогресса при наложениии профилей
|
|
|
|
|
"""
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def numberProcessProfiles(self, number):
|
|
|
|
|
"""Номер текущего обрабатываемого профиля
|
|
|
|
|
|
|
|
|
|
Вызов происходит при наложении профиля
|
|
|
|
|
в момент вызова в number находится номер обрабатываемого профиля
|
|
|
|
|
Наследуемая функция
|
|
|
|
|
Используется для отображения прогресса при наложениии профилей
|
|
|
|
|
"""
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def scanDirs(self, profilesDirs, objVar=False):
|
|
|
|
|
"""Измененный метод сканирования директорий"""
|
|
|
|
|
dirs = []
|
|
|
|
|
class dirProf:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.baseDir = False
|
|
|
|
|
self.dirs = []
|
|
|
|
|
self.files = []
|
|
|
|
|
self.links = []
|
|
|
|
|
self.sockets = []
|
|
|
|
|
flagError = False
|
|
|
|
|
blockDirs = []
|
|
|
|
|
def getFilesDir(dirP, dirname, names):
|
|
|
|
|
for nameFile in names:
|
|
|
|
|
absNameFile = dirname + "/" + nameFile
|
|
|
|
|
findBlock = False
|
|
|
|
|
for blDir in blockDirs:
|
|
|
|
|
st,mid,end = absNameFile.partition(blDir)
|
|
|
|
|
if (not st) and mid and end:
|
|
|
|
|
findBlock = True
|
|
|
|
|
break
|
|
|
|
|
if not findBlock:
|
|
|
|
|
if os.path.islink(absNameFile):
|
|
|
|
|
dest = absNameFile
|
|
|
|
|
src = os.readlink(absNameFile)
|
|
|
|
|
dirP.links.append((src,dest))
|
|
|
|
|
elif os.path.isfile(absNameFile):
|
|
|
|
|
# Добавляем файлы кроме описаний директорий
|
|
|
|
|
if self.profDirNameFile != nameFile:
|
|
|
|
|
dirP.files.append(absNameFile)
|
|
|
|
|
elif os.path.isdir(absNameFile):
|
|
|
|
|
# Обработка условий в названии директории
|
|
|
|
|
if self.getNeedProfile(absNameFile):
|
|
|
|
|
if self.getError():
|
|
|
|
|
blockDirs.append(absNameFile)
|
|
|
|
|
flagError = True
|
|
|
|
|
break
|
|
|
|
|
dirP.dirs.append(absNameFile)
|
|
|
|
|
else:
|
|
|
|
|
if self.getError():
|
|
|
|
|
blockDirs.append(absNameFile)
|
|
|
|
|
flagError = True
|
|
|
|
|
break
|
|
|
|
|
blockDirs.append(absNameFile)
|
|
|
|
|
elif stat.S_ISSOCK(os.stat(absNameFile)[stat.ST_MODE]):
|
|
|
|
|
dirP.sockets.append(absNameFile)
|
|
|
|
|
for profileDir in profilesDirs:
|
|
|
|
|
if profileDir:
|
|
|
|
|
# Обработка условий в названии директории
|
|
|
|
|
if self.getNeedProfile(profileDir):
|
|
|
|
|
if self.getError():
|
|
|
|
|
flagError = True
|
|
|
|
|
break
|
|
|
|
|
dirP = dirProf()
|
|
|
|
|
dirP.baseDir = profileDir
|
|
|
|
|
dirs.append(dirP)
|
|
|
|
|
os.path.walk(profileDir, getFilesDir, dirP)
|
|
|
|
|
else:
|
|
|
|
|
if self.getError():
|
|
|
|
|
flagError = True
|
|
|
|
|
break
|
|
|
|
|
if flagError:
|
|
|
|
|
return []
|
|
|
|
|
return dirs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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")
|
|
|
|
|
dirsProfiles.sort()
|
|
|
|
|
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,self.objVar)
|
|
|
|
|
#файлы к которым были применены профили
|
|
|
|
|
filesApply = []
|
|
|
|
|
# Словарь измененных директорий
|
|
|
|
|
changeDirs = {}
|
|
|
|
|
#созданные директории
|
|
|
|
|
createdDirs = []
|
|
|
|
|
# Получаем общее количество профилей (нужно для прогресбара)
|
|
|
|
|
allApplyFiles = self.scanProfiles(False, dirObjs)
|
|
|
|
|
if allApplyFiles == False:
|
|
|
|
|
return False
|
|
|
|
|
numberAllProfiles = len(allApplyFiles)
|
|
|
|
|
# Вызываем пустой метод с параметром общее количество профилей
|
|
|
|
|
self.numberAllProfiles(numberAllProfiles)
|
|
|
|
|
# номер обрабатываемого файла
|
|
|
|
|
numberProcessProfiles = 0
|
|
|
|
|
# имя текущей программы
|
|
|
|
|
_nameProgram = self.objVar.Get("cl_name").capitalize()
|
|
|
|
|
# версия текущей программы
|
|
|
|
|
_versionProgram = self.objVar.Get("cl_ver")
|
|
|
|
|
# имя и версия текущей программы
|
|
|
|
|
programVersion = "%s %s"%(_nameProgram, _versionProgram)
|
|
|
|
|
dirObjsApply = []
|
|
|
|
|
for dirObj in dirObjs:
|
|
|
|
|
dirInfoFile = os.path.join(dirObj.baseDir, self.profDirNameFile)
|
|
|
|
|
ret = self.__isApplyHeadDir(dirInfoFile)
|
|
|
|
|
if ret:
|
|
|
|
|
dirObjsApply.append(dirObj)
|
|
|
|
|
else:
|
|
|
|
|
if self.getError():
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
dirInfoFile)
|
|
|
|
|
return False
|
|
|
|
|
for dirObj in dirObjsApply:
|
|
|
|
|
# сортируем файлы по названию
|
|
|
|
|
if dirObj.files:
|
|
|
|
|
dirObj.files.sort()
|
|
|
|
|
# сортируем директории по названию
|
|
|
|
|
if dirObj.dirs:
|
|
|
|
|
dirObj.dirs.sort()
|
|
|
|
|
blockDirs = []
|
|
|
|
|
for dirProfile in dirObj.dirs:
|
|
|
|
|
newDir = self._baseDir + dirProfile.partition(dirObj.baseDir)[2]
|
|
|
|
|
newDir = "/".join(map(lambda x:x.split("?")[0],\
|
|
|
|
|
newDir.split("/")))
|
|
|
|
|
# Проверяем условие на директорию
|
|
|
|
|
dirInfoFile = os.path.join(dirProfile, self.profDirNameFile)
|
|
|
|
|
pathDir, objHeadDir = self.__getApplyHeadDir(newDir,
|
|
|
|
|
dirInfoFile,
|
|
|
|
|
changeDirs)
|
|
|
|
|
# Фильтрация профилей по названию директории
|
|
|
|
|
if pathDir in self.dirsFilter:
|
|
|
|
|
blockDirs.append(dirProfile)
|
|
|
|
|
continue
|
|
|
|
|
if objHeadDir:
|
|
|
|
|
if isinstance(objHeadDir, dirHeader):
|
|
|
|
|
if not objHeadDir.headerCorrect:
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
dirInfoFile)
|
|
|
|
|
self.setError(objHeadDir.errorMessage)
|
|
|
|
|
return False
|
|
|
|
|
if not objHeadDir.headerTerm:
|
|
|
|
|
if objHeadDir.getError():
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
dirInfoFile)
|
|
|
|
|
return False
|
|
|
|
|
if objHeadDir.params.has_key("name"):
|
|
|
|
|
changeDirs[dirProfile] = pathDir
|
|
|
|
|
crDirs = self.createDir(dirObj.baseDir, dirProfile,
|
|
|
|
|
self._baseDir, pathDir)
|
|
|
|
|
if crDirs == False:
|
|
|
|
|
return False
|
|
|
|
|
createdDirs += crDirs
|
|
|
|
|
else:
|
|
|
|
|
if self.getError():
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
dirInfoFile)
|
|
|
|
|
return False
|
|
|
|
|
blockDirs.append(dirProfile)
|
|
|
|
|
for fileProfile in dirObj.files:
|
|
|
|
|
findBlock = False
|
|
|
|
|
for blDir in blockDirs:
|
|
|
|
|
st,mid,end = fileProfile.partition(blDir)
|
|
|
|
|
if (not st) and mid and end:
|
|
|
|
|
findBlock = True
|
|
|
|
|
break
|
|
|
|
|
if findBlock:
|
|
|
|
|
continue
|
|
|
|
|
numberProcessProfiles += 1
|
|
|
|
|
self.numberProcessProfiles(numberProcessProfiles)
|
|
|
|
|
if self.getNeedProfile(fileProfile):
|
|
|
|
|
if self.getError():
|
|
|
|
|
#print self.getError()
|
|
|
|
|
return False
|
|
|
|
|
fileProfileChange = fileProfile
|
|
|
|
|
findChangeDir = False
|
|
|
|
|
listD = changeDirs.items()
|
|
|
|
|
listD.reverse()
|
|
|
|
|
for dirChangeIn, dirChangeOut in listD:
|
|
|
|
|
st,mid,end = fileProfile.partition(dirChangeIn)
|
|
|
|
|
if (not st) and mid and end:
|
|
|
|
|
findChangeDir = True
|
|
|
|
|
break
|
|
|
|
|
if findChangeDir:
|
|
|
|
|
oldFile = dirChangeOut + end
|
|
|
|
|
else:
|
|
|
|
|
oldFile = fileProfile.partition(dirObj.baseDir)[2]
|
|
|
|
|
# файл в системе без условий
|
|
|
|
|
oldFile = "/".join(map(lambda x:x.split("?")[0],\
|
|
|
|
|
oldFile.split("/")))
|
|
|
|
|
if not findChangeDir:
|
|
|
|
|
oldFile = self._baseDir + oldFile
|
|
|
|
|
# Фильтрация профилей по названию файла
|
|
|
|
|
if oldFile in self.filesFilter:
|
|
|
|
|
continue
|
|
|
|
|
listProfTitle = dirObj.baseDir.split("/")[-2:]
|
|
|
|
|
profTitle = '"' + "/".join(listProfTitle) + '"'
|
|
|
|
|
# Записываем в переменную обрабатываемый файл
|
|
|
|
|
self.objVar.Set("cl_pass_file",oldFile)
|
|
|
|
|
filesApl = self.join(fileProfile, oldFile,
|
|
|
|
|
(programVersion,profTitle))
|
|
|
|
|
if filesApl:
|
|
|
|
|
filesApply += filesApl
|
|
|
|
|
else:
|
|
|
|
|
if self.getError():
|
|
|
|
|
#print self.getError()
|
|
|
|
|
return False
|
|
|
|
|
self.closeFiles()
|
|
|
|
|
return (createdDirs, filesApply)
|
|
|
|
|
|
|
|
|
|
def __getGenHeadDir(self, newDir, profileDirFile, changeDirs):
|
|
|
|
|
"""Определяет название создаваемой директории"""
|
|
|
|
|
|
|
|
|
|
def function(text):
|
|
|
|
|
"""Функция обработки функций в заголовке"""
|
|
|
|
|
return self.applyFuncProfile(text, newDir, profileDirFile)
|
|
|
|
|
|
|
|
|
|
newDirMv = newDir
|
|
|
|
|
findChangeDir = False
|
|
|
|
|
#Меняем путь к директории
|
|
|
|
|
listD = changeDirs.items()
|
|
|
|
|
listD.reverse()
|
|
|
|
|
for dirChangeIn, dirChangeOut in listD:
|
|
|
|
|
st,mid,end = profileDirFile.partition(dirChangeIn)
|
|
|
|
|
if (not st) and mid:
|
|
|
|
|
findChangeDir = True
|
|
|
|
|
break
|
|
|
|
|
if findChangeDir:
|
|
|
|
|
pathRel = dirChangeOut
|
|
|
|
|
lenPathRel = len(pathRel.split("/"))
|
|
|
|
|
lenNewDir = len(newDir.split("/"))
|
|
|
|
|
lenEndDir = lenNewDir - lenPathRel
|
|
|
|
|
tmpDir = newDir
|
|
|
|
|
namesDirs = []
|
|
|
|
|
for i in range(lenEndDir):
|
|
|
|
|
namesDirs.append(os.path.split(tmpDir)[1])
|
|
|
|
|
tmpDir = os.path.split(tmpDir)[0]
|
|
|
|
|
namesDirs.reverse()
|
|
|
|
|
nameDir = "/".join(namesDirs)
|
|
|
|
|
newDirMv = os.path.join(pathRel, nameDir)
|
|
|
|
|
applyDir = newDirMv
|
|
|
|
|
if not os.path.exists(profileDirFile):
|
|
|
|
|
return (applyDir, True)
|
|
|
|
|
try:
|
|
|
|
|
FD = open(profileDirFile)
|
|
|
|
|
textProfile = FD.read()
|
|
|
|
|
FD.close()
|
|
|
|
|
except:
|
|
|
|
|
self.setError(_("Error open profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return (applyDir, False)
|
|
|
|
|
objHead = dirHeader(textProfile, self.objVar,function)
|
|
|
|
|
if not objHead.headerCorrect:
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
self.setError(objHead.errorMessage)
|
|
|
|
|
return (applyDir, False)
|
|
|
|
|
if not objHead.headerTerm:
|
|
|
|
|
if objHead.getError():
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return (applyDir, False)
|
|
|
|
|
# Изменяем название директории
|
|
|
|
|
if objHead.params.has_key("name"):
|
|
|
|
|
nameDir = objHead.params['name']
|
|
|
|
|
if "/" in nameDir or nameDir == ".." or nameDir == ".":
|
|
|
|
|
self.setError (_("False value 'name' in profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return (applyDir, False)
|
|
|
|
|
if not findChangeDir:
|
|
|
|
|
pathRel = os.path.split(os.path.abspath(newDirMv))[0]
|
|
|
|
|
# Новый путь к оригинальному файлу
|
|
|
|
|
newDirMv = os.path.join(pathRel, nameDir)
|
|
|
|
|
applyDir = newDirMv
|
|
|
|
|
# При удаленнии директории
|
|
|
|
|
if objHead.typeAppend == "remove":
|
|
|
|
|
return (applyDir, False)
|
|
|
|
|
return (applyDir, objHead)
|
|
|
|
|
|
|
|
|
|
def scanProfiles(self, serviceName=False, dirObjs=False):
|
|
|
|
|
"""Сканирует директории профилей - выводит список файлов"""
|
|
|
|
|
if not self.objVar.defined("cl_profile_path"):
|
|
|
|
|
self.setError (_("not defined Var: ") + "cl_profile_path")
|
|
|
|
|
return False
|
|
|
|
|
if not dirObjs:
|
|
|
|
|
if serviceName :
|
|
|
|
|
self._servDir = serviceName
|
|
|
|
|
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]
|
|
|
|
|
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,self.objVar)
|
|
|
|
|
#файлы к которым были применены профили
|
|
|
|
|
filesApply = []
|
|
|
|
|
# Словарь измененных директорий
|
|
|
|
|
changeDirs = {}
|
|
|
|
|
dirObjsApply = []
|
|
|
|
|
for dirObj in dirObjs:
|
|
|
|
|
dirInfoFile = os.path.join(dirObj.baseDir, self.profDirNameFile)
|
|
|
|
|
ret = self.__isApplyHeadDir(dirInfoFile)
|
|
|
|
|
if ret:
|
|
|
|
|
dirObjsApply.append(dirObj)
|
|
|
|
|
else:
|
|
|
|
|
if self.getError():
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
dirInfoFile)
|
|
|
|
|
return False
|
|
|
|
|
for dirObj in dirObjsApply:
|
|
|
|
|
# сортируем файлы по названию
|
|
|
|
|
if dirObj.files:
|
|
|
|
|
dirObj.files.sort()
|
|
|
|
|
# сортируем директории по названию
|
|
|
|
|
if dirObj.dirs:
|
|
|
|
|
dirObj.dirs.sort()
|
|
|
|
|
blockDirs = []
|
|
|
|
|
for dirProfile in dirObj.dirs:
|
|
|
|
|
newDir = self._baseDir + dirProfile.partition(dirObj.baseDir)[2]
|
|
|
|
|
newDir = "/".join(map(lambda x:x.split("?")[0],\
|
|
|
|
|
newDir.split("/")))
|
|
|
|
|
# Проверяем условие на директорию
|
|
|
|
|
dirInfoFile = os.path.join(dirProfile, self.profDirNameFile)
|
|
|
|
|
pathDir, objHeadDir = self.__getGenHeadDir(newDir,
|
|
|
|
|
dirInfoFile,
|
|
|
|
|
changeDirs)
|
|
|
|
|
# Фильтрация профилей по названию директории
|
|
|
|
|
if pathDir in self.dirsFilter:
|
|
|
|
|
blockDirs.append(dirProfile)
|
|
|
|
|
continue
|
|
|
|
|
if objHeadDir:
|
|
|
|
|
if isinstance(objHeadDir, dirHeader):
|
|
|
|
|
if not objHeadDir.headerCorrect:
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
dirInfoFile)
|
|
|
|
|
self.setError(objHeadDir.errorMessage)
|
|
|
|
|
return False
|
|
|
|
|
if not objHeadDir.headerTerm:
|
|
|
|
|
if objHeadDir.getError():
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
dirInfoFile)
|
|
|
|
|
return False
|
|
|
|
|
if objHeadDir.params.has_key("name"):
|
|
|
|
|
changeDirs[dirProfile] = pathDir
|
|
|
|
|
else:
|
|
|
|
|
if self.getError():
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
dirInfoFile)
|
|
|
|
|
return False
|
|
|
|
|
blockDirs.append(dirProfile)
|
|
|
|
|
for fileProfile in dirObj.files:
|
|
|
|
|
findBlock = False
|
|
|
|
|
for blDir in blockDirs:
|
|
|
|
|
st,mid,end = fileProfile.partition(blDir)
|
|
|
|
|
if (not st) and mid and end:
|
|
|
|
|
findBlock = True
|
|
|
|
|
break
|
|
|
|
|
if findBlock:
|
|
|
|
|
continue
|
|
|
|
|
if self.getNeedProfile(fileProfile):
|
|
|
|
|
if self.getError():
|
|
|
|
|
#print self.getError()
|
|
|
|
|
return False
|
|
|
|
|
fileProfileChange = fileProfile
|
|
|
|
|
findChangeDir = False
|
|
|
|
|
listD = changeDirs.items()
|
|
|
|
|
listD.reverse()
|
|
|
|
|
for dirChangeIn, dirChangeOut in listD:
|
|
|
|
|
st,mid,end = fileProfile.partition(dirChangeIn)
|
|
|
|
|
if (not st) and mid and end:
|
|
|
|
|
findChangeDir = True
|
|
|
|
|
break
|
|
|
|
|
if findChangeDir:
|
|
|
|
|
oldFile = dirChangeOut + end
|
|
|
|
|
else:
|
|
|
|
|
oldFile = fileProfile.partition(dirObj.baseDir)[2]
|
|
|
|
|
# файл в системе без условий
|
|
|
|
|
oldFile = "/".join(map(lambda x:x.split("?")[0],\
|
|
|
|
|
oldFile.split("/")))
|
|
|
|
|
if not findChangeDir:
|
|
|
|
|
oldFile = self._baseDir + oldFile
|
|
|
|
|
# Фильтрация профилей по названию файла
|
|
|
|
|
if oldFile in self.filesFilter:
|
|
|
|
|
continue
|
|
|
|
|
filesApply.append(oldFile)
|
|
|
|
|
else:
|
|
|
|
|
if self.getError():
|
|
|
|
|
return False
|
|
|
|
|
return filesApply
|
|
|
|
|
|
|
|
|
|
def __isApplyHeadDir(self, profileDirFile):
|
|
|
|
|
"""Будет ли применен профиль корневой директории
|
|
|
|
|
|
|
|
|
|
Возвращает True, False
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def function(text):
|
|
|
|
|
"""Функция обработки функций в заголовке"""
|
|
|
|
|
return self.applyFuncProfile(text, "", profileDirFile)
|
|
|
|
|
|
|
|
|
|
if not os.path.exists(profileDirFile):
|
|
|
|
|
return True
|
|
|
|
|
try:
|
|
|
|
|
FD = open(profileDirFile)
|
|
|
|
|
textProfile = FD.read()
|
|
|
|
|
FD.close()
|
|
|
|
|
except:
|
|
|
|
|
self.setError(_("Error open profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return False
|
|
|
|
|
# Заменяем переменные на их значения
|
|
|
|
|
textProfile = self.applyVarsProfile(textProfile, profileDirFile)
|
|
|
|
|
# Обработка заголовка
|
|
|
|
|
objHead = dirHeader(textProfile, self.objVar,function)
|
|
|
|
|
if not objHead.headerCorrect:
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
self.setError(objHead.errorMessage)
|
|
|
|
|
return False
|
|
|
|
|
if not objHead.headerTerm:
|
|
|
|
|
if objHead.getError():
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
# Изменяем название директории
|
|
|
|
|
if objHead.params.has_key("name"):
|
|
|
|
|
self.setError (_("Invalid name 'name' in profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
# Удаляем директорию
|
|
|
|
|
if objHead.typeAppend == "remove":
|
|
|
|
|
self.setError (_("Invalid name 'remove' in profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
# chmod - изменяем права
|
|
|
|
|
if objHead.params.has_key("chmod"):
|
|
|
|
|
self.setError (_("Invalid name 'chmod' in profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
# chown - изменяем владельца и группу
|
|
|
|
|
if objHead.params.has_key("chown"):
|
|
|
|
|
self.setError (_("Invalid name 'chown' in profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def __getApplyHeadDir(self, newDir, profileDirFile, changeDirs):
|
|
|
|
|
"""Применяет профиль к директории (права, владелец, и.т. д)"""
|
|
|
|
|
|
|
|
|
|
def function(text):
|
|
|
|
|
"""Функция обработки функций в заголовке"""
|
|
|
|
|
return self.applyFuncProfile(text, newDir, profileDirFile)
|
|
|
|
|
|
|
|
|
|
newDirMv = newDir
|
|
|
|
|
findChangeDir = False
|
|
|
|
|
#Меняем путь к директории
|
|
|
|
|
listD = changeDirs.items()
|
|
|
|
|
listD.reverse()
|
|
|
|
|
for dirChangeIn, dirChangeOut in listD:
|
|
|
|
|
st,mid,end = profileDirFile.partition(dirChangeIn)
|
|
|
|
|
if (not st) and mid:
|
|
|
|
|
findChangeDir = True
|
|
|
|
|
break
|
|
|
|
|
if findChangeDir:
|
|
|
|
|
pathRel = dirChangeOut
|
|
|
|
|
lenPathRel = len(pathRel.split("/"))
|
|
|
|
|
lenNewDir = len(newDir.split("/"))
|
|
|
|
|
lenEndDir = lenNewDir - lenPathRel
|
|
|
|
|
tmpDir = newDir
|
|
|
|
|
namesDirs = []
|
|
|
|
|
for i in range(lenEndDir):
|
|
|
|
|
namesDirs.append(os.path.split(tmpDir)[1])
|
|
|
|
|
tmpDir = os.path.split(tmpDir)[0]
|
|
|
|
|
namesDirs.reverse()
|
|
|
|
|
nameDir = "/".join(namesDirs)
|
|
|
|
|
newDirMv = os.path.join(pathRel, nameDir)
|
|
|
|
|
applyDir = newDirMv
|
|
|
|
|
if not os.path.exists(profileDirFile):
|
|
|
|
|
return (applyDir, True)
|
|
|
|
|
try:
|
|
|
|
|
FD = open(profileDirFile)
|
|
|
|
|
textProfile = FD.read()
|
|
|
|
|
FD.close()
|
|
|
|
|
except:
|
|
|
|
|
self.setError(_("Error open profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return (applyDir, False)
|
|
|
|
|
# Заменяем переменные на их значения
|
|
|
|
|
textProfile = self.applyVarsProfile(textProfile, profileDirFile)
|
|
|
|
|
# Обработка заголовка
|
|
|
|
|
objHead = dirHeader(textProfile, self.objVar,function)
|
|
|
|
|
if not objHead.headerCorrect:
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
self.setError(objHead.errorMessage)
|
|
|
|
|
return (applyDir, False)
|
|
|
|
|
if not objHead.headerTerm:
|
|
|
|
|
if objHead.getError():
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return (applyDir, False)
|
|
|
|
|
|
|
|
|
|
# Изменяем название директории
|
|
|
|
|
if objHead.params.has_key("name"):
|
|
|
|
|
nameDir = objHead.params['name']
|
|
|
|
|
if "/" in nameDir or nameDir == ".." or nameDir == ".":
|
|
|
|
|
self.setError (_("False value 'name' in profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return (applyDir, False)
|
|
|
|
|
if not findChangeDir:
|
|
|
|
|
pathRel = os.path.split(os.path.abspath(newDirMv))[0]
|
|
|
|
|
# Новый путь к оригинальному файлу
|
|
|
|
|
newDirMv = os.path.join(pathRel, nameDir)
|
|
|
|
|
applyDir = newDirMv
|
|
|
|
|
|
|
|
|
|
# Удаляем директорию
|
|
|
|
|
if objHead.typeAppend == "remove":
|
|
|
|
|
if os.path.isdir(newDirMv):
|
|
|
|
|
# удаляем директорию
|
|
|
|
|
try:
|
|
|
|
|
self.removeDir(newDirMv)
|
|
|
|
|
except:
|
|
|
|
|
self.setError(_("Can not delete dir: " ) +\
|
|
|
|
|
newDirMv)
|
|
|
|
|
return (applyDir, False)
|
|
|
|
|
|
|
|
|
|
# chmod - изменяем права
|
|
|
|
|
if objHead.params.has_key("chmod"):
|
|
|
|
|
mode = self.__octToInt(objHead.params['chmod'])
|
|
|
|
|
if mode:
|
|
|
|
|
if not os.path.exists(newDirMv):
|
|
|
|
|
os.mkdir(newDirMv, mode)
|
|
|
|
|
else:
|
|
|
|
|
os.chmod(newDirMv, mode)
|
|
|
|
|
else:
|
|
|
|
|
self.setError (_("False value 'chmod' in profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return (applyDir, False)
|
|
|
|
|
# chown - изменяем владельца и группу
|
|
|
|
|
if objHead.params.has_key("chown"):
|
|
|
|
|
owner = objHead.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: " )+\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return (applyDir, 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: " )+\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return (applyDir, False)
|
|
|
|
|
|
|
|
|
|
if not os.path.exists(newDirMv):
|
|
|
|
|
dirProfile = os.path.split(profileDirFile)[0]
|
|
|
|
|
try:
|
|
|
|
|
mode,uidTmp,gidTmp = self.getModeFile(dirProfile)
|
|
|
|
|
except OSError:
|
|
|
|
|
self.setError (_("not access dir:" ) + newDirMv)
|
|
|
|
|
return (applyDir, False)
|
|
|
|
|
os.mkdir(newDirMv, mode)
|
|
|
|
|
os.chown(newDirMv, uid, gid)
|
|
|
|
|
else:
|
|
|
|
|
self.setError (_("False value 'chown' in profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return (applyDir, False)
|
|
|
|
|
else:
|
|
|
|
|
self.setError (_("False value 'chown' in profile: " ) +\
|
|
|
|
|
profileDirFile)
|
|
|
|
|
return (applyDir, False)
|
|
|
|
|
return (applyDir, objHead)
|
|
|
|
|
|
|
|
|
|
def __getApplyHeadProfile(self ,newFile, oldFile, copyFile):
|
|
|
|
|
"""Применяет заголовок к профилю (права, владелец, и.т. д)"""
|
|
|
|
|
|
|
|
|
|
def function(text):
|
|
|
|
|
"""Функция обработки функций в заголовке"""
|
|
|
|
|
return self.applyFuncProfile(text, newFile, oldFile)
|
|
|
|
|
|
|
|
|
|
self.closeFiles()
|
|
|
|
|
# Файлы в системе к которым были применены профили
|
|
|
|
|
applyFiles = [oldFile]
|
|
|
|
|
if copyFile:
|
|
|
|
|
self.nameFileNew = self.absFileName(newFile)
|
|
|
|
|
self.FN = self.openNewFile(self.nameFileNew)
|
|
|
|
|
self.newProfile = self.FN.read()
|
|
|
|
|
self.closeNewFile()
|
|
|
|
|
objHeadNew = fileHeader(self.newProfile, False,
|
|
|
|
|
self.getFileType(),objVar=self.objVar,
|
|
|
|
|
function=function)
|
|
|
|
|
if not objHeadNew.headerCorrect:
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
newFile)
|
|
|
|
|
self.setError(objHeadNew.errorMessage)
|
|
|
|
|
return (applyFiles, False)
|
|
|
|
|
if not objHeadNew.headerTerm:
|
|
|
|
|
if objHeadNew.getError():
|
|
|
|
|
self.setError(_("Incorrect profile: " ) +\
|
|
|
|
|
newFile)
|
|
|
|
|
return (applyFiles, False)
|
|
|
|
|
|
|
|
|
|
pathProg = ""
|
|
|
|
|
# Путь к оригинальному файлу
|
|
|
|
|
pathOldFile = oldFile
|
|
|
|
|
# Изменяем путь к оригинальному файлу
|
|
|
|
|
if objHeadNew.params.has_key("name"):
|
|
|
|
|
nameFile = objHeadNew.params['name']
|
|
|
|
|
if "/" in nameFile or nameFile == ".." or nameFile == ".":
|
|
|
|
|
self.setError (_("False value 'name' in profile: " ) + newFile)
|
|
|
|
|
return False
|
|
|
|
|
pathRel = os.path.split(os.path.abspath(oldFile))[0]
|
|
|
|
|
# Новый путь к оригинальному файлу
|
|
|
|
|
pathOldFile = os.path.join(pathRel,nameFile)
|
|
|
|
|
|
|
|
|
|
# В случае force
|
|
|
|
|
if objHeadNew.params.has_key("force"):
|
|
|
|
|
if os.path.islink(pathOldFile):
|
|
|
|
|
# удаляем ссылку
|
|
|
|
|
try:
|
|
|
|
|
os.unlink(pathOldFile)
|
|
|
|
|
except:
|
|
|
|
|
self.setError(_("Can not delete link: " ) +\
|
|
|
|
|
pathOldFile)
|
|
|
|
|
return (applyFiles, False)
|
|
|
|
|
if os.path.isfile(pathOldFile):
|
|
|
|
|
# удаляем файл
|
|
|
|
|
try:
|
|
|
|
|
os.remove(pathOldFile)
|
|
|
|
|
except:
|
|
|
|
|
self.setError(_("Can not delete file: " ) +\
|
|
|
|
|
pathOldFile)
|
|
|
|
|
return (applyFiles, False)
|
|
|
|
|
|
|
|
|
|
# Удаляем оригинальный файл
|
|
|
|
|
if objHeadNew.typeAppend == "remove":
|
|
|
|
|
if os.path.islink(pathOldFile):
|
|
|
|
|
# удаляем ссылку
|
|
|
|
|
try:
|
|
|
|
|
os.unlink(pathOldFile)
|
|
|
|
|
except:
|
|
|
|
|
self.setError(_("Can not delete link: " ) +\
|
|
|
|
|
pathOldFile)
|
|
|
|
|
if os.path.isfile(pathOldFile):
|
|
|
|
|
# удаляем файл
|
|
|
|
|
try:
|
|
|
|
|
os.remove(pathOldFile)
|
|
|
|
|
except:
|
|
|
|
|
self.setError(_("Can not delete file: " ) +\
|
|
|
|
|
pathOldFile)
|
|
|
|
|
return (applyFiles, False)
|
|
|
|
|
|
|
|
|
|
flagSymlink = False
|
|
|
|
|
flagForce = False
|
|
|
|
|
# Если есть параметр mirror
|
|
|
|
|
if objHeadNew.params.has_key("mirror"):
|
|
|
|
|
if objHeadNew.params.has_key("link"):
|
|
|
|
|
profileFile = objHeadNew.params['link']
|
|
|
|
|
if not os.path.exists(profileFile):
|
|
|
|
|
if os.path.exists(pathOldFile):
|
|
|
|
|
os.remove(pathOldFile)
|
|
|
|
|
return (applyFiles, False)
|
|
|
|
|
elif not os.path.exists(pathOldFile):
|
|
|
|
|
return (applyFiles, False)
|
|
|
|
|
# Если есть указатель на файл профиля (link)
|
|
|
|
|
if objHeadNew.params.has_key("link") and\
|
|
|
|
|
not objHeadNew.params.has_key("symbolic"):
|
|
|
|
|
profileFile = objHeadNew.params['link']
|
|
|
|
|
foundProfileFile = os.path.exists(profileFile)
|
|
|
|
|
if foundProfileFile:
|
|
|
|
|
FO = self.openNewFile(profileFile)
|
|
|
|
|
buff = FO.read()
|
|
|
|
|
FO.close()
|
|
|
|
|
if os.path.exists(pathOldFile):
|
|
|
|
|
os.remove(pathOldFile)
|
|
|
|
|
if foundProfileFile:
|
|
|
|
|
fd = os.open(pathOldFile, os.O_CREAT)
|
|
|
|
|
os.close(fd)
|
|
|
|
|
os.chmod(pathOldFile, self._mode)
|
|
|
|
|
os.chown(pathOldFile, self._uid, self._gid)
|
|
|
|
|
FON = open (pathOldFile, "r+")
|
|
|
|
|
FON.write(buff)
|
|
|
|
|
FON.close()
|
|
|
|
|
|
|
|
|
|
# Если символическая ссылка
|
|
|
|
|
if objHeadNew.params.has_key("symbolic"):
|
|
|
|
|
prevOldFile = pathOldFile
|
|
|
|
|
pathOldFile = objHeadNew.params['link']
|
|
|
|
|
flagSymlink = True
|
|
|
|
|
if not "/" == pathOldFile[0]:
|
|
|
|
|
pathLink = os.path.split(os.path.abspath(prevOldFile))[0]
|
|
|
|
|
pathProg = os.getcwd()
|
|
|
|
|
os.chdir(pathLink)
|
|
|
|
|
|
|
|
|
|
# chmod - изменяем права
|
|
|
|
|
if objHeadNew.params.has_key("chmod"):
|
|
|
|
|
mode = self.__octToInt(objHeadNew.params['chmod'])
|
|
|
|
|
if mode:
|
|
|
|
|
if not os.path.exists(pathOldFile):
|
|
|
|
|
fd = os.open(pathOldFile, os.O_CREAT)
|
|
|
|
|
os.close(fd)
|
|
|
|
|
os.chmod(pathOldFile, mode)
|
|
|
|
|
else:
|
|
|
|
|
self.setError (_("False value 'chmod' in profile: " ) +\
|
|
|
|
|
newFile)
|
|
|
|
|
return (applyFiles, False)
|
|
|
|
|
|
|
|
|
|
# chown - изменяем владельца и группу
|
|
|
|
|
if objHeadNew.params.has_key("chown"):
|
|
|
|
|
owner = objHeadNew.params['chown']
|
|
|
|
|
if owner:
|
|
|
|
|
if ":" in owner:
|
|
|
|
|
strUid, strGid = owner.split(":")
|
|
|
|
|
import pwd
|
|
|
|
|
try:
|
|
|
|
|
uid = pwd.getpwnam(strUid)[2]
|
|
|
|
|
except:
|
|
|
|
|
self.setError (_("Not user in this system: ") + strUid)
|
|
|
|
|
self.setError (_("False value 'chown' in profile: " )+\
|
|
|
|
|
newFile)
|
|
|
|
|
return (applyFiles, 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 (applyFiles, False)
|
|
|
|
|
|
|
|
|
|
if not os.path.exists(pathOldFile):
|
|
|
|
|
FO = self.openNewFile(newFile)
|
|
|
|
|
FO.close()
|
|
|
|
|
fd = os.open(pathOldFile, os.O_CREAT)
|
|
|
|
|
os.close(fd)
|
|
|
|
|
os.chmod(pathOldFile, self._mode)
|
|
|
|
|
os.chown(pathOldFile, uid, gid)
|
|
|
|
|
else:
|
|
|
|
|
self.setError (_("False value 'chown' in profile: " ) +\
|
|
|
|
|
newFile)
|
|
|
|
|
return (applyFiles, False)
|
|
|
|
|
else:
|
|
|
|
|
self.setError (_("False value 'chown' in profile: " ) +\
|
|
|
|
|
newFile)
|
|
|
|
|
return (applyFiles, False)
|
|
|
|
|
|
|
|
|
|
self.openFiles(newFile, pathOldFile)
|
|
|
|
|
if flagSymlink:
|
|
|
|
|
if os.path.exists(prevOldFile) or os.path.islink(prevOldFile):
|
|
|
|
|
if os.path.islink(prevOldFile):
|
|
|
|
|
# если ссылка то удаляем её
|
|
|
|
|
os.unlink(prevOldFile)
|
|
|
|
|
else:
|
|
|
|
|
# иначе удаляем файл
|
|
|
|
|
os.remove(prevOldFile)
|
|
|
|
|
if not "/" == pathOldFile[0]:
|
|
|
|
|
os.symlink(pathOldFile, prevOldFile)
|
|
|
|
|
applyFiles = [prevOldFile,os.path.join(pathLink,pathOldFile)]
|
|
|
|
|
else:
|
|
|
|
|
os.symlink(pathOldFile, prevOldFile)
|
|
|
|
|
applyFiles = [prevOldFile,pathOldFile]
|
|
|
|
|
if not objHeadNew.body.strip():
|
|
|
|
|
return (applyFiles, False)
|
|
|
|
|
else:
|
|
|
|
|
applyFiles = [pathOldFile]
|
|
|
|
|
if pathProg:
|
|
|
|
|
os.chdir(pathProg)
|
|
|
|
|
# Если файлы заменяются не нужно их обрабатывать дальше
|
|
|
|
|
if objHeadNew.typeAppend == "replace" and\
|
|
|
|
|
not objHeadNew.params.has_key("symbolic") and\
|
|
|
|
|
objHeadNew.params.has_key("link"):
|
|
|
|
|
return (applyFiles, False)
|
|
|
|
|
return (applyFiles, objHeadNew)
|
|
|
|
|
|
|
|
|
|
def createNewClass(self, name, bases, attrs={}):
|
|
|
|
|
"""Создает объект нового класса
|
|
|
|
|
|
|
|
|
|
createNewClass(self, name, bases, attrs)
|
|
|
|
|
name - имя класса - str,
|
|
|
|
|
bases - cписок наследуемых классов - (tuple),
|
|
|
|
|
attrs - аттрибуты класса - {dict}
|
|
|
|
|
"""
|
|
|
|
|
class newMethod:
|
|
|
|
|
#Объединяем конфигурации
|
|
|
|
|
def join(self, newObj):
|
|
|
|
|
if newObj.__class__.__name__ == self.__class__.__name__:
|
|
|
|
|
self.docObj.joinDoc(newObj.doc)
|
|
|
|
|
# Пост обработка
|
|
|
|
|
if 'postXML' in dir(self):
|
|
|
|
|
self.postXML()
|
|
|
|
|
attrsNew = {}
|
|
|
|
|
attrsNew["configName"] = name
|
|
|
|
|
if attrs:
|
|
|
|
|
for key in attrs.keys():
|
|
|
|
|
attrsNew[key] = attrs[key]
|
|
|
|
|
newCl = type(name, bases + (newMethod, object,), attrsNew)
|
|
|
|
|
return newCl
|
|
|
|
|
|
|
|
|
|
def fileIsUtf(self, fileName):
|
|
|
|
|
"""Проверяет файл на кодировку UTF-8"""
|
|
|
|
|
if os.path.exists(fileName):
|
|
|
|
|
FD = open(self.absFileName(fileName))
|
|
|
|
|
newProfile = FD.read()
|
|
|
|
|
FD.close()
|
|
|
|
|
try:
|
|
|
|
|
newProfile.decode("UTF-8")
|
|
|
|
|
except:
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def join(self, newFile, oldFile, ListOptTitle):
|
|
|
|
|
"""Объединения профиля и конф. файла
|
|
|
|
|
|
|
|
|
|
join(newFile, oldFile, ListOptTitle)
|
|
|
|
|
Объединение профиля newFile и конф. файла oldFile,
|
|
|
|
|
ListOptTitle - список строк которые добавятся в заголовок
|
|
|
|
|
"""
|
|
|
|
|
# Выполняем условия для блока текста а так-же заменяем переменные
|
|
|
|
|
self.nameFileNew = self.absFileName(newFile)
|
|
|
|
|
self.FN = self.openNewFile(self.nameFileNew)
|
|
|
|
|
self.newProfile = self.FN.read()
|
|
|
|
|
self.closeNewFile()
|
|
|
|
|
copyFile = True
|
|
|
|
|
if self.getFileType() != "bin":
|
|
|
|
|
# Вычисляем условные блоки
|
|
|
|
|
self.newProfile = self.applyTermsProfile(self.newProfile,
|
|
|
|
|
newFile, oldFile)
|
|
|
|
|
#print "|%s|" %(self.newProfile)
|
|
|
|
|
# Заменяем переменные на их значения
|
|
|
|
|
self.newProfile = self.applyVarsProfile(self.newProfile,
|
|
|
|
|
newFile)
|
|
|
|
|
# Вычисляем функции
|
|
|
|
|
self.newProfile = self.applyFuncProfile(self.newProfile,
|
|
|
|
|
newFile, oldFile)
|
|
|
|
|
copyFile = False
|
|
|
|
|
filesApply, objHeadNew = self.__getApplyHeadProfile(newFile, oldFile,
|
|
|
|
|
copyFile)
|
|
|
|
|
if not objHeadNew:
|
|
|
|
|
return filesApply
|
|
|
|
|
# Флаг - кодировка с бинарными примесями у файла профиля включаем при
|
|
|
|
|
# условии текстового файла и кодировки отличной от UTF-8
|
|
|
|
|
flagNotUtf8New = False
|
|
|
|
|
# Флаг - кодировка с бинарными примесями у оригинального файла
|
|
|
|
|
flagNotUtf8Old = False
|
|
|
|
|
if not copyFile:
|
|
|
|
|
# проверяем кодировку профиля
|
|
|
|
|
if not self.fileIsUtf(newFile):
|
|
|
|
|
flagNotUtf8New = True
|
|
|
|
|
if not (objHeadNew.params.has_key("link") and\
|
|
|
|
|
objHeadNew.params.has_key("symbolic")):
|
|
|
|
|
# проверяем кодировку оригинального файла
|
|
|
|
|
if not self.fileIsUtf(oldFile):
|
|
|
|
|
flagNotUtf8Old = 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 = fileHeader(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"):
|
|
|
|
|
# Преобразовываем бинарные файлы
|
|
|
|
|
if flagNotUtf8New:
|
|
|
|
|
objTxtCoder = utfBin()
|
|
|
|
|
self.newProfile = objTxtCoder.encode(self.newProfile)
|
|
|
|
|
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 "xml_" in objHeadNew.fileType:
|
|
|
|
|
if objProfNew.getError():
|
|
|
|
|
self.setError (_("False profile: " ) + newFile)
|
|
|
|
|
return False
|
|
|
|
|
nameRootNode = oldFile.rpartition("/")[2].split(".")[0]
|
|
|
|
|
objProfNew.setNameBodyNode(nameRootNode)
|
|
|
|
|
# Объект Документ
|
|
|
|
|
docObj = objProfNew.docObj
|
|
|
|
|
# Удаление комментариев из документа
|
|
|
|
|
docObj.removeComment(docObj.getNodeBody())
|
|
|
|
|
# Добавление необходимых переводов строк
|
|
|
|
|
docObj.insertBRtoBody(docObj.getNodeBody())
|
|
|
|
|
# Добавление необходимых разделителей между областями
|
|
|
|
|
docObj.insertBeforeSepAreas(docObj.getNodeBody())
|
|
|
|
|
# Пост обработка
|
|
|
|
|
if 'postXML' in dir(objProfNew):
|
|
|
|
|
objProfNew.postXML()
|
|
|
|
|
# Получение текстового файла из XML документа
|
|
|
|
|
self.newProfile = objProfNew.getConfig().encode("UTF-8")
|
|
|
|
|
# Если не UTF-8 производим преобразование
|
|
|
|
|
if flagNotUtf8New:
|
|
|
|
|
self.newProfile = objTxtCoder.decode(self.newProfile)
|
|
|
|
|
# Титл для объединения
|
|
|
|
|
if ListOptTitle:
|
|
|
|
|
title = self.getTitle(objProfNew._comment,
|
|
|
|
|
ListOptTitle)
|
|
|
|
|
title = title.encode("UTF-8")
|
|
|
|
|
# Замена
|
|
|
|
|
if objHeadNew.typeAppend == "replace":
|
|
|
|
|
if "xml_" in objHeadNew.fileType:
|
|
|
|
|
data = self.newProfile.split("\n")
|
|
|
|
|
data.insert(1,title)
|
|
|
|
|
self.oldProfile = "\n".join(data)
|
|
|
|
|
else:
|
|
|
|
|
if objHeadNew.execStr:
|
|
|
|
|
self.oldProfile = objHeadNew.execStr+title+\
|
|
|
|
|
self.newProfile
|
|
|
|
|
else:
|
|
|
|
|
self.oldProfile = title + self.newProfile
|
|
|
|
|
self.saveOldFile()
|
|
|
|
|
return filesApply
|
|
|
|
|
# Впереди
|
|
|
|
|
elif objHeadNew.typeAppend == "before":
|
|
|
|
|
if "xml_" in objHeadNew.fileType:
|
|
|
|
|
self.setError (\
|
|
|
|
|
_("False option append=before in profile %s") %newFile)
|
|
|
|
|
return False
|
|
|
|
|
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 filesApply
|
|
|
|
|
# Cзади
|
|
|
|
|
elif objHeadNew.typeAppend == "after":
|
|
|
|
|
if "xml_" in objHeadNew.fileType:
|
|
|
|
|
self.setError (\
|
|
|
|
|
_("False option append=after in profile %s") %newFile)
|
|
|
|
|
return False
|
|
|
|
|
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 filesApply
|
|
|
|
|
# Объединение
|
|
|
|
|
elif objHeadNew.typeAppend == "join":
|
|
|
|
|
if flagNotUtf8New:
|
|
|
|
|
objTxtCoder = utfBin()
|
|
|
|
|
self.newProfile = objTxtCoder.encode(self.newProfile)
|
|
|
|
|
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 "xml_" in objHeadNew.fileType:
|
|
|
|
|
if objProfNew.getError():
|
|
|
|
|
self.setError (_("False profile: " ) + newFile)
|
|
|
|
|
return False
|
|
|
|
|
nameRootNode = oldFile.rpartition("/")[2].split(".")[0]
|
|
|
|
|
objProfNew.setNameBodyNode(nameRootNode)
|
|
|
|
|
# Титл для объединения
|
|
|
|
|
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 = fileHeader(self.oldProfile, objProfNew._comment)
|
|
|
|
|
if objHeadOld.body:
|
|
|
|
|
self.oldProfile = objHeadOld.body
|
|
|
|
|
else:
|
|
|
|
|
self.oldProfile = ""
|
|
|
|
|
if flagNotUtf8Old:
|
|
|
|
|
objTxtCoder = utfBin()
|
|
|
|
|
self.oldProfile = objTxtCoder.encode(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))
|
|
|
|
|
if "xml_" in objHeadNew.fileType:
|
|
|
|
|
if objProfOld.getError():
|
|
|
|
|
self.setError (_("False profile: " ) + oldFile)
|
|
|
|
|
return False
|
|
|
|
|
nameRootNode = oldFile.rpartition("/")[2].split(".")[0]
|
|
|
|
|
objProfOld.setNameBodyNode(nameRootNode)
|
|
|
|
|
|
|
|
|
|
#print "#%s#" %(objProfOld.docObj.body.toprettyxml())
|
|
|
|
|
#print "#%s#" %(objProfNew.docObj.body.toprettyxml())
|
|
|
|
|
objProfOld.join(objProfNew)
|
|
|
|
|
#print objProfOld.doc.toprettyxml()
|
|
|
|
|
#print objProfNew.doc.toprettyxml()
|
|
|
|
|
if "xml_" in objHeadNew.fileType:
|
|
|
|
|
if objProfOld.getError():
|
|
|
|
|
self.setError (_("False profile: " ) + newFile)
|
|
|
|
|
return False
|
|
|
|
|
data = \
|
|
|
|
|
objProfOld.getConfig().encode("UTF-8").split("\n")
|
|
|
|
|
data.insert(1,title)
|
|
|
|
|
self.oldProfile = "\n".join(data)
|
|
|
|
|
else:
|
|
|
|
|
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")
|
|
|
|
|
# Декодируем если кодировка не UTF-8
|
|
|
|
|
if flagNotUtf8New or flagNotUtf8Old:
|
|
|
|
|
self.newProfile = objTxtCoder.decode(self.newProfile)
|
|
|
|
|
self.oldProfile = objTxtCoder.decode(self.oldProfile)
|
|
|
|
|
self.saveOldFile()
|
|
|
|
|
return filesApply
|
|
|
|
|
else:
|
|
|
|
|
self.setError (_("False (type append) profile: " ) +\
|
|
|
|
|
objHeadNew.typeAppend)
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
self.setError (_("Type profile not found: ") + newFile)
|
|
|
|
|
return False
|
|
|
|
|
return filesApply
|
|
|
|
|
|
|
|
|
|
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 postXML(self):
|
|
|
|
|
"""Последующая постобработка XML"""
|
|
|
|
|
# Для добавления перевода строки между областями если его нет
|
|
|
|
|
#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
|
|
|
|
|
firstArea = False
|
|
|
|
|
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 join(self, sambaObj):
|
|
|
|
|
"""Объединяем конфигурации"""
|
|
|
|
|
if isinstance(sambaObj, samba):
|
|
|
|
|
self.docObj.joinDoc(sambaObj.doc)
|
|
|
|
|
self.postXML()
|
|
|
|
|
|
|
|
|
|
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 из
|
|
|
|
|
заголовка (строка) и словаря переменных
|
|
|
|
|
"""
|
|
|
|
|
if not strHeader:
|
|
|
|
|
return ""
|
|
|
|
|
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 compiz(samba):
|
|
|
|
|
"""Класс для обработки конфигурационного файла типа compiz
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
_comment = "#"
|
|
|
|
|
configName = "compiz"
|
|
|
|
|
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("\s*=\s*")
|
|
|
|
|
sepFields = "\n"
|
|
|
|
|
reSepFields = re.compile(sepFields)
|
|
|
|
|
|
|
|
|
|
def __init__(self,text):
|
|
|
|
|
samba.__init__(self,text)
|
|
|
|
|
|
|
|
|
|
def join(self, compizObj):
|
|
|
|
|
"""Объединяем конфигурации"""
|
|
|
|
|
if isinstance(compizObj, compiz):
|
|
|
|
|
self.docObj.joinDoc(compizObj.doc)
|
|
|
|
|
self.postXML()
|
|
|
|
|
|
|
|
|
|
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|^%s|(?<=;)%s"%(_comment,_comment,_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, 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 postXML(self):
|
|
|
|
|
"""Последующая постобработка XML"""
|
|
|
|
|
# Для добавления перевода строки перед закрывающим тегом
|
|
|
|
|
# конфигурационного файла
|
|
|
|
|
xmlFields = xpath.Evaluate("child::fields", self.docObj.body)
|
|
|
|
|
if not (xmlFields and\
|
|
|
|
|
self.docObj.getTypeField(xmlFields[-1]) == "br"):
|
|
|
|
|
self.docObj.body.appendChild(self.docObj.createField("br",
|
|
|
|
|
[],"",[],
|
|
|
|
|
False,False))
|
|
|
|
|
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 join(self, apacheObj):
|
|
|
|
|
"""Объединяем конфигурации"""
|
|
|
|
|
if isinstance(apacheObj, apache):
|
|
|
|
|
#print self.docObj.doc.toprettyxml()
|
|
|
|
|
self.docObj.joinDoc(apacheObj.doc)
|
|
|
|
|
self.postXML()
|
|
|
|
|
|
|
|
|
|
# Делим область на составные части
|
|
|
|
|
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|syncrepl)[^\n]+\n?")
|
|
|
|
|
# Регулярное выражения для области
|
|
|
|
|
reArea = re.compile("([\t ]*(access|syncrepl)[^\n]+\
|
|
|
|
|
\n([\t ]+[^\n]+\n?)+)",re.M|re.S)
|
|
|
|
|
reComment = re.compile("\s*%s.*"%(_comment))
|
|
|
|
|
# разделитель между переменной и значением переменной
|
|
|
|
|
reSeparator = re.compile("\s+|\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()
|
|
|
|
|
# Создаем поля-массивы
|
|
|
|
|
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 postXML(self, xmlArea=False):
|
|
|
|
|
"""Последующая постобработка XML"""
|
|
|
|
|
# Добавляем перевод строки если его нет в конец области
|
|
|
|
|
if not xmlArea:
|
|
|
|
|
xmlArea = self.docObj.body
|
|
|
|
|
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.postXML(area)
|
|
|
|
|
|
|
|
|
|
def join(self, dovecotObj):
|
|
|
|
|
"""Объединяем конфигурации"""
|
|
|
|
|
if isinstance(dovecotObj, dovecot):
|
|
|
|
|
#print self.docObj.doc.toprettyxml()
|
|
|
|
|
self.docObj.joinDoc(dovecotObj.doc)
|
|
|
|
|
# Для добавления перевода строки перед закрывающим тегом
|
|
|
|
|
# конфигурационного файла
|
|
|
|
|
self.postXML()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 _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]:
|
|
|
|
|
reH = re.compile("]\s*$")
|
|
|
|
|
#listfinH = h.split("]")
|
|
|
|
|
listfinH = reH.split(h)
|
|
|
|
|
finH = listfinH[0]
|
|
|
|
|
if "[" in finH:
|
|
|
|
|
startHeaders.append(finH + "]")
|
|
|
|
|
else:
|
|
|
|
|
startHeaders.append(finH)
|
|
|
|
|
if len(listfinH) == 2:
|
|
|
|
|
finHeaders.append(listfinH[1])
|
|
|
|
|
else:
|
|
|
|
|
finHeaders.append("")
|
|
|
|
|
head=finH.replace("][",".").replace("[","").replace("]","").strip()
|
|
|
|
|
headers.append(head)
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
def postXML(self):
|
|
|
|
|
"""Последующая постобработка XML"""
|
|
|
|
|
# Для добавления перевода строки между областями если его нет
|
|
|
|
|
#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
|
|
|
|
|
firstArea = False
|
|
|
|
|
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 join(self, kdeObj):
|
|
|
|
|
"""Объединяем конфигурации"""
|
|
|
|
|
if isinstance(kdeObj, kde):
|
|
|
|
|
self.docObj.joinDoc(kdeObj.doc)
|
|
|
|
|
self.postXML()
|
|
|
|
|
|
|
|
|
|
class xmlDocPlasma:
|
|
|
|
|
"""Класс для замены метода joinArea в xmlDoc для plasma"""
|
|
|
|
|
# заменяемый метод для xmlDoc
|
|
|
|
|
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"):
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
# Заменяем QUOTE
|
|
|
|
|
oldAreaNode = oName.parentNode.parentNode
|
|
|
|
|
oldAreaQuote = xpath.Evaluate('child::caption/quote',
|
|
|
|
|
oldAreaNode)[0]
|
|
|
|
|
if oldAreaQuote and\
|
|
|
|
|
not oldAreaQuote.firstChild:
|
|
|
|
|
newAreaQuote = xpath.Evaluate('child::caption/quote',
|
|
|
|
|
xmlNewArea)[0]
|
|
|
|
|
oldAreaCaption = xpath.Evaluate('child::caption',
|
|
|
|
|
oldAreaNode)[0]
|
|
|
|
|
if newAreaQuote and oldAreaCaption:
|
|
|
|
|
oldAreaCaption.replaceChild(newAreaQuote, oldAreaQuote)
|
|
|
|
|
|
|
|
|
|
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"):
|
|
|
|
|
appendArea(baseNode, xmlNewArea)
|
|
|
|
|
else:
|
|
|
|
|
tmpXmlNewAreas = xpath.Evaluate('child::area',xmlNewArea)
|
|
|
|
|
for na in tmpXmlNewAreas:
|
|
|
|
|
for bn in baseNodes:
|
|
|
|
|
self.joinArea(bn, na)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
class plasma(samba):
|
|
|
|
|
"""Класс для обработки конфигурационного файла типа kde
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
_comment = "#"
|
|
|
|
|
configName = "plasma"
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
# Делим текст на области включая вложенные (areas массив областей)
|
|
|
|
|
def splitToAllArea(self, text, areas):
|
|
|
|
|
"""Делит текст на области включая вложенные
|
|
|
|
|
|
|
|
|
|
возвращает список объектов областей (переменная areas)
|
|
|
|
|
"""
|
|
|
|
|
class area:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.header = False
|
|
|
|
|
self.start = False
|
|
|
|
|
self.fields = []
|
|
|
|
|
self.end = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def findPathArea(listPath, areaF):
|
|
|
|
|
"""Ищет путь в области
|
|
|
|
|
|
|
|
|
|
areaF - объект area
|
|
|
|
|
listPath - cписок названий областей
|
|
|
|
|
"""
|
|
|
|
|
ret = False
|
|
|
|
|
if not listPath:
|
|
|
|
|
return ret
|
|
|
|
|
flagList = False
|
|
|
|
|
if type(areaF) == types.ListType:
|
|
|
|
|
fields = areaF
|
|
|
|
|
flagList = True
|
|
|
|
|
else:
|
|
|
|
|
fields = areaF.fields
|
|
|
|
|
if areaF.header == listPath[0]:
|
|
|
|
|
ret = areaF
|
|
|
|
|
else:
|
|
|
|
|
return ret
|
|
|
|
|
for i in fields:
|
|
|
|
|
if str(i.__class__.__name__) == "area":
|
|
|
|
|
add = False
|
|
|
|
|
if not flagList:
|
|
|
|
|
add = listPath.pop(0)
|
|
|
|
|
if not listPath:
|
|
|
|
|
break
|
|
|
|
|
ret = False
|
|
|
|
|
if i.header == listPath[0]:
|
|
|
|
|
ret = findPathArea(listPath, i)
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
if add:
|
|
|
|
|
listPath.insert(0,add)
|
|
|
|
|
if ret == areaF and len(listPath)>1:
|
|
|
|
|
ret = False
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody)
|
|
|
|
|
blocs = self.getFullAreas(blTmp)
|
|
|
|
|
reH = re.compile("\[([^\[\]]+)\]")
|
|
|
|
|
# Список имен блоков
|
|
|
|
|
namesBlockList = []
|
|
|
|
|
# Временные поля
|
|
|
|
|
fieldsTmp = []
|
|
|
|
|
# Добавляем заголовки
|
|
|
|
|
z = 0
|
|
|
|
|
for h in blocs[0]:
|
|
|
|
|
if not h:
|
|
|
|
|
if blocs[1][z] == "":
|
|
|
|
|
fieldsTmp.append("")
|
|
|
|
|
#fieldsTmp.append("\n")
|
|
|
|
|
else:
|
|
|
|
|
fieldsTmp.append(blocs[1][z])
|
|
|
|
|
#print '"' + blocs[1][z] + '"'
|
|
|
|
|
z += 1
|
|
|
|
|
continue
|
|
|
|
|
#print '"' + blocs[1][z] + '"'
|
|
|
|
|
z += 1
|
|
|
|
|
slpNamesBlock = reH.split(h)
|
|
|
|
|
# Отступ слева для заголовка
|
|
|
|
|
indentionLeft = slpNamesBlock[0]
|
|
|
|
|
namesBlock = filter(lambda x: x.strip(), slpNamesBlock)
|
|
|
|
|
#namesBlock = map(lambda x: self.removeSymbolTerm(x), namesBlock)
|
|
|
|
|
findArea = findPathArea(copy.copy(namesBlock), areas)
|
|
|
|
|
namesBlockList.append(namesBlock)
|
|
|
|
|
if findArea:
|
|
|
|
|
if len(namesBlock) > 1:
|
|
|
|
|
namesBlockView = map(lambda x: self.removeSymbolTerm(x),
|
|
|
|
|
namesBlock)
|
|
|
|
|
else:
|
|
|
|
|
namesBlockView = namesBlock
|
|
|
|
|
findArea.start = indentionLeft + "[" + \
|
|
|
|
|
"][".join(namesBlockView) + "]"
|
|
|
|
|
else:
|
|
|
|
|
i = 0
|
|
|
|
|
lenNamesBlock = len(namesBlock)
|
|
|
|
|
namesBlockTmp = []
|
|
|
|
|
for nameB in namesBlock:
|
|
|
|
|
namesBlockTmp.append(nameB)
|
|
|
|
|
findArea = findPathArea(copy.copy(namesBlockTmp), areas)
|
|
|
|
|
i += 1
|
|
|
|
|
if not findArea:
|
|
|
|
|
areaNew = area()
|
|
|
|
|
areaNew.header = nameB
|
|
|
|
|
if lenNamesBlock == i:
|
|
|
|
|
if len(namesBlock) > 1:
|
|
|
|
|
namesBlockView = map(\
|
|
|
|
|
lambda x: self.removeSymbolTerm(x),
|
|
|
|
|
namesBlock)
|
|
|
|
|
else:
|
|
|
|
|
namesBlockView = namesBlock
|
|
|
|
|
areaNew.start = indentionLeft + "[" + \
|
|
|
|
|
"][".join(namesBlockView) + "]"
|
|
|
|
|
else:
|
|
|
|
|
areaNew.start = ""
|
|
|
|
|
areaNew.end = ""
|
|
|
|
|
if i == 1:
|
|
|
|
|
if lenNamesBlock == i:
|
|
|
|
|
areas += fieldsTmp
|
|
|
|
|
areas.append(areaNew)
|
|
|
|
|
findAreaPrev = areas[-1]
|
|
|
|
|
else:
|
|
|
|
|
if lenNamesBlock == i:
|
|
|
|
|
findAreaPrev.fields += fieldsTmp
|
|
|
|
|
findAreaPrev.fields.append(areaNew)
|
|
|
|
|
findAreaPrev = findAreaPrev.fields[-1]
|
|
|
|
|
else:
|
|
|
|
|
findAreaPrev = findArea
|
|
|
|
|
fieldsTmp = []
|
|
|
|
|
i = 0
|
|
|
|
|
delt = 0
|
|
|
|
|
# Добавляем тела
|
|
|
|
|
for body in blocs[1]:
|
|
|
|
|
#print "#" + body + "#"
|
|
|
|
|
#print
|
|
|
|
|
if not blocs[0][i]:
|
|
|
|
|
i += 1
|
|
|
|
|
delt +=1
|
|
|
|
|
continue
|
|
|
|
|
## В случае последнего комментария не добавляем перевод строки
|
|
|
|
|
#if self.reComment.search(body.splitlines()[-1]):
|
|
|
|
|
body = "\n" + body
|
|
|
|
|
|
|
|
|
|
namesBlock = namesBlockList[i-delt]
|
|
|
|
|
findArea = findPathArea(copy.copy(namesBlock), areas)
|
|
|
|
|
if findArea:
|
|
|
|
|
#if findArea.fields:
|
|
|
|
|
#if type(findArea.fields[0]) == types.StringType:
|
|
|
|
|
#findArea.fields.pop(0)
|
|
|
|
|
findArea.fields.insert(0, body)
|
|
|
|
|
i += 1
|
|
|
|
|
|
|
|
|
|
#eee = 1
|
|
|
|
|
#def prAreas(ar, eee):
|
|
|
|
|
#for a in ar:
|
|
|
|
|
#if type(a) == types.StringType:
|
|
|
|
|
#print 'field', a
|
|
|
|
|
#else:
|
|
|
|
|
#print "--------------------"
|
|
|
|
|
#print "HEADER =", a.header
|
|
|
|
|
#print "START =", a.start
|
|
|
|
|
#print "FIELDS =", a.fields
|
|
|
|
|
#print "LEVEL", eee
|
|
|
|
|
#if type(a) != types.StringType:
|
|
|
|
|
#if a.fields:
|
|
|
|
|
#eee += 1
|
|
|
|
|
#prAreas(a.fields, eee)
|
|
|
|
|
|
|
|
|
|
#prAreas(areas, eee)
|
|
|
|
|
return areas
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
areaXML = self.createCaptionTerm(i.header, i.start,
|
|
|
|
|
i.end.replace("\n",""),
|
|
|
|
|
docObj)
|
|
|
|
|
for f in i.fields:
|
|
|
|
|
if str(f.__class__.__name__) == "area":
|
|
|
|
|
if f.header:
|
|
|
|
|
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)
|
|
|
|
|
if areaXML:
|
|
|
|
|
areaXML.appendChild(fieldXML)
|
|
|
|
|
|
|
|
|
|
if i.header:
|
|
|
|
|
rootNode.appendChild(areaXML)
|
|
|
|
|
if "\n" in i.end:
|
|
|
|
|
fieldXMLBr = docObj.createField("br",[],
|
|
|
|
|
"",[],
|
|
|
|
|
False, False)
|
|
|
|
|
rootNode.appendChild(fieldXMLBr)
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
if not i:
|
|
|
|
|
continue
|
|
|
|
|
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)
|
|
|
|
|
#docObj = xmlDoc()
|
|
|
|
|
# Создаем новый класс xmlDoc с измененным методом joinArea
|
|
|
|
|
newClass = type("newXmlDocPlalma",(xmlDocPlasma,xmlDoc,object),{})
|
|
|
|
|
# Создаем экземпляр нового класса
|
|
|
|
|
docObj = newClass()
|
|
|
|
|
# Создание объекта документ c пустым разделителем между полями
|
|
|
|
|
docObj.createDoc(self.configName, self.configVersion)
|
|
|
|
|
if not areas:
|
|
|
|
|
return docObj
|
|
|
|
|
self.createXML(areas, docObj.getNodeBody(), docObj)
|
|
|
|
|
return docObj
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def postXML(self):
|
|
|
|
|
"""Последующая постобработка XML"""
|
|
|
|
|
# Для добавления перевода строки между областями если его нет
|
|
|
|
|
#print self.docObj.body.toprettyxml()
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
xmlAreas = xpath.Evaluate("descendant::area", self.docObj.body)
|
|
|
|
|
#print "-------------------------------------------------------"
|
|
|
|
|
#print xmlAreas
|
|
|
|
|
#if xmlAreas:
|
|
|
|
|
#prXmlArea = xmlAreas[0]
|
|
|
|
|
for xmlArea in xmlAreas:
|
|
|
|
|
# Перед пустой областью и после нее удаляем переводы строк
|
|
|
|
|
if getQuotesArea(xmlArea) == ["",""]:
|
|
|
|
|
#areaTXT = xpath.Evaluate("child::caption/name", xmlArea)[0]
|
|
|
|
|
#print "CL_AREA", areaTXT.firstChild
|
|
|
|
|
if xmlArea.previousSibling and\
|
|
|
|
|
self.docObj.getTypeField(xmlArea.previousSibling) == "br":
|
|
|
|
|
parentNode = xmlArea.previousSibling.parentNode
|
|
|
|
|
if xmlArea.previousSibling.previousSibling and\
|
|
|
|
|
self.docObj.getTypeField(xmlArea.previousSibling.previousSibling) == "br":
|
|
|
|
|
parentNode.removeChild(\
|
|
|
|
|
xmlArea.previousSibling.previousSibling)
|
|
|
|
|
parentNode.removeChild(xmlArea.previousSibling)
|
|
|
|
|
if xmlArea.nextSibling and\
|
|
|
|
|
self.docObj.getTypeField(xmlArea.nextSibling) == "br":
|
|
|
|
|
parentNode = xmlArea.nextSibling.parentNode
|
|
|
|
|
if xmlArea.nextSibling.nextSibling and\
|
|
|
|
|
self.docObj.getTypeField(xmlArea.nextSibling.nextSibling) == "br":
|
|
|
|
|
parentNode.removeChild(xmlArea.nextSibling.nextSibling)
|
|
|
|
|
parentNode.removeChild(xmlArea.nextSibling)
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
# Собираем поля в кучку
|
|
|
|
|
xmlChildAreas = xpath.Evaluate("child::area", xmlArea)
|
|
|
|
|
if xmlChildAreas:
|
|
|
|
|
childNodes = self.docObj.getFieldsArea(xmlArea)
|
|
|
|
|
firstChildArea = xmlChildAreas[0]
|
|
|
|
|
if firstChildArea.previousSibling and\
|
|
|
|
|
self.docObj.getTypeField(firstChildArea.previousSibling)=="br":
|
|
|
|
|
if firstChildArea.previousSibling.previousSibling:
|
|
|
|
|
if self.docObj.getTypeField(\
|
|
|
|
|
firstChildArea.previousSibling.previousSibling)=="br":
|
|
|
|
|
firstChildArea = firstChildArea.previousSibling
|
|
|
|
|
flagFoundArea = False
|
|
|
|
|
it = 0
|
|
|
|
|
lenChild = len(childNodes)
|
|
|
|
|
for node in childNodes:
|
|
|
|
|
it += 1
|
|
|
|
|
if node.tagName == "area":
|
|
|
|
|
flagFoundArea = True
|
|
|
|
|
continue
|
|
|
|
|
if flagFoundArea and node.tagName == "field":
|
|
|
|
|
if self.docObj.getTypeField(node) == "var":
|
|
|
|
|
xmlArea.insertBefore(node, firstChildArea)
|
|
|
|
|
if it < lenChild:
|
|
|
|
|
if self.docObj.getTypeField(childNodes[it])==\
|
|
|
|
|
"br":
|
|
|
|
|
xmlArea.insertBefore(childNodes[it],
|
|
|
|
|
firstChildArea)
|
|
|
|
|
|
|
|
|
|
# Добавляем BR если его нет первым полем
|
|
|
|
|
xmlFields = xpath.Evaluate("child::field", xmlArea)
|
|
|
|
|
if not (xmlFields and\
|
|
|
|
|
(self.docObj.getTypeField(xmlFields[0]) == "br" or\
|
|
|
|
|
self.docObj.getTypeField(xmlFields[0]) == "comment")):
|
|
|
|
|
if xmlFields:
|
|
|
|
|
xmlArea.insertBefore(self.docObj.createField("br",
|
|
|
|
|
[],"",[],
|
|
|
|
|
False,False),
|
|
|
|
|
xmlFields[0])
|
|
|
|
|
# Если последним полем BR, удаляем его
|
|
|
|
|
if xmlFields and self.docObj.getTypeField(xmlFields[-1]) == "br":
|
|
|
|
|
#print "DEL_BR", xmlFields[-1].nextSibling
|
|
|
|
|
#and\
|
|
|
|
|
if not xmlFields[-1].nextSibling:
|
|
|
|
|
xmlArea.removeChild(xmlFields[-1])
|
|
|
|
|
|
|
|
|
|
# Если предыдущим полем не (BR или комментарий) - добавляем BR
|
|
|
|
|
if xmlArea.previousSibling and\
|
|
|
|
|
not (self.docObj.getTypeField(xmlArea.previousSibling) == "br" or\
|
|
|
|
|
self.docObj.getTypeField(xmlArea.previousSibling) == "comment"):
|
|
|
|
|
parentNode = xmlArea.parentNode
|
|
|
|
|
parentNode.insertBefore(self.docObj.createField("br",
|
|
|
|
|
[],"",[],
|
|
|
|
|
False,False),
|
|
|
|
|
xmlArea)
|
|
|
|
|
# Если есть предыдущее поле, и поле предыдущеее предыдущему
|
|
|
|
|
# не равно BR или комментарий то добавляем BR
|
|
|
|
|
if xmlArea.previousSibling:
|
|
|
|
|
prPrSibling = xmlArea.previousSibling.previousSibling
|
|
|
|
|
if prPrSibling and\
|
|
|
|
|
not (self.docObj.getTypeField(prPrSibling) == "br" or\
|
|
|
|
|
self.docObj.getTypeField(prPrSibling) == "comment"):
|
|
|
|
|
parentNode = xmlArea.parentNode
|
|
|
|
|
parentNode.insertBefore(self.docObj.createField("br",
|
|
|
|
|
[],"",[],
|
|
|
|
|
False,False),
|
|
|
|
|
xmlArea)
|
|
|
|
|
# Если после есть BR а за ним ничего нет, удаляем BR
|
|
|
|
|
if xmlArea.nextSibling and\
|
|
|
|
|
self.docObj.getTypeField(xmlArea.nextSibling) == "br":
|
|
|
|
|
if not xmlArea.nextSibling.nextSibling:
|
|
|
|
|
parentNode = xmlArea.nextSibling.parentNode
|
|
|
|
|
parentNode.removeChild(xmlArea.nextSibling)
|
|
|
|
|
|
|
|
|
|
#xmlName = xpath.Evaluate("child::caption/name", xmlArea)[0]
|
|
|
|
|
#print "------------------------------------"
|
|
|
|
|
#print "Name =", xmlName.firstChild
|
|
|
|
|
#if xmlArea.previousSibling:
|
|
|
|
|
#print "PR_TYPE =", self.docObj.getTypeField(xmlArea.previousSibling)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def join(self, kdeObj):
|
|
|
|
|
"""Объединяем конфигурации"""
|
|
|
|
|
if isinstance(kdeObj, plasma):
|
|
|
|
|
self.docObj.joinDoc(kdeObj.doc)
|
|
|
|
|
self.postXML()
|
|
|
|
|
|
|
|
|
|
class xml_xfce(_error):
|
|
|
|
|
"""Класс для объединения xfce-xml файлов"""
|
|
|
|
|
# root нода
|
|
|
|
|
rootNode = False
|
|
|
|
|
# body нода
|
|
|
|
|
bodyNode = False
|
|
|
|
|
# Документ
|
|
|
|
|
doc = False
|
|
|
|
|
# Текст профиля
|
|
|
|
|
text = ""
|
|
|
|
|
# Комментарий
|
|
|
|
|
_comment = ("<!--","-->")
|
|
|
|
|
|
|
|
|
|
def __init__(self, text):
|
|
|
|
|
self.text = text
|
|
|
|
|
# Создаем пустой объект
|
|
|
|
|
self.docObj = type("_empty_class", (object,), {})()
|
|
|
|
|
# Названия аттрибутов для пустого объекта
|
|
|
|
|
emptyMethods = ["getNodeBody","removeComment","insertBRtoBody",
|
|
|
|
|
"insertBeforeSepAreas"]
|
|
|
|
|
# Добавляем необходимые аттрибуты пустому объекту
|
|
|
|
|
for method in emptyMethods:
|
|
|
|
|
setattr(self.docObj, method, self.emptyMethod)
|
|
|
|
|
# Создаем XML документ
|
|
|
|
|
self.doc = self.textToXML()
|
|
|
|
|
|
|
|
|
|
def emptyMethod(self, *arg , **argv):
|
|
|
|
|
"""Пустой метод"""
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def setNameBodyNode(self, name):
|
|
|
|
|
"""Устанавливает название для корневой ноды документа"""
|
|
|
|
|
if not self.bodyNode:
|
|
|
|
|
return False
|
|
|
|
|
self.bodyNode.setAttribute("name", name)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def textToXML(self):
|
|
|
|
|
"""Создание из текста XML документа
|
|
|
|
|
Храним xml в своем формате
|
|
|
|
|
"""
|
|
|
|
|
if not self.text.strip():
|
|
|
|
|
self.text = '''<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
|
<channel version="1.0">
|
|
|
|
|
</channel>'''
|
|
|
|
|
try:
|
|
|
|
|
self.doc = xml.dom.minidom.parseString(self.text)
|
|
|
|
|
except:
|
|
|
|
|
self.setError(_("Can not text profile is XML"))
|
|
|
|
|
return False
|
|
|
|
|
self.rootNode = self.doc.documentElement
|
|
|
|
|
self.bodyNode = self.rootNode
|
|
|
|
|
return self.doc
|
|
|
|
|
|
|
|
|
|
def join(self, xml_xfceObj):
|
|
|
|
|
"""Объединяем конфигурации"""
|
|
|
|
|
if isinstance(xml_xfceObj, xml_xfce):
|
|
|
|
|
try:
|
|
|
|
|
self.joinDoc(xml_xfceObj.doc)
|
|
|
|
|
except:
|
|
|
|
|
self.setError(_("Can not join profile"))
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def _removeDropNodesAndAttrAction(self, xmlNode):
|
|
|
|
|
"""Удаляет ноды с аттрибутом action='drop'
|
|
|
|
|
|
|
|
|
|
Также удаляет аттрибут action у всех нод
|
|
|
|
|
"""
|
|
|
|
|
flagError = False
|
|
|
|
|
childNodes = xmlNode.childNodes
|
|
|
|
|
if xmlNode.nodeType ==xmlNode.ELEMENT_NODE:
|
|
|
|
|
if xmlNode.hasAttribute("action"):
|
|
|
|
|
nAction = xmlNode.getAttribute("action")
|
|
|
|
|
if not nAction in ("join","replace","drop"):
|
|
|
|
|
textError = _('''In the text, XML profile, look \
|
|
|
|
|
for a reserved attribute 'action' with the incorrect value.\n\
|
|
|
|
|
Valid values attribute 'action': \
|
|
|
|
|
(action="join", action="replace", action="drop")''')
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
xmlNode.removeAttribute("action")
|
|
|
|
|
if nAction == "drop":
|
|
|
|
|
parentNode = xmlNode.parentNode
|
|
|
|
|
if parentNode:
|
|
|
|
|
parentNode.removeChild(xmlNode)
|
|
|
|
|
if childNodes:
|
|
|
|
|
for node in childNodes:
|
|
|
|
|
if not self._removeDropNodesAndAttrAction(node):
|
|
|
|
|
flagError = True
|
|
|
|
|
break
|
|
|
|
|
if flagError:
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def postXML(self):
|
|
|
|
|
"""Последующая постобработка XML"""
|
|
|
|
|
# Удаляем теги action и удаляемые ноды
|
|
|
|
|
self._removeDropNodesAndAttrAction(self.bodyNode)
|
|
|
|
|
|
|
|
|
|
def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True):
|
|
|
|
|
"""Объединение корневой ноды профиля и корневой ноды файла"""
|
|
|
|
|
xmlNode = xmlNewNode
|
|
|
|
|
childNodes = xmlNode.childNodes
|
|
|
|
|
nextOldNode = xmlOldNode
|
|
|
|
|
flagError = False
|
|
|
|
|
if xmlNode.nodeType ==xmlNode.ELEMENT_NODE:
|
|
|
|
|
n = xmlNode
|
|
|
|
|
path = u''
|
|
|
|
|
nName = u''
|
|
|
|
|
nType = u''
|
|
|
|
|
nValue = u''
|
|
|
|
|
nAction = u''
|
|
|
|
|
attrName = ''
|
|
|
|
|
attrType = ''
|
|
|
|
|
path = n.tagName
|
|
|
|
|
if n.hasAttribute("name"):
|
|
|
|
|
nName = n.getAttribute("name")
|
|
|
|
|
attrName = u"attribute::name='%s'"%nName
|
|
|
|
|
if n.hasAttribute("type"):
|
|
|
|
|
nType = n.getAttribute("type")
|
|
|
|
|
attrType = u"attribute::type='%s'"%nType
|
|
|
|
|
if n.hasAttribute("value"):
|
|
|
|
|
nValue = n.getAttribute("value")
|
|
|
|
|
if n.hasAttribute("action"):
|
|
|
|
|
nAction = n.getAttribute("action")
|
|
|
|
|
if not nAction in ("join","replace","drop"):
|
|
|
|
|
textError = _('''In the text, XML profile, look \
|
|
|
|
|
for a reserved attribute 'action' with the incorrect value.\n\
|
|
|
|
|
Valid values attribute 'action': \
|
|
|
|
|
(action="join", action="replace", action="drop")''')
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
if xmlOldNode.parentNode:
|
|
|
|
|
findStr = u"child::%s"%path
|
|
|
|
|
strAttr = [attrName, attrType]
|
|
|
|
|
findAttr = filter(lambda x: x, strAttr)
|
|
|
|
|
findAttrStr = ''
|
|
|
|
|
if findAttr:
|
|
|
|
|
strAttr = u' and '.join(findAttr)
|
|
|
|
|
findAttrStr = "[%s]"%strAttr
|
|
|
|
|
findPath = u"child::%s%s"%(path,findAttrStr)
|
|
|
|
|
# Рабочая нода
|
|
|
|
|
if flagRootNode:
|
|
|
|
|
workNode = xmlOldNode.parentNode
|
|
|
|
|
else:
|
|
|
|
|
workNode = xmlOldNode
|
|
|
|
|
oldNodes = xpath.Evaluate(findPath, workNode)
|
|
|
|
|
#print findPath
|
|
|
|
|
#print workNode
|
|
|
|
|
#print "----------------------------"
|
|
|
|
|
# Новая нода список
|
|
|
|
|
flagArray = False
|
|
|
|
|
if nType == "array":
|
|
|
|
|
flagArray = True
|
|
|
|
|
flagDrop = False
|
|
|
|
|
flagJoin = True
|
|
|
|
|
flagReplace = False
|
|
|
|
|
if nAction == "replace":
|
|
|
|
|
flagJoin = False
|
|
|
|
|
flagReplace = True
|
|
|
|
|
elif nAction == "drop":
|
|
|
|
|
flagJoin = False
|
|
|
|
|
flagDrop = True
|
|
|
|
|
if flagRootNode:
|
|
|
|
|
textError = _('Incorrect action="drop" in root node')
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
if oldNodes:
|
|
|
|
|
if len(oldNodes)>1:
|
|
|
|
|
textError = _("The uncertainty in this profile are \
|
|
|
|
|
the same nodes at one level")
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
nextOldNode = oldNodes[0]
|
|
|
|
|
# Замещаем ноду в случае массива
|
|
|
|
|
if flagArray and not flagDrop:
|
|
|
|
|
replaceXmlNode = xmlNode.cloneNode(True)
|
|
|
|
|
if nAction:
|
|
|
|
|
replaceXmlNode.removeAttribute("action")
|
|
|
|
|
workNode.replaceChild(replaceXmlNode,
|
|
|
|
|
nextOldNode)
|
|
|
|
|
flagJoin = False
|
|
|
|
|
flagReplace = False
|
|
|
|
|
childNodes = False
|
|
|
|
|
# Объединение нод
|
|
|
|
|
if flagJoin:
|
|
|
|
|
if nextOldNode.hasAttribute("value"):
|
|
|
|
|
oValue = nextOldNode.getAttribute("value")
|
|
|
|
|
if nValue != oValue:
|
|
|
|
|
nextOldNode.setAttribute("value",nValue)
|
|
|
|
|
# Замещение ноды
|
|
|
|
|
elif flagReplace:
|
|
|
|
|
replaceXmlNode = xmlNode.cloneNode(True)
|
|
|
|
|
if not\
|
|
|
|
|
self._removeDropNodesAndAttrAction(replaceXmlNode):
|
|
|
|
|
return False
|
|
|
|
|
workNode.replaceChild(replaceXmlNode,
|
|
|
|
|
nextOldNode)
|
|
|
|
|
childNodes = False
|
|
|
|
|
# Удаление ноды
|
|
|
|
|
elif flagDrop:
|
|
|
|
|
workNode.removeChild(nextOldNode)
|
|
|
|
|
childNodes = False
|
|
|
|
|
else:
|
|
|
|
|
# Добавление ноды
|
|
|
|
|
childNodes = False
|
|
|
|
|
if not flagDrop:
|
|
|
|
|
appendXmlNode = xmlNode.cloneNode(True)
|
|
|
|
|
if not\
|
|
|
|
|
self._removeDropNodesAndAttrAction(appendXmlNode):
|
|
|
|
|
return False
|
|
|
|
|
workNode.appendChild(appendXmlNode)
|
|
|
|
|
if childNodes:
|
|
|
|
|
for node in childNodes:
|
|
|
|
|
if not self._join(node, nextOldNode, False):
|
|
|
|
|
flagError = True
|
|
|
|
|
break
|
|
|
|
|
if flagError:
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def joinDoc(self, doc):
|
|
|
|
|
"""Объединение документа профиля и документа файла"""
|
|
|
|
|
if not self.doc:
|
|
|
|
|
self.setError(_("Can not text file is XML"))
|
|
|
|
|
return False
|
|
|
|
|
if not doc:
|
|
|
|
|
self.setError(_("Can not text profile is XML"))
|
|
|
|
|
return False
|
|
|
|
|
# Импортируем корневую ноду нового документа в текущий документ
|
|
|
|
|
#newImportBodyNode = self.doc.importNode(doc.documentElement, True)
|
|
|
|
|
# Объединение корневой ноды профиля и корневой ноды файла
|
|
|
|
|
if not self._join(doc.documentElement, self.bodyNode):
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def getConfig(self):
|
|
|
|
|
"""Получение текстового файла из XML документа"""
|
|
|
|
|
data = self.doc.toprettyxml(encoding='UTF-8').split("\n")
|
|
|
|
|
data = filter(lambda x: x.strip(), data)
|
|
|
|
|
return "\n".join(data).replace("\t"," ").decode("UTF-8")
|
|
|
|
|
|
|
|
|
|
class squid(procmail):
|
|
|
|
|
"""Класс для обработки конфигурационного файла типа squid
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
configName = "squid"
|
|
|
|
|
configVersion = "0.1"
|
|
|
|
|
# разделитель названия и значения переменной
|
|
|
|
|
reSeparator = re.compile(" ")
|
|
|
|
|
|
|
|
|
|
def __init__(self, text):
|
|
|
|
|
procmail.__init__(self, text)
|
|
|
|
|
# Создаем поля-массивы
|
|
|
|
|
self.docObj.postParserList()
|
|
|
|
|
# Создаем поля разделенные массивы
|
|
|
|
|
self.docObj.postParserListSeplist(self.docObj.body)
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
flagVariable = True
|
|
|
|
|
if not textLine.strip():
|
|
|
|
|
field.br = textLine
|
|
|
|
|
fields.append(field)
|
|
|
|
|
field = fieldData()
|
|
|
|
|
flagVariable = False
|
|
|
|
|
elif findComment:
|
|
|
|
|
if textLine[:findComment.start()].strip():
|
|
|
|
|
field.comment = textLine[findComment.start():]
|
|
|
|
|
textLine = textLine[:findComment.start()]
|
|
|
|
|
else:
|
|
|
|
|
field.comment = textLine
|
|
|
|
|
flagVariable = False
|
|
|
|
|
fields.append(field)
|
|
|
|
|
field = fieldData()
|
|
|
|
|
if flagVariable:
|
|
|
|
|
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 join(self, squidObj):
|
|
|
|
|
"""Объединяем конфигурации"""
|
|
|
|
|
if isinstance(squidObj, squid):
|
|
|
|
|
#print squidObj.getConfig()
|
|
|
|
|
self.docObj.joinDoc(squidObj.doc)
|
|
|
|
|
|
|
|
|
|
class xml_xfcepanel(xml_xfce):
|
|
|
|
|
"""Класс для объединения xfce-panel файлов"""
|
|
|
|
|
def __init__(self, text):
|
|
|
|
|
xml_xfce.__init__(self, text)
|
|
|
|
|
self.panelNumbers = {}
|
|
|
|
|
|
|
|
|
|
def textToXML(self):
|
|
|
|
|
"""Создание из текста XML документа
|
|
|
|
|
Храним xml в своем формате
|
|
|
|
|
"""
|
|
|
|
|
if not self.text.strip():
|
|
|
|
|
self.text = '''<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
|
<!DOCTYPE config SYSTEM "config.dtd">
|
|
|
|
|
<panels>
|
|
|
|
|
</panels>'''
|
|
|
|
|
try:
|
|
|
|
|
self.doc = xml.dom.minidom.parseString(self.text)
|
|
|
|
|
except:
|
|
|
|
|
self.setError(_("Can not text profile is XML"))
|
|
|
|
|
return False
|
|
|
|
|
self.rootNode = self.doc.documentElement
|
|
|
|
|
self.bodyNode = self.rootNode
|
|
|
|
|
return self.doc
|
|
|
|
|
|
|
|
|
|
def setNameBodyNode(self, name):
|
|
|
|
|
"""Пустой метод"""
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True, levelNumber=0):
|
|
|
|
|
"""Объединение корневой ноды профиля и корневой ноды файла"""
|
|
|
|
|
xmlNode = xmlNewNode
|
|
|
|
|
childNodes = xmlNode.childNodes
|
|
|
|
|
nextOldNode = xmlOldNode
|
|
|
|
|
flagError = False
|
|
|
|
|
if xmlNode.nodeType ==xmlNode.ELEMENT_NODE:
|
|
|
|
|
n = xmlNode
|
|
|
|
|
path = u''
|
|
|
|
|
nName = u''
|
|
|
|
|
flagArray = False
|
|
|
|
|
nValue = u''
|
|
|
|
|
nAction = u''
|
|
|
|
|
attrName = ''
|
|
|
|
|
attrType = ''
|
|
|
|
|
path = n.tagName
|
|
|
|
|
if path == "items":
|
|
|
|
|
flagArray = True
|
|
|
|
|
if not flagArray:
|
|
|
|
|
if n.hasAttribute("name"):
|
|
|
|
|
nName = n.getAttribute("name")
|
|
|
|
|
attrName = u"attribute::name='%s'"%nName
|
|
|
|
|
if n.hasAttribute("value"):
|
|
|
|
|
nValue = n.getAttribute("value")
|
|
|
|
|
if n.hasAttribute("action"):
|
|
|
|
|
nAction = n.getAttribute("action")
|
|
|
|
|
if not nAction in ("join","replace","drop"):
|
|
|
|
|
textError = _('''In the text, XML profile, look \
|
|
|
|
|
for a reserved attribute 'action' with the incorrect value.\n\
|
|
|
|
|
Valid values attribute 'action': \
|
|
|
|
|
(action="join", action="replace", action="drop")''')
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
if xmlOldNode.parentNode:
|
|
|
|
|
findStr = u"child::%s"%path
|
|
|
|
|
findAttrStr = ""
|
|
|
|
|
if attrName:
|
|
|
|
|
findAttrStr = "[%s]"%attrName
|
|
|
|
|
findPath = u"child::%s%s"%(path,findAttrStr)
|
|
|
|
|
# Рабочая нода
|
|
|
|
|
if flagRootNode:
|
|
|
|
|
workNode = xmlOldNode.parentNode
|
|
|
|
|
else:
|
|
|
|
|
workNode = xmlOldNode
|
|
|
|
|
oldNodes = xpath.Evaluate(findPath, workNode)
|
|
|
|
|
flagDrop = False
|
|
|
|
|
flagJoin = True
|
|
|
|
|
flagReplace = False
|
|
|
|
|
flagAppend = False
|
|
|
|
|
if nAction == "replace":
|
|
|
|
|
flagJoin = False
|
|
|
|
|
flagReplace = True
|
|
|
|
|
elif nAction == "drop":
|
|
|
|
|
flagJoin = False
|
|
|
|
|
flagDrop = True
|
|
|
|
|
if flagRootNode:
|
|
|
|
|
textError = _('Incorrect action="drop" in root node')
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
if path == "panel":
|
|
|
|
|
flagJoin = False
|
|
|
|
|
if levelNumber in self.panelNumbers.keys():
|
|
|
|
|
self.panelNumbers[levelNumber] += 1
|
|
|
|
|
else:
|
|
|
|
|
self.panelNumbers[levelNumber] = 0
|
|
|
|
|
if oldNodes:
|
|
|
|
|
if len(oldNodes)>1 and path != "panel":
|
|
|
|
|
textError = _("The uncertainty in this profile are \
|
|
|
|
|
the same nodes at one level")
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
if path == "panel":
|
|
|
|
|
if len(oldNodes)<=self.panelNumbers[levelNumber]:
|
|
|
|
|
nextOldNode = oldNodes[-1]
|
|
|
|
|
# Добавляем ноду
|
|
|
|
|
if not flagDrop:
|
|
|
|
|
flagAppend = True
|
|
|
|
|
flagReplace = False
|
|
|
|
|
childNodes = False
|
|
|
|
|
else:
|
|
|
|
|
nextOldNode=oldNodes[self.panelNumbers[levelNumber]]
|
|
|
|
|
else:
|
|
|
|
|
nextOldNode = oldNodes[0]
|
|
|
|
|
# Замещаем ноду в случае массива
|
|
|
|
|
if flagArray and not flagDrop:
|
|
|
|
|
replaceXmlNode = xmlNode.cloneNode(True)
|
|
|
|
|
if nAction:
|
|
|
|
|
replaceXmlNode.removeAttribute("action")
|
|
|
|
|
workNode.replaceChild(replaceXmlNode,
|
|
|
|
|
nextOldNode)
|
|
|
|
|
flagJoin = False
|
|
|
|
|
flagReplace = False
|
|
|
|
|
childNodes = False
|
|
|
|
|
# Объединение нод
|
|
|
|
|
if flagJoin:
|
|
|
|
|
if nextOldNode.hasAttribute("value"):
|
|
|
|
|
oValue = nextOldNode.getAttribute("value")
|
|
|
|
|
if nValue != oValue:
|
|
|
|
|
nextOldNode.setAttribute("value",nValue)
|
|
|
|
|
# Замещение ноды
|
|
|
|
|
elif flagReplace:
|
|
|
|
|
replaceXmlNode = xmlNode.cloneNode(True)
|
|
|
|
|
if not\
|
|
|
|
|
self._removeDropNodesAndAttrAction(replaceXmlNode):
|
|
|
|
|
return False
|
|
|
|
|
workNode.replaceChild(replaceXmlNode,
|
|
|
|
|
nextOldNode)
|
|
|
|
|
childNodes = False
|
|
|
|
|
# Удаление ноды
|
|
|
|
|
elif flagDrop:
|
|
|
|
|
workNode.removeChild(nextOldNode)
|
|
|
|
|
childNodes = False
|
|
|
|
|
else:
|
|
|
|
|
flagAppend = True
|
|
|
|
|
flagDrop = False
|
|
|
|
|
if flagAppend and not flagDrop:
|
|
|
|
|
# Добавление ноды
|
|
|
|
|
childNodes = False
|
|
|
|
|
if not flagDrop:
|
|
|
|
|
appendXmlNode = xmlNode.cloneNode(True)
|
|
|
|
|
if not\
|
|
|
|
|
self._removeDropNodesAndAttrAction(appendXmlNode):
|
|
|
|
|
return False
|
|
|
|
|
workNode.appendChild(appendXmlNode)
|
|
|
|
|
if childNodes:
|
|
|
|
|
for node in childNodes:
|
|
|
|
|
levelNumber +=1
|
|
|
|
|
if not self._join(node, nextOldNode, False, levelNumber):
|
|
|
|
|
flagError = True
|
|
|
|
|
break
|
|
|
|
|
levelNumber -= 1
|
|
|
|
|
if flagError:
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def join(self, xml_xfceObj):
|
|
|
|
|
"""Объединяем конфигурации"""
|
|
|
|
|
if isinstance(xml_xfceObj, xml_xfcepanel):
|
|
|
|
|
try:
|
|
|
|
|
self.joinDoc(xml_xfceObj.doc)
|
|
|
|
|
except:
|
|
|
|
|
self.setError(_("Can not join profile"))
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class dhcp(bind):
|
|
|
|
|
"""Класс для обработки конфигурационного файла типа dhcp
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
_comment = "#"
|
|
|
|
|
configName = "dhcp"
|
|
|
|
|
configVersion = "0.1"
|
|
|
|
|
__openArea = "{"
|
|
|
|
|
__closeArea = "[ \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):
|
|
|
|
|
bind.__init__(self,text)
|
|
|
|
|
|
|
|
|
|
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 = textLine.replace(self.sepFields,"").strip()
|
|
|
|
|
field.value = ""
|
|
|
|
|
field.br = textLine
|
|
|
|
|
fields.append(field)
|
|
|
|
|
field = fieldData()
|
|
|
|
|
|
|
|
|
|
if len(nameValue) > 2:
|
|
|
|
|
nameCheck = nameValue[0]
|
|
|
|
|
if nameValue[0][:1] in ["+","-","!"]:
|
|
|
|
|
nameCheck = nameValue[0][1:]
|
|
|
|
|
if nameCheck == "option" or nameCheck == "hardware" or\
|
|
|
|
|
nameCheck == "set":
|
|
|
|
|
valueList = nameValue[2:]
|
|
|
|
|
nameValue =[nameValue[0]+nameValue[1],
|
|
|
|
|
" ".join(valueList).replace(\
|
|
|
|
|
self.sepFields,"")]
|
|
|
|
|
else:
|
|
|
|
|
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 join(self, dhcpObj):
|
|
|
|
|
"""Объединяем конфигурации"""
|
|
|
|
|
if isinstance(dhcpObj, dhcp):
|
|
|
|
|
self.docObj.joinDoc(dhcpObj.doc)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class xml_gconf(xml_xfce):
|
|
|
|
|
"""Класс для объединения gconf-xml файлов"""
|
|
|
|
|
# root нода
|
|
|
|
|
rootNode = False
|
|
|
|
|
# body нода
|
|
|
|
|
bodyNode = False
|
|
|
|
|
# Документ
|
|
|
|
|
doc = False
|
|
|
|
|
# Текст профиля
|
|
|
|
|
text = ""
|
|
|
|
|
# Текущее время в секундах
|
|
|
|
|
currentTime = ""
|
|
|
|
|
# Комментарий
|
|
|
|
|
_comment = ("<!--","-->")
|
|
|
|
|
# поддерживаемые аттрибуты тега entry. Пример <entry type="int"/>
|
|
|
|
|
supportEntryTypes = ("int", "bool", "float", "string", "list", "pair")
|
|
|
|
|
|
|
|
|
|
def __init__(self, text):
|
|
|
|
|
self.text = text
|
|
|
|
|
# Создаем пустой объект
|
|
|
|
|
self.docObj = type("_empty_class", (object,), {})()
|
|
|
|
|
# Названия аттрибутов для пустого объекта
|
|
|
|
|
emptyMethods = ["getNodeBody","removeComment","insertBRtoBody",
|
|
|
|
|
"insertBeforeSepAreas"]
|
|
|
|
|
# Добавляем необходимые аттрибуты пустому объекту
|
|
|
|
|
for method in emptyMethods:
|
|
|
|
|
setattr(self.docObj, method, self.emptyMethod)
|
|
|
|
|
# Пустой метод (не нужно имя файла для корневой ноды)
|
|
|
|
|
setattr(self, "setNameBodyNode", self.emptyMethod)
|
|
|
|
|
# Создаем XML документ
|
|
|
|
|
self.doc = self.textToXML()
|
|
|
|
|
|
|
|
|
|
def getCurrentTime(self):
|
|
|
|
|
"""Получение текущего времени в секундах"""
|
|
|
|
|
return str(int(time.time()))
|
|
|
|
|
|
|
|
|
|
def textToXML(self):
|
|
|
|
|
"""Создание из текста XML документа
|
|
|
|
|
Храним xml в своем формате
|
|
|
|
|
"""
|
|
|
|
|
if not self.text.strip():
|
|
|
|
|
self.text = '''<?xml version="1.0"?><gconf></gconf>'''
|
|
|
|
|
try:
|
|
|
|
|
self.doc = xml.dom.minidom.parseString(self.text)
|
|
|
|
|
except:
|
|
|
|
|
self.setError(_("Can not text profile is XML"))
|
|
|
|
|
return False
|
|
|
|
|
self.rootNode = self.doc.documentElement
|
|
|
|
|
self.bodyNode = self.rootNode
|
|
|
|
|
return self.doc
|
|
|
|
|
|
|
|
|
|
def cmpListsNodesEntry(self, listXmlA, listXmlB):
|
|
|
|
|
"""Сравнение содержимого двух списков XML нод"""
|
|
|
|
|
getTextsNodes = lambda y: map(lambda x:\
|
|
|
|
|
x.toxml().replace(" ","").replace("\t","").replace("\n",""),
|
|
|
|
|
map(lambda x: x.removeAttribute("mtime") or x,
|
|
|
|
|
map(lambda x: x.cloneNode(True),
|
|
|
|
|
filter(lambda x: x.nodeType==x.ELEMENT_NODE, y))))
|
|
|
|
|
if set(getTextsNodes(listXmlA))==set(getTextsNodes(listXmlB)):
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True, levelNumber=0):
|
|
|
|
|
"""Объединение корневой ноды профиля и корневой ноды файла"""
|
|
|
|
|
if levelNumber>1:
|
|
|
|
|
return True
|
|
|
|
|
xmlNode = xmlNewNode
|
|
|
|
|
childNodes = xmlNode.childNodes
|
|
|
|
|
nextOldNode = xmlOldNode
|
|
|
|
|
flagError = False
|
|
|
|
|
if xmlNode.nodeType == xmlNode.ELEMENT_NODE:
|
|
|
|
|
n = xmlNode
|
|
|
|
|
tagName = n.tagName
|
|
|
|
|
nAction = u''
|
|
|
|
|
nName = u''
|
|
|
|
|
nType = u''
|
|
|
|
|
nValue = u''
|
|
|
|
|
attrName = ''
|
|
|
|
|
attrType = ''
|
|
|
|
|
if flagRootNode:
|
|
|
|
|
if not tagName == "gconf":
|
|
|
|
|
self.setError(_("The text is not a valid gconf-XML format \
|
|
|
|
|
(not found '<gconf>...</gconf>')"))
|
|
|
|
|
return False
|
|
|
|
|
else:
|
|
|
|
|
if not tagName == "entry":
|
|
|
|
|
self.setError(_("The text is not a valid gconf-XML format \
|
|
|
|
|
(found '<gconf><%s>..</%s></gconf>'")%(tagName,tagName))
|
|
|
|
|
return False
|
|
|
|
|
if not n.hasAttribute("name"):
|
|
|
|
|
self.setError(_('Not found arrtibute "name" in tag entry'))
|
|
|
|
|
return False
|
|
|
|
|
if not n.hasAttribute("type"):
|
|
|
|
|
self.setError(_('Not found arrtibute "type" in tag entry'))
|
|
|
|
|
return False
|
|
|
|
|
nName = n.getAttribute("name")
|
|
|
|
|
attrName = u"attribute::name='%s'"%nName
|
|
|
|
|
nType = n.getAttribute("type")
|
|
|
|
|
# Проверка правильности аттрибута type
|
|
|
|
|
if not nType in self.supportEntryTypes:
|
|
|
|
|
self.setError(\
|
|
|
|
|
_('Incorrect arrtibute "type" - <entry type="%s"/>')%nType)
|
|
|
|
|
return False
|
|
|
|
|
attrType = u"attribute::type='%s'"%nType
|
|
|
|
|
if n.hasAttribute("value"):
|
|
|
|
|
nValue = n.getAttribute("value")
|
|
|
|
|
if n.hasAttribute("action"):
|
|
|
|
|
nAction = n.getAttribute("action")
|
|
|
|
|
if not nAction in ("join","replace","drop"):
|
|
|
|
|
textError = _('''In the text, XML profile, look \
|
|
|
|
|
for a reserved attribute 'action' with the incorrect value.\n\
|
|
|
|
|
Valid values attribute 'action': \
|
|
|
|
|
(action="join", action="replace", action="drop")''')
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
if xmlOldNode.parentNode:
|
|
|
|
|
findStr = u"child::%s"%tagName
|
|
|
|
|
strAttr = [attrName, attrType]
|
|
|
|
|
findAttr = filter(lambda x: x, strAttr)
|
|
|
|
|
findAttrStr = ''
|
|
|
|
|
if findAttr:
|
|
|
|
|
strAttr = u' and '.join(findAttr)
|
|
|
|
|
findAttrStr = "[%s]"%strAttr
|
|
|
|
|
findPath = u"child::%s%s"%(tagName,findAttrStr)
|
|
|
|
|
# Рабочая нода
|
|
|
|
|
if flagRootNode:
|
|
|
|
|
workNode = xmlOldNode.parentNode
|
|
|
|
|
else:
|
|
|
|
|
workNode = xmlOldNode
|
|
|
|
|
oldNodes = xpath.Evaluate(findPath, workNode)
|
|
|
|
|
# Новая нода список
|
|
|
|
|
flagArray = False
|
|
|
|
|
if nType == "list" or nType == "pair":
|
|
|
|
|
flagArray = True
|
|
|
|
|
flagDrop = False
|
|
|
|
|
flagJoin = True
|
|
|
|
|
flagReplace = False
|
|
|
|
|
if nType=="string" or nAction=="replace":
|
|
|
|
|
flagJoin = False
|
|
|
|
|
flagReplace = True
|
|
|
|
|
elif nAction == "drop":
|
|
|
|
|
flagJoin = False
|
|
|
|
|
flagDrop = True
|
|
|
|
|
if flagRootNode:
|
|
|
|
|
textError = _('Incorrect action="drop" in root node')
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
if oldNodes:
|
|
|
|
|
if len(oldNodes)>1:
|
|
|
|
|
textError = _("The uncertainty in this profile are \
|
|
|
|
|
the same nodes at one level")
|
|
|
|
|
self.setError(textError)
|
|
|
|
|
return False
|
|
|
|
|
nextOldNode = oldNodes[0]
|
|
|
|
|
# Замещаем ноду в случае массива
|
|
|
|
|
if flagArray and not flagDrop:
|
|
|
|
|
replaceXmlNode = xmlNode.cloneNode(True)
|
|
|
|
|
# Сравнение содержимого нод
|
|
|
|
|
if not self.cmpListsNodesEntry([replaceXmlNode],
|
|
|
|
|
[nextOldNode]):
|
|
|
|
|
replaceXmlNode.setAttribute("mtime",
|
|
|
|
|
self.currentTime)
|
|
|
|
|
if nAction:
|
|
|
|
|
replaceXmlNode.removeAttribute("action")
|
|
|
|
|
workNode.replaceChild(replaceXmlNode,
|
|
|
|
|
nextOldNode)
|
|
|
|
|
flagJoin = False
|
|
|
|
|
flagReplace = False
|
|
|
|
|
childNodes = False
|
|
|
|
|
# Объединение нод
|
|
|
|
|
if flagJoin:
|
|
|
|
|
if nextOldNode.hasAttribute("value"):
|
|
|
|
|
oValue = nextOldNode.getAttribute("value")
|
|
|
|
|
if nValue != oValue:
|
|
|
|
|
nextOldNode.setAttribute("mtime",
|
|
|
|
|
self.currentTime)
|
|
|
|
|
nextOldNode.setAttribute("value",nValue)
|
|
|
|
|
# Замещение ноды
|
|
|
|
|
elif flagReplace:
|
|
|
|
|
replaceXmlNode = xmlNode.cloneNode(True)
|
|
|
|
|
# Сравнение содержимого нод
|
|
|
|
|
if not self.cmpListsNodesEntry([replaceXmlNode],
|
|
|
|
|
[nextOldNode]):
|
|
|
|
|
replaceXmlNode.setAttribute("mtime",
|
|
|
|
|
self.currentTime)
|
|
|
|
|
if not\
|
|
|
|
|
self._removeDropNodesAndAttrAction(\
|
|
|
|
|
replaceXmlNode):
|
|
|
|
|
return False
|
|
|
|
|
workNode.replaceChild(replaceXmlNode,
|
|
|
|
|
nextOldNode)
|
|
|
|
|
childNodes = False
|
|
|
|
|
# Удаление ноды
|
|
|
|
|
elif flagDrop:
|
|
|
|
|
workNode.removeChild(nextOldNode)
|
|
|
|
|
childNodes = False
|
|
|
|
|
else:
|
|
|
|
|
# Добавление ноды
|
|
|
|
|
childNodes = False
|
|
|
|
|
if not flagDrop:
|
|
|
|
|
appendXmlNode = xmlNode.cloneNode(True)
|
|
|
|
|
appendXmlNode.setAttribute("mtime", self.currentTime)
|
|
|
|
|
if not\
|
|
|
|
|
self._removeDropNodesAndAttrAction(appendXmlNode):
|
|
|
|
|
return False
|
|
|
|
|
workNode.appendChild(appendXmlNode)
|
|
|
|
|
if childNodes:
|
|
|
|
|
for node in childNodes:
|
|
|
|
|
levelNumber +=1
|
|
|
|
|
if not self._join(node, nextOldNode, False, levelNumber):
|
|
|
|
|
flagError = True
|
|
|
|
|
break
|
|
|
|
|
levelNumber -= 1
|
|
|
|
|
if flagError:
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def join(self, xml_gconfObj):
|
|
|
|
|
"""Объединяем конфигурации"""
|
|
|
|
|
# Получаем текущее время
|
|
|
|
|
self.currentTime = self.getCurrentTime()
|
|
|
|
|
if isinstance(xml_gconfObj, xml_gconf):
|
|
|
|
|
try:
|
|
|
|
|
self.joinDoc(xml_gconfObj.doc)
|
|
|
|
|
except:
|
|
|
|
|
self.setError(_("Can not join profile"))
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def getConfig(self):
|
|
|
|
|
"""Получение текстового файла из XML документа"""
|
|
|
|
|
data = self.doc.toprettyxml().split("\n")
|
|
|
|
|
data = filter(lambda x: x.strip(), data)
|
|
|
|
|
return "\n".join(data).replace("\t"," ")
|