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/pym/cl_template.py

4985 lines
217 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 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
import time
# Переопределение exit
import cl_overriding
from cl_utils import _error, _toUNICODE, getModeFile, removeDir, typeFile,\
scanDirectory, convertStrListDict, pathJoin
import cl_lang
tr = cl_lang.lang()
tr.setLocalDomain('cl_lib')
tr.setLanguage(sys.modules[__name__])
class _shareTermsFunction:
"""Общие аттрибуты для классов _terms и templateFunctions"""
# Символы допустимые в скобках функции шаблона
_reFunctionArgvInSquareBrackets = "a-zA-Z0-9_\-\+\,\*\/\.\'\"~\\\\ "
_reFunctionArgvText = "[%s]"%_reFunctionArgvInSquareBrackets
# регулярное выражение для поиска функции в шаблоне
_reFunctionText = "([a-zA-Z0-9\_\-]+)\((%s+|)\)" %_reFunctionArgvText
class _terms(_error, _shareTermsFunction):
"""Вычисление условий применяемых в шаблонах
"""
# регулярное выражение для поиска функции в шаблоне
_reFunction = re.compile(_shareTermsFunction._reFunctionText)
# регулярное выражение для не версии
_re_not_Version = re.compile("[^0-9\.]|^$")
# Регулярное выражение для названия переменной
_reDenyName = re.compile("[^a-zA-Z0-9\_\-]")
# Регулярное выражение для сравниваемого значения
_reDenyValue = re.compile("[^0-9a-zA-Z_\.-]")
def _convertVers(self, verA, verB):
"""Конвертирование номеров версий для корректного сравнения
"""
elemA = verA.split(".")
elemB = verB.split(".")
if len(elemA) > len(elemB):
maxElemB = len(elemB)-1
for i in range(len(elemA)):
if i > maxElemB:
elemB.append("0")
else:
maxElemA = len(elemA)-1
for i in range(len(elemB)):
if i > maxElemA:
elemA.append("0")
for i in range(len(elemB)):
lenA = len(elemA[i])
lenB = len(elemB[i])
if lenA == lenB:
pass
elif lenA > lenB:
res = lenA - lenB
for z in range(res):
elemB[i] = "0" + elemB[i]
elif lenB > lenA:
res = lenB - lenA
for z in range(res):
elemA[i] = "0" + elemA[i]
return (".".join(elemA), ".".join(elemB))
def _equalTerm(self, term, textError, function=False):
"""Вычисление логических выражений для условий
Для корректной работы в классе который наследует этот класс
должен быть объявлен аттрибут self.objVar
(объект для работы с переменными)
function - функция для для обработки функций в заголовке блока
"""
trm = {"&&":" and ","||":" or "}
rule = ["==", "!=", ">=", "<=", ">", "<"]
listEqual = []
for k in trm.keys():
if k in term:
term = term.replace(k,trm[k])
trs = term.split(" ")
listSplitOr = []
if "or" in trs:
lst = []
for t in trs:
if t != "or":
lst.append(t)
else:
listSplitOr.append(lst)
lst = []
if lst:
listSplitOr.append(lst)
else:
listSplitOr = [trs]
for trsAnd in listSplitOr:
listEqual = []
for t in trsAnd:
flagRule = False
for sepF in rule:
if sepF in t:
flagRule = True
vals = t.split(sepF)
break
if flagRule:
#проверка на допустимость названия переменной
flagFunction = False
if self._reDenyName.search(vals[0]):
#проверка на допустимость функции
flagError = True
if function:
searchFunct = self._reFunction.search(vals[0])
if searchFunct:
flagError = False
flagFunction = True
if flagError:
self.setError("'%s'"%term + " " + _("incorrect"))
self.setError(textError)
return False
#проверка на допустимость значения
if self._reDenyValue.search(vals[1]):
self.setError("'%s'"%term + " " + _("incorrect"))
self.setError(textError)
return False
flagIntTypeVar = None
if flagFunction:
valVars = function("#-%s-#"%vals[0])
if valVars is False:
self.setError("'%s'"%term + " " + _("incorrect"))
self.setError(textError)
return False
if "load" == searchFunct.group(1) and\
re.search("\(\s*num\s*,",vals[0]):
if valVars:
try:
valVars = int(valVars)
except:
self.setError("'%s'"%term + " " + \
_("incorrect"))
self.setError(textError)
return False
flagIntTypeVar = True
else:
flagIntTypeVar = False
else:
if valVars == "" and\
not self._re_not_Version.search(vals[1]):
valVars = "0"
elif vals[1] == "" and\
not self._re_not_Version.search(valVars):
vals[1] = "0"
else:
try:
valVars = self.objVar.Get(vals[0])
except self.objVar.DataVarsError, e:
cl_overriding.printERROR(textError)
cl_overriding.printERROR(e)
cl_overriding.exit(1)
# Номера версий для ini
flagNotIniFunct = True
# Два значения не пусты
flagNotEmptyVals = not (valVars == "" and vals[1] == "")
if flagFunction and flagNotEmptyVals and\
searchFunct.group(1) == "ini":
# Проверка значения на версию
if not self._re_not_Version.search(valVars) and\
not self._re_not_Version.search(vals[1]):
verFile, verVar = self._convertVers(vals[1],valVars)
exec(\
"res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")")
if res:
listEqual.append(True)
else:
listEqual.append(False)
flagNotIniFunct = False
# Cравниваем номера версий
if flagNotIniFunct:
if flagNotEmptyVals and\
("_ver" in vals[0] or\
(flagFunction and searchFunct.group(1)=="pkg") or\
(flagFunction and searchFunct.group(1)=="load" and\
re.search("\(\s*ver\s*,",vals[0]))):
# Проверка значения на версию
if self._re_not_Version.search(vals[1]):
self.setError("'%s'"%term+" "+_("incorrect"))
self.setError(_("Value is not version"))
return False
# Проверка значения функции на версию
if self._re_not_Version.search(valVars):
self.setError("'%s'"%term+" "+_("incorrect"))
self.setError(\
_("Value function is not version"))
return False
verFile, verVar = self._convertVers(vals[1],valVars)
exec(\
"res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")")
if res:
listEqual.append(True)
else:
listEqual.append(False)
flagNotIniFunct = False
else:
if flagIntTypeVar is 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 not flagNotEmptyVals:
listEqual.append(False)
else:
self.setError("'%s'"%term + " "\
+ _("incorrect"))
self.setError(textError)
return False
else:
if t == "and":
if listEqual == [] or False in listEqual:
listEqual = [False]
else:
listEqual = [True]
else:
self.setError("'%s'"%term + " " + _("incorrect"))
self.setError(textError)
return False
if not (listEqual == [] or False in listEqual):
break
if listEqual == [] or False in listEqual:
return False
return True
#exec("res=(%s)"%("".join(listEqual)))
#return res
class fileHeader(_terms):
"""Обработка заголовков шаблонов и конфигурационных файлов
"""
# Допустимые параметры заголовка
allowParam = ["format", "format_conf", "comment", "append", "force",
"link", "mirror", "symbolic", "chmod", "chown", "name",
"path"]
# Тип шаблона
fileType = ""
# Тип вставки шаблона
typeAppend = ""
# Возможные типы вставки шаблонов
_fileAppend = "join", "before", "after", "replace", "remove", "skip"
# Интерпретатор (#!/bin/bash) (#!/usr/bin/python)
execStr = ""
# Символ комментария
comment = False
# Выражение для поиска строки интерпретатора
reExecStr = re.compile("^#!.+\s*",re.I)
# условные операторы
terms = ('>', '<', '==', '!=', '>=', '<=')
# параметры без значения
listParNotVal = ("symbolic", "force", "mirror")
# Результат вычисления условия в заголовке
headerTerm = True
def __init__(self, templateName, text, comment=False, fileType=False,
objVar=False, function=False):
self.body = text
# Объект с переменными
self.objVar=objVar
# Параметры описанные в заголовке файла шаблона
self.params = {}
# некорректные параметры
incorrectParams = set([])
# Удаление Заголовка Calculate
if comment:
titleFirst = _("Modified")
# В случае текста XML
if type(comment) == types.TupleType and len(comment) == 2:
reCalcHeader =\
re.compile("\s*%s\s+%s.+\s+(.+\n)+%s\s?"\
%(comment[0], titleFirst, comment[1]),re.M|re.I)
reS = reCalcHeader.search(text)
if reS:
self.body = text[:reS.start()]+text[reS.end():]
else:
reCalcHeader = re.compile(\
"\s*%s\-+\s+%s\s+%s.+\s+(%s.+\s+)+%s\-+\s?"\
%(comment, comment, titleFirst ,comment,comment),
re.M|re.I)
reS = reCalcHeader.search(text)
if reS:
self.body = text[reS.end():]
if fileType != False:
if fileType=="bin":
self.params["format"] = fileType
self.fileType = self._getType()
self.typeAppend = self._getAppend()
else:
textLines = text.splitlines()
if textLines:
textLine = textLines[0]
rePar = re.compile("\s*#\s*calculate\s+",re.I)
reP = rePar.search(textLine)
if reP:
reL = False
reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
reLs = reLns.search(text)
if reLs:
reL = reLs
paramLine = text[reP.end():reLs.end()]
paramLine = paramLine.replace("\\"," ")
else:
reLn = re.compile("\n")
reL = reLn.search(text)
paramLine = textLine[reP.end():]
if reL:
self.body = text[reL.end():]
else:
self.body = ""
paramList = re.split("\s+",paramLine)
if paramList:
for i in paramList:
foundTerm = False
for term in self.terms:
if term in i:
foundTerm = True
errorMsg = _("Incorrect template") +\
": "+ templateName +"\n"+\
_("header template not valid")+\
": "+ i
if function:
rezTerm = self._equalTerm(i,
errorMsg,
function)
else:
rezTerm = self._equalTerm(i,
errorMsg)
if not rezTerm:
self.headerTerm = False
break
if not foundTerm:
par = i.split("=")
if len(par) == 1:
if i in self.listParNotVal:
self.params[i] = "True"
else:
if i.strip():
incorrectParams = set([i])
elif len(par) == 2:
self.params[par[0]] = par[1]
self.comment = self._getComment()
self.fileType = self._getType()
self.typeAppend = self._getAppend()
reExecRes = self.reExecStr.search(self.body)
if reExecRes:
self.execStr = self.body[reExecRes.start():reExecRes.end()]
self.body = self.body[reExecRes.end():]
if not incorrectParams:
incorrectParams = set(self.params.keys()) - set(self.allowParam)
if incorrectParams:
self.headerTerm = False
self.setError(_("incorrect header parameters - '%s'")\
%" ".join(list(incorrectParams)))
def _getType(self):
"""Выдать тип файла"""
if self.params.has_key("format"):
return self.params["format"]
else:
return "raw"
def _getAppend(self):
"""Выдать тип добавления файла"""
if self.params.has_key("append") and self.params["append"] in\
self._fileAppend:
return self.params["append"]
else:
if self.fileType != "raw" and self.fileType != "bin" and\
self.fileType != "":
self.params["append"] = "join"
return "join"
self.params["append"] = "replace"
return "replace"
def _getComment(self):
"""Выдать символ комментария файла"""
if self.params.has_key("comment"):
return self.params["comment"]
else:
return False
class dirHeader(_terms):
"""Обработка заголовков шаблонов директорий
"""
# Допустимые параметры заголовка
allowParam = ["append", "chmod", "chown", "name", "path"]
# Тип вставки шаблона
typeAppend = ""
# Возможные типы вставки шаблонов
_fileAppend = "join", "remove", "skip"
# условные операторы
terms = ('>', '<', '==', '!=', '>=', '<=')
# параметры без значения
listParNotVal = ("symbolic", "force")
# Результат вычисления условия в заголовке
headerTerm = True
def __init__(self, templateName, text, objVar=False, function=False):
self.body = text
# Объект с переменными
self.objVar=objVar
# Параметры описанные в заголовке файла шаблона
self.params = {}
# некорректные параметры
incorrectParams = set([])
textLines = text.splitlines()
flagErrorBody = False
if textLines:
textLine = textLines[0]
rePar = re.compile("\s*#\s*calculate\s+",re.I)
reP = rePar.search(textLine)
if reP:
reL = False
reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
reLs = reLns.search(text)
if reLs:
reL = reLs
paramLine = text[reP.end():reLs.end()]
paramLine = paramLine.replace("\\"," ")
else:
reLn = re.compile("\n")
reL = reLn.search(text)
paramLine = textLine[reP.end():]
if reL:
self.body = text[reL.end():]
else:
self.body = ""
if self.body.strip():
self.headerTerm = False
self.setError(_("incorrect text in template: '%s'")\
%self.body)
flagErrorBody = True
if not flagErrorBody:
paramList = re.split("\s+",paramLine)
if paramList:
for i in paramList:
foundTerm = False
for term in self.terms:
if term in i:
foundTerm = True
errorMsg = _("Incorrect template") +\
": "+ templateName +"\n"+\
_("header template not valid")+ ": "+ i
if function:
rezTerm = self._equalTerm(i, errorMsg,
function)
else:
rezTerm = self._equalTerm(i, errorMsg)
if not rezTerm:
self.headerTerm = False
break
if not foundTerm:
par = i.split("=")
if len(par) == 1:
if i in self.listParNotVal:
self.params[i] = "True"
else:
if i.strip():
incorrectParams = set([i])
elif len(par) == 2:
self.params[par[0]] = par[1]
self.typeAppend = self._getAppend()
if not flagErrorBody:
if not incorrectParams:
incorrectParams = set(self.params.keys()) - set(self.allowParam)
if incorrectParams:
self.headerTerm = False
self.setError(_("incorrect header parameters - '%s'")\
%" ".join(list(incorrectParams)))
def _getAppend(self):
"""Выдать тип добавления директории"""
if self.params.has_key("append") and self.params["append"] in\
self._fileAppend:
return self.params["append"]
else:
return "join"
class objShare:
"""Общий клас для объектов, наследуем
"""
def createFieldTerm(self, name, value, quote, docObj):
"""Создание поля переменная - значение
при создании поля проверяется первый символ названия переменной
и добавляется тег action
"!" - <action>drop</action> удаляет
"+" - <action>join</action> добавляет
"-" - <action>replace</action> заменяет
"""
fieldAction = False
if name:
if name[0] == "!" or name[0] == "-" or name[0] == "+":
qnt = self.removeSymbolTerm(quote)
fieldXML = docObj.createField("var",[qnt],
name[1:], [value],
False, False)
if name[0] == "!":
fieldAction = "drop"
elif name[0] == "+":
fieldXML.setAttribute("type", "seplist")
fieldAction = "join"
else:
fieldXML = docObj.createField("var",
[quote.replace("\n","")],
name, [value],
False, False)
else:
fieldXML = docObj.createField("var",
[quote.replace("\n","")],
name, [value],
False, False)
if fieldAction:
docObj.setActionField(fieldXML, fieldAction)
return fieldXML
def removeSymbolTerm(self, text):
"""Удаляет первый символ названия переменной в строке
Если первый встречающийся символ с начала строки
'+', '-', '!' то он из этой строки будет удален,
если перед этим символом были пробельные символы,
то они будут сохранены, так-же если в строке есть символ
перевода строки он будет удален.
"""
reTerm = re.compile("^[ \t]*(\!|\+|\-)")
textNS = text.replace("\n","")
res = reTerm.search(textNS)
if res:
textNS = textNS[res.start():res.end()-1] + textNS[res.end():]
return textNS
def getConfig(self):
"""Выдает конфигурационный файл"""
listConfigTxt = []
childNodes = self.docObj.getNodeBody().childNodes
for node in childNodes:
if node.nodeType == node.ELEMENT_NODE:
if node.tagName == "field":
listConfigTxt.append(self.docObj.getQuoteField(node))
elif node.tagName == "area":
self.docObj.xmlToText([node], listConfigTxt)
return "".join(listConfigTxt)
def splitToFields(self, txtBloc):
"""Разбиваем текст на поля (объекты) которые имеют следующие аттрибуты
self.name - если переменная то имя переменной
self.value - если у переменной есть значение то значение переменной
self.comment - если комментарий то текст комментария
self.br - если перевод строки то текст перед переводом из пробелов
Результат список объектов полей
"""
finBloc = "\n"
if txtBloc[-1] != "\n":
finBloc = ""
linesBlocTmp = txtBloc.splitlines()
linesBloc = []
brBloc = []
z = 0
lenLines = len(linesBlocTmp)
for i in linesBlocTmp:
if self.reComment.split(i)[0]:
findCooment = self.reComment.search(i)
comment = False
par = i
if findCooment:
par = i[:findCooment.start()]
comment = i[findCooment.start():]
fields = self.reSepFields.split(par)
lenFields = len(fields)
if lenFields>1:
for fi in range(lenFields-1):
linesBloc.append(fields[fi]+ self.sepFields)
if fi == lenFields-2:
if comment:
brBloc.append("")
else:
if (lenLines-1)== z:
brBloc.append(finBloc)
else:
brBloc.append("\n")
else:
brBloc.append("")
if comment:
linesBloc.append(comment)
if (lenLines-1)== z:
brBloc.append(finBloc)
else:
brBloc.append("\n")
else:
linesBloc.append(i)
if (lenLines-1)== z:
brBloc.append(finBloc)
else:
brBloc.append("\n")
else:
linesBloc.append(i)
if (lenLines-1)== z:
brBloc.append(finBloc)
else:
brBloc.append("\n")
z +=1
fields = self.setDataField(linesBloc, brBloc)
return fields
class xmlShare:
"""Общий класс для объектов XML, наследуем
"""
def _createElement(self, doc, tagName, text="", attributes={}):
"""Создание нового XML элемента"""
element = doc.createElement(tagName)
if text:
txtNode = doc.createTextNode(_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
if parentNode:
fieldsVal = xpath.Evaluate(\
"child::field[attribute::type='seplist'][child::name='%s'] "\
%(nameField), parentNode)
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)
for node in notSepListField:
if self.getTypeField(node) == "seplist":
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])
if not fieldValue:
return False
if fieldValue[0].firstChild:
return fieldValue[0].firstChild.nodeValue
else:
return ""
def getAllAreas(self):
"""Выдает все области"""
return xpath.Evaluate('descendant::area', self.body)
def getArea(self, nameArea, xmlArea):
"""По имени области находит области (первый потомок xmlArea)"""
namesAreaComare = xpath.Evaluate(\
"child::area/child::caption[child::name='%s']" %(nameArea),
xmlArea)
return map(lambda x: x.parentNode, namesAreaComare)
def joinArea(self, baseNode, xmlNewArea):
"""Объединяет область c областью Body (xmlNewArea c baseNode)"""
def appendArea(baseNode, xmlNewArea):
fieldsRemove = xpath.Evaluate(\
"descendant::field[child::action='drop']", xmlNewArea)
for rmNode in fieldsRemove:
parentNode = rmNode.parentNode
parentNode.removeChild(rmNode)
captionAreasRemove = xpath.Evaluate(\
"descendant::area/child::caption[child::action='drop']",
xmlNewArea)
for rmNodeCapt in captionAreasRemove:
rmNode = rmNodeCapt.parentNode
parentNode = rmNode.parentNode
parentNode.removeChild(rmNode)
self.setActionArea(xmlNewArea, "append")
# Добавляем разделитель областей во вложенные области
areaNodes = xpath.Evaluate('descendant::area',xmlNewArea)
for areaNode in areaNodes:
self.setActionArea(areaNode,"append")
parentNode = areaNode.parentNode
parentNode.insertBefore(self.sepAreas.cloneNode(True),
areaNode)
baseNode.appendChild(xmlNewArea)
# Добавляем разделитель областей
baseNode.insertBefore(self.sepAreas.cloneNode(True), xmlNewArea)
nodesNames = xpath.Evaluate('child::area/caption/name',baseNode)
nodesNewArea = xpath.Evaluate('child::caption/name',xmlNewArea)
if not nodesNames:
# Добавляем область
if nodesNewArea:
newAreaAction = self.getActionArea(xmlNewArea)
if not (newAreaAction == "drop" or newAreaAction == "replace"):
appendArea(baseNode, xmlNewArea)
return True
if not nodesNames or not nodesNewArea:
return False
nameArea = ""
if nodesNewArea[0].firstChild:
nameArea = nodesNewArea[0].firstChild.nodeValue.strip()
flagFindArea = False
baseNodes = []
for oName in nodesNames:
newAreaAction = self.getActionArea(xmlNewArea)
oArea = oName.parentNode.parentNode
oNameTxt = ""
if oName.firstChild:
oNameTxt = oName.firstChild.nodeValue
if nameArea == oNameTxt:
flagFindArea = True
# При использовании удаления
if newAreaAction == "drop":
prevNode = oName.parentNode.parentNode.previousSibling
removePrevNodes = []
while (prevNode) and self.getTypeField(prevNode) == "br":
removePrevNodes.append(prevNode)
prevNode = prevNode.previousSibling
for removeNode in removePrevNodes:
baseNode.removeChild(removeNode)
baseNode.removeChild(oName.parentNode.parentNode)
continue
elif newAreaAction == "replace":
oldAreaNode = oName.parentNode.parentNode
newAreaCaption = xpath.Evaluate('child::caption',
xmlNewArea)[0]
oldAreaCaption = xpath.Evaluate('child::caption',
oldAreaNode)[0]
if newAreaCaption and oldAreaCaption:
xmlNewArea.replaceChild(oldAreaCaption,newAreaCaption)
self.setActionArea(xmlNewArea,"replace")
baseNode.replaceChild(xmlNewArea,
oldAreaNode)
continue
baseNodes.append(oName.parentNode.parentNode)
newFields = xpath.Evaluate('child::field',xmlNewArea)
joinNewFields = xpath.Evaluate(\
"child::field[child::action='join']"
,xmlNewArea)
self.addNewFielsOldArea(newFields, joinNewFields, oArea)
if not flagFindArea:
# Добавляем область
if not (newAreaAction == "drop" or\
newAreaAction == "replace"):
appendArea(baseNode, xmlNewArea)
else:
tmpXmlNewAreas = xpath.Evaluate('child::area',xmlNewArea)
for na in tmpXmlNewAreas:
for bn in baseNodes:
self.joinArea(bn, na)
return True
def joinDoc(self, xmlNewDoc):
"""Объединяет два документа"""
newRootNode = xmlNewDoc.documentElement
newBodyNode = xpath.Evaluate('child::body',newRootNode)[0]
newImportBodyNode = self.doc.importNode(newBodyNode, True)
# Перед объединение области с документом
# удаляем комментарии
self.removeComment(newImportBodyNode)
self.joinBody(self.body, newImportBodyNode)
# расставляем BR
self.insertBRtoBody(self.body)
def getQuoteField(self, xmlField):
"""Выдает текст из поля"""
xmlQuotes = xpath.Evaluate('child::quote',xmlField)
br = ""
if xmlField.hasAttribute("type") and\
xmlField.getAttribute("type") == "br":
br = "\n"
if xmlQuotes:
field = xmlQuotes[0]
if field.firstChild:
return field.firstChild.nodeValue + br
return "" + br
def getFieldsArea(self, xmlArea):
"""Выдает потомков XML области"""
xmlFields = []
childNodes = xmlArea.childNodes
for node in childNodes:
if node.nodeType == node.ELEMENT_NODE:
if node.tagName == "area" or node.tagName == "field":
xmlFields.append(node)
return xmlFields
def getTypeField(self, xmlField):
"""Выдает тип поля"""
if xmlField.hasAttribute("type"):
return xmlField.getAttribute("type")
else:
return False
def getNameField(self, xmlField):
"""Выдает имя поля"""
xmlNameFields = xpath.Evaluate('child::name', xmlField)
if xmlNameFields and xmlNameFields[0].firstChild:
return xmlNameFields[0].firstChild.nodeValue
else:
return False
def getNameArea(self, xmlArea):
"""Выдает имя области"""
xmlNameAreas = xpath.Evaluate('child::caption/name', xmlArea)
if xmlNameAreas and xmlNameAreas[0].firstChild:
return xmlNameAreas[0].firstChild.nodeValue
else:
return False
def xmlToText(self, xmlAreas, text):
"""Преобразует список XML областей в текст"""
def getQuotesArea(xmlArea):
quotes = []
xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea)
for node in xmlQuotes:
if node.firstChild:
quotes.append(node.firstChild.nodeValue)
if len(quotes) == 0:
quotes.append("")
quotes.append("")
elif len(quotes) == 1:
quotes.append("")
return quotes
for i in xmlAreas:
if i.tagName == "area":
quotesI = getQuotesArea(i)
startAreaI = quotesI[0]
endAreaI = quotesI[1]
text.append(startAreaI)
xmlFieldsI = self.getFieldsArea(i)
for f in xmlFieldsI:
if f.tagName == "area":
quotesF = getQuotesArea(f)
startAreaF = quotesF[0]
endAreaF = quotesF[1]
text.append(startAreaF)
xmlFieldsF = self.getFieldsArea(f)
self.xmlToText(xmlFieldsF, text)
text.append(endAreaF)
else:
fieldF = self.getQuoteField(f)
text.append(fieldF)
text.append(endAreaI)
else:
fieldI = self.getQuoteField(i)
text.append(fieldI)
def getActionField(self, xmlField):
"""Выдает свойство action XML поля"""
xmlActions = xpath.Evaluate('child::action',xmlField)
if xmlActions and xmlActions[0].firstChild:
return xmlActions[0].firstChild.nodeValue
else:
return False
def getFieldValues(self, xmlField):
"""Выдает значения XML поля в виде массива"""
vals = []
xmlValues = xpath.Evaluate('child::value',xmlField)
if xmlValues:
for node in xmlValues:
if node.firstChild:
vals.append(node.firstChild.nodeValue)
return vals
def getActionArea(self, xmlArea):
"""Выдает свойство action XML области"""
xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
if xmlActions and xmlActions[0].firstChild:
return xmlActions[0].firstChild.nodeValue
else:
return False
def delActionNodeArea(self, xmlArea):
"""Удаляет свойство action XML области"""
xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
if xmlActions and xmlActions[0].firstChild:
parentNode = xmlActions[0].parentNode
parentNode.removeChild(xmlActions[0])
return True
else:
return False
def delActionNodeField(self, xmlField):
"""Удаляет свойство action XML поля"""
xmlActions = xpath.Evaluate('child::action',xmlField)
if xmlActions and xmlActions[0].firstChild:
parentNode = xmlActions[0].parentNode
parentNode.removeChild(xmlActions[0])
return True
else:
return False
# Создает распределенные списки
def postParserListSeplist(self, xmlArea):
"""Создает распределенные списки из элементов области"""
# Потомки
childNodes = self.getFieldsArea(xmlArea)
# содержит списки нод полей с одинаковыми именами в одной области
fieldsSeplist = {}
for node in childNodes:
if node.tagName == "area":
self.postParserListSeplist(node)
else:
fieldName = False
xmlFieldNameNodes = xpath.Evaluate('child::name',node)
if xmlFieldNameNodes and xmlFieldNameNodes[0].firstChild:
fieldName = xmlFieldNameNodes[0].firstChild.nodeValue
if fieldName:
if fieldsSeplist.has_key(fieldName):
fieldsSeplist[fieldName].append(node)
else:
fieldsSeplist[fieldName] = []
fieldsSeplist[fieldName].append(node)
for listNodes in fieldsSeplist.values():
if len(listNodes) > 1:
for node in listNodes:
node.setAttribute("type", "seplist")
def insertBRtoBody(self, xmlArea):
"""Добавляет необходимые переводы строк
"""
# Потомки
childNodes = self.getFieldsArea(xmlArea)
# нода BR
fieldXMLBr = self.createField("br",[],"",[],False, False)
# разделитель поля
fieldSplit = False
# Предыдущая нода
lastNode = False
# Cледующая нода
nextNode = False
lenChildNodes = len(childNodes)
for i in range(lenChildNodes):
node = childNodes[i]
lastTmpNode = node
# Нода area
if node.tagName == "area":
if self.getActionArea(node) == "append" or\
self.getActionArea(node) == "join":
self.delActionNodeArea(node)
if lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "br" or\
lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "comment":
indNext = i + 1
if indNext == lenChildNodes:
xmlArea.appendChild(fieldXMLBr.cloneNode(True))
else:
nextNode = childNodes[indNext]
lastTmpNode = xmlArea.insertBefore(\
fieldXMLBr.cloneNode(True),
nextNode)
else:
xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
node)
self.insertBRtoBody(node)
# Нода field
else:
if self.getActionField(node) == "append" or\
self.getActionField(node) == "join":
self.delActionNodeField(node)
if lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "br" or\
lastNode and lastNode.hasAttribute("type") and\
lastNode.getAttribute("type") == "comment":
indNext = i + 1
if indNext == lenChildNodes:
xmlArea.appendChild(fieldXMLBr.cloneNode(True))
else:
nextNode = childNodes[indNext]
lastTmpNode = xmlArea.insertBefore(\
fieldXMLBr.cloneNode(True),
nextNode)
else:
xmlArea.insertBefore(fieldXMLBr.cloneNode(True),
node)
lastNode = lastTmpNode
def postParserList(self):
"""Находит подходящие XML области и делаем из них поля-массивы"""
xmlAreas = xpath.Evaluate('descendant::area', self.body)
for xmlArea in xmlAreas:
flagListXml = True
fieldValues = []
xmlFields = xpath.Evaluate('child::field',xmlArea)
if not xmlFields:
flagListXml = False
lenXmlFields = len(xmlFields)
lenBrArea = 0
for xmlField in xmlFields:
xmlNames = xpath.Evaluate('child::name',xmlField)
xmlVals = xpath.Evaluate('child::value',xmlField)
if xmlField.hasAttribute("type") and\
xmlField.getAttribute("type") == "br":
lenBrArea += 1
continue
if not xmlNames and not xmlVals:
flagListXml = False
break
if xmlNames and xmlNames[0].firstChild and\
xmlNames[0].firstChild.nodeValue:
flagListXml = False
break
if not (xmlVals and xmlVals[0].firstChild and\
xmlVals[0].firstChild.nodeValue):
flagListXml = False
break
else:
fieldValues.append(xmlVals[0].firstChild.nodeValue)
if lenXmlFields == lenBrArea:
flagListXml = False
if flagListXml:
nameNode = xpath.Evaluate('child::caption/name',xmlArea)[0]
fieldName = ""
if nameNode.firstChild:
fieldName = nameNode.firstChild.nodeValue
listArea = []
self.xmlToText([xmlArea],listArea)
fieldQuote = "".join(listArea)
fieldXMLBr = False
if fieldQuote and fieldQuote[-1] == "\n":
fieldQuote = fieldQuote[:-1]
fieldXMLBr = self.createField("br",[],"",[],False, False)
fieldXML = self.createField("list",
[fieldQuote],
fieldName, fieldValues,
False, False)
areaAction = self.getActionArea(xmlArea)
if areaAction:
self.setActionField(fieldXML, areaAction)
parentNode = xmlArea.parentNode
parentNode.insertBefore(fieldXML,xmlArea)
if fieldXMLBr:
parentNode.insertBefore(fieldXMLBr,xmlArea)
parentNode.removeChild(xmlArea)
class blocText:
"""Разбиваем текст на блоки"""
def splitTxtToBloc(self, text ,openTxtBloc,closeTxtBloc,
commentTxtBloc, sepField):
"""Делит текст на блоки (без заголовков)
openTxtBloc - регулярное выражение для начала блока
closeTxtBloc - регулярное выражение для конца блока
commentTxtBloc - регулярное выражение - комментарий
возвращает блоки текста
"""
blocs = []
level = 0
# Нахождение нескольких блоков в строке
# разделители линий, разделителями могут быть ("","\n")
sepsLines = []
# линии
txtLines = []
# Исходные строки
txtLinesSrc = text.splitlines()
for line in txtLinesSrc:
lineBR = ""
lineTmpA = line
closeBl = False
txtLinesTmp = []
commentSpl = commentTxtBloc.split(line)
flagCommentLine = False
if commentSpl[0].strip():
closeBl = True
if len(commentSpl) > 1:
commentBl = commentTxtBloc.search(line)
textLine =commentSpl[0]
commentLine = line[commentBl.start(0):]
lineTmpA = textLine
flagCommentLine = True
while (closeBl):
closeBl = sepField.search(lineTmpA)
if closeBl:
lineTmpB = lineTmpA[closeBl.end(0):]
txtLinesTmp.append(lineTmpA[:closeBl.end(0)])
lineTmpA = lineTmpB
if lineTmpA.strip():
txtLinesTmp.append(lineTmpA)
# Если есть значение и комментарий в строке
if flagCommentLine:
for l in txtLinesTmp:
txtLines.append(l)
sepsLines.append("")
if not txtLinesTmp:
txtLines.append(textLine)
sepsLines.append("")
txtLines.append(commentLine)
sepsLines.append("\n")
# Если есть несколько блоков в строке
elif len(txtLinesTmp)>1 and txtLinesTmp[1].strip():
lenTmpLines = len(txtLinesTmp)
for l in range(lenTmpLines):
txtLines.append(txtLinesTmp[l])
if l == lenTmpLines-1:
sepsLines.append("\n")
else:
sepsLines.append("")
# Cтрока не преобразована
else:
txtLines.append(line)
sepsLines.append("\n")
# разбивание на блоки
z = 0
bl = ""
for i in txtLines:
if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(i):
level += len(openTxtBloc.split(i)) - 1
if commentTxtBloc.split(i)[0].strip() and closeTxtBloc.search(i):
level -= len(closeTxtBloc.split(i)) - 1
bl += i + sepsLines[z]
if level == 0:
if bl:
blocs.append(bl)
bl = ""
z += 1
# cоздание блоков с элементами не входящими в блоки
realBlocs = []
z = 0
bl = ""
for i in blocs:
txtLines = i.splitlines()
if len(txtLines) > 0:
line = txtLines[0]
else:
line = i
if commentTxtBloc.split(i)[0].strip() and openTxtBloc.search(line):
if bl:
realBlocs.append(bl)
bl = ""
realBlocs.append(i)
else:
bl += i
z += 1
if bl:
realBlocs.append(bl)
bl = ""
if level == 0:
if text and text[-1] != "\n":
tmpBlocs = realBlocs.pop()
tmpBlocs = tmpBlocs[:-1]
realBlocs.append(tmpBlocs)
return realBlocs
else:
return []
def findArea(self, text, reTextHeader, reTextArea, numGroupArea=0):
""" Делит текст на области (с заголовками)
reTextHeader - регулярное выражение для заголовка области
reTextArea - регулярное выражение для всей области
numGroupArea - номер групы результата поиска по регулярному выражению
по всей области
возвращает два списка: первый - заголовки, второй - тела областей без
заголоков
"""
# Заголовки областей
headersArea = []
# Тексты областей без заголовков
textBodyArea = []
r = reTextArea.search(text)
if not r:
headersArea.append("")
textBodyArea.append(text)
return (headersArea, textBodyArea)
txtWr = text
while r:
textArea = r.group(numGroupArea)
txtSpl = txtWr.split(textArea)
area = txtSpl[0]
txtWr = txtSpl[1]
if area:
headersArea.append("")
textBodyArea.append(area)
res = reTextHeader.search(textArea)
header = textArea[:res.end()]
body = textArea[res.end():]
headersArea.append(header)
textBodyArea.append(body)
if txtWr:
r = reTextArea.search(txtWr)
else:
r = False
if txtWr:
headersArea.append("")
textBodyArea.append(txtWr)
return (headersArea, textBodyArea)
def findBloc(self, text, captionTxtBloc, bodyTxtBloc):
""" Делит текст на блоки (с заголовками)
captionTxtBloc - регулярное выражение для заголовка блока
bodyTxtBloc - регулярное выражение для тела блока
возвращает два списка: первый - заголовки, второй - тела блоков
"""
# Заголовки блоков
headersTxt = []
# Тексты блоков
blocsTxt = []
r = captionTxtBloc.search(text)
if r:
headersTxt.append(r.group(0))
txtSpl = text.split(r.group(0))
blocTxt = txtSpl[0]
txtWr = txtSpl[1]
rb = bodyTxtBloc.search(blocTxt)
if not blocTxt:
blocsTxt.append(blocTxt)
if rb:
blocsTxt.append(rb.group(0))
while (r):
r = captionTxtBloc.search(txtWr)
if r:
headersTxt.append(r.group(0))
txtSpl = txtWr.split(r.group(0))
blocTxt = txtSpl[0]
txtWr = txtSpl[1]
rb = bodyTxtBloc.search(blocTxt)
if rb:
blocsTxt.append(rb.group(0))
else:
blocsTxt.append(txtWr)
if headersTxt and blocsTxt:
if len(headersTxt)>len(blocsTxt):
blocsTxt.insert(0,"")
elif len(headersTxt)<len(blocsTxt):
headersTxt.insert(0,"")
if len(headersTxt)!=len(blocsTxt):
return False
return (headersTxt, blocsTxt)
else:
return False
class _file(_error):
"""Класс для работы с файлами
"""
def __init__(self):
# Имя файла конфигурационного файла
self.nameFileConfig = ""
# Содержимое конфигурационного файла
self.textConfig = ""
# Имя файла шаблона
self.nameFileTemplate = ""
# Содержимое шаблона
self.textTemplate = ""
# Дескриптор файла шаблона
self.F_TEMPL = False
# Дескриптор файла конфигурационного файла
self.F_CONF = False
def saveConfFile(self):
"""Записать конфигурацию"""
if self.F_CONF:
self.F_CONF.truncate(0)
self.F_CONF.seek(0)
if not self.textConfig:
self.textConfig = self.textTemplate
try:
self.F_CONF.write(self.textConfig)
except:
self.setError(_("not open file:" ) + self.nameFileConfig)
return False
self.F_CONF.flush()
return True
def openTemplFile(self, nameFileTemplate):
"""Открыть файл шаблона"""
F_TEMPL = False
try:
F_TEMPL = open(nameFileTemplate, "r")
except:
self.setError(_("not open file:" ) + nameFileTemplate)
return False
return F_TEMPL
def closeTemplFile(self):
if self.F_TEMPL:
self.F_TEMPL.close()
self.F_TEMPL = False
def __closeOldFile(self):
if self.F_CONF:
self.F_CONF.close()
self.F_CONF = False
def __openConfFile(self, nameFileConfig):
"""Отктрыть конфигурационный файл"""
F_CONF = False
try:
if os.path.islink(nameFileConfig):
# если ссылка то удаляем её
os.unlink(nameFileConfig)
F_CONF = open (nameFileConfig, "r+")
except:
try:
F_CONF = open(nameFileConfig, "w+")
except:
self.setError(_("not open file:" ) + nameFileConfig)
return False
return F_CONF
def openFiles(self, nameFileTemplate, nameFileConfig):
"""Открывает шаблон и конфигурационный файл"""
self.textConfig = ""
self.textTemplate = ""
self.closeFiles()
self.F_TEMPL = False
self.F_CONF = False
self.nameFileConfig = os.path.abspath(nameFileConfig)
self.nameFileTemplate = os.path.abspath(nameFileTemplate)
self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
self.F_CONF = self.__openConfFile(self.nameFileConfig)
if self.F_TEMPL and self.F_CONF:
self.textTemplate = self.F_TEMPL.read()
self.textConfig = self.F_CONF.read()
def __del__(self):
self.closeFiles()
def closeFiles(self):
"""Закрытие файлов"""
self.closeTemplFile()
self.__closeOldFile()
class utfBin:
"""Класс для преобразования в utf-8
преобразование бинарного или смеси бинарного и utf-8 кода в utf-8 и
обратное преобразование
методы класса encode и decode
"""
def _retUTF(self, char):
byte = ord(char)
if byte<=127:
return ('_ch_',1)
elif byte<=191:
return ('_nb_',1)
elif byte<=223:
return ('_fb_',2)
elif byte<=239:
return ('_fb_',3)
elif byte<=247:
return ('_fb_',4)
else:
return ('_er_',1)
def _sumbUtf(self, symbols, lenTail):
if not symbols:
return (False,0)
lenSymb = len(symbols)
if lenSymb >= 4:
l = 4
elif lenSymb >= 3:
l = 3
elif lenSymb >= 2:
l = 2
else:
if symbols[0] == '_ch_':
return (True,1)
else:
return (False,1)
result = False
for i in range(l):
if i == 0 and symbols[i] != '_fb_':
break
elif i > 0 and symbols[i] != '_nb_':
break
if lenTail>1 and lenTail != i:
return (False,1)
if i > 0:
result = True
return (result, i)
def _intToChar(self, x):
he = hex(x)[2:]
exec("ret = '\\x%s'" %he)
return ret
def _hexToChar(self, he):
exec("ret = '\\x%s'" %he)
return ret
def encode(self, text):
"""Кодирует смешанный формат в UTF-8"""
ind = 0
l = 0
utf = []
lenUtf = []
indErr = []
i = 0
for ch in text:
r, l = self._retUTF(ch)
utf.append(r)
lenUtf.append(l)
i+=1
while 1:
if utf[ind] == '_fb_':
res, l = self._sumbUtf(utf[ind:],lenUtf[ind])
if res is False:
indErr.append(ind)
if l>0:
ind +=l
if ind >= len(utf):
break
else:
if utf[ind] != '_ch_':
indErr.append(ind)
ind +=1
if ind >= len(utf):
break
if indErr:
lenIndErr = len(indErr)
block = []
blocks = []
if lenIndErr > 1:
i = 1
while 1:
if i == 1:
block.append(indErr[i-1])
if indErr[i] - indErr[i-1] == 1:
block.append(indErr[i])
else:
if block:
blocks.append(block)
block = []
block.append(indErr[i])
i +=1
if i >= lenIndErr:
break
else:
block.append(indErr[0])
if block:
blocks.append(block)
listErr = []
for block in blocks:
string = ""
for elem in block:
string += hex(ord(text[elem]))[-2:]
listErr.append((block[0],"__hex__?%s?__hex__" %string,elem))
textOut = text
deltaInd = 0
for erEl in listErr:
startInd = erEl[0] + deltaInd
endInd = erEl[2] + 1 + deltaInd
textOut = textOut[:startInd] + erEl[1] + textOut[endInd:]
deltaInd += len(erEl[1])-(erEl[2]-erEl[0]+1)
#if i == 1:
#break
#i += 1
return textOut
def decode(self, text):
"""Декодирует UTF-8 в смешанный формат"""
varStart = "__hex__\?"
varEnd = "\?__hex__"
# -1 Это экранирование '?' которое тоже считается
deltVarStart = len(varStart)-1
deltVarEnd = len(varEnd)-1
reVar = re.compile(("%s[a-f0-9]+%s")%(varStart,varEnd),re.M)
resS = reVar.search(text)
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 += self._hexToChar(hexCode)
hexCode = ""
i = 0
else:
hexCode += ch
i += 1
textTemplateTmp = textTemplateTmp.replace(mark, stringInsert)
resS = reVar.search(textTemplateTmp)
return textTemplateTmp
class templateFormat:
"""Методы получения классов и объектов форматов шаблонов"""
# Импортированные классы поддерживаемых форматов шаблонов
importFormats = {}
def getClassObj(self, nameClassTemplate):
"""Создает класс шаблона по имени"""
if nameClassTemplate in self.importFormats:
classFormat = self.importFormats[nameClassTemplate]
else:
try:
classFormat = getattr(__import__("format.%s"%nameClassTemplate,
globals(), locals(),
[nameClassTemplate]),
nameClassTemplate)
except (ImportError, AttributeError):
#Создаем объект из self.newObjProt с помощью
# метаклассов
if nameClassTemplate in self.newObjProt:
# Прототип класса
nameProt = self.newObjProt[nameClassTemplate]
if nameProt in self.importFormats:
classProt = self.importFormats[nameProt]
else:
try:
classProt = getattr(__import__("format.%s"%nameProt,
globals(), locals(),
[nameProt]),
nameProt)
except (ImportError, AttributeError):
return False
self.importFormats[nameProt] = classProt
classFormat = self.createNewClass(nameClassTemplate,
(classProt,))
else:
return False
self.importFormats[nameClassTemplate] = classFormat
return classFormat
def getFormatObj(self, formatTemplate, textTemplate):
"""Создание объекта формата шаблона.
Объект создается на основании формата шаблона и текста шаблона"""
classFormat = self.getClassObj(formatTemplate)
if classFormat:
return classFormat(textTemplate)
else:
return False
class _shareTemplate:
"""Общие аттрибуты для классов шаблонов"""
# Метка начала переменной
varStart = "#-"
# Метка конца переменной
varEnd = "-#"
_deltVarStart = len(varStart)
_deltVarEnd = len(varEnd)
def getDataUser(self, groupsInfo=False):
"""Получить информацию о пользователе"""
userName = self.objVar.Get("ur_login")
if not userName:
userName = "root"
import pwd
try:
pwdObj = pwd.getpwnam(userName)
uid = pwdObj.pw_uid
gid = pwdObj.pw_gid
homeDir = pwdObj.pw_dir
except:
cl_overriding.printERROR(_("Can not found user %s")%str(userName))
cl_overriding.exit(1)
if groupsInfo:
import grp
try:
groupName = grp.getgrgid(gid).gr_name
except:
cl_overriding.printERROR(\
_("Can not found group id %s")%str(gid))
cl_overriding.exit(1)
groupsNames = map(lambda x: x.gr_name,\
filter(lambda x: userName in x.gr_mem, grp.getgrall()))
groupsNames = [groupName] + groupsNames
return uid, gid, homeDir, groupsNames
return uid, gid, homeDir
class templateFunction(_error, _shareTemplate, _shareTermsFunction):
"""Класс для функций шаблонов"""
# Словарь установленных программ {"имя программы":[версии]}
installProg = {}
# Cписок просканированных категорий установленных программ
installCategory = []
# Флаг сканирования всех установленных программ
flagAllPkgScan = False
# Список названий функций шаблона
namesTemplateFunction = []
# Словарь {название функции шаблона: функция шаблона, ...}
templateFunction = {}
# Регулярное выражение для сложения
sNum = re.compile("\-[^\-\+]+|[^\-\+]+")
# Регулярное выражение для умножениея и деления
sMD = re.compile("[^\-\+\*\/]+")
# директория установленных программ
basePkgDir = "/var/db/pkg"
# стек глобальных переменных
stackGlobalVars = []
# регулярное выражение для поиска версии
reFindVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*")
# Имя обрабатываемого шаблона
nameTemplate = ""
# Текст функции шаблона
functText = ""
def __init__(self, objVar):
# Если не определен словарь функций шаблона
if not self.templateFunction:
# префикс функций шаблона
pref = "func"
# cписок [(название функции, функция), ...]
dictFunc = filter(lambda x: x[0].startswith(pref) and\
hasattr(x[1],"__call__"),
self.__class__.__dict__.items())
# удаляем у названия функции префикс и переводим остаток названия
# в нижний регистр
dictFunc = map(lambda x: (x[0][len(pref):].lower(), x[1]), dictFunc)
# Формируем словарь функций шаблона
self.templateFunction.update(dictFunc)
# Формируем список функций шаблона
for nameFunction in self.templateFunction.keys():
self.namesTemplateFunction.append(nameFunction)
# Объект хранения переменных
self.objVar = objVar
# Директория другой системы
self._chrootDir = self.objVar.Get("cl_chroot_path")
if self._chrootDir != '/':
# Изменение директории к базе пакетов
self.basePkgDir = pathJoin(self._chrootDir, self.basePkgDir)
# Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
self._baseDir=pathJoin(self._chrootDir,self.objVar.Get("cl_root_path"))
self._reFunc = re.compile(("%s%s%s")\
%(self.varStart,self._reFunctionText,self.varEnd),re.M)
# Аттрибуты для функции шаблона ini()
# Первоначальный словарь переменных для ini()
self.prevDictIni = {}
# Текущий словарь переменных для ini()
self.currDictIni = {}
# Время модификации конфигурационного файла для ini()
self.timeIni = -1
self.uid, self.gid, self.homeDir, self.groups =\
self.getDataUser(groupsInfo=True)
# Домашняя директория, плюс базовая директория
self.homeDir = pathJoin(self._baseDir, self.homeDir)
# Путь к конфигурационному файлу для ini()
self.pathConfigIni = os.path.join(self.homeDir, ".calculate")
self.fileConfigIni = os.path.join(self.pathConfigIni,"ini.env")
# Словарь времен модификации env файлов
self.timeConfigsIni = {}
# Словарь хранения переменых полученных функцией env() из env файлов
self.valuesVarEnv = {}
# Словарь хранения опций для функции info()
self.optionsInfo = {}
# файл параметров сервисов
envFile = self.objVar.Get("cl_env_server_path")
# объект конвертирования из старого remote env файла
self.convObj = False
if os.access(envFile, os.R_OK):
self.convObj = False
elif os.access("/var/calculate/remote/calculate.env", os.R_OK):
from convertenv import convertEnv
self.convObj = convertEnv()
def equalTerm(self, term, localVars):
"""Метод для вычисления выражения"""
terms = self.sNum.findall(term)
if terms:
strNumers = []
for n in terms:
strNum = n.strip()
if "*" in strNum or "/" in strNum:
strNum = self.multAndDiv(strNum,localVars)
try:
num = int(strNum)
except:
minus = False
if strNum[:1] == "-":
minus = True
strNum = strNum[1:]
if localVars.has_key(strNum):
try:
num = int(localVars[strNum])
except:
self.printErrTemplate()
cl_overriding.printERROR(\
_("error var %s not int")%str(strNum))
cl_overriding.exit(1)
elif self.objVar.exists(strNum):
try:
num = int(self.objVar.Get(strNum))
except:
self.printErrTemplate()
cl_overriding.printERROR(\
_("error var %s not int")%str(strNum))
cl_overriding.exit(1)
else:
self.printErrTemplate()
cl_overriding.printERROR(\
_("error local var %s not defined")%str(strNum))
cl_overriding.exit(1)
if minus:
num = -num
strNumers.append(num)
return sum(strNumers)
self.printErrTemplate()
cl_overriding.printERROR(_("error template term %s, incorrect data")\
%str(term))
cl_overriding.exit(1)
def multAndDiv(self, term, localVars):
"""Метод для умножения и деления"""
termTmp = term
varsLocal = self.sMD.findall(term)
for var in varsLocal:
flagVarTxt = True
try:
int(var)
except:
flagVarTxt = False
if flagVarTxt:
continue
varReplace = str(self.equalTerm(var, localVars))
termTmp = termTmp.replace(var,varReplace)
ret = eval(termTmp)
return ret
def funcSum(self, funArgv, resS, localVars, textTemplateTmp):
"""Функция шаблона, вычисляет функцию sum()"""
terms = funArgv.replace(" ","").split(",")
# Название локальной переменной
nameLocVar = terms[0]
if not localVars.has_key(nameLocVar):
localVars[nameLocVar] = 0
if len(terms) == 2:
if terms[1].strip():
localVars[nameLocVar] = self.equalTerm(terms[1], localVars)
replace = str(localVars[nameLocVar])
else:
replace = ""
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
elif len(terms) == 3:
if terms[1].strip():
replaceInt = self.equalTerm(terms[1], localVars)
replace = str(replaceInt)
else:
replace = ""
localVars[nameLocVar] = self.equalTerm(terms[2], localVars)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
else:
self.printErrTemplate()
cl_overriding.exit(1)
return textTemplateTmp
def funcExists(self, funArgv, resS, localVars, textTemplateTmp):
"""Функция шаблона exists(),
проверяет существование файла, если существует выдает '1'
"""
terms = map(lambda x: x.strip(), funArgv.split(","))
if len(terms) !=1:
self.printErrTemplate()
cl_overriding.exit(1)
fileName = terms[0]
if fileName[0] == "~":
# Получаем директорию пользователя
fileName = os.path.join(self.homeDir,
fileName.partition("/")[2],"")[:-1]
elif fileName[0] != "/":
self.printErrTemplate()
cl_overriding.printERROR(_("wrong path '%s'")%fileName)
cl_overriding.exit(1)
else:
fileName = pathJoin(self._baseDir, fileName)
replace = ""
if os.path.exists(fileName):
replace = "1"
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcLoad(self, funArgv, resS, localVars, textTemplateTmp):
"""Функция шаблона load(),
если файл существует читает из файла локальную переменную
если один параметр - выводит значение локальной переменной
"""
terms = funArgv.split(",")
if not terms or not terms[0].strip() or\
(len(terms)==2 and not terms[1].strip()) or\
len(terms)>2:
self.printErrTemplate()
cl_overriding.exit(1)
if len(terms) == 2:
if not terms[0] in ["ver","num","char","key"]:
self.printErrTemplate()
cl_overriding.printERROR(\
_("first argument function is not 'ver' or 'num' or 'char'"))
cl_overriding.exit(1)
if len(terms) == 1:
fileName = terms[0].strip()
# Если домашняя директория
if fileName[0] == "~":
# Получаем директорию пользователя
fileName = os.path.join(self.homeDir,
fileName.partition("/")[2],"")[:-1]
elif fileName[0] != "/":
self.printErrTemplate()
cl_overriding.printERROR(_("wrong path '%s'")%fileName)
cl_overriding.exit(1)
else:
fileName = pathJoin(self._baseDir, fileName)
else:
fileName = terms[1].strip()
# Если домашняя директория
if fileName[0] == "~":
# Получаем директорию пользователя
fileName = os.path.join(self.homeDir,
fileName.partition("/")[2],"")[:-1]
elif fileName[0] != "/":
self.printErrTemplate()
cl_overriding.printERROR(_("wrong path '%s'")%fileName)
cl_overriding.exit(1)
else:
fileName = pathJoin(self._baseDir,fileName)
replace = ""
if os.path.exists(fileName):
FD = open(fileName)
replace = FD.read().strip()
FD.close
if not replace and len(terms) == 2 and terms[0] in ["ver","num"]:
replace = "0"
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def sharePkg(self, pkgs):
"""Получение имен и номеров версий программ"""
pkgs.sort()
installProg = {}
for pkg in pkgs:
findVer = self.reFindVer.search(pkg)
if findVer:
version = findVer.group()
name = pkg.split(version)[0][:-1]
if name in installProg:
installProg[name].append(version)
else:
installProg[name] = [version]
return installProg
def getInstallPkgGentoo(self):
"""Выдает словарь инсталлированных программ и номеров версий"""
pkgs = []
def getFilesDir(pkgs, dirname, names):
for nameFile in names:
absNameFile = os.path.join(dirname,nameFile)
if os.path.isdir(absNameFile):
tail = absNameFile.split(self.basePkgDir)
if len(tail)==2:
tail = tail[1].split('/')
if len(tail)==3 and tail[1]!='virtual':
pkgs.append(tail[2])
return True
os.path.walk(self.basePkgDir,getFilesDir, pkgs)
return self.sharePkg(pkgs)
def pkg(self, nameProg, installProg):
"""Выдает установленные версии по имени программы"""
if nameProg in installProg:
return installProg[nameProg][-1]
else:
return ""
def funcPkg(self, funArgv, resS, localVars, textTemplateTmp):
"""Функция шаблона pkg(), выдает номер версии программы"""
# Название программы
nameProg = funArgv.replace(" ","")
# Замена функции в тексте шаблона
replace = ""
if "/" in nameProg:
if nameProg in self.installProg:
replace = self.pkg(nameProg, self.installProg)
else:
category, spl, nProg = nameProg.partition("/")
if not category in self.installCategory:
self.installCategory.append(category)
pathCategory = os.path.join(self.basePkgDir, category)
if os.path.exists(pathCategory):
pkgs = os.listdir(pathCategory)
pkgs = map(lambda x: os.path.join(category,x),
pkgs)
installProg = self.sharePkg(pkgs)
replace = self.pkg(nameProg, installProg)
self.installProg.update(installProg)
else:
if not self.flagAllPkgScan:
installProg = self.getInstallPkgGentoo()
self.installProg.update(installProg)
templateFunction.flagAllPkgScan = True
replace = self.pkg(nameProg, self.installProg)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcRnd(self, funArgv, resS, localVars, textTemplateTmp):
"""Функция шаблона rnd(), выдает строку случайных символов
первый аргумент:
'num' - числа,
'pas' - цифры и буквы
второй аргумент:
количество символов
"""
terms = funArgv.replace(" ","").split(",")
if not terms[0].strip() or\
(len(terms)==2 and not terms[1].strip()) or\
len(terms)!=2:
self.printErrTemplate()
cl_overriding.exit(1)
fArgvNames = ['num','pas']
if not terms[0] in fArgvNames:
self.printErrTemplate()
cl_overriding.printERROR(\
_("first argument function is not 'num' or 'pas'"))
cl_overriding.exit(1)
try:
lenStr = int(terms[1])
except:
self.printErrTemplate()
cl_overriding.printERROR(\
_("two argument function is not number"))
cl_overriding.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:
self.printErrTemplate()
cl_overriding.exit(1)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcCase(self, funArgv, resS, localVars, textTemplateTmp):
"""Функция шаблона case(), выдает переменную в определенном регистре
первый аргумент:
'upper' - верхний регистр,
'lower' - нижний регистр,
'capitalize' - первая буква в верхнем регистре
второй аргумент:
название переменной
"""
terms = funArgv.replace(" ","").split(",")
if not terms[0].strip() or\
(len(terms)==2 and not terms[1].strip()) or len(terms)!=2:
self.printErrTemplate()
cl_overriding.exit(1)
fArgvNames = ['upper','lower','capitalize']
if not terms[0] in fArgvNames:
self.printErrTemplate()
cl_overriding.printERROR(_("first argument function is not 'upper' \
or 'lower' or 'capitalize'"))
cl_overriding.exit(1)
try:
strValue = str(self.objVar.Get(terms[1]))
except:
cl_overriding.printERROR(_("error in template %s")\
%self.nameTemplate)
cl_overriding.printERROR(_("error var %s not found")%str(terms[1]))
cl_overriding.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
def funcPush(self, funArgv, resS, localVars, textTemplateTmp):
"""локальная функция записывает значение переменной
в стек глобальных переменных
"""
terms = funArgv.replace(" ","").split(",")
# Название локальной переменной
nameLocVar = terms[0]
flagFoundVar = False
if nameLocVar in localVars.keys():
flagFoundVar = True
value = localVars[nameLocVar]
else:
try:
value = self.objVar.Get(nameLocVar)
flagFoundVar = True
except:
pass
if flagFoundVar:
# Если переменная существует
if len(terms) == 1:
self.stackGlobalVars.append(str(value))
else:
self.printErrTemplate()
cl_overriding.printERROR(_("error var %s exists")\
%str(nameLocVar))
cl_overriding.exit(1)
else:
# Если переменная не существует
if len(terms) == 1:
self.printErrTemplate()
cl_overriding.printERROR(_("error var %s not exists")\
%str(nameLocVar))
cl_overriding.exit(1)
elif len(terms) == 2:
value = terms[1].strip()
self.stackGlobalVars.append(str(value))
localVars[nameLocVar] = value
else:
self.printErrTemplate()
cl_overriding.exit(1)
replace = ""
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcPop(self, funArgv, resS, localVars, textTemplateTmp):
"""локальная функция получает значение
из стека глобальных переменных и присваивает локальной переменной
"""
terms = funArgv.replace(" ","").split(",")
# Название локальной переменной
nameLocVar = terms[0]
if len(terms) == 1:
if self.stackGlobalVars:
localVars[nameLocVar] = self.stackGlobalVars.pop()
else:
self.printErrTemplate()
cl_overriding.printERROR(\
_("error, gloval variables stack is empty"))
cl_overriding.exit(1)
else:
self.printErrTemplate()
cl_overriding.exit(1)
replace = ""
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def loadVarsIni(self, iniFileName):
""" Читает файл fileName
создает и заполняет переменные на основе этого файла
Используеться совместно c funcIni
"""
localVarsIni = {}
# получить объект ini файла
config = iniParser(iniFileName)
# получаем все секции из конфигурационного файла
allsect = config.getAllSectionNames()
if not allsect:
if self.getError():
# Очистка ошибки
_error.error = []
return localVarsIni
# Заполняем переменные для funcIni
for sect in allsect:
sectVars = config.getAreaVars(sect)
for name in sectVars.keys():
nameVar = "%s.%s"%(sect,name)
valueVar = sectVars[name]
localVarsIni[nameVar] = valueVar
return localVarsIni
def getTimeFile(self, fileName):
# Получаем время модификации файла
nameEnvFile = os.path.split(fileName)[1]
if nameEnvFile in self.timeConfigsIni:
return self.timeConfigsIni[nameEnvFile]
return 0
def funcIni(self, funArgv, resS, localVars, textTemplateTmp):
"""локальная функция записывает и считывает значение переменной
из ini файла ~./calculate/ini.env
"""
# Создаем директорию
if not os.path.exists(self.pathConfigIni):
os.makedirs(self.pathConfigIni)
os.chown(self.pathConfigIni, self.uid, self.gid)
termsRaw = funArgv.split(",")
flagFirst = True
terms = []
for term in termsRaw:
if flagFirst:
terms.append(term.replace(" ",""))
flagFirst = False
else:
val = term.strip()
# Флаг (не найдены кавычки)
flagNotFoundQuote = True
for el in ('"',"'"):
if val.startswith(el) and val.endswith(el):
terms.append(val[1:-1])
flagNotFoundQuote = False
break
if flagNotFoundQuote:
terms.append(val)
# Название локальной переменной
nameLocVar = terms[0]
namesVar = nameLocVar.split(".")
if len(namesVar) == 1:
nameLocVar = "main.%s"%nameLocVar
elif len(namesVar)>2:
self.printErrTemplate()
cl_overriding.exit(1)
replace = ""
# Получаем время модификации конфигурационного файла
curTime = self.getTimeFile(self.fileConfigIni)
if len(terms) == 1:
if self.timeIni != curTime:
# читаем переменные из файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
self.currDictIni.update(self.prevDictIni)
self.timeIni = self.getTimeFile(self.fileConfigIni)
if nameLocVar in self.currDictIni.keys():
replace = self.currDictIni[nameLocVar]
elif len(terms) == 2:
if self.timeIni != curTime:
# читаем переменные из файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
self.currDictIni.update(self.prevDictIni)
self.timeIni = self.getTimeFile(self.fileConfigIni)
# Значение локальной переменной
valueLocVar = terms[1]
self.currDictIni[nameLocVar] = valueLocVar
else:
self.printErrTemplate()
cl_overriding.exit(1)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return (textTemplateTmp)
def funcReplace(self, funArgv, resS, localVars, textTemplateTmp):
"""локальная функция заменяет в значении переменной old на new
replace(old, new, name_var_template)
одинарные и двойные кавычки должны быть обязательно использованы
в первых двух аргументах old и new
"test\ntest" - преобразование строки (строка с переводом)
'test\ntest' - без преобразования (одна строка)
"""
def getStrArgv(terms):
"""Определяет в двойных или одинарных кавычках параметры
Результат [(тип, аргумент),...] [("double", arg1).]
"""
listArgv = []
for term in terms:
if term.startswith('"') and term.endswith('"'):
replTerms = [(r"\'", "'"), (r'\"', '"'), (r'\n', '\n'),
(r'\r', '\r'), (r'\t', '\t'), (r"\\", "\\")]
textArgv = term[1:-1]
for replTerm in replTerms:
textArgv = textArgv.replace(*replTerm)
listArgv.append(textArgv)
elif term.startswith("'") and term.endswith("'"):
listArgv.append(term[1:-1])
else:
self.printErrTemplate()
cl_overriding.exit(1)
return listArgv
terms = map(lambda x: x.strip(), funArgv.split(","))
if len(terms) != 3:
self.printErrTemplate()
cl_overriding.exit(1)
listArgv = getStrArgv(terms[:2])
old = listArgv[0]
new = listArgv[1]
nameVar = terms[2]
# Получаем значение переменной
if nameVar in localVars:
value = str(localVars[nameVar])
else:
try:
value = str(self.objVar.Get(nameVar))
except:
self.printErrTemplate()
cl_overriding.printERROR(_("not found template variable '%s'")\
%str(nameVar))
cl_overriding.exit(1)
replace = value.replace(old,new)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcEnv(self, funArgv, resS, localVars, textTemplateTmp):
"""Функция шаблона env(), выдает значение переменной из env файлов
"""
terms = funArgv.replace(" ","").split(",")
if len(terms) != 1:
self.printErrTemplate()
cl_overriding.exit(1)
nameVar = terms[0]
replace = ''
if nameVar in self.valuesVarEnv:
replace = self.valuesVarEnv[nameVar]
else:
# Получаем значение из env файлов
value = self.objVar.GetIniVar(nameVar)
if value is False:
self.printErrTemplate()
errMsg = self.getError()
if errMsg:
cl_overriding.printERROR(errMsg)
cl_overriding.exit(1)
self.valuesVarEnv[nameVar] = value
replace = value
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcServer(self, funArgv, resS, localVars, textTemplateTmp):
"""Функция шаблона info(), выдает значение опций сервиса
из /var/calculate/remote/calculate.env
"""
terms = funArgv.replace(" ","").split(",")
if len(terms)==0 or len(terms)>2:
self.printErrTemplate()
cl_overriding.exit(1)
nameLocalVar = ""
if len(terms)==2:
if not terms[1]:
self.printErrTemplate()
cl_overriding.exit(1)
nameLocalVar = terms[1]
textLine = terms[0]
vals = textLine.split(".")
if len(vals)!= 2:
self.printErrTemplate()
cl_overriding.exit(1)
if filter(lambda x: not x.strip(), vals):
self.printErrTemplate()
cl_overriding.exit(1)
service, option = vals
if not service or not option:
self.printErrTemplate()
cl_overriding.exit(1)
if not self.optionsInfo:
# файл /var/calculate/remote/server.env
envFile = self.objVar.Get("cl_env_server_path")
# получаем словарь всех информационных переменных
if self.convObj:
optInfo = self.convObj.convert()
else:
optInfo = self.objVar.GetRemoteInfo(envFile)
if optInfo is False:
self.printErrTemplate()
cl_overriding.exit(1)
if optInfo:
self.optionsInfo = optInfo
replace = ''
if service in self.optionsInfo and option in self.optionsInfo[service]:
value = self.optionsInfo[service][option]
if nameLocalVar:
localVars[nameLocalVar] = value
else:
replace = value
elif nameLocalVar:
localVars[nameLocalVar] = ""
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcGroups(self, funArgv, resS, localVars, textTemplateTmp):
"""Функция шаблона groups(),
проверяет нахождение пользователя в группах, если находится выдает '1'
"""
terms = map(lambda x: x.strip(), funArgv.split(","))
groupNames = set(terms)
userGroups = set(self.groups)
replace = ""
if groupNames & userGroups:
replace = "1"
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcBelong(self, funArgv, resS, localVars, textTemplateTmp):
"""Функция шаблона belong().
В случае установки переменной os_belongs_pkg=имя пакета, и совпадения
имени пакета в переменной и имени пакета в функции выдает "1" иначе ""
Если переменная os_belongs_pkg пуста выдает "1"
"""
terms = funArgv.replace(" ","").split(",")
if len(terms) != 1:
self.printErrTemplate()
cl_overriding.exit(1)
funcPkg = terms[0]
if not funcPkg:
funcPkg = os.path.split(os.path.dirname(self.nameTemplate))[1]
if not funcPkg:
cl_overriding.printERROR(_("incorrect template path"))
self.printErrTemplate()
cl_overriding.exit(1)
pkg = self.objVar.Get("cl_belong_pkg")
replace = ""
if pkg:
if pkg == funcPkg:
replace = "1"
else:
replace = "1"
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcList(self, funArgv, resS, localVars, textTemplateTmp):
"""Функция шаблона list().
Если первый аргумент является именем локальной или глобальной
переменной и значение переменной является списком, выдает
элемент списка по второму аргументу индексу.
Первый элемент имеет индекс 0
"""
terms = funArgv.replace(" ","").split(",")
# У функции должно быть два аргумента
if len(terms) != 2:
self.printErrTemplate()
cl_overriding.exit(1)
# Название локальной или глобальной переменной
nameLocVar = terms[0]
strIndex = terms[1]
try:
intIndex = int(strIndex)
except:
cl_overriding.printERROR(_("'%s' is not a number")%strIndex)
self.printErrTemplate()
cl_overriding.exit(1)
flagFoundVar = False
if nameLocVar in localVars.keys():
flagFoundVar = True
value = localVars[nameLocVar]
else:
try:
value = self.objVar.Get(nameLocVar)
flagFoundVar = True
except:
pass
if not flagFoundVar:
# Если переменная не существует
cl_overriding.printERROR(_("error var %s not exists")\
%str(nameLocVar))
self.printErrTemplate()
cl_overriding.exit(1)
if not type(value) in (list,tuple):
# Значение переменной не список или кортеж
cl_overriding.printERROR(_("value of %s is not a list or tuple")\
%str(nameLocVar))
self.printErrTemplate()
cl_overriding.exit(1)
try:
replace = str(value[intIndex])
except:
cl_overriding.printERROR(_("%s wrong")%strIndex)
self.printErrTemplate()
cl_overriding.exit(1)
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def funcDisk(self, funArgv, resS, localVars, textTemplateTmp):
"""Функция шаблона disk().
Первый аргумент ищется в значении переменной os_disk_install
(значение os_install_disk_mount - список точек монтирования при установке)
второй аргумент используется для поиска в переменной
os_disk_второй_аргумент (значение os_disk_второй_аргумент - список)
В os_install_disk_mount ищется первый аргумент, находим его индекс
результат - элемент cписка из os_disk_второй_аргумент с этим индексом
"""
terms = funArgv.replace(" ","").split(",")
# У функции должно быть два аргумента
if len(terms) != 2:
self.printErrTemplate()
cl_overriding.exit(1)
# Название глобальной переменной
mountPoint = terms[0]
lastElementVar = terms[1]
if not mountPoint or mountPoint[:1] !="/":
cl_overriding.printERROR(_("%s wrong")%lastElementVar)
self.printErrTemplate()
cl_overriding.exit(1)
nameVar = "os_install_disk_mount"
try:
valueVar = self.objVar.Get(nameVar)
except:
# Если переменная не существует
cl_overriding.printERROR(_("error var %s not exists")%nameVar)
self.printErrTemplate()
cl_overriding.exit(1)
nameElementVar = "os_disk_%s"%lastElementVar
try:
valueElementVar = self.objVar.Get(nameElementVar)
except:
# Если переменная не существует
cl_overriding.printERROR(_("%s wrong")%lastElementVar)
cl_overriding.printERROR(_("error var %s not exists")\
%nameElementVar)
self.printErrTemplate()
cl_overriding.exit(1)
if not type(valueVar) in (list,tuple):
# Значение переменной не список или кортеж
cl_overriding.printERROR(_("value of %s is not a list or tuple")\
%nameVar)
self.printErrTemplate()
cl_overriding.exit(1)
if not type(valueElementVar) in (list,tuple):
# Значение переменной не список или кортеж
cl_overriding.printERROR(_("value of %s is not a list or tuple")\
%nameElementVar)
self.printErrTemplate()
cl_overriding.exit(1)
if len(valueVar) != len(valueElementVar):
cl_overriding.printERROR(\
_("size %s is not equal to the size of %s")\
%(nameVar, nameElementVar))
self.printErrTemplate()
cl_overriding.exit(1)
index = None
for num, mPoint in enumerate(valueVar):
if mountPoint == mPoint:
index = num
break
if index is None:
for num, mPoint in enumerate(valueVar):
if "/" == mPoint:
index = num
break
if index is None:
cl_overriding.printERROR(_("in the value of the variable \
os_disk_install not found mount point '\' and '\%s'")%mountPoint)
self.printErrTemplate()
cl_overriding.exit(1)
replace = valueElementVar[index]
textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\
textTemplateTmp[resS.end():]
return textTemplateTmp
def printErrTemplate(self):
"""Печать ошибки при обработке функций шаблона"""
cl_overriding.printERROR(_("error in template %s")%self.nameTemplate)
cl_overriding.printERROR(_("error template term '%s'")\
%str(self.functText))
def applyFuncTemplate(self, textTemplate, nameTemplate):
"""Применяет функции к тексту шаблона"""
# Локальные переменные
localVars = {}
# Имя обрабатываемого шаблона
self.nameTemplate = nameTemplate
# Регулярное выражение для поиска функции в шаблоне
reFunc = self._reFunc
resS = reFunc.search(textTemplate)
textTemplateTmp = textTemplate
flagIniFunc = False
while resS:
mark = textTemplateTmp[resS.start():resS.end()]
self.functText = mark[self._deltVarStart:-self._deltVarEnd]
funcName, spl, funcEnd = self.functText.partition("(")
if funcName in self.namesTemplateFunction:
# аргументы функции - '(' аргументы ')'
funArgv = funcEnd.rpartition(")")[0]
# вызов функции шаблона
textTemplateTmp = self.templateFunction[funcName](self, funArgv,
resS, localVars,
textTemplateTmp)
resS = reFunc.search(textTemplateTmp)
if funcName == "ini":
flagIniFunc = True
else:
self.printErrTemplate()
cl_overriding.printERROR(\
_("can not found template function '%s'")\
%str(self.functText))
cl_overriding.exit(1)
if flagIniFunc:
# Очистка файла в случае его ошибочного чтения
if not self.prevDictIni and os.path.exists(self.fileConfigIni):
FD = open(self.fileConfigIni, "r+")
FD.truncate(0)
FD.seek(0)
FD.close()
# Если конф. файл модифицирован шаблоном
curTime = self.getTimeFile(self.fileConfigIni)
if curTime != self.timeIni:
# Считаем переменные из конф. файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
self.currDictIni.update(self.prevDictIni)
self.timeIni = curTime
# Если словари переменных не совпадают
if self.prevDictIni != self.currDictIni:
# Запишем переменные в конфигурационный файл
# Создание объекта парсера
config = iniParser(self.fileConfigIni)
# секции будущего конфигурационного файла
sects = list(set(map(lambda x: x.split(".")[0],\
self.currDictIni.keys())))
# запись переменных в файл
for sect in sects:
dictVar = {}
for varName in self.currDictIni.keys():
if varName.startswith("%s."%sect):
nameVar = varName.rpartition(".")[2]
valueVar = self.currDictIni[varName]
if valueVar:
dictVar[nameVar] = valueVar
if dictVar:
# Запись переменных в секцию
config.setVar(sect, dictVar)
# читаем переменные из файла
self.prevDictIni = self.loadVarsIni(self.fileConfigIni)
self.currDictIni.update(self.prevDictIni)
self.timeConfigsIni[self.fileConfigIni] = float(time.time())
self.timeIni = self.getTimeFile(self.fileConfigIni)
# Меняем владельца в случае необходимости
if os.path.exists(self.fileConfigIni):
uid, gid = getModeFile(self.fileConfigIni, "owner")
if self.uid!=uid or self.gid!=gid:
os.chown(self.fileConfigIni, self.uid, self.gid)
return textTemplateTmp
class template(_file, _terms, xmlShare, templateFormat, _shareTemplate):
"""Класс для работы с шаблонами
На вход 2 параметра: объект хранения переменных, имя сервиса - не
обязательный параметр
"""
# Название файла шаблона директории
templDirNameFile = ".calculate_directory"
def __init__(self, objVar, servDir=False, dirsFilter=[], filesFilter=[],
cltObj=True, cltFilter=True):
# Необрабатываемые директории
self.dirsFilter = dirsFilter
# Необрабатываемые файлы
self.filesFilter = filesFilter
_file.__init__(self)
# Словарь для создания объектов новых классов по образцу
self.newObjProt = {'proftpd':'apache'}
# Заголовок title
self.__titleHead = "--------------------------------------\
----------------------------------------"
self._titleBody = ""
self._titleList = (_("Modified"), _("Processed template files") + ":")
self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")%(self.varStart,
self.varEnd),re.M)
# Условия
self._reTermBloc = re.compile("#\?(?P<rTerm>[a-zA-Z0-9\-_]+)\
(?P<func>\((%s+|)\))?\
(?P<lTerm>[\>\<\=\!\&\|]+\
[\>\<\=\!\|\&\(\)%s]*)#\
\n*(?P<body>.+?)\n*#(?P=rTerm)#(?P<end>[ ,\t]*\n?)"\
%(self._reFunctionArgvText, self._reFunctionArgvInSquareBrackets),
re.M|re.S)
# Объект с переменными
self.objVar = objVar
# Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д
self._baseDir = pathJoin(self.objVar.Get("cl_chroot_path"),
self.objVar.Get("cl_root_path"))
# Последняя часть директории шаблона (имя сервиса: samba, mail)
self._servDir = servDir
if self._servDir:
if self._servDir[0] != "/":
self._servDir = "/" + self._servDir
if self._servDir[-1] != "/":
self._servDir += "/"
self._servDir = os.path.split(self._servDir)[0]
# Созданные директории
self.createdDirs = []
# Примененные файлы
self.filesApply = []
# номер обрабатываемого файла
self.numberProcessTempl = 0
# имя текущей программы
_nameProgram = self.objVar.Get("cl_name").capitalize()
# версия текущей программы
_versionProgram = self.objVar.Get("cl_ver")
# имя и версия текущей программы
self.programVersion = "%s %s"%(_nameProgram, _versionProgram)
# Словарь директорий с количеством файлов шаблонов
self.dictTemplates = {}
# Общее количество шаблонов
self.allTemplates = 0
# Объект функций шаблона
self.functObj = templateFunction(self.objVar)
# Метод применения функций к шаблонам
self.applyFuncTemplate = self.functObj.applyFuncTemplate
# Объект для определения типа файла шаблона
self.typeFileObj = typeFile()
self.uid, self.gid, self.homeDir = self.getDataUser()
# Домашняя директория, плюс базовая директория
self.homeDir = pathJoin(self._baseDir, self.homeDir)
# Глобальный словарь обработанных шаблонов файлов
# {путь к конф. файлу:[имена шаблонов] ...}
self.dictProcessedTemplates = {}
if cltObj is True:
# Объект templateClt
self.cltObj = templateClt(self.objVar)
elif cltObj:
# Объект templateClt
self.cltObj = cltObj
else:
# Объект templateClt
self.cltObj = False
# Фильтровать ли шаблоны clt по конфигурационным файлам обычных шаблонов
self.cltFilter = cltFilter
# Преобразование восьмеричного в целое (ввод строка, вывод число)
def __octToInt(self, strOct):
if strOct:
try:
exec("res =" + "0" + strOct)
except:
self.setError(_("Not valid oct value: ") + str(strOct))
return False
return res
else:
self.setError(_("Empty oct value"))
return False
def getTemplateType(self):
"""выдать тип шаблона (text, bin)"""
isBin = self.typeFileObj.isBinary(self.nameFileTemplate)
typeTemplate = "bin"
if isBin is True:
typeTemplate = "bin"
elif isBin is False:
typeTemplate = "text"
else:
self.setError(_("ERROR") + ": getTemplateType()")
self.setError(isBin)
return False
return typeTemplate
def createDir(self, dirName, mode=False, uid=False, gid=False):
"""Создает директорию"""
if os.access(dirName, os.F_OK):
return True
else:
dMode = False
prevDir, tmpSubdir = os.path.split(dirName)
createDirs = []
while not os.access(prevDir, os.F_OK) and prevDir:
createDirs.append(prevDir)
prevDir = os.path.split(prevDir)[0]
try:
dUid,dGid = getModeFile(prevDir,"owner")
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:
cl_overriding.printERROR(_("error in template %s")%nameTemplate)
cl_overriding.printERROR(e)
cl_overriding.exit(1)
textTemplateTmp = textTemplateTmp.replace(mark, varValue)
resS = self._reVar.search(textTemplateTmp)
return textTemplateTmp
def applyTermsTemplate(self,textTemplate,nameTemplate):
""" Применяет условия, к условным блокам текста
"""
def function(text):
"""Функция обработки функций в заголовке"""
return self.applyFuncTemplate(text, nameTemplate)
textTerm = ""
resS = self._reTermBloc.search(textTemplate)
textTemplateTmp = textTemplate
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)
return textTemplateTmp
def getNeedTemplate(self, fileTemplate):
"""Применяем правила к названию файла"""
dirP,fileP = os.path.split(fileTemplate)
if fileP:
spFile = fileP.split("?")
realFileName = spFile[0]
if len(spFile)>1:
flagTrue = False
for term in spFile[1:]:
if self._equalTerm(term, _("name template not valid: ")+\
fileTemplate):
flagTrue = True
break
if flagTrue:
return True
else:
return False
else:
return True
else:
self.setError(_("name template not valid: ")+ str(fileTemplate))
return False
def getTitle(self, comment, commentList):
"""Выдает заголовок шаблона ( версия и.т.д)"""
if comment:
commentFirst = comment
commentInsert = comment
commentLast = comment
flagList = False
# В случае открывающего и закрывающего комментария
if type(comment) == types.TupleType and len(comment) == 2:
commentFirst = comment[0]
commentInsert = ""
commentLast = comment[1]
flagList = True
if flagList:
self._titleBody = commentFirst + "\n"
else:
self._titleBody = commentFirst + self.__titleHead + "\n"
z = 0
flagFirst = True
for com in list(self._titleList) + [""]*(len(commentList)):
if com:
if flagFirst:
self._titleBody += commentInsert + " " + com + " "+\
self.programVersion + "\n"
flagFirst = False
else:
self._titleBody += commentInsert + " " + com + "\n"
else:
self._titleBody += commentInsert + " " +\
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 applyTemplates(self):
"""Применяет шаблоны к конфигурационным файлам"""
def createDictTemplates(path, prefix, dictTemplates):
"""Создает словарь {"директория":"кол-во шаблонов" ...}
и считает общее количество шаблонов
"""
# Количество шаблонов
self.allTemplates += 1
dirTemplate = os.path.split(path)[0]
while(True):
if dirTemplate in dictTemplates.keys():
dictTemplates[dirTemplate] += 1
else:
dictTemplates[dirTemplate] = 1
if dirTemplate == prefix:
break
dirTemplate = os.path.split(dirTemplate)[0]
return dictTemplates
if not self.objVar.defined("cl_template_path"):
self.setError(_("not defined Var: ") + "cl_template_path")
return False
dirsTemplates = self.objVar.Get("cl_template_path")
dirsTemplates.sort()
# Созданные директории
self.createdDirs = []
# Примененные файлы
self.filesApply = []
# Номер применяемого шаблона
self.numberProcessTempl = 0
# Словарь директорий с количеством файлов шаблонов
self.dictTemplates = {}
# Количество шаблонов
self.allTemplates = 0
# Установка по умолчанию аттрибутов для функциии шаблонов ini()
# Время доступа к конфигурационному файлу функции шаблона ini()
self.functObj.timeIni = -1
# Первоначальный словарь переменных для ini()
self.functObj.prevDictIni = {}
# Текущий словарь переменных для ini()
self.functObj.currDictIni = {}
# Словарь времен модификации env файлов для ini()
self.functObj.timeConfigsIni = {}
if self._servDir:
tmpDirsTemplates = []
for dirP in dirsTemplates:
dirTempl = dirP + self._servDir
if os.access(dirTempl, os.F_OK):
# Если директория существует
tmpDirsTemplates.append(dirTempl)
dirsTemplates = tmpDirsTemplates
scanObj = scanDirectory()
scanObj.processingFile = lambda x,y: createDictTemplates(x, y,\
self.dictTemplates)
# Считаем количество шаблонов
dirsTemplatesExists = filter(lambda x: os.path.exists(x), dirsTemplates)
if not dirsTemplatesExists:
self.setError(_("No such template directories") +\
": %s"%", ".join(map(lambda x: "'%s'"%x ,dirsTemplates)))
return (self.createdDirs, self.filesApply)
for dirTemplate in dirsTemplatesExists:
scanObj.scanningDirectory(dirTemplate)
# Считаем количество шаблонов clt
if self.cltObj:
# Считаем количество шаблонов clt
self.cltObj.countsNumberTemplates()
# не считать количество файлов в объекте self.cltObj
self.cltObj.checkNumberTemplate = False
# начальны номер clt шаблона
self.cltObj.numberProcessTempl = self.allTemplates
# метод показывающий номер clt шаблона
self.cltObj.numberProcessTemplates = self.numberProcessTemplates
# общее количество шаблонов
self.allTemplates += self.cltObj.allTemplates
self.cltObj.allTemplates = self.allTemplates
self.numberAllTemplates(self.allTemplates)
# Обрабатываем шаблоны
for dirTemplate in dirsTemplatesExists:
if self.scanningTemplates(dirTemplate) is False:
return False
if self.cltObj:
# Созданные директории
self.cltObj.createdDirs = self.createdDirs
# Примененные файлы
self.cltObj.filesApply = self.filesApply
# Словарь директорий с количеством файлов шаблонов
self.cltObj.dictTemplates = self.dictTemplates
# Количество шаблонов
self.cltObj.allTemplates = self.allTemplates
# Установка по умолчанию аттрибутов для функциии шаблонов ini()
# Время доступа к конфигурационному файлу функции шаблона ini()
self.cltObj.functObj = self.functObj
# Словарь примененных файлов шаблонов
self.cltObj.dictProcessedTemplates = self.dictProcessedTemplates
if self.cltFilter:
# Шаблоны + .clt которые будут применены
self.cltObj.filterApplyTemplates=\
map(lambda x: pathJoin('/', x.partition(self._baseDir)[2]),
self.dictProcessedTemplates.keys())
# Обрабатываем шаблоны clt
if not self.cltObj.applyTemplates():
return False
return (self.createdDirs, self.filesApply)
def scanningTemplates(self, scanDir, prefix=None, flagDir=False, optDir={}):
"""Сканирование и обработка шаблонов в директории scanDir"""
ret = True
if not prefix:
prefix = os.path.realpath(scanDir)
if not flagDir:
# проверка корневой директории
retDir = self.processingDirectory(scanDir, scanDir, optDir)
if retDir is None:
return None
elif retDir is False:
return False
pathDir, objHead = retDir
optDir["path"] = pathDir
if not objHead is True and objHead.typeAppend == "skip":
# Установка опции пропуска директории
optDir["skip"] = True
if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]):
for fileOrDir in sorted(os.listdir(scanDir)):
absPath = os.path.join(scanDir,fileOrDir)
stInfo = os.lstat(absPath)
statInfo = stInfo[stat.ST_MODE]
if stat.S_ISREG(statInfo):
if not self.processingFile(absPath, prefix, optDir):
ret = False
break
elif stat.S_ISDIR(statInfo):
# Обработка директории
retDir = self.processingDirectory(absPath, prefix,
optDir)
if retDir is None:
continue
elif retDir is False:
ret = False
break
# Опции следующей директории
optNextDir = {}
pathDir, objHead = retDir
optNextDir["path"] = pathDir
if not objHead is True and objHead.typeAppend == "skip":
# Установка опции пропуска директории
optNextDir["skip"] = True
ret = self.scanningTemplates(absPath, prefix, True,
optNextDir)
if ret is False:
break
return ret
def processingFile(self, path, prefix, optFile):
"""Обработка в случае шаблона файла"""
self.numberProcessTempl += 1
self.numberProcessTemplates(self.numberProcessTempl)
# Пропуск шаблонов директорий
if self.templDirNameFile == os.path.split(path)[1]:
return True
# Проверка на переменные в названии файла
if not self.getNeedTemplate(path):
if self.getError():
return False
return True
if self.getError():
return False
nameFileConfig = path.partition(prefix)[2]
# файл в системе без условий
nameFileConfig = "/".join(map(lambda x:x.split("?")[0],\
nameFileConfig.split("/")))
# Записываем в переменную обрабатываемый файл
self.objVar.Set("cl_pass_file",nameFileConfig)
# Пишем время модификации *.env файлов
if nameFileConfig.endswith(".env"):
nameEnvFile = os.path.split(nameFileConfig)[1]
self.functObj.timeConfigsIni[nameEnvFile] = float(time.time())
filesApl = self.joinTemplate(path, nameFileConfig, optFile)
if self.getError():
return False
if filesApl:
self.filesApply += filesApl
return True
def processingDirectory(self, path, prefix, opt):
"""Обработка в случае директории если возвращаем None то пропуск дир."""
# Файл шаблона директории
dirInfoFile = os.path.join(path, self.templDirNameFile)
newDir = pathJoin(self._baseDir, path.partition(prefix)[2])
newDir = "/".join(map(lambda x:x.split("?")[0], newDir.split("/")))
# Применяем шаблон
pathDir, objHeadDir, createdDirs =\
self.__getApplyHeadDir(newDir, dirInfoFile, opt)
if createdDirs:
self.createdDirs += createdDirs
if objHeadDir:
return pathDir, objHeadDir
else:
if self.getError():
return False
# Добавление количества файлов в пропущенной директории
if path in self.dictTemplates.keys():
self.numberProcessTempl += self.dictTemplates[path]
return None
def __getApplyHeadDir(self, newDir, templateDirFile, optDir):
"""Применяет шаблон к директории (права, владелец, и.т. д)"""
def function(text):
"""Функция обработки функций в заголовке"""
return self.applyFuncTemplate(text, templateDirFile)
def chownConfDir(nameDirConfig, uid, gid, nameFileTemplate):
"""Изменение владельца конфигурационной директории"""
try:
os.chown(nameDirConfig, uid, gid)
except:
import pwd, grp
try:
userName = pwd.getpwuid(uid).pw_name
except:
userName = str(uid)
try:
groupName = grp.getgrgid(gid).gr_name
except:
groupName = str(gid)
owner = userName + ":" + groupName
self.setError(_("Failed to apply template file %s")\
%nameFileTemplate)
self.setError(_("error") + " " +\
"'chown %s %s'"%(owner, nameDirConfig))
return False
return True
applyDir = newDir
# Родительская директория
if optDir.get("path"):
path = optDir["path"]
else:
path = os.path.split(applyDir)[1]
path = pathJoin(self._baseDir, path)
if not os.path.exists(templateDirFile):
applyDir = os.path.join(path, os.path.split(applyDir)[1])
# Фильтрация шаблонов по названию директории
realPath = os.path.join("/",applyDir.partition(self._baseDir)[2])
if realPath in self.dirsFilter:
return ("", False, [])
# Создаем директорию если необходимо
crDirs = self.createDir(applyDir, False, self.uid, self.gid)
if not crDirs:
return ("", False, [])
if crDirs is True:
return (applyDir, True, [])
else:
return (applyDir, True, crDirs)
try:
FD = open(templateDirFile)
textTemplate = FD.read()
FD.close()
except:
self.setError(_("Error open template") + ": " +\
templateDirFile)
return ("", False, [])
# Заменяем переменные на их значения
textTemplate = self.applyVarsTemplate(textTemplate, templateDirFile)
# Заменяем функции на их значения
textTemplate = self.applyFuncTemplate(textTemplate, templateDirFile)
# Обработка заголовка
objHead = dirHeader(templateDirFile,textTemplate,self.objVar,function)
# Директория с профилями не будет применена
if not objHead.headerTerm:
if objHead.getError():
self.setError(_("Incorrect template") + ": " +\
templateDirFile)
return ("", False, [])
# Пропускаем директорию
if objHead.typeAppend == "skip":
applyDir = path
return (applyDir, objHead, [])
# Изменяем название родительской директории
if "path" in objHead.params:
path = objHead.params['path']
if path and path[0] == "~":
# Получаем путь с заменой ~ на директорию пользователя
path = os.path.join(self.homeDir,
path.partition("/")[2],"")[:-1]
elif not path or path and path[0] != "/":
self.setError(_("False value 'path' in template") + ": " +\
templateDirFile)
return ("", False, [])
else:
path = pathJoin(self._baseDir, path)
# Изменяем название директории
if "name" in objHead.params:
nameDir = objHead.params['name']
if "/" in nameDir or nameDir == ".." or nameDir == ".":
self.setError(_("False value 'name' in template") + ": " +\
templateDirFile)
return ("", False, [])
# Новый путь к директории
applyDir = os.path.join(path, nameDir)
else:
applyDir = os.path.join(path, os.path.split(applyDir)[1])
# Фильтрация шаблонов по названию директории
realPath = os.path.join("/",applyDir.partition(self._baseDir)[2])
if realPath in self.dirsFilter:
return ("", False, [])
# Удаляем директорию
if objHead.typeAppend == "remove":
if os.path.isdir(applyDir):
# удаляем директорию
try:
removeDir(applyDir)
except:
self.setError(_("Can not delete dir: " ) +\
applyDir)
return ("", False, [])
# Созданные директории
createdDirs = []
# chmod - изменяем права
if "chmod" in objHead.params:
mode = self.__octToInt(objHead.params['chmod'])
if mode:
if not os.path.exists(applyDir):
crDirs = self.createDir(applyDir, mode, self.uid, self.gid)
if not crDirs:
return ("", False, [])
if not crDirs is True:
createdDirs += crDirs
else:
os.chmod(applyDir, mode)
else:
self.setError(_("False value 'chmod' in template") + ": " +\
templateDirFile)
return ("", False, [])
# chown - изменяем владельца и группу
if "chown" in objHead.params:
owner = objHead.params['chown']
if owner:
if ":" in owner:
strUid, strGid = owner.split(":")
import pwd
try:
uid = pwd.getpwnam(strUid).pw_uid
except:
self.setError(_("Not user in this system: ") + strUid)
self.setError(_("False value 'chown' in template")+\
": " + templateDirFile)
return ("", False, [])
try:
import grp
gid = grp.getgrnam(strGid).gr_gid
except:
self.setError(_("Not group in this system: ")+strGid)
self.setError(_("False value 'chown' in template") +\
": "+ templateDirFile)
return ("", False, [])
if not os.path.exists(applyDir):
crDirs = self.createDir(applyDir, False, uid, gid)
if not crDirs:
return ("", False, [])
if not crDirs is True:
createdDirs += crDirs
else:
if not chownConfDir(applyDir, uid, gid,
templateDirFile):
return ("", False, [])
else:
self.setError(_("False value 'chown' in template") + ": " +\
templateDirFile)
return ("", False, [])
else:
self.setError(_("False value 'chown' in template") + ": " +\
templateDirFile)
return ("", False, [])
else:
# Устанавливаем владельцем директории, пользователя по умолчанию
# (переменная шаблона ur_login)
if os.path.exists(applyDir):
tUid, tGid = getModeFile(applyDir, mode="owner")
if (self.uid, self.gid) != (tUid, tGid):
if not chownConfDir(applyDir, self.uid, self.gid,
templateDirFile):
return ("", False, [])
else:
crDirs = self.createDir(applyDir, False, self.uid, self.gid)
if not crDirs:
return ("", False, [])
if not crDirs is True:
createdDirs += crDirs
if not objHead:
applyDir = ""
return (applyDir, objHead, createdDirs)
def __getApplyHeadTemplate(self, nameFileTemplate, nameFileConfig,
templateFileType, optFile):
"""Применяет заголовок к шаблону (права, владелец, и.т. д)"""
def function(text):
"""Функция обработки функций в заголовке"""
return self.applyFuncTemplate(text,nameFileTemplate)
def preReturn(pathProg):
"""Действия перед выходом из метода"""
if pathProg:
os.chdir(pathProg)
def chownConfFile(nameFileConfig, uid, gid, nameFileTemplate,
checkExists=True):
"""Изменение владельца конфигурационного файла"""
try:
if checkExists and not os.path.exists(nameFileConfig):
# Создание файла
FD = open(nameFileConfig, "w")
FD.close()
os.chown(nameFileConfig, uid, gid)
except:
import pwd, grp
try:
userName = pwd.getpwuid(uid).pw_name
except:
userName = str(uid)
try:
groupName = grp.getgrgid(gid).gr_name
except:
groupName = str(gid)
owner = userName + ":" + groupName
self.setError(_("Failed to apply template file %s")\
%nameFileTemplate)
self.setError(_("error") + " " +\
"'chown %s %s'"%(owner, nameFileConfig))
return False
return True
def chmodConfFile(nameFileConfig, mode, nameFileTemplate,
checkExists=True):
"""Изменения режима доступа конфигурационного файла"""
try:
if checkExists and not os.path.exists(pathOldFile):
# Создание файла
FD = open(nameFileConfig, "w")
FD.close()
os.chmod(nameFileConfig, mode)
except:
self.setError(_("Failed to apply template file %s")\
%nameFileTemplate)
self.setError(\
_("error") + " " +\
"'chmod %s %s'"%(str(oct(mode)), nameFileConfig))
return False
return True
self.closeFiles()
pathProg = ""
# Файлы в системе к которым были применены шаблоны
applyFiles = [nameFileConfig]
# В случае бинарного типа файла читаем шаблон
if templateFileType == "bin":
self.nameFileTemplate = os.path.abspath(nameFileTemplate)
self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
self.textTemplate = self.F_TEMPL.read()
self.closeTemplFile()
objHeadNew = fileHeader(nameFileTemplate, self.textTemplate, False,
templateFileType ,objVar=self.objVar,
function=function)
# файл шаблона не будет применен
if not objHeadNew.headerTerm:
if objHeadNew.getError():
self.setError(_("Incorrect template") + ": " +\
nameFileTemplate)
return ([], False)
# Родительская директория
path = optFile["path"]
# Изменяем название родительской директории
if "path" in objHeadNew.params:
path = objHeadNew.params['path']
if path and path[0] == "~":
# Получаем путь с заменой ~ на директорию пользователя
path = os.path.join(self.homeDir,path.partition("/")[2],"")[:-1]
elif not path or path and path[0] != "/":
self.setError(_("False value 'path' in template") + ": " +\
nameFileTemplate)
return ([], False)
else:
path = pathJoin(self._baseDir, path)
# Путь к оригинальному файлу - pathOldFile
# Изменяем путь к оригинальному файлу
if objHeadNew.params.has_key("name"):
nameFile = objHeadNew.params['name']
if "/" in nameFile or nameFile == ".." or nameFile == ".":
self.setError(_("False value 'name' in template") + ": " +\
nameFileTemplate)
return ([], False)
# Новый путь к оригинальному файлу
pathOldFile = os.path.join(path,nameFile)
else:
pathOldFile = os.path.join(path,os.path.split(nameFileConfig)[1])
applyFiles = [pathOldFile]
# Фильтрация шаблонов по названию файла
realPath = os.path.join("/",pathOldFile.partition(self._baseDir)[2])
if realPath in self.filesFilter:
return ([], False)
typeAppendTemplate = objHeadNew.typeAppend
# Удаляем оригинальный файл
if typeAppendTemplate == "remove":
if os.path.islink(pathOldFile):
# удаляем ссылку
try:
os.unlink(pathOldFile)
except:
self.setError(_("Error in template") + ": " +\
nameFileTemplate)
self.setError(_("Can not delete link") + ": " +\
pathOldFile)
return ([], False)
if os.path.isfile(pathOldFile):
# удаляем файл
try:
os.remove(pathOldFile)
except:
self.setError(_("Error in template") + ": " +\
nameFileTemplate)
self.setError(_("Can not delete file") + ": " +\
pathOldFile)
return ([], False)
return (applyFiles, False)
# Пропускаем обработку шаблона
elif typeAppendTemplate == "skip":
return ([], False)
# Создаем директорию для файла если ее нет
if not os.path.exists(path):
if not self.createDir(path):
return ([], False)
# В случае force
if objHeadNew.params.has_key("force"):
if os.path.islink(pathOldFile):
# удаляем ссылку
try:
os.unlink(pathOldFile)
except:
self.setError(_("Error in template") + ": " +\
nameFileTemplate)
self.setError(_("Can not delete link") + ": " +\
pathOldFile)
return ([], False)
if os.path.isfile(pathOldFile):
# удаляем файл
try:
os.remove(pathOldFile)
except:
self.setError(_("Error in template") + ": " +\
nameFileTemplate)
self.setError(_("Can not delete file") + ": " +\
pathOldFile)
return ([], False)
flagSymlink = False
flagForce = False
# Если есть параметр mirror
if objHeadNew.params.has_key("mirror"):
if objHeadNew.params.has_key("link"):
templateFile = objHeadNew.params['link']
templateFile = pathJoin(self._baseDir, templateFile)
if not os.path.exists(templateFile):
if os.path.exists(pathOldFile):
try:
os.remove(pathOldFile)
except:
self.setError(_("Error in template") + ": " +\
nameFileTemplate)
self.setError(_("Can not delete file") + ": " +\
pathOldFile)
return ([], False)
elif not os.path.exists(pathOldFile):
return ([], False)
# Если есть указатель на файл шаблона (link)
if objHeadNew.params.has_key("link") and\
not objHeadNew.params.has_key("symbolic"):
templateFile = objHeadNew.params['link']
templateFile = pathJoin(self._baseDir, templateFile)
foundTemplateFile = os.path.exists(templateFile)
if foundTemplateFile:
try:
F_CONF = self.openTemplFile(templateFile)
buff = F_CONF.read()
F_CONF.close()
fMode, fUid, fGid = getModeFile(templateFile)
except:
self.setError(_("Error in template") + ": " +\
nameFileTemplate)
self.setError(_("Can not open file") + ": " +\
templateFile)
return ([], False)
if os.path.exists(pathOldFile):
try:
os.remove(pathOldFile)
except:
self.setError(_("Error in template") + ": " +\
nameFileTemplate)
self.setError(_("Can not delete file") + ": " +\
pathOldFile)
return ([], False)
if foundTemplateFile:
try:
FD = open(pathOldFile, "w+")
FD.write(buff)
FD.close()
except:
self.setError(_("Error in template") + ": " +\
nameFileTemplate)
self.setError(_("Can not create file") + " '%s'"\
%pathOldFile)
return ([], False)
oMode = getModeFile(pathOldFile, mode="mode")
# Если права не совпадают, меняем права
if fMode != oMode:
if not chmodConfFile(pathOldFile, fMode, nameFileTemplate,
checkExists=False):
return ([], False)
# Если символическая ссылка
if objHeadNew.params.has_key("symbolic"):
prevOldFile = pathOldFile
pathOldFile = objHeadNew.params['link']
flagSymlink = True
if not "/" == pathOldFile[0]:
pathLink = os.path.split(os.path.abspath(prevOldFile))[0]
pathProg = os.getcwd()
try:
os.chdir(pathLink)
except:
self.setError(_("Error in template") + ": " +\
nameFileTemplate)
self.setError(_("Can not change the current directory to")+\
" " + pathLink)
return ([], False)
# chmod - изменяем права
if objHeadNew.params.has_key("chmod"):
mode = self.__octToInt(objHeadNew.params['chmod'])
if mode:
if not chmodConfFile(pathOldFile, mode, nameFileTemplate):
preReturn(pathProg)
return ([], False)
else:
self.setError(_("False value 'chmod' in template") + ": " +\
nameFileTemplate)
preReturn(pathProg)
return ([], False)
# chown - изменяем владельца и группу
if objHeadNew.params.has_key("chown"):
owner = objHeadNew.params['chown']
if owner:
if ":" in owner:
strUid, strGid = owner.split(":")
import pwd
try:
uid = pwd.getpwnam(strUid).pw_uid
except:
self.setError(_("Not user in this system: ") + strUid)
self.setError(_("False value 'chown' in template") +\
": "+ nameFileTemplate)
preReturn(pathProg)
return ([], False)
try:
import grp
gid = grp.getgrnam(strGid).gr_gid
except:
self.setError(_("Not group in this system: ")+strGid)
self.setError(_("False value 'chown' in template") +\
": "+ nameFileTemplate)
preReturn(pathProg)
return ([], False)
# Изменяем владельца файла
if not chownConfFile(pathOldFile,uid,gid,nameFileTemplate):
preReturn(pathProg)
return ([], False)
else:
self.setError(_("False value 'chown' in template") + ": " +\
nameFileTemplate)
preReturn(pathProg)
return ([], False)
else:
self.setError(_("False value 'chown' in template") + ": " +\
nameFileTemplate)
preReturn(pathProg)
return ([], False)
self.openFiles(nameFileTemplate, pathOldFile)
if not objHeadNew.params.has_key("chown"):
# Устанавливаем владельцем конфигурационного файла,
# пользователя по умолчанию (переменная шаблона ur_login)
tUid, tGid = getModeFile(pathOldFile, mode="owner")
if (self.uid, self.gid) != (tUid, tGid):
# Изменяем владельца файла
if not chownConfFile(pathOldFile, self.uid, self.gid,
nameFileTemplate, checkExists=False):
preReturn(pathProg)
return ([], False)
if flagSymlink:
if os.path.exists(prevOldFile) or os.path.islink(prevOldFile):
try:
if os.path.islink(prevOldFile):
# если ссылка то удаляем её
os.unlink(prevOldFile)
else:
# иначе удаляем файл
os.remove(prevOldFile)
except:
self.setError(_("Error in template") + ": " +\
nameFileTemplate)
self.setError(_("Can not delete file") + ": " +\
prevOldFile)
preReturn(pathProg)
return ([], False)
if not "/" == pathOldFile[0]:
applyFiles = [prevOldFile,os.path.join(pathLink,pathOldFile)]
else:
applyFiles = [prevOldFile,pathOldFile]
try:
os.symlink(pathOldFile, prevOldFile)
except:
self.setError(_("Error in template") + ": " +\
nameFileTemplate)
self.setError(_("Can not create symbolic link") + " :" +\
"%s -> %s"%(prevOldFile, pathOldFile))
preReturn(pathProg)
return ([], False)
if not objHeadNew.body.strip():
preReturn(pathProg)
return ([], False)
else:
applyFiles = [pathOldFile]
if pathProg:
os.chdir(pathProg)
# Если файлы заменяются не нужно их обрабатывать дальше
if typeAppendTemplate == "replace" and\
not objHeadNew.params.has_key("symbolic") and\
objHeadNew.params.has_key("link"):
preReturn(pathProg)
return ([], False)
if not pathOldFile in self.dictProcessedTemplates:
self.dictProcessedTemplates[pathOldFile] = []
self.dictProcessedTemplates[pathOldFile].append(nameFileTemplate)
preReturn(pathProg)
return (applyFiles, objHeadNew)
def createNewClass(self, name, bases, attrs={}):
"""Создает объект нового класса
createNewClass(self, name, bases, attrs)
name - имя класса - str,
bases - cписок наследуемых классов - (tuple),
attrs - аттрибуты класса - {dict}
"""
class newMethod:
#Объединяем конфигурации
def join(self, newObj):
if newObj.__class__.__name__ == self.__class__.__name__:
self.docObj.joinDoc(newObj.doc)
# Пост обработка
if 'postXML' in dir(self):
self.postXML()
attrsNew = {}
attrsNew["configName"] = name
if attrs:
for key in attrs.keys():
attrsNew[key] = attrs[key]
newCl = type(name, bases + (newMethod, object,), attrsNew)
return newCl
def fileIsUtf(self, fileName):
"""Проверяет файл на кодировку UTF-8"""
if os.path.exists(fileName):
FD = open(os.path.abspath(fileName))
newTemplate = FD.read()
FD.close()
try:
newTemplate.decode("UTF-8")
except:
return False
return True
def joinTemplate(self, nameFileTemplate, nameFileConfig, optFile={}):
"""Объединения шаблона и конф. файла
join(nameFileTemplate, nameFileConfig, ListOptTitle)
Объединение шаблона nameFileTemplate и конф. файла nameFileConfig,
ListOptTitle - список строк которые добавятся в заголовок
optFile = опции для шаблона
"""
# Выполняем условия для блока текста а так-же заменяем переменные
self.nameFileTemplate = os.path.abspath(nameFileTemplate)
self.F_TEMPL = self.openTemplFile(self.nameFileTemplate)
self.textTemplate = self.F_TEMPL.read()
self.closeTemplFile()
# Флаг копирования шаблона в конфигурационный файл
flagCopyTemplate = True
# Тип шаблона бинарный или текстовый
templateFileType = self.getTemplateType()
if templateFileType != "bin":
# Вычисляем условные блоки
self.textTemplate = self.applyTermsTemplate(self.textTemplate,
nameFileTemplate)
# Заменяем переменные на их значения
self.textTemplate = self.applyVarsTemplate(self.textTemplate,
nameFileTemplate)
# Вычисляем функции
self.textTemplate = self.applyFuncTemplate(self.textTemplate,
nameFileTemplate)
flagCopyTemplate = False
if not optFile:
optFile = {"path":os.path.split(nameFileConfig)[0]}
filesApply, objHeadNew = self.__getApplyHeadTemplate(nameFileTemplate,
nameFileConfig,
templateFileType,
optFile)
if not objHeadNew:
return filesApply
# Настоящее имя конфигурационного файла
nameFileConfig = filesApply[0]
# Флаг - кодировка с бинарными примесями у файла шаблона включаем при
# условии текстового файла и кодировки отличной от UTF-8
flagNotUtf8New = False
# Флаг - кодировка с бинарными примесями у оригинального файла
flagNotUtf8Old = False
if not flagCopyTemplate:
# проверяем кодировку шаблона
if not self.fileIsUtf(nameFileTemplate):
flagNotUtf8New = True
if not (objHeadNew.params.has_key("link") and\
objHeadNew.params.has_key("symbolic")):
# проверяем кодировку оригинального файла
if not self.fileIsUtf(nameFileConfig):
flagNotUtf8Old = True
self.textTemplate = objHeadNew.body
# Список примененных шаблонов
ListOptTitle = []
if nameFileConfig in self.dictProcessedTemplates:
ListOptTitle = self.dictProcessedTemplates[nameFileConfig]
# Титл конфигурационного файла
title = ""
if ListOptTitle:
title = self.getTitle(objHeadNew.comment, ListOptTitle)
title = title.encode("UTF-8")
objHeadOld = False
if objHeadNew.comment:
objHeadOld = fileHeader(nameFileConfig, self.textConfig,
objHeadNew.comment)
if objHeadNew.fileType:
formatTemplate = objHeadNew.fileType
typeAppendTemplate = objHeadNew.typeAppend
# Создаем объект в случае параметра format в заголовке
if (typeAppendTemplate == "replace" or\
typeAppendTemplate == "before" or\
typeAppendTemplate == "after") and\
not (formatTemplate == "bin" or\
formatTemplate == "raw"):
# Преобразовываем бинарные файлы
if flagNotUtf8New:
objTxtCoder = utfBin()
self.textTemplate = objTxtCoder.encode(self.textTemplate)
# создаем объект формата шаблона
objTemplNew = self.getFormatObj(formatTemplate,
self.textTemplate)
if not objTemplNew:
self.setError(\
_("Incorrect header parmeter format=%s in template")\
%formatTemplate + " " + nameFileTemplate)
return False
if "xml_" in formatTemplate:
if objTemplNew.getError():
self.setError(_("False template") + ": " +\
nameFileTemplate)
return False
# Имя файла внутри xml xfce конфигурационных файлов
nameRootNode=nameFileConfig.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.textTemplate = objTemplNew.getConfig().encode("UTF-8")
# Если не UTF-8 производим преобразование
if flagNotUtf8New:
self.textTemplate = objTxtCoder.decode(self.textTemplate)
# Титл для объединения
if ListOptTitle:
title = self.getTitle(objTemplNew._comment,
ListOptTitle)
title = title.encode("UTF-8")
# Замена
if typeAppendTemplate == "replace":
if "xml_" in formatTemplate:
data = self.textTemplate.split("\n")
data.insert(1,title)
self.textConfig = "\n".join(data)
else:
if objHeadNew.execStr:
self.textConfig = objHeadNew.execStr+title+\
self.textTemplate
else:
self.textConfig = title + self.textTemplate
self.saveConfFile()
return filesApply
# Впереди
elif typeAppendTemplate == "before":
if "xml_" in formatTemplate:
self.setError(\
_("False option append=before in template %s")\
%nameFileTemplate)
return False
if objHeadOld and objHeadOld.body:
self.textConfig = objHeadOld.body
if self.textTemplate[-1] == "\n":
tmpTemplate = self.textTemplate + self.textConfig
else:
tmpTemplate = self.textTemplate + "\n" + self.textConfig
if objHeadNew.execStr:
self.textConfig = objHeadNew.execStr + title + tmpTemplate
elif objHeadOld and objHeadOld.execStr:
self.textConfig = objHeadOld.execStr + title + tmpTemplate
else:
self.textConfig = title + tmpTemplate
self.saveConfFile()
return filesApply
# Cзади
elif typeAppendTemplate == "after":
if "xml_" in formatTemplate:
self.setError(\
_("False option append=after in template %s")\
%nameFileTemplate)
return False
if objHeadOld and objHeadOld.body:
self.textConfig = objHeadOld.body
if self.textTemplate[-1] == "\n":
tmpTemplate = self.textConfig + self.textTemplate
else:
tmpTemplate = self.textConfig + "\n" + self.textTemplate
if objHeadNew.execStr:
self.textConfig = objHeadNew.execStr + title + tmpTemplate
elif objHeadOld and objHeadOld.execStr:
self.textConfig = objHeadOld.execStr + title + tmpTemplate
else:
self.textConfig = title + tmpTemplate
self.saveConfFile()
return filesApply
# Объединение
elif typeAppendTemplate == "join":
if flagNotUtf8New:
objTxtCoder = utfBin()
self.textTemplate = objTxtCoder.encode(self.textTemplate)
# создаем объект формата шаблона
objTemplNew = self.getFormatObj(formatTemplate,
self.textTemplate)
if not objTemplNew:
self.setError(\
_("Incorrect header parmeter format=%s in template")\
%formatTemplate + " " + nameFileTemplate)
return False
if "xml_" in formatTemplate:
if objTemplNew.getError():
self.setError(_("False template") + ": " +\
nameFileTemplate)
return False
nameRootNode=nameFileConfig.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.textConfig or\
not reNoClean.search(self.textConfig):
self.textConfig = ""
#if objHeadNew.execStr:
#self.textConfig = objHeadNew.execStr + \
#title + objTemplNew.getConfig().encode("UTF-8")
#else:
#self.textConfig = title +\
#objTemplNew.getConfig().encode("UTF-8")
#self.saveConfFile()
#return True
objHeadOld = fileHeader(nameFileConfig, self.textConfig,
objTemplNew._comment)
if objHeadOld.body:
self.textConfig = objHeadOld.body
else:
self.textConfig = ""
if flagNotUtf8Old:
objTxtCoder = utfBin()
self.textConfig = objTxtCoder.encode(self.textConfig)
# создаем объект формата шаблона для конфигурационного файла
objTemplOld = self.getFormatObj(formatTemplate,
self.textConfig)
if not objTemplOld:
self.setError(_("Error in template %s") %nameFileConfig)
return False
if "xml_" in formatTemplate:
if objTemplOld.getError():
self.setError(_("False template") + ": " +\
nameFileConfig)
return False
nameRootNode=nameFileConfig.rpartition("/")[2].split(".")[0]
objTemplOld.setNameBodyNode(nameRootNode)
objTemplOld.join(objTemplNew)
if "xml_" in formatTemplate:
if objTemplOld.getError():
self.setError(_("False template") + ": " +\
nameFileTemplate)
return False
data = objTemplOld.getConfig().encode("UTF-8").split("\n")
data.insert(1,title)
self.textConfig = "\n".join(data)
else:
if objHeadNew.execStr:
self.textConfig = objHeadNew.execStr + title +\
objTemplOld.getConfig().encode("UTF-8")
elif objHeadOld.execStr:
self.textConfig = objHeadOld.execStr + title +\
objTemplOld.getConfig().encode("UTF-8")
else:
self.textConfig = title +\
objTemplOld.getConfig().encode("UTF-8")
# Декодируем если кодировка не UTF-8
if flagNotUtf8New or flagNotUtf8Old:
self.textTemplate = objTxtCoder.decode(self.textTemplate)
self.textConfig = objTxtCoder.decode(self.textConfig)
self.saveConfFile()
return filesApply
else:
self.setError(_("False (type append) template") + ": " +\
typeAppendTemplate)
return False
else:
self.setError(_("Type template not found: ") + nameFileTemplate)
return False
return filesApply
class scanDirectoryClt:
"""Класс для cканирования директорий с файлами .clt"""
# Расширение файла шаблона
extFileTemplate = ".clt"
lenExtFileTemplate = len(extFileTemplate)
filterApplyTemplates = []
def processingFile(self, path, prefix):
"""Обработка в случае файла"""
return True
def scanningTemplates(self, scanDir, prefix=None, flagDir=False):
"""Сканирование и обработка шаблонов в директории scanDir"""
ret = True
if not prefix:
prefix = os.path.realpath(scanDir)
if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]):
for fileOrDir in sorted(os.listdir(scanDir)):
absPath = os.path.join(scanDir,fileOrDir)
stInfo = os.lstat(absPath)
statInfo = stInfo[stat.ST_MODE]
if fileOrDir.endswith(self.extFileTemplate) and\
stat.S_ISREG(statInfo):
if not self.filterApplyTemplates or\
absPath[:-self.lenExtFileTemplate] in\
self.filterApplyTemplates:
if not self.processingFile(absPath, prefix):
ret = False
break
elif stat.S_ISDIR(statInfo):
ret = self.scanningTemplates(absPath, prefix, True)
if ret is False:
break
return ret
class templateClt(scanDirectoryClt, template):
"""Класс для обработки шаблонов c расширением .clt"""
def __init__(self, objVar):
self.checkNumberTemplate = True
template.__init__(self, objVar, cltObj=False)
applyPackages = ["calculate-install"]
self.flagApplyTemplates = False
if self.objVar.Get("cl_name") in applyPackages:
self.flagApplyTemplates = True
def applyTemplate(self, path):
"""Применение отдельного .clt шаблона"""
if not self.flagApplyTemplates:
return True
return self.processingFile(path, "")
def processingFile(self, path, prefix):
"""Обработка в случае шаблона файла"""
self.numberProcessTempl += 1
self.numberProcessTemplates(self.numberProcessTempl)
# Пропуск шаблонов директорий
if self.templDirNameFile == os.path.split(path)[1]:
return True
# Проверка на переменные в названии файла
if not self.getNeedTemplate(path):
if self.getError():
return False
return True
if self.getError():
return False
if prefix and prefix[-1] == "/":
prefix = prefix[:-1]
if prefix:
nameFileConfig = path.partition(prefix)[2]
else:
nameFileConfig = path
nameFileConfig = nameFileConfig[:-self.lenExtFileTemplate]
# файл в системе без условий
nameFileConfig = "/".join(map(lambda x:x.split("?")[0],\
nameFileConfig.split("/")))
# Записываем в переменную обрабатываемый файл
self.objVar.Set("cl_pass_file",nameFileConfig)
# Пишем время модификации *.env файлов
if nameFileConfig.endswith(".env"):
nameEnvFile = os.path.split(nameFileConfig)[1]
self.functObj.timeConfigsIni[nameEnvFile] = float(time.time())
filesApl = self.joinTemplate(path, nameFileConfig)
if self.getError():
return False
if filesApl:
self.filesApply += filesApl
# Настоящее имя конфигурационного файла
nameFileConfig = filesApl[0]
return nameFileConfig
def countsNumberTemplates(self, dirsTemplates=[]):
"""Считаем количество шаблонов"""
def createDictTemplates(path, prefix, dictTemplates):
"""Создает словарь {"директория":"кол-во шаблонов" ...}
и считает общее количество шаблонов
"""
# Количество шаблонов
self.allTemplates += 1
dirTemplate = os.path.split(path)[0]
while(True):
if dirTemplate in dictTemplates.keys():
dictTemplates[dirTemplate] += 1
else:
dictTemplates[dirTemplate] = 1
if dirTemplate == prefix:
break
dirTemplate = os.path.split(dirTemplate)[0]
return dictTemplates
if not dirsTemplates:
dirsTemplates = self.objVar.Get("cl_template_clt_path")
dirsTemplates.sort()
scanObj = scanDirectoryClt()
scanObj.processingFile = lambda x,y: createDictTemplates(x, y,\
self.dictTemplates)
# Считаем количество шаблонов
for dirTemplate in dirsTemplates:
scanObj.scanningTemplates(dirTemplate, "/")
def applyTemplates(self):
"""Применяет шаблоны к конфигурационным файлам"""
if not self.flagApplyTemplates:
return ([],[])
if not self.objVar.defined("cl_template_clt_path"):
self.setError(_("not defined Var: ") + "cl_template_clt_path")
return False
dirsTemplates = self.objVar.Get("cl_template_clt_path")
dirsTemplates.sort()
if self.checkNumberTemplate:
# Созданные директории
self.createdDirs = []
# Примененные файлы
self.filesApply = []
# Номер применяемого шаблона
self.numberProcessTempl = 0
# Словарь директорий с количеством файлов шаблонов
self.dictTemplates = {}
# Количество шаблонов
self.allTemplates = 0
# Установка по умолчанию аттрибутов для функциии шаблонов ini()
# Время доступа к конфигурационному файлу функции шаблона ini()
self.functObj.timeIni = -1
# Первоначальный словарь переменных для ini()
self.functObj.prevDictIni = {}
# Текущий словарь переменных для ini()
self.functObj.currDictIni = {}
# Словарь времен модификации env файлов для ini()
self.functObj.timeConfigsIni = {}
# Считаем количество шаблонов
self.countsNumberTemplates(dirsTemplates=dirsTemplates)
self.numberAllTemplates(self.allTemplates)
# Обрабатываем шаблоны
for dirTemplate in dirsTemplates:
if self.scanningTemplates(dirTemplate, "/") is False:
return False
return (self.createdDirs, self.filesApply)
class iniParser(_error, templateFormat):
"""Класс для работы с ini файлами
"""
def __init__(self, iniFile):
# название 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):
try:
# Создание файла
FD = open(self.iniFile, "w+")
os.chmod(self.iniFile, self.mode)
except:
self.setError(_("Unable to create file") + ": " + self.iniFile)
return False
else:
try:
FD = open(self.iniFile, "r+")
except:
self.setError(_("Unable to open file") + ": " + self.iniFile)
return False
FD.truncate(0)
FD.seek(0)
FD.write(txtConfig)
FD.close()
return True
def setVar(self, strHeader, dictVar):
"""Заменяет или добавляет область и переменные
Добавляет область в ini-файл или объединяет с существующей
strHeader - имя области
dictVar - словарь переменных
"""
textIni = self.openIniFile()
nameFomat = self.checkIniFile(textIni)
if not nameFomat:
return False
if type(strHeader) in (tuple, list):
# формат plasma
classObj = self.getClassObj("plasma")
else:
if nameFomat == "plasma":
self.setError(_("In the file %s (format - 'plasma'), \
write the variable in the format 'samba'")\
%self.iniFile)
return False
# формат samba
classObj = self.getClassObj("samba")
# создаем объект
# и записываем в него содержимое ini-файла
objIni = classObj(textIni)
# создаем текст из строки заголовка и
# словаря переменных области
txtConfig = objIni.createTxtConfig(strHeader, dictVar)
# создаем объект и записываем в него текст
objIniAdd = classObj(txtConfig)
# объединяем объекты для получения результирующего текста
objIni.join(objIniAdd)
# получаем текст
txtConfig = objIni.getConfig().encode("UTF-8")
# записываем его в ini файл
if not self.writeIniFile(txtConfig):
return False
return True
def isEmptyFile(self, textIni):
"""Является ли файл пустым"""
if not textIni.strip():
return True
else:
return False
def checkIniFile(self, textIni):
"""Проверка на правильность формата файла"""
if self.checkIni is None:
# Ошибка
if textIni == False:
self.checkIni = False
return False
self.checkIni = "samba"
# В файле есть данные
if not self.isEmptyFile(textIni):
try:
objIni = self.getClassObj("plasma")(textIni)
except:
self.setError(_("Incorrect format file") + ": " + \
self.iniFile)
self.checkIni = False
return self.checkIni
allAreas = objIni.docObj.getAllAreas()
for xmlArea in allAreas:
parentNode = xmlArea.parentNode
if parentNode and parentNode.tagName == "area":
self.checkIni = "plasma"
break
if self.checkIni == "samba":
objIni = self.getClassObj("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 файла"""
if type(strHeader) in (tuple, list):
# Формат plasma
delStrHeader = strHeader[:]
delStrHeader[-1] = "!%s"%delStrHeader[-1]
else:
# Формат samba
delStrHeader = "!%s" %(strHeader)
dictVar = {"del":"del"}
res = self.setVar(delStrHeader, dictVar)
return res
def getVar(self, strHeader, nameVar, checkExistVar=False):
"""Получаем значение переменной из ini-файла"""
textIni = self.openIniFile()
nameFomat = self.checkIniFile(textIni)
if not nameFomat:
return False
formatPlasma = False
if type(strHeader) in (tuple, list):
# формат plasma
classObj = self.getClassObj("plasma")
formatPlasma = True
else:
if nameFomat == "plasma":
self.setError(_("In the file %s (format - 'plasma'), \
get the variable in the format 'samba'")\
%self.iniFile)
return False
# формат samba
classObj = self.getClassObj("samba")
# создаем объект и записываем в него содержимое ini-файла
objIni = classObj(textIni)
# получаем ноду body
xmlBody = objIni.docObj.getNodeBody()
flagFound, xmlBody = self.getLastNode(objIni, xmlBody, strHeader,
formatPlasma)
if flagFound and xmlBody:
if formatPlasma:
strHeader = strHeader[-1]
# находим в области переменную
res = objIni.docObj.getAreaFieldValues(strHeader, nameVar, xmlBody)
else:
res = False
if checkExistVar:
if res is False:
return False, ""
else:
return True, res
else:
if res is False:
return ""
else:
return res
def getLastNode(self, objIni, xmlBody, strHeader, formatPlasma):
"""Ищет область в XML в которой область с переменными"""
flagFound = True
if not strHeader:
flagFound = False
return flagFound,xmlBody
lenStrHeader = len(strHeader)
if formatPlasma and lenStrHeader>0:
xmlAreas = [xmlBody]
for i in xrange(lenStrHeader-1):
flagFound = False
for xmlArea in xmlAreas:
xmlAreas = objIni.docObj.getArea(strHeader[i], xmlArea)
if xmlAreas:
flagFound = True
break
if xmlAreas:
xmlBody = xmlAreas[0]
return flagFound,xmlBody
def getAreaVars(self, strHeader):
"""Получаем все переменнные области из ini-файла"""
textIni = self.openIniFile()
nameFomat = self.checkIniFile(textIni)
if not nameFomat:
return False
formatPlasma = False
if type(strHeader) in (tuple, list):
# формат plasma
classObj = self.getClassObj("plasma")
formatPlasma = True
else:
if nameFomat == "plasma":
self.setError(_("In the file %s (format - 'plasma'), \
get all variables in the format 'samba'")\
%self.iniFile)
return False
# формат samba
classObj = self.getClassObj("samba")
# создаем объект типа samba и записываем в него содержимое ini-файла
objIni = classObj(textIni)
# получаем ноду body
xmlBody = objIni.docObj.getNodeBody()
flagFound, xmlBody = self.getLastNode(objIni, xmlBody, strHeader,
formatPlasma)
if flagFound and xmlBody:
if formatPlasma:
strHeader = strHeader[-1]
# если находим область то выдаем словарем все переменные иначе False
res = objIni.docObj.getAreaFields(strHeader, xmlBody)
else:
res = False
if res is False:
return {}
else:
return res
def getAllSectionNames(self):
"""Получаем все имена секций определенных в ini файле
Если формат ini файла plasma то имя секции -
имена нескольких секций через запятую
"""
textIni = self.openIniFile()
nameFomat = self.checkIniFile(textIni)
if not nameFomat:
return False
if nameFomat == "samba":
# создаем объект типа samba и записываем в него содержимое ini-файла
objIni = self.getClassObj("samba")(textIni)
elif nameFomat == "plasma":
# создаем объект типа plasma и записываем в него содержимое
# ini-файла
objIni = self.getClassObj("plasma")(textIni)
else:
return []
xmlNodes = objIni.docObj.getAllAreas()
# Имена секций ini файла
namesSection = []
if nameFomat == "plasma":
for xmlNode in xmlNodes:
nSect = objIni.docObj.getNameArea(xmlNode)
if nSect:
namesSect = [nSect]
parentNode = xmlNode.parentNode
while parentNode != objIni.docObj.body:
nameSect = objIni.docObj.getNameArea(parentNode)
if nameSect:
namesSect.append(nameSect)
parentNode = parentNode.parentNode
else:
return []
namesSection.append(",".join(reversed(namesSect)))
elif nameFomat == "samba":
# получаем ноду body
for xmlNode in xmlNodes:
nSect = objIni.docObj.getNameArea(xmlNode)
if nSect:
namesSection.append(nSect)
return namesSection