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.2-lib/build/lib/calculate-lib/pym/cl_template.py

3775 lines
161 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#-*- coding: utf-8 -*-
# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
import os
import stat
import re
import xml.dom.minidom
from xml import xpath
import subprocess
import types
import random
import string
from cl_utils import _error, scan, _toUNICODE
from cl_overriding import exit
import cl_lang
tr = cl_lang.lang()
tr.setLocalDomain('cl_lib')
tr.setLanguage(sys.modules[__name__])
class _terms(_error):
"""Вычисление условий применяемых в шаблонах
"""
def _convertVers(self, verA, verB):
"""Конвертирование номеров версий для корректного сравнения
"""
elemA = verA.split(".")
elemB = verB.split(".")
if len(elemA) > len(elemB):
maxElemB = len(elemB)-1
for i in range(len(elemA)):
if i > maxElemB:
elemB.append("0")
else:
maxElemA = len(elemA)-1
for i in range(len(elemB)):
if i > maxElemA:
elemA.append("0")
for i in range(len(elemB)):
lenA = len(elemA[i])
lenB = len(elemB[i])
if lenA == lenB:
pass
elif lenA > lenB:
res = lenA - lenB
for z in range(res):
elemB[i] = "0" + elemB[i]
elif lenB > lenA:
res = lenB - lenA
for z in range(res):
elemA[i] = "0" + elemA[i]
return (".".join(elemA), ".".join(elemB))
def executeListEqual(self, listEqual):
"""Вычисляет список выражений
пример списка:
listEqual = [False, True, ' or ', True , True]
(если нет or между логическими выражениями то между ними and)
результат True
"""
lenOr = listEqual.count(" or ")
for i in xrange(lenOr):
ind = listEqual.index(' or ')
if False in listEqual[:ind]:
listEqual = listEqual[ind+1:]
continue
else:
return True
if False in listEqual:
return False
else:
return True
def _equalTerm(self, term, textError, function=False):
"""Вычисление логических выражений для условий
Для корректной работы в классе который наследует этот класс
должен быть объявлен аттрибут self.objVar
(объект для работы с переменными)
function - функция для для обработки функций в заголовке блока
"""
trm = {"&&":" and ","||":" or "}
rule = ["==", "!=", ">=", "<=", ">", "<"]
listEqual = []
for k in trm.keys():
if k in term:
term = term.replace(k,trm[k])
trs = term.split(" ")
for t in trs:
flagRule = False
for sepF in rule:
if sepF in t:
flagRule = True
vals = t.split(sepF)
break
if not flagRule:
flagLog = False
for k in trm.values():
if k.strip() == t:
flagLog = True
break
if not flagLog:
self.setError("'%s'"%term + " " + _("incorrect"))
self.setError (textError)
return False
elif k == " or ":
listEqual.append(k)
else:
#проверка на допустимость названия переменной
reDenyName = re.compile("[^a-zA-Z0-9\_\-]")
flagFunction = False
if reDenyName.search(vals[0]):
#проверка на допустимость функции
flagError = True
if function:
reFunction = re.compile(\
"([a-zA-Z0-9\_\-]+)\([a-zA-Z0-9_\-\+\,\*\/\.]+\)")
searchFunct = reFunction.search(vals[0])
if searchFunct:
flagError = False
flagFunction = True
if flagError:
self.setError("'%s'"%term + " " + _("incorrect"))
self.setError(textError)
return False
#проверка на допустимость значения
reDenyValue = re.compile("[^0-9a-zA-Z_\.-]")
if reDenyValue.search(vals[1]):
self.setError("'%s'"%term + " " + _("incorrect"))
self.setError(textError)
return False
flagIntTypeVar = None
if flagFunction:
valVars = function("#-%s-#"%vals[0])
if valVars == "":
flagFunction = False
if valVars == False:
self.setError("'%s'"%term + " " + _("incorrect"))
self.setError(textError)
return False
if "load" == searchFunct.group(1):
if re.search("\(\s*num\s*,",vals[0]):
if valVars:
try:
valVars = int(valVars)
except:
self.setError("'%s'"%term + " " + \
_("incorrect"))
self.setError (textError)
return False
flagIntTypeVar = True
else:
flagIntTypeVar = False
else:
try:
valVars = self.objVar.Get(vals[0])
except self.objVar.DataVarsError, e:
print textError
print e
exit(1)
# Cравниваем номера версий
if "_ver" in vals[0] or \
(flagFunction and "pkg" == searchFunct.group(1)) or\
(flagFunction and "load" == searchFunct.group(1) and\
re.search("\(\s*ver\s*,",vals[0])):
verFile, verVar = self._convertVers(vals[1],valVars)
exec("res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")")
if res:
listEqual.append(True)
else:
listEqual.append(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
exec("res=(%d%s%d)"%(valVar,sepF,valFile))
if res:
listEqual.append(True)
else:
listEqual.append(False)
else:
if sepF == "!=" or sepF == "==":
if not vals[1].strip():
vals[1] = ""
valFile = vals[1]
valVar = valVars
exec("res=("+'"""'+valVar+'"""'+sepF+"'"+valFile+\
"'"+")")
if res:
listEqual.append(True)
else:
listEqual.append(False)
else:
if valVars == "":
listEqual.append(False)
else:
self.setError("'%s'"%term + " "\
+ _("incorrect"))
self.setError (textError)
return False
#exec("res=(%s)"%("".join(listEqual)))
res = self.executeListEqual(listEqual)
return res
class shareHeader:
"""Общие методы для обработки заголовков"""
reSplParHeader = re.compile("\s+",re.I)
reHeader=re.compile(r"\A\s*#\s*calculate(\s+)?\\?([^\\\n]*\\\n)+[^\\\n]*\n?\
|\s*#\s*calculate\s+([^\\\n]*\n?)",re.I|re.M)
def getHeader(self, text):
"""Получаем результат поиска и заголовок файла"""
sHeader = self.reHeader.search(text)
if sHeader:
return (sHeader, sHeader.group())
else:
return (False, "")
def getParamsHeader(self, textHeader):
"""Получаем параметры заголовка в виде списка"""
listParams = self.reSplParHeader.split(textHeader.replace("\\"," "))
if listParams[0] == "#":
return filter(lambda x: x, listParams[2:])
else:
return filter(lambda x: x, listParams[1:])
class fileHeader(shareHeader, _terms):
"""Обработка заголовков шаблонов и конфигурационных файлов
"""
# Допустимые параметры заголовка
allowParam = ("format", "comment", "append", "force", "link", "mirror",
"symbolic", "chmod", "chown", "path", "name")
# параметры без значения
listParNotVal = ("symbolic", "force", "mirror")
# Возможные типы вставки шаблонов
_fileAppend = ("join", "before", "after", "replace", "remove", "skip")
# условные операторы
terms = ('>', '<', '==', '!=', '>=', '<=')
# параметры без значения
#listParNotVal = ("symbolic", "force", "mirror")
# Форматы файлов для которых метод объединения replace если он не задан
#replaceFormats = ("raw","bin")
def delHeaderConfFile(self, text, comment):
"""Удаляет заголовок в тексте конфигурационного файла"""
if comment and text:
# Удаление Заголовка Calculate в конфигурационном файле
# В случае текста XML
if type(comment) == types.TupleType and len(comment) == 2:
_titleList = (_("Modified"), _("File of a template"))
reCalcHeader =\
re.compile(u"\s*%s\s+%s.+Calculate.+\s+%s.+\s+%s\s?"%(\
comment[0],
_titleList[0].decode("UTF-8"),
_titleList[1].decode("UTF-8"),
comment[1],
),
re.M|re.I|re.U)
textUnicode = text.decode("UTF-8")
reS = reCalcHeader.search(textUnicode)
if reS:
textBody = textUnicode[:reS.start()]+textUnicode[reS.end():]
if textBody:
return textBody.encode("UTF-8")
else:
# В остальных случаях
reCalcHeader =\
re.compile("\s*%s\-+\s+%s.+Calculate.+\s+%s.+\s+%s\-+\s?"%(\
comment,
comment,
comment,
comment,
),
re.M|re.I)
reS = reCalcHeader.search(text)
if reS:
return text[reS.end():]
return text
def getPropertyTemplate(self, textHeader, foundHeader, fileType, objVar,
function, fileName):
"""Получаем свойства шаблона из текста заголовка шаблона"""
# Объект с переменными
self.objVar=objVar
# Параметры файла шаблона
params = {}
# Будет ли шаблон применен
headerTerm = True
# Бинарный шаблон
if fileType=="bin":
params["format"] = fileType
params["_position"] = 0
params["append"] = "replace"
params["_apply"] = headerTerm
# текстовый шаблон с заголовком
elif foundHeader:
# некорректные параметры
incorrectParams = set([])
# Получаем список параметров шаблона
paramList = self.getParamsHeader(textHeader)
if paramList:
errTerm = _("header template '%s' not valid")%fileName
for i in paramList:
foundTerm = False
for term in self.terms:
if term in i:
foundTerm = True
rezTerm = self._equalTerm(i, "%s: %s"%(errTerm,i),
function)
if not rezTerm:
headerTerm = False
break
if not foundTerm:
par = i.split("=")
if len(par) == 1:
ret = self.checkParams(i, None, params)
if not ret:
incorrectParams = set([i])
break
elif len(par) == 2:
ret = self.checkParams(par[0], par[1], params)
if not ret:
incorrectParams = set([i])
break
if not "format" in params:
# format - raw
params["format"] = "raw"
if not "append" in params:
params["append"] = "replace"
else:
if not "append" in params:
# в зависимости от формата - join или replace
formatTemplate = params["format"]
if formatTemplate in ("raw", "bin", ""):
params["append"] = "replace"
else:
params["append"] = "join"
if incorrectParams:
headerTerm = False
self.setError(_("incorrect header parameters - '%s'")\
%" ".join(list(incorrectParams)))
params["_position"] = foundHeader.end()
params["_apply"] = headerTerm
# текстовый шаблон без заголовка
else:
params["format"] = "raw"
params["_position"] = 0
params["append"] = "replace"
params["_apply"] = headerTerm
return params
def checkParams(self, name, value, dictPar):
"""Проверка параметра заголовка, при успехе запись в словарь dictPar"""
# Проверка на допустимые параметры заголовка
if not name in self.allowParam:
return False
if name in self.listParNotVal and not value is None:
return False
if name == "append":
if not value in self._fileAppend:
return False
dictPar[name] = value
return True
class dirHeader(shareHeader, _terms):
"""Обработка заголовков шаблонов директорий
"""
# Допустимые параметры заголовка
allowParam = ("append", "chmod", "chown", "path", "name")
# Возможные типы вставки шаблонов
_fileAppend = ("join", "remove", "skip")
# условные операторы
terms = ('>', '<', '==', '!=', '>=', '<=')
def getPropertyTemplate(self, text, objVar, function, fileName):
"""Получаем свойства шаблона из текста шаблона"""
# Объект с переменными
self.objVar=objVar
# Параметры описанные в заголовке файла шаблона
params = {}
# Некорректные параметры
incorrectParams = set([])
# Будет ли шаблон применен
headerTerm = True
foundHeader, textHeader = self.getHeader(text)
if foundHeader:
paramList = self.getParamsHeader(textHeader)
if paramList:
errTerm = _("header template '%s' not valid")%fileName
for i in paramList:
foundTerm = False
for term in self.terms:
if term in i:
foundTerm = True
rezTerm = self._equalTerm(i, "%s: %s"%(errTerm,i),
function)
if not rezTerm:
headerTerm = False
break
if not foundTerm:
par = i.split("=")
if len(par) == 1:
ret = self.checkParams(i, None, params)
if not ret:
incorrectParams = set([i])
break
elif len(par) == 2:
ret = self.checkParams(par[0], par[1], params)
if not ret:
incorrectParams = set([i])
break
if not "append" in params:
# По умолчанию join
params["append"] = "join"
if incorrectParams:
headerTerm = False
self.setError(_("incorrect header parameters - '%s'")\
%" ".join(list(incorrectParams)))
params["_apply"] = headerTerm
# текстовый шаблон без заголовка
else:
headerTerm = False
self.setError(_("Can not found header in template"))
params["_apply"] = headerTerm
return params
def checkParams(self, name, value, dictPar):
"""Проверка параметра заголовка, при успехе запись в словарь dictPar"""
# Проверка на допустимые параметры заголовка
if not name in self.allowParam:
return False
if name == "append":
if not value in self._fileAppend:
return False
if value is None:
return False
dictPar[name] = value
return True
class objShare:
"""Общий клас для объектов, наследуем
"""
def createFieldTerm(self, name, value, quote, docObj):
"""Создание поля переменная - значение
при создании поля проверяется первый символ названия переменной
и добавляется тег action
"!" - <action>drop</action> удаляет
"+" - <action>join</action> добавляет
"-" - <action>replace</action> заменяет
"""
fieldAction = False
if name:
if name[0] == "!" or name[0] == "-" or name[0] == "+":
qnt = self.removeSymbolTerm(quote)
fieldXML = docObj.createField("var",[qnt],
name[1:], [value],
False, False)
if name[0] == "!":
fieldAction = "drop"
elif name[0] == "+":
fieldXML.setAttribute("type", "seplist")
fieldAction = "join"
else:
fieldXML = docObj.createField("var",
[quote.replace("\n","")],
name, [value],
False, False)
else:
fieldXML = docObj.createField("var",
[quote.replace("\n","")],
name, [value],
False, False)
if fieldAction:
docObj.setActionField(fieldXML, fieldAction)
return fieldXML
def removeSymbolTerm(self, text):
"""Удаляет первый символ названия переменной в строке
Если первый встречающийся символ с начала строки
'+', '-', '!' то он из этой строки будет удален,
если перед этим символом были пробельные символы,
то они будут сохранены, так-же если в строке есть символ
перевода строки он будет удален.
"""
reTerm = re.compile("^[ \t]*(\!|\+|\-)")
textNS = text.replace("\n","")
res = reTerm.search(textNS)
if res:
textNS = textNS[res.start():res.end()-1] + textNS[res.end():]
return textNS
def getConfig(self):
"""Выдает конфигурационный файл"""
listConfigTxt = []
childNodes = self.docObj.getNodeBody().childNodes
for node in childNodes:
if node.nodeType == node.ELEMENT_NODE:
if node.tagName == "field":
listConfigTxt.append(self.docObj.getQuoteField(node))
elif node.tagName == "area":
self.docObj.xmlToText([node], listConfigTxt)
return "".join(listConfigTxt)
def splitToFields(self, txtBloc):
"""Разбиваем текст на поля (объекты) которые имеют следующие аттрибуты
self.name - если переменная то имя переменной
self.value - если у переменной есть значение то значение переменной
self.comment - если комментарий то текст комментария
self.br - если перевод строки то текст перед переводом из пробелов
Результат список объектов полей
"""
finBloc = "\n"
if txtBloc[-1] != "\n":
finBloc = ""
linesBlocTmp = txtBloc.splitlines()
linesBloc = []
brBloc = []
z = 0
lenLines = len(linesBlocTmp)
for i in linesBlocTmp:
if self.reComment.split(i)[0]:
findCooment = self.reComment.search(i)
comment = False
par = i
if findCooment:
par = i[:findCooment.start()]
comment = i[findCooment.start():]
fields = self.reSepFields.split(par)
lenFields = len(fields)
if lenFields>1:
for fi in range(lenFields-1):
linesBloc.append(fields[fi]+ self.sepFields)
if fi == lenFields-2:
if comment:
brBloc.append("")
else:
if (lenLines-1)== z:
brBloc.append(finBloc)
else:
brBloc.append("\n")
else:
brBloc.append("")
if comment:
linesBloc.append(comment)
if (lenLines-1)== z:
brBloc.append(finBloc)
else:
brBloc.append("\n")
else:
linesBloc.append(i)
if (lenLines-1)== z:
brBloc.append(finBloc)
else:
brBloc.append("\n")
else:
linesBloc.append(i)
if (lenLines-1)== z:
brBloc.append(finBloc)
else:
brBloc.append("\n")
z +=1
fields = self.setDataField(linesBloc, brBloc)
return fields
class xmlShare:
"""Общий класс для объектов XML, наследуем
"""
def _createElement(self, doc, tagName, text="", attributes={}):
"""Создание нового XML элемента"""
element = doc.createElement(tagName)
if text:
txtNode = doc.createTextNode(_toUNICODE(text))
element.appendChild(txtNode)
for attr in attributes.keys():
attribute = doc.createAttribute(attr)
attribute.nodeValue = attributes[attr]
element.setAttributeNode(attribute)
return element
class xmlNode(xmlShare):
"""Класс для создания нод без аттрибутов
"""
def __init__(self):
self.node = False
def createNode(self, doc, tagName, text=""):
"""Создает XML элемент без аттрибутов"""
self.node=self._createElement(doc, tagName, text)
return self.node
def getNode(self):
return self.node
class xmlCaption:
"""Класс XML заголовок
"""
def __init__(self):
#Заголовок области XML нода
self.caption = False
def createCaption(self, doc, name, quotes, action=False):
"""Создание заголовка области"""
tmpNode = xmlNode()
self.caption = tmpNode.createNode(doc, "caption")
nameNode = tmpNode.createNode(doc, "name",name)
self.caption.appendChild(nameNode)
if action:
actNode = tmpNode.createNode(doc, "action", action)
self.caption.appendChild(actNode)
for q in quotes:
quoteNode = tmpNode.createNode(doc, "quote", q)
self.caption.appendChild(quoteNode)
return self.caption
def getCaption(self):
"""Выдает XML ноду заголовка области"""
return self.caption
class xmlField(xmlShare):
"""Класс для работы с XML полем
"""
def __init__(self):
# XML нода поле
self.field = False
def createField(self, doc, typeField, quotes, name="",
values=[],action=False):
"""Cоздание XML ноды поле"""
self.field = self._createElement(doc, "field", "", {"type":typeField})
if name:
nameNode = self._createElement(doc, "name", name)
self.field.appendChild(nameNode)
for v in values:
valueNode = self._createElement(doc, "value", v)
self.field.appendChild(valueNode)
if action:
actNode = self._createElement(doc, "action", action)
self.field.appendChild(actNode)
for q in quotes:
quoteNode = self._createElement(doc, "quote", q)
self.field.appendChild(quoteNode)
return self.field
class xmlFields:
"""Класс, в котором находится список ХМL нод field
"""
def __init__(self):
self.fields = []
def appendField(self, field):
"""Добавить XML ноду field"""
self.fields.append(field)
return self.fields
def getFields(self):
"""Выдать список XML нод"""
return self.fields
class xmlArea:
"""Класс для работы с XML областью
"""
def __init__(self):
# Область
self.area = False
def createArea(self, doc, xmlCaption, xmlFields):
"""Создание XML области"""
tmpNode = xmlNode()
self.area = tmpNode.createNode(doc, "area")
if xmlCaption and xmlCaption.getCaption():
self.area.appendChild(xmlCaption.getCaption())
if xmlFields:
fields = xmlFields.getFields()
for field in fields:
self.area.appendChild(field)
return self.area
class xmlDoc:
"""Класс для работы с XML документом
"""
def __init__(self):
# документ
self.doc = False
# главная нода
self.root = False
# тело документа
self.body = False
# Заголовок области - временный (в реальности один объект заголовок)
self.tmpCaption = False
# Поля - временные (в реальности один объект поля)
self.tmpFields = False
# Разделитель областей - по умолчанию перевод строки "\n"
self.sepAreas = False
# Разделитель разделенных списков - по умолчанию перевод строки "\n"
#self.sepSplitFields = False
def createDoc(self, typeDoc, version):
"""Создание нового документа новый документ"""
docTxt = '<?xml version="1.0" encoding="UTF-8"?><cxmlconf><head>'
docTxt += '<ver>%s</ver>'% version
docTxt += '<format>%s</format>' % typeDoc
docTxt += '</head><body></body></cxmlconf>'
self.doc = xml.dom.minidom.parseString(docTxt)
self.root = self.doc.documentElement
self.body = xpath.Evaluate('child::body',self.root)[0]
# установка разделителя областей
self.sepAreas = self.createField("br",[],"",[],False,False)
# установка разделителя областей разделенных списков
#self.sepSplitFields = self.createField("br",[],"",[],False,False)
return self.doc
def addField(self, field):
"""Добавляет поле во временный список
Из этого списка в дальнейшем формируется XML область
"""
if not self.tmpFields:
self.tmpFields = xmlFields()
self.tmpFields.appendField(field)
def createCaption(self, name, quotes, action=False):
"""Cоздает заголовок области
Помещает заголовок в временный артибут
Используется при создании области
"""
self.tmpCaption = xmlCaption()
return self.tmpCaption.createCaption(self.doc, name, quotes, action)
def createField(self, typeField, quotes=[], name="",
values=[] ,action=False,addTmpField=True):
"""Cоздает поле
Если установлена переменнная addTmpField
добавляет поле во временный список
"""
fieldObj = xmlField()
field = fieldObj.createField(self.doc, typeField, quotes, name,
values, action)
if addTmpField:
self.addField(field)
return field
def clearTmpFields(self):
"""Очищает временный список"""
self.tmpFields = False
def createArea(self):
"""Cоздает область
Область создается на основании временного атрибута и временного списка
"""
areaObj = xmlArea()
area = areaObj.createArea(self.doc, self.tmpCaption, self.tmpFields)
self.clearTmpCaptionAndFields()
return area
def clearTmpCaptionAndFields(self):
"""Очищает временный аттрибут и временный список"""
self.tmpCaption = False
self.tmpFields = False
def getNodeRoot(self):
"""Выдает корневую ноду"""
return self.root
def getNodeBody(self):
"""Выдает ноду body"""
return self.body
def setActionField(self, xmlField, actionTxt):
"""Устанавливает свойство action для XML поля"""
xmlActions = xpath.Evaluate('child::action',xmlField)
if xmlActions and xmlActions[0].firstChild:
xmlActions[0].firstChild.nodeValue = actionTxt
else:
nodeObj = xmlNode()
newNode = nodeObj.createNode(self.doc, "action", actionTxt)
xmlField.appendChild(newNode)
def setActionArea(self, xmlArea, actionTxt):
"""Устанавливает свойство action для XML области"""
xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
xmlCaptions = xpath.Evaluate('child::caption',xmlArea)
if xmlActions and xmlActions[0].firstChild:
xmlActions[0].firstChild.nodeValue = actionTxt
else:
if xmlCaptions:
nodeObj = xmlNode()
newNode = nodeObj.createNode(self.doc, "action", actionTxt)
xmlCaptions[0].appendChild(newNode)
def joinField(self, xmlArea, xmlNewField):
"""Объединяет XML ноду область и XML ноду поле"""
newNameField = self.getNameField(xmlNewField)
if not newNameField or not newNameField.strip():
return False
fieldsOldComp = xpath.Evaluate("child::field[child::name='%s']"\
%(newNameField), xmlArea)
# Если поле не найдено добавляем его
typeNewField = self.getTypeField(xmlNewField)
if not fieldsOldComp and typeNewField != "seplist":
if self.getActionField(xmlNewField) != "drop":
self.setActionField(xmlNewField, "append")
xmlArea.appendChild(xmlNewField)
return True
newFieldsAction = self.getActionField(xmlNewField)
newValues = self.getFieldValues(xmlNewField)
flagCompare = True
for nodeFieldOld in fieldsOldComp:
if newFieldsAction == "drop":
if nodeFieldOld.nextSibling and\
self.getTypeField(nodeFieldOld.nextSibling) == "br":
xmlArea.removeChild(nodeFieldOld.nextSibling)
elif nodeFieldOld.previousSibling and\
self.getTypeField(nodeFieldOld.previousSibling) == "br":
xmlArea.removeChild(nodeFieldOld.previousSibling)
xmlArea.removeChild(nodeFieldOld)
continue
oldValues = self.getFieldValues(nodeFieldOld)
# Сравнение значений переменной шаблона и файла
if set(newValues) != set(oldValues):
flagCompare = False
if self.getActionField(xmlNewField) == "drop":
return True
appSplLst = []
insSplLst = []
if typeNewField == "seplist":
if fieldsOldComp:
xmlOldField = fieldsOldComp[-1]
else:
xmlOldField = False
seplistNewXML = self.getSepListToField(xmlNewField)
if seplistNewXML:
for nodeSeplist in seplistNewXML:
if self.getActionField(nodeSeplist) != "drop":
if newFieldsAction == "join":
flagCompareSeplist = False
newValues = self.getFieldValues(nodeSeplist)
for nodeFieldOld in fieldsOldComp:
oldValues = self.getFieldValues(nodeFieldOld)
for newValue in newValues:
if newValue in oldValues:
flagCompareSeplist = True
break
if not flagCompareSeplist:
nextNode = xmlOldField.nextSibling
newInsNode = nodeSeplist.cloneNode(True)
self.setActionField(newInsNode,"append")
if nextNode:
appSplLst.append((newInsNode,
nextNode,
"insert"))
else:
appSplLst.append((newInsNode,
False,
"append"))
else:
newInsNode = nodeSeplist.cloneNode(True)
if self.getActionField(newInsNode) == "join":
self.setActionField(newInsNode,"append")
if xmlOldField:
insSplLst.append((newInsNode,
xmlOldField,
"insert"))
else:
insSplLst.append((newInsNode,
False,
"append"))
#xmlArea.insertBefore(\
#nodeSeplist.cloneNode(True),
#xmlOldField)
parentNode = nodeSeplist.parentNode
parentNode.removeChild(nodeSeplist)
insNodesRepl = []
for newNode, nxtNode, app in insSplLst:
flagCompareSeplist = False
newValues = self.getFieldValues(newNode)
for nodeRepl, nxtNode, app in insNodesRepl:
oldValues = self.getFieldValues(nodeRepl)
for newValue in newValues:
if newValue in oldValues:
flagCompareSeplist = True
break
if not flagCompareSeplist:
if xmlOldField:
insNodesRepl.append((newNode, nxtNode, app))
for newNode, nxtNode, app in insNodesRepl:
if app == "insert":
xmlArea.insertBefore(newNode,nxtNode)
elif app == "append":
xmlArea.appendChild(newNode)
if xmlOldField:
parentNode = xmlOldField.parentNode
if parentNode and newFieldsAction != "join":
parentNode.removeChild(xmlOldField)
for newNode, nxtNode, app in appSplLst:
if app == "insert":
xmlArea.insertBefore(newNode,nxtNode)
elif app == "append":
xmlArea.appendChild(newNode)
if not flagCompare and typeNewField != "seplist":
# Устанавливаем action=replace
self.setActionField(xmlNewField, "replace")
# Если параметры поля не сходятся заменяем поле
xmlArea.replaceChild(xmlNewField.cloneNode(True),
fieldsOldComp[-1])
if newFieldsAction == "join":
fieldsOldRemove = []
else:
fieldsOldRemove = fieldsOldComp[:-1]
for nodeFieldOld in fieldsOldRemove:
actionOldNode = self.getActionField(nodeFieldOld)
if actionOldNode == "insert" or actionOldNode == "append":
pass
else:
if nodeFieldOld.nextSibling and\
self.getTypeField(nodeFieldOld.nextSibling) == "br":
xmlArea.removeChild(nodeFieldOld.nextSibling)
xmlArea.removeChild(nodeFieldOld)
return True
def getSepListToField(self, xmlField):
"""Выдает элементы распределенного массива
Область предок поля, в этой области ищутся
элементы распределенного массива
"""
nameField = self.getNameField(xmlField)
if not nameField:
return []
parentNode = xmlField.parentNode
#print parentNode.toprettyxml()
if parentNode:
fieldsVal = xpath.Evaluate(\
"child::field[attribute::type='seplist'][child::name='%s'] "\
%(nameField), parentNode)
#print nameField
return fieldsVal
else:
return []
def removeComment(self, xmlArea):
"""Удаляет комментарии в XML области"""
fieldNodes = xpath.Evaluate('descendant::field',xmlArea)
for fieldNode in fieldNodes:
if fieldNode.hasAttribute("type"):
if fieldNode.getAttribute("type") == "comment" or\
fieldNode.getAttribute("type") == "br":
parentNode = fieldNode.parentNode
parentNode.removeChild(fieldNode)
else:
if self.getActionField(fieldNode) == "drop":
pass
elif self.getActionField(fieldNode) == "join":
pass
else:
self.setActionField(fieldNode,"append")
def joinBody(self, baseBody, newBody):
"""Объединяет две области Body"""
newFields = xpath.Evaluate('child::field',newBody)
xmlNewAreas = xpath.Evaluate('child::area',newBody)
for xmlNewArea in xmlNewAreas:
self.joinArea(baseBody,xmlNewArea)
joinNewFields = xpath.Evaluate("child::field[child::action='join']"
,newBody)
self.addNewFielsOldArea(newFields, joinNewFields, baseBody)
def getRemoveNodeSepList(self, removeNodesDict, baseNode, xmNewlField):
"""Находит элементы разделенного списка
Параметры:
removeNodesDict - Cловарь удаляемых полей разделенного списка
формируется программой
baseNode - Нода в которой идет поиск
xmNewlField - Нода field которая проверяется на принадлежность
к разделенному списку
"""
flagNewNodeSeplist = False
if self.getTypeField(xmNewlField) == "seplist":
flagNewNodeSeplist = True
nameNewField = self.getNameField(xmNewlField)
if nameNewField:
if removeNodesDict.has_key(nameNewField):
return removeNodesDict[nameNewField]
else:
oldFields = xpath.Evaluate('child::field', baseNode)
removeNodes = []
lenOldFields = len(oldFields)
for i in range(lenOldFields):
oldNode = oldFields[i]
flagSep = self.getTypeField(oldNode) == "seplist"
if flagNewNodeSeplist:
flagSep = True
if flagSep and\
nameNewField == self.getNameField(oldNode):
removeNodes.append(oldNode)
if i+1<lenOldFields:
nextNode = oldFields[i+1]
if self.getTypeField(nextNode) == "br":
removeNodes.append(nextNode)
removeNodesDict[nameNewField] = removeNodes
return removeNodes
def addNewFielsOldArea(self, newFields, joinNewFields, xmlOldArea):
"""Добавляет новые XML поля в область шаблона"""
removeNodesDict = {}
notRemoveNodesDict = {}
for notRemNode in joinNewFields:
nameField = self.getNameField(notRemNode)
if not notRemoveNodesDict.has_key(nameField):
notRemoveNodesDict[nameField] = []
notRemoveNodesDict[nameField].append(notRemNode)
else:
notRemoveNodesDict[nameField].append(notRemNode)
notSepListField = []
sepListField = []
for nField in newFields:
if self.getRemoveNodeSepList(removeNodesDict, xmlOldArea,
nField):
sepListField.append(nField)
else:
if self.getNameField(nField):
notSepListField.append(nField)
for name in notRemoveNodesDict.keys():
if removeNodesDict.has_key(name):
removeNodesDict[name] = []
for removeNodes in removeNodesDict.values():
if removeNodes:
if self.getTypeField(removeNodes[-1]) == "seplist":
removeNodes = removeNodes[:-1]
else:
removeNodes = removeNodes[:-2]
for removeNode in removeNodes:
xmlOldArea.removeChild(removeNode)
for node in sepListField:
node.setAttribute("type", "seplist")
if not (self.getActionField(node) == "join" or\
self.getActionField(node) == "drop"):
self.setActionField(node,"insert")
self.joinField(xmlOldArea, node)
#else:
#self.setActionField(node, "append")
#baseBody.appendChild(node)
for node in notSepListField:
if self.getTypeField(node) == "seplist":
#if removeNodesDict.has_key(self.getNameField(node)):
#print removeNodesDict[self.getNameField(node)]
self.setActionField(node, "append")
xmlOldArea.appendChild(node)
else:
self.joinField(xmlOldArea, node)
def insertBeforeSepAreas(self, xmlArea):
"""Добавляет разделитель областей перед каждой областью"""
if not self.sepAreas:
return False
areaNodes = xpath.Evaluate('descendant::area',xmlArea)
for areaNode in areaNodes:
prevNode = areaNode.previousSibling
if prevNode:
parentNode = areaNode.parentNode
parentNode.insertBefore(self.sepAreas.cloneNode(True),
areaNode)
return True
def getAreaFields(self, nameArea, xmlArea):
"""По имени области выводит названия и значения всех переменных
поиск ведется только в 1-х потомках области xmlArea
на выход словарь переменных {имя:значение}
"""
namesAreaComare = xpath.Evaluate(\
"child::area/child::caption[child::name='%s']" %(nameArea),
xmlArea)
if not namesAreaComare:
return False
fields = xpath.Evaluate("child::field/child::name",
namesAreaComare[0].parentNode)
dictVar = {}
for fieldName in fields:
nodeField = fieldName.parentNode
fieldValue = xpath.Evaluate("child::value",nodeField)
name = fieldName.firstChild.nodeValue
value = ""
if fieldValue and fieldValue[0].firstChild:
value = fieldValue[0].firstChild.nodeValue
dictVar[name] = value
return dictVar
def getAreaFieldValues(self, nameArea, nameField, xmlArea):
"""По имени области и имени переменной выводит значениe переменной
поиск ведется только в 1-х потомках области xmlArea
"""
namesAreaComare = xpath.Evaluate(\
"child::area/child::caption[child::name='%s']" %(nameArea),
xmlArea)
fieldsVal = False
for areaComp in namesAreaComare:
fieldsVal = xpath.Evaluate(\
"child::field[child::name='%s'] "\
%(nameField), areaComp.parentNode)
if fieldsVal:
break
if not fieldsVal:
return False
fieldValue = xpath.Evaluate("child::value",
fieldsVal[0])
return fieldValue[0].firstChild.nodeValue
def joinArea(self, baseNode, xmlNewArea):
"""Объединяет область c областью Body (xmlNewArea c baseNode)"""
def appendArea(baseNode, xmlNewArea):
fieldsRemove = xpath.Evaluate(\
"descendant::field[child::action='drop']", xmlNewArea)
for rmNode in fieldsRemove:
parentNode = rmNode.parentNode
parentNode.removeChild(rmNode)
captionAreasRemove = xpath.Evaluate(\
"descendant::area/child::caption[child::action='drop']",
xmlNewArea)
for rmNodeCapt in captionAreasRemove:
rmNode = rmNodeCapt.parentNode
parentNode = rmNode.parentNode
parentNode.removeChild(rmNode)
self.setActionArea(xmlNewArea, "append")
# Добавляем разделитель областей во вложенные области
areaNodes = xpath.Evaluate('descendant::area',xmlNewArea)
for areaNode in areaNodes:
self.setActionArea(areaNode,"append")
parentNode = areaNode.parentNode
parentNode.insertBefore(self.sepAreas.cloneNode(True),
areaNode)
baseNode.appendChild(xmlNewArea)
# Добавляем разделитель областей
baseNode.insertBefore(self.sepAreas.cloneNode(True), xmlNewArea)
nodesNames = xpath.Evaluate('child::area/caption/name',baseNode)
nodesNewArea = xpath.Evaluate('child::caption/name',xmlNewArea)
if not nodesNames:
# Добавляем область
if nodesNewArea:
newAreaAction = self.getActionArea(xmlNewArea)
if not (newAreaAction == "drop" or newAreaAction == "replace"):
appendArea(baseNode, xmlNewArea)
return True
if not nodesNames or not nodesNewArea:
return False
nameArea = ""
if nodesNewArea[0].firstChild:
nameArea = nodesNewArea[0].firstChild.nodeValue.strip()
flagFindArea = False
baseNodes = []
for oName in nodesNames:
newAreaAction = self.getActionArea(xmlNewArea)
oArea = oName.parentNode.parentNode
oNameTxt = ""
if oName.firstChild:
oNameTxt = oName.firstChild.nodeValue
if nameArea == oNameTxt:
flagFindArea = True
# При использовании удаления
if newAreaAction == "drop":
prevNode = oName.parentNode.parentNode.previousSibling
removePrevNodes = []
while (prevNode) and self.getTypeField(prevNode) == "br":
removePrevNodes.append(prevNode)
prevNode = prevNode.previousSibling
for removeNode in removePrevNodes:
baseNode.removeChild(removeNode)
baseNode.removeChild(oName.parentNode.parentNode)
continue
elif newAreaAction == "replace":
oldAreaNode = oName.parentNode.parentNode
newAreaCaption = xpath.Evaluate('child::caption',
xmlNewArea)[0]
oldAreaCaption = xpath.Evaluate('child::caption',
oldAreaNode)[0]
if newAreaCaption and oldAreaCaption:
xmlNewArea.replaceChild(oldAreaCaption,newAreaCaption)
self.setActionArea(xmlNewArea,"replace")
baseNode.replaceChild(xmlNewArea,
oldAreaNode)
continue
baseNodes.append(oName.parentNode.parentNode)
newFields = xpath.Evaluate('child::field',xmlNewArea)
joinNewFields = xpath.Evaluate(\
"child::field[child::action='join']"
,xmlNewArea)
self.addNewFielsOldArea(newFields, joinNewFields, oArea)
if not flagFindArea:
# Добавляем область
if not (newAreaAction == "drop" or\
newAreaAction == "replace"):
appendArea(baseNode, xmlNewArea)
else:
tmpXmlNewAreas = xpath.Evaluate('child::area',xmlNewArea)
for na in tmpXmlNewAreas:
for bn in baseNodes:
self.joinArea(bn, na)
return True
def joinDoc(self, xmlNewDoc):
"""Объединяет два документа"""
newRootNode = xmlNewDoc.documentElement
newBodyNode = xpath.Evaluate('child::body',newRootNode)[0]
newImportBodyNode = self.doc.importNode(newBodyNode, True)
# Перед объединение области с документом
# удаляем комментарии
self.removeComment(newImportBodyNode)
self.joinBody(self.body, newImportBodyNode)
# расставляем BR
self.insertBRtoBody(self.body)
def getQuoteField(self, xmlField):
"""Выдает текст из поля"""
xmlQuotes = xpath.Evaluate('child::quote',xmlField)
br = ""
if xmlField.hasAttribute("type") and\
xmlField.getAttribute("type") == "br":
br = "\n"
if xmlQuotes:
field = xmlQuotes[0]
if field.firstChild:
return field.firstChild.nodeValue + br
return "" + br
def getFieldsArea(self, xmlArea):
"""Выдает потомков XML области"""
xmlFields = []
childNodes = xmlArea.childNodes
for node in childNodes:
if node.nodeType == node.ELEMENT_NODE:
if node.tagName == "area" or node.tagName == "field":
xmlFields.append(node)
return xmlFields
def getTypeField(self, xmlField):
"""Выдает тип поля"""
if xmlField.hasAttribute("type"):
return xmlField.getAttribute("type")
else:
return False
def getNameField(self, xmlField):
"""Выдает имя поля"""
xmlNameFields = xpath.Evaluate('child::name', xmlField)
if xmlNameFields and xmlNameFields[0].firstChild:
return xmlNameFields[0].firstChild.nodeValue
else:
return False
def getNameArea(self, xmlArea):
"""Выдает имя области"""
xmlNameAreas = xpath.Evaluate('child::caption/name', xmlArea)
if xmlNameAreas and xmlNameAreas[0].firstChild:
return xmlNameAreas[0].firstChild.nodeValue
else:
return False
def xmlToText(self, xmlAreas, text):
"""Преобразует список XML областей в текст"""
def getQuotesArea(xmlArea):
quotes = []
xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea)
for node in xmlQuotes:
if node.firstChild:
quotes.append(node.firstChild.nodeValue)
if len(quotes) == 0:
quotes.append("")
quotes.append("")
elif len(quotes) == 1:
quotes.append("")
return quotes
for i in xmlAreas:
if i.tagName == "area":
quotesI = getQuotesArea(i)
startAreaI = quotesI[0]
endAreaI = quotesI[1]
text.append(startAreaI)
xmlFieldsI = self.getFieldsArea(i)
for f in xmlFieldsI:
if f.tagName == "area":
quotesF = getQuotesArea(f)
startAreaF = quotesF[0]
endAreaF = quotesF[1]
text.append(startAreaF)
xmlFieldsF = self.getFieldsArea(f)
self.xmlToText(xmlFieldsF, text)
text.append(endAreaF)
else:
fieldF = self.getQuoteField(f)
text.append(fieldF)
text.append(endAreaI)
else:
fieldI = self.getQuoteField(i)
text.append(fieldI)
def getActionField(self, xmlField):
"""Выдает свойство action XML поля"""
xmlActions = xpath.Evaluate('child::action',xmlField)
if xmlActions and xmlActions[0].firstChild:
return xmlActions[0].firstChild.nodeValue
else:
return False
def getFieldValues(self, xmlField):
"""Выдает значения XML поля в виде массива"""
vals = []
xmlValues = xpath.Evaluate('child::value',xmlField)
if xmlValues:
for node in xmlValues:
if node.firstChild:
vals.append(node.firstChild.nodeValue)
return vals
def getActionArea(self, xmlArea):
"""Выдает свойство action XML области"""
xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
if xmlActions and xmlActions[0].firstChild:
return xmlActions[0].firstChild.nodeValue
else:
return False
def delActionNodeArea(self, xmlArea):
"""Удаляет свойство action XML области"""
xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
if xmlActions and xmlActions[0].firstChild:
parentNode = xmlActions[0].parentNode
parentNode.removeChild(xmlActions[0])
return True
else:
return False
def delActionNodeField(self, xmlField):
"""Удаляет свойство action XML поля"""
xmlActions = xpath.Evaluate('child::action',xmlField)
if xmlActions and xmlActions[0].firstChild:
parentNode = xmlActions[0].parentNode
parentNode.removeChild(xmlActions[0])
return True
else:
return False
# Создает распределенные списки
def postParserListSeplist(self, xmlArea):
"""Создает распределенные списки из элементов области"""
# Потомки
childNodes = self.getFieldsArea(xmlArea)
# содержит списки нод полей с одинаковыми именами в одной области
fieldsSeplist = {}
for node in childNodes:
if node.tagName == "area":
self.postParserListSeplist(node)
else:
fieldName = False
xmlFieldNameNodes = xpath.Evaluate('child::name',node)
if xmlFieldNameNodes and xmlFieldNameNodes[0].firstChild:
fieldName = xmlFieldNameNodes[0].firstChild.nodeValue
if fieldName:
if fieldsSeplist.has_key(fieldName):
fieldsSeplist[fieldName].append(node)
else:
fieldsSeplist[fieldName] = []
fieldsSeplist[fieldName].append(node)
for listNodes in fieldsSeplist.values():
if len(listNodes) > 1:
for node in listNodes:
node.setAttribute("type", "seplist")
def insertBRtoBody(self, xmlArea):
"""Добавляет необходимые переводы строк
"""
# Потомки
childNodes = self.getFieldsArea(xmlArea)
# нода BR
fieldXMLBr = self.createField("br",[],"",[],False, False)
# разделитель поля
fieldSplit = False
# Предыдущая нода
lastNode = False
# Cледующая нода
nextNode = False
lenChildNodes = len(childNodes)
for i in range(lenChildNodes):
node = childNodes[i]
lastTmpNode = node
# Нода area
if node.tagName == "area":
if self.getActionArea(node) == "append" or\
self.getActionArea(node) == "join":
self.delActionNodeArea(node)
if lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "br" or\
lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "comment":
indNext = i + 1
if indNext == lenChildNodes:
xmlArea.appendChild(fieldXMLBr.cloneNode(True))
else:
nextNode = childNodes[indNext]
lastTmpNode = xmlArea.insertBefore(\
fieldXMLBr.cloneNode(True),
nextNode)
else:
xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
node)
self.insertBRtoBody(node)
# Нода field
else:
if self.getActionField(node) == "append" or\
self.getActionField(node) == "join":
self.delActionNodeField(node)
if lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "br" or\
lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "comment":
indNext = i + 1
if indNext == lenChildNodes:
xmlArea.appendChild(fieldXMLBr.cloneNode(True))
else:
nextNode = childNodes[indNext]
lastTmpNode = xmlArea.insertBefore(\
fieldXMLBr.cloneNode(True),
nextNode)
else:
xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
node)
lastNode = lastTmpNode
def postParserList(self):
"""Находит подходящие XML области и делаем из них поля-массивы"""
xmlAreas = xpath.Evaluate('descendant::area', self.body)
for xmlArea in xmlAreas:
flagListXml = True
fieldValues = []
xmlFields = xpath.Evaluate('child::field',xmlArea)
if not xmlFields:
flagListXml = False
lenXmlFields = len(xmlFields)
lenBrArea = 0
for xmlField in xmlFields:
xmlNames = xpath.Evaluate('child::name',xmlField)
xmlVals = xpath.Evaluate('child::value',xmlField)
if xmlField.hasAttribute("type") and\
xmlField.getAttribute("type") == "br":
lenBrArea += 1
continue
if not xmlNames and not xmlVals:
flagListXml = False
break
if xmlNames and xmlNames[0].firstChild and\
xmlNames[0].firstChild.nodeValue:
flagListXml = False
break
if not (xmlVals and xmlVals[0].firstChild and\
xmlVals[0].firstChild.nodeValue):
flagListXml = False
break
else:
fieldValues.append(xmlVals[0].firstChild.nodeValue)
if lenXmlFields == lenBrArea:
flagListXml = False
if flagListXml:
nameNode = xpath.Evaluate('child::caption/name',xmlArea)[0]
fieldName = ""
if nameNode.firstChild:
fieldName = nameNode.firstChild.nodeValue
listArea = []
self.xmlToText([xmlArea],listArea)
fieldQuote = "".join(listArea)
fieldXMLBr = False
if fieldQuote and fieldQuote[-1] == "\n":
fieldQuote = fieldQuote[:-1]
fieldXMLBr = self.createField("br",[],"",[],False, False)
fieldXML = self.createField("list",
[fieldQuote],
fieldName, fieldValues,
False, False)
areaAction = self.getActionArea(xmlArea)
if areaAction:
self.setActionField(fieldXML, areaAction)
parentNode = xmlArea.parentNode
parentNode.insertBefore(fieldXML,xmlArea)
if fieldXMLBr:
parentNode.insertBefore(fieldXMLBr,xmlArea)
parentNode.removeChild(xmlArea)
class blocText:
"""Разбиваем текст на блоки"""
def splitTxtToBloc(self, text ,openTxtBloc,closeTxtBloc,
commentTxtBloc, sepField):
"""Делит текст на блоки (без заголовков)
openTxtBloc - регулярное выражение для начала блока
closeTxtBloc - регулярное выражение для конца блока
commentTxtBloc - регулярное выражение - комментарий
возвращает блоки текста
"""
blocs = []
level = 0
# Нахождение нескольких блоков в строке
# разделители линий, разделителями могут быть ("","\n")
sepsLines = []
# линии
txtLines = []
# Исходные строки
txtLinesSrc = text.splitlines()
for line in txtLinesSrc:
lineBR = ""
lineTmpA = line
closeBl = False
txtLinesTmp = []
commentSpl = commentTxtBloc.split(line)
flagCommentLine = False
if commentSpl[0].strip():
closeBl = True
if len(commentSpl) > 1:
commentBl = commentTxtBloc.search(line)
textLine =commentSpl[0]
commentLine = line[commentBl.start(0):]
lineTmpA = textLine
flagCommentLine = True
while (closeBl):
closeBl = sepField.search(lineTmpA)
if closeBl:
lineTmpB = lineTmpA[closeBl.end(0):]
txtLinesTmp.append(lineTmpA[:closeBl.end(0)])
lineTmpA = lineTmpB
if lineTmpA.strip():
txtLinesTmp.append(lineTmpA)
# Если есть значение и комментарий в строке
if flagCommentLine:
for l in txtLinesTmp:
txtLines.append(l)
sepsLines.append("")
if not txtLinesTmp:
txtLines.append(textLine)
sepsLines.append("")
txtLines.append(commentLine)
sepsLines.append("\n")
# Если есть несколько блоков в строке
elif len(txtLinesTmp)>1 and txtLinesTmp[1].strip():
lenTmpLines = len(txtLinesTmp)
for l in range(lenTmpLines):
txtLines.append(txtLinesTmp[l])
if l == lenTmpLines-1:
sepsLines.append("\n")
else:
sepsLines.append("")
# Cтрока не преобразована
else:
txtLines.append(line)
sepsLines.append("\n")
# разбивание на блоки
z = 0
bl = ""
for i in txtLines:
if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(i):
level += len(openTxtBloc.split(i)) - 1
if commentTxtBloc.split(i)[0].strip() and closeTxtBloc.search(i):
level -= len(closeTxtBloc.split(i)) - 1
bl += i + sepsLines[z]
if level == 0:
if bl:
blocs.append(bl)
bl = ""
z += 1
# cоздание блоков с элементами не входящими в блоки
realBlocs = []
z = 0
bl = ""
for i in blocs:
txtLines = i.splitlines()
if len(txtLines) > 0:
line = txtLines[0]
else:
line = i
if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(line):
if bl:
realBlocs.append(bl)
bl = ""
realBlocs.append(i)
else:
bl += i
z += 1
if bl:
realBlocs.append(bl)
bl = ""
if level == 0:
if text and text[-1] != "\n":
tmpBlocs = realBlocs.pop()
tmpBlocs = tmpBlocs[:-1]
realBlocs.append(tmpBlocs)
return realBlocs
else:
return []
def findArea(self, text, reTextHeader, reTextArea, numGroupArea=0):
""" Делит текст на области (с заголовками)
reTextHeader - регулярное выражение для заголовка области
reTextArea - регулярное выражение для всей области
numGroupArea - номер групы результата поиска по регулярному выражению
по всей области
возвращает два списка: первый - заголовки, второй - тела областей без
заголоков
"""
# Заголовки областей
headersArea = []
# Тексты областей без заголовков
textBodyArea = []
r = reTextArea.search(text)
if not r:
headersArea.append("")
textBodyArea.append(text)
return (headersArea, textBodyArea)
txtWr = text
while r:
textArea = r.group(numGroupArea)
txtSpl = txtWr.split(textArea)
area = txtSpl[0]
txtWr = txtSpl[1]
if area:
headersArea.append("")
textBodyArea.append(area)
res = reTextHeader.search(textArea)
header = textArea[:res.end()]
body = textArea[res.end():]
headersArea.append(header)
textBodyArea.append(body)
if txtWr:
r = reTextArea.search(txtWr)
else:
r = False
if txtWr:
headersArea.append("")
textBodyArea.append(txtWr)
return (headersArea, textBodyArea)
def findBloc(self, text, captionTxtBloc, bodyTxtBloc):
""" Делит текст на блоки (с заголовками)
captionTxtBloc - регулярное выражение для заголовка блока
bodyTxtBloc - регулярное выражение для тела блока
возвращает два списка: первый - заголовки, второй - тела блоков
"""
# Заголовки блоков
headersTxt = []
# Тексты блоков
blocsTxt = []
r = captionTxtBloc.search(text)
if r:
headersTxt.append(r.group(0))
txtSpl = text.split(r.group(0))
blocTxt = txtSpl[0]
txtWr = txtSpl[1]
rb = bodyTxtBloc.search(blocTxt)
if not blocTxt:
blocsTxt.append(blocTxt)
if rb:
blocsTxt.append(rb.group(0))
while (r):
r = captionTxtBloc.search(txtWr)
if r:
headersTxt.append(r.group(0))
txtSpl = txtWr.split(r.group(0))
blocTxt = txtSpl[0]
txtWr = txtSpl[1]
rb = bodyTxtBloc.search(blocTxt)
if rb:
blocsTxt.append(rb.group(0))
else:
blocsTxt.append(txtWr)
if headersTxt and blocsTxt:
if len(headersTxt)>len(blocsTxt):
blocsTxt.insert(0,"")
elif len(headersTxt)<len(blocsTxt):
headersTxt.insert(0,"")
if len(headersTxt)!=len(blocsTxt):
return False
return (headersTxt, blocsTxt)
else:
return False
class _file(_error, scan):
"""Класс для работы с файлами
"""
def __init__(self):
# Имя файла старого шаблона
self.nameFileOld = ""
# Старый шаблон
self.oldTemplate = ""
# Имя файла нового шаблона
self.nameFileNew = ""
# Новый шаблон
self.newTemplate = ""
# Дескриптор файла нового шаблона
self.FN = False
# Дескриптор файла старого шаблона
self.FO = False
def getFileType(self, fileName=""):
"""выдать тип файла (text, bin)
"""
if fileName:
nameFile = fileName
elif self.nameFileNew:
nameFile = self.nameFileNew
else:
return ""
sp = subprocess.Popen("file '%s'"%nameFile, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
close_fds=True, shell=True)
fout, fin, ferr = (sp.stdout, sp.stdin, sp.stderr)
fin.close()
textLine = fout.readline()
fout.readlines()
fout.close()
retText = ""
if textLine:
listTextLine = textLine.split(":")
if len(listTextLine) == 2:
textFormats = ["text", "XML"]
retText = "bin"
fileTypeString = listTextLine[1]
for textFormat in textFormats:
if textFormat in fileTypeString:
retText = "text"
break
ferr.close()
return retText
def 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.oldTemplate:
self.oldTemplate = self.newTemplate
try:
self.FO.write(self.oldTemplate)
except:
self.setError (_("not open file:" ) + self.nameFileOld)
return False
return True
def getModeFile(self, nameFile):
"""Выдает информацию о файле
права файла, владелец, группа файла (777,test, group)
"""
fd = os.open(nameFile, os.O_RDONLY)
fst = os.fstat(fd)
uid = fst.st_uid
gid = fst.st_gid
mode = stat.S_IMODE(fst.st_mode)
os.close(fd)
return (mode,uid,gid)
def openNewFile(self, nameFileNew):
"""Открыть файл шаблона"""
try:
FN = open (nameFileNew, "r")
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, funcCreateFile, removeLink):
"""Открыть конфигурационный файл"""
FO = False
try:
if os.path.islink(nameFileOld) and removeLink:
# если ссылка то удаляем её
os.unlink(nameFileOld)
FO = open (nameFileOld, "r+")
except:
#try:
# Создаем новый файл
funcCreateFile.__call__(nameFileOld)
FO = open(nameFileOld, "r+")
#except:
#self.setError (_("not open file:" ) + nameFileOld)
#return False
return FO
def openFiles(self, nameFileNew, nameFileOld, funcCreateFile, seekFileNew,
removeLink):
"""Открывает шаблон и конфигурационный файл"""
self.oldTemplate = ""
self.newTemplate = ""
self.closeFiles()
self.nameFileOld = self.absFileName(nameFileOld)
self.nameFileNew = self.absFileName(nameFileNew)
self.FN = self.openNewFile(self.nameFileNew)
self.FO = self.__openOldFile(self.nameFileOld,funcCreateFile,removeLink)
if not (self.FN and self.FO):
return False
self.FN.seek(seekFileNew)
self.newTemplate = self.FN.read()
self.oldTemplate = self.FO.read()
return True
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
i += 1
if lenTail>1 and lenTail != i:
return (False,1)
if i > 0:
result = True
return (result, i)
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:(ind+lenUtf[ind])],lenUtf[ind])
if res == False:
indErr.append(ind)
if l>0:
ind +=l
if ind >= len(utf):
break
else:
if utf[ind] != '_ch_':
indErr.append(ind)
ind +=1
if ind >= len(utf):
break
if indErr:
lenIndErr = len(indErr)
block = []
blocks = []
if lenIndErr > 1:
i = 1
while 1:
if i == 1:
block.append(indErr[i-1])
if indErr[i] - indErr[i-1] == 1:
block.append(indErr[i])
else:
if block:
blocks.append(block)
block = []
block.append(indErr[i])
i +=1
if i >= lenIndErr:
break
else:
block.append(indErr[0])
if block:
blocks.append(block)
listErr = []
for block in blocks:
string = ""
for elem in block:
string += hex(ord(text[elem]))[-2:]
listErr.append((block[0],"__hex__?%s?__hex__" %string,elem))
textOut = text
deltaInd = 0
for erEl in listErr:
startInd = erEl[0] + deltaInd
endInd = erEl[2] + 1 + deltaInd
textOut = textOut[:startInd] + erEl[1] + textOut[endInd:]
deltaInd += len(erEl[1])-(erEl[2]-erEl[0]+1)
return textOut
def decode(self, text):
"""Декодирует UTF-8 в смешанный формат"""
varStart = "__hex__\?"
varEnd = "\?__hex__"
# -1 Это экранирование '?' которое тоже считается
deltVarStart = len(varStart)-1
deltVarEnd = len(varEnd)-1
reVar = re.compile(("%s[a-f0-9]+%s")%(varStart,varEnd),re.M)
resS = reVar.search(text)
textTemplateTmp = text
while resS:
mark = textTemplateTmp[resS.start():resS.end()]
hexString = mark[deltVarStart:-deltVarEnd]
i = 0
stringInsert = ""
hexCode = ""
for ch in hexString:
if i>=1:
hexCode += ch
stringInsert += chr(int(hexCode, 16))
hexCode = ""
i = 0
else:
hexCode += ch
i += 1
textTemplateTmp = textTemplateTmp.replace(mark, stringInsert)
resS = reVar.search(textTemplateTmp)
return textTemplateTmp
class template(_file, _terms, xmlShare):
"""Класс для работы с шаблонами
На вход 2 параметра: объект хранения переменных, имя сервиса - не
обязательный параметр
"""
# Импортированные классы поддерживаемых форматов шаблонов
importFormats = {}
# Имена установленных программ
installProg = []
# Версии установленных программ
installProgVersions = []
# кеш вызванных значений программа, номер версии
cacheInstallProg = {}
# Название файла шаблона директории
templDirNameFile = ".calculate_directory"
def __init__(self, objVar, dirsFilter=[], filesFilter=[]):
# Необрабатываемые директории
self.dirsFilter = dirsFilter
# Необрабатываемые файлы
self.filesFilter = filesFilter
_file.__init__(self)
# Словарь для создания объектов новых классов по образцу
# (proftpd создается на основе apache)
self.newObjProt = {'proftpd':'apache'}
# Заголовок title
self.__titleHead = "--------------------------------------\
----------------------------------------"
self._titleBody = ""
self._titleList = (_("Modified"), _("File of a template"))
# Метки
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 = ""
def __octToInt(self, strOct):
"""Преобразование восьмеричного в целое (ввод строка, вывод число)"""
if strOct:
z = 0
i = 0
lst = list(strOct)
lst.reverse()
for ch in lst:
try:
v = int(ch)
except:
self.setError(_("Not valid oct value: ") + str(strOct))
return False
if v > 7:
self.setError (_("Not valid oct value: ") + str(strOct))
return False
z = z + v*8**i
i = i +1
return z
else:
self.setError (_("Empty oct value"))
return False
def getFormatObj(self, formatTemplate, textTemplate):
"""Создание объекта формата шаблона.
Объект создается на основании формата шаблона и текста шаблона"""
if formatTemplate in self.importFormats:
classFormat = self.importFormats[formatTemplate]
else:
try:
classFormat = getattr(__import__("format.%s"%formatTemplate,
globals(), locals(),
[formatTemplate]),
formatTemplate)
except (ImportError, AttributeError):
#Создаем объект из self.newObjProt с помощью
# метаклассов
if formatTemplate in self.newObjProt:
# Прототип класса
nameProt = self.newObjProt[formatTemplate]
try:
classProt = getattr(__import__("format.%s"%nameProt,
globals(), locals(),
[nameProt]),
nameProt)
except (ImportError, AttributeError):
return False
newCl = self.createNewClass(formatTemplate, (classProt,))
self.importFormats[formatTemplate] = newCl
return newCl(textTemplate)
else:
return False
self.importFormats[formatTemplate] = classFormat
return classFormat(textTemplate)
def removeDir(self, rmDir):
"""Рекурсивное удаление директории
входной параметр директория
"""
if not os.path.exists(rmDir):
self.printERROR(_("Not found remove dir %s") %rmDir)
return False
fileObj = _file()
# Сканируем директорию
scanObjs = fileObj.scanDirs([rmDir])
for socketRm in scanObjs[0].sockets:
# Удаляем сокеты
if os.path.exists(socketRm):
os.remove(socketRm)
for linkRm in scanObjs[0].links:
# Удаляем ссылки
os.unlink(linkRm[1])
for fileRm in scanObjs[0].files:
# Удаляем файлы
os.remove(fileRm)
scanObjs[0].dirs.sort(lambda x, y: cmp(len(y), len(x)))
for dirRm in scanObjs[0].dirs:
# Удаляем директории
os.rmdir(dirRm)
if rmDir:
os.rmdir(rmDir)
return True
def createConfFile(self, pathTemplate, path=False):
"""Создает конфигурационный файл если его нет"""
# Создаем директорию если ее нет
if not path:
path = os.path.split(pathTemplate)[0]
if not os.path.exists(path):
createDirs = self.createDir(path)
if not createDirs:
self.setError (_("Can not create file:" ) + pathTemplate)
return False
# Создаем файл если его нет
if not os.path.exists(pathTemplate):
try:
dMode, uid, gid = self.getModeFile(path)
#mode = dMode & ~0111
# Создаем файл
open(pathTemplate,"w").close()
#os.chmod(pathTemplate, mode)
os.chown(pathTemplate, uid, gid)
except:
self.setError (_("Can not create file:" ) + pathTemplate)
return False
return True
def createDir(self, dirName, mode=False, uid=False, gid=False):
"""Создает директорию"""
if os.access(dirName, os.F_OK):
return [dirName]
else:
dMode = False
prevDir, tmpSubdir = os.path.split(dirName)
createDirs = []
while not os.access(prevDir, os.F_OK):
createDirs.append(prevDir)
prevDir = os.path.split(prevDir)[0]
try:
tmpMode,dUid,dGid = self.getModeFile(prevDir)
except OSError:
self.setError (_("Not access dir: " ) + prevDir)
return False
if not mode is False:
dMode = mode
if not uid is False:
dUid = uid
if not gid is False:
dGid = gid
createDirs.reverse()
for nameDir in createDirs:
try:
if dMode:
os.mkdir(nameDir, dMode)
else:
os.mkdir(nameDir)
os.chown(nameDir, dUid, dGid)
except:
self.setError (_("Can not create dir: " ) + nameDir)
return False
try:
if dMode:
os.mkdir(dirName, dMode)
else:
os.mkdir(dirName)
os.chown(dirName, dUid, dGid)
createDirs.append(dirName)
except:
self.setError (_("Can not create dir: " ) + dirName)
return False
return createDirs
def applyVarsTemplate(self, textTemplate, nameTemplate):
""" Заменяет переменные на их значения
"""
resS = self._reVar.search(textTemplate)
textTemplateTmp = textTemplate
while resS:
mark = textTemplateTmp[resS.start():resS.end()]
varName = mark[self._deltVarStart:-self._deltVarEnd]
varValue = ""
try:
varValue = str(self.objVar.Get(varName))
except self.objVar.DataVarsError, e:
print _("error in template %s")%nameTemplate
print e
exit(1)
textTemplateTmp = textTemplateTmp.replace(mark, varValue)
resS = self._reVar.search(textTemplateTmp)
return textTemplateTmp
def applyFuncTemplate(self, textTemplate, nameTemplate):
""" Применяет функции к тексту шаблона
"""
def equalTerm(term, sNum, sMD, localVars):
"""Локальная функция для вычисления выражения"""
terms = sNum.findall(term)
if terms:
strNumers = []
for n in terms:
strNum = n.strip()
if "*" in strNum or "/" in strNum:
strNum = multAndDiv(strNum,sNum,sMD,localVars)
try:
num = int(strNum)
except:
minus = False
if strNum[:1] == "-":
minus = True
strNum = strNum[1:]
if localVars.has_key(strNum):
num = localVars[strNum]
elif self.objVar.exists(strNum):
try:
num = int(self.objVar.Get(strNum))
except:
print _("error in template %s")%nameTemplate
print _("error var %s not int")%str(strNum)
exit(1)
else:
print _("error in template %s")%nameTemplate
print _("error local var %s not defined")\
%str(strNum)
exit(1)
if minus:
num =-num
strNumers.append(num)
return sum(strNumers)
print _("error in template %s")%nameTemplate
print _("error template term %s, incorrect data")%str(term)
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,textTemplateTmp):
"""локальная функция вычисляет первую функцию sum() в шаблоне"""
terms = funTxt[4:-1].replace(" ","").split(",")
# Название локальной переменной
nameLocVar = terms[0]
if not localVars.has_key(nameLocVar):
localVars[nameLocVar] = 0
if len(terms) == 2:
if terms[1].strip():
localVars[nameLocVar] = equalTerm(terms[1],sNum,sMD,
localVars)
replace = str(localVars[nameLocVar])
else:
replace = ""
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[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)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
else:
print _("error in template %s")%nameTemplate
print _("error template term %s")%str(funTxt)
exit(1)
return textTemplateTmp
def funcLoad(funTxt,resS,textTemplateTmp):
"""если файл существует читает из файла локальную переменную
если один параметр - выводит значение локальной переменной
"""
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 template %s")%nameTemplate
print _("error template term %s")%str(funTxt)
exit(1)
if len(terms) == 2:
if not terms[0] in ["ver","num","char","key"]:
print _("error in template %s")%nameTemplate
print _("error template term %s")%str(funTxt)
print _("first argument function is not 'ver' or 'num' or\
'char'")
exit(1)
if len(terms) == 1:
fileName = terms[0].strip()
if fileName[0] != "/":
print _("error in template %s")%nameTemplate
print _("error template term %s")%str(funTxt)
print _("incorrect path %s")%fileName
exit(1)
else:
fileName = terms[1].strip()
if fileName[0] != "/":
print _("error in template %s")%nameTemplate
print _("error template term %s")%str(funTxt)
print _("incorrect path %s")%fileName
exit(1)
replace = ""
if os.path.exists(fileName):
FD = open(fileName)
replace = FD.read().strip()
FD.close
if not replace and len(terms) == 2 and terms[0] in ["ver","num"]:
replace = "0"
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def getInstallPkgGentoo(names = [], versions = []):
"""Выдает два списка, инсталлированные программы и номера версий"""
baseDir = "/var/db/pkg"
pkgs = []
reVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*")
def getFilesDir(pkgs, dirname, names):
for nameFile in names:
absNameFile = os.path.join(dirname,nameFile)
if os.path.isdir(absNameFile):
tail = absNameFile.split(baseDir)
if len(tail)==2:
tail = tail[1].split('/')
if len(tail)==3 and tail[1]!='virtual':
pkgs.append(tail[2])
return True
os.path.walk(baseDir,getFilesDir, pkgs)
pkgs.sort()
for pkg in pkgs:
findVer = reVer.search(pkg)
if findVer:
ver = findVer.group()
versions.append(ver)
names.append(pkg.split(ver)[0][:-1])
#return pkgs
return names, versions
def pkg(nameProg, names, versions):
"""Выдает установленные версии по имени программы"""
# Значение версии из кеша
if nameProg in self.cacheInstallProg:
return self.cacheInstallProg[nameProg]
i = 0
vers = []
for name in names:
if nameProg == name:
while nameProg == names[i]:
vers.append(versions[i])
i += 1
break
i += 1
if vers:
version = vers[-1]
# Запись значения версии в кеш
self.cacheInstallProg[nameProg] = version
return version
else:
return ""
def funcPkg(funTxt,resS,textTemplateTmp):
"""локальная функция выдает номер версии программы"""
terms = funTxt[4:-1].replace(" ","")
# Название программы
nameProg = terms
if not self.installProg:
# Получение всех названий и версий установленных программ
self.installProg,self.installProgVersions =\
getInstallPkgGentoo(names=self.installProg,
versions=self.installProgVersions)
replace = pkg(nameProg,self.installProg,self.installProgVersions)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcRnd(funTxt,resS,textTemplateTmp):
"""локальная функция выдает строку случайных символов
первый аргумент:
'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 template %s")%nameTemplate
print _("error template term %s")%str(funTxt)
exit(1)
fArgvNames = ['num','pas']
if not terms[0] in fArgvNames:
print _("error in template %s")%nameTemplate
print _("error template term %s")%str(funTxt)
print _("first argument function is not 'num' or 'pas'")
exit(1)
try:
lenStr = int(terms[1])
except:
print _("error in template %s")%nameTemplate
print _("error template term %s")%str(funTxt)
print _("two argument function is not number")
exit(1)
if terms[0] == fArgvNames[0]:
replace=''.join([random.choice(string.digits)\
for i in xrange(lenStr)])
elif terms[0] == fArgvNames[1]:
replace=''.join([random.choice(string.ascii_letters + \
string.digits) for i in xrange(lenStr)])
else:
print _("error in template %s")%nameTemplate
print _("error template term %s")%str(funTxt)
exit(1)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcCase(funTxt,resS,textTemplateTmp):
"""локальная функция выдает переменную в определенном регистре
первый аргумент:
'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 template %s")%nameTemplate
print _("error template term %s")%str(funTxt)
exit(1)
fArgvNames = ['upper','lower','capitalize']
if not terms[0] in fArgvNames:
print _("error in template %s")%nameTemplate
print _("error template term %s")%str(funTxt)
print _("first argument function is not 'upper' or 'lower' or\
'capitalize'")
exit(1)
try:
strValue = str(self.objVar.Get(terms[1]))
except:
print _("error in template %s")%nameTemplate
print _("error var %s not found")%str(terms[1])
exit(1)
replace = ""
strValue = _toUNICODE(strValue)
if terms[0] == 'upper':
replace = strValue.upper()
elif terms[0] == 'lower':
replace = strValue.lower()
elif terms[0] == 'capitalize':
replace = strValue.capitalize()
if replace:
replace = replace.encode("UTF-8")
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
# Локальные переменные
localVars = {}
# Регулярное выражние для сложения
sNum = re.compile("\-[^\-\+]+|[^\-\+]+")
# Регулярное выражение для умножениея и деления
sMD = re.compile("[^\-\+\*\/]+")
resS = self._reFunc.search(textTemplate)
textTemplateTmp = textTemplate
while resS:
mark = textTemplateTmp[resS.start():resS.end()]
funTxt = mark[self._deltVarStart:-self._deltVarEnd]
# Функция sum
if funTxt[:4] == "sum(":
textTemplateTmp = funcSum(funTxt,resS,localVars,textTemplateTmp)
resS = self._reFunc.search(textTemplateTmp)
# Функция load
elif funTxt[:5] == "load(":
textTemplateTmp = funcLoad(funTxt,resS,textTemplateTmp)
resS = self._reFunc.search(textTemplateTmp)
elif funTxt[:4] == "pkg(":
textTemplateTmp = funcPkg(funTxt,resS,textTemplateTmp)
resS = self._reFunc.search(textTemplateTmp)
elif funTxt[:4] == "rnd(":
textTemplateTmp = funcRnd(funTxt,resS,textTemplateTmp)
resS = self._reFunc.search(textTemplateTmp)
elif funTxt[:5] == "case(":
textTemplateTmp = funcCase(funTxt,resS,textTemplateTmp)
resS = self._reFunc.search(textTemplateTmp)
else:
resS = False
return textTemplateTmp
def applyTermsTemplate(self,textTemplate,nameTemplate,nameSystemFile=False):
""" Применяет условия, к условным блокам текста
"""
textTerm = ""
resS = self._reTermBloc.search(textTemplate)
textTemplateTmp = textTemplate
def function(text):
"""Функция обработки функций в заголовке"""
return self.applyFuncTemplate(text, nameTemplate)
if nameSystemFile:
while resS:
mark = resS.group(0)
body = resS.group("body")
end = resS.group("end")
parent = resS.group("func")
if not parent:
parent = ""
term = resS.group("rTerm") + parent +\
resS.group("lTerm")
if self._equalTerm(term, _("content template not valid: ")+\
nameTemplate, function):
textTemplateTmp = textTemplateTmp.replace(mark, body+end)
else:
textTemplateTmp = textTemplateTmp.replace(mark, "")
resS = self._reTermBloc.search(textTemplateTmp)
else:
while resS:
mark = resS.group(0)
body = resS.group("body")
end = resS.group("end")
term = resS.group("rTerm") + resS.group("lTerm")
if self._equalTerm(term, _("content template not valid: ")+\
nameTemplate):
textTemplateTmp = textTemplateTmp.replace(mark, body+end)
else:
textTemplateTmp = textTemplateTmp.replace(mark, "")
resS = self._reTermBloc.search(textTemplateTmp)
return textTemplateTmp
def getTitle(self, comment, commentList):
"""Выдает заголовок шаблона ( версия и.т.д)"""
if comment:
commentFirst = comment
commentInsert = comment
commentLast = comment
flagList = False
# В случае открывающего и закрывающего комментария
if type(comment) == types.TupleType and len(comment) == 2:
commentFirst = comment[0]
commentInsert = ""
commentLast = comment[1]
flagList = True
if flagList:
self._titleBody = commentFirst + "\n"
else:
self._titleBody = commentFirst + self.__titleHead + "\n"
z = 0
lenCommentList = len(commentList) - 1
for com in self._titleList:
if lenCommentList < z:
self._titleBody += commentInsert + " " + com + "\n"
else:
self._titleBody += commentInsert + " " + com +\
" " + commentList[z] + "\n"
z += 1
if flagList:
self._titleBody += commentLast +"\n"
else:
self._titleBody += commentLast + self.__titleHead + "\n"
return self._titleBody
else:
return ""
def numberAllTemplates(self, number):
"""Количество шаблонов
Вызов происходит перед наложением шаблонов
в момент вызова в number находится количество обрабатываемых файлов
Наследуемая функция
Используется для отображения прогресса при наложениии шаблонов
"""
return True
def numberProcessTemplates(self, number):
"""Номер текущего обрабатываемого шаблона
Вызов происходит при наложении шаблона
в момент вызова в number находится номер обрабатываемого шаблона
Наследуемая функция
Используется для отображения прогресса при наложениии шаблонов
"""
return True
def __clearInErrorDirObj(self, dirObj):
"""Очищает объект директории при ошибке"""
# директории [(путь к директории, свойства директории)...]
dirObj.dirs = []
# файлы [(путь к файлу, свойства файла)...]
dirObj.files = []
# Ошибка
dirObj.flagError = True
return dirObj
def __scanDir(self, templatesDir, dirObj, dirProperties=()):
"""Измененное cканирование одной директории"""
# сканирование файлов и директорий (следующие сканирования)
if dirProperties:
# Выход при ошибке
if dirObj.flagError:
return dirObj
dirName, prop = dirProperties
# В случае удаления не смотрим внутренние директории
if "append" in prop and prop["append"] == "remove":
return dirObj
filesOrDirs = os.listdir(dirName)
# Сортируем файлы и директории
filesOrDirs.sort()
# Добавляем директорию и ее свойства
dirObj.dirs.append((dirName, prop))
if self.templDirNameFile in filesOrDirs:
# Удаляем файл описания директории из списка файлов
filesOrDirs.remove(self.templDirNameFile)
for fileOrDir in filesOrDirs:
# Выход при ошибке
if dirObj.flagError:
return dirObj
absPath = os.path.join(dirName,fileOrDir)
statInfo = os.stat(absPath)[stat.ST_MODE]
if stat.S_ISREG(statInfo):
# Свойства файла
propF, applyFile=self.__isApplyHeadTemplate(dirObj.fHeadObj,
absPath)
if self.getError():
self.setError(_("Incorrect template: " ) + absPath)
return self.__clearInErrorDirObj(dirObj)
if not applyFile:
continue
# Обработка skip
if "append" in propF and propF["append"] == "skip":
continue
if not "path" in propF:
propF["path"] = prop["_real_path"]
if not "name" in propF:
propF["name"] = os.path.split(absPath)[1]
propF["_real_path"] = os.path.join(propF["path"],
propF["name"])
dirObj.files.append((absPath, propF))
elif stat.S_ISDIR(statInfo):
# Информация о директории
pDir = {}
# Файл информации о директории
dirInfoFile = os.path.join(absPath,
self.templDirNameFile)
if os.path.exists(dirInfoFile) and\
stat.S_ISREG(os.stat(dirInfoFile)[stat.ST_MODE]):
# Настройки директории и применение
pDir, applyDir = self.__isApplyHeadDir(dirObj.dHeadObj,
dirInfoFile)
if self.getError():
self.setError(_("Incorrect template: " ) +\
dirInfoFile)
return self.__clearInErrorDirObj(dirObj)
if not applyDir:
continue
if not "path" in pDir:
pDir["path"] = prop["_real_path"]
if not "name" in pDir:
pDir["name"] = os.path.split(absPath)[1]
# Обработка skip
if "append" in pDir and pDir["append"] == "skip":
pDir["_real_path"] = pDir["path"]
else:
pDir["_real_path"] = os.path.join(pDir["path"],
pDir["name"])
self.__scanDir(False, dirObj, (absPath, pDir))
return dirObj
# Сканирование для получения настроек директории (первое)
else:
if templatesDir and stat.S_ISDIR(os.stat(templatesDir)[stat.ST_MODE]):
# настройки директории
pDir = {}
# Файл информации о директории
dirInfoFile = os.path.join(templatesDir, self.templDirNameFile)
if os.path.exists(dirInfoFile) and\
stat.S_ISREG(os.stat(dirInfoFile)[stat.ST_MODE]):
# Настройки директории и применение
pDir,applyDir = self.__isApplyHeadDir(dirObj.dHeadObj,
dirInfoFile)
if self.getError():
self.setError(_("Incorrect template: " ) +\
dirInfoFile)
return self.__clearInErrorDirObj(dirObj)
if not applyDir:
return dirObj
if not "path" in pDir:
pDir["path"] = "/"
if not "name" in pDir:
pDir["name"] = os.path.split(templatesDir)[1]
# Обработка skip
if "append" in pDir and pDir["append"] == "skip":
pDir["_real_path"] = pDir["path"]
else:
pDir["_real_path"] = os.path.join(pDir["path"],
pDir["name"])
self.__scanDir(False, dirObj, (templatesDir, pDir))
return dirObj
def scanDirs(self, templatesDirs, objVar):
"""Измененное cканирование директорий на вход список
Выход список объктов _dir
"""
dirs = []
# Объект заголовка файла
fHeadObj = fileHeader()
# Объект заголовка директории
dHeadObj = dirHeader()
# Объект переменных
for templateDir in templatesDirs:
dirP = scan._dir()
dirP.baseDir = templateDir
# Ошибка при сканировании
dirP.flagError = False
# Объект заголовка файла
dirP.fHeadObj = fHeadObj
# Объект заголовка директории
dirP.dHeadObj = dHeadObj
# Объект переменных
dirP.objVar = objVar
try:
self.__scanDir(templateDir, dirP)
except OSError, e:
print e.strerror, e.filename
self.__clearInErrorDirObj(dirP)
return [dirP]
if dirP.flagError:
return [dirP]
dirs.append(dirP)
return dirs
def applyTemplates(self):
"""Применяет шаблоны к конфигурационным файлам"""
if not self.objVar.defined("cl_template_path"):
self.setError (_("not defined Var: ") + "cl_template_path")
return False
dirsTemplates = self.objVar.Get("cl_template_path")
dirsTemplates.sort()
dirObjs = self.scanDirs(dirsTemplates,self.objVar)
#файлы к которым были применены шаблоны
filesApply = []
#созданные директории
createdDirs = []
# Получаем общее количество шаблонов (нужно для прогресбара)
allApplyFiles = self.scanTemplates(dirObjs)
if allApplyFiles == False:
return False
numberAllTemplates = len(allApplyFiles)
# Вызываем пустой метод с параметром общее количество шаблонов
self.numberAllTemplates(numberAllTemplates)
# номер обрабатываемого файла
numberProcessTemplates = 0
# имя текущей программы
_nameProgram = self.objVar.Get("cl_name").capitalize()
# версия текущей программы
_versionProgram = self.objVar.Get("cl_ver")
# имя и версия текущей программы
programVersion = "%s %s"%(_nameProgram, _versionProgram)
# Объект обработки заголовков файлов шаблонов
fileHeadObj = fileHeader()
# Проверка на ошибки
for dirObj in dirObjs:
if dirObj.flagError:
return False
for dirObj in dirObjs:
# сортируем файлы по названию
if dirObj.files:
dirObj.files.sort()
# сортируем директории по названию
if dirObj.dirs:
dirObj.dirs.sort()
blockDirs = []
propDir = {}
for dirTemplate, pDirs in dirObj.dirs:
# Получаем реальный путь директории
pathDir = pDirs["_real_path"]
# Фильтрация шаблонов по названию директории
if pathDir in self.dirsFilter:
blockDirs.append(dirTemplate)
continue
dirInfoFile = os.path.join(dirTemplate, self.templDirNameFile)
pathDir, propDir, crDirs = self.__getApplyHeadDir(pDirs)
if not propDir and self.getError():
self.setError(_("Error in apply template: " ) +\
dirInfoFile)
return False
if crDirs:
createdDirs += crDirs
for fileTemplate, propFile in dirObj.files:
findBlock = False
pathFile = propFile["_real_path"]
for blDir in blockDirs:
st,mid,end = pathFile.partition(blDir)
if (not st) and mid and end:
findBlock = True
break
if findBlock:
continue
numberProcessTemplates += 1
self.numberProcessTemplates(numberProcessTemplates)
# Фильтрация шаблонов по названию файла
if pathFile in self.filesFilter:
continue
titleBaseDir = os.path.split(dirObj.baseDir)[0]
titlePath = fileTemplate.partition(titleBaseDir)[2]
templTitle = '"' + titlePath[1:] + '"'
# Записываем в переменную обрабатываемый файл
self.objVar.Set("cl_pass_file",pathFile)
filesApl = self.join(fileTemplate, propFile,
(programVersion,templTitle), fileHeadObj)
if filesApl:
filesApply += filesApl
else:
if self.getError():
#print self.getError()
return False
self.closeFiles()
return (createdDirs, filesApply)
def scanTemplates(self, dirObjs=False):
"""Сканирует директории шаблонов - выводит список файлов"""
if not self.objVar.defined("cl_template_path"):
self.setError (_("not defined Var: ") + "cl_template_path")
return False
if not dirObjs:
dirsTemplates = self.objVar.Get("cl_template_path")
dirObjs = self.scanDirs(dirsTemplates, self.objVar)
#файлы к которым были применены шаблоны
filesApply = []
# Проверка на ошибки
for dirObj in dirObjs:
if dirObj.flagError:
return False
for dirObj in dirObjs:
# сортируем файлы по названию
if dirObj.files:
dirObj.files.sort()
# сортируем директории по названию
if dirObj.dirs:
dirObj.dirs.sort()
blockDirs = []
for dirTemplate, pDirs in dirObj.dirs:
pathDir = pDirs["_real_path"]
# Фильтрация шаблонов по названию директории
if pathDir in self.dirsFilter:
blockDirs.append(dirTemplate)
continue
for fileTemplate, propFile in dirObj.files:
findBlock = False
pathFile = propFile["_real_path"]
# Фильтрация файлов по названию директории
for blDir in blockDirs:
st,mid,end = pathFile.partition(blDir)
if (not st) and mid and end:
findBlock = True
break
if findBlock:
continue
# Фильтрация шаблонов по названию файла
if pathFile in self.filesFilter:
continue
filesApply.append(pathFile)
return filesApply
def __isApplyHeadDir(self, headerObj, templateDirFile):
"""Будет ли применен шаблон корневой директории
Возвращает:
(Настройки директории, и будет ли она применена (True, False))
"""
# Настройки для директории
dPrefs = {}
def function(text):
"""Функция обработки функций в заголовке"""
return self.applyFuncTemplate(text, templateDirFile)
if not os.path.exists(templateDirFile):
return (dPrefs, True)
try:
FD = open(templateDirFile)
textTemplate = FD.read()
FD.close()
except:
self.setError(_("Error open template: " ) + templateDirFile)
return (dPrefs, False)
# Заменяем переменные на их значения
textTemplate = self.applyVarsTemplate(textTemplate, templateDirFile)
# Обработка заголовка
propDir = headerObj.getPropertyTemplate(textTemplate,self.objVar,
function, templateDirFile)
if not propDir["_apply"]:
if headerObj.getError():
self.setError(_("Incorrect template: " ) + templateDirFile)
return (dPrefs, False)
# Записываем настройки
dPrefs.update(propDir)
# Тип добавления
if dPrefs['append'] == "remove":
# Удаление конфигурационного файла
return (dPrefs, False)
# chmod - изменяем права
if "chmod" in dPrefs:
mode = self.__octToInt(dPrefs["chmod"])
if mode:
dPrefs["chmod"] = mode
else:
self.setError (_("False value 'chmod' in template: " ) +\
templateDirFile)
return (dPrefs, False)
# chown - изменяем владельца и группу
if "chown" in dPrefs:
owner = dPrefs["chown"]
uid = False
gid = False
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 template: " )+\
templateDirFile)
return (dPrefs, False)
try:
import grp
gid = grp.getgrnam(strGid)[2]
except:
self.setError (_("Not group in this system: ")+strGid)
self.setError (_("False value 'chown' in template: " )+\
templateDirFile)
return (dPrefs, False)
dPrefs["chown"] = [uid, gid]
else:
self.setError (_("False value 'chown' in template: " ) +\
templateDirFile)
return (dPrefs, False)
# Проверяем path
if "path" in dPrefs and\
(not dPrefs["path"] or not dPrefs["path"][0] == "/"):
self.setError (_("False value 'path' in template: " )+\
templateDirFile)
return (dPrefs, False)
# Проверяем name
if "name" in dPrefs and\
(dPrefs["name"] and dPrefs["name"][0] == "/"):
self.setError (_("False value 'name' in template: " )+\
templateDirFile)
return (dPrefs, False)
return (dPrefs, True)
def __getApplyHeadDir(self, dictPropDir):
"""Применяет шаблон к директории (права, владелец, и.т. д)"""
newDirMv = dictPropDir["_real_path"]
applyDir = newDirMv
# Созданные директории
createDirs = []
if "append" in dictPropDir:
if dictPropDir["append"]=="skip":
return (applyDir, dictPropDir, createDirs)
# Удаляем директорию
elif dictPropDir["append"]=="remove":
if os.path.isdir(newDirMv):
# удаляем директорию
try:
self.removeDir(newDirMv)
except:
self.setError(_("Can not delete dir: " ) +\
newDirMv)
return (applyDir, False, createDirs)
# Флаг проверки существования директории
flagFoundDir = os.path.exists(newDirMv)
mode = False
uid = False
gid = False
# chmod - изменяем права
if "chmod" in dictPropDir:
mode = dictPropDir['chmod']
if flagFoundDir:
os.chmod(newDirMv, mode)
# chown - изменяем владельца и группу
if "chown" in dictPropDir:
uid, gid = dictPropDir['chown']
if flagFoundDir:
os.chown(newDirMv, uid, gid)
if not flagFoundDir:
createDirs = self.createDir(newDirMv, mode, uid, gid)
if not createDirs:
return (applyDir, False, createDirs)
return (applyDir, dictPropDir, createDirs)
def __isApplyHeadTemplate(self, headerObj, templateName):
"""Будет ли применен файл шаблона
Возвращает:
(Настройки файла, и будет ли он применен (True, False))
"""
# Настройки для файла
fPrefs = {}
def function(text):
"""Функция обработки функций в заголовке"""
return self.applyFuncTemplate(text, templateName)
if not os.path.exists(templateName):
return (fPrefs, True)
try:
FD = open(templateName)
textTemplate = FD.read()
FD.close()
except:
self.setError(_("Error open template: " ) + templateName)
return (fPrefs, False)
# Бинарный или текстовый файл шаблона
templateType = self.getFileType(templateName)
foundHeader = False
textHeader = ""
if templateType != "bin":
# Получаем заголовок файла шаблона
foundHeader, textHeader = headerObj.getHeader(textTemplate)
# Заменяем переменные на их значения
textHeader = self.applyVarsTemplate(textHeader, templateName)
propFile = headerObj.getPropertyTemplate(textHeader, foundHeader,
templateType, self.objVar,
function,templateName)
if not propFile["_apply"]:
if headerObj.getError():
self.setError(_("Incorrect template: " ) + templateName)
return (fPrefs, False)
if propFile["append"] == "remove":
# Удаление конфигурационного файла
return (propFile, False)
# Записываем настройки
fPrefs.update(propFile)
# chmod - изменяем права
if "chmod" in fPrefs:
mode = self.__octToInt(fPrefs["chmod"])
if mode:
fPrefs["chmod"] = mode
else:
self.setError (_("False value 'chmod' in template: " ) +\
templateName)
return (fPrefs, False)
# chown - изменяем владельца и группу
if "chown" in fPrefs:
owner = fPrefs["chown"]
uid = False
gid = False
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 template: " )+\
templateName)
return (fPrefs, False)
try:
import grp
gid = grp.getgrnam(strGid)[2]
except:
self.setError (_("Not group in this system: ")+strGid)
self.setError (_("False value 'chown' in template: " )+\
templateName)
return (fPrefs, False)
fPrefs["chown"] = [uid, gid]
else:
self.setError (_("False value 'chown' in template: " ) +\
templateName)
return (fPrefs, False)
# Проверяем path
if "path" in fPrefs and\
(not fPrefs["path"] or not fPrefs["path"][0] == "/"):
self.setError (_("False value 'path' in template: " )+\
templateDirFile)
return (fPrefs, False)
# Проверяем name
if "name" in fPrefs and\
(not fPrefs["name"] or fPrefs["name"][0] == "/"):
self.setError (_("False value 'name' in template: " )+\
templateDirFile)
return (fPrefs, False)
return (fPrefs, True)
def __getApplyHeadTemplate(self, newFile, dictPropFile):
"""Применяет заголовок к шаблону (права, владелец, и.т. д)"""
# Конфигурационный файл в системе
pathOldFile = dictPropFile["_real_path"]
# Директория в которой находится шаблон
newDir = dictPropFile["path"]
# Файлы в системе к которым были применены шаблоны
applyFiles = [pathOldFile]
pathProg = ""
# В случае force
if "force" in dictPropFile:
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 dictPropFile["append"] == "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 dictPropFile:
if "link" in dictPropFile:
templateFile = dictPropFile['link']
if not os.path.exists(templateFile):
if os.path.exists(pathOldFile):
os.remove(pathOldFile)
return (applyFiles, False)
elif not os.path.exists(pathOldFile):
return (applyFiles, False)
# Если есть указатель на файл шаблона (link)
if "link" in dictPropFile and\
not "symbolic" in dictPropFile:
templateFile = dictPropFile['link']
foundTemplateFile = os.path.exists(templateFile)
if foundTemplateFile:
FO = self.openNewFile(templateFile)
buff = FO.read()
FO.close()
if os.path.exists(pathOldFile):
os.remove(pathOldFile)
if foundTemplateFile:
if not self.createConfFile(pathOldFile, newDir):
return (applyFiles, False)
FON = open (pathOldFile, "r+")
FON.write(buff)
FON.close()
# Если символическая ссылка
if "symbolic" in dictPropFile:
prevOldFile = pathOldFile
if "link" in dictPropFile:
pathOldFile = dictPropFile['link']
flagSymlink = True
if not "/" == pathOldFile[0]:
pathLink = os.path.split(os.path.abspath(prevOldFile))[0]
pathProg = os.getcwd()
os.chdir(pathLink)
# Флаг - создан конфигурационный файл
flagCreateFile = False
# chmod - изменяем права
if "chmod" in dictPropFile:
mode = dictPropFile['chmod']
if not os.path.exists(pathOldFile):
if not self.createConfFile(pathOldFile, newDir):
return (applyFiles, False)
flagCreateFile = True
os.chmod(pathOldFile, mode)
# chown - изменяем владельца и группу
if "chown" in dictPropFile:
uid, gid = dictPropFile['chown']
if not flagCreateFile and not os.path.exists(pathOldFile):
if not self.createConfFile(pathOldFile, newDir):
return (applyFiles, False)
os.chown(pathOldFile, uid, gid)
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]
removeLink = not flagSymlink
# Создаем конфигурационный файл если он отсутствует
# открываем файл шаблона и конфигурационный файл
# указатель начала файла шаблона указыввает на текст после заголовка
# файла
if not self.openFiles(newFile, pathOldFile, self.createConfFile,
dictPropFile["_position"], removeLink):
return (applyFiles, False)
if pathProg:
os.chdir(pathProg)
# Если файлы заменяются не нужно их обрабатывать дальше
if "replace" in dictPropFile and\
not "symbolic" in dictPropFile and\
"link" in dictPropFile:
return (applyFiles, False)
return (applyFiles, dictPropFile)
def createNewClass(self, name, bases, attrs={}):
"""Создает объект нового класса
createNewClass(self, name, bases, attrs)
name - имя класса - str,
bases - cписок наследуемых классов - (tuple),
attrs - аттрибуты класса - {dict}
"""
class newMethod:
#Объединяем конфигурации
def join(self, newObj):
if newObj.__class__.__name__ == self.__class__.__name__:
self.docObj.joinDoc(newObj.doc)
# Пост обработка
if 'postXML' in dir(self):
self.postXML()
attrsNew = {}
attrsNew["configName"] = name
if attrs:
for key in attrs.keys():
attrsNew[key] = attrs[key]
newCl = type(name, bases + (newMethod, object), attrsNew)
return newCl
def textIsUtf8(self, text):
"""Проверяет текст на кодировку UTF-8"""
try:
text.decode("UTF-8")
except:
return False
return True
def setTemplateRules(self, templateProp, textTemplate, templFile, confFile):
"""Устанавливаем значения переменных, условий, функций для текста"""
# Вычисляем условные блоки
textTemplate = self.applyTermsTemplate(textTemplate,
templFile, confFile)
# Заменяем переменные на их значения
textTemplate = self.applyVarsTemplate(textTemplate,
templFile)
# Вычисляем функции
textTemplate = self.applyFuncTemplate(textTemplate, templFile)
return textTemplate
def join(self, newFile, propFile, ListOptTitle, fileHeadObj):
"""Объединения шаблона и конф. файла
join(newFile, oldFile, ListOptTitle)
Объединение шаблона newFile и конф. файла oldFile,
propFile - словарь свойств конфигурационного файла
ListOptTitle - список строк которые добавятся в заголовок
"""
# Применяем свойства к конфигурационному файлу
# Открываем файл шаблона и конфигурационный файл
# В случае type=print (печатаем содержимое шаблона)
flagPrintTemplate = False
filesApply, templateProp = self.__getApplyHeadTemplate(newFile,propFile)
if not templateProp:
if self.getError():
return []
return filesApply
# Путь к конфигурационному файлу
oldFile = templateProp["_real_path"]
# Формат шаблона
formatTemplate = templateProp["format"]
# Тип объединение шаблона
appendTemplate = templateProp["append"]
if formatTemplate != "bin":
# Применение условий, переменных, функций и переменных заголовка
self.newTemplate = self.setTemplateRules(templateProp,
self.newTemplate, newFile,
oldFile)
else:
# Копируем содержимое шаблона в содержимое конфигурационного файла
self.oldTemplate = self.newTemplate
# Если файл шаблона имеет поддерживаемый формат
if not formatTemplate in ["raw", "bin"]:
# Флаг- кодировка с бинарными примесями у файла шаблона включаем при
# условии текстового файла и кодировки отличной от UTF-8
flagNotUtf8New = False
# Флаг - кодировка с бинарными примесями у оригинального файла
flagNotUtf8Old = False
# проверяем кодировку шаблона
if not self.textIsUtf8(self.newTemplate):
flagNotUtf8New = True
if not ("link" in templateProp and "symbolic" in templateProp):
# проверяем кодировку оригинального файла
if not self.textIsUtf8(self.oldTemplate):
flagNotUtf8Old = True
# Титл конфигурационного файла
title = ""
if ListOptTitle and "comment" in templateProp:
title = self.getTitle(templateProp["comment"],
ListOptTitle)
title = title.encode("UTF-8")
# Удаляем заголовок Calculate из конфигурационного файла
if "comment" in templateProp:
self.oldTemplate = fileHeadObj.delHeaderConfFile(self.oldTemplate,
templateProp["comment"])
# Создаем объект в случае параметра format в заголовке
if not formatTemplate in ["raw", "bin"] and\
appendTemplate in ["replace", "before", "after"]:
# Преобразовываем бинарные файлы
if flagNotUtf8New:
objTxtCoder = utfBin()
self.newTemplate = objTxtCoder.encode(self.newTemplate)
# создаем объект формата шаблона
objTemplNew = self.getFormatObj(formatTemplate, self.newTemplate)
if not objTemplNew:
self.setError (\
_("Incorrect header parmeter format=%s in template")\
%formatTemplate + " " + newFile)
return False
if "xml_" in formatTemplate:
if objTemplNew.getError():
self.setError (_("False template: " ) + newFile)
return False
nameRootNode = oldFile.rpartition("/")[2].split(".")[0]
objTemplNew.setNameBodyNode(nameRootNode)
# Объект Документ
docObj = objTemplNew.docObj
# Удаление комментариев из документа
docObj.removeComment(docObj.getNodeBody())
# Добавление необходимых переводов строк
docObj.insertBRtoBody(docObj.getNodeBody())
# Добавление необходимых разделителей между областями
docObj.insertBeforeSepAreas(docObj.getNodeBody())
# Пост обработка
if 'postXML' in dir(objTemplNew):
objTemplNew.postXML()
# Получение текстового файла из XML документа
self.newTemplate = objTemplNew.getConfig().encode("UTF-8")
# Если не UTF-8 производим преобразование
if flagNotUtf8New:
self.newTemplate = objTxtCoder.decode(self.newTemplate)
# Титл для объединения
if ListOptTitle:
title = self.getTitle(objTemplNew._comment,
ListOptTitle)
title = title.encode("UTF-8")
# Замена
if appendTemplate == "replace":
if "xml_" in formatTemplate:
data = self.newTemplate.split("\n")
data.insert(1,title)
self.oldTemplate = "\n".join(data)
else:
self.oldTemplate = title + self.newTemplate
self.saveOldFile()
return filesApply
# Впереди
elif appendTemplate == "before":
if "xml_" in formatTemplate:
self.setError (\
_("False option append=before in template %s") %newFile)
return False
if self.newTemplate:
if self.newTemplate[-1] == "\n":
tmpTemplate = self.newTemplate + self.oldTemplate
else:
tmpTemplate = self.newTemplate + "\n" + self.oldTemplate
else:
tmpTemplate = self.oldTemplate
self.oldTemplate = title + tmpTemplate
self.saveOldFile()
return filesApply
# Cзади
elif appendTemplate == "after":
if "xml_" in formatTemplate:
self.setError (\
_("False option append=after in template %s") %newFile)
return False
if self.newTemplate:
if self.newTemplate[-1] == "\n":
tmpTemplate = self.oldTemplate + self.newTemplate
else:
tmpTemplate = self.oldTemplate + "\n" + self.newTemplate
else:
tmpTemplate = self.oldTemplate
self.oldTemplate = title + tmpTemplate
self.saveOldFile()
return filesApply
# Объединение
elif appendTemplate == "join":
if flagNotUtf8New:
objTxtCoder = utfBin()
self.newTemplate = objTxtCoder.encode(self.newTemplate)
# создаем объект формата шаблона
objTemplNew = self.getFormatObj(formatTemplate, self.newTemplate)
if not objTemplNew:
self.setError (\
_("Incorrect header parmeter format=%s in template")\
%formatTemplate + " " + newFile)
return False
if "xml_" in formatTemplate:
if objTemplNew.getError():
self.setError (_("False template: " ) + newFile)
return False
nameRootNode = oldFile.rpartition("/")[2].split(".")[0]
objTemplNew.setNameBodyNode(nameRootNode)
# Титл для объединения
if ListOptTitle:
title = self.getTitle(objTemplNew._comment,
ListOptTitle)
title = title.encode("UTF-8")
# В случае пустого конфигурационного файла
reNoClean = re.compile("[^\s]",re.M)
if not self.oldTemplate or\
not reNoClean.search(self.oldTemplate):
self.oldTemplate = ""
# Удаляем заголовок Calculate из конфигурационного файла
self.oldTemplate = fileHeadObj.delHeaderConfFile(self.oldTemplate,
objTemplNew._comment)
if flagNotUtf8Old:
objTxtCoder = utfBin()
self.oldTemplate = objTxtCoder.encode(self.oldTemplate)
# создаем объект формата шаблона для конфигурационного файла
objTemplOld = self.getFormatObj(formatTemplate, self.oldTemplate)
if not objTemplOld:
self.setError (_("Error in template %s") %oldFile)
return False
if "xml_" in formatTemplate:
if objTemplOld.getError():
self.setError (_("False template: " ) + oldFile)
return False
nameRootNode = oldFile.rpartition("/")[2].split(".")[0]
objTemplOld.setNameBodyNode(nameRootNode)
#print "#%s#" %(objTemplOld.docObj.body.toprettyxml())
#print "#%s#" %(objTemplNew.docObj.body.toprettyxml())
objTemplOld.join(objTemplNew)
if "xml_" in formatTemplate:
if objTemplOld.getError():
self.setError (_("False template: " ) + newFile)
return False
data = \
objTemplOld.getConfig().encode("UTF-8").split("\n")
data.insert(1,title)
self.oldTemplate = "\n".join(data)
else:
self.oldTemplate = title +\
objTemplOld.getConfig().encode("UTF-8")
# Декодируем если кодировка не UTF-8
if flagNotUtf8New or flagNotUtf8Old:
self.newTemplate = objTxtCoder.decode(self.newTemplate)
self.oldTemplate = objTxtCoder.decode(self.oldTemplate)
self.saveOldFile()
return filesApply
else:
self.setError (_("False (type append) template: " )+appendTemplate)
return False
class iniParser(_error):
"""Класс для работы с ini файлами
"""
def __init__(self, iniFile):
# Класс samba
self.samba = getattr(__import__("format.samba",
globals(), locals(),
["samba"]), "samba")
# название ini файла
self.iniFile = iniFile
# права создаваемого ini-файла
self.mode = 0640
# Cоответствует ли формат файла нужному
self.checkIni = None
def setMode(self, mode):
"""установка прав создаваемого ini-файла"""
self.mode = mode
def openIniFile(self):
if not os.access(self.iniFile, os.R_OK):
return ""
FD = open(self.iniFile, "r")
textIni = FD.read()
FD.close()
return textIni
def writeIniFile(self, txtConfig):
if not os.path.exists(self.iniFile):
fd = os.open(self.iniFile, os.O_CREAT)
os.close(fd)
os.chmod(self.iniFile, self.mode)
if not os.path.exists(self.iniFile):
self.setError(_("Unable to create file") + ": " + self.iniFile)
return False
FD = open(self.iniFile, "r+")
FD.truncate(0)
FD.seek(0)
FD.write(txtConfig)
FD.close()
def setVar(self, strHeader, dictVar):
"""Заменяет или добавляет область и переменные
Добавляет область в ini-файл или объединяет с существующей
strHeader - имя области
dictVar - словарь переменных
"""
textIni = self.openIniFile()
if not self.checkIniFile(textIni):
return False
# создаем объект типа samba и записываем в него содержимое ini-файла
objIni = self.samba(textIni)
# создаем текст в формате samba из строки заголовка и
# словаря переменных области
txtConfig = objIni.createTxtConfig(strHeader, dictVar)
# создаем объект типа samba и записываем в него текст
objIniAdd = self.samba(txtConfig)
# объединяем объекты для получения результирующего текста
objIni.join(objIniAdd)
# получаем текст
txtConfig = objIni.getConfig().encode("UTF-8")
# записываем его в ini файл
self.writeIniFile(txtConfig)
return True
def isEmptyFile(self, textIni):
"""Является ли файл пустым"""
if not textIni.strip():
return True
else:
return False
def checkIniFile(self, textIni):
"""Проверка на правильность формата файла"""
if self.checkIni == None:
# Ошибка
if textIni == False:
self.checkIni = False
return False
self.checkIni = True
# В файле есть данные
if not self.isEmptyFile(textIni):
objIni = self.samba(textIni)
xmlBody = objIni.docObj.getNodeBody()
if not xmlBody.firstChild:
self.checkIni = False
return self.checkIni
def delVar(self, strHeader, nameVar):
"""Удаляем переменную из ini файла"""
delNameVar = "!%s" %(nameVar)
dictVar = {delNameVar:"del"}
res = self.setVar(strHeader, dictVar)
return res
def delArea(self, strHeader):
"""Удаляем область из ini файла"""
delStrHeader = "!%s" %(strHeader)
dictVar = {"del":"del"}
res = self.setVar(delStrHeader, dictVar)
return res
def getVar(self, strHeader, nameVar):
"""Получаем значение переменной из ini-файла"""
textIni = self.openIniFile()
if not self.checkIniFile(textIni):
return False
# создаем объект типа samba и записываем в него содержимое ini-файла
objIni = self.samba(textIni)
# получаем ноду body
xmlBody = objIni.docObj.getNodeBody()
# находим в области переменную
res = objIni.docObj.getAreaFieldValues(strHeader, nameVar, xmlBody)
if res == False:
return ""
else:
return res
def getAreaVars(self,strHeader):
"""Получаем все переменнные области из ini-файла"""
textIni = self.openIniFile()
if not self.checkIniFile(textIni):
return False
# создаем объект типа samba и записываем в него содержимое ini-файла
objIni = self.samba(textIni)
# получаем ноду body
xmlBody = objIni.docObj.getNodeBody()
# если находим область то выдаем словарем все переменные иначе False
res = objIni.docObj.getAreaFields(strHeader, xmlBody)
if res == False:
return {}
else:
return res
def getAllSectionNames(self):
"""Получаем все имена секций определенных в ini файле"""
textIni = self.openIniFile()
if not self.checkIniFile(textIni):
return False
# создаем объект типа samba и записываем в него содержимое ini-файла
objIni = self.samba(textIni)
# получаем ноду body
xmlBody = objIni.docObj.getNodeBody()
xmlNodes = objIni.docObj.getFieldsArea(xmlBody)
# Имена секций ini файла
namesSection = []
for xmlNode in xmlNodes:
if xmlNode.tagName == "area":
nSect = objIni.docObj.getNameArea(xmlNode)
if nSect:
namesSection.append(nSect)
return namesSection