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

7237 lines
310 KiB

#-*- coding: utf-8 -*-
# Copyright 2008-2010 Mir Calculate. 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
3 years ago
import cl_base
# from . import cl_base
import stat
import re
3 years ago
# import xml.dom.minidom
# import xml
# if hasattr(xml,"use_pyxml"):
# xml.use_pyxml()
# from xml import xpath
3 years ago
import cl_xml
# from . import cl_xml
# from .cl_xml import xpath, firstChild,\
from cl_xml import xpath, firstChild,\
insertBefore, str_to_xml_doc, xml_to_str, xmlShare,\
xmlNode, xmlField, xmlFields, xmlArea, xmlDoc
import subprocess
import types
import copy
import random
import string
import time
3 years ago
from copy import deepcopy
from collections.abc import Iterable
_ = lambda x : x
tr = cl_base.lang()
tr.setLocalDomain('cl_lib')
tr.setLanguage(sys.modules[__name__])
def cmp(a, b):
return (a > b) - (b < a)
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):
"""Вычисление условий применяемых в профилях
"""
# регулярное выражение для не версии
_re_not_Version = re.compile("[^0-9\.]|^$")
# регулярное выражение для функции
_reFunction = re.compile(\
"([a-zA-Z0-9\_\-]+)\([a-zA-Z0-9_\-\+\,\*\/\.\'\"~]+\)")
# Регулярное выражение для названия переменной
_reDenyName = re.compile("[^a-zA-Z0-9\_\-]")
# Регулярное выражение для сравниваемого значения
_reDenyValue = re.compile("[^0-9a-zA-Z_\.-]")
def _convertVers(self, verA, verB):
"""Конвертирование номеров версий для корректного сравнения
"""
elemA = verA.split(".")
elemB = verB.split(".")
if len(elemA) > len(elemB):
maxElemB = len(elemB)-1
for i in range(len(elemA)):
if i > maxElemB:
elemB.append("0")
else:
maxElemA = len(elemA)-1
for i in range(len(elemB)):
if i > maxElemA:
elemA.append("0")
for i in range(len(elemB)):
lenA = len(elemA[i])
lenB = len(elemB[i])
if lenA == lenB:
pass
elif lenA > lenB:
res = lenA - lenB
for z in range(res):
elemB[i] = "0" + elemB[i]
elif lenB > lenA:
res = lenB - lenA
for z in range(res):
elemA[i] = "0" + elemA[i]
return (".".join(elemA), ".".join(elemB))
def _equalTerm(self, term, textError, function=False):
"""Вычисление логических выражений для условий
Для корректной работы в классе который наследует этот класс
должен быть объявлен аттрибут self.objVar
(объект для работы с переменными)
function - функция для для обработки функций в заголовке блока
"""
trm = {"&":" and ","||":" or "}
rule = ["==", "!=", ">=", "<=", ">", "<"]
listEqual = []
for k in trm.keys():
if k in term:
3 years ago
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:
3 years ago
self.setError("'%s'" % term + " " + _("incorrect"))
self.setError (textError)
return False
else:
listEqual.append(k)
else:
#проверка на допустимость названия переменной
flagFunction = False
if self._reDenyName.search(vals[0]):
#проверка на допустимость функции
flagError = True
if function:
searchFunct = self._reFunction.search(vals[0])
if searchFunct:
flagError = False
flagFunction = True
if flagError:
self.setError("'%s'"%term + " " + _("incorrect"))
self.setError(textError)
return False
#проверка на допустимость значения
if self._reDenyValue.search(vals[1]):
self.setError("'%s'"%term + " " + _("incorrect"))
self.setError(textError)
return False
flagIntTypeVar = None
if flagFunction:
valVars = function("#-%s-#"%vals[0])
if valVars is False:
self.setError("'%s'"%term + " " + _("incorrect"))
self.setError(textError)
return False
if "load" == searchFunct.group(1):
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:
if valVars == "" and\
not self._re_not_Version.search(vals[1]):
valVars = "0"
elif vals[1] == "" and\
not self._re_not_Version.search(valVars):
vals[1] = "0"
else:
try:
valVars = self.objVar.Get(vals[0])
except self.objVar.DataVarsError as e:
print(textError)
print(e)
cl_base.exit(1)
# Номера версий для ini
flagNotIniFunct = True
# Два значения не пусты
flagNotEmptyVals = not (valVars == "" and vals[1] == "")
if flagFunction and flagNotEmptyVals and\
searchFunct.group(1) == "ini":
# Проверка значения на версию
if not self._re_not_Version.search(valVars) and\
not self._re_not_Version.search(vals[1]):
verFile, verVar = self._convertVers(vals[1],valVars)
res = eval("("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")")
if res:
listEqual.append("1")
else:
listEqual.append("0")
flagNotIniFunct = False
# Cравниваем номера версий
if flagNotIniFunct:
if flagNotEmptyVals and\
("_ver" in vals[0] or\
(flagFunction and searchFunct.group(1) == "pkg") or\
(flagFunction and searchFunct.group(1) == "load" and\
re.search("\(\s*ver\s*,",vals[0]))):
# Проверка значения на версию
if self._re_not_Version.search(vals[1]):
self.setError("'%s'"%term + " " + _("incorrect"))
self.setError (_("Value is not version"))
return False
# Проверка значения функции на версию
if self._re_not_Version.search(valVars):
self.setError("'%s'"%term + " " + _("incorrect"))
self.setError (_("Value function is not version"))
return False
verFile, verVar = self._convertVers(vals[1],valVars)
res = eval("("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")")
if res:
listEqual.append("1")
else:
listEqual.append("0")
flagNotIniFunct = False
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
res = eval("(%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
res = eval("("+'"""'+valVar+'"""'+sepF+"'"+valFile+"'"+")")
if res:
listEqual.append("1")
else:
listEqual.append("0")
else:
if not flagNotEmptyVals:
listEqual.append("0")
else:
self.setError("'%s'"%term + " "\
+ _("incorrect"))
self.setError (textError)
return False
res = eval("(%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) == tuple and len(comment) == 2:
_titleList = (_("Modified"), _("File of a profile"))
reCalcHeader =\
re.compile("\s*%s\s+%s.+Calculate.+\s+%s.+\s+%s\s?" % (\
comment[0],
_titleList[0],
_titleList[1],
comment[1],
),
re.M|re.I|re.U)
textUnicode = text
reS = reCalcHeader.search(textUnicode)
if reS:
textBody = textUnicode[:reS.start()]+textUnicode[reS.end():]
if textBody:
self.body = textBody
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 "format" in self.params:
return self.params["format"]
else:
return "raw"
def _getAppend(self):
"""Выдать тип добавления файла"""
if "append" in self.params 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 "comment" in self.params:
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 "append" in self.params 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.set("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 = []
3 years ago
childNodes = list(self.docObj.getNodeBody())
for node in childNodes:
if node.tag == "field":
3 years ago
listConfigTxt.append(self.docObj.getQuoteField(node))
elif node.tag == "area":
3 years ago
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 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)
3 years ago
self.caption.append(nameNode)
if action:
actNode = tmpNode.createNode(doc, "action", action)
3 years ago
self.caption.append(actNode)
for q in quotes:
quoteNode = tmpNode.createNode(doc, "quote", q)
3 years ago
self.caption.append(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.append(nameNode)
# for v in values:
# valueNode = self._createElement(doc, "value", v)
# self.field.append(valueNode)
# if action:
# actNode = self._createElement(doc, "action", action)
# self.field.append(actNode)
# for q in quotes:
# quoteNode = self._createElement(doc, "quote", q)
# self.field.append(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.append(xmlCaption.getCaption())
# if xmlFields:
# fields = xmlFields.getFields()
# for field in fields:
# self.area.append(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 is not None and firstChild(xmlActions[0]):
# firstChild(xmlActions[0]).text = actionTxt
# else:
# nodeObj = xmlNode()
# newNode = nodeObj.createNode(self.doc, "action", actionTxt)
# xmlField.append(newNode)
# def setActionArea(self, xmlArea, actionTxt):
# """Устанавливает свойство action для XML области"""
# xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
# xmlCaptions = xpath.Evaluate('child::caption',xmlArea)
# if xmlActions is not None and firstChild(xmlActions[0]):
# firstChild(xmlActions[0]).text = actionTxt
# else:
# if xmlCaptions:
# nodeObj = xmlNode()
# newNode = nodeObj.createNode(self.doc, "action", actionTxt)
# xmlCaptions[0].append(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.append(xmlNewField)
# return True
# newFieldsAction = self.getActionField(xmlNewField)
# newValues = self.getFieldValues(xmlNewField)
# flagCompare = True
# for nodeFieldOld in fieldsOldComp:
# if newFieldsAction == "drop":
# if nodeFieldOld.getnext() and\
# self.getTypeField(nodeFieldOld.getnext()) == "br":
# xmlArea.remove(nodeFieldOld.getnext())
# elif nodeFieldOld.getprevious() and\
# self.getTypeField(nodeFieldOld.getprevious()) == "br":
# xmlArea.remove(nodeFieldOld.getprevious())
# xmlArea.remove(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.getnext()
# newInsNode = deepcopy(nodeSeplist)
# self.setActionField(newInsNode,"append")
# if nextNode:
# appSplLst.append((newInsNode,
# nextNode,
# "insert"))
# else:
# appSplLst.append((newInsNode,
# False,
# "append"))
# else:
# newInsNode = deepcopy(nodeSeplist)
# 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.getparent()
# parentNode.remove(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 is not None:
# insNodesRepl.append((newNode, nxtNode, app))
# for newNode, nxtNode, app in insNodesRepl:
# if app == "insert":
# insertBefore(xmlArea, newNode, nxtNode)
# elif app == "append":
# xmlArea.append(newNode)
# if xmlOldField:
# parentNode = xmlOldField.getparent()
# if parentNode and newFieldsAction != "join":
# parentNode.remove(xmlOldField)
# for newNode, nxtNode, app in appSplLst:
# if app == "insert":
# insertBefore(xmlArea, newNode, nxtNode)
# elif app == "append":
# xmlArea.append(newNode)
# if not flagCompare and typeNewField != "seplist":
# # Устанавливаем action=replace
# self.setActionField(xmlNewField, "replace")
# # Если параметры поля не сходятся заменяем поле
# xmlArea.replace(fieldsOldComp[-1], deepcopy(xmlNewField))
# 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.getnext() and\
# self.getTypeField(nodeFieldOld.getnext()) == "br":
# xmlArea.remove(nodeFieldOld.getnext())
# xmlArea.remove(nodeFieldOld)
# return True
# def getSepListToField(self, xmlField):
# """Выдает элементы распределенного массива
# Область предок поля, в этой области ищутся
# элементы распределенного массива
# """
# nameField = self.getNameField(xmlField)
# if not nameField:
# return []
# parentNode = xmlField.getparent()
# #print parentNode.toprettyxml()
# if parentNode is not None:
# 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 "type" in fieldNode.keys():
# if fieldNode.get("type") == "comment" or\
# fieldNode.get("type") == "br":
# parentNode = fieldNode.getparent()
# parentNode.remove(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 nameNewField in removeNodesDict:
# 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 nameField not in notRemoveNodesDict:
# 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 name in removeNodesDict:
# 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.remove(removeNode)
# for node in sepListField:
# node.set("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.append(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.append(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.getprevious()
# if prevNode:
# parentNode = areaNode.getparent()
# insertBefore(parentNode, deepcopy(self.sepAreas),
# 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].getparent())
# dictVar = {}
# for fieldName in fields:
# nodeField = fieldName.getparent()
# fieldValue = xpath.Evaluate("child::value",nodeField)
# name = firstChild(fieldName).text
# value = ""
# if fieldValue is not None and firstChild(fieldValue[0]):
# value = firstChild(fieldValue[0]).text
# 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.getparent())
# if fieldsVal:
# break
# if not fieldsVal:
# return False
# fieldValue = xpath.Evaluate("child::value",
# fieldsVal[0])
# return firstChild(fieldValue[0]).text
# def getAllAreas(self):
# """Выдает все области"""
# return xpath.Evaluate('descendant::area', self.body)
# def getArea(self, nameArea, xmlArea):
# """По имени области находит области (первый потомок xmlArea)"""
# namesAreaComare = xpath.Evaluate(\
# "child::area/child::caption[child::name='%s']" %(nameArea),
# xmlArea)
# return [x.getparent() for x in namesAreaComare]
# 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.getparent()
# parentNode.remove(rmNode)
# captionAreasRemove = xpath.Evaluate(\
# "descendant::area/child::caption[child::action='drop']",
# xmlNewArea)
# for rmNodeCapt in captionAreasRemove:
# rmNode = rmNodeCapt.getparent()
# parentNode = rmNode.getparent()
# parentNode.remove(rmNode)
# self.setActionArea(xmlNewArea, "append")
# # Добавляем разделитель областей во вложенные области
# areaNodes = xpath.Evaluate('descendant::area',xmlNewArea)
# for areaNode in areaNodes:
# self.setActionArea(areaNode,"append")
# parentNode = areaNode.getparent()
# insertBefore(parentNode, deepcopy(self.sepAreas),
# areaNode)
# baseNode.append(xmlNewArea)
# # Добавляем разделитель областей
# insertBefore(baseNode, deepcopy(self.sepAreas), 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 firstChild(nodesNewArea[0]):
# nameArea = firstChild(nodesNewArea[0]).text.strip()
# flagFindArea = False
# baseNodes = []
# for oName in nodesNames:
# newAreaAction = self.getActionArea(xmlNewArea)
# oArea = oName.getparent().getparent()
# oNameTxt = ""
# if firstChild(oName) is not None:
# oNameTxt = firstChild(oName).text
# if nameArea == oNameTxt:
# flagFindArea = True
# # При использовании удаления
# if newAreaAction == "drop":
# prevNode = oName.getparent().getparent().getprevious()
# removePrevNodes = []
# while (prevNode) and self.getTypeField(prevNode) == "br":
# removePrevNodes.append(prevNode)
# prevNode = prevNode.getprevious()
# for removeNode in removePrevNodes:
# baseNode.remove(removeNode)
# baseNode.remove(oName.getparent().getparent())
# continue
# elif newAreaAction == "replace":
# oldAreaNode = oName.getparent().getparent()
# newAreaCaption = xpath.Evaluate('child::caption',
# xmlNewArea)[0]
# oldAreaCaption = xpath.Evaluate('child::caption',
# oldAreaNode)[0]
# if newAreaCaption and oldAreaCaption:
# xmlNewArea.replace(newAreaCaption, oldAreaCaption)
# self.setActionArea(xmlNewArea,"replace")
# baseNode.replace(oldAreaNode, xmlNewArea)
# continue
# baseNodes.append(oName.getparent().getparent())
# 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 "type" in xmlField.keys() and\
# xmlField.get("type") == "br":
# br = "\n"
# if xmlQuotes:
# field = xmlQuotes[0]
# if firstChild(field) is not None:
# return firstChild(field).text + br
# return "" + br
# def getFieldsArea(self, xmlArea):
# """Выдает потомков XML области"""
# xmlFields = []
# childNodes = list(xmlArea)
# for node in childNodes:
# if node.tag == "area" or node.tag == "field":
# xmlFields.append(node)
# return xmlFields
# def getTypeField(self, xmlField):
# """Выдает тип поля"""
# if "type" in xmlField.keys():
# return xmlField.get("type")
# else:
# return False
# def getNameField(self, xmlField):
# """Выдает имя поля"""
# xmlNameFields = xpath.Evaluate('child::name', xmlField)
# if xmlNameFields is not None and firstChild(xmlNameFields[0]):
# return firstChild(xmlNameFields[0]).text
# else:
# return False
# def getNameArea(self, xmlArea):
# """Выдает имя области"""
# xmlNameAreas = xpath.Evaluate('child::caption/name', xmlArea)
# if xmlNameAreas is not None and firstChild(xmlNameAreas[0]):
# return firstChild(xmlNameAreas[0]).text
# 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 firstChild(node) is not None:
# quotes.append(firstChild(node).text)
# if len(quotes) == 0:
# quotes.append("")
# quotes.append("")
# elif len(quotes) == 1:
# quotes.append("")
# return quotes
# for i in xmlAreas:
# if i.tag == "area":
# quotesI = getQuotesArea(i)
# startAreaI = quotesI[0]
# endAreaI = quotesI[1]
# text.append(startAreaI)
# xmlFieldsI = self.getFieldsArea(i)
# for f in xmlFieldsI:
# if f.tag == "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 is not None and firstChild(xmlActions[0]):
# return firstChild(xmlActions[0]).text
# else:
# return False
# def getFieldValues(self, xmlField):
# """Выдает значения XML поля в виде массива"""
# vals = []
# xmlValues = xpath.Evaluate('child::value',xmlField)
# if xmlValues:
# for node in xmlValues:
# if firstChild(node) is not None:
# vals.append(firstChild(node).text)
# return vals
# def getActionArea(self, xmlArea):
# """Выдает свойство action XML области"""
# xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
# if xmlActions is not None and firstChild(xmlActions[0]):
# return firstChild(xmlActions[0]).text
# else:
# return False
# def delActionNodeArea(self, xmlArea):
# """Удаляет свойство action XML области"""
# xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
# if xmlActions is not None and firstChild(xmlActions[0]):
# parentNode = xmlActions[0].getparent()
# parentNode.remove(xmlActions[0])
# return True
# else:
# return False
# def delActionNodeField(self, xmlField):
# """Удаляет свойство action XML поля"""
# xmlActions = xpath.Evaluate('child::action',xmlField)
# if xmlActions is not None and firstChild(xmlActions[0]):
# parentNode = xmlActions[0].getparent()
# parentNode.remove(xmlActions[0])
# return True
# else:
# return False
# # Создает распределенные списки
# def postParserListSeplist(self, xmlArea):
# """Создает распределенные списки из элементов области"""
# # Потомки
# childNodes = self.getFieldsArea(xmlArea)
# # содержит списки нод полей с одинаковыми именами в одной области
# fieldsSeplist = {}
# for node in childNodes:
# if node.tag == "area":
# self.postParserListSeplist(node)
# else:
# fieldName = False
# xmlFieldNameNodes = xpath.Evaluate('child::name',node)
# if xmlFieldNameNodes is not None and firstChild(xmlFieldNameNodes[0]):
# fieldName = firstChild(xmlFieldNameNodes[0]).text
# if fieldName:
# if fieldName in fieldsSeplist:
# 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.set("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.tag == "area":
# if self.getActionArea(node) == "append" or\
# self.getActionArea(node) == "join":
# self.delActionNodeArea(node)
# if lastNode and "type" in lastNode.keys() and\
# lastNode.get("type") == "br" or\
# lastNode and "type" in lastNode.keys() and\
# lastNode.get("type") == "comment":
# indNext = i + 1
# if indNext == lenChildNodes:
# xmlArea.append(deepcopy(fieldXMLBr))
# else:
# nextNode = childNodes[indNext]
# lastTmpNode = insertBefore(xmlArea, deepcopy(fieldXMLBr),
# nextNode)
# else:
# insertBefore(xmlArea, deepcopy(fieldXMLBr),
# node)
# self.insertBRtoBody(node)
# # Нода field
# else:
# if self.getActionField(node) == "append" or\
# self.getActionField(node) == "join":
# self.delActionNodeField(node)
# if lastNode and "type" in lastNode.keys() and\
# lastNode.get("type") == "br" or\
# lastNode and "type" in lastNode.keys() and\
# lastNode.get("type") == "comment":
# indNext = i + 1
# if indNext == lenChildNodes:
# xmlArea.append(deepcopy(fieldXMLBr))
# else:
# nextNode = childNodes[indNext]
# lastTmpNode = insertBefore(xmlArea,
# deepcopy(fieldXMLBr),
# nextNode)
# else:
# insertBefore(xmlArea, deepcopy(fieldXMLBr),
# 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 "type" in xmlField.keys() and\
# xmlField.get("type") == "br":
# lenBrArea += 1
# continue
# if not xmlNames and not xmlVals:
# flagListXml = False
# break
# if xmlNames and firstChild(xmlNames[0]) is not None and\
# firstChild(xmlNames[0]).text:
# flagListXml = False
# break
# if not (xmlVals and firstChild(xmlVals[0]) is not None and\
# firstChild(xmlVals[0]).text):
# flagListXml = False
# break
# else:
# fieldValues.append(firstChild(xmlVals[0]).text)
# if lenXmlFields == lenBrArea:
# flagListXml = False
# if flagListXml:
# nameNode = xpath.Evaluate('child::caption/name',xmlArea)[0]
# fieldName = ""
# if firstChild(nameNode) is not None:
# fieldName = firstChild(nameNode).text
# 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.getparent()
# insertBefore(parentNode, fieldXML, xmlArea)
# if fieldXMLBr:
# insertBefore(parentNode, fieldXMLBr, xmlArea)
# parentNode.remove(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.decode("UTF-8").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 = []
self.fifo = []
for profileDir in profilesDirs:
if profileDir:
dirP = dirProf()
dirP.baseDir = profileDir
for dirname, dirs, files in os.walk(profileDir):
for nameFile in dirs + files:
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)
elif stat.S_ISFIFO(os.stat(absNameFile)[stat.ST_MODE]):
dirP.fifo.append(absNameFile)
dirs.append(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
self.FO.flush()
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:]
return chr(int(he, 16))
def _hexToChar(self, he):
return chr(int(he, 16))
def encode(self, text):
"""Кодирует смешанный формат в UTF-8"""
ind = 0
l = 0
utf = []
lenUtf = []
indErr = []
i = 0
for ch in text:
r, l = self._retUTF(ch)
utf.append(r)
lenUtf.append(l)
i+=1
while 1:
if utf[ind] == '_fb_':
res, l = self._sumbUtf(utf[ind:],lenUtf[ind])
if res is False:
indErr.append(ind)
if l>0:
ind +=l
if ind >= len(utf):
break
else:
if utf[ind] != '_ch_':
indErr.append(ind)
ind +=1
if ind >= len(utf):
break
if indErr:
lenIndErr = len(indErr)
block = []
blocks = []
if lenIndErr > 1:
i = 1
while 1:
if i == 1:
block.append(indErr[i-1])
if indErr[i] - indErr[i-1] == 1:
block.append(indErr[i])
else:
if block:
blocks.append(block)
block = []
block.append(indErr[i])
i +=1
if i >= lenIndErr:
break
else:
block.append(indErr[0])
if block:
blocks.append(block)
listErr = []
for block in blocks:
string = ""
for elem in block:
string += hex(ord(text[elem]))[-2:]
listErr.append((block[0],"__hex__?%s?__hex__" %string,elem))
textOut = text
deltaInd = 0
for erEl in listErr:
startInd = erEl[0] + deltaInd
endInd = erEl[2] + 1 + deltaInd
textOut = textOut[:startInd] + erEl[1] + textOut[endInd:]
deltaInd += len(erEl[1])-(erEl[2]-erEl[0]+1)
#if i == 1:
#break
#i += 1
return textOut
def decode(self, text):
"""Декодирует UTF-8 в смешанный формат"""
varStart = "__hex__\?"
varEnd = "\?__hex__"
# -1 Это экранирование '?' которое тоже считается
deltVarStart = len(varStart)-1
deltVarEnd = len(varEnd)-1
reVar = re.compile(("%s[a-f0-9]+%s")%(varStart,varEnd),re.M)
resS = reVar.search(text)
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
def getUserDataInLDAP(self, userName):
"""Получаем домашнюю директорию пользователя из LDAP"""
if not self.conLdap:
3 years ago
# from . import cl_utils2
import cl_utils2
data = self.getLDAPDataInConfig()
if not data:
return ""
serverName, usersDN, bindDN, bindPW = data
# Подключаемся к LDAP
ldapObj = cl_utils2.ldapFun(bindDN, bindPW, serverName)
if self.getError():
return ""
self.conLdap = ldapObj.conLdap
searchScope = ldap.SCOPE_ONELEVEL
searchFilter = "uid=%s" %(userName)
retrieveAttributes = ["uidNumber",
"gidNumber"
"homeDirectory"]
resSearch = ldapObj.ldapSearch(usersDN, searchScope,
searchFilter, retrieveAttributes)
if resSearch:
if 'uidNumber' in resSearch[0][0][1] and\
'gidNumber' in resSearch[0][0][1] and\
'homeDirectory' in resSearch[0][0][1]:
uid = resSearch[0][0][1]['uidNumber'][0].decode("UTF-8")
gid = resSearch[0][0][1]['gidNumber'][0].decode("UTF-8")
# uid = searchUser[0][0][1]['uidNumber'][0]
# gid = searchUser[0][0][1]['gidNumber'][0]
homeDir = resSearch[0][0][1]['homeDirectory'][0].decode("UTF-8")
return uid, gid, homeDir
return ""
class processingTemplates:
"""Класс для обработки шаблонов"""
def processingFile(self, path, prefix):
"""Обработка в случае профиля файла"""
return True
def processingDirectory(self, path, prefix):
"""Обработка в случае директории если возвращаем None то пропуск дир."""
return True
def scanningTemplates(self, scanDir, skipFile=None, skipDir=None,
prefix=None, flagDir=False):
"""Время последней модификации внутри директории scanDir"""
if skipFile is None:
skipFile = []
if skipDir is None:
skipDir = []
ret = True
if prefix is None:
prefix = os.path.join(scanDir,"")[:-1]
if not flagDir:
# проверка корневой директории
retDir = self.processingDirectory(scanDir, scanDir)
if retDir is None:
return None
elif retDir is False:
return False
if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]):
for fileOrDir in sorted(os.listdir(scanDir)):
absPath = os.path.join(scanDir,fileOrDir)
relPath = absPath.split(prefix)[1]
stInfo = os.lstat(absPath)
statInfo = stInfo[stat.ST_MODE]
if stat.S_ISREG(statInfo):
# Обработка файла
if relPath in skipFile:
continue
if not self.processingFile(absPath, prefix):
ret = False
break
elif stat.S_ISDIR(statInfo):
# Обработка директории
if relPath in skipDir:
continue
retDir = self.processingDirectory(absPath, prefix)
if retDir is None:
continue
elif retDir is False:
ret = False
break
ret = self.scanningTemplates(absPath, skipFile,
skipDir, prefix, True)
if ret is False:
break
return ret
class profile(_file, _terms, xmlShare, processingTemplates):
"""Класс для работы с профилями
На вход 2 параметра: объект хранения переменных, имя сервиса - не
обязательный параметр
"""
# Словарь установленных программ {"имя программы":[версии]}
installProg = {}
# Cписок просканированных категорий установленных программ
installCategory = []
# Флаг сканирования всех установленных программ
flagAllPkgScan = False
# Название файла профиля директории
profDirNameFile = ".calculate_directory"
# стек глобальных переменных
stackGlobalVars = []
# директория установленных программ
basePkgDir = "/var/db/pkg"
# регулярное выражение для поиска версии
reFindVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*")
def __init__(self, objVar, servDir=False, dirsFilter=None, filesFilter=None):
# Необрабатываемые директории
self.dirsFilter = dirsFilter if dirsFilter is not None else []
# Необрабатываемые файлы
self.filesFilter = filesFilter if filesFilter is not None else []
_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]
# Созданные директории
self.createdDirs = []
# Примененные файлы
self.filesApply = []
# номер обрабатываемого файла
self.numberProcessProf = 0
# имя текущей программы
_nameProgram = self.objVar.Get("cl_name").capitalize()
# версия текущей программы
_versionProgram = self.objVar.Get("cl_ver")
# имя и версия текущей программы
self.programVersion = "%s %s"%(_nameProgram, _versionProgram)
# Словарь измененных директорий
self.changeDirs = {}
# Словарь директорий с количесвом файлов шаблонов
self.dictTemplates = {}
# Общее количество шаблонов
self.allTemplates = 0
# Аттрибуты для функции шаблона ini()
# Первоначальный словарь переменных для ini()
self.prevDictIni = {}
# Текущий словарь переменных для ini()
self.currDictIni = {}
# Время модификации конфигурационного файла для ini()
self.timeIni = -1
self.uid, self.gid, self.homeDir = self.getDataUser()
# Путь к конфигурационному файлу для ini()
self.pathConfigIni = os.path.join(self.homeDir, ".calculate")
self.fileConfigIni = os.path.join(self.pathConfigIni,"ini.env")
# Словарь времен модификации env файлов
self.timeConfigsIni = {}
def getDataUser(self):
"""Получить информацию о пользователе"""
userName = self.objVar.Get("ur_login")
if not userName:
userName = "root"
import pwd
try:
pwdObj = pwd.getpwnam(userName)
uid = pwdObj.pw_uid
gid = pwdObj.pw_gid
homeDir = pwdObj.pw_dir
except:
print(_("Can not found user %s")%str(userName))
cl_base.exit(1)
return uid, gid, homeDir
# Преобразование восьмеричного в целое (ввод строка, вывод число)
def __octToInt(self, strOct):
if strOct:
try:
# exec("res =" + "0" + strOct)
res = int(strOct, 8)
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):
"""Рекурсивное удаление директории
входной параметр директория
Обязательно должен быть определен метод self.printERROR
"""
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(key=len, reverse=True)
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 = [[x,next(genOut)] for x in genIn]
createDirs = []
createDir = []
while (len(inAndOutDirs)>1):
tmpDirIn = baseDir + "/".join(x[0] for x in inAndOutDirs)
tmpDirOut = baseDirMv + "/".join(x[1] for x in 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 as 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 strNum in localVars:
try:
num = int(localVars[strNum])
except:
print(_("error in profile %s")%nameProfile)
print(_("error local var %s not int")\
%str(strNum))
cl_base.exit(1)
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 nameLocVar not in localVars:
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 funcExists(funTxt,resS,textProfileTmp):
"""если файл существует читает из файла локальную переменную
если один параметр - выводит значение локальной переменной
"""
terms = funTxt[7:-1].replace(" ","").split(",")
if len(terms) !=1:
print(_("error in profile %s")%nameProfile)
print(_("error profile term %s")%str(funTxt))
cl_base.exit(1)
fileName = terms[0].strip()
if fileName[0] == "~":
# Получаем директорию пользователя
fileName = os.path.join(self.homeDir,
fileName.partition("/")[2],"")[:-1]
elif fileName[0] != "/":
path = os.path.split(nameSystemFile)[0]
fileName=os.path.join(path,fileName)
replace = ""
if os.path.exists(fileName):
replace = "1"
textProfileTmp = textProfileTmp[:resS.start()] + replace +\
textProfileTmp[resS.end():]
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] == "~":
# Получаем директорию пользователя
fileName = os.path.join(self.homeDir,
fileName.partition("/")[2],"")[:-1]
elif fileName[0] != "/":
path = os.path.split(nameSystemFile)[0]
fileName=os.path.join(path,fileName)
else:
fileName = terms[1].strip()
# Если домашняя директория
if fileName[0] == "~":
# Получаем директорию пользователя
fileName = os.path.join(self.homeDir,
fileName.partition("/")[2],"")[:-1]
elif fileName[1] != "/":
path = os.path.split(nameSystemFile)[0]
fileName=os.path.join(path,fileName)
replace = ""
if os.path.exists(fileName):
FD = open(fileName)
replace = FD.read().strip()
FD.close
if not replace and len(terms) == 2 and terms[0] in ["ver","num"]:
replace = "0"
textProfileTmp = textProfileTmp[:resS.start()] + replace +\
textProfileTmp[resS.end():]
return textProfileTmp
def getInstallPkgGentoo():
"""Выдает словарь инсталлированных программ и номеров версий"""
pkgs = []
for dirname, dirs, files in os.walk(self.basePkgDir):
for nameFile in dirs + files:
absNameFile = os.path.join(dirname, nameFile)
if os.path.isdir(absNameFile):
tail = absNameFile.split(self.basePkgDir)
if len(tail) == 2:
tail = tail[1].split('/')
if len(tail) == 3 and tail[1] != 'virtual':
pkgs.append(tail[2])
return sharePkg(pkgs)
def sharePkg(pkgs):
"""Получение имен и номеров версий программ"""
pkgs.sort()
installProg = {}
for pkg in pkgs:
findVer = self.reFindVer.search(pkg)
if findVer:
version = findVer.group()
name = pkg.split(version)[0][:-1]
if name in installProg:
installProg[name].append(version)
else:
installProg[name] = [version]
return installProg
def pkg(nameProg, installProg):
"""Выдает установленные версии по имени программы"""
if nameProg in installProg:
return installProg[nameProg][-1]
else:
return ""
def funcPkg(funTxt,resS,textProfileTmp):
"""локальная функция выдает номер версии программы"""
terms = funTxt[4:-1].replace(" ","")
# Название программы
nameProg = terms
# Замена функции в тексте шаблона
replace = ""
if "/" in nameProg:
if nameProg in self.installProg:
replace = pkg(nameProg, self.installProg)
else:
category, spl, nProg = terms.partition("/")
if not category in self.installCategory:
self.installCategory.append(category)
pathCategory = os.path.join(self.basePkgDir, category)
if os.path.exists(pathCategory):
pkgs = os.listdir(pathCategory)
pkgs = [os.path.join(category, x) for x in pkgs]
installProg = sharePkg(pkgs)
replace = pkg(nameProg, installProg)
self.installProg.update(installProg)
else:
if not self.flagAllPkgScan:
installProg = getInstallPkgGentoo()
self.installProg.update(installProg)
profile.flagAllPkgScan = True
replace = pkg(nameProg, self.installProg)
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 range(lenStr)])
elif terms[0] == fArgvNames[1]:
replace=''.join([random.choice(string.ascii_letters + \
string.digits) for i in range(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
def funcPush(funTxt,resS,localVars,textProfileTmp):
"""локальная функция записывает значение переменной
в стек глобальных переменных
"""
terms = funTxt[5:-1].replace(" ","").split(",")
# Название локальной переменной
nameLocVar = terms[0]
flagFoundVar = False
if nameLocVar in localVars.keys():
flagFoundVar = True
value = localVars[nameLocVar]
else:
try:
value = self.objVar.Get(nameLocVar)
flagFoundVar = True
except:
pass
if flagFoundVar:
# Если переменная существует
if len(terms) == 1:
self.stackGlobalVars.append(str(value))
else:
print(_("error in profile %s")%nameProfile)
print(_("error profile term %s")%str(funTxt))
print(_("error var %s exists")%str(nameLocVar))
cl_base.exit(1)
else:
# Если переменная не существует
if len(terms) == 1:
print(_("error in profile %s")%nameProfile)
print(_("error profile term %s")%str(funTxt))
print(_("error var %s not exists")%str(nameLocVar))
cl_base.exit(1)
elif len(terms) == 2:
value = terms[1].strip()
self.stackGlobalVars.append(str(value))
localVars[nameLocVar] = value
else:
print(_("error in profile %s")%nameProfile)
print(_("error profile term %s")%str(funTxt))
cl_base.exit(1)
replace = ""
textProfileTmp = textProfileTmp[:resS.start()] + replace +\
textProfileTmp[resS.end():]
return textProfileTmp
def funcPop(funTxt,resS,localVars,textProfileTmp):
"""локальная функция получает значение
из стека глобальных переменных и присвает локальной переменной
"""
terms = funTxt[4:-1].replace(" ","").split(",")
# Название локальной переменной
nameLocVar = terms[0]
if len(terms) == 1:
if self.stackGlobalVars:
localVars[nameLocVar] = self.stackGlobalVars.pop()
else:
print(_("error in profile %s")%nameProfile)
print(_("error profile term %s")%str(funTxt))
print(_("error, gloval variables stack is empty"))
cl_base.exit(1)
else:
print(_("error in profile %s")%nameProfile)
print(_("error profile term %s")%str(funTxt))
cl_base.exit(1)
replace = ""
textProfileTmp = textProfileTmp[:resS.start()] + replace +\
textProfileTmp[resS.end():]
return textProfileTmp
def loadVarsIni(iniFileName):
""" Читает файл fileName
создает и заполняет переменные на основе этого файла
Используеться совместно c funcIni
"""
localVarsIni = {}
# Выходим если есть предыдущие ошибки
if self.getError():
return False
# получить объект ini файла
config = cl_base.iniParser(iniFileName)
# получаем все секции из конфигурационного файла
allsect = config.getAllSectionNames()
if not allsect:
if self.getError():
# Очистка ошибки
_error.error = []
return localVarsIni
# Заполняем переменные для funcIni
for sect in allsect:
sectVars = config.getAreaVars(sect)
for name in sectVars.keys():
nameVar = "%s.%s"%(sect,name)
valueVar = sectVars[name]
localVarsIni[nameVar] = valueVar
return localVarsIni
def getTimeFile(fileName):
# Получаем время модификации файла
if fileName in self.timeConfigsIni:
return self.timeConfigsIni[fileName]
return 0
def funcIni(funTxt, resS, textProfileTmp):
"""локальная функция записывает и считывает значение переменной
из ini файла ~./calculate/ini.env
"""
# Создаем директорию
if not os.path.exists(self.pathConfigIni):
os.makedirs(self.pathConfigIni)
os.chown(self.pathConfigIni, int(self.uid), int(self.gid))
termsRaw = funTxt[4:-1].split(",")
flagFirst = True
terms = []
for term in termsRaw:
if flagFirst:
terms.append(term.replace(" ",""))
flagFirst = False
else:
val = term.strip()
# Флаг (не найдены кавычки)
flagNotFoundQuote = True
for el in ('"',"'"):
if val.startswith(el) and val.endswith(el):
terms.append(val[1:-1])
flagNotFoundQuote = False
break
if flagNotFoundQuote:
terms.append(val)
# Название локальной переменной
nameLocVar = terms[0]
namesVar = nameLocVar.split(".")
if len(namesVar) == 1:
nameLocVar = "main.%s"%nameLocVar
elif len(namesVar)>2:
print(_("error in profile %s")%nameProfile)
print(_("error profile term %s")%str(funTxt))
cl_base.exit(1)
replace = ""
# Получаем время модификации конфигурационного файла
curTime = getTimeFile(self.fileConfigIni)
if len(terms) == 1:
if self.timeIni != curTime:
# читаем переменные из файла
self.prevDictIni = loadVarsIni(self.fileConfigIni)
self.currDictIni.update(self.prevDictIni)
self.timeIni = getTimeFile(self.fileConfigIni)
if nameLocVar in self.currDictIni.keys():
replace = self.currDictIni[nameLocVar]
elif len(terms) == 2:
if self.timeIni != curTime:
# читаем переменные из файла
self.prevDictIni = loadVarsIni(self.fileConfigIni)
self.currDictIni.update(self.prevDictIni)
self.timeIni = getTimeFile(self.fileConfigIni)
# Значение локальной переменной
valueLocVar = terms[1]
self.currDictIni[nameLocVar] = valueLocVar
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)
# Локальные переменные
localVars = {}
# Регулярное выражние для сложения
sNum = re.compile("\-[^\-\+]+|[^\-\+]+")
# Регулярное выражение для умножениея и деления
sMD = re.compile("[^\-\+\*\/]+")
resS = self._reFunc.search(textProfile)
textProfileTmp = textProfile
flagIniFunc = False
while resS:
mark = textProfileTmp[resS.start():resS.end()]
funTxt = mark[self._deltVarStart:-self._deltVarEnd]
# Функция sum
if funTxt.startswith("sum("):
textProfileTmp = funcSum(funTxt,resS,localVars,textProfileTmp)
resS = self._reFunc.search(textProfileTmp)
# Функция load
elif funTxt.startswith("load("):
textProfileTmp = funcLoad(funTxt,resS,textProfileTmp)
resS = self._reFunc.search(textProfileTmp)
elif funTxt.startswith("pkg("):
textProfileTmp = funcPkg(funTxt,resS,textProfileTmp)
resS = self._reFunc.search(textProfileTmp)
elif funTxt.startswith("rnd("):
textProfileTmp = funcRnd(funTxt,resS,textProfileTmp)
resS = self._reFunc.search(textProfileTmp)
elif funTxt.startswith("case("):
textProfileTmp = funcCase(funTxt,resS,textProfileTmp)
resS = self._reFunc.search(textProfileTmp)
elif funTxt.startswith("pop("):
textProfileTmp = funcPop(funTxt,resS,localVars,textProfileTmp)
resS = self._reFunc.search(textProfileTmp)
elif funTxt.startswith("push("):
textProfileTmp = funcPush(funTxt,resS,localVars,textProfileTmp)
resS = self._reFunc.search(textProfileTmp)
elif funTxt.startswith("ini("):
flagIniFunc = True
textProfileTmp = funcIni(funTxt, resS, textProfileTmp)
resS = self._reFunc.search(textProfileTmp)
elif funTxt.startswith("exists("):
textProfileTmp = funcExists(funTxt, resS, textProfileTmp)
resS = self._reFunc.search(textProfileTmp)
else:
resS = False
if flagIniFunc:
# Очистка файла в случае его ошибочного чтения
if not self.prevDictIni and os.path.exists(self.fileConfigIni):
FD = open(self.fileConfigIni, "r+")
FD.truncate(0)
FD.seek(0)
FD.close()
# Если конф. файл модифицирован шаблоном
curTime = getTimeFile(self.fileConfigIni)
if curTime != self.timeIni:
# Считаем переменные из конф. файла
self.prevDictIni = loadVarsIni(self.fileConfigIni)
self.currDictIni.update(self.prevDictIni)
self.timeIni = curTime
# Если словари переменных не совпадают
if self.prevDictIni != self.currDictIni:
# Запишем переменные в конфигурационный файл
# Создание объекта парсера
config = cl_base.iniParser(self.fileConfigIni)
# секции будущего конфигурационного файла
sects = list(set(x.split(".")[0] for x in self.currDictIni.keys()))
# запись переменных в файл
for sect in sects:
dictVar = {}
for varName in self.currDictIni.keys():
if varName.startswith("%s."%sect):
nameVar = varName.rpartition(".")[2]
valueVar = self.currDictIni[varName]
if valueVar:
dictVar[nameVar] = valueVar
if dictVar:
# Запись переменных в секцию
config.setVar(sect, dictVar)
# читаем переменные из файла
self.prevDictIni = loadVarsIni(self.fileConfigIni)
self.currDictIni.update(self.prevDictIni)
self.timeConfigsIni[self.fileConfigIni] = float(time.time())
self.timeIni = getTimeFile(self.fileConfigIni)
# Меняем владельца в случае необходимости
if os.path.exists(self.fileConfigIni):
fd = os.open(self.fileConfigIni, os.O_RDONLY)
fst = os.fstat(fd)
uid = fst.st_uid
gid = fst.st_gid
os.close(fd)
if self.uid!=uid or self.gid!=gid:
os.chown(self.fileConfigIni, int(self.uid), int(self.gid))
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) == tuple 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 = []
for profileDir in profilesDirs:
if profileDir:
# Обработка условий в названии директории
if self.getNeedProfile(profileDir):
if self.getError():
flagError = True
break
dirP = dirProf()
dirP.baseDir = profileDir
for dirname, dirs, files in os.walk(profileDir):
for nameFile in dirs + files:
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)
dirs.append(dirP)
else:
if self.getError():
flagError = True
break
if flagError:
return []
return dirs
def applyProfiles(self):
"""Применяет профили к конфигурационным файлам"""
def createDictTemplates(path, prefix, dictTemplates):
"""Создает словарь {"директория":"кол-во шаблонов" ...}
и считает общее количество шаблонов
"""
# Количество шаблонов
self.allTemplates += 1
dirTemplate = os.path.split(path)[0]
while(True):
if dirTemplate in dictTemplates.keys():
dictTemplates[dirTemplate] += 1
else:
dictTemplates[dirTemplate] = 1
if dirTemplate == prefix:
break
dirTemplate = os.path.split(dirTemplate)[0]
return dictTemplates
if not self.objVar.defined("cl_profile_path"):
self.setError (_("not defined Var: ") + "cl_profile_path")
return False
dirsProfiles = self.objVar.Get("cl_profile_path")
dirsProfiles.sort()
# Словарь измененных директорий
self.changeDirs = {}
# Созданные директории
self.createdDirs = []
# Примененные файлы
self.filesApply = []
# Номер применяемого шаблона
self.numberProcessProf = 0
# Словарь директорий с количеством файлов шаблонов
self.dictTemplates = {}
# Количество шаблонов
self.allTemplates = 0
# Время доступа к конфигурационному файлу функции шаблона ini()
self.timeIni = -1
# Первоначальный словарь переменных для ini()
self.prevDictIni = {}
# Текущий словарь переменных для ini()
self.currDictIni = {}
# Словарь времен модификации env файлов
self.timeConfigsIni = {}
if self._servDir:
tmpDirsProfiles = []
for dirP in dirsProfiles:
dirProf = dirP + self._servDir
if os.access(dirProf, os.F_OK):
# Если директория существует
tmpDirsProfiles.append(dirProf)
dirsProfiles = tmpDirsProfiles
scanObj = processingTemplates()
scanObj.processingFile = lambda x,y: createDictTemplates(x, y,\
self.dictTemplates)
# Считаем количество шаблонов
for dirTemplate in dirsProfiles:
scanObj.scanningTemplates(dirTemplate,
skipFile=self.filesFilter,
skipDir=self.dirsFilter)
self.numberAllProfiles(self.allTemplates)
for dirTemplate in dirsProfiles:
if self.scanningTemplates(dirTemplate,
skipFile=self.filesFilter,
skipDir=self.dirsFilter) is False:
return False
return (self.createdDirs, self.filesApply)
def processingFile(self, path, prefix):
"""Обработка в случае профиля файла"""
self.numberProcessProf += 1
self.numberProcessProfiles(self.numberProcessProf)
# Пропуск шаблонов директорий
if self.profDirNameFile == os.path.split(path)[1]:
return True
if self.getNeedProfile(path):
if self.getError():
return False
fileProfileChange = path
findChangeDir = False
listD = list(self.changeDirs.items())
listD.reverse()
for dirChangeIn, dirChangeOut in listD:
st,mid,end = path.partition(dirChangeIn)
if (not st) and mid and end:
findChangeDir = True
break
if findChangeDir:
oldFile = dirChangeOut + end
else:
oldFile = path.partition(prefix)[2]
# файл в системе без условий
oldFile = "/".join(x.split("?")[0] for x in oldFile.split("/"))
if not findChangeDir:
oldFile = self._baseDir + oldFile
# Фильтрация профилей по названию файла
if oldFile in self.filesFilter:
return True
listProfTitle = prefix.split("/")[-2:]
profTitle = '"' + "/".join(listProfTitle) + '"'
# Записываем в переменную обрабатываемый файл
self.objVar.Set("cl_pass_file",oldFile)
# Пишем время модификации *.env файлов
if oldFile.endswith(".env"):
self.timeConfigsIni[oldFile] = float(time.time())
filesApl = self.join(path, oldFile,
(self.programVersion,profTitle))
if filesApl:
self.filesApply += filesApl
else:
if self.getError():
#print self.getError()
return False
return True
def processingDirectory(self, path, prefix):
"""Обработка в случае директории если возвращаем None то пропуск дир."""
# Файл шаблона директории
dirInfoFile = os.path.join(path, self.profDirNameFile)
# Проверяем заголовок
ret = self.__isApplyHeadDir(dirInfoFile)
if not ret:
if self.getError():
self.setError(_("Incorrect profile: " ) + dirInfoFile)
return False
# Добавление количества файлов в пропущенной директории
if path in self.dictTemplates.keys():
self.numberProcessProf += self.dictTemplates[path]
return None
newDir = self._baseDir + path.partition(prefix)[2]
newDir = "/".join(x.split("?")[0] for x in newDir.split("/"))
# Применяем шаблон
pathDir, objHeadDir = self.__getApplyHeadDir(newDir,
dirInfoFile,
self.changeDirs)
# Фильтрация профилей по названию директории
if pathDir in self.dirsFilter:
# Добавление количества файлов в пропущенной директории
if path in self.dictTemplates.keys():
self.numberProcessProf += self.dictTemplates[path]
return None
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 "name" in objHeadDir.params:
self.changeDirs[path] = pathDir
crDirs = self.createDir(prefix, path,
self._baseDir, pathDir)
if crDirs is False:
return False
self.createdDirs += crDirs
else:
if self.getError():
self.setError(_("Incorrect profile: " ) +\
dirInfoFile)
return False
# Добавление количества файлов в пропущенной директории
if path in self.dictTemplates.keys():
self.numberProcessProf += self.dictTemplates[path]
return None
return True
def __getGenHeadDir(self, newDir, profileDirFile, changeDirs):
"""Определяет название создаваемой директории"""
def function(text):
"""Функция обработки функций в заголовке"""
return self.applyFuncProfile(text, newDir, profileDirFile)
newDirMv = newDir
findChangeDir = False
#Меняем путь к директории
listD = list(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 "name" in objHead.params:
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(x.split("?")[0] for x in 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 "name" in objHeadDir.params:
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 = list(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(x.split("?")[0] for x in 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 = list(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 "name" in objHead.params:
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 "chmod" in objHead.params:
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 "chown" in objHead.params:
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 "name" in objHeadNew.params:
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 "force" in objHeadNew.params:
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 "mirror" in objHeadNew.params:
if "link" in objHeadNew.params:
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 "link" in objHeadNew.params and\
"symbolic" not in objHeadNew.params:
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 "symbolic" in objHeadNew.params:
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 "chmod" in objHeadNew.params:
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 "chown" in objHeadNew.params:
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\
"symbolic" not in objHeadNew.params and\
"link" in objHeadNew.params:
return (applyFiles, False)
return (applyFiles, objHeadNew)
def createNewClass(self, name, bases, attrs=None):
"""Создает объект нового класса
createNewClass(self, name, bases, attrs)
name - имя класса - str,
bases - cписок наследуемых классов - (tuple),
attrs - аттрибуты класса - {dict}
"""
if attrs is None:
attrs = {}
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):
try:
with open(fileName, encoding="utf-8", errors="strict") as FD:
newProfile = FD.read()
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 ("link" in objHeadNew.params and\
"symbolic" in objHeadNew.params):
# проверяем кодировку оригинального файла
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)
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:
objProfNew = eval("%s(self.newProfile)"%\
(objHeadNew.fileType))
except NameError:
#Создаем объект из self.newObjProt с помощью
# метаклассов
if objHeadNew.fileType in self.newObjProt:
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()
# Если не UTF-8 производим преобразование
if flagNotUtf8New:
self.newProfile = objTxtCoder.decode(self.newProfile)
# Титл для объединения
if ListOptTitle:
title = self.getTitle(objProfNew._comment,
ListOptTitle)
# Замена
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:
objProfNew = eval("%s(self.newProfile)"%\
(objHeadNew.fileType))
except NameError:
#Создаем объект из self.newObjProt с помощью
# метаклассов
if objHeadNew.fileType in self.newObjProt:
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)
# В случае пустого конфигурационного файла
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 objHeadNew.fileType in self.newObjProt:
objProfOldCl = self.createNewClass(\
objHeadNew.fileType,
self.newObjProt[objHeadNew.fileType])
objProfOld = objProfOldCl(self.oldProfile)
else:
objProfOld = eval("%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().split("\n")
data.insert(1,title)
self.oldProfile = "\n".join(data)
else:
if objHeadNew.execStr:
self.oldProfile = objHeadNew.execStr + title +\
objProfOld.getConfig()
elif objHeadOld.execStr:
self.oldProfile = objHeadOld.execStr + title +\
objProfOld.getConfig()
else:
self.oldProfile = title +\
objProfOld.getConfig()
# Декодируем если кодировка не 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"""
# удаляем пустые области
xmlAreas = xpath.Evaluate("child::area", self.docObj.body)
removeList = []
for xmlArea in xmlAreas:
xmlFields = xpath.Evaluate("child::field/name", xmlArea)
if not xmlFields:
removeList.append(xmlArea)
for xmlArea in removeList:
parentNode = xmlArea.getparent()
parentNode.remove(xmlArea)
# Для добавления перевода строки между областями если его нет
xmlAreas = xpath.Evaluate("child::area", self.docObj.body)
xmlArea = None
for xmlArea in xmlAreas:
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.getnext() is not None:
3 years ago
parentNode = xmlArea.getparent()
nextNode = xmlArea.getnext()
insertBefore(parentNode, self.docObj.createField(
"br", [], "", [], False, False), nextNode)
# Добавление переводов строк между полями
if xmlFields:
for node in xmlFields:
# Добавление перевода строк в если его нет между полями
if (self.docObj.getTypeField(node) == "var" and
node.getprevious() is not None and
not (self.docObj.getTypeField(
node.getprevious()) in ("br", "comment"))):
insertBefore(xmlArea, self.docObj.createField(
"br", [], "", [], False, False), node)
# Удаление лишних переводов строк
childNodes = self.docObj.getFieldsArea(self.docObj.body)
lenBr = 0
removeBrNodes = []
for node in childNodes:
if (node.tag == "field" and
self.docObj.getTypeField(node) == "br"):
lenBr += 1
if lenBr > 2:
removeBrNodes.append(node)
else:
lenBr = 0
# Удаление
for rmNode in removeBrNodes:
self.docObj.body.remove(rmNode)
# Если после есть BR а за ним ничего нет, удаляем BR
if xmlArea is not None:
if (xmlArea.getnext() is not None and
self.docObj.getTypeField(xmlArea.getnext()) == "br"):
if xmlArea.getnext().getnext() is None:
parentNode = xmlArea.getnext().getparent()
parentNode.remove(xmlArea.getnext())
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)
3 years ago
rootNode.append(area)
else:
fieldsNodes = docObj.tmpFields.getFields()
for fieldNode in fieldsNodes:
3 years ago
rootNode.append(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)
3 years ago
areaXML.append(areaXMLChild)
else:
self.createXML(f.fields, areaXML, docObj)
if "\n" in f.end:
fieldXMLBr = docObj.createField("br",[],
"",[],
False, False)
3 years ago
areaXML.append(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)
3 years ago
areaXML.append(fieldXML)
if field.br[-1] == "\n":
fieldXMLBr = docObj.createField("br",[],
"",[],
False, False)
3 years ago
areaXML.append(fieldXMLBr)
elif field.comment != False:
fieldXML = docObj.createField("comment",
[field.comment],
"", [],
False, False)
3 years ago
areaXML.append(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)
3 years ago
areaXML.append(fieldXML)
if i.header and i.start:
3 years ago
rootNode.append(areaXML)
if "\n" in i.end:
fieldXMLBr = docObj.createField("br",[],
"",[],
False, False)
3 years ago
rootNode.append(fieldXMLBr)
else:
fields = self.splitToFields(i)
for field in fields:
if field.name != False:
fieldXML = self.createFieldTerm(field.name,
field.value,
field.br, docObj)
3 years ago
rootNode.append(fieldXML)
if field.br[-1] == "\n":
fieldXMLBr = docObj.createField("br",[],"", [],
False, False)
3 years ago
rootNode.append(fieldXMLBr)
elif field.comment != False:
fieldXML = docObj.createField("comment",
[field.comment],
"", [],
False, False)
3 years ago
rootNode.append(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)
3 years ago
rootNode.append(fieldXML)
#rootNode.append(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.append(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"):
3 years ago
xmlArea.append(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.set("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)
3 years ago
rootNode.append(area)
else:
fieldsNodes = docObj.tmpFields.getFields()
for fieldNode in fieldsNodes:
3 years ago
rootNode.append(fieldNode)
docObj.clearTmpFields()
z += 1
#print docObj.doc.toprettyxml()
return docObj
def getConfig(self):
"""Выдает конфигурационный файл"""
listConfigTxt = []
childNodes = list(self.docObj.getNodeBody())
for node in childNodes:
if node.tag == "field":
listConfigTxt.append(self.docObj.getQuoteField(node))
elif node.tag == "area":
self.docObj.xmlToText([node], listConfigTxt)
tmp = "".join(listConfigTxt)
return "\n".join(x for x in tmp.split("\n") if x.strip())
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"):
3 years ago
xmlArea.append(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()
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 and \
( nameValue[0].startswith("!include") or
nameValue[0][1:].startswith("!include")):
field.name = textLine.replace(self.sepFields,"")
field.value = ""
field.br = textLine
fields.append(field)
field = fieldData()
elif len (nameValue) == 1:
field.name = ""
field.value = textLine.replace(self.sepFields,"")
field.br = textLine
fields.append(field)
field = fieldData()
elif 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 createFieldTerm(self, name, value, quote, docObj):
"""Создание поля переменная - значение
при создании поля проверяется первый символ названия переменной
и добавляется тег action
"!" - <action>drop</action> удаляет
"+" - <action>join</action> добавляет
"-" - <action>replace</action> заменяет
"""
fieldAction = False
if name:
if name.startswith("!include") or name[1:].startswith("!include"):
prefix = "!"
name = re.sub(r"(include)\s*(\S)",r"\1 \2", name[1:])
else:
prefix = ""
if name[0] == "!" or name[0] == "-" or name[0] == "+":
qnt = self.removeSymbolTerm(quote)
fieldXML = docObj.createField("var",[qnt],
prefix+name[1:], [value],
False, False)
if name[0] == "!":
fieldAction = "drop"
elif name[0] == "+":
fieldXML.set("type", "seplist")
fieldAction = "join"
else:
fieldXML = docObj.createField("var",
[quote.replace("\n","")],
prefix+name, [value],
False, False)
else:
fieldXML = docObj.createField("var",
[quote.replace("\n","")],
name, [value],
False, False)
if fieldAction:
docObj.setActionField(fieldXML, fieldAction)
return fieldXML
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 postXML(self):
"""Последующая постобработка XML"""
xmlFields = xpath.Evaluate("child::field", self.docObj.body)
# Добавление переводов строк между полями
for node in xmlFields:
# Добавление перевода строк в если его нет между полями
if (self.docObj.getTypeField(node) == "var" and
node.getprevious() is not None and
(self.docObj.getTypeField(node.getprevious()) not in
("br", "comment"))):
insertBefore(self.docObj.body, self.docObj.createField(
"br", [], "", [], False, False), node)
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)
3 years ago
nodeBody.append(fieldXML)
if field.br[-1] == "\n":
fieldXMLBr = docObj.createField("br",[],
"",[],
False, False)
3 years ago
nodeBody.append(fieldXMLBr)
elif field.comment != False:
fieldXML = docObj.createField("comment",
[field.comment],
"", [],
False, False)
3 years ago
nodeBody.append(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)
3 years ago
nodeBody.append(fieldXML)
return docObj
def join(self, procmailObj):
"""Объединяем конфигурации"""
if isinstance(procmailObj, procmail):
#print self.docObj.doc.toprettyxml()
self.docObj.joinDoc(procmailObj.doc)
self.postXML()
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)
3 years ago
rootNode.append(area)
else:
fieldsNodes = docObj.tmpFields.getFields()
for fieldNode in fieldsNodes:
3 years ago
rootNode.append(fieldNode)
docObj.clearTmpFields()
z += 1
#print docObj.doc.toprettyxml()
return docObj
def join(self, kdeObj):
"""Объединяем конфигурации"""
if isinstance(kdeObj, kde):
self.docObj.joinDoc(kdeObj.doc)
self.postXML()
class PlasmaArea():
def __init__(self):
self.header = False
self.start = False
self.fields = []
self.end = ""
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:
3 years ago
parentNode = rmNode.getparent()
parentNode.remove(rmNode)
captionAreasRemove = xpath.Evaluate(\
"descendant::area/child::caption[child::action='drop']",
xmlNewArea)
for rmNodeCapt in captionAreasRemove:
3 years ago
rmNode = rmNodeCapt.getparent()
parentNode = rmNode.getparent()
parentNode.remove(rmNode)
self.setActionArea(xmlNewArea, "append")
# Добавляем разделитель областей во вложенные области
areaNodes = xpath.Evaluate('descendant::area',xmlNewArea)
for areaNode in areaNodes:
self.setActionArea(areaNode,"append")
3 years ago
parentNode = areaNode.getparent()
insertBefore(parentNode, deepcopy(self.sepAreas),
areaNode)
3 years ago
baseNode.append(xmlNewArea)
# Добавляем разделитель областей
3 years ago
insertBefore(baseNode, deepcopy(self.sepAreas), 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 = ""
3 years ago
if firstChild(nodesNewArea[0]) is not None:
nameArea = firstChild(nodesNewArea[0]).text.strip()
flagFindArea = False
baseNodes = []
newAreaAction = None
for oName in nodesNames:
newAreaAction = self.getActionArea(xmlNewArea)
3 years ago
oArea = oName.getparent().getparent()
oNameTxt = ""
3 years ago
if firstChild(oName) is not None:
oNameTxt = firstChild(oName).text
if nameArea == oNameTxt:
flagFindArea = True
# При использовании удаления
if newAreaAction == "drop":
3 years ago
prevNode = oName.getparent().getparent().getprevious()
removePrevNodes = []
while prevNode is not None\
and self.getTypeField(prevNode) == "br":
removePrevNodes.append(prevNode)
3 years ago
prevNode = prevNode.getprevious()
for removeNode in removePrevNodes:
3 years ago
baseNode.remove(removeNode)
baseNode.remove(oName.getparent().getparent())
continue
elif newAreaAction == "replace":
3 years ago
oldAreaNode = oName.getparent().getparent()
newAreaCaption = xpath.Evaluate('child::caption',
xmlNewArea)[0]
oldAreaCaption = xpath.Evaluate('child::caption',
oldAreaNode)[0]
if newAreaCaption and oldAreaCaption:
3 years ago
xmlNewArea.replace(newAreaCaption, oldAreaCaption)
self.setActionArea(xmlNewArea,"replace")
3 years ago
baseNode.replace(oldAreaNode, xmlNewArea)
continue
3 years ago
baseNodes.append(oName.getparent().getparent())
# Заменяем QUOTE
3 years ago
oldAreaNode = oName.getparent().getparent()
oldAreaQuote = xpath.Evaluate('child::caption/quote',
oldAreaNode)[0]
if oldAreaQuote and\
3 years ago
firstChild(oldAreaQuote) is None:
newAreaQuote = xpath.Evaluate('child::caption/quote',
xmlNewArea)[0]
oldAreaCaption = xpath.Evaluate('child::caption',
oldAreaNode)[0]
if newAreaQuote and oldAreaCaption:
3 years ago
oldAreaCaption.replace(oldAreaQuote, newAreaQuote)
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)
"""
area = PlasmaArea
def findPathArea(listPath, areaF):
"""Ищет путь в области
areaF - объект area
listPath - cписок названий областей
"""
ret = False
if not listPath:
return ret
flagList = False
if isinstance(areaF, list):
fields = areaF
flagList = True
else:
fields = areaF.fields
if areaF.header == listPath[0]:
ret = areaF
else:
return ret
for i in fields:
if isinstance(i, PlasmaArea):
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 = [x for x in slpNamesBlock if x.strip()]
#namesBlock = map(lambda x: self.removeSymbolTerm(x), namesBlock)
findArea = findPathArea(copy.copy(namesBlock), areas)
namesBlockList.append(namesBlock)
if findArea:
if len(namesBlock) > 1:
namesBlockView = [self.removeSymbolTerm(x) for x in 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 = [self.removeSymbolTerm(x) for x in 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 and
isinstance(findAreaPrev, area)):
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 isinstance(findArea, area):
#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 isinstance(i, PlasmaArea):
if i.header:
areaXML = self.createCaptionTerm(i.header, i.start,
i.end.replace("\n",""),
docObj)
for f in i.fields:
if isinstance(f, PlasmaArea):
if f.header:
areaXMLChild = self.createCaptionTerm(f.header,
f.start,
f.end.replace("\n",""),
docObj)
self.createXML(f.fields, areaXMLChild, docObj)
3 years ago
areaXML.append(areaXMLChild)
else:
self.createXML(f.fields, areaXML, docObj)
if "\n" in f.end:
fieldXMLBr = docObj.createField("br",[],
"",[],
False, False)
3 years ago
areaXML.append(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)
3 years ago
areaXML.append(fieldXML)
if field.br[-1] == "\n":
fieldXMLBr = docObj.createField("br",[],
"",[],
False, False)
3 years ago
areaXML.append(fieldXMLBr)
elif field.comment != False:
fieldXML = docObj.createField("comment",
[field.comment],
"", [],
False, False)
3 years ago
areaXML.append(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:
3 years ago
areaXML.append(fieldXML)
if i.header:
3 years ago
rootNode.append(areaXML)
if "\n" in i.end:
fieldXMLBr = docObj.createField("br",[],
"",[],
False, False)
3 years ago
rootNode.append(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)
3 years ago
rootNode.append(fieldXML)
if field.br[-1] == "\n":
fieldXMLBr = docObj.createField("br",[],"", [],
False, False)
3 years ago
rootNode.append(fieldXMLBr)
elif field.comment != False:
fieldXML = docObj.createField("comment",
[field.comment],
"", [],
False, False)
3 years ago
rootNode.append(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)
3 years ago
rootNode.append(fieldXML)
#rootNode.append(areaXML)
def createTxtConfig(self, strHeader, dictVar):
"""Cоздает область с заголовком
создает текст конфигурационного файла в формате samba из
заголовка (строка) и словаря переменных
"""
if not strHeader:
return ""
if type(strHeader) in (tuple, list):
outTxt = "".join("["+x+"]" for x in strHeader)
if not outTxt:
return ""
outTxt += "\n"
else:
outTxt = "[" + strHeader + "]\n"
for key in dictVar.keys():
outTxt += "%s=%s\n" %(key,dictVar[key])
return outTxt
def _textToXML(self):
"""Преобразуем текст в XML"""
areas = []
if self.text.strip():
self.splitToAllArea(self.text, areas)
# docObj = xmlDoc()
# Создаем новый класс xmlDoc с измененным методом joinArea
# Создаем экземпляр нового класса
docObj = xmlDocPlasma()
# Создание объекта документ c пустым разделителем между полями
docObj.createDoc(self.configName, self.configVersion)
if not areas:
return docObj
self.createXML(areas, docObj.getNodeBody(), docObj)
return docObj
def postXML(self):
"""Последующая постобработка XML"""
# Для добавления перевода строки между областями если его нет
def getQuotesArea(xmlArea):
quotes = []
xmlQuotes = xpath.Evaluate('child::caption/quote', xmlArea)
for node in xmlQuotes:
if firstChild(node) is not None:
quotes.append(firstChild(node).text)
if len(quotes) == 0:
quotes.append("")
quotes.append("")
elif len(quotes) == 1:
quotes.append("")
return quotes
xmlAreas = xpath.Evaluate("descendant::area", self.docObj.body)
for xmlArea in xmlAreas:
# Перед пустой областью и после нее удаляем переводы строк
if getQuotesArea(xmlArea) == ["", ""]:
if (xmlArea.getprevious() is not None and
self.docObj.getTypeField(
xmlArea.getprevious()) == "br"):
3 years ago
parentNode = xmlArea.getprevious().getparent()
prev_prev_sbl = xmlArea.getprevious().getprevious()
if (prev_prev_sbl and
self.docObj.getTypeField(
prev_prev_sbl) == "br"):
parentNode.remove(
xmlArea.getprevious().getprevious())
3 years ago
parentNode.remove(xmlArea.getprevious())
if (xmlArea.getnext() is not None and
self.docObj.getTypeField(
xmlArea.getnext()) == "br"):
3 years ago
parentNode = xmlArea.getnext().getparent()
next_next_sbl = xmlArea.getnext().getnext()
if (next_next_sbl is not None and
self.docObj.getTypeField(
next_next_sbl) == "br"):
3 years ago
parentNode.remove(xmlArea.getnext().getnext())
parentNode.remove(xmlArea.getnext())
continue
# Собираем поля в кучку
xmlChildAreas = xpath.Evaluate("child::area", xmlArea)
if xmlChildAreas:
childNodes = self.docObj.getFieldsArea(xmlArea)
firstChildArea = xmlChildAreas[0]
if (firstChildArea.getprevious() and
self.docObj.getTypeField(
firstChildArea.getprevious()) == "br"):
prev_prev_sbl = (
firstChildArea.getprevious().getprevious())
if prev_prev_sbl:
if self.docObj.getTypeField(prev_prev_sbl) == "br":
3 years ago
firstChildArea = firstChildArea.getprevious()
flagFoundArea = False
it = 0
lenChild = len(childNodes)
for node in childNodes:
it += 1
if node.tag == "area":
flagFoundArea = True
continue
if flagFoundArea and node.tag == "field":
if self.docObj.getTypeField(node) == "var":
3 years ago
insertBefore(xmlArea, node, firstChildArea)
if it < lenChild:
node_type = self.docObj.getTypeField(
childNodes[it])
if node_type == "br":
3 years ago
insertBefore(xmlArea, childNodes[it],
firstChildArea)
# Добавление перевода строк в если его нет между полями
if (self.docObj.getTypeField(node) == "var" and
node.getprevious() and
not (self.docObj.getTypeField(
node.getprevious()) in ("br", "comment"))):
insertBefore(xmlArea, self.docObj.createField(
"br", [], "", [], False, False), node)
# Добавляем 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:
3 years ago
insertBefore(xmlArea, self.docObj.createField("br",
[], "", [],
False, False),
xmlFields[0])
# Добавление переводов строк между полями
if xmlFields:
for node in xmlFields:
# Добавление перевода строк в если его нет между полями
if (self.docObj.getTypeField(node) == "var" and
node.getprevious() is not None and
not (self.docObj.getTypeField(
node.getprevious()) in ("br", "comment"))):
insertBefore(xmlArea, self.docObj.createField("br",
[], "", [],
False,
False),
node)
# Если последним полем BR, удаляем его
if xmlFields and self.docObj.getTypeField(xmlFields[-1]) == "br":
if not xmlFields[-1].getnext():
xmlArea.remove(xmlFields[-1])
# Если предыдущим полем не (BR или комментарий) - добавляем BR
if (xmlArea.getprevious() is not None and
not (self.docObj.getTypeField(
xmlArea.getprevious()) == "br" or
self.docObj.getTypeField(
xmlArea.getprevious()) == "comment")):
3 years ago
parentNode = xmlArea.getparent()
insertBefore(parentNode, self.docObj.createField(
"br", [], "", [], False, False), xmlArea)
# Если есть предыдущее поле, и поле предыдущеее предыдущему
# не равно BR или комментарий то добавляем BR
if xmlArea.getprevious() is not None:
3 years ago
prPrSibling = xmlArea.getprevious().getprevious()
if (prPrSibling is not None and
not (self.docObj.getTypeField(
prPrSibling) == "br" or
self.docObj.getTypeField(
prPrSibling) == "comment")):
3 years ago
parentNode = xmlArea.getparent()
insertBefore(parentNode, self.docObj.createField(
"br", [], "", [], False, False), xmlArea)
# Если после есть BR а за ним ничего нет, удаляем BR
if (xmlArea.getnext() is not None and
self.docObj.getTypeField(xmlArea.getnext()) == "br"):
if xmlArea.getnext().getnext() is None:
parentNode = xmlArea.getnext().getparent()
parentNode.remove(xmlArea.getnext())
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.set("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 = str_to_xml_doc(self.text)
except Exception as e:
print(e)
self.setError(_("The template content is not XML"))
return False
self.rootNode = self.doc.getroottree().getroot()
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 у всех нод
"""
3 years ago
childNodes = list(xmlNode)
if "action" in xmlNode.keys():
nAction = xmlNode.get("action")
if nAction not in ("join", "replace", "drop"):
3 years ago
textError = _("In the text of the XML template, "
"reserved attribute 'action' comes with an "
"incorrect value.\n"
"Valid values of the 'action' attribute are: "
'(action="join", action="replace",'
'action="drop")')
self.setError(textError)
return False
xmlNode.removeAttribute("action")
if nAction == "drop":
parentNode = xmlNode.getparent()
if parentNode:
parentNode.remove(xmlNode)
if childNodes:
for node in childNodes:
if not self._removeDropNodesAndAttrAction(node):
return False
return True
def postXML(self):
"""Последующая постобработка XML"""
# Удаляем теги action и удаляемые ноды
self._removeDropNodesAndAttrAction(self.bodyNode)
def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True):
3 years ago
"""Объединение корневой ноды шаблона и корневой ноды файла"""
xmlNode = xmlNewNode
3 years ago
childNodes = list(xmlNode)
nextOldNode = xmlOldNode
3 years ago
# if xmlNode.nodeType == xmlNode.ELEMENT_NODE:
n = xmlNode
nType = ''
nValue = ''
nAction = ''
attrName = ''
attrType = ''
path = n.tag
if "name" in n.keys():
nName = n.get("name")
attrName = "attribute::name='%s'" % nName
if "type" in n.keys():
nType = n.get("type")
attrType = "attribute::type='%s'" % nType
if "value" in n.keys():
nValue = n.get("value")
if "action" in n.keys():
nAction = n.get("action")
if not nAction in ("join", "replace", "drop"):
textError = _(
"In the text of the XML template, "
"reserved attribute 'action' comes with an "
"incorrect value.\n"
"Valid values of the 'action' attribute are: "
'(action="join", action="replace", action="drop")')
self.setError(textError)
return False
if xmlNewNode.getparent() is not None:
strAttr = [attrName, attrType]
findAttr = [x for x in strAttr if x]
findAttrStr = ''
if findAttr:
strAttr = ' and '.join(findAttr)
findAttrStr = "[%s]" % strAttr
findPath = "child::%s%s" % (path, findAttrStr)
# Рабочая нода
if flagRootNode:
workNode = xmlOldNode.getparent()
else:
workNode = xmlOldNode
oldNodes = xpath.Evaluate(findPath, workNode)
# Новая нода список
flagArray = nType == "array"
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 '
'the root node')
self.setError(textError)
return False
3 years ago
if oldNodes:
if len(oldNodes) > 1:
textError = _("Ambiguity in this template: "
"the same nodes are on a same level")
self.setError(textError)
return False
nextOldNode = oldNodes[0]
# Замещаем ноду в случае массива
if flagArray and not flagDrop:
replaceXmlNode = deepcopy(xmlNode)
if nAction:
del replaceXmlNode.attrib["action"]
workNode.replace(nextOldNode, replaceXmlNode)
flagJoin = False
3 years ago
flagReplace = False
childNodes = False
# Объединение нод
if flagJoin:
if "value" in nextOldNode.keys():
oValue = nextOldNode.getAttribute("value")
3 years ago
if nValue != oValue:
nextOldNode.setAttribute("value", nValue)
# Замещение ноды
elif flagReplace:
replaceXmlNode = deepcopy(xmlNode)
if not self._removeDropNodesAndAttrAction(
replaceXmlNode):
return False
3 years ago
workNode.replace(nextOldNode, replaceXmlNode)
childNodes = False
3 years ago
# Удаление ноды
elif flagDrop:
workNode.remove(nextOldNode)
childNodes = False
else:
# Добавление ноды
childNodes = False
if not flagDrop:
appendXmlNode = deepcopy(xmlNode)
if not self._removeDropNodesAndAttrAction(
appendXmlNode):
return False
workNode.append(appendXmlNode)
if isinstance(childNodes, Iterable):
for node in childNodes:
if not self._join(node, nextOldNode, False):
return False
return True
def joinDoc(self, doc):
"""Объединение документа шаблона и документа файла"""
if self.doc is None:
self.setError(_("The text file is not XML"))
return False
if doc is None:
self.setError(_("The text file is not XML"))
return False
# Импортируем корневую ноду нового документа в текущий документ
# newImportBodyNode = self.doc.importNode(doc.documentElement, True)
# Объединение корневой ноды шаблона и корневой ноды файла
3 years ago
if not self._join(doc, self.bodyNode):
return False
return True
def getConfig(self):
"""Получение текстового файла из XML документа"""
3 years ago
data = xml_to_str(self.doc).split("\n")
data = [x for x in data if x.strip()]
3 years ago
data.insert(0, '<?xml version="1.0" encoding="UTF-8"?>\n')
return "\n".join(data).replace("\t", " ")
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:
3 years ago
self.doc = str_to_xml_doc(self.text)
except:
self.setError(_("Can not text profile is XML"))
return False
3 years ago
self.rootNode = self.doc.getroottree().getroot()
self.bodyNode = self.rootNode
return self.doc
3 years ago
def setNameBodyNode(self, name):
"""Пустой метод"""
return True
def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True, levelNumber=0):
"""Объединение корневой ноды шаблона и корневой ноды файла"""
xmlNode = xmlNewNode
3 years ago
childNodes = list(xmlNode)
nextOldNode = xmlOldNode
n = xmlNode
flagArray = False
nValue = ''
nAction = ''
attrName = ''
path = n.tag
if path == "items":
flagArray = True
if not flagArray:
if "name" in n.keys():
nName = n.get("name")
attrName = "attribute::name='%s'" % nName
if "value" in n.keys():
nValue = n.get("value")
if "action" in n.keys():
nAction = n.get("action")
if not nAction in ("join", "replace", "drop"):
textError = _("In the text of the XML template, "
"reserved attribute 'action' comes with an "
"incorrect value.\n"
"Valid values of the 'action' attribute are: "
'(action="join", action="replace", '
'action="drop")')
self.setError(textError)
return False
if xmlNewNode.getparent() is not None:
findAttrStr = ""
if attrName:
findAttrStr = "[%s]" % attrName
findPath = "child::%s%s" % (path, findAttrStr)
# Рабочая нода
if flagRootNode:
workNode = xmlOldNode.getparent()
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 the 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 = _("Ambiguity in this template: the "
"same nodes are on a same 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 = deepcopy(xmlNode)
if nAction:
del replaceXmlNode.attrib["action"]
workNode.replace(nextOldNode, replaceXmlNode)
flagJoin = False
flagReplace = False
childNodes = False
# Объединение нод
if flagJoin:
if "value" in nextOldNode.keys():
oValue = nextOldNode.get("value")
if nValue != oValue:
nextOldNode.set("value", nValue)
# Замещение ноды
elif flagReplace:
replaceXmlNode = deepcopy(xmlNode)
if not self._removeDropNodesAndAttrAction(
replaceXmlNode):
return False
workNode.replace(nextOldNode, replaceXmlNode)
childNodes = False
# Удаление ноды
elif flagDrop:
workNode.remove(nextOldNode)
childNodes = False
else:
flagAppend = True
flagDrop = False
if flagAppend and not flagDrop:
# Добавление ноды
childNodes = False
if not flagDrop:
appendXmlNode = deepcopy(xmlNode)
if not self._removeDropNodesAndAttrAction(
appendXmlNode):
return False
workNode.append(appendXmlNode)
if isinstance(childNodes, Iterable):
for node in childNodes:
levelNumber += 1
if not self._join(node, nextOldNode, False, levelNumber):
return False
levelNumber -= 1
return True
def join(self, xml_xfceObj):
"""Объединяем конфигурации"""
if isinstance(xml_xfceObj, xml_xfcepanel):
try:
self.joinDoc(xml_xfceObj.doc)
except Exception:
self.setError(_("Failed to join the template"))
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")
# регулярное выражения для поиска \t в начале строки (преобразование xml)
reStartTabs = re.compile("^(\t+)(.*)$")
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 = str_to_xml_doc(self.text)
except Exception:
self.setError(_("Can not text profile is XML"))
return False
self.rootNode = self.doc.getroottree().getroot()
self.bodyNode = self.rootNode #? a mistake, maybe?
return self.doc
def cmpListsNodesEntry(self, listXmlA, listXmlB):
"""Сравнение содержимого двух списков XML нод"""
def getTextsNodes(listXml):
for node in (deepcopy(x)
for x in listXml):# if x.nodeType == x.ELEMENT_NODE):
if "mtime" in node.keys():
# node.removeAttribute("mtime")
del node.attrib["mtime"]
text = node.toxml()
yield text.replace(" ", "").replace("\t", "").replace("\n", "")
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
3 years ago
childNodes = list(xmlNode)
nextOldNode = xmlOldNode
# if xmlNode.nodeType == xmlNode.ELEMENT_NODE:
n = xmlNode
tagName = n.tag
nAction = ''
nType = ''
nValue = ''
nSchema = ''
attrName = ''
if flagRootNode:
if not tagName == "gconf":
self.setError(_("The text is not a valid gconf-XML format \
(not found '<gconf>...</gconf>')"))
return False
flagType = False
flagValue = False
flagSchema = False
else:
if not tagName == "entry":
self.setError(_("The text is not a valid gconf-XML format \
(found '<gconf><%(tag)s>..</%(tag)s></gconf>')") % {'tag': tagName})
return False
if "name" not in n.keys():
self.setError(
_("Attribute \"name\" not found in the tag entry"))
return False
flagType = "type" in n.keys()
flagValue = False
flagSchema = "schema" in n.keys()
if flagSchema:
nSchema = n.get("schema")
if not flagType and not flagSchema:
self.setError(
_("Attribute \"type\" not found in the tag entry"))
return False
nName = n.get("name")
attrName = "attribute::name='%s'" % nName
if flagType:
flagValue = "value" in n.keys()
nType = n.get("type")
# Проверка правильности аттрибута type
if nType not in self.supportEntryTypes:
self.setError(_("Incorrect \"type\" attribute "
": <entry type=\"%s\"/>") % nType)
return False
if flagValue:
nValue = n.get("value")
if "action" in n.keys():
nAction = n.get("action")
if nAction not in ("join", "replace", "drop"):
textError = _("In the text of the XML template, "
"reserved attribute 'action' comes with an "
"incorrect value.\n"
"Valid values of the 'action' attribute are: "
'(action="join", action="replace",'
'action="drop")')
self.setError(textError)
return False
if xmlNewNode.getparent():
findAttrStr = ""
if attrName:
findAttrStr = "[%s]" % attrName
findPath = "child::%s%s" % (tagName, findAttrStr)
# Рабочая нода
if flagRootNode:
workNode = xmlOldNode.getparent()
else:
workNode = xmlOldNode
oldNodes = xpath.Evaluate(findPath, workNode)
# По умолчанию - объединение
flagJoin = True
flagReplace = False
flagDrop = False
# Замещаем ноду
if nType == "string" or nAction == "replace":
flagJoin = False
flagReplace = True
# Замещаем ноду в случае массива
elif nType == "list" or nType == "pair":
flagJoin = False
flagReplace = True
# Удаляем ноду
elif nAction == "drop":
flagJoin = False
flagDrop = True
if flagRootNode:
textError = _('Incorrect action="drop" in '
'the root node')
self.setError(textError)
return False
if oldNodes:
if len(oldNodes) > 1:
textError = _("Ambiguity in this template: the same "
"nodes are on a same level")
self.setError(textError)
return False
nextOldNode = oldNodes[0]
# Объединение нод
if flagJoin:
if flagType and flagValue:
flagChange = False
if "value" in nextOldNode.keys():
oValue = nextOldNode.get("value")
if nValue != oValue:
flagChange = True
else:
flagChange = True
if flagChange:
nextOldNode.set("mtime", self.currentTime)
nextOldNode.set("value", nValue)
elif flagSchema:
flagChange = False
if "schema" in nextOldNode.keys():
oSchema = nextOldNode.get("schema")
if nSchema != oSchema:
flagChange = True
else:
flagChange = True
if flagChange:
nextOldNode.set("mtime", self.currentTime)
nextOldNode.set("schema", nSchema)
# Замещение ноды
elif flagReplace:
replaceXmlNode = deepcopy(xmlNode)
# Сравнение содержимого нод
if not self.cmpListsNodesEntry([replaceXmlNode],
[nextOldNode]):
replaceXmlNode.set("mtime",
self.currentTime)
if not self._removeDropNodesAndAttrAction(
replaceXmlNode):
return False
workNode.replace(nextOldNode, replaceXmlNode)
childNodes = False
# Удаление ноды
elif flagDrop:
workNode.remove(nextOldNode)
childNodes = False
else:
# Добавление ноды
childNodes = False
if not flagDrop:
appendXmlNode = deepcopy(xmlNode)
appendXmlNode.set("mtime", self.currentTime)
if not self._removeDropNodesAndAttrAction(
appendXmlNode):
return False
workNode.append(appendXmlNode)
if isinstance(childNodes, Iterable):
for node in childNodes:
levelNumber += 1
if not self._join(node, nextOldNode, False, levelNumber):
return False
levelNumber -= 1
return True
def join(self, xml_gconfObj):
"""Объединяем конфигурации"""
# Получаем текущее время
self.currentTime = self.getCurrentTime()
if isinstance(xml_gconfObj, xml_gconf):
try:
self.joinDoc(xml_gconfObj.doc)
except Exception:
self.setError(_("Can not join profile"))
return False
return True
def getConfig(self):
"""Получение текстового файла из XML документа"""
def expandStartTabs(s):
if s.startswith("\t"):
res = self.reStartTabs.search(s)
if res:
return str(res.group(1)).replace("\t", " ") + res.group(2)
return s
else:
return s
data = xml_to_str(self.doc).split("\n")
data = [expandStartTabs(x) for x in data if x.strip()]
dataOut = []
z = 0
lenData = len(data)
lenM2 = lenData - 2
for i in range(lenData):
if z > 0:
z -= 1
continue
if i < lenM2 and data[i].endswith(">") and "<" not in data[i + 1]:
dataOut.append(
data[i] + data[i + 1].strip() + data[i + 2].strip())
z = 2
continue
dataOut.append(data[i])
dataOut.insert(0, '<?xml version="1.0" encoding="UTF-8"?>\n')
return "\n".join(dataOut)