diff --git a/build/lib/calculate-lib/pym/__init__.py b/build/lib/calculate-lib/pym/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/build/lib/calculate-lib/pym/cl_base.py b/build/lib/calculate-lib/pym/cl_base.py
new file mode 100644
index 0000000..4a8626e
--- /dev/null
+++ b/build/lib/calculate-lib/pym/cl_base.py
@@ -0,0 +1,1156 @@
+#-*- coding: utf-8 -*-
+
+# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import gettext
+import os
+import getopt
+import sys
+##############################################################################
+import re
+import copy
+import types
+import string
+#import os
+import filecmp
+import ConfigParser
+import time
+import socket
+#import sys
+import random
+import string
+import cl_utils
+##############################################################################
+
+_expand_lang = gettext._expand_lang
+
+def exit(codeExit):
+ """Метод выхода из программы"""
+ sys.exit(codeExit)
+
+def __findFileMO(domain, localedir=None, languages=None, all=0):
+ # Модифицинрованный метод модуля gettext ищет файл перевода
+ if localedir is None:
+ localedir = _default_localedir
+ if languages is None:
+ languages = []
+ for envar in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'):
+ val = os.environ.get(envar)
+ if val:
+ languages = val.split(':')
+ break
+ if 'C' not in languages:
+ languages.append('C')
+ # now normalize and expand the languages
+ nelangs = []
+ for lang in languages:
+ for nelang in _expand_lang(lang):
+ if nelang not in nelangs:
+ nelangs.append(nelang)
+ # select a language
+ if all:
+ result = []
+ else:
+ result = None
+ for lang in nelangs:
+ if lang == 'C':
+ break
+ mofile = os.path.join(localedir, '%s_%s.mo' % (domain,lang))
+ if os.path.exists(mofile):
+ if all:
+ result.append(mofile)
+ else:
+ return mofile
+ return result
+
+gettext.find = __findFileMO
+
+class GlobalParam(type):
+ """ Метакласс для глобальных параметров
+ """
+ def __init__(cls, *args):
+ cls.GP = []
+ cls.GP.append("")
+
+class lang:
+ """Класс многоязыковой поддержки lang для перевода сообщений программ на
+другие языки.
+
+Типичное использование:
+ import sys
+ import lang
+
+ # язык сообщений английский
+ tr = lang.lang(en)
+ # язык определяется системой
+ #tr = lang.lang()
+
+ #Установка домена переводаldap
+ # в последующем можно не использовать - задается глобально
+ tr.setGlobalDomain('calc')
+ # задается локально для одного файла
+ #tr.setLocalDomain('calc')
+
+ # Установка метода перевода для текущего модуля
+ tr.setLanguage(sys.modules[__name__])
+
+Где:
+ tr -- объект перевода
+ 'en' -- язык выводимых сообщений
+ sys.modules[__name__] -- модуль сообщения которого переводятся
+ calc - домен перевода - имя файла перевода без расширения
+
+Если файл перевода не найден то сообщения не переводятся
+Если в модуле сообщения которого переводим, экспортируются другие модули то
+они тоже переводятся.
+
+По умолчанию директория в которой находятся переводы: 'lang/i18h' относительно
+исполняемого файла названия файлов перевода совпадают с названиями модулей
+если не определен методом setDomainTranslate() - домен перевода.
+ """
+ __metaclass__ = GlobalParam
+ def __init__(self,l=''):
+ self.nameDomain = self.GP[0]
+ #self.nameDomain = ''
+ """ Название файла перевода (Домен) если используется 1 файл перевода
+ """
+ self.__catalog = os.path.abspath('/usr/share/calculate/i18n')
+ """ Путь к каталогу переводов (в этом каталоге
+ ru_RU/LC_MESSAGES в котором файл перевода)
+ """
+ env = os.environ
+ if l == "" and env.has_key('LANG'):
+ l = env['LANG'].split('.')[0].split("_")[0]
+ """ Определение языка """
+ self.__modnames = {}
+ """ Словарь переведенных модулей
+ ключ --- имя модуля
+ значение --- был ли модуль переведен (1 или 0)
+ """
+ self.__l = l
+ """Язык перевода для всех модулей"""
+
+ def __translate(self,message):
+ """Метод translate возвращает полученное значение без
+изменений"""
+ return message
+
+ def setLanguage(self,module):
+ """ Установка языка перевода для модуля module.
+
+ параметр --- экспортируемый модуль python
+ если в этом модуле экспортируются другие модули
+ то язык устанавливается и для них
+ Метод запускается после экспорта модуля который будем переводить
+ """
+ t = vars(module)
+ for i in dir(module):
+ q = str(t[i])
+ if 'module' in q and not '__' in i and not '/usr/lib' in q\
+ and not 'built-in' in q :
+ mod = vars(module)[i]
+ self.__setLang(mod)
+ return self.__setLang(module)
+
+ def __setLang(self,module):
+ """ Установка языка перевода для модуля module.
+
+ В случае нахождения файла перевода возвращает истину.
+ Во всех случаях устанавливает метод перевода для модуля.
+ Если нет файла перевода метод перевода возвращает то же
+ значение что получает
+ """
+ if module.__name__ in self.__modnames.keys():
+ return True
+
+ if self.nameDomain == '':
+ if module.__name__ == "__main__":
+ nameDomain = module.__file__.split('.')[0]
+ else:
+ nameDomain = module.__name__
+ else:
+ nameDomain = self.nameDomain
+
+ if self.__l == 'en':
+ module._ = self.__translate
+ ret = 1
+ else:
+ la = []
+ la.append(self.__l)
+ if gettext.find(nameDomain,self.__catalog,la):
+ """Если найден словарь то инициализируем переводчик"""
+ transl = gettext.translation(nameDomain\
+ ,self.__catalog,la)
+
+ #module._ = transl.ugettext
+ module._ = transl.gettext
+ ret = 1
+ else:
+ module._ = self.__translate
+ ret = 0
+ self.__modnames[module.__name__] = ret
+ return ret
+
+ def getTranslatorByName(self,namemodule):
+ """ Метод который по имени модуля определяет, был ли модуль с этим
+ именем переведен
+ """
+ if self.__modnames.has_key(namemodule):
+ return self.__modnames[namemodule]
+ return 0
+
+ def setGlobalDomain(self, nameDomain):
+ """ Метод для установки домена перевода (глобально для всех файлов)
+ """
+ self.GP[0] = nameDomain
+ self.nameDomain = self.GP[0]
+ return True
+
+ def setLocalDomain(self, nameDomain):
+ """ Метод для установки домена перевода (локально для одного файла)
+ """
+ self.nameDomain = nameDomain
+ return True
+
+##############################################################################
+# Перевод модуля на другой язык
+tr = lang()
+tr.setLocalDomain('cl_lib')
+tr.setLanguage(sys.modules[__name__])
+
+##############################################################################
+class opt:
+ def __init__(self,shortOpt,longOpt = []):
+ """ Длинные и короткие опции командной строки допустимые в программе
+ a - короткая опция
+ >program -a
+
+ a: - короткая опциия со значением
+ >program -a 10
+
+ a:: - короткая опциия у которой может быть или не быть значение
+ >program -a
+ >program -a 15
+
+ "ha:" - значение параметра shortOpt
+ две опции h - без значения, a - со значением
+
+ help - длинная опция без значения
+ test= - длинная опция со значением
+
+ ["help","test="] - значение парамера longOpt
+ >program -a
+ две опции help - без значения, test - со значением
+ """
+ self.shortOpt = shortOpt
+ self.longOpt = longOpt
+ self.sysArgv = sys.argv[1:]
+
+ def getopt(self):
+ try:
+ opts, args = getopt.getopt(self.sysArgv,self.shortOpt,self.longOpt)
+ except getopt.GetoptError:
+ self.handlerErrOpt()
+ sys.exit(1)
+ for option, value in opts:
+ if len(option) == 2:
+ option = option[1:]
+ else:
+ option = option[2:]
+ self.handlerOpt(option,value)
+ for param in args:
+ self.handlerParam(param)
+
+ def handlerErrOpt(self):
+ # Обработчик в случае неправильных параметров
+ pass
+
+ def handlerOpt(self,option,value):
+ # Обработчик (параметр значение)
+ pass
+
+ def handlerParam(self,param):
+ # Обработчик хвостов (значение)
+ pass
+
+###############################################################################
+import cl_profile
+class iniParser(cl_profile._error):
+ """Класс для работы с 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):
+ fd = os.open(self.iniFile, os.O_CREAT)
+ os.close(fd)
+ os.chmod(self.iniFile, self.mode)
+ if not os.path.exists(self.iniFile):
+ self.setError(_("Unable to create file") + ": " + self.iniFile)
+ return False
+ FD = open(self.iniFile, "r+")
+ FD.truncate(0)
+ FD.seek(0)
+ FD.write(txtConfig)
+ FD.close()
+
+ def setVar(self, strHeader, dictVar):
+ """Заменяет или добавляет область и переменные
+
+ Добавляет область в ini-файл или объединяет с существующей
+ strHeader - имя области
+ dictVar - словарь переменных
+ """
+ textIni = self.openIniFile()
+ nameFomat = self.checkIniFile(textIni)
+ if not nameFomat:
+ return False
+ if type(strHeader) in (tuple, list):
+ # формат plasma
+ classObj = cl_profile.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 = cl_profile.samba
+ # создаем объект
+ # и записываем в него содержимое ini-файла
+ objIni = classObj(textIni)
+ # создаем текст из строки заголовка и
+ # словаря переменных области
+ txtConfig = objIni.createTxtConfig(strHeader, dictVar)
+ # создаем объект и записываем в него текст
+ objIniAdd = classObj(txtConfig)
+ # объединяем объекты для получения результирующего текста
+ objIni.join(objIniAdd)
+ # получаем текст
+ txtConfig = objIni.getConfig().encode("UTF-8")
+ # записываем его в ini файл
+ self.writeIniFile(txtConfig)
+ return True
+
+ def isEmptyFile(self, textIni):
+ """Является ли файл пустым"""
+ if not textIni.strip():
+ return True
+ else:
+ return False
+
+ def checkIniFile(self, textIni):
+ """Проверка на правильность формата файла"""
+ if self.checkIni == None:
+ # Ошибка
+ if textIni == False:
+ self.checkIni = False
+ return False
+ self.checkIni = "samba"
+ # В файле есть данные
+ if not self.isEmptyFile(textIni):
+ try:
+ objIni = cl_profile.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 = cl_profile.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):
+ """Получаем значение переменной из ini-файла"""
+ textIni = self.openIniFile()
+ nameFomat = self.checkIniFile(textIni)
+ if not nameFomat:
+ return False
+ formatPlasma = False
+ if type(strHeader) in (tuple, list):
+ # формат plasma
+ classObj = cl_profile.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 = cl_profile.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 res is False:
+ return ""
+ else:
+ return res
+
+
+ def getLastNode(self, objIni, xmlBody, strHeader, formatPlasma):
+ """Ищет область в XML в которой область с переменными"""
+ flagFound = True
+ 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 = cl_profile.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 = cl_profile.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 = cl_profile.samba(textIni)
+ elif nameFomat == "plasma":
+ # создаем объект типа plasma и записываем в него содержимое
+ # ini-файла
+ objIni = cl_profile.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
+
+##############################################################################
+
+class var:
+ '''Объект "Переменная окружения"'''
+ # название сервиса которому принадлежит переменная
+ #(Global, Builder, Client, Server итд)
+ service = None
+ # значение переменной
+ value = ""
+ # режим записи (атрибут mode)
+ mode = "r"
+ # переменная для внутреннего использования (official)
+ official = False
+ # количество вызовов метода заполнения
+ countFill = 0
+ # объект в котором создан этот объект
+ parentObj = None
+ # запускать или нет метод заполнения
+ fillStart = True
+ # dynamic = True то переменная динамическая при повтороном запуске
+ # запускается метод заполнения
+ # метод заполнения не запускается только если fillStart = False
+ # (осторожно возможно зацикливание программы если методы заполнения
+ # переменных используют методы друг друга)
+ dynamic = False
+
+ def __init__(self, parentObj):
+ # словарь зависимых переменных {имя:значение}
+ self.dependValues = {}
+ # тип переменной (атрибут type)
+ self.type = ('default')
+ # список допустимых значений переменных (select)
+ self.select = ()
+ # объект который создал этот объект
+ self.parentObj = parentObj
+
+ def is_update(self):
+ #Нужно ли перезапускать метод заполнения (если зависимые переменные
+ #обновились то нужно)
+ upd = False
+ for depVarName in self.dependValues.keys():
+ value = self.parentObj.__getattribute__(depVarName).Get()
+ if self.dependValues[depVarName] != value:
+ self.dependValues[depVarName] =\
+ self.parentObj.__getattribute__(depVarName).value
+ upd = True
+ break
+ return upd
+
+ def Get(self):
+ """Получение значения переменной"""
+ if not self.fillStart:
+ return self.value
+ if self.dynamic:
+ self.value = self.Fill()
+ return self.value
+ if not self.value:
+ if self.countFill>0:
+ return self.value
+ self.countFill += 1
+ self.value = self.Fill()
+ if self.dependValues and self.is_update():
+ self.countFill += 1
+ self.value = self.Fill()
+ return self.value
+
+ def Set(self, value):
+ """Запись значения переменной"""
+ self.value = value
+ return self.value
+
+ def Fill(self):
+ """Заполнение переменной в далнейшем заменяем методом заполнения"""
+ return self.value
+
+
+class DataVars(object):
+ class DataVarsError(Exception):
+ """Класс ошибок"""
+ pass
+ # добавляем пути к модулям если они не добавлены
+ if not os.path.abspath(\
+ '/usr/lib/calculate/calculate-server/pym') in sys.path:
+ sys.path.insert(0,os.path.abspath(\
+ '/usr/lib/calculate/calculate-server/pym'))
+ if not os.path.abspath(\
+ '/usr/lib/calculate/calculate-lib/pym') in sys.path:
+ sys.path.insert(0,os.path.abspath(\
+ '/usr/lib/calculate/calculate-lib/pym'))
+ if not os.path.abspath(\
+ '/usr/lib/calculate/calculate-builder/pym') in sys.path:
+ sys.path.insert(0,os.path.abspath(\
+ '/usr/lib/calculate/calculate-builder/pym'))
+ # Импортируемые модули - (раздел: модуль переменных, модуль заполнения
+ #переменных)
+ __modlist={'Global':('cl_vars','cl_fill'),
+ 'Server':('cl_vars_server','cl_fill_server'),
+ 'Builder':('cl_vars_builder','cl_fill_builder'),
+ 'Client':('cl_vars_client','cl_fill_client'),
+ }
+ def __init__(self):
+ #self.t1 = fillVars()
+ #self.t1.Get = self.Get
+ #self.t1.Set = self.Set
+ # Для нахождения зависимостей переменных
+ self.__levelNumber = 0
+ self.__LevelsVar = []
+ # Для хранения импортированных модулей и объектов
+ #[(cекция,импортированный модуль переменных, объект заполнения),]
+ self._importList = []
+ self._importData("Global")
+
+ def _importData(self, section):
+ """Импортирует модули с переменными и модули с функциями заполнения
+
+ section секция раздела (Global, Server, Client итд)
+ создает необходимые структуры данных
+ """
+ if not section in self.__modlist.keys():
+ raise self.DataVarsError(_("Unsupported section %s")%section)
+ modVar = self.__modlist[section][0]
+ modFill = self.__modlist[section][1]
+ # Импортируем класс описания переменных и класс заполнения
+ try:
+ exec ("import %s" % (modVar))
+ except ImportError, e:
+ err1 = _("Error in import module %s")%modVar
+ err2 = _("error") + ": " +str(e)
+ raise self.DataVarsError("%s\n%s"%(err1,err2))
+ flagFindFillModule = True
+ try:
+ exec ("import %s" % (modFill))
+ except ImportError, e:
+ if "No module named" in str(e):
+ flagFindFillModule = False
+ else:
+ err1 = _("Error in import module %s")%modFill
+ err2 = _("error") + ": " +str(e)
+ raise self.DataVarsError("%s\n%s"%(err1,err2))
+ if flagFindFillModule:
+ # Создаем объект с методами заполнения переменных
+ exec("fillObj = %s.fillVars()" %modFill)
+ # Подключаем методы получения и записи переменных
+ fillObj.Get = self.Get
+ fillObj.Set = self.Set
+ else:
+ fillObj = False
+ # Заполняем self._importList
+ exec("self._importList.insert(0,(section,%s,fillObj))"%(modVar))
+
+ def __findVarData(self, nameVar):
+ """Находит данные для создания объекта переменная в модулях и
+
+ объектах
+ """
+ # Ищем переменную в модуле
+ dataVar = False
+ e = False
+ for section, moduleVar, fillobj in self._importList:
+ try:
+ exec("dataVar=moduleVar.Data.%s"%nameVar)
+ except AttributeError, e:
+ pass
+ if dataVar:
+ break
+ if dataVar == False:
+ err1 = _("Not found variable %s")%nameVar
+ err2 = ""
+ if e:
+ err2 = _("error") + ": " +str(e)
+ raise self.DataVarsError("%s\n%s"%(err1,err2))
+ dataVar['service'] = section
+ # Ищем метод в объекте методов заполнения
+ nameMethod = "get_" + nameVar
+ flagFindMetod = False
+ for section, moduleVar, fillobj in self._importList:
+ if fillobj:
+ if nameMethod in dir(fillobj):
+ flagFindMetod = True
+ method = fillobj.__getattribute__(nameMethod)
+ break
+ if flagFindMetod:
+ return (dataVar,method)
+ else:
+ return (dataVar,False)
+
+ def __setAttributesVar(self, var ,nameVar, dict):
+ """Установка аттрибутов для созданного объекта var
+
+ название аттрибута и его значение берется из словаря dict
+ """
+ dict['type'] = nameVar.split('_')
+ if not set(dict.keys()) <= set(dir(var)):
+ raise self.DataVarsError(\
+ _("error initalize variable %s, incorrect data")%nameVar)
+ for nameAttr in dict.keys():
+ setattr(var,nameAttr, dict[nameAttr])
+ return True
+
+ def __Get(self, nameVar):
+ ret = ""
+ self.__LevelsVar.append((self.__levelNumber, nameVar))
+ self.__levelNumber += 1
+ #nameMethod = "get_" + nameVar
+ if hasattr(self, nameVar):
+ ret = self.__getattribute__(nameVar).Get()
+ elif self.__findVarData(nameVar):
+ dictVar, methodFill =self.__findVarData(nameVar)
+ varobj = var(self)
+ # Устанавливаем аттрибуты
+ self.__setAttributesVar(varobj, nameVar, dictVar)
+ if methodFill:
+ varobj.Fill = methodFill
+ self.__setattr__(nameVar, varobj)
+ ret = self.__getattribute__(nameVar).Get()
+ self.__levelNumber -= 1
+ if self.__levelNumber == 0 and\
+ self.__getattribute__(nameVar).fillStart and\
+ len(self.__LevelsVar)>1:
+ links = self.__getLinks(self.__LevelsVar)
+ for name in links.keys():
+ for nameLink in links[name].keys():
+ val = self.__getattribute__(nameLink).Get()
+ self.__getattribute__(name).dependValues[nameLink] = val
+ if self.__levelNumber == 0:
+ self.__LevelsVar = []
+ return ret
+
+ def Get(self, nameVar):
+ return self.__Get(nameVar)
+
+
+ def __Set(self, nameVar, value, force=False):
+ nameMethod = "get_" +nameVar
+ if not hasattr(self, nameVar) and self.__findVarData(nameVar):
+ dictVar, methodFill =self.__findVarData(nameVar)
+ varobj = var(self)
+ # Устанавливаем аттрибуты
+ self.__setAttributesVar(varobj, nameVar, dictVar)
+ if methodFill:
+ varobj.Fill = methodFill
+ self.__setattr__(nameVar, varobj)
+ if hasattr(self, nameVar):
+ if not force and "r" in getattr(self, nameVar).mode:
+ print _("Attempt to rewrite a variable for reading:%s")\
+ %nameVar
+ return False
+ self.__getattribute__(nameVar).fillStart = False
+ return self.__getattribute__(nameVar).Set(value)
+
+ def Set(self, nameVar, value, force=False):
+ return self.__Set(nameVar, value, force)
+
+ def __frame(self, lVar):
+ """получить список областей зависимости переменных"""
+ data = []
+ if not lVar:
+ return data
+ firstLevel = lVar[0][0]
+ for level, name in lVar[1:]:
+ if level> firstLevel:
+ data.append((level, name))
+ else:
+ break
+ return data
+
+ def __getLinks(self, lVar):
+ """Получить список переменных и от каких переменных они зависят
+
+ на вход список [(уровень рекурсии, название переменной),]
+ """
+ links = {}
+ frames = {}
+ levelLinks = {}
+ lVarFr = lVar
+ for level, name in lVar:
+ fr = self.__frame(lVarFr)
+ if not frames.has_key(name):
+ frames[name] = fr
+ levelLinks[name] = level+1
+ lVarFr = lVarFr[1:]
+ for name in frames.keys():
+ level = levelLinks[name]
+ fr = frames[name]
+ links[name] = {}
+ for lv, nm in fr:
+ if level == lv:
+ links[name][nm] = ""
+ return links
+
+ def __getPathCalculateIni(self):
+ """Получить пути до ini файлов"""
+ return self.Get('cl_env_path')
+
+ def __getSection(self, vname):
+ """секция для записи в ini файл переменной
+
+ vname - имя переменной
+ """
+ if hasattr(self, vname):
+ if getattr(self, vname).service == 'Global':
+ return 'calculate'
+ else:
+ return getattr(self, vname).service.lower()
+
+ def __writeVarValue(self, vname, val, location, header):
+ '''Записать значение в calculate.ini
+
+ Параметры:
+ vname имя переменной
+ val значение переменной
+ location расположение ini файла ('default', 'local', 'remote')
+ header раздел ini файла ('client', 'server', 'calculate')
+
+ Возвращаемые значение:
+ True запись успешна
+ False запись не удалсь
+ '''
+ # получаем все пути до ini файлов
+ calculate_ini = self.__getPathCalculateIni()
+ # получаем полный путь до файла ini
+ if location == 'default':
+ name_calculate_ini = calculate_ini[2]
+ elif location == 'local':
+ name_calculate_ini = calculate_ini[1]
+ elif location == 'remote':
+ name_calculate_ini = calculate_ini[0]
+ else:
+ return False
+ # извлекаем из полного имени файла путь
+ onlydir = os.path.split(name_calculate_ini)[0]
+ try:
+ # проверяем чтобы путь до ини файла существовал
+ if not os.path.exists(onlydir):
+ # создаем его если отсутствует
+ os.makedirs(onlydir)
+ except OSError (nerr,msg):
+ print nerr, msg
+ return False
+ config = iniParser(name_calculate_ini)
+ # Получаем секцию конфигурационного файла
+ if not header:
+ header = self.__getSection(vname)
+ return config.setVar(header,{vname: cl_utils.convertStrListDict(val)})
+
+ def __deleteVarValue(self, vname, location, header):
+ '''Удалить переменную в calculate.ini
+
+ Параметры:
+ vname имя переменной
+ location расположение ini файла ('default', 'local', 'remote')
+ header раздел ini файла ('client', 'server', 'calculate')
+
+ Возвращаемые значение:
+ True удалено успешно
+ False удаление не удалсь
+ '''
+ # получаем все пути до ini файлов
+ calculate_ini = self.__getPathCalculateIni()
+ # получаем полный путь до файла ini
+ if location == 'default':
+ name_calculate_ini = calculate_ini[2]
+ elif location == 'local':
+ name_calculate_ini = calculate_ini[1]
+ elif location == 'remote':
+ name_calculate_ini = calculate_ini[0]
+ else:
+ return False
+ # извлекаем из полного имени файла путь
+ onlydir = os.path.split(name_calculate_ini)[0]
+ # проверяем чтобы путь до ини файла существовал
+ if not os.path.exists(onlydir):
+ return False
+ config = iniParser(name_calculate_ini)
+ # Получаем секцию конфигурационного файла
+ if not header:
+ header = self.__getSection(vname)
+ if not header:
+ self.Get(vname)
+ header = self.__getSection(vname)
+ # Удаляем переменную
+ retDelVar = config.delVar(header, vname)
+ retDelArea = True
+ if not config.getAreaVars(header):
+ retDelArea = config.delArea(header)
+ if retDelArea and retDelVar:
+ return True
+ else:
+ return False
+
+ def Write(self, vname, val, force=False, location='default',header=False):
+ '''Установить и записать значение переменной в ini файл
+
+ Параметры:
+ vname имя переменной
+ val значение переменной
+ force "принудительный режим"
+ location расположение ini файла ('default', 'local', 'remote')
+ header раздел ini файла ('client', 'server', 'calculate')
+ '''
+ if self.__Set(vname, val, force)!= False:
+ if not val.strip():
+ self.__deleteVarValue(vname, location, header)
+ self.__writeVarValue(vname, val, location, header)
+ return True
+ return False
+
+ def Delete(self, vname, location='default', header=False):
+ '''Удалить переменную в calculate.ini
+
+ Параметры:
+ vname имя переменной
+ location расположение ini файла ('default', 'local', 'remote')
+
+ Возвращаемые значение:
+ True удалено успешна
+ False удаление не удалсь
+ '''
+ return self.__deleteVarValue(vname, location, header)
+
+ def __getActiveSections(self):
+ """активные секции в ini файле"""
+ act_section = []
+ for service,t,t in self._importList:
+ if service == "Global":
+ act_section.append('calculate')
+ else:
+ act_section.append(service.lower())
+ return act_section
+
+ def flIniFile(self):
+ '''Заместить значение переменных значениями из ини файлов
+
+ Возвращаемые значения:
+ cловарь импортированных переменных - переменные считаны
+ False - файл не был обнаружен
+ '''
+ #Cловарь переменных из ini файлов
+ importVars = {}
+ calculate_ini = self.__getPathCalculateIni()
+ # активные секции (секции из которых будут использованы переменные)
+ act_section = self.__getActiveSections()
+ set_act_section = set(act_section)
+ i = 0
+ locations = ['remote','local','default']
+ for name_calculate_ini in calculate_ini:
+ # проверить сущестование ini файла
+ if os.path.exists(name_calculate_ini):
+ # получить объект настроенный на ini
+ config = iniParser(name_calculate_ini)
+ # получаем все секции из конфигурационного файла
+ allsect = config.getAllSectionNames()
+ if not allsect:
+ continue
+ # находим встречающиеся у обоих секции
+ act_sect = tuple(set(allsect)& set_act_section)
+ # словарь переменных для ini - файла
+ importFileVars = {}
+ # получаем все переменные из всех секций
+ for section in act_sect:
+ allvars = config.getAreaVars(section)
+ if allvars == False:
+ return False
+ # словарь переменных для ini - файла
+ importFileVars = {}
+ # принудительно переписать все переменные окружения
+ # полученные из ini
+ for (k,v) in allvars.items():
+ k = k.encode("UTF-8")
+ value = cl_utils.convertStrListDict(v.encode("UTF-8"))
+ self.Set(k, value, True)
+ importFileVars[k] = value
+ if i < 3:
+ importVars[locations[i]] = importFileVars
+ i += 1
+ return importVars
+
+ def flServer(self, **args):
+ '''Заполнить конфигурацию переменных, для ldap'''
+ # заполнить переменные окружения алгоритмом по умолнанию
+ self._importData("Server")
+
+ def flClient(self, **args):
+ '''Заполнить конфигурацию переменных, для клиента'''
+ # заполнить переменные окружения алгоритмом по умолнанию
+ self._importData("Client")
+
+ def flBuilder(self, **args):
+ '''Заполнить конфигурацию переменных, для билдера'''
+ self.Set('setup_pass','builder',True)
+ # заполнить переменные окружения алгоритмом по умолнанию
+ self._importData("Builder")
+
+ def flInstall(self, **args):
+ '''Заполнить конфигурацию переменных для инсталятора'''
+ self.Set('setup_pass','install',True)
+
+
+ def defined(self, vname):
+ return True
+
+
+
+ def exists(self, nameVar):
+ """ Определяет существует ли переменная с таким имененм
+ """
+ if hasattr(self, nameVar):
+ return True
+ foundVar = False
+ # Ищем переменную в импортируемых модулях
+ for section, moduleVar, fillobj in self._importList:
+ if moduleVar.Data.__dict__.has_key(nameVar):
+ foundVar = True
+ break
+ return foundVar
+
+ def getVars(self, type_names=None):
+ ret = {}
+ for section, moduleVar, fillobj in self._importList:
+ dataVar=moduleVar.Data
+ dictVars = dir(dataVar)
+ for nameVar in dictVars:
+ if not "__" in nameVar:
+ if not (getattr(dataVar,nameVar).has_key("official") and\
+ getattr(dataVar,nameVar)['official']):
+ self.Get(nameVar)
+ if type_names:
+ #type_names.sort()
+ varType =list(getattr(dataVar,nameVar)['type'])
+ #varType.sort()
+ #print type_names
+ #print varType
+ #print
+ if not set(type_names)<=set(varType):
+ continue
+ ret[nameVar] = getattr(self,nameVar)
+ return ret
+
+ #распечатать список переменных с значениями
+ def printVars(self,type_names=None):
+ var=None
+ var=self.getVars(type_names)
+ mlen_name=0;
+ mlen_type=0;
+ mlen_mode=0;
+ for i,j in var.items():
+ if len(i)>mlen_name:
+ mlen_name=len(i)
+ #if len(str(j.type))>mlen_type:
+ #mlen_type=len(str(j.type))
+ vtype=str(type(var[i].value)).split(" ")[1][1]
+ if not '[' in var[i].mode:
+ if vtype in ['d','l']:
+ mode="[%s%s]"%(var[i].mode.lower(),vtype)
+ else:
+ mode="[%s]"%(var[i].mode.lower())
+ var[i].mode=mode
+ if len(mode)>mlen_mode:
+ mlen_mode=len(mode)
+ plist=var.keys()
+ plist.sort()
+ br = cl_utils.fillstr("-",mlen_name) + " " +\
+ cl_utils.fillstr("-",mlen_mode) + " " + cl_utils.fillstr("-",10)
+ #cl_utils.fillstr("-",mlen_type) + " " +\
+
+ print "The list of variables:"
+ print "var name".center(mlen_name),\
+ "Mode","Value"
+ #"Type".center(mlen_type),\
+
+
+ print br
+ for i in plist:
+ #if var[i].value is None:
+ #continue
+ p_val=var[i].value
+ if var[i].official:
+ continue
+ cl_utils.columnWrite( i, mlen_name, var[i].mode.lower(),
+ mlen_mode,
+ #str(var[i].type),
+ #mlen_type,
+ p_val)
+ print br
+##############################################################################
+class glob_attr:
+ """Глобальные аттрибуты для методов заполнения переменных"""
+
+ def _runos(self,cmd, ret_first=None, env={}):
+ """Вернуть результат выполнения команды ОС"""
+ if not env:
+ envDict = {}
+ env.update(os.environ.items() + [("PATH",cl_utils.getpathenv())] +\
+ env.items())
+ retCode, programOut = cl_utils.runOsCommand(cmd, None, ret_first, env)
+ if not retCode:
+ return programOut
+ return False
diff --git a/build/lib/calculate-lib/pym/cl_fill.py b/build/lib/calculate-lib/pym/cl_fill.py
new file mode 100644
index 0000000..c5dea91
--- /dev/null
+++ b/build/lib/calculate-lib/pym/cl_fill.py
@@ -0,0 +1,346 @@
+#-*- coding: utf-8 -*-
+
+# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import re
+import os
+import types
+import cl_utils
+import cl_base
+
+class fillVars(object, cl_base.glob_attr):
+
+ def get_os_net_domain(self):
+ ''' Определим домен'''
+ domain=self._runos("hostname -d 2>&1")
+ if not domain:
+ print _("Error:") + " " +_("Not found domain name")
+ print _("Command 'hostname -d' returns an empty value")
+ cl_base.exit(1)
+ elif re.search("^hostname: ",domain):
+ return "local"
+ else:
+ return domain
+
+ def get_os_linux_shortname(self):
+ '''Получить переменную короткого названия системы'''
+ path = '/etc/calculate/calculate.ini'
+ if os.path.exists(path):
+ FD = open(path)
+ data = FD.readlines()
+ FD.close()
+ shortNameList = filter(lambda y:y,
+ map(lambda x:\
+ len(x.split("="))==2 and\
+ x.split("=")[0]=="calculate" and\
+ x.split("=")[1].strip(), data))
+ if shortNameList:
+ return shortNameList[0]
+ gentooFile = "/etc/gentoo-release"
+ shortName = "Linux"
+ if os.path.exists(gentooFile):
+ shortName = "Gentoo"
+ return shortName
+
+ def get_os_linux_name(self):
+ """полное название системы"""
+ linuxShortName = self.Get("os_linux_shortname")
+ if linuxShortName:
+ dictLinuxName = {"CLD":"Calculate Linux Desktop",
+ "CLDX":"Calculate Linux Desktop",
+ "CLDG":"Calculate Linux Desktop",
+ "CDS":"Calculate Directory Server",
+ "Gentoo":"Gentoo"}
+ if linuxShortName in dictLinuxName.keys():
+ return dictLinuxName[linuxShortName]
+ else:
+ return "Linux"
+ else:
+ return "Linux"
+
+ def get_os_linux_subname(self):
+ """постфикс к названию системы"""
+ linuxShortName = self.Get("os_linux_shortname")
+ if linuxShortName:
+ dictLinuxSubName = {"CLD":"KDE", "CLDX":"XFCE", "CLDG":"GNOME"}
+ if linuxShortName in dictLinuxSubName.keys():
+ return dictLinuxSubName[linuxShortName]
+ else:
+ return ""
+ else:
+ return ""
+
+ def get_os_linux_ver(self):
+ '''Получить версию системы'''
+ path = '/etc/calculate/calculate.ini'
+ if os.path.exists(path):
+ FD = open(path)
+ data = FD.readlines()
+ FD.close()
+ shortNameList = filter(lambda y:y,
+ map(lambda x:\
+ len(x.split("="))==2 and\
+ x.split("=")[0]=="linuxver" and\
+ x.split("=")[1].strip(), data))
+ if shortNameList:
+ return shortNameList[0]
+ gentooFile = "/etc/gentoo-release"
+ systemVersion = ""
+ flagGentoo = False
+ if os.path.exists(gentooFile):
+ gentooLink = "/etc/make.profile"
+ if os.path.islink(gentooLink):
+ systemVersion = os.readlink(gentooLink).rpartition("/")[2]
+ flagGentoo = True
+ if not flagGentoo:
+ kernelVersion=self._runos("uname -r")
+ if kernelVersion:
+ systemVersion = kernelVersion.partition("-")[0]
+ return systemVersion
+
+ def get_os_net_hostname(self):
+ '''Считать имя компьютера net_host'''
+ hostname=self._runos("hostname -s 2>&1")
+ if not hostname:
+ return ""
+ if re.search("^hostname: ",hostname):
+ hostname=self._runos("hostname 2>&1")
+ if not hostname:
+ return ""
+ if re.search("^hostname: ",hostname):
+ return self.Get('os_linux_shortname')
+ else:
+ if hostname=='livecd':
+ return self.Get('os_linux_shortname')
+ return hostname
+
+ # все ip
+ def get_os_net_ip(self):
+ """все ip компьютера, разделитель запятая"""
+ IPs = []
+ netInterfaces=cl_utils.getdirlist("/sys/class/net/")
+ for i in netInterfaces:
+ res = self._runos("/sbin/ifconfig %s"%i)
+ if not res:
+ break
+ for line in res:
+ searchIP = re.search('addr:([0-9\.]+).+Bcast:', line)
+ if searchIP:
+ # ip адрес
+ ip = searchIP.groups()[0]
+ IPs.append(ip)
+ return ",".join(IPs)
+
+ # Разрешенные сети (в данном случае все сети)
+ def get_os_net_allow(self):
+ """Разрешенные сети разделитель запятая"""
+
+ def getNet(ip, mask):
+ """По ip и маске получаем сеть"""
+ octetsMult = (0x1, 0x100, 0x10000, 0x1000000)
+ octetsIp = map(lambda x: int(x), ip.split("."))
+ octetsMask = map(lambda x: int(x), mask.split("."))
+ ipNumb = 0
+ for i in octetsMult:
+ ipNumb += octetsIp.pop()*i
+ maskNumb = 0
+ for i in octetsMult:
+ maskNumb += octetsMask.pop()*i
+ startIpNumber = maskNumb&ipNumb
+ x = startIpNumber
+ nMask = lambda y: len(filter(lambda x: y >> x &1 ,range(32)))
+ return "%s.%s.%s.%s/%s"\
+ %(x>>24, x>>16&255, x>>8&255, x&255, nMask(maskNumb))
+
+ networks=[]
+ netInterfaces=cl_utils.getdirlist("/sys/class/net/")
+ flagError = False
+ for i in netInterfaces:
+ res = self._runos("/sbin/ifconfig %s"%i)
+ if not res:
+ flagError = True
+ break
+ for j in res:
+ s_ip=re.search('addr:([0-9\.]+).+Bcast:.+Mask:([0-9\.]+)' ,j)
+ if s_ip:
+ ip, mask = s_ip.groups()
+ networks.append(getNet(ip, mask))
+ if flagError:
+ return ""
+ return ",".join(networks)
+
+ def get_os_locale_locale(self):
+ """локаль (прим: ru_RU.UTF-8)"""
+ if os.environ.has_key("LANG"):
+ return os.environ["LANG"]
+ else:
+ return "en_US.UTF-8"
+
+ def get_os_locale_lang(self):
+ """язык (прим: ru_RU)"""
+ locale = self.Get("os_locale_locale")
+ if locale:
+ return locale.split(".")[0]
+ return ""
+
+ def get_os_locale_language(self):
+ """язык (прим: ru)"""
+ lang = self.Get("os_locale_lang")
+ if lang:
+ return lang.split("_")[0]
+ return ""
+
+ def get_os_locale_xkb(self):
+ """раскладка клавиатуры для X"""
+ path = '/etc/conf.d/keymaps'
+ mapDict={"by":"us,by",
+ "be-latin1":"be,us",
+ "br-abnt2":"br,us",
+ "cf":"ca,us",
+ "dk-latin1":"dk,us",
+ "fr-latin9":"fr,us",
+ "de-latin1":"de,us",
+ "is-latin1":"is,us",
+ "it":"it,us",
+ "no-latin1":"no,us",
+ "pl":"pl,us",
+ "-u ru4":"us,ru(winkeys)",
+ "es euro2":"es,us",
+ "sv-latin1":"se,us",
+ "ua-utf":"us,ua(winkeys)",
+ "uk":"gb,us",
+ "us":"us"}
+ if os.path.exists(path):
+ FD = open(path)
+ data = FD.readlines()
+ FD.close()
+ shortNameList = filter(lambda y:y,
+ map(lambda x:\
+ len(x.split("="))==2 and\
+ x.split("=")[0]=="KEYMAP" and\
+ x.split("=")[1].replace('"',"").strip(),\
+ data))
+ if shortNameList:
+ if shortNameList[0] in mapDict.keys():
+ return mapDict[shortNameList[0]]
+ lang = self.Get("os_locale_lang")
+ # Языки:
+ # Португальский - pt_BR
+ # Французский - fr_FR
+ # Немецкий - de_DE
+ # Итальянский - it_IT
+ # Польский - pl_PL
+ # Русский - ru_RU
+ # Испанский - es_ES
+ # Украинский - uk_UA
+ # Английский - en_US
+ xkbDict = {'pt_BR':'br,us',
+ 'fr_FR':'fr,us',
+ 'de_DE':'de,us',
+ 'it_IT':'it,us',
+ 'pl_PL':'pl,us',
+ 'ru_RU':'us,ru(winkeys)',
+ 'es_ES':'es,us',
+ 'uk_UA':'us,ua(winkeys)',
+ 'en_US':'us'}
+ if lang:
+ if xkbDict.has_key(lang):
+ return xkbDict[lang]
+ return ""
+
+ def get_os_locale_xkbname(self):
+ """названия используемых раскладок клавиатуры для X"""
+ localeXkb = self.Get("os_locale_xkb")
+ if localeXkb:
+ return localeXkb.split("(")[0]
+ return ""
+
+ def get_os_arch_machine(self):
+ """архитектура процессора"""
+ march = self._runos("uname -m")
+ if not march:
+ return ""
+ return march
+
+ def get_os_root_dev(self):
+ """корневой раздел файловой системы"""
+ for record in open('/proc/cmdline','rb').readlines():
+ re_res=re.search('^root=(\/dev\/[a-z]+[0-9]).*',record.strip())
+ if re_res:
+ return re_res.group(1)
+ else:
+ mountLunes = self._runos("mount")
+ if not mountLunes:
+ return ""
+ if type(mountLunes) == types.ListType:
+ root_dev = mountLunes[0].split("on / type")[0].strip()
+ if root_dev:
+ return root_dev
+ return ""
+
+ def get_os_root_type(self):
+ """тип носителя (ram, hdd, livecd)"""
+ mountLunes = self._runos("mount")
+ if not mountLunes:
+ return ""
+ rootType = "hdd"
+ if type(mountLunes) == types.ListType:
+ flagCD = False
+ for line in mountLunes:
+ if "/dev/loop0 on / type" in line:
+ rootType = "ram"
+ break
+ elif "/dev/loop0 on /newroot/mnt/livecd type" in line:
+ rootType = "ram"
+ flagCD = True
+ break
+ if rootType == "ram":
+ if os.path.exists("/mnt/livecd") or flagCD:
+ rootType = "livecd"
+ return rootType
+ rootDev = self.Get("os_root_dev")
+ if rootType != "ram" and rootDev:
+ slpRootDev = rootDev.split("/dev/")
+ if len(slpRootDev) == 2:
+ rDev = slpRootDev[1]
+ devLines = self._runos("ls -la /dev/disk/by-id/", None,
+ {"LANG":"C"})
+ if not devLines:
+ return ""
+ if type(devLines) == types.ListType:
+ for line in devLines:
+ if rDev in line and "usb-" in line:
+ rootType = "usb-hdd"
+ break
+ if rootType == "ram":
+ rootType = "hdd"
+ return rootType
+ else:
+ return ""
+
+ def get_hr_virtual(self):
+ """Название виртуальной машины (virtualbox, vmware, qemu)"""
+ pciLines = self._runos("/usr/sbin/lspci")
+ if not pciLines:
+ return False
+ virtSysDict = {'VirtualBox':'virtualbox',
+ 'VMware':'vmware',
+ 'Qumranet':'qemu'}
+ virtName = ''
+ for vName in virtSysDict.keys():
+ if filter(lambda x: vName in x, pciLines):
+ virtName = virtSysDict[vName]
+ break
+ return virtName
diff --git a/build/lib/calculate-lib/pym/cl_log.py b/build/lib/calculate-lib/pym/cl_log.py
new file mode 100644
index 0000000..46acdf7
--- /dev/null
+++ b/build/lib/calculate-lib/pym/cl_log.py
@@ -0,0 +1,59 @@
+#-*- coding: utf-8 -*-
+
+# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import os
+import time
+
+class log():
+ """Класс для записи в лог"""
+ # Директория хранения логов
+ logDir = "/var/log/calculate"
+ def __init__(self,fileName, addDataTime=True):
+ self.logFile = os.path.join(self.logDir,fileName)
+ if not os.path.exists(self.logDir):
+ os.makedirs(self.logDir)
+ self.addDataTime = addDataTime
+
+ def addLog(self, textLog):
+ """Добавляет текст в лог файл"""
+ if not os.path.exists(self.logFile):
+ try:
+ fd = os.open(self.logFile, os.O_CREAT,0600)
+ os.close(fd)
+ except:
+ print "Error creating file %s"%self.logFile
+ return False
+ textWrite = textLog
+ if not textLog[-1:] == "\n" :
+ textWrite = "%s\n"%textLog
+ if self.addDataTime:
+ textWrite = "%s %s"%(time.strftime("%d/%m/%Y %H:%M:%S",\
+ time.localtime()),textWrite)
+ try:
+ FD = open (self.logFile, "a")
+ FD.write(textWrite)
+ FD.close()
+ except:
+ print "Error writing to file %s"%self.logFile
+ return False
+ return True
+
+ def writeError(self, textLog):
+ """Добавляет сообщение об ошибке в log"""
+ return self.addLog("ERROR: %s" %textLog)
+
+ def writeSuccess(self, textLog):
+ """Добавляет сообщение об успехе в log"""
+ return self.addLog("SUCCESS: %s" %textLog)
diff --git a/build/lib/calculate-lib/pym/cl_profile.py b/build/lib/calculate-lib/pym/cl_profile.py
new file mode 100644
index 0000000..8d8ab64
--- /dev/null
+++ b/build/lib/calculate-lib/pym/cl_profile.py
@@ -0,0 +1,7136 @@
+#-*- coding: utf-8 -*-
+
+# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+import os
+import cl_base
+import stat
+import re
+import xml.dom.minidom
+from xml import xpath
+import subprocess
+import types
+import copy
+import random
+import string
+import time
+
+tr = cl_base.lang()
+tr.setLocalDomain('cl_lib')
+tr.setLanguage(sys.modules[__name__])
+
+
+class _error:
+ # Здесь ошибки, если они есть
+ error = []
+ def getError(self):
+ """Выдать ошибки"""
+ if not self.error:
+ return False
+ error = ""
+ for e in self.error:
+ error += e + "\n"
+ return error
+
+ def setError(self, error):
+ """Установка ошибки"""
+ self.error.append(error)
+ return True
+
+
+class _terms(_error):
+ """Вычисление условий применяемых в профилях
+
+ """
+ # регулярное выражение для не версии
+ _re_not_Version = re.compile("[^0-9\.]|^$")
+ # регулярное выражение для функции
+ _reFunction = re.compile(\
+ "([a-zA-Z0-9\_\-]+)\([a-zA-Z0-9_\-\+\,\*\/\.\'\"~]+\)")
+ # Регулярное выражение для названия переменной
+ _reDenyName = re.compile("[^a-zA-Z0-9\_\-]")
+ # Регулярное выражение для сравниваемого значения
+ _reDenyValue = re.compile("[^0-9a-zA-Z_\.-]")
+
+ def _convertVers(self, verA, verB):
+ """Конвертирование номеров версий для корректного сравнения
+ """
+ elemA = verA.split(".")
+ elemB = verB.split(".")
+ if len(elemA) > len(elemB):
+ maxElemB = len(elemB)-1
+ for i in range(len(elemA)):
+ if i > maxElemB:
+ elemB.append("0")
+ else:
+ maxElemA = len(elemA)-1
+ for i in range(len(elemB)):
+ if i > maxElemA:
+ elemA.append("0")
+ for i in range(len(elemB)):
+ lenA = len(elemA[i])
+ lenB = len(elemB[i])
+ if lenA == lenB:
+ pass
+ elif lenA > lenB:
+ res = lenA - lenB
+ for z in range(res):
+ elemB[i] = "0" + elemB[i]
+ elif lenB > lenA:
+ res = lenB - lenA
+ for z in range(res):
+ elemA[i] = "0" + elemA[i]
+ return (".".join(elemA), ".".join(elemB))
+
+ def _equalTerm(self, term, textError, function=False):
+ """Вычисление логических выражений для условий
+
+ Для корректной работы в классе который наследует этот класс
+ должен быть объявлен аттрибут self.objVar
+ (объект для работы с переменными)
+ function - функция для для обработки функций в заголовке блока
+ """
+ trm = {"&":" and ","||":" or "}
+ rule = ["==", "!=", ">=", "<=", ">", "<"]
+ listEqual = []
+ for k in trm.keys():
+ if k in term:
+ term = term.replace(k,trm[k])
+ trs = term.split(" ")
+ for t in trs:
+ flagRule = False
+ for sepF in rule:
+ if sepF in t:
+ flagRule = True
+ vals = t.split(sepF)
+ break
+
+ if not flagRule:
+ flagLog = False
+ for k in trm.values():
+ if k.strip() == t:
+ flagLog = True
+ break
+ if not flagLog:
+ self.setError("'%s'"%term + " " + _("incorrect"))
+ self.setError (textError)
+ return False
+ else:
+ listEqual.append(k)
+ else:
+ #проверка на допустимость названия переменной
+ flagFunction = False
+ if self._reDenyName.search(vals[0]):
+ #проверка на допустимость функции
+ flagError = True
+ if function:
+ searchFunct = self._reFunction.search(vals[0])
+ if searchFunct:
+ flagError = False
+ flagFunction = True
+ if flagError:
+ self.setError("'%s'"%term + " " + _("incorrect"))
+ self.setError(textError)
+ return False
+ #проверка на допустимость значения
+ if self._reDenyValue.search(vals[1]):
+ self.setError("'%s'"%term + " " + _("incorrect"))
+ self.setError(textError)
+ return False
+ flagIntTypeVar = None
+ if flagFunction:
+ valVars = function("#-%s-#"%vals[0])
+ if valVars is False:
+ self.setError("'%s'"%term + " " + _("incorrect"))
+ self.setError(textError)
+ return False
+ if "load" == searchFunct.group(1):
+ if re.search("\(\s*num\s*,",vals[0]):
+ if valVars:
+ try:
+ valVars = int(valVars)
+ except:
+ self.setError("'%s'"%term + " " + \
+ _("incorrect"))
+ self.setError (textError)
+ return False
+ flagIntTypeVar = True
+ else:
+ flagIntTypeVar = False
+ else:
+ if valVars == "" and\
+ not self._re_not_Version.search(vals[1]):
+ valVars = "0"
+ elif vals[1] == "" and\
+ not self._re_not_Version.search(valVars):
+ vals[1] = "0"
+ else:
+ try:
+ valVars = self.objVar.Get(vals[0])
+ except self.objVar.DataVarsError, e:
+ print textError
+ print e
+ cl_base.exit(1)
+ # Номера версий для ini
+ flagNotIniFunct = True
+ # Два значения не пусты
+ flagNotEmptyVals = not (valVars == "" and vals[1] == "")
+ if flagFunction and flagNotEmptyVals and\
+ searchFunct.group(1) == "ini":
+ # Проверка значения на версию
+ if not self._re_not_Version.search(valVars) and\
+ not self._re_not_Version.search(vals[1]):
+ verFile, verVar = self._convertVers(vals[1],valVars)
+ exec(\
+ "res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")")
+ if res:
+ listEqual.append("1")
+ else:
+ listEqual.append("0")
+ flagNotIniFunct = False
+ # Cравниваем номера версий
+ if flagNotIniFunct:
+ if flagNotEmptyVals and\
+ ("_ver" in vals[0] or\
+ (flagFunction and searchFunct.group(1) == "pkg") or\
+ (flagFunction and searchFunct.group(1) == "load" and\
+ re.search("\(\s*ver\s*,",vals[0]))):
+ # Проверка значения на версию
+ if self._re_not_Version.search(vals[1]):
+ self.setError("'%s'"%term + " " + _("incorrect"))
+ self.setError (_("Value is not version"))
+ return False
+ # Проверка значения функции на версию
+ if self._re_not_Version.search(valVars):
+ self.setError("'%s'"%term + " " + _("incorrect"))
+ self.setError (_("Value function is not version"))
+ return False
+ verFile, verVar = self._convertVers(vals[1],valVars)
+ exec("res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")")
+ if res:
+ listEqual.append("1")
+ else:
+ listEqual.append("0")
+ flagNotIniFunct = False
+ else:
+ if flagIntTypeVar == None:
+ flagIntTypeVar = True
+ try:
+ valVars = int(valVars)
+ except:
+ flagIntTypeVar = False
+ if flagIntTypeVar:
+ if not vals[1].strip():
+ vals[1] = 0
+ try:
+ valFile = int(vals[1])
+ except:
+ self.setError("'%s'"%term +" " +_("incorrect"))
+ self.setError (textError)
+ return False
+ valVar = valVars
+ exec("res=(%d%s%d)"%(valVar,sepF,valFile))
+ if res:
+ listEqual.append("1")
+ else:
+ listEqual.append("0")
+ else:
+ if sepF == "!=" or sepF == "==":
+ if not vals[1].strip():
+ vals[1] = ""
+ valFile = vals[1]
+ valVar = valVars
+ exec(\
+ "res=("+'"""'+valVar+'"""'+sepF+"'"+valFile+\
+ "'"+")")
+ if res:
+ listEqual.append("1")
+ else:
+ listEqual.append("0")
+ else:
+ if not flagNotEmptyVals:
+ listEqual.append("0")
+ else:
+ self.setError("'%s'"%term + " "\
+ + _("incorrect"))
+ self.setError (textError)
+ return False
+ exec("res=(%s)"%("".join(listEqual)))
+ return res
+
+class fileHeader(_terms):
+ """Обработка заголовков профилей и конфигурационных файлов
+
+ """
+ # Допустимые параметры заголовка
+ allowParam = ["format", "format_conf", "comment", "append", "force",
+ "link", "mirror", "symbolic", "chmod", "chown", "name"]
+ # Корректность заголовка
+ headerCorrect = True
+
+ # Тип профиля
+ fileType = ""
+ # Тип вставки профиля
+ typeAppend = ""
+ # Возможные типы вставки профилей
+ _fileAppend = "join", "before", "after", "replace", "remove"
+ # Интерпретатор (#!/bin/bash) (#!/usr/bin/python)
+ execStr = ""
+ # Символ комментария
+ comment = False
+ # Выражение для поиска строки интерпретатора
+ reExecStr = re.compile("^#!.+\s*",re.I)
+ # условные операторы
+ terms = ('>', '<', '==', '!=', '>=', '<=')
+ # параметры без значения
+ listParNotVal = ("symbolic", "force", "mirror")
+ # Результат вычисления условия в заголовке
+ headerTerm = True
+ # Сообщение о ошибке
+ errorMessage = ""
+
+ def __init__(self, text, comment=False, fileType=False, objVar=False,
+ function=False):
+ self.body = text
+ # Объект с переменными
+ self.objVar=objVar
+ # Параметры описанные в заголовке файла профиля
+ self.params = {}
+ # некорректные параметры
+ incorrectParams = set([])
+ # Удаление Заголовка Calculate
+ if comment:
+ # В случае текста XML
+ if type(comment) == types.TupleType and len(comment) == 2:
+ _titleList = (_("Modified"), _("File of a profile"))
+ reCalcHeader =\
+ re.compile(u"\s*%s\s+%s.+Calculate.+\s+%s.+\s+%s\s?"%(\
+ comment[0],
+ _titleList[0].decode("UTF-8"),
+ _titleList[1].decode("UTF-8"),
+ comment[1],
+ ),
+ re.M|re.I|re.U)
+ textUnicode = text.decode("UTF-8")
+ reS = reCalcHeader.search(textUnicode)
+ if reS:
+ textBody = textUnicode[:reS.start()]+textUnicode[reS.end():]
+ if textBody:
+ self.body = textBody.encode("UTF-8")
+ else:
+ reCalcHeader =\
+ re.compile("\s*%s\-+\s+%s.+Calculate.+\s+%s.+\s+%s\-+\s?"%(\
+ comment,
+ comment,
+ comment,
+ comment,
+ ),
+ re.M|re.I)
+ reS = reCalcHeader.search(text)
+ if reS:
+ self.body = text[reS.end():]
+
+ if fileType != False:
+ if fileType=="bin":
+ self.params["format"] = fileType
+ self.fileType = self._getType()
+ self.typeAppend = self._getAppend()
+ else:
+ textLines = text.splitlines()
+ if textLines:
+ textLine = textLines[0]
+ rePar = re.compile("\s*#\s*calculate\s+",re.I)
+ reP = rePar.search(textLine)
+ if reP:
+ reL = False
+ reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
+ reLs = reLns.search(text)
+ if reLs:
+ reL = reLs
+ paramLine = text[reP.end():reLs.end()]
+ paramLine = paramLine.replace("\\"," ")
+ else:
+ reLn = re.compile("\n")
+ reL = reLn.search(text)
+ paramLine = textLine[reP.end():]
+ if reL:
+ self.body = text[reL.end():]
+ else:
+ self.body = ""
+ paramList = re.split("\s+",paramLine)
+ if paramList:
+ for i in paramList:
+ foundTerm = False
+ for term in self.terms:
+ if term in i:
+ foundTerm = True
+ if function:
+ rezTerm = self._equalTerm(i,\
+ _("header profile not valid: ") + \
+ i,function)
+ else:
+ rezTerm = self._equalTerm(i,\
+ _("header profile not valid: ") + \
+ i)
+ if not rezTerm:
+ self.headerTerm = False
+ break
+ if not foundTerm:
+ par = i.split("=")
+ if len(par) == 1:
+ if i in self.listParNotVal:
+ self.params[i] = "True"
+ else:
+ if i.strip():
+ incorrectParams = set([i])
+ elif len(par) == 2:
+ self.params[par[0]] = par[1]
+
+ self.comment = self._getComment()
+ self.fileType = self._getType()
+ self.typeAppend = self._getAppend()
+ reExecRes = self.reExecStr.search(self.body)
+ if reExecRes:
+ self.execStr = self.body[reExecRes.start():reExecRes.end()]
+ self.body = self.body[reExecRes.end():]
+ if not incorrectParams:
+ incorrectParams = set(self.params.keys()) - set(self.allowParam)
+ if incorrectParams:
+ self.headerTerm = False
+ self.headerCorrect = False
+ self.errorMessage = _("incorrect header parameters - '%s'")\
+ % " ".join(list(incorrectParams))
+
+ def _getType(self):
+ """Выдать тип файла"""
+ if self.params.has_key("format"):
+ return self.params["format"]
+ else:
+ return "raw"
+
+ def _getAppend(self):
+ """Выдать тип добавления файла"""
+ if self.params.has_key("append") and self.params["append"] in\
+ self._fileAppend:
+ return self.params["append"]
+ else:
+ if self.fileType != "raw" and self.fileType != "bin" and\
+ self.fileType != "":
+ self.params["append"] = "join"
+ return "join"
+ self.params["append"] = "replace"
+ return "replace"
+
+ def _getComment(self):
+ """Выдать символ комментария файла"""
+ if self.params.has_key("comment"):
+ return self.params["comment"]
+ else:
+ return False
+
+
+class dirHeader(_terms):
+ """Обработка заголовков профилей директорий
+
+ """
+ # Допустимые параметры заголовка
+ allowParam = ["append", "chmod", "chown", "name"]
+ # Корректность заголовка
+ headerCorrect = True
+
+ # Тип вставки профиля
+ typeAppend = ""
+ # Возможные типы вставки профилей
+ _fileAppend = "join", "remove"
+ # условные операторы
+ terms = ('>', '<', '==', '!=', '>=', '<=')
+ # параметры без значения
+ listParNotVal = ("symbolic", "force")
+ # Результат вычисления условия в заголовке
+ headerTerm = True
+ # Сообщение о ошибке
+ errorMessage = ""
+
+ def __init__(self, text, objVar=False, function=False):
+ self.body = text
+ # Объект с переменными
+ self.objVar=objVar
+ # Параметры описанные в заголовке файла профиля
+ self.params = {}
+ # некорректные параметры
+ incorrectParams = set([])
+
+ textLines = text.splitlines()
+ flagErrorBody = False
+ if textLines:
+ textLine = textLines[0]
+ rePar = re.compile("\s*#\s*calculate\s+",re.I)
+ reP = rePar.search(textLine)
+ if reP:
+ reL = False
+ reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M)
+ reLs = reLns.search(text)
+ if reLs:
+ reL = reLs
+ paramLine = text[reP.end():reLs.end()]
+ paramLine = paramLine.replace("\\"," ")
+ else:
+ reLn = re.compile("\n")
+ reL = reLn.search(text)
+ paramLine = textLine[reP.end():]
+ if reL:
+ self.body = text[reL.end():]
+ else:
+ self.body = ""
+ if self.body.strip():
+ self.headerTerm = False
+ self.headerCorrect = False
+ self.errorMessage = _("incorrect text in profile: '%s'")\
+ %self.body
+ flagErrorBody = True
+ if not flagErrorBody:
+ paramList = re.split("\s+",paramLine)
+ if paramList:
+ for i in paramList:
+ foundTerm = False
+ for term in self.terms:
+ if term in i:
+ foundTerm = True
+ if function:
+ rezTerm = self._equalTerm(i,\
+ _("header profile not valid: ") + \
+ i,function)
+ else:
+ rezTerm = self._equalTerm(i,\
+ _("header profile not valid: ") + \
+ i)
+ if not rezTerm:
+ self.headerTerm = False
+ break
+ if not foundTerm:
+ par = i.split("=")
+ if len(par) == 1:
+ if i in self.listParNotVal:
+ self.params[i] = "True"
+ else:
+ if i.strip():
+ incorrectParams = set([i])
+ elif len(par) == 2:
+ self.params[par[0]] = par[1]
+ self.typeAppend = self._getAppend()
+ if not flagErrorBody:
+ if not incorrectParams:
+ incorrectParams = set(self.params.keys()) - set(self.allowParam)
+ if incorrectParams:
+ self.headerTerm = False
+ self.headerCorrect = False
+ self.errorMessage = _("incorrect header parameters - '%s'")\
+ % " ".join(list(incorrectParams))
+
+ def _getAppend(self):
+ """Выдать тип добавления директории"""
+ if self.params.has_key("append") and self.params["append"] in\
+ self._fileAppend:
+ return self.params["append"]
+ else:
+ return "join"
+
+class objShare:
+ """Общий клас для объектов, наследуем
+
+ """
+
+ def createFieldTerm(self, name, value, quote, docObj):
+ """Создание поля переменная - значение
+
+ при создании поля проверяется первый символ названия переменной
+ и добавляется тег action
+ "!" - drop удаляет
+ "+" - join добавляет
+ "-" - replace заменяет
+ """
+ fieldAction = False
+ if name:
+ if name[0] == "!" or name[0] == "-" or name[0] == "+":
+ qnt = self.removeSymbolTerm(quote)
+ fieldXML = docObj.createField("var",[qnt],
+ name[1:], [value],
+ False, False)
+ if name[0] == "!":
+ fieldAction = "drop"
+ elif name[0] == "+":
+ fieldXML.setAttribute("type", "seplist")
+ fieldAction = "join"
+ else:
+ fieldXML = docObj.createField("var",
+ [quote.replace("\n","")],
+ name, [value],
+ False, False)
+ else:
+ fieldXML = docObj.createField("var",
+ [quote.replace("\n","")],
+ name, [value],
+ False, False)
+ if fieldAction:
+ docObj.setActionField(fieldXML, fieldAction)
+ return fieldXML
+
+ def removeSymbolTerm(self, text):
+ """Удаляет первый символ названия переменной в строке
+
+ Если первый встречающийся символ с начала строки
+ '+', '-', '!' то он из этой строки будет удален,
+ если перед этим символом были пробельные символы,
+ то они будут сохранены, так-же если в строке есть символ
+ перевода строки он будет удален.
+ """
+ reTerm = re.compile("^[ \t]*(\!|\+|\-)")
+ textNS = text.replace("\n","")
+ res = reTerm.search(textNS)
+ if res:
+ textNS = textNS[res.start():res.end()-1] + textNS[res.end():]
+ return textNS
+
+ def getConfig(self):
+ """Выдает конфигурационный файл"""
+ listConfigTxt = []
+ childNodes = self.docObj.getNodeBody().childNodes
+ for node in childNodes:
+ if node.nodeType == node.ELEMENT_NODE:
+ if node.tagName == "field":
+ listConfigTxt.append(self.docObj.getQuoteField(node))
+ elif node.tagName == "area":
+ self.docObj.xmlToText([node], listConfigTxt)
+ return "".join(listConfigTxt)
+
+
+ def splitToFields(self, txtBloc):
+ """Разбиваем текст на поля (объекты) которые имеют следующие аттрибуты
+
+ self.name - если переменная то имя переменной
+ self.value - если у переменной есть значение то значение переменной
+ self.comment - если комментарий то текст комментария
+ self.br - если перевод строки то текст перед переводом из пробелов
+
+ Результат список объектов полей
+ """
+ finBloc = "\n"
+ if txtBloc[-1] != "\n":
+ finBloc = ""
+
+ linesBlocTmp = txtBloc.splitlines()
+ linesBloc = []
+ brBloc = []
+ z = 0
+ lenLines = len(linesBlocTmp)
+ for i in linesBlocTmp:
+
+ if self.reComment.split(i)[0]:
+ findCooment = self.reComment.search(i)
+ comment = False
+ par = i
+ if findCooment:
+ par = i[:findCooment.start()]
+ comment = i[findCooment.start():]
+ fields = self.reSepFields.split(par)
+ lenFields = len(fields)
+
+ if lenFields>1:
+ for fi in range(lenFields-1):
+ linesBloc.append(fields[fi]+ self.sepFields)
+ if fi == lenFields-2:
+ if comment:
+ brBloc.append("")
+ else:
+ if (lenLines-1)== z:
+ brBloc.append(finBloc)
+ else:
+ brBloc.append("\n")
+ else:
+ brBloc.append("")
+ if comment:
+ linesBloc.append(comment)
+ if (lenLines-1)== z:
+ brBloc.append(finBloc)
+ else:
+ brBloc.append("\n")
+ else:
+ linesBloc.append(i)
+ if (lenLines-1)== z:
+ brBloc.append(finBloc)
+ else:
+ brBloc.append("\n")
+ else:
+ linesBloc.append(i)
+ if (lenLines-1)== z:
+ brBloc.append(finBloc)
+ else:
+ brBloc.append("\n")
+ z +=1
+ fields = self.setDataField(linesBloc, brBloc)
+ return fields
+
+class xmlShare:
+ """Общий класс для объектов XML, наследуем
+
+ """
+ def _createElement(self, doc, tagName, text="", attributes={}):
+ """Создание нового XML элемента"""
+ element = doc.createElement(tagName)
+ if text:
+ txtNode = doc.createTextNode(self._toUNICODE(text))
+ element.appendChild(txtNode)
+ for attr in attributes.keys():
+ attribute = doc.createAttribute(attr)
+ attribute.nodeValue = attributes[attr]
+ element.setAttributeNode(attribute)
+ return element
+
+ def _toUNICODE(self,val):
+ """перевод текста в юникод"""
+ if 'unicode' in "%s" %(type(val)):
+ return val
+ else:
+ return val.decode('UTF-8')
+
+
+class xmlNode(xmlShare):
+ """Класс для создания нод без аттрибутов
+
+ """
+ def __init__(self):
+ self.node = False
+
+
+ def createNode(self, doc, tagName, text=""):
+ """Создает XML элемент без аттрибутов"""
+ self.node=self._createElement(doc, tagName, text)
+ return self.node
+
+ def getNode(self):
+ return self.node
+
+
+class xmlCaption:
+ """Класс XML заголовок
+
+ """
+ def __init__(self):
+ #Заголовок области XML нода
+ self.caption = False
+
+
+ def createCaption(self, doc, name, quotes, action=False):
+ """Создание заголовка области"""
+ tmpNode = xmlNode()
+ self.caption = tmpNode.createNode(doc, "caption")
+ nameNode = tmpNode.createNode(doc, "name",name)
+ self.caption.appendChild(nameNode)
+ if action:
+ actNode = tmpNode.createNode(doc, "action", action)
+ self.caption.appendChild(actNode)
+ for q in quotes:
+ quoteNode = tmpNode.createNode(doc, "quote", q)
+ self.caption.appendChild(quoteNode)
+ return self.caption
+
+ def getCaption(self):
+ """Выдает XML ноду заголовка области"""
+ return self.caption
+
+class xmlField(xmlShare):
+ """Класс для работы с XML полем
+
+ """
+ def __init__(self):
+ # XML нода поле
+ self.field = False
+
+
+ def createField(self, doc, typeField, quotes, name="",
+ values=[],action=False):
+ """Cоздание XML ноды поле"""
+ self.field = self._createElement(doc, "field", "", {"type":typeField})
+ if name:
+ nameNode = self._createElement(doc, "name", name)
+ self.field.appendChild(nameNode)
+ for v in values:
+ valueNode = self._createElement(doc, "value", v)
+ self.field.appendChild(valueNode)
+ if action:
+ actNode = self._createElement(doc, "action", action)
+ self.field.appendChild(actNode)
+ for q in quotes:
+ quoteNode = self._createElement(doc, "quote", q)
+ self.field.appendChild(quoteNode)
+ return self.field
+
+
+
+class xmlFields:
+ """Класс, в котором находится список ХМL нод field
+
+ """
+ def __init__(self):
+ self.fields = []
+
+ def appendField(self, field):
+ """Добавить XML ноду field"""
+ self.fields.append(field)
+ return self.fields
+
+ def getFields(self):
+ """Выдать список XML нод"""
+ return self.fields
+
+
+class xmlArea:
+ """Класс для работы с XML областью
+
+ """
+ def __init__(self):
+ # Область
+ self.area = False
+
+ def createArea(self, doc, xmlCaption, xmlFields):
+ """Создание XML области"""
+ tmpNode = xmlNode()
+ self.area = tmpNode.createNode(doc, "area")
+ if xmlCaption and xmlCaption.getCaption():
+ self.area.appendChild(xmlCaption.getCaption())
+ if xmlFields:
+ fields = xmlFields.getFields()
+ for field in fields:
+ self.area.appendChild(field)
+ return self.area
+
+class xmlDoc:
+ """Класс для работы с XML документом
+
+ """
+ def __init__(self):
+ # документ
+ self.doc = False
+ # главная нода
+ self.root = False
+ # тело документа
+ self.body = False
+ # Заголовок области - временный (в реальности один объект заголовок)
+ self.tmpCaption = False
+ # Поля - временные (в реальности один объект поля)
+ self.tmpFields = False
+ # Разделитель областей - по умолчанию перевод строки "\n"
+ self.sepAreas = False
+ # Разделитель разделенных списков - по умолчанию перевод строки "\n"
+ #self.sepSplitFields = False
+
+
+ def createDoc(self, typeDoc, version):
+ """Создание нового документа новый документ"""
+ docTxt = ''
+ docTxt += '%s'% version
+ docTxt += '%s' % typeDoc
+ docTxt += ''
+ self.doc = xml.dom.minidom.parseString(docTxt)
+ self.root = self.doc.documentElement
+ self.body = xpath.Evaluate('child::body',self.root)[0]
+ # установка разделителя областей
+ self.sepAreas = self.createField("br",[],"",[],False,False)
+ # установка разделителя областей разделенных списков
+ #self.sepSplitFields = self.createField("br",[],"",[],False,False)
+ return self.doc
+
+ def addField(self, field):
+ """Добавляет поле во временный список
+
+ Из этого списка в дальнейшем формируется XML область
+ """
+ if not self.tmpFields:
+ self.tmpFields = xmlFields()
+ self.tmpFields.appendField(field)
+
+ def createCaption(self, name, quotes, action=False):
+ """Cоздает заголовок области
+
+ Помещает заголовок в временный артибут
+ Используется при создании области
+ """
+ self.tmpCaption = xmlCaption()
+ return self.tmpCaption.createCaption(self.doc, name, quotes, action)
+
+ def createField(self, typeField, quotes=[], name="",
+ values=[] ,action=False,addTmpField=True):
+ """Cоздает поле
+
+ Если установлена переменнная addTmpField
+ добавляет поле во временный список
+ """
+ fieldObj = xmlField()
+ field = fieldObj.createField(self.doc, typeField, quotes, name,
+ values, action)
+ if addTmpField:
+ self.addField(field)
+ return field
+
+ def clearTmpFields(self):
+ """Очищает временный список"""
+ self.tmpFields = False
+
+ def createArea(self):
+ """Cоздает область
+
+ Область создается на основании временного атрибута и временного списка
+ """
+ areaObj = xmlArea()
+ area = areaObj.createArea(self.doc, self.tmpCaption, self.tmpFields)
+ self.clearTmpCaptionAndFields()
+ return area
+
+ def clearTmpCaptionAndFields(self):
+ """Очищает временный аттрибут и временный список"""
+ self.tmpCaption = False
+ self.tmpFields = False
+
+ def getNodeRoot(self):
+ """Выдает корневую ноду"""
+ return self.root
+
+ def getNodeBody(self):
+ """Выдает ноду body"""
+ return self.body
+
+ def setActionField(self, xmlField, actionTxt):
+ """Устанавливает свойство action для XML поля"""
+ xmlActions = xpath.Evaluate('child::action',xmlField)
+ if xmlActions and xmlActions[0].firstChild:
+ xmlActions[0].firstChild.nodeValue = actionTxt
+ else:
+ nodeObj = xmlNode()
+ newNode = nodeObj.createNode(self.doc, "action", actionTxt)
+ xmlField.appendChild(newNode)
+
+
+ def setActionArea(self, xmlArea, actionTxt):
+ """Устанавливает свойство action для XML области"""
+ xmlActions = xpath.Evaluate('child::caption/action',xmlArea)
+ xmlCaptions = xpath.Evaluate('child::caption',xmlArea)
+ if xmlActions and xmlActions[0].firstChild:
+ xmlActions[0].firstChild.nodeValue = actionTxt
+ else:
+ if xmlCaptions:
+ nodeObj = xmlNode()
+ newNode = nodeObj.createNode(self.doc, "action", actionTxt)
+ xmlCaptions[0].appendChild(newNode)
+
+ def joinField(self, xmlArea, xmlNewField):
+ """Объединяет XML ноду область и XML ноду поле"""
+ newNameField = self.getNameField(xmlNewField)
+ if not newNameField or not newNameField.strip():
+ return False
+ fieldsOldComp = xpath.Evaluate("child::field[child::name='%s']"\
+ %(newNameField), xmlArea)
+ # Если поле не найдено добавляем его
+ typeNewField = self.getTypeField(xmlNewField)
+ if not fieldsOldComp and typeNewField != "seplist":
+ if self.getActionField(xmlNewField) != "drop":
+ self.setActionField(xmlNewField, "append")
+ xmlArea.appendChild(xmlNewField)
+ return True
+ newFieldsAction = self.getActionField(xmlNewField)
+ newValues = self.getFieldValues(xmlNewField)
+ flagCompare = True
+
+ for nodeFieldOld in fieldsOldComp:
+ if newFieldsAction == "drop":
+ if nodeFieldOld.nextSibling and\
+ self.getTypeField(nodeFieldOld.nextSibling) == "br":
+ xmlArea.removeChild(nodeFieldOld.nextSibling)
+ elif nodeFieldOld.previousSibling and\
+ self.getTypeField(nodeFieldOld.previousSibling) == "br":
+ xmlArea.removeChild(nodeFieldOld.previousSibling)
+ xmlArea.removeChild(nodeFieldOld)
+ continue
+ oldValues = self.getFieldValues(nodeFieldOld)
+ # Сравнение значений переменной профиля и файла
+ if set(newValues) != set(oldValues):
+ flagCompare = False
+ if self.getActionField(xmlNewField) == "drop":
+ return True
+ appSplLst = []
+ insSplLst = []
+ if typeNewField == "seplist":
+ if fieldsOldComp:
+ xmlOldField = fieldsOldComp[-1]
+ else:
+ xmlOldField = False
+ seplistNewXML = self.getSepListToField(xmlNewField)
+ if seplistNewXML:
+ for nodeSeplist in seplistNewXML:
+ if self.getActionField(nodeSeplist) != "drop":
+ if newFieldsAction == "join":
+ flagCompareSeplist = False
+ newValues = self.getFieldValues(nodeSeplist)
+ for nodeFieldOld in fieldsOldComp:
+ oldValues = self.getFieldValues(nodeFieldOld)
+ for newValue in newValues:
+ if newValue in oldValues:
+ flagCompareSeplist = True
+ break
+ if not flagCompareSeplist:
+ nextNode = xmlOldField.nextSibling
+ newInsNode = nodeSeplist.cloneNode(True)
+ self.setActionField(newInsNode,"append")
+
+ if nextNode:
+ appSplLst.append((newInsNode,
+ nextNode,
+ "insert"))
+ else:
+ appSplLst.append((newInsNode,
+ False,
+ "append"))
+ else:
+ newInsNode = nodeSeplist.cloneNode(True)
+ if self.getActionField(newInsNode) == "join":
+ self.setActionField(newInsNode,"append")
+ if xmlOldField:
+ insSplLst.append((newInsNode,
+ xmlOldField,
+ "insert"))
+ else:
+ insSplLst.append((newInsNode,
+ False,
+ "append"))
+
+ #xmlArea.insertBefore(\
+ #nodeSeplist.cloneNode(True),
+ #xmlOldField)
+
+ parentNode = nodeSeplist.parentNode
+ parentNode.removeChild(nodeSeplist)
+
+ insNodesRepl = []
+ for newNode, nxtNode, app in insSplLst:
+ flagCompareSeplist = False
+ newValues = self.getFieldValues(newNode)
+ for nodeRepl, nxtNode, app in insNodesRepl:
+ oldValues = self.getFieldValues(nodeRepl)
+ for newValue in newValues:
+ if newValue in oldValues:
+ flagCompareSeplist = True
+ break
+ if not flagCompareSeplist:
+ if xmlOldField:
+ insNodesRepl.append((newNode, nxtNode, app))
+
+ for newNode, nxtNode, app in insNodesRepl:
+ if app == "insert":
+ xmlArea.insertBefore(newNode,nxtNode)
+ elif app == "append":
+ xmlArea.appendChild(newNode)
+ if xmlOldField:
+ parentNode = xmlOldField.parentNode
+ if parentNode and newFieldsAction != "join":
+ parentNode.removeChild(xmlOldField)
+
+ for newNode, nxtNode, app in appSplLst:
+ if app == "insert":
+ xmlArea.insertBefore(newNode,nxtNode)
+ elif app == "append":
+ xmlArea.appendChild(newNode)
+
+ if not flagCompare and typeNewField != "seplist":
+ # Устанавливаем action=replace
+ self.setActionField(xmlNewField, "replace")
+ # Если параметры поля не сходятся заменяем поле
+ xmlArea.replaceChild(xmlNewField.cloneNode(True),
+ fieldsOldComp[-1])
+
+ if newFieldsAction == "join":
+ fieldsOldRemove = []
+ else:
+ fieldsOldRemove = fieldsOldComp[:-1]
+
+ for nodeFieldOld in fieldsOldRemove:
+ actionOldNode = self.getActionField(nodeFieldOld)
+ if actionOldNode == "insert" or actionOldNode == "append":
+ pass
+ else:
+ if nodeFieldOld.nextSibling and\
+ self.getTypeField(nodeFieldOld.nextSibling) == "br":
+ xmlArea.removeChild(nodeFieldOld.nextSibling)
+ xmlArea.removeChild(nodeFieldOld)
+ return True
+
+
+ def getSepListToField(self, xmlField):
+ """Выдает элементы распределенного массива
+
+ Область предок поля, в этой области ищутся
+ элементы распределенного массива
+ """
+ nameField = self.getNameField(xmlField)
+ if not nameField:
+ return []
+ parentNode = xmlField.parentNode
+ #print parentNode.toprettyxml()
+ if parentNode:
+ fieldsVal = xpath.Evaluate(\
+ "child::field[attribute::type='seplist'][child::name='%s'] "\
+ %(nameField), parentNode)
+ #print nameField
+ return fieldsVal
+ else:
+ return []
+
+ def removeComment(self, xmlArea):
+ """Удаляет комментарии в XML области"""
+ fieldNodes = xpath.Evaluate('descendant::field',xmlArea)
+ for fieldNode in fieldNodes:
+ if fieldNode.hasAttribute("type"):
+ if fieldNode.getAttribute("type") == "comment" or\
+ fieldNode.getAttribute("type") == "br":
+ parentNode = fieldNode.parentNode
+ parentNode.removeChild(fieldNode)
+ else:
+ if self.getActionField(fieldNode) == "drop":
+ pass
+ elif self.getActionField(fieldNode) == "join":
+ pass
+ else:
+ self.setActionField(fieldNode,"append")
+
+
+ def joinBody(self, baseBody, newBody):
+ """Объединяет две области Body"""
+ newFields = xpath.Evaluate('child::field',newBody)
+ xmlNewAreas = xpath.Evaluate('child::area',newBody)
+ for xmlNewArea in xmlNewAreas:
+ self.joinArea(baseBody,xmlNewArea)
+ joinNewFields = xpath.Evaluate("child::field[child::action='join']"
+ ,newBody)
+ self.addNewFielsOldArea(newFields, joinNewFields, baseBody)
+
+
+ def getRemoveNodeSepList(self, removeNodesDict, baseNode, xmNewlField):
+ """Находит элементы разделенного списка
+
+ Параметры:
+ removeNodesDict - Cловарь удаляемых полей разделенного списка
+ формируется программой
+ baseNode - Нода в которой идет поиск
+ xmNewlField - Нода field которая проверяется на принадлежность
+ к разделенному списку
+ """
+ flagNewNodeSeplist = False
+ if self.getTypeField(xmNewlField) == "seplist":
+ flagNewNodeSeplist = True
+ nameNewField = self.getNameField(xmNewlField)
+ if nameNewField:
+ if removeNodesDict.has_key(nameNewField):
+ return removeNodesDict[nameNewField]
+ else:
+ oldFields = xpath.Evaluate('child::field', baseNode)
+ removeNodes = []
+ lenOldFields = len(oldFields)
+ for i in range(lenOldFields):
+ oldNode = oldFields[i]
+ flagSep = self.getTypeField(oldNode) == "seplist"
+ if flagNewNodeSeplist:
+ flagSep = True
+ if flagSep and\
+ nameNewField == self.getNameField(oldNode):
+ removeNodes.append(oldNode)
+ if i+1 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)= 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)
+ textProfileTmp = text
+ while resS:
+ mark = textProfileTmp[resS.start():resS.end()]
+ hexString = mark[deltVarStart:-deltVarEnd]
+ i = 0
+ stringInsert = ""
+ hexCode = ""
+ for ch in hexString:
+ if i>=1:
+ hexCode += ch
+ stringInsert += self._hexToChar(hexCode)
+ hexCode = ""
+ i = 0
+ else:
+ hexCode += ch
+ i += 1
+ textProfileTmp = textProfileTmp.replace(mark, stringInsert)
+ resS = reVar.search(textProfileTmp)
+ return textProfileTmp
+
+ def getUserDataInLDAP(self, userName):
+ """Получаем домашнюю директорию пользователя из LDAP"""
+ if not self.conLdap:
+ import cl_utils2
+ data = self.getLDAPDataInConfig()
+ if not data:
+ return ""
+ serverName, usersDN, bindDN, bindPW = data
+ # Подключаемся к LDAP
+ ldapObj = cl_utils2.ldapFun(bindDN, bindPW, serverName)
+ if self.getError():
+ return ""
+ self.conLdap = ldapObj.conLdap
+ searchScope = ldap.SCOPE_ONELEVEL
+ searchFilter = "uid=%s" %(userName)
+ retrieveAttributes = ["uidNumber",
+ "gidNumber"
+ "homeDirectory"]
+ resSearch = ldapObj.ldapSearch(usersDN, searchScope,
+ searchFilter, retrieveAttributes)
+ if resSearch:
+ if resSearch[0][0][1].has_key('uidNumber') and\
+ resSearch[0][0][1].has_key('gidNumber') and\
+ resSearch[0][0][1].has_key('homeDirectory'):
+ uid = searchUser[0][0][1]['uidNumber'][0]
+ gid = searchUser[0][0][1]['gidNumber'][0]
+ homeDir = resSearch[0][0][1]['homeDirectory'][0]
+ return uid, gid, homeDir
+ return ""
+
+
+class processingTemplates:
+ """Класс для обработки шаблонов"""
+
+ def processingFile(self, path, prefix):
+ """Обработка в случае профиля файла"""
+ return True
+
+ def processingDirectory(self, path, prefix):
+ """Обработка в случае директории если возвращаем None то пропуск дир."""
+ return True
+
+ def scanningTemplates(self, scanDir, skipFile=[], skipDir=[],
+ prefix=None, flagDir=False):
+ """Время последней модификации внутри директории scanDir"""
+ ret = True
+ if not prefix:
+ prefix = os.path.join(scanDir,"")[:-1]
+ if not flagDir:
+ # проверка корневой директории
+ retDir = self.processingDirectory(scanDir, scanDir)
+ if retDir is None:
+ return None
+ elif retDir is False:
+ return False
+ if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]):
+ for fileOrDir in sorted(os.listdir(scanDir)):
+ absPath = os.path.join(scanDir,fileOrDir)
+ relPath = absPath.split(prefix)[1]
+ stInfo = os.lstat(absPath)
+ statInfo = stInfo[stat.ST_MODE]
+ if stat.S_ISREG(statInfo):
+ # Обработка файла
+ if relPath in skipFile:
+ continue
+ if not self.processingFile(absPath, prefix):
+ ret = False
+ break
+ elif stat.S_ISDIR(statInfo):
+ # Обработка директории
+ if relPath in skipDir:
+ continue
+ retDir = self.processingDirectory(absPath, prefix)
+ if retDir is None:
+ continue
+ elif retDir is False:
+ ret = False
+ break
+ ret = self.scanningTemplates(absPath, skipFile,
+ skipDir, prefix, True)
+ if ret is False:
+ break
+ return ret
+
+
+class profile(_file, _terms, xmlShare, processingTemplates):
+ """Класс для работы с профилями
+
+ На вход 2 параметра: объект хранения переменных, имя сервиса - не
+ обязательный параметр
+
+ """
+ # Словарь установленных программ {"имя программы":[версии]}
+ installProg = {}
+
+ # Cписок просканированных категорий установленных программ
+ installCategory = []
+
+ # Флаг сканирования всех установленных программ
+ flagAllPkgScan = False
+
+ # Название файла профиля директории
+ profDirNameFile = ".calculate_directory"
+
+ # стек глобальных переменных
+ stackGlobalVars = []
+
+ # директория установленных программ
+ basePkgDir = "/var/db/pkg"
+
+ # регулярное выражение для поиска версии
+ reFindVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*")
+
+ def __init__(self, objVar, servDir=False, dirsFilter=[], filesFilter=[]):
+ # Необрабатываемые директории
+ self.dirsFilter = dirsFilter
+ # Необрабатываемые файлы
+ self.filesFilter = filesFilter
+ _file.__init__(self)
+ # Словарь для создания объектов новых классов по образцу
+ self.newObjProt = {'proftpd':(apache,),}
+ # Заголовок title
+ self.__titleHead = "--------------------------------------\
+----------------------------------------"
+ self._titleBody = ""
+ self._titleList = (_("Modified"), _("File of a profile"))
+
+ # Метки
+ varStart = "#-"
+ varEnd = "-#"
+ self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")%(varStart,varEnd),re.M)
+ self._reFunc = re.compile(("%s[a-zA-Z0-9_\-\+\(\)\, \*\/\.\'\"~]+%s")\
+ %(varStart,varEnd),re.M)
+ self._deltVarStart = len(varStart)
+ self._deltVarEnd = len(varEnd)
+ # Условия
+ self._reTermBloc = re.compile("#\?(?P[a-zA-Z0-9\-_]+)\
+(?P\([a-zA-Z0-9_\-\+\,\*\/\.\'\"~]+\))?\
+(?P[\>\<\=\!\&\|]+\
+[a-zA-Z0-9\>\<\=\!\|\&\-\+\*\/_\.\,\(\)\'\"~]*)#\
+\n*(?P.+?)\n*#(?P=rTerm)#(?P[ ,\t]*\n?)",re.M|re.S)
+ # Объект с переменными
+ self.objVar = objVar
+ # Базовая директория переноса профилей "/mnt/calculate" или "/" и.т.д
+ baseDir = self.objVar.Get("cl_root_path")
+ #self._baseDir = os.path.split(baseDir)[0]
+ self._baseDir = baseDir
+ if self._baseDir == "/":
+ self._baseDir = ""
+ # Последняя часть директории профиля (имя сервиса: samba, mail)
+ self._servDir = servDir
+ if self._servDir:
+ if self._servDir[0] != "/":
+ self._servDir = "/" + self._servDir
+ if self._servDir[-1] != "/":
+ self._servDir += "/"
+ self._servDir = os.path.split(self._servDir)[0]
+ # Созданные директории
+ self.createdDirs = []
+ # Примененные файлы
+ self.filesApply = []
+ # номер обрабатываемого файла
+ self.numberProcessProf = 0
+ # имя текущей программы
+ _nameProgram = self.objVar.Get("cl_name").capitalize()
+ # версия текущей программы
+ _versionProgram = self.objVar.Get("cl_ver")
+ # имя и версия текущей программы
+ self.programVersion = "%s %s"%(_nameProgram, _versionProgram)
+ # Словарь измененных директорий
+ self.changeDirs = {}
+ # Словарь директорий с количесвом файлов шаблонов
+ self.dictTemplates = {}
+ # Общее количество шаблонов
+ self.allTemplates = 0
+ # Аттрибуты для функции шаблона ini()
+ # Первоначальный словарь переменных для ini()
+ self.prevDictIni = {}
+ # Текущий словарь переменных для ini()
+ self.currDictIni = {}
+ # Время модификации конфигурационного файла для ini()
+ self.timeIni = -1
+ self.uid, self.gid, self.homeDir = self.getDataUser()
+ # Путь к конфигурационному файлу для ini()
+ self.pathConfigIni = os.path.join(self.homeDir, ".calculate")
+ self.fileConfigIni = os.path.join(self.pathConfigIni,"ini.env")
+ # Словарь времен модификации env файлов
+ self.timeConfigsIni = {}
+
+ def getDataUser(self):
+ """Получить информацию о пользователе"""
+ userName = self.objVar.Get("ur_login")
+ if not userName:
+ userName = "root"
+ import pwd
+ try:
+ pwdObj = pwd.getpwnam(userName)
+ uid = pwdObj.pw_uid
+ gid = pwdObj.pw_gid
+ homeDir = pwdObj.pw_dir
+ except:
+ print _("Can not found user %s")%str(userName)
+ cl_base.exit(1)
+ return uid, gid, homeDir
+
+
+ # Преобразование восьмеричного в целое (ввод строка, вывод число)
+ def __octToInt(self, strOct):
+ if strOct:
+ try:
+ exec("res =" + "0" + strOct)
+ except:
+ self.setError (_("Not valid oct value: ") + str(strOct))
+ return False
+ return res
+ else:
+ self.setError (_("Empty oct value"))
+ return False
+
+ def removeDir(self, rmDir):
+ """Рекурсивное удаление директории
+
+ входной параметр директория
+ Обязательно должен быть определен метод self.printERROR
+ """
+ if not os.path.exists(rmDir):
+ self.printERROR(_("Not found remove dir %s") %rmDir)
+ return False
+ fileObj = _file()
+ # Сканируем директорию
+ scanObjs = fileObj.scanDirs([rmDir])
+ for socketRm in scanObjs[0].sockets:
+ # Удаляем сокеты
+ if os.path.exists(socketRm):
+ os.remove(socketRm)
+ for linkRm in scanObjs[0].links:
+ # Удаляем ссылки
+ os.unlink(linkRm[1])
+ for fileRm in scanObjs[0].files:
+ # Удаляем файлы
+ os.remove(fileRm)
+ scanObjs[0].dirs.sort(lambda x, y: cmp(len(y), len(x)))
+ for dirRm in scanObjs[0].dirs:
+ # Удаляем директории
+ os.rmdir(dirRm)
+ if rmDir:
+ os.rmdir(rmDir)
+ return True
+
+
+ def createDir(self, baseProfDir, profDir, baseDirMv, createDir):
+ """Создает директорию
+
+ baseDirMv + результат вычитания из profDir baseProfDir
+ createDir - создаваемая директория
+ """
+ if baseDirMv and not os.access(baseDirMv, os.F_OK):
+ os.makedirs(baseDirMv)
+ # Созданные директории
+ createDirs = []
+ baseDir = baseProfDir
+ if baseProfDir[-1] == "/":
+ baseDir = baseProfDir[:-1]
+ # Директория в системе относительно baseDirMv без условий
+ if baseDirMv:
+ dirMvNoTerm = createDir.partition(baseDirMv)[2]
+ else:
+ dirMvNoTerm = createDir
+ # директория в системе
+ dirMv = profDir.partition(baseDir)[2]
+ if len(dirMv)>1 and dirMv[-1] == "/":
+ dirMv = dirMv[:-1]
+ ## директория в системе без условий
+ #dirMvNoTerm = "/".join(map(lambda x:x.split("?")[0],\
+ #dirMv.split("/")))
+ listDirMv = dirMv.split("/")
+ listDirMvNoTerm = dirMvNoTerm.split("/")
+ if len(listDirMv) != len(listDirMvNoTerm):
+ self.setError (_("Error in profile") + " :" + profDir)
+ return False
+ genIn = listDirMv.__iter__()
+ genOut = listDirMvNoTerm.__iter__()
+ inAndOutDirs = map(lambda x: [x,genOut.next()], genIn)
+ createDirs = []
+ createDir = []
+ while (len(inAndOutDirs)>1):
+ tmpDirIn = baseDir+"/".join(map(lambda x:x[0], inAndOutDirs))
+ tmpDirOut = baseDirMv + "/".join(map(lambda x:x[1],\
+ inAndOutDirs))
+ if os.access(tmpDirOut, os.F_OK):
+ break
+ else:
+ createDir.append((tmpDirIn, tmpDirOut))
+ inAndOutDirs.pop()
+ createDir.reverse()
+ for crDirIn,crDirOut in createDir:
+ try:
+ mode,uid,gid = self.getModeFile(crDirIn)
+ except OSError:
+ self.setError (_("not access dir:" ) + crDirIn)
+ return False
+ createDirs.append(crDirOut)
+ os.mkdir(crDirOut, mode)
+ os.chown(crDirOut, uid, gid)
+ return createDirs
+
+
+ def applyVarsProfile(self, textProfile, nameProfile):
+ """ Заменяет переменные на их значения
+ """
+ resS = self._reVar.search(textProfile)
+ textProfileTmp = textProfile
+ while resS:
+ mark = textProfileTmp[resS.start():resS.end()]
+ varName = mark[self._deltVarStart:-self._deltVarEnd]
+ varValue = ""
+ try:
+ varValue = str(self.objVar.Get(varName))
+ except self.objVar.DataVarsError, e:
+ print _("error in profile %s")%nameProfile
+ print e
+ cl_base.exit(1)
+ textProfileTmp = textProfileTmp.replace(mark, varValue)
+ resS = self._reVar.search(textProfileTmp)
+ return textProfileTmp
+
+
+ def applyFuncProfile(self, textProfile, nameProfile, nameSystemFile):
+ """ Применяет функции к тексту профиля
+ """
+ def equalTerm(term, sNum, sMD, localVars):
+ """Локальная функция для вычисления выражения"""
+ terms = sNum.findall(term)
+ if terms:
+ strNumers = []
+ for n in terms:
+ strNum = n.strip()
+ if "*" in strNum or "/" in strNum:
+ strNum = multAndDiv(strNum,sNum,sMD,localVars)
+ try:
+ num = int(strNum)
+ except:
+ minus = False
+ if strNum[:1] == "-":
+ minus = True
+ strNum = strNum[1:]
+ if localVars.has_key(strNum):
+ try:
+ num = int(localVars[strNum])
+ except:
+ print _("error in profile %s")%nameProfile
+ print _("error local var %s not int")\
+ %str(strNum)
+ cl_base.exit(1)
+ elif self.objVar.exists(strNum):
+ try:
+ num = int(self.objVar.Get(strNum))
+ except:
+ print _("error in profile %s")%nameProfile
+ print _("error var %s not int")%str(strNum)
+ cl_base.exit(1)
+ else:
+ print _("error in profile %s")%nameProfile
+ print _("error local var %s not defined")\
+ %str(strNum)
+ cl_base.exit(1)
+ if minus:
+ num =-num
+ strNumers.append(num)
+ return sum(strNumers)
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s, incorrect data")%str(term)
+ cl_base.exit(1)
+
+ def multAndDiv(term,sNum,sMD,localVars):
+ """локальная функция для умножения и деления"""
+ termTmp = term
+ varsLocal = sMD.findall(term)
+ for var in varsLocal:
+ flagVarTxt = True
+ try:
+ int(var)
+ except:
+ flagVarTxt = False
+ if flagVarTxt:
+ continue
+ varReplace = str(equalTerm(var,sNum,sMD,localVars))
+ termTmp = termTmp.replace(var,varReplace)
+ ret = eval(termTmp)
+ return ret
+
+ def funcSum(funTxt,resS,localVars,textProfileTmp):
+ """локальная функция вычисляет первую функцию sum() в профиле"""
+ terms = funTxt[4:-1].replace(" ","").split(",")
+ # Название локальной переменной
+ nameLocVar = terms[0]
+ if not localVars.has_key(nameLocVar):
+ localVars[nameLocVar] = 0
+ if len(terms) == 2:
+ if terms[1].strip():
+ localVars[nameLocVar] = equalTerm(terms[1],sNum,sMD,
+ localVars)
+ replace = str(localVars[nameLocVar])
+ else:
+ replace = ""
+ textProfileTmp = textProfileTmp[:resS.start()] + replace +\
+ textProfileTmp[resS.end():]
+ elif len(terms) == 3:
+ if terms[1].strip():
+ replaceInt = equalTerm(terms[1],sNum,sMD,localVars)
+ replace = str(replaceInt)
+ else:
+ replace = ""
+ localVars[nameLocVar] = equalTerm(terms[2],
+ sNum,sMD,localVars)
+ textProfileTmp = textProfileTmp[:resS.start()] + replace +\
+ textProfileTmp[resS.end():]
+ else:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ cl_base.exit(1)
+ return textProfileTmp
+
+
+ def funcExists(funTxt,resS,textProfileTmp):
+ """если файл существует читает из файла локальную переменную
+
+ если один параметр - выводит значение локальной переменной
+ """
+ terms = funTxt[7:-1].replace(" ","").split(",")
+ if len(terms) !=1:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ cl_base.exit(1)
+ fileName = terms[0].strip()
+ if fileName[0] == "~":
+ # Получаем директорию пользователя
+ fileName = os.path.join(self.homeDir,
+ fileName.partition("/")[2],"")[:-1]
+ elif fileName[0] != "/":
+ path = os.path.split(nameSystemFile)[0]
+ fileName=os.path.join(path,fileName)
+ replace = ""
+ if os.path.exists(fileName):
+ replace = "1"
+ textProfileTmp = textProfileTmp[:resS.start()] + replace +\
+ textProfileTmp[resS.end():]
+ return textProfileTmp
+
+ def funcLoad(funTxt,resS,textProfileTmp):
+ """если файл существует читает из файла локальную переменную
+
+ если один параметр - выводит значение локальной переменной
+ """
+ terms = funTxt[5:-1].replace(" ","").split(",")
+ if not terms[0].strip() or\
+ (len(terms)==2 and not terms[1].strip()) or\
+ len(terms)>2:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ cl_base.exit(1)
+ if len(terms) == 2:
+ if not terms[0] in ["ver","num","char","key"]:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ print _("first argument function is not 'ver' or 'num' or\
+ 'char'")
+ cl_base.exit(1)
+ if len(terms) == 1:
+ fileName = terms[0].strip()
+ # Если домашняя директория
+ if fileName[0] == "~":
+ # Получаем директорию пользователя
+ fileName = os.path.join(self.homeDir,
+ fileName.partition("/")[2],"")[:-1]
+ elif fileName[0] != "/":
+ path = os.path.split(nameSystemFile)[0]
+ fileName=os.path.join(path,fileName)
+ else:
+ fileName = terms[1].strip()
+ # Если домашняя директория
+ if fileName[0] == "~":
+ # Получаем директорию пользователя
+ fileName = os.path.join(self.homeDir,
+ fileName.partition("/")[2],"")[:-1]
+ elif fileName[1] != "/":
+ path = os.path.split(nameSystemFile)[0]
+ fileName=os.path.join(path,fileName)
+ replace = ""
+ if os.path.exists(fileName):
+ FD = open(fileName)
+ replace = FD.read().strip()
+ FD.close
+ if not replace and len(terms) == 2 and terms[0] in ["ver","num"]:
+ replace = "0"
+ textProfileTmp = textProfileTmp[:resS.start()] + replace +\
+ textProfileTmp[resS.end():]
+ return textProfileTmp
+
+ def getInstallPkgGentoo():
+ """Выдает словарь инсталлированных программ и номеров версий"""
+ pkgs = []
+ 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 sharePkg(pkgs)
+
+ def sharePkg(pkgs):
+ """Получение имен и номеров версий программ"""
+ pkgs.sort()
+ installProg = {}
+ for pkg in pkgs:
+ findVer = self.reFindVer.search(pkg)
+ if findVer:
+ version = findVer.group()
+ name = pkg.split(version)[0][:-1]
+ if name in installProg:
+ installProg[name].append(version)
+ else:
+ installProg[name] = [version]
+ return installProg
+
+ def pkg(nameProg, installProg):
+ """Выдает установленные версии по имени программы"""
+ if nameProg in installProg:
+ return installProg[nameProg][-1]
+ else:
+ return ""
+
+ def funcPkg(funTxt,resS,textProfileTmp):
+ """локальная функция выдает номер версии программы"""
+ terms = funTxt[4:-1].replace(" ","")
+ # Название программы
+ nameProg = terms
+ # Замена функции в тексте шаблона
+ replace = ""
+ if "/" in nameProg:
+ if nameProg in self.installProg:
+ replace = pkg(nameProg, self.installProg)
+ else:
+ category, spl, nProg = terms.partition("/")
+ if not category in self.installCategory:
+ self.installCategory.append(category)
+ pathCategory = os.path.join(self.basePkgDir, category)
+ if os.path.exists(pathCategory):
+ pkgs = os.listdir(pathCategory)
+ pkgs = map(lambda x: os.path.join(category,x),
+ pkgs)
+ installProg = sharePkg(pkgs)
+ replace = pkg(nameProg, installProg)
+ self.installProg.update(installProg)
+ else:
+ if not self.flagAllPkgScan:
+ installProg = getInstallPkgGentoo()
+ self.installProg.update(installProg)
+ profile.flagAllPkgScan = True
+ replace = pkg(nameProg, self.installProg)
+ textProfileTmp = textProfileTmp[:resS.start()] + replace +\
+ textProfileTmp[resS.end():]
+ return textProfileTmp
+
+ def funcRnd(funTxt,resS,textProfileTmp):
+ """локальная функция выдает строку случайных символов
+
+ первый аргумент:
+ 'num' - числа,
+ 'pas' - цифры и буквы
+ второй аргумент:
+ количество символов
+ """
+ terms = funTxt[4:-1].replace(" ","").split(",")
+ if not terms[0].strip() or\
+ (len(terms)==2 and not terms[1].strip()) or\
+ len(terms)!=2:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ cl_base.exit(1)
+ fArgvNames = ['num','pas']
+ if not terms[0] in fArgvNames:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ print _("first argument function is not 'num' or 'pas'")
+ cl_base.exit(1)
+ try:
+ lenStr = int(terms[1])
+ except:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ print _("two argument function is not number")
+ cl_base.exit(1)
+ if terms[0] == fArgvNames[0]:
+ replace=''.join([random.choice(string.digits)\
+ for i in xrange(lenStr)])
+ elif terms[0] == fArgvNames[1]:
+ replace=''.join([random.choice(string.ascii_letters + \
+ string.digits) for i in xrange(lenStr)])
+ else:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ cl_base.exit(1)
+ textProfileTmp = textProfileTmp[:resS.start()] + replace +\
+ textProfileTmp[resS.end():]
+ return textProfileTmp
+
+ def funcCase(funTxt,resS,textProfileTmp):
+ """локальная функция выдает переменную в определенном регистре
+
+ первый аргумент:
+ 'upper' - верхний регистр,
+ 'lower' - нижний регистр,
+ 'capitalize' - первая буква в верхнем регистре
+ второй аргумент:
+ название переменной
+ """
+ terms = funTxt[5:-1].replace(" ","").split(",")
+ if not terms[0].strip() or\
+ (len(terms)==2 and not terms[1].strip()) or len(terms)!=2:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ cl_base.exit(1)
+ fArgvNames = ['upper','lower','capitalize']
+ if not terms[0] in fArgvNames:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ print _("first argument function is not 'upper' or 'lower' or\
+ 'capitalize'")
+ cl_base.exit(1)
+ try:
+ strValue = str(self.objVar.Get(terms[1]))
+ except:
+ print _("error in profile %s")%nameProfile
+ print _("error var %s not found")%str(terms[1])
+ cl_base.exit(1)
+ replace = ""
+ strValue = self._toUNICODE(strValue)
+ if terms[0] == 'upper':
+ replace = strValue.upper()
+ elif terms[0] == 'lower':
+ replace = strValue.lower()
+ elif terms[0] == 'capitalize':
+ replace = strValue.capitalize()
+ if replace:
+ replace = replace.encode("UTF-8")
+ textProfileTmp = textProfileTmp[:resS.start()] + replace +\
+ textProfileTmp[resS.end():]
+ return textProfileTmp
+
+ def funcPush(funTxt,resS,localVars,textProfileTmp):
+ """локальная функция записывает значение переменной
+
+ в стек глобальных переменных
+ """
+ terms = funTxt[5:-1].replace(" ","").split(",")
+ # Название локальной переменной
+ nameLocVar = terms[0]
+ flagFoundVar = False
+ if nameLocVar in localVars.keys():
+ flagFoundVar = True
+ value = localVars[nameLocVar]
+ else:
+ try:
+ value = self.objVar.Get(nameLocVar)
+ flagFoundVar = True
+ except:
+ pass
+ if flagFoundVar:
+ # Если переменная существует
+ if len(terms) == 1:
+ self.stackGlobalVars.append(str(value))
+ else:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ print _("error var %s exists")%str(nameLocVar)
+ cl_base.exit(1)
+ else:
+ # Если переменная не существует
+ if len(terms) == 1:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ print _("error var %s not exists")%str(nameLocVar)
+ cl_base.exit(1)
+ elif len(terms) == 2:
+ value = terms[1].strip()
+ self.stackGlobalVars.append(str(value))
+ localVars[nameLocVar] = value
+ else:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ cl_base.exit(1)
+ replace = ""
+ textProfileTmp = textProfileTmp[:resS.start()] + replace +\
+ textProfileTmp[resS.end():]
+ return textProfileTmp
+
+ def funcPop(funTxt,resS,localVars,textProfileTmp):
+ """локальная функция получает значение
+
+ из стека глобальных переменных и присвает локальной переменной
+
+ """
+ terms = funTxt[4:-1].replace(" ","").split(",")
+ # Название локальной переменной
+ nameLocVar = terms[0]
+ if len(terms) == 1:
+ if self.stackGlobalVars:
+ localVars[nameLocVar] = self.stackGlobalVars.pop()
+ else:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ print _("error, gloval variables stack is empty")
+ cl_base.exit(1)
+ else:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ cl_base.exit(1)
+ replace = ""
+ textProfileTmp = textProfileTmp[:resS.start()] + replace +\
+ textProfileTmp[resS.end():]
+ return textProfileTmp
+
+ def loadVarsIni(iniFileName):
+ """ Читает файл fileName
+ создает и заполняет переменные на основе этого файла
+ Используеться совместно c funcIni
+ """
+ localVarsIni = {}
+ # Выходим если есть предыдущие ошибки
+ if self.getError():
+ return False
+ # получить объект ini файла
+ config = cl_base.iniParser(iniFileName)
+ # получаем все секции из конфигурационного файла
+ allsect = config.getAllSectionNames()
+ if not allsect:
+ if self.getError():
+ # Очистка ошибки
+ _error.error = []
+ return localVarsIni
+ # Заполняем переменные для funcIni
+ for sect in allsect:
+ sectVars = config.getAreaVars(sect)
+ for name in sectVars.keys():
+ nameVar = "%s.%s"%(sect,name)
+ valueVar = sectVars[name]
+ localVarsIni[nameVar] = valueVar
+ return localVarsIni
+
+ def getTimeFile(fileName):
+ # Получаем время модификации файла
+ if fileName in self.timeConfigsIni:
+ return self.timeConfigsIni[fileName]
+ return 0
+
+ def funcIni(funTxt, resS, textProfileTmp):
+ """локальная функция записывает и считывает значение переменной
+
+ из ini файла ~./calculate/ini.env
+ """
+ # Создаем директорию
+ if not os.path.exists(self.pathConfigIni):
+ os.makedirs(self.pathConfigIni)
+ os.chown(self.pathConfigIni, int(self.uid), int(self.gid))
+ termsRaw = funTxt[4:-1].split(",")
+ flagFirst = True
+ terms = []
+ for term in termsRaw:
+ if flagFirst:
+ terms.append(term.replace(" ",""))
+ flagFirst = False
+ else:
+ val = term.strip()
+ # Флаг (не найдены кавычки)
+ flagNotFoundQuote = True
+ for el in ('"',"'"):
+ if val.startswith(el) and val.endswith(el):
+ terms.append(val[1:-1])
+ flagNotFoundQuote = False
+ break
+ if flagNotFoundQuote:
+ terms.append(val)
+ # Название локальной переменной
+ nameLocVar = terms[0]
+ namesVar = nameLocVar.split(".")
+ if len(namesVar) == 1:
+ nameLocVar = "main.%s"%nameLocVar
+ elif len(namesVar)>2:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ cl_base.exit(1)
+ replace = ""
+ # Получаем время модификации конфигурационного файла
+ curTime = getTimeFile(self.fileConfigIni)
+ if len(terms) == 1:
+ if self.timeIni != curTime:
+ # читаем переменные из файла
+ self.prevDictIni = loadVarsIni(self.fileConfigIni)
+ self.currDictIni.update(self.prevDictIni)
+ self.timeIni = getTimeFile(self.fileConfigIni)
+ if nameLocVar in self.currDictIni.keys():
+ replace = self.currDictIni[nameLocVar]
+ elif len(terms) == 2:
+ if self.timeIni != curTime:
+ # читаем переменные из файла
+ self.prevDictIni = loadVarsIni(self.fileConfigIni)
+ self.currDictIni.update(self.prevDictIni)
+ self.timeIni = getTimeFile(self.fileConfigIni)
+ # Значение локальной переменной
+ valueLocVar = terms[1]
+ self.currDictIni[nameLocVar] = valueLocVar
+ else:
+ print _("error in profile %s")%nameProfile
+ print _("error profile term %s")%str(funTxt)
+ cl_base.exit(1)
+ textProfileTmp = textProfileTmp[:resS.start()] + replace +\
+ textProfileTmp[resS.end():]
+ return (textProfileTmp)
+
+ # Локальные переменные
+ localVars = {}
+ # Регулярное выражние для сложения
+ sNum = re.compile("\-[^\-\+]+|[^\-\+]+")
+ # Регулярное выражение для умножениея и деления
+ sMD = re.compile("[^\-\+\*\/]+")
+ resS = self._reFunc.search(textProfile)
+ textProfileTmp = textProfile
+ flagIniFunc = False
+ while resS:
+ mark = textProfileTmp[resS.start():resS.end()]
+ funTxt = mark[self._deltVarStart:-self._deltVarEnd]
+ # Функция sum
+ if funTxt.startswith("sum("):
+ textProfileTmp = funcSum(funTxt,resS,localVars,textProfileTmp)
+ resS = self._reFunc.search(textProfileTmp)
+ # Функция load
+ elif funTxt.startswith("load("):
+ textProfileTmp = funcLoad(funTxt,resS,textProfileTmp)
+ resS = self._reFunc.search(textProfileTmp)
+ elif funTxt.startswith("pkg("):
+ textProfileTmp = funcPkg(funTxt,resS,textProfileTmp)
+ resS = self._reFunc.search(textProfileTmp)
+ elif funTxt.startswith("rnd("):
+ textProfileTmp = funcRnd(funTxt,resS,textProfileTmp)
+ resS = self._reFunc.search(textProfileTmp)
+ elif funTxt.startswith("case("):
+ textProfileTmp = funcCase(funTxt,resS,textProfileTmp)
+ resS = self._reFunc.search(textProfileTmp)
+ elif funTxt.startswith("pop("):
+ textProfileTmp = funcPop(funTxt,resS,localVars,textProfileTmp)
+ resS = self._reFunc.search(textProfileTmp)
+ elif funTxt.startswith("push("):
+ textProfileTmp = funcPush(funTxt,resS,localVars,textProfileTmp)
+ resS = self._reFunc.search(textProfileTmp)
+ elif funTxt.startswith("ini("):
+ flagIniFunc = True
+ textProfileTmp = funcIni(funTxt, resS, textProfileTmp)
+ resS = self._reFunc.search(textProfileTmp)
+ elif funTxt.startswith("exists("):
+ textProfileTmp = funcExists(funTxt, resS, textProfileTmp)
+ resS = self._reFunc.search(textProfileTmp)
+ else:
+ resS = False
+ if flagIniFunc:
+ # Очистка файла в случае его ошибочного чтения
+ if not self.prevDictIni and os.path.exists(self.fileConfigIni):
+ FD = open(self.fileConfigIni, "r+")
+ FD.truncate(0)
+ FD.seek(0)
+ FD.close()
+ # Если конф. файл модифицирован шаблоном
+ curTime = getTimeFile(self.fileConfigIni)
+ if curTime != self.timeIni:
+ # Считаем переменные из конф. файла
+ self.prevDictIni = loadVarsIni(self.fileConfigIni)
+ self.currDictIni.update(self.prevDictIni)
+ self.timeIni = curTime
+ # Если словари переменных не совпадают
+ if self.prevDictIni != self.currDictIni:
+ # Запишем переменные в конфигурационный файл
+ # Создание объекта парсера
+ config = cl_base.iniParser(self.fileConfigIni)
+ # секции будущего конфигурационного файла
+ sects = list(set(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 = loadVarsIni(self.fileConfigIni)
+ self.currDictIni.update(self.prevDictIni)
+ self.timeConfigsIni[self.fileConfigIni] = float(time.time())
+ self.timeIni = getTimeFile(self.fileConfigIni)
+ # Меняем владельца в случае необходимости
+ if os.path.exists(self.fileConfigIni):
+ fd = os.open(self.fileConfigIni, os.O_RDONLY)
+ fst = os.fstat(fd)
+ uid = fst.st_uid
+ gid = fst.st_gid
+ os.close(fd)
+ if self.uid!=uid or self.gid!=gid:
+ os.chown(self.fileConfigIni, int(self.uid), int(self.gid))
+ return textProfileTmp
+
+ def applyTermsProfile(self, textProfile, nameProfile, nameSystemFile=False):
+ """ Применяет условия, к условным блокам текста
+ """
+ textTerm = ""
+ resS = self._reTermBloc.search(textProfile)
+ textProfileTmp = textProfile
+ def function(text):
+ """Функция обработки функций в заголовке"""
+ return self.applyFuncProfile(text, nameProfile, nameSystemFile)
+ if nameSystemFile:
+ while resS:
+ mark = resS.group(0)
+ body = resS.group("body")
+ end = resS.group("end")
+ parent = resS.group("func")
+ if not parent:
+ parent = ""
+ term = resS.group("rTerm") + parent +\
+ resS.group("lTerm")
+ if self._equalTerm(term, _("content profile not valid: ")+\
+ nameProfile, function):
+ textProfileTmp = textProfileTmp.replace(mark, body+end)
+ else:
+ textProfileTmp = textProfileTmp.replace(mark, "")
+ resS = self._reTermBloc.search(textProfileTmp)
+ else:
+ while resS:
+ mark = resS.group(0)
+ body = resS.group("body")
+ end = resS.group("end")
+ term = resS.group("rTerm") + resS.group("lTerm")
+ if self._equalTerm(term, _("content profile not valid: ")+\
+ nameProfile):
+ textProfileTmp = textProfileTmp.replace(mark, body+end)
+ else:
+ textProfileTmp = textProfileTmp.replace(mark, "")
+ resS = self._reTermBloc.search(textProfileTmp)
+ return textProfileTmp
+
+ def getNeedProfile(self, fileProfile):
+ """Применяем правила к названию файла"""
+ dirP,fileP = os.path.split(fileProfile)
+ if fileP:
+ spFile = fileP.split("?")
+ realFileName = spFile[0]
+ if len(spFile)>1:
+ flagTrue = False
+ for term in spFile[1:]:
+ if self._equalTerm(term, _("name profile not valid: ")+\
+ fileProfile):
+ flagTrue = True
+ break
+ if flagTrue:
+ return True
+ else:
+ return False
+ else:
+ return True
+ else:
+ self.setError (_("name profile not valid: ")+ str(fileProfile))
+ return False
+
+ def getTitle(self, comment, commentList):
+ """Выдает заголовок профиля ( версия и.т.д)"""
+ if comment:
+ commentFirst = comment
+ commentInsert = comment
+ commentLast = comment
+ flagList = False
+ # В случае открывающего и закрывающего комментария
+ if type(comment) == types.TupleType and len(comment) == 2:
+ commentFirst = comment[0]
+ commentInsert = ""
+ commentLast = comment[1]
+ flagList = True
+ if flagList:
+ self._titleBody = commentFirst + "\n"
+ else:
+ self._titleBody = commentFirst + self.__titleHead + "\n"
+ z = 0
+ lenCommentList = len(commentList) - 1
+ for com in self._titleList:
+ if lenCommentList < z:
+ self._titleBody += commentInsert + " " + com + "\n"
+ else:
+ self._titleBody += commentInsert + " " + com +\
+ " " + commentList[z] + "\n"
+ z += 1
+ if flagList:
+ self._titleBody += commentLast +"\n"
+ else:
+ self._titleBody += commentLast + self.__titleHead + "\n"
+ return self._titleBody
+ else:
+ return ""
+
+ def numberAllProfiles(self, number):
+ """Количество профилей
+
+ Вызов происходит перед наложением профилей
+ в момент вызова в number находится количество обрабатываемых файлов
+ Наследуемая функция
+ Используется для отображения прогресса при наложениии профилей
+ """
+ return True
+
+ def numberProcessProfiles(self, number):
+ """Номер текущего обрабатываемого профиля
+
+ Вызов происходит при наложении профиля
+ в момент вызова в number находится номер обрабатываемого профиля
+ Наследуемая функция
+ Используется для отображения прогресса при наложениии профилей
+ """
+ return True
+
+
+ def scanDirs(self, profilesDirs, objVar=False):
+ """Измененный метод сканирования директорий"""
+ dirs = []
+ class dirProf:
+ def __init__(self):
+ self.baseDir = False
+ self.dirs = []
+ self.files = []
+ self.links = []
+ self.sockets = []
+ flagError = False
+ blockDirs = []
+ def getFilesDir(dirP, dirname, names):
+ for nameFile in names:
+ absNameFile = dirname + "/" + nameFile
+ findBlock = False
+ for blDir in blockDirs:
+ st,mid,end = absNameFile.partition(blDir)
+ if (not st) and mid and end:
+ findBlock = True
+ break
+ if not findBlock:
+ if os.path.islink(absNameFile):
+ dest = absNameFile
+ src = os.readlink(absNameFile)
+ dirP.links.append((src,dest))
+ elif os.path.isfile(absNameFile):
+ # Добавляем файлы кроме описаний директорий
+ if self.profDirNameFile != nameFile:
+ dirP.files.append(absNameFile)
+ elif os.path.isdir(absNameFile):
+ # Обработка условий в названии директории
+ if self.getNeedProfile(absNameFile):
+ if self.getError():
+ blockDirs.append(absNameFile)
+ flagError = True
+ break
+ dirP.dirs.append(absNameFile)
+ else:
+ if self.getError():
+ blockDirs.append(absNameFile)
+ flagError = True
+ break
+ blockDirs.append(absNameFile)
+ elif stat.S_ISSOCK(os.stat(absNameFile)[stat.ST_MODE]):
+ dirP.sockets.append(absNameFile)
+ for profileDir in profilesDirs:
+ if profileDir:
+ # Обработка условий в названии директории
+ if self.getNeedProfile(profileDir):
+ if self.getError():
+ flagError = True
+ break
+ dirP = dirProf()
+ dirP.baseDir = profileDir
+ dirs.append(dirP)
+ os.path.walk(profileDir, getFilesDir, dirP)
+ else:
+ if self.getError():
+ flagError = True
+ break
+ if flagError:
+ return []
+ return dirs
+
+
+ def applyProfiles(self):
+ """Применяет профили к конфигурационным файлам"""
+
+ def createDictTemplates(path, prefix, dictTemplates):
+ """Создает словарь {"директория":"кол-во шаблонов" ...}
+
+ и считает общее количество шаблонов
+ """
+ # Количество шаблонов
+ self.allTemplates += 1
+ dirTemplate = os.path.split(path)[0]
+ while(True):
+ if dirTemplate in dictTemplates.keys():
+ dictTemplates[dirTemplate] += 1
+ else:
+ dictTemplates[dirTemplate] = 1
+ if dirTemplate == prefix:
+ break
+ dirTemplate = os.path.split(dirTemplate)[0]
+ return dictTemplates
+
+ if not self.objVar.defined("cl_profile_path"):
+ self.setError (_("not defined Var: ") + "cl_profile_path")
+ return False
+ dirsProfiles = self.objVar.Get("cl_profile_path")
+ dirsProfiles.sort()
+ # Словарь измененных директорий
+ self.changeDirs = {}
+ # Созданные директории
+ self.createdDirs = []
+ # Примененные файлы
+ self.filesApply = []
+ # Номер применяемого шаблона
+ self.numberProcessProf = 0
+ # Словарь директорий с количеством файлов шаблонов
+ self.dictTemplates = {}
+ # Количество шаблонов
+ self.allTemplates = 0
+ # Время доступа к конфигурационному файлу функции шаблона ini()
+ self.timeIni = -1
+ # Первоначальный словарь переменных для ini()
+ self.prevDictIni = {}
+ # Текущий словарь переменных для ini()
+ self.currDictIni = {}
+ # Словарь времен модификации env файлов
+ self.timeConfigsIni = {}
+ if self._servDir:
+ tmpDirsProfiles = []
+ for dirP in dirsProfiles:
+ dirProf = dirP + self._servDir
+ if os.access(dirProf, os.F_OK):
+ # Если директория существует
+ tmpDirsProfiles.append(dirProf)
+ dirsProfiles = tmpDirsProfiles
+ scanObj = processingTemplates()
+ scanObj.processingFile = lambda x,y: createDictTemplates(x, y,\
+ self.dictTemplates)
+ # Считаем количество шаблонов
+ for dirTemplate in dirsProfiles:
+ scanObj.scanningTemplates(dirTemplate,
+ skipFile=self.filesFilter,
+ skipDir=self.dirsFilter)
+ self.numberAllProfiles(self.allTemplates)
+ for dirTemplate in dirsProfiles:
+ if self.scanningTemplates(dirTemplate,
+ skipFile=self.filesFilter,
+ skipDir=self.dirsFilter) is False:
+ return False
+ return (self.createdDirs, self.filesApply)
+
+
+ def processingFile(self, path, prefix):
+ """Обработка в случае профиля файла"""
+ self.numberProcessProf += 1
+ self.numberProcessProfiles(self.numberProcessProf)
+ # Пропуск шаблонов директорий
+ if self.profDirNameFile == os.path.split(path)[1]:
+ return True
+ if self.getNeedProfile(path):
+ if self.getError():
+ return False
+ fileProfileChange = path
+ findChangeDir = False
+ listD = self.changeDirs.items()
+ listD.reverse()
+ for dirChangeIn, dirChangeOut in listD:
+ st,mid,end = path.partition(dirChangeIn)
+ if (not st) and mid and end:
+ findChangeDir = True
+ break
+ if findChangeDir:
+ oldFile = dirChangeOut + end
+ else:
+ oldFile = path.partition(prefix)[2]
+ # файл в системе без условий
+ oldFile = "/".join(map(lambda x:x.split("?")[0],\
+ oldFile.split("/")))
+ if not findChangeDir:
+ oldFile = self._baseDir + oldFile
+ # Фильтрация профилей по названию файла
+ if oldFile in self.filesFilter:
+ return True
+ listProfTitle = prefix.split("/")[-2:]
+ profTitle = '"' + "/".join(listProfTitle) + '"'
+ # Записываем в переменную обрабатываемый файл
+ self.objVar.Set("cl_pass_file",oldFile)
+ # Пишем время модификации *.env файлов
+ if oldFile.endswith(".env"):
+ self.timeConfigsIni[oldFile] = float(time.time())
+ filesApl = self.join(path, oldFile,
+ (self.programVersion,profTitle))
+ if filesApl:
+ self.filesApply += filesApl
+ else:
+ if self.getError():
+ #print self.getError()
+ return False
+ return True
+
+ def processingDirectory(self, path, prefix):
+ """Обработка в случае директории если возвращаем None то пропуск дир."""
+ # Файл шаблона директории
+ dirInfoFile = os.path.join(path, self.profDirNameFile)
+ # Проверяем заголовок
+ ret = self.__isApplyHeadDir(dirInfoFile)
+ if not ret:
+ if self.getError():
+ self.setError(_("Incorrect profile: " ) + dirInfoFile)
+ return False
+ # Добавление количества файлов в пропущенной директории
+ if path in self.dictTemplates.keys():
+ self.numberProcessProf += self.dictTemplates[path]
+ return None
+ newDir = self._baseDir + path.partition(prefix)[2]
+ newDir = "/".join(map(lambda x:x.split("?")[0],\
+ newDir.split("/")))
+ # Применяем шаблон
+ pathDir, objHeadDir = self.__getApplyHeadDir(newDir,
+ dirInfoFile,
+ self.changeDirs)
+ # Фильтрация профилей по названию директории
+ if pathDir in self.dirsFilter:
+ # Добавление количества файлов в пропущенной директории
+ if path in self.dictTemplates.keys():
+ self.numberProcessProf += self.dictTemplates[path]
+ return None
+ if objHeadDir:
+ if isinstance(objHeadDir, dirHeader):
+ if not objHeadDir.headerCorrect:
+ self.setError(_("Incorrect profile: " ) +\
+ dirInfoFile)
+ self.setError(objHeadDir.errorMessage)
+ return False
+ if not objHeadDir.headerTerm:
+ if objHeadDir.getError():
+ self.setError(_("Incorrect profile: " ) +\
+ dirInfoFile)
+ return False
+ if objHeadDir.params.has_key("name"):
+ self.changeDirs[path] = pathDir
+ crDirs = self.createDir(prefix, path,
+ self._baseDir, pathDir)
+ if crDirs is False:
+ return False
+ self.createdDirs += crDirs
+ else:
+ if self.getError():
+ self.setError(_("Incorrect profile: " ) +\
+ dirInfoFile)
+ return False
+ # Добавление количества файлов в пропущенной директории
+ if path in self.dictTemplates.keys():
+ self.numberProcessProf += self.dictTemplates[path]
+ return None
+ return True
+
+ def __getGenHeadDir(self, newDir, profileDirFile, changeDirs):
+ """Определяет название создаваемой директории"""
+
+ def function(text):
+ """Функция обработки функций в заголовке"""
+ return self.applyFuncProfile(text, newDir, profileDirFile)
+
+ newDirMv = newDir
+ findChangeDir = False
+ #Меняем путь к директории
+ listD = changeDirs.items()
+ listD.reverse()
+ for dirChangeIn, dirChangeOut in listD:
+ st,mid,end = profileDirFile.partition(dirChangeIn)
+ if (not st) and mid:
+ findChangeDir = True
+ break
+ if findChangeDir:
+ pathRel = dirChangeOut
+ lenPathRel = len(pathRel.split("/"))
+ lenNewDir = len(newDir.split("/"))
+ lenEndDir = lenNewDir - lenPathRel
+ tmpDir = newDir
+ namesDirs = []
+ for i in range(lenEndDir):
+ namesDirs.append(os.path.split(tmpDir)[1])
+ tmpDir = os.path.split(tmpDir)[0]
+ namesDirs.reverse()
+ nameDir = "/".join(namesDirs)
+ newDirMv = os.path.join(pathRel, nameDir)
+ applyDir = newDirMv
+ if not os.path.exists(profileDirFile):
+ return (applyDir, True)
+ try:
+ FD = open(profileDirFile)
+ textProfile = FD.read()
+ FD.close()
+ except:
+ self.setError(_("Error open profile: " ) +\
+ profileDirFile)
+ return (applyDir, False)
+ objHead = dirHeader(textProfile, self.objVar,function)
+ if not objHead.headerCorrect:
+ self.setError(_("Incorrect profile: " ) +\
+ profileDirFile)
+ self.setError(objHead.errorMessage)
+ return (applyDir, False)
+ if not objHead.headerTerm:
+ if objHead.getError():
+ self.setError(_("Incorrect profile: " ) +\
+ profileDirFile)
+ return (applyDir, False)
+ # Изменяем название директории
+ if objHead.params.has_key("name"):
+ nameDir = objHead.params['name']
+ if "/" in nameDir or nameDir == ".." or nameDir == ".":
+ self.setError (_("False value 'name' in profile: " ) +\
+ profileDirFile)
+ return (applyDir, False)
+ if not findChangeDir:
+ pathRel = os.path.split(os.path.abspath(newDirMv))[0]
+ # Новый путь к оригинальному файлу
+ newDirMv = os.path.join(pathRel, nameDir)
+ applyDir = newDirMv
+ # При удаленнии директории
+ if objHead.typeAppend == "remove":
+ return (applyDir, False)
+ return (applyDir, objHead)
+
+ def scanProfiles(self, serviceName=False, dirObjs=False):
+ """Сканирует директории профилей - выводит список файлов"""
+ if not self.objVar.defined("cl_profile_path"):
+ self.setError (_("not defined Var: ") + "cl_profile_path")
+ return False
+ if not dirObjs:
+ if serviceName :
+ self._servDir = serviceName
+ if self._servDir:
+ if self._servDir[0] != "/":
+ self._servDir = "/" + self._servDir
+ if self._servDir[-1] != "/":
+ self._servDir += "/"
+ self._servDir = os.path.split(self._servDir)[0]
+ dirsProfiles = self.objVar.Get("cl_profile_path")
+ if self._servDir:
+ tmpDirsProfiles = []
+ for dirP in dirsProfiles:
+ dirProf = dirP + self._servDir
+ if os.access(dirProf, os.F_OK):
+ # Если директория существует
+ tmpDirsProfiles.append(dirProf)
+ else:
+ tmpDirsProfiles.append(False)
+ dirsProfiles = tmpDirsProfiles
+ dirObjs = self.scanDirs(dirsProfiles,self.objVar)
+ #файлы к которым были применены профили
+ filesApply = []
+ # Словарь измененных директорий
+ changeDirs = {}
+ dirObjsApply = []
+ for dirObj in dirObjs:
+ dirInfoFile = os.path.join(dirObj.baseDir, self.profDirNameFile)
+ ret = self.__isApplyHeadDir(dirInfoFile)
+ if ret:
+ dirObjsApply.append(dirObj)
+ else:
+ if self.getError():
+ self.setError(_("Incorrect profile: " ) +\
+ dirInfoFile)
+ return False
+ for dirObj in dirObjsApply:
+ # сортируем файлы по названию
+ if dirObj.files:
+ dirObj.files.sort()
+ # сортируем директории по названию
+ if dirObj.dirs:
+ dirObj.dirs.sort()
+ blockDirs = []
+ for dirProfile in dirObj.dirs:
+ newDir = self._baseDir + dirProfile.partition(dirObj.baseDir)[2]
+ newDir = "/".join(map(lambda x:x.split("?")[0],\
+ newDir.split("/")))
+ # Проверяем условие на директорию
+ dirInfoFile = os.path.join(dirProfile, self.profDirNameFile)
+ pathDir, objHeadDir = self.__getGenHeadDir(newDir,
+ dirInfoFile,
+ changeDirs)
+ # Фильтрация профилей по названию директории
+ if pathDir in self.dirsFilter:
+ blockDirs.append(dirProfile)
+ continue
+ if objHeadDir:
+ if isinstance(objHeadDir, dirHeader):
+ if not objHeadDir.headerCorrect:
+ self.setError(_("Incorrect profile: " ) +\
+ dirInfoFile)
+ self.setError(objHeadDir.errorMessage)
+ return False
+ if not objHeadDir.headerTerm:
+ if objHeadDir.getError():
+ self.setError(_("Incorrect profile: " ) +\
+ dirInfoFile)
+ return False
+ if objHeadDir.params.has_key("name"):
+ changeDirs[dirProfile] = pathDir
+ else:
+ if self.getError():
+ self.setError(_("Incorrect profile: " ) +\
+ dirInfoFile)
+ return False
+ blockDirs.append(dirProfile)
+ for fileProfile in dirObj.files:
+ findBlock = False
+ for blDir in blockDirs:
+ st,mid,end = fileProfile.partition(blDir)
+ if (not st) and mid and end:
+ findBlock = True
+ break
+ if findBlock:
+ continue
+ if self.getNeedProfile(fileProfile):
+ if self.getError():
+ #print self.getError()
+ return False
+ fileProfileChange = fileProfile
+ findChangeDir = False
+ listD = changeDirs.items()
+ listD.reverse()
+ for dirChangeIn, dirChangeOut in listD:
+ st,mid,end = fileProfile.partition(dirChangeIn)
+ if (not st) and mid and end:
+ findChangeDir = True
+ break
+ if findChangeDir:
+ oldFile = dirChangeOut + end
+ else:
+ oldFile = fileProfile.partition(dirObj.baseDir)[2]
+ # файл в системе без условий
+ oldFile = "/".join(map(lambda x:x.split("?")[0],\
+ oldFile.split("/")))
+ if not findChangeDir:
+ oldFile = self._baseDir + oldFile
+ # Фильтрация профилей по названию файла
+ if oldFile in self.filesFilter:
+ continue
+ filesApply.append(oldFile)
+ else:
+ if self.getError():
+ return False
+ return filesApply
+
+ def __isApplyHeadDir(self, profileDirFile):
+ """Будет ли применен профиль корневой директории
+
+ Возвращает True, False
+ """
+
+ def function(text):
+ """Функция обработки функций в заголовке"""
+ return self.applyFuncProfile(text, "", profileDirFile)
+
+ if not os.path.exists(profileDirFile):
+ return True
+ try:
+ FD = open(profileDirFile)
+ textProfile = FD.read()
+ FD.close()
+ except:
+ self.setError(_("Error open profile: " ) +\
+ profileDirFile)
+ return False
+ # Заменяем переменные на их значения
+ textProfile = self.applyVarsProfile(textProfile, profileDirFile)
+ # Обработка заголовка
+ objHead = dirHeader(textProfile, self.objVar,function)
+ if not objHead.headerCorrect:
+ self.setError(_("Incorrect profile: " ) +\
+ profileDirFile)
+ self.setError(objHead.errorMessage)
+ return False
+ if not objHead.headerTerm:
+ if objHead.getError():
+ self.setError(_("Incorrect profile: " ) +\
+ profileDirFile)
+ return False
+
+ ## Изменяем название директории
+ #if objHead.params.has_key("name"):
+ #self.setError (_("Invalid name 'name' in profile: " ) +\
+ #profileDirFile)
+ #return False
+
+ ## Удаляем директорию
+ #if objHead.typeAppend == "remove":
+ #self.setError (_("Invalid name 'remove' in profile: " ) +\
+ #profileDirFile)
+ #return False
+
+ ## chmod - изменяем права
+ #if objHead.params.has_key("chmod"):
+ #self.setError (_("Invalid name 'chmod' in profile: " ) +\
+ #profileDirFile)
+ #return False
+
+ ## chown - изменяем владельца и группу
+ #if objHead.params.has_key("chown"):
+ #self.setError (_("Invalid name 'chown' in profile: " ) +\
+ #profileDirFile)
+ #return False
+ return True
+
+ def __getApplyHeadDir(self, newDir, profileDirFile, changeDirs):
+ """Применяет профиль к директории (права, владелец, и.т. д)"""
+
+ def function(text):
+ """Функция обработки функций в заголовке"""
+ return self.applyFuncProfile(text, newDir, profileDirFile)
+
+ newDirMv = newDir
+ findChangeDir = False
+ #Меняем путь к директории
+ listD = changeDirs.items()
+ listD.reverse()
+ for dirChangeIn, dirChangeOut in listD:
+ st,mid,end = profileDirFile.partition(dirChangeIn)
+ if (not st) and mid:
+ findChangeDir = True
+ break
+ if findChangeDir:
+ pathRel = dirChangeOut
+ lenPathRel = len(pathRel.split("/"))
+ lenNewDir = len(newDir.split("/"))
+ lenEndDir = lenNewDir - lenPathRel
+ tmpDir = newDir
+ namesDirs = []
+ for i in range(lenEndDir):
+ namesDirs.append(os.path.split(tmpDir)[1])
+ tmpDir = os.path.split(tmpDir)[0]
+ namesDirs.reverse()
+ nameDir = "/".join(namesDirs)
+ newDirMv = os.path.join(pathRel, nameDir)
+ applyDir = newDirMv
+ if not os.path.exists(profileDirFile):
+ return (applyDir, True)
+ try:
+ FD = open(profileDirFile)
+ textProfile = FD.read()
+ FD.close()
+ except:
+ self.setError(_("Error open profile: " ) +\
+ profileDirFile)
+ return (applyDir, False)
+ # Заменяем переменные на их значения
+ textProfile = self.applyVarsProfile(textProfile, profileDirFile)
+ # Обработка заголовка
+ objHead = dirHeader(textProfile, self.objVar,function)
+ if not objHead.headerCorrect:
+ self.setError(_("Incorrect profile: " ) +\
+ profileDirFile)
+ self.setError(objHead.errorMessage)
+ return (applyDir, False)
+ if not objHead.headerTerm:
+ if objHead.getError():
+ self.setError(_("Incorrect profile: " ) +\
+ profileDirFile)
+ return (applyDir, False)
+
+ # Изменяем название директории
+ if objHead.params.has_key("name"):
+ nameDir = objHead.params['name']
+ if "/" in nameDir or nameDir == ".." or nameDir == ".":
+ self.setError (_("False value 'name' in profile: " ) +\
+ profileDirFile)
+ return (applyDir, False)
+ if not findChangeDir:
+ pathRel = os.path.split(os.path.abspath(newDirMv))[0]
+ # Новый путь к оригинальному файлу
+ newDirMv = os.path.join(pathRel, nameDir)
+ applyDir = newDirMv
+
+ # Удаляем директорию
+ if objHead.typeAppend == "remove":
+ if os.path.isdir(newDirMv):
+ # удаляем директорию
+ try:
+ self.removeDir(newDirMv)
+ except:
+ self.setError(_("Can not delete dir: " ) +\
+ newDirMv)
+ return (applyDir, False)
+
+ # chmod - изменяем права
+ if objHead.params.has_key("chmod"):
+ mode = self.__octToInt(objHead.params['chmod'])
+ if mode:
+ if not os.path.exists(newDirMv):
+ os.mkdir(newDirMv, mode)
+ else:
+ os.chmod(newDirMv, mode)
+ else:
+ self.setError (_("False value 'chmod' in profile: " ) +\
+ profileDirFile)
+ return (applyDir, False)
+ # chown - изменяем владельца и группу
+ if objHead.params.has_key("chown"):
+ owner = objHead.params['chown']
+ if owner:
+ if ":" in owner:
+ strUid, strGid = owner.split(":")
+ import pwd
+ try:
+ uid = pwd.getpwnam(strUid)[2]
+ except:
+ self.setError (_("Not user in this system: ") + strUid)
+ self.setError (_("False value 'chown' in profile: " )+\
+ profileDirFile)
+ return (applyDir, False)
+ try:
+ import grp
+ gid = grp.getgrnam(strGid)[2]
+ except:
+ self.setError (_("Not group in this system: ")+strGid)
+ self.setError (_("False value 'chown' in profile: " )+\
+ profileDirFile)
+ return (applyDir, False)
+
+ if not os.path.exists(newDirMv):
+ dirProfile = os.path.split(profileDirFile)[0]
+ try:
+ mode,uidTmp,gidTmp = self.getModeFile(dirProfile)
+ except OSError:
+ self.setError (_("not access dir:" ) + newDirMv)
+ return (applyDir, False)
+ os.mkdir(newDirMv, mode)
+ os.chown(newDirMv, uid, gid)
+ else:
+ self.setError (_("False value 'chown' in profile: " ) +\
+ profileDirFile)
+ return (applyDir, False)
+ else:
+ self.setError (_("False value 'chown' in profile: " ) +\
+ profileDirFile)
+ return (applyDir, False)
+ return (applyDir, objHead)
+
+ def __getApplyHeadProfile(self ,newFile, oldFile, copyFile):
+ """Применяет заголовок к профилю (права, владелец, и.т. д)"""
+
+ def function(text):
+ """Функция обработки функций в заголовке"""
+ return self.applyFuncProfile(text, newFile, oldFile)
+
+ self.closeFiles()
+ # Файлы в системе к которым были применены профили
+ applyFiles = [oldFile]
+ if copyFile:
+ self.nameFileNew = self.absFileName(newFile)
+ self.FN = self.openNewFile(self.nameFileNew)
+ self.newProfile = self.FN.read()
+ self.closeNewFile()
+ objHeadNew = fileHeader(self.newProfile, False,
+ self.getFileType(),objVar=self.objVar,
+ function=function)
+ if not objHeadNew.headerCorrect:
+ self.setError(_("Incorrect profile: " ) +\
+ newFile)
+ self.setError(objHeadNew.errorMessage)
+ return (applyFiles, False)
+ if not objHeadNew.headerTerm:
+ if objHeadNew.getError():
+ self.setError(_("Incorrect profile: " ) +\
+ newFile)
+ return (applyFiles, False)
+
+ pathProg = ""
+ # Путь к оригинальному файлу
+ pathOldFile = oldFile
+ # Изменяем путь к оригинальному файлу
+ if objHeadNew.params.has_key("name"):
+ nameFile = objHeadNew.params['name']
+ if "/" in nameFile or nameFile == ".." or nameFile == ".":
+ self.setError (_("False value 'name' in profile: " ) + newFile)
+ return False
+ pathRel = os.path.split(os.path.abspath(oldFile))[0]
+ # Новый путь к оригинальному файлу
+ pathOldFile = os.path.join(pathRel,nameFile)
+
+ # В случае force
+ if objHeadNew.params.has_key("force"):
+ if os.path.islink(pathOldFile):
+ # удаляем ссылку
+ try:
+ os.unlink(pathOldFile)
+ except:
+ self.setError(_("Can not delete link: " ) +\
+ pathOldFile)
+ return (applyFiles, False)
+ if os.path.isfile(pathOldFile):
+ # удаляем файл
+ try:
+ os.remove(pathOldFile)
+ except:
+ self.setError(_("Can not delete file: " ) +\
+ pathOldFile)
+ return (applyFiles, False)
+
+ # Удаляем оригинальный файл
+ if objHeadNew.typeAppend == "remove":
+ if os.path.islink(pathOldFile):
+ # удаляем ссылку
+ try:
+ os.unlink(pathOldFile)
+ except:
+ self.setError(_("Can not delete link: " ) +\
+ pathOldFile)
+ if os.path.isfile(pathOldFile):
+ # удаляем файл
+ try:
+ os.remove(pathOldFile)
+ except:
+ self.setError(_("Can not delete file: " ) +\
+ pathOldFile)
+ return (applyFiles, False)
+
+ flagSymlink = False
+ flagForce = False
+ # Если есть параметр mirror
+ if objHeadNew.params.has_key("mirror"):
+ if objHeadNew.params.has_key("link"):
+ profileFile = objHeadNew.params['link']
+ if not os.path.exists(profileFile):
+ if os.path.exists(pathOldFile):
+ os.remove(pathOldFile)
+ return (applyFiles, False)
+ elif not os.path.exists(pathOldFile):
+ return (applyFiles, False)
+ # Если есть указатель на файл профиля (link)
+ if objHeadNew.params.has_key("link") and\
+ not objHeadNew.params.has_key("symbolic"):
+ profileFile = objHeadNew.params['link']
+ foundProfileFile = os.path.exists(profileFile)
+ if foundProfileFile:
+ FO = self.openNewFile(profileFile)
+ buff = FO.read()
+ FO.close()
+ if os.path.exists(pathOldFile):
+ os.remove(pathOldFile)
+ if foundProfileFile:
+ fd = os.open(pathOldFile, os.O_CREAT)
+ os.close(fd)
+ os.chmod(pathOldFile, self._mode)
+ os.chown(pathOldFile, self._uid, self._gid)
+ FON = open (pathOldFile, "r+")
+ FON.write(buff)
+ FON.close()
+
+ # Если символическая ссылка
+ if objHeadNew.params.has_key("symbolic"):
+ prevOldFile = pathOldFile
+ pathOldFile = objHeadNew.params['link']
+ flagSymlink = True
+ if not "/" == pathOldFile[0]:
+ pathLink = os.path.split(os.path.abspath(prevOldFile))[0]
+ pathProg = os.getcwd()
+ os.chdir(pathLink)
+
+ # chmod - изменяем права
+ if objHeadNew.params.has_key("chmod"):
+ mode = self.__octToInt(objHeadNew.params['chmod'])
+ if mode:
+ if not os.path.exists(pathOldFile):
+ fd = os.open(pathOldFile, os.O_CREAT)
+ os.close(fd)
+ os.chmod(pathOldFile, mode)
+ else:
+ self.setError (_("False value 'chmod' in profile: " ) +\
+ newFile)
+ return (applyFiles, False)
+
+ # chown - изменяем владельца и группу
+ if objHeadNew.params.has_key("chown"):
+ owner = objHeadNew.params['chown']
+ if owner:
+ if ":" in owner:
+ strUid, strGid = owner.split(":")
+ import pwd
+ try:
+ uid = pwd.getpwnam(strUid)[2]
+ except:
+ self.setError (_("Not user in this system: ") + strUid)
+ self.setError (_("False value 'chown' in profile: " )+\
+ newFile)
+ return (applyFiles, False)
+ try:
+ import grp
+ gid = grp.getgrnam(strGid)[2]
+ except:
+ self.setError (_("Not group in this system: ")+strGid)
+ self.setError (_("False value 'chown' in profile: " )+\
+ newFile)
+ return (applyFiles, False)
+
+ if not os.path.exists(pathOldFile):
+ FO = self.openNewFile(newFile)
+ FO.close()
+ fd = os.open(pathOldFile, os.O_CREAT)
+ os.close(fd)
+ os.chmod(pathOldFile, self._mode)
+ os.chown(pathOldFile, uid, gid)
+ else:
+ self.setError (_("False value 'chown' in profile: " ) +\
+ newFile)
+ return (applyFiles, False)
+ else:
+ self.setError (_("False value 'chown' in profile: " ) +\
+ newFile)
+ return (applyFiles, False)
+
+ self.openFiles(newFile, pathOldFile)
+ if flagSymlink:
+ if os.path.exists(prevOldFile) or os.path.islink(prevOldFile):
+ if os.path.islink(prevOldFile):
+ # если ссылка то удаляем её
+ os.unlink(prevOldFile)
+ else:
+ # иначе удаляем файл
+ os.remove(prevOldFile)
+ if not "/" == pathOldFile[0]:
+ os.symlink(pathOldFile, prevOldFile)
+ applyFiles = [prevOldFile,os.path.join(pathLink,pathOldFile)]
+ else:
+ os.symlink(pathOldFile, prevOldFile)
+ applyFiles = [prevOldFile,pathOldFile]
+ if not objHeadNew.body.strip():
+ return (applyFiles, False)
+ else:
+ applyFiles = [pathOldFile]
+ if pathProg:
+ os.chdir(pathProg)
+ # Если файлы заменяются не нужно их обрабатывать дальше
+ if objHeadNew.typeAppend == "replace" and\
+ not objHeadNew.params.has_key("symbolic") and\
+ objHeadNew.params.has_key("link"):
+ return (applyFiles, False)
+ return (applyFiles, objHeadNew)
+
+ def createNewClass(self, name, bases, attrs={}):
+ """Создает объект нового класса
+
+ createNewClass(self, name, bases, attrs)
+ name - имя класса - str,
+ bases - cписок наследуемых классов - (tuple),
+ attrs - аттрибуты класса - {dict}
+ """
+ class newMethod:
+ #Объединяем конфигурации
+ def join(self, newObj):
+ if newObj.__class__.__name__ == self.__class__.__name__:
+ self.docObj.joinDoc(newObj.doc)
+ # Пост обработка
+ if 'postXML' in dir(self):
+ self.postXML()
+ attrsNew = {}
+ attrsNew["configName"] = name
+ if attrs:
+ for key in attrs.keys():
+ attrsNew[key] = attrs[key]
+ newCl = type(name, bases + (newMethod, object,), attrsNew)
+ return newCl
+
+ def fileIsUtf(self, fileName):
+ """Проверяет файл на кодировку UTF-8"""
+ if os.path.exists(fileName):
+ FD = open(self.absFileName(fileName))
+ newProfile = FD.read()
+ FD.close()
+ try:
+ newProfile.decode("UTF-8")
+ except:
+ return False
+ return True
+
+ def join(self, newFile, oldFile, ListOptTitle):
+ """Объединения профиля и конф. файла
+
+ join(newFile, oldFile, ListOptTitle)
+ Объединение профиля newFile и конф. файла oldFile,
+ ListOptTitle - список строк которые добавятся в заголовок
+ """
+ # Выполняем условия для блока текста а так-же заменяем переменные
+ self.nameFileNew = self.absFileName(newFile)
+ self.FN = self.openNewFile(self.nameFileNew)
+ self.newProfile = self.FN.read()
+ self.closeNewFile()
+ copyFile = True
+ if self.getFileType() != "bin":
+ # Вычисляем условные блоки
+ self.newProfile = self.applyTermsProfile(self.newProfile,
+ newFile, oldFile)
+ #print "|%s|" %(self.newProfile)
+ # Заменяем переменные на их значения
+ self.newProfile = self.applyVarsProfile(self.newProfile,
+ newFile)
+ # Вычисляем функции
+ self.newProfile = self.applyFuncProfile(self.newProfile,
+ newFile, oldFile)
+ copyFile = False
+ filesApply, objHeadNew = self.__getApplyHeadProfile(newFile, oldFile,
+ copyFile)
+ if not objHeadNew:
+ return filesApply
+ # Флаг - кодировка с бинарными примесями у файла профиля включаем при
+ # условии текстового файла и кодировки отличной от UTF-8
+ flagNotUtf8New = False
+ # Флаг - кодировка с бинарными примесями у оригинального файла
+ flagNotUtf8Old = False
+ if not copyFile:
+ # проверяем кодировку профиля
+ if not self.fileIsUtf(newFile):
+ flagNotUtf8New = True
+ if not (objHeadNew.params.has_key("link") and\
+ objHeadNew.params.has_key("symbolic")):
+ # проверяем кодировку оригинального файла
+ if not self.fileIsUtf(oldFile):
+ flagNotUtf8Old = True
+ self.newProfile = objHeadNew.body
+ #if objHeadNew.fileType != "bin":
+ #self.newProfile = self.applyTermsProfile(self.newProfile,
+ #newFile)
+ #self.newProfile = self.applyVarsProfile(self.newProfile)
+
+ # Титл конфигурационного файла
+ title = ""
+ if ListOptTitle:
+ title = self.getTitle(objHeadNew.comment,
+ ListOptTitle)
+ title = title.encode("UTF-8")
+
+ objHeadOld = False
+ if objHeadNew.comment:
+ objHeadOld = fileHeader(self.oldProfile, objHeadNew.comment)
+ # Тестирование
+ #print self.nameFileOld
+ #print objHeadNew.typeAppend
+ if objHeadNew.fileType:
+ # Создаем объект в случае параметра format в заголовке
+ if (objHeadNew.typeAppend == "replace" or\
+ objHeadNew.typeAppend == "before" or\
+ objHeadNew.typeAppend == "after") and\
+ not (objHeadNew.fileType == "bin" or\
+ objHeadNew.fileType == "raw"):
+ # Преобразовываем бинарные файлы
+ if flagNotUtf8New:
+ objTxtCoder = utfBin()
+ self.newProfile = objTxtCoder.encode(self.newProfile)
+ try:
+ exec ("objProfNew=%s(self.newProfile)"%\
+ (objHeadNew.fileType))
+ except NameError:
+ #Создаем объект из self.newObjProt с помощью
+ # метаклассов
+ if self.newObjProt.has_key(objHeadNew.fileType):
+ objProfNewCl = self.createNewClass(\
+ objHeadNew.fileType,
+ self.newObjProt[objHeadNew.fileType])
+ objProfNew = objProfNewCl(self.newProfile)
+ else:
+ self.setError (\
+ _("False join profile for type profile: ")\
+ + objHeadNew.fileType + " : " +\
+ newFile)
+ return False
+
+ if "xml_" in objHeadNew.fileType:
+ if objProfNew.getError():
+ self.setError (_("False profile: " ) + newFile)
+ return False
+ nameRootNode = oldFile.rpartition("/")[2].split(".")[0]
+ objProfNew.setNameBodyNode(nameRootNode)
+ # Объект Документ
+ docObj = objProfNew.docObj
+ # Удаление комментариев из документа
+ docObj.removeComment(docObj.getNodeBody())
+ # Добавление необходимых переводов строк
+ docObj.insertBRtoBody(docObj.getNodeBody())
+ # Добавление необходимых разделителей между областями
+ docObj.insertBeforeSepAreas(docObj.getNodeBody())
+ # Пост обработка
+ if 'postXML' in dir(objProfNew):
+ objProfNew.postXML()
+ # Получение текстового файла из XML документа
+ self.newProfile = objProfNew.getConfig().encode("UTF-8")
+ # Если не UTF-8 производим преобразование
+ if flagNotUtf8New:
+ self.newProfile = objTxtCoder.decode(self.newProfile)
+ # Титл для объединения
+ if ListOptTitle:
+ title = self.getTitle(objProfNew._comment,
+ ListOptTitle)
+ title = title.encode("UTF-8")
+ # Замена
+ if objHeadNew.typeAppend == "replace":
+ if "xml_" in objHeadNew.fileType:
+ data = self.newProfile.split("\n")
+ data.insert(1,title)
+ self.oldProfile = "\n".join(data)
+ else:
+ if objHeadNew.execStr:
+ self.oldProfile = objHeadNew.execStr+title+\
+ self.newProfile
+ else:
+ self.oldProfile = title + self.newProfile
+ self.saveOldFile()
+ return filesApply
+ # Впереди
+ elif objHeadNew.typeAppend == "before":
+ if "xml_" in objHeadNew.fileType:
+ self.setError (\
+ _("False option append=before in profile %s") %newFile)
+ return False
+ if objHeadOld and objHeadOld.body:
+ self.oldProfile = objHeadOld.body
+ if self.newProfile[-1] == "\n":
+ tmpProfile = self.newProfile + self.oldProfile
+ else:
+ tmpProfile = self.newProfile + "\n" + self.oldProfile
+ if objHeadNew.execStr:
+ self.oldProfile = objHeadNew.execStr + title + tmpProfile
+ elif objHeadOld.execStr:
+ self.oldProfile = objHeadOld.execStr + title + tmpProfile
+ else:
+ self.oldProfile = title + tmpProfile
+
+ #print self.oldProfile
+ self.saveOldFile()
+ return filesApply
+ # Cзади
+ elif objHeadNew.typeAppend == "after":
+ if "xml_" in objHeadNew.fileType:
+ self.setError (\
+ _("False option append=after in profile %s") %newFile)
+ return False
+ if objHeadOld and objHeadOld.body:
+ self.oldProfile = objHeadOld.body
+ if self.newProfile[-1] == "\n":
+ tmpProfile = self.oldProfile + self.newProfile
+ else:
+ tmpProfile = self.oldProfile + "\n" + self.newProfile
+ if objHeadNew.execStr:
+ self.oldProfile = objHeadNew.execStr + title + tmpProfile
+ elif objHeadOld.execStr:
+ self.oldProfile = objHeadOld.execStr + title + tmpProfile
+ else:
+ self.oldProfile = title + tmpProfile
+ self.saveOldFile()
+ return filesApply
+ # Объединение
+ elif objHeadNew.typeAppend == "join":
+ if flagNotUtf8New:
+ objTxtCoder = utfBin()
+ self.newProfile = objTxtCoder.encode(self.newProfile)
+ try:
+ exec ("objProfNew=%s(self.newProfile)"%\
+ (objHeadNew.fileType))
+ except NameError:
+ #Создаем объект из self.newObjProt с помощью
+ # метаклассов
+ if self.newObjProt.has_key(objHeadNew.fileType):
+ objProfNewCl = self.createNewClass(\
+ objHeadNew.fileType,
+ self.newObjProt[objHeadNew.fileType])
+ objProfNew = objProfNewCl(self.newProfile)
+ else:
+ self.setError (\
+ _("False join profile for type profile: ")\
+ + objHeadNew.fileType + " : " +\
+ newFile)
+ return False
+ if "xml_" in objHeadNew.fileType:
+ if objProfNew.getError():
+ self.setError (_("False profile: " ) + newFile)
+ return False
+ nameRootNode = oldFile.rpartition("/")[2].split(".")[0]
+ objProfNew.setNameBodyNode(nameRootNode)
+ # Титл для объединения
+ if ListOptTitle:
+ title = self.getTitle(objProfNew._comment,
+ ListOptTitle)
+ title = title.encode("UTF-8")
+
+ # В случае пустого конфигурационного файла
+ reNoClean = re.compile("[^\s]",re.M)
+ if not self.oldProfile or\
+ not reNoClean.search(self.oldProfile):
+ self.oldProfile = ""
+ #if objHeadNew.execStr:
+ #self.oldProfile = objHeadNew.execStr + \
+ #title + objProfNew.getConfig().encode("UTF-8")
+ #else:
+ #self.oldProfile = title +\
+ #objProfNew.getConfig().encode("UTF-8")
+ #self.saveOldFile()
+ #return True
+
+ objHeadOld = fileHeader(self.oldProfile, objProfNew._comment)
+ if objHeadOld.body:
+ self.oldProfile = objHeadOld.body
+ else:
+ self.oldProfile = ""
+ if flagNotUtf8Old:
+ objTxtCoder = utfBin()
+ self.oldProfile = objTxtCoder.encode(self.oldProfile)
+ if self.newObjProt.has_key(objHeadNew.fileType):
+ objProfOldCl = self.createNewClass(\
+ objHeadNew.fileType,
+ self.newObjProt[objHeadNew.fileType])
+ objProfOld = objProfOldCl(self.oldProfile)
+ else:
+ exec ("objProfOld=%s(self.oldProfile)"%\
+ (objHeadNew.fileType))
+ if "xml_" in objHeadNew.fileType:
+ if objProfOld.getError():
+ self.setError (_("False profile: " ) + oldFile)
+ return False
+ nameRootNode = oldFile.rpartition("/")[2].split(".")[0]
+ objProfOld.setNameBodyNode(nameRootNode)
+
+ #print "#%s#" %(objProfOld.docObj.body.toprettyxml())
+ #print "#%s#" %(objProfNew.docObj.body.toprettyxml())
+ objProfOld.join(objProfNew)
+ #print objProfOld.doc.toprettyxml()
+ #print objProfNew.doc.toprettyxml()
+ if "xml_" in objHeadNew.fileType:
+ if objProfOld.getError():
+ self.setError (_("False profile: " ) + newFile)
+ return False
+ data = \
+ objProfOld.getConfig().encode("UTF-8").split("\n")
+ data.insert(1,title)
+ self.oldProfile = "\n".join(data)
+ else:
+ if objHeadNew.execStr:
+ self.oldProfile = objHeadNew.execStr + title +\
+ objProfOld.getConfig().encode("UTF-8")
+ elif objHeadOld.execStr:
+ self.oldProfile = objHeadOld.execStr + title +\
+ objProfOld.getConfig().encode("UTF-8")
+ else:
+ self.oldProfile = title +\
+ objProfOld.getConfig().encode("UTF-8")
+ # Декодируем если кодировка не UTF-8
+ if flagNotUtf8New or flagNotUtf8Old:
+ self.newProfile = objTxtCoder.decode(self.newProfile)
+ self.oldProfile = objTxtCoder.decode(self.oldProfile)
+ self.saveOldFile()
+ return filesApply
+ else:
+ self.setError (_("False (type append) profile: " ) +\
+ objHeadNew.typeAppend)
+ return False
+ else:
+ self.setError (_("Type profile not found: ") + newFile)
+ return False
+ return filesApply
+
+class samba(objShare):
+ """Класс для обработки конфигурационного файла типа samba
+
+ """
+ _comment = "#"
+ configName = "samba"
+ configVersion = "0.1"
+ reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n",re.M)
+ reBody = re.compile(".+",re.M|re.S)
+ reComment = re.compile("\s*%s.*|\s*;.*"%(_comment))
+ reSeparator = re.compile("\s*=\s*")
+ sepFields = "\n"
+ reSepFields = re.compile(sepFields)
+
+ def __init__(self,text):
+ self.text = text
+ self.blocTextObj = blocText()
+ self._splitToFields = self.splitToFields
+ # Объект документ
+ self.docObj = self._textToXML()
+ # XML документ
+ self.doc = self.docObj.doc
+
+ def postXML(self):
+ """Последующая постобработка XML"""
+ # Для добавления перевода строки между областями если его нет
+ #print self.docObj.body.toprettyxml()
+ xmlAreas = xpath.Evaluate("child::area", self.docObj.body)
+ for xmlArea in xmlAreas:
+ if xmlArea.previousSibling and\
+ self.docObj.getTypeField(xmlArea.previousSibling) == "br":
+ continue
+ firstArea = False
+ xmlFields = xpath.Evaluate("child::field", xmlArea)
+ if not (xmlFields and\
+ (self.docObj.getTypeField(xmlFields[-1]) == "br" or\
+ self.docObj.getTypeField(xmlFields[-1]) == "comment")):
+ if xmlArea.nextSibling:
+ parentNode = xmlArea.parentNode
+ nextNode = xmlArea.nextSibling
+ parentNode.insertBefore(self.docObj.createField("br",
+ [],"",[],
+ False,False),
+ nextNode)
+ # Удаление лишних переводов строк
+ childNodes = self.docObj.getFieldsArea(self.docObj.body)
+ lenBr = 0
+ removeBrNodes = []
+ for node in childNodes:
+ if node.tagName == "field" and\
+ self.docObj.getTypeField(node) == "br":
+ lenBr += 1
+ if lenBr > 2:
+ removeBrNodes.append(node)
+ else:
+ lenBr = 0
+ # Удаление
+ for rmNode in removeBrNodes:
+ self.docObj.body.removeChild(rmNode)
+
+
+ def join(self, sambaObj):
+ """Объединяем конфигурации"""
+ if isinstance(sambaObj, samba):
+ self.docObj.joinDoc(sambaObj.doc)
+ self.postXML()
+
+ def setDataField(self, txtLines, endtxtLines):
+ """Создаем список объектов с переменными"""
+ class fieldData:
+ def __init__(self):
+ self.name = False
+ self.value = False
+ self.comment = False
+ self.br = False
+ fields = []
+ field = fieldData()
+ z = 0
+ for k in txtLines:
+ textLine = k + endtxtLines[z]
+ z += 1
+ findComment = self.reComment.search(textLine)
+ if not textLine.strip():
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ elif findComment:
+ field.comment = textLine
+ fields.append(field)
+ field = fieldData()
+ else:
+ pars = textLine.strip()
+ nameValue = self.reSeparator.split(pars)
+ if len(nameValue) > 2:
+ valueList = nameValue[1:]
+ nameValue =[nameValue[0],"=".join(valueList)]
+ if len(nameValue) == 2:
+ name = nameValue[0]
+ value = nameValue[1].replace(self.sepFields,"")
+ field.name = name.replace(" ","").replace("\t","")
+ field.value = value
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ return fields
+
+
+ def splitCleanBloc(self, txtBloc):
+ """Делим блок на две части (переменные, пустые строки в конце)"""
+ txtLines = txtBloc.split("\n")
+ firstBloc = []
+ nextBloc = []
+ txtLines.reverse()
+ z = 0
+ for txtLine in txtLines:
+ if not txtLine.strip():
+ nextBloc.append(txtLine)
+ else:
+ break
+ z += 1
+ txtLines.reverse()
+ firstBloc = txtLines[:-z]
+ nextBloc.reverse()
+ if nextBloc:
+ firstBloc.append("")
+ if nextBloc and "\n".join(nextBloc):
+ return ("\n".join(firstBloc), "\n".join(nextBloc))
+ else:
+ return False
+
+ def getFullAreas(self, blocs):
+ """Делит текст на области, (Заголовок, тело)
+
+ Возвращает два списка: заголовки, тела
+ """
+ headsAreas = []
+ bodyAreas = []
+ if not blocs:
+ return []
+ lenBlocs = len(blocs[0])
+ for i in range(lenBlocs):
+ txtBloc = blocs[1][i]
+ clean = self.splitCleanBloc(txtBloc)
+ if clean:
+ headsAreas.append(blocs[0][i])
+ bodyAreas.append(clean[0])
+ headsAreas.append("")
+ bodyAreas.append(clean[1])
+ else:
+ headsAreas.append(blocs[0][i])
+ bodyAreas.append(blocs[1][i])
+ return (headsAreas, bodyAreas)
+
+ def createTxtConfig(self, strHeader, dictVar):
+ """Cоздает область с заголовком
+
+ создает текст конфигурационного файла в формате samba из
+ заголовка (строка) и словаря переменных
+ """
+ if not strHeader:
+ return ""
+ outTxt = "[" + strHeader + "]\n"
+ for key in dictVar.keys():
+ outTxt += "%s = %s\n" %(key,dictVar[key])
+ return outTxt
+
+ def _textToXML(self):
+ """Преобразует текст в XML"""
+ blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody)
+ blocs = self.getFullAreas(blTmp)
+ headers = []
+ startHeaders = []
+ finHeaders = []
+ docObj = xmlDoc()
+ docObj.createDoc(self.configName, self.configVersion)
+ rootNode = docObj.getNodeBody()
+ # Если пустой текст то создаем пустой документ
+ if not blocs:
+ return docObj
+
+ for h in blocs[0]:
+ listfinH = h.split("]")
+ finH = listfinH[0]
+ if "[" in finH:
+ startHeaders.append(finH + "]")
+ else:
+ startHeaders.append(finH)
+ if len(listfinH) == 2:
+ finHeaders.append(listfinH[1])
+ else:
+ finHeaders.append("")
+ headers.append(finH.replace("[","").replace("]","").strip())
+ bodys = blocs[1]
+
+ z = 0
+ for h in headers:
+ if not bodys[z]:
+ z += 1
+ continue
+ areaAction = False
+ if h:
+ if h[0] == "!":
+ docObj.createCaption(h[1:], [startHeaders[z],""])
+ areaAction = "drop"
+ elif h[0] == "-":
+ docObj.createCaption(h[1:], [startHeaders[z],""])
+ areaAction = "replace"
+ else:
+ docObj.createCaption(h, [startHeaders[z],""])
+ else:
+ docObj.createCaption(h, [startHeaders[z],""])
+
+ if "\n" in blocs[0][z]:
+ if self.reComment.search(finHeaders[z]):
+ docObj.createField('comment', [finHeaders[z]])
+ elif not finHeaders[z].strip() and\
+ finHeaders[z].replace("\n",""):
+ docObj.createField('br',
+ [finHeaders[z].replace("\n","")])
+ else:
+ docObj.createField('br')
+ fields = self._splitToFields(bodys[z])
+ for f in fields:
+ if f.name != False and f.value!=False and f.br!=False:
+ # Обработка условий для samba
+ if f.name[0] == "!" or f.name[0] == "-" or\
+ f.name[0] == "+":
+ qns = self.removeSymbolTerm(f.br)
+ xmlField = docObj.createField("var",
+ [qns],
+ f.name[1:], [f.value])
+ if f.name[0] == "!":
+ # Удаляемое в дальнейшем поле
+ docObj.setActionField(xmlField, "drop")
+ else:
+ docObj.createField("var",[f.br.replace("\n","")],
+ f.name, [f.value])
+ docObj.createField('br')
+ elif f.comment != False:
+ docObj.createField('comment', [f.comment])
+ elif f.br != False:
+ docObj.createField('br', [f.br.replace("\n","")])
+ if h.strip():
+ area = docObj.createArea()
+ if areaAction:
+ docObj.setActionArea(area, areaAction)
+ rootNode.appendChild(area)
+ else:
+ fieldsNodes = docObj.tmpFields.getFields()
+ for fieldNode in fieldsNodes:
+ rootNode.appendChild(fieldNode)
+ docObj.clearTmpFields()
+ z += 1
+ #print docObj.doc.toprettyxml()
+ return docObj
+
+class compiz(samba):
+ """Класс для обработки конфигурационного файла типа compiz
+
+ """
+ _comment = "#"
+ configName = "compiz"
+ configVersion = "0.1"
+ reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n",re.M)
+ reBody = re.compile(".+",re.M|re.S)
+ reComment = re.compile("\s*%s.*"%(_comment))
+ reSeparator = re.compile("\s*=\s*")
+ sepFields = "\n"
+ reSepFields = re.compile(sepFields)
+
+ def __init__(self,text):
+ samba.__init__(self,text)
+
+ def join(self, compizObj):
+ """Объединяем конфигурации"""
+ if isinstance(compizObj, compiz):
+ self.docObj.joinDoc(compizObj.doc)
+ self.postXML()
+
+class bind(objShare):
+ """Класс для обработки конфигурационного файла типа bind
+
+ """
+ _comment = "//"
+ configName = "bind"
+ configVersion = "0.1"
+ __openArea = "{"
+ __closeArea = "[ \t]*\}[ \t]*;[ \t]*"
+ sepFields = ";"
+ reOpen = re.compile(__openArea)
+ reClose = re.compile(__closeArea)
+ reCloseArea = re.compile(__closeArea + "\s*\Z")
+ reComment = re.compile("[ \t]+%s|^%s|(?<=;)%s"%(_comment,_comment,_comment))
+ reSepFields = re.compile(sepFields)
+ reSeparator = re.compile("[ \t]+")
+
+ def __init__(self,text):
+ self.text = text
+ self.blocTextObj = blocText()
+ # Объект документ
+ self.docObj = self.textToXML()
+ # Создаем поля-массивы
+ self.docObj.postParserList()
+ # XML документ
+ self.doc = self.docObj.doc
+
+ # Делим область на составные части
+ def findOpenClose(self, text, reOpen, reClose, reComment):
+ """Делит область на составные части
+
+ начальный текстовый блок,
+ открывающий блок,
+ блок-тело,
+ закрывающий блок
+ """
+ firstBloc = ""
+ startBloc = ""
+ bodyBloc = ""
+ endBloc = ""
+ textLines = text.splitlines()
+ findOpen = False
+ if textLines:
+ findOpen = reOpen.search(textLines[0])
+ openBl = reOpen.search(text)
+ if findOpen and reComment.split(text)[0].strip():
+ blocA = text[openBl.end():]
+ firstBloc = text[:openBl.start()]
+ startBloc = text[openBl.start():openBl.end()]
+ closeBl = reClose.search(blocA)
+ endBloc = blocA[closeBl.start():closeBl.end()]
+ bodyBloc = blocA[:closeBl.start()]
+ return (firstBloc, startBloc, bodyBloc, endBloc)
+ else:
+ return (firstBloc, startBloc, text, endBloc)
+
+
+ # Делим текст на области включая вложенные (areas массив областей)
+ def splitToAllArea(self, text, areas, reOpen, reClose, reCloseArea,
+ reComment, reSepFields):
+ """Делит текст на области включая вложенные
+
+ возвращает список объектов областей (переменная areas)
+ """
+ class area:
+ def __init__(self):
+ self.header = False
+ self.start = False
+ self.fields = []
+ self.end = False
+
+ blocs = self.blocTextObj.splitTxtToBloc(text,reOpen,reClose,
+ reComment,reSepFields)
+ for i in blocs:
+ areaA = area()
+ first,start,body,end = self.findOpenClose(i, reOpen, reCloseArea,
+ reComment)
+ areaA.header = first.replace(" ","").replace("\t","")
+ areaA.start = first + start
+ areaA.end = end
+
+ if areaA.end:
+ blocsA = self.blocTextObj.splitTxtToBloc(body,reOpen,reClose,
+ reComment,reSepFields)
+ if blocsA and blocsA[0] == body:
+ areaA.fields.append(body)
+ areas.append(areaA)
+ else:
+ for ar in blocsA:
+ self.splitToAllArea(ar, areaA.fields, reOpen,
+ reClose,
+ reCloseArea, reComment,
+ reSepFields)
+ areas.append(areaA)
+ else:
+ areaA.fields.append(body)
+ areas.append(areaA)
+ return areas
+
+
+ def setDataField(self, txtLines, endtxtLines):
+ """Создаем список объектов с переменными"""
+ class fieldData:
+ def __init__(self):
+ self.name = False
+ self.value = False
+ self.comment = False
+ self.br = False
+ fields = []
+ field = fieldData()
+ z = 0
+ for k in txtLines:
+ textLine = k + endtxtLines[z]
+ z += 1
+ findComment = self.reComment.search(textLine)
+ if not textLine.strip():
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ elif findComment:
+ field.comment = textLine
+ fields.append(field)
+ field = fieldData()
+ else:
+ pars = textLine.strip()
+ nameValue = self.reSeparator.split(pars)
+ if len (nameValue) == 1:
+ field.name = ""
+ field.value = textLine.replace(self.sepFields,"")
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+
+ if len(nameValue) > 2:
+ valueList = nameValue[1:]
+ nameValue =[nameValue[0]," ".join(valueList).replace(\
+ self.sepFields,"")]
+ if len(nameValue) == 2:
+ name = nameValue[0]
+ value = nameValue[1].replace(self.sepFields,"")
+ field.name = name.replace(" ","").replace("\t","")
+ field.value = value
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ return fields
+
+ def createCaptionTerm(self, header, start, end, docObj):
+ """Создание пустой области с заголовком
+
+ при создании области проверяется первый символ заголовка
+ и добавляется тег action
+ "!" - drop
+ "-" - replace
+ """
+ areaAction = False
+ if header:
+ if header[0] == "!":
+ docObj.createCaption(header[1:], [start,
+ end.replace("\n","")])
+ areaAction = "drop"
+ elif header[0] == "-":
+ docObj.createCaption(header[1:], [start,
+ end.replace("\n","")])
+ areaAction = "replace"
+ else:
+ docObj.createCaption(header, [start,
+ end.replace("\n","")])
+ else:
+ docObj.createCaption(header, [start,
+ end.replace("\n","")])
+
+ areaXML = docObj.createArea()
+ if areaAction:
+ docObj.setActionArea(areaXML, areaAction)
+ return areaXML
+
+ def createXML(self, areas, rootNode, docObj):
+ """Создаем из массивов областей XML"""
+ for i in areas:
+ if str(i.__class__.__name__) == "area":
+ if i.header and i.start:
+ areaXML = self.createCaptionTerm(i.header, i.start,
+ i.end.replace("\n",""),
+ docObj)
+ else:
+ areaXML = rootNode
+ for f in i.fields:
+ if str(f.__class__.__name__) == "area":
+ if f.header and f.start:
+ areaXMLChild = self.createCaptionTerm(f.header,
+ f.start,
+ f.end.replace("\n",""),
+ docObj)
+
+ self.createXML(f.fields, areaXMLChild, docObj)
+
+ areaXML.appendChild(areaXMLChild)
+ else:
+ self.createXML(f.fields, areaXML, docObj)
+ if "\n" in f.end:
+ fieldXMLBr = docObj.createField("br",[],
+ "",[],
+ False, False)
+ areaXML.appendChild(fieldXMLBr)
+ else:
+ if not f:
+ continue
+ fields = self.splitToFields(f)
+ for field in fields:
+ if field.name != False:
+ fieldXML = self.createFieldTerm(field.name,
+ field.value,
+ field.br, docObj)
+ areaXML.appendChild(fieldXML)
+ if field.br[-1] == "\n":
+ fieldXMLBr = docObj.createField("br",[],
+ "",[],
+ False, False)
+ areaXML.appendChild(fieldXMLBr)
+ elif field.comment != False:
+ fieldXML = docObj.createField("comment",
+ [field.comment],
+ "", [],
+ False, False)
+ areaXML.appendChild(fieldXML)
+ elif field.br != False:
+ brText = field.br.replace("\n","")
+ if brText:
+ fieldXML = docObj.createField('br',
+ [brText],
+ "", [],
+ False, False)
+ else:
+ fieldXML = docObj.createField('br',
+ [],
+ "", [],
+ False, False)
+ areaXML.appendChild(fieldXML)
+
+ if i.header and i.start:
+ rootNode.appendChild(areaXML)
+ if "\n" in i.end:
+ fieldXMLBr = docObj.createField("br",[],
+ "",[],
+ False, False)
+ rootNode.appendChild(fieldXMLBr)
+
+ else:
+ fields = self.splitToFields(i)
+ for field in fields:
+ if field.name != False:
+ fieldXML = self.createFieldTerm(field.name,
+ field.value,
+ field.br, docObj)
+ rootNode.appendChild(fieldXML)
+ if field.br[-1] == "\n":
+ fieldXMLBr = docObj.createField("br",[],"", [],
+ False, False)
+ rootNode.appendChild(fieldXMLBr)
+ elif field.comment != False:
+ fieldXML = docObj.createField("comment",
+ [field.comment],
+ "", [],
+ False, False)
+ rootNode.appendChild(fieldXML)
+ elif field.br != False:
+ brText = field.br.replace("\n","")
+ if brText:
+ fieldXML = docObj.createField('br', [brText],"",[],
+ False, False)
+ else:
+ fieldXML = docObj.createField('br', [], "", [],
+ False, False)
+ rootNode.appendChild(fieldXML)
+ #rootNode.appendChild(areaXML)
+
+ def textToXML(self):
+ """Преобразуем текст в XML"""
+ areas = []
+ if self.text.strip():
+ self.splitToAllArea(self.text, areas, self.reOpen, self.reClose,
+ self.reCloseArea,self.reComment,self.reSepFields)
+ docObj = xmlDoc()
+ # Создание объекта документ c пустым разделителем между полями
+ docObj.createDoc(self.configName, self.configVersion)
+ if not areas:
+ return docObj
+ self.createXML(areas, docObj.getNodeBody(), docObj)
+ return docObj
+
+
+ def join(self, bindObj):
+ """Объединяем конфигурации"""
+ if isinstance(bindObj, bind):
+ self.docObj.joinDoc(bindObj.doc)
+
+class apache(bind):
+ """Класс для обработки конфигурационного файла типа apache
+
+ """
+ _comment = "#"
+ configName = "apache"
+ configVersion = "0.1"
+ __headerArea = "[^\<\> \t]+[ \t]+[^\<\> \t]+"
+ __openArea = "[ \t]*\<%s\>"%(__headerArea)
+ __closeArea = "[ \t]*\<\/[^\<\>]+\>"
+ sepFields = "\n"
+ reOpen = re.compile(__openArea)
+ reClose = re.compile(__closeArea)
+ reCloseArea = re.compile(__closeArea + "\s*\Z")
+ reComment = re.compile("[ \t]*%s"%(_comment))
+ reSepFields = re.compile(sepFields)
+ reSeparator = re.compile("[ \t]+")
+ reHeader = re.compile(__headerArea)
+
+ def __init__(self,text):
+ self.text = text
+ self.blocTextObj = blocText()
+ # Объект документ
+ self.docObj = self.textToXML()
+ # Создаем поля-массивы
+ self.docObj.postParserList()
+ # Создаем поля разделенные массивы
+ self.docObj.postParserListSeplist(self.docObj.body)
+ # XML документ
+ self.doc = self.docObj.doc
+
+ def postXML(self):
+ """Последующая постобработка XML"""
+ # Для добавления перевода строки перед закрывающим тегом
+ # конфигурационного файла
+ xmlFields = xpath.Evaluate("child::fields", self.docObj.body)
+ if not (xmlFields and\
+ self.docObj.getTypeField(xmlFields[-1]) == "br"):
+ self.docObj.body.appendChild(self.docObj.createField("br",
+ [],"",[],
+ False,False))
+ xmlAreas = xpath.Evaluate("child::area", self.docObj.body)
+ for xmlArea in xmlAreas:
+ xmlFields = xpath.Evaluate("child::field", xmlArea)
+ if not (xmlFields and\
+ self.docObj.getTypeField(xmlFields[-1]) == "br"):
+ xmlArea.appendChild(self.docObj.createField("br",
+ [],"",[],
+ False,False))
+
+ def join(self, apacheObj):
+ """Объединяем конфигурации"""
+ if isinstance(apacheObj, apache):
+ #print self.docObj.doc.toprettyxml()
+ self.docObj.joinDoc(apacheObj.doc)
+ self.postXML()
+
+ # Делим область на составные части
+ def findOpenClose(self, text, reOpen, reClose, reComment, reHeader):
+ """Делит область на составные части
+
+ начальный текстовый блок,
+ открывающий блок,
+ блок-тело,
+ закрывающий блок
+ """
+ firstBloc = ""
+ startBloc = ""
+ bodyBloc = ""
+ endBloc = ""
+ textLines = text.splitlines()
+ findOpen = False
+ if textLines:
+ findOpen = reOpen.search(textLines[0])
+ openBl = reOpen.search(text)
+ if findOpen and reComment.split(text)[0].strip():
+ blocA = text[openBl.end():]
+ firstBloc = ""
+ startBloc = text[openBl.start():openBl.end()]
+ headBl = reHeader.search(startBloc)
+ if headBl:
+ firstBloc = headBl.group(0)
+ closeBl = reClose.search(blocA)
+ endBloc = blocA[closeBl.start():closeBl.end()]
+ bodyBloc = blocA[:closeBl.start()]
+ return (firstBloc, startBloc, bodyBloc, endBloc)
+ else:
+ return (firstBloc, startBloc, text, endBloc)
+
+ # Делим текст на области включая вложенные (areas массив областей)
+ def splitToAllArea(self, text, areas, reOpen, reClose, reCloseArea,
+ reComment, reSepFields, reHeader):
+ """Делит текст на области включая вложенные
+
+ возвращает список объектов областей (переменная areas)
+ """
+ class area:
+ def __init__(self):
+ self.header = False
+ self.start = False
+ self.fields = []
+ self.end = False
+
+ blocs = self.blocTextObj.splitTxtToBloc(text,reOpen,reClose,
+ reComment,reSepFields)
+ for i in blocs:
+ areaA = area()
+ first,start,body,end = self.findOpenClose(i, reOpen, reCloseArea,
+ reComment, reHeader)
+ areaA.header = first.replace(" ","").replace("\t","")
+ areaA.start = start
+ areaA.end = end
+
+ if areaA.end:
+ blocsA = self.blocTextObj.splitTxtToBloc(body,reOpen,reClose,
+ reComment,reSepFields)
+ if blocsA and blocsA[0] == body:
+ areaA.fields.append(body)
+ areas.append(areaA)
+ else:
+ for ar in blocsA:
+ self.splitToAllArea(ar, areaA.fields, reOpen,
+ reClose,
+ reCloseArea, reComment,
+ reSepFields, reHeader)
+ areas.append(areaA)
+ else:
+ areaA.fields.append(body)
+ areas.append(areaA)
+
+
+ def setDataField(self, txtLines, endtxtLines):
+ """Создаем список объектов с переменными"""
+ class fieldData:
+ def __init__(self):
+ self.name = False
+ self.value = False
+ self.comment = False
+ self.br = False
+ fields = []
+ field = fieldData()
+ z = 0
+ for k in txtLines:
+ textLine = k + endtxtLines[z]
+ #print "#"+brBloc[z]+"#"
+ z += 1
+ findComment = self.reComment.search(textLine)
+ if not textLine.strip():
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ elif findComment:
+ field.comment = textLine
+ fields.append(field)
+ field = fieldData()
+ else:
+ pars = textLine.strip()
+ nameValue = self.reSeparator.split(pars)
+ if len (nameValue) == 1:
+ field.name = ""
+ field.value = textLine.replace(self.sepFields,"")
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+
+ if len(nameValue) == 3:
+ valueList = nameValue[2:]
+ nameValue =["".join(nameValue[:2])," ".join(valueList)]
+
+ if len(nameValue) > 3:
+ valueList = nameValue[1:]
+ nameValue =[nameValue[0]," ".join(valueList).replace(\
+ self.sepFields,"")]
+ if len(nameValue) == 2:
+ name = nameValue[0]
+ value = nameValue[1].replace(self.sepFields,"")
+ field.name = name.replace(" ","").replace("\t","")
+ field.value = value
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ return fields
+
+
+ def textToXML(self):
+ """Преобразуем тект в XML"""
+ areas = []
+ self.splitToAllArea(self.text, areas, self.reOpen, self.reClose,
+ self.reCloseArea,self.reComment,self.reSepFields,
+ self.reHeader)
+ docObj = xmlDoc()
+
+ # Создание объекта документ c пустым разделителем между полями
+ docObj.createDoc(self.configName, self.configVersion)
+ if not areas:
+ return docObj
+ self.createXML(areas, docObj.getNodeBody(), docObj)
+ return docObj
+
+class postfix(apache):
+ """Класс для обработки конфигурационного файла типа postfix
+
+ """
+ _comment = "#"
+ configName = "postfix"
+ configVersion = "0.1"
+ sepFields = "\n"
+ reComment = re.compile("[ \t]*%s"%(_comment))
+ reSepFields = re.compile(sepFields)
+ # разделитель названия и значения переменной
+ reSeparator = re.compile("\s*=\s*")
+ def __init__(self,text):
+ self.text = text
+ # Объект документ
+ self.docObj = self.textToXML()
+ # Создаем поля разделенные массивы
+ self.docObj.postParserListSeplist(self.docObj.body)
+ # XML документ
+ self.doc = self.docObj.doc
+
+ def join(self, postfixObj):
+ """Объединяем конфигурации"""
+ if isinstance(postfixObj, postfix):
+ self.docObj.joinDoc(postfixObj.doc)
+
+ def textToXML(self):
+ """Преобразуем текст в XML"""
+ class area:
+ def __init__(self):
+ self.header = False
+ self.start = False
+ self.fields = []
+ self.end = False
+ areas = []
+ oneArea = area()
+ oneArea.header = ""
+ oneArea.start = ""
+ oneArea.fields = [self.text]
+ oneArea.end = ""
+ areas.append(oneArea)
+ docObj = xmlDoc()
+ # Создание объекта документ c пустым разделителем между полями
+ docObj.createDoc(self.configName, self.configVersion)
+ if not areas:
+ return docObj
+ self.createXML(areas, docObj.getNodeBody(), docObj)
+ return docObj
+
+
+ def setDataField(self, txtLines, endtxtLines):
+ """Cоздаем список объектов с переменными"""
+ class fieldData:
+ def __init__(self):
+ self.name = False
+ self.value = False
+ self.comment = False
+ self.br = False
+ fields = []
+ field = fieldData()
+ z = 0
+ for k in txtLines:
+ textLine = k + endtxtLines[z]
+ #print "#"+brBloc[z]+"#"
+ z += 1
+ findComment = self.reComment.search(textLine)
+ if not textLine.strip():
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ elif findComment:
+ field.comment = textLine
+ fields.append(field)
+ field = fieldData()
+ else:
+ pars = textLine.strip()
+ nameValue = self.reSeparator.split(pars)
+ if len (nameValue) == 1:
+ field.name = ""
+ field.value = textLine.replace(self.sepFields,"")
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+
+ if len(nameValue) > 2:
+ valueList = nameValue[1:]
+ nameValue =[nameValue[0],"=".join(valueList).replace(\
+ self.sepFields,"")]
+ if len(nameValue) == 2:
+ name = nameValue[0]
+ value = nameValue[1].replace(self.sepFields,"")
+ field.name = name.replace(" ","").replace("\t","")
+ field.value = value
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ return fields
+
+class ldap(samba):
+ """Класс для обработки конфигурационного файла типа ldap
+
+ """
+ _comment = "#"
+ configName = "ldap"
+ configVersion = "0.1"
+ # Регулярное выражение для заголовка области
+ reHeader = re.compile("^[\t ]*(access|syncrepl)[^\n]+\n?")
+ # Регулярное выражения для области
+ reArea = re.compile("([\t ]*(access|syncrepl)[^\n]+\
+\n([\t ]+[^\n]+\n?)+)",re.M|re.S)
+ reComment = re.compile("\s*%s.*"%(_comment))
+ # разделитель между переменной и значением переменной
+ reSeparator = re.compile("\s+|\s*=\s*")
+ # разделитель полей
+ sepFields = "\n"
+ # регулярное выражение для разделителя полей
+ reSepFields = re.compile(sepFields)
+
+ def __init__(self,text):
+ self.text = text
+ self.blocTextObj = blocText()
+ self._splitToFields = self.splitToFields
+ # Объект документ
+ self.docObj = self._textToXML()
+ # Создаем поля-массивы
+ self.docObj.postParserList()
+ # Создаем поля разделенные массивы
+ self.docObj.postParserListSeplist(self.docObj.body)
+ # XML документ
+ self.doc = self.docObj.doc
+
+ def join(self, ldapObj):
+ """Объединяем конфигурации"""
+ if isinstance(ldapObj, ldap):
+ self.docObj.joinDoc(ldapObj.doc)
+
+ def setDataField(self, txtLines, endtxtLines):
+ """Создаем список объектов с переменными"""
+ class fieldData:
+ def __init__(self):
+ self.name = False
+ self.value = False
+ self.comment = False
+ self.br = False
+ fields = []
+ field = fieldData()
+ z = 0
+ for k in txtLines:
+ textLine = k + endtxtLines[z]
+ z += 1
+ findComment = self.reComment.search(textLine)
+ if not textLine.strip():
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ elif findComment:
+ field.comment = textLine
+ fields.append(field)
+ field = fieldData()
+ else:
+ pars = textLine.strip()
+ nameValue = self.reSeparator.split(pars)
+ if len(nameValue) > 2:
+ valueList = nameValue[2:]
+ nameValue =[nameValue[0]+nameValue[1]," ".join(valueList)]
+ if len(nameValue) == 2:
+ name = nameValue[0]
+ value = nameValue[1].replace(self.sepFields,"")
+ field.name = name.replace(" ","").replace("\t","")
+ field.value = value
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ return fields
+
+ def _textToXML(self):
+ """Преобразует текст в XML"""
+ blTmp = self.blocTextObj.findArea(self.text,self.reHeader,self.reArea)
+ blocs = self.getFullAreas(blTmp)
+ headers = []
+ startHeaders = []
+ finHeaders = []
+ docObj = xmlDoc()
+ docObj.createDoc(self.configName, self.configVersion)
+ rootNode = docObj.getNodeBody()
+ # Если пустой текст то создаем пустой документ
+ if not blocs:
+ return docObj
+
+ for h in blocs[0]:
+ headers.append(h.rstrip())
+ bodys = blocs[1]
+
+ z = 0
+ for h in headers:
+ if not bodys[z]:
+ z += 1
+ continue
+ areaAction = False
+ if h:
+ if h[0] == "!":
+ header = self.removeSymbolTerm(h.strip())
+ headerQuote = self.removeSymbolTerm(h)
+ docObj.createCaption(header,[headerQuote,""])
+ areaAction = "drop"
+ elif h[0] == "-":
+ header = self.removeSymbolTerm(h.strip())
+ headerQuote = self.removeSymbolTerm(h)
+ docObj.createCaption(header,[headerQuote,""])
+ areaAction = "replace"
+ else:
+ docObj.createCaption(h.strip(), [h.rstrip(),""])
+ else:
+ docObj.createCaption(h.strip(), [h.rstrip(),""])
+
+ if "\n" in blocs[0][z]:
+ resHead = self.reComment.search(h)
+ if resHead:
+ docObj.createField('comment',
+ blocs[0][z][resHead.start():])
+ else:
+ docObj.createField('br')
+
+ fields = self._splitToFields(bodys[z])
+ for f in fields:
+ if f.name != False and f.value!=False and f.br!=False:
+ # Обработка условий для samba
+ if f.name[0] == "!" or f.name[0] == "-" or\
+ f.name[0] == "+":
+ qns = self.removeSymbolTerm(f.br)
+ xmlField = docObj.createField("var",
+ [qns],
+ f.name[1:], [f.value])
+ if f.name[0] == "!":
+ # Удаляемое в дальнейшем поле
+ docObj.setActionField(xmlField, "drop")
+ elif f.name[0] == "+":
+ # Добавляем уникальное поле
+ xmlField.setAttribute("type", "seplist")
+ docObj.setActionField(xmlField, "join")
+ else:
+ docObj.createField("var",[f.br.replace("\n","")],
+ f.name, [f.value])
+ docObj.createField('br')
+ elif f.comment != False:
+ docObj.createField('comment', [f.comment])
+ elif f.br != False:
+ docObj.createField('br', [f.br.replace("\n","")])
+ if h.strip():
+ area = docObj.createArea()
+ if areaAction:
+ docObj.setActionArea(area, areaAction)
+ rootNode.appendChild(area)
+ else:
+ fieldsNodes = docObj.tmpFields.getFields()
+ for fieldNode in fieldsNodes:
+ rootNode.appendChild(fieldNode)
+ docObj.clearTmpFields()
+ z += 1
+ #print docObj.doc.toprettyxml()
+ return docObj
+
+class dovecot(bind):
+ """Класс для обработки конфигурационного файла типа dovecot
+
+ """
+ _comment = "#"
+ configName = "dovecot"
+ configVersion = "0.1"
+ __openArea = "{"
+ __closeArea = "[ \t]*\}[ \t]*"
+ sepFields = "\n"
+ reOpen = re.compile(__openArea)
+ reClose = re.compile(__closeArea)
+ reCloseArea = re.compile(__closeArea + "\s*\Z")
+ reComment = re.compile("[ \t]*%s" %(_comment))
+ reSepFields = re.compile(sepFields)
+ # разделитель названия и значения переменной
+ reSeparator = re.compile("\s*=\s*")
+
+ def __init__(self, text):
+ bind.__init__(self,text)
+
+ def postXML(self, xmlArea=False):
+ """Последующая постобработка XML"""
+ # Добавляем перевод строки если его нет в конец области
+ if not xmlArea:
+ xmlArea = self.docObj.body
+ xmlFields = xpath.Evaluate("child::field", xmlArea)
+ if xmlFields and not (\
+ self.docObj.getTypeField(xmlFields[-1]) == "br" or\
+ self.docObj.getTypeField(xmlFields[-1]) == "comment"):
+ xmlArea.appendChild(self.docObj.createField("br",
+ [],"",[],
+ False,False))
+ xmlAreas = xpath.Evaluate("child::area", xmlArea)
+ for area in xmlAreas:
+ self.postXML(area)
+
+ def join(self, dovecotObj):
+ """Объединяем конфигурации"""
+ if isinstance(dovecotObj, dovecot):
+ #print self.docObj.doc.toprettyxml()
+ self.docObj.joinDoc(dovecotObj.doc)
+ # Для добавления перевода строки перед закрывающим тегом
+ # конфигурационного файла
+ self.postXML()
+
+
+class procmail(objShare):
+ """Класс для обработки конфигурационного файла типа procmail
+
+ """
+ _comment = "#"
+ configName = "procmail"
+ configVersion = "0.1"
+ sepFields = "\n"
+ reComment = re.compile("[ \t]*%s" %(_comment))
+ reSepFields = re.compile(sepFields)
+ # разделитель названия и значения переменной
+ reSeparator = re.compile("=")
+ def __init__(self, text):
+ self.text = text
+ self.docObj = self.textToXML()
+ self.doc = self.docObj.doc
+
+ def setDataField(self, txtLines, endtxtLines):
+ """Создаем список объектов с переменными"""
+ class fieldData:
+ def __init__(self):
+ self.name = False
+ self.value = False
+ self.comment = False
+ self.br = False
+ fields = []
+ field = fieldData()
+ z = 0
+ for k in txtLines:
+ textLine = k + endtxtLines[z]
+ z += 1
+ findComment = self.reComment.search(textLine)
+ if not textLine.strip():
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ elif findComment:
+ field.comment = textLine
+ fields.append(field)
+ field = fieldData()
+ else:
+ pars = textLine.strip()
+ nameValue = self.reSeparator.split(pars)
+ if len(nameValue) == 2:
+ name = nameValue[0]
+ value = nameValue[1].replace(self.sepFields,"")
+ field.name = name.replace(" ","").replace("\t","")
+ field.value = value
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ return fields
+
+ def textToXML(self):
+ docObj = xmlDoc()
+ docObj.createDoc(self.configName, self.configVersion)
+ if self.text:
+ nodeBody = docObj.getNodeBody()
+ fields = self.splitToFields(self.text)
+ for field in fields:
+ if field.name != False:
+ fieldXML = self.createFieldTerm(field.name,
+ field.value,
+ field.br, docObj)
+ nodeBody.appendChild(fieldXML)
+ if field.br[-1] == "\n":
+ fieldXMLBr = docObj.createField("br",[],
+ "",[],
+ False, False)
+ nodeBody.appendChild(fieldXMLBr)
+ elif field.comment != False:
+ fieldXML = docObj.createField("comment",
+ [field.comment],
+ "", [],
+ False, False)
+ nodeBody.appendChild(fieldXML)
+ elif field.br != False:
+ brText = field.br.replace("\n","")
+ if brText:
+ fieldXML = docObj.createField('br',
+ [brText],
+ "", [],
+ False, False)
+ else:
+ fieldXML = docObj.createField('br',
+ [],
+ "", [],
+ False, False)
+ nodeBody.appendChild(fieldXML)
+ return docObj
+
+ def join(self, procmailObj):
+ """Объединяем конфигурации"""
+ if isinstance(procmailObj, procmail):
+ #print self.docObj.doc.toprettyxml()
+ self.docObj.joinDoc(procmailObj.doc)
+
+class kde(samba):
+ """Класс для обработки конфигурационного файла типа kde
+
+ """
+ _comment = "#"
+ configName = "kde"
+ configVersion = "0.1"
+ reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n?",re.M)
+ reBody = re.compile(".+",re.M|re.S)
+ reComment = re.compile("^\s*%s.*"%(_comment))
+ reSeparator = re.compile("=")
+ sepFields = "\n"
+ reSepFields = re.compile(sepFields)
+
+ def __init__(self,text):
+ samba.__init__(self,text)
+
+
+ def _textToXML(self):
+ """Преобразует текст в XML"""
+ blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody)
+ blocs = self.getFullAreas(blTmp)
+ headers = []
+ startHeaders = []
+ finHeaders = []
+ docObj = xmlDoc()
+ docObj.createDoc(self.configName, self.configVersion)
+ rootNode = docObj.getNodeBody()
+ # Если пустой текст то создаем пустой документ
+ if not blocs:
+ return docObj
+
+ for h in blocs[0]:
+ reH = re.compile("]\s*$")
+ #listfinH = h.split("]")
+ listfinH = reH.split(h)
+ finH = listfinH[0]
+ if "[" in finH:
+ startHeaders.append(finH + "]")
+ else:
+ startHeaders.append(finH)
+ if len(listfinH) == 2:
+ finHeaders.append(listfinH[1])
+ else:
+ finHeaders.append("")
+ head=finH.replace("][",".").replace("[","").replace("]","").strip()
+ headers.append(head)
+ bodys = blocs[1]
+
+ z = 0
+ for h in headers:
+ if not bodys[z]:
+ z += 1
+ continue
+ areaAction = False
+ if h:
+ if h[0] == "!":
+ docObj.createCaption(h[1:], [startHeaders[z],""])
+ areaAction = "drop"
+ elif h[0] == "-":
+ docObj.createCaption(h[1:], [startHeaders[z],""])
+ areaAction = "replace"
+ else:
+ docObj.createCaption(h, [startHeaders[z],""])
+ else:
+ docObj.createCaption(h, [startHeaders[z],""])
+
+ if "\n" in blocs[0][z]:
+ if self.reComment.search(finHeaders[z]):
+ docObj.createField('comment', [finHeaders[z]])
+ elif not finHeaders[z].strip() and\
+ finHeaders[z].replace("\n",""):
+ docObj.createField('br',
+ [finHeaders[z].replace("\n","")])
+ else:
+ docObj.createField('br')
+ fields = self._splitToFields(bodys[z])
+ for f in fields:
+ if f.name != False and f.value!=False and f.br!=False:
+ # Обработка условий для samba
+ if f.name[0] == "!" or f.name[0] == "-" or\
+ f.name[0] == "+":
+ qns = self.removeSymbolTerm(f.br)
+ xmlField = docObj.createField("var",
+ [qns],
+ f.name[1:], [f.value])
+ if f.name[0] == "!":
+ # Удаляемое в дальнейшем поле
+ docObj.setActionField(xmlField, "drop")
+ else:
+ docObj.createField("var",[f.br.replace("\n","")],
+ f.name, [f.value])
+ docObj.createField('br')
+ elif f.comment != False:
+ docObj.createField('comment', [f.comment])
+ elif f.br != False:
+ docObj.createField('br', [f.br.replace("\n","")])
+ if h.strip():
+ area = docObj.createArea()
+ if areaAction:
+ docObj.setActionArea(area, areaAction)
+ rootNode.appendChild(area)
+ else:
+ fieldsNodes = docObj.tmpFields.getFields()
+ for fieldNode in fieldsNodes:
+ rootNode.appendChild(fieldNode)
+ docObj.clearTmpFields()
+ z += 1
+ #print docObj.doc.toprettyxml()
+ return docObj
+
+ def join(self, kdeObj):
+ """Объединяем конфигурации"""
+ if isinstance(kdeObj, kde):
+ self.docObj.joinDoc(kdeObj.doc)
+ self.postXML()
+
+
+class xmlDocPlasma:
+ """Класс для замены метода joinArea в xmlDoc для plasma"""
+ # заменяемый метод для xmlDoc
+ def joinArea(self, baseNode, xmlNewArea):
+ """Объединяет область c областью Body (xmlNewArea c baseNode)"""
+ def appendArea(baseNode, xmlNewArea):
+ fieldsRemove = xpath.Evaluate(\
+ "descendant::field[child::action='drop']", xmlNewArea)
+ for rmNode in fieldsRemove:
+ parentNode = rmNode.parentNode
+ parentNode.removeChild(rmNode)
+ captionAreasRemove = xpath.Evaluate(\
+ "descendant::area/child::caption[child::action='drop']",
+ xmlNewArea)
+ for rmNodeCapt in captionAreasRemove:
+ rmNode = rmNodeCapt.parentNode
+ parentNode = rmNode.parentNode
+ parentNode.removeChild(rmNode)
+ self.setActionArea(xmlNewArea, "append")
+ # Добавляем разделитель областей во вложенные области
+ areaNodes = xpath.Evaluate('descendant::area',xmlNewArea)
+ for areaNode in areaNodes:
+ self.setActionArea(areaNode,"append")
+ parentNode = areaNode.parentNode
+ parentNode.insertBefore(self.sepAreas.cloneNode(True),
+ areaNode)
+ baseNode.appendChild(xmlNewArea)
+ # Добавляем разделитель областей
+ baseNode.insertBefore(self.sepAreas.cloneNode(True), xmlNewArea)
+
+ nodesNames = xpath.Evaluate('child::area/caption/name',baseNode)
+ nodesNewArea = xpath.Evaluate('child::caption/name',xmlNewArea)
+ if not nodesNames:
+ # Добавляем область
+ if nodesNewArea:
+ newAreaAction = self.getActionArea(xmlNewArea)
+ if not (newAreaAction == "drop"):
+ appendArea(baseNode, xmlNewArea)
+ return True
+ if not nodesNames or not nodesNewArea:
+ return False
+ nameArea = ""
+ if nodesNewArea[0].firstChild:
+ nameArea = nodesNewArea[0].firstChild.nodeValue.strip()
+ flagFindArea = False
+ baseNodes = []
+ for oName in nodesNames:
+ newAreaAction = self.getActionArea(xmlNewArea)
+ oArea = oName.parentNode.parentNode
+ oNameTxt = ""
+ if oName.firstChild:
+ oNameTxt = oName.firstChild.nodeValue
+ if nameArea == oNameTxt:
+ flagFindArea = True
+ # При использовании удаления
+ if newAreaAction == "drop":
+ prevNode = oName.parentNode.parentNode.previousSibling
+ removePrevNodes = []
+ while (prevNode) and self.getTypeField(prevNode) == "br":
+ removePrevNodes.append(prevNode)
+ prevNode = prevNode.previousSibling
+ for removeNode in removePrevNodes:
+ baseNode.removeChild(removeNode)
+ baseNode.removeChild(oName.parentNode.parentNode)
+ continue
+ elif newAreaAction == "replace":
+ oldAreaNode = oName.parentNode.parentNode
+ newAreaCaption = xpath.Evaluate('child::caption',
+ xmlNewArea)[0]
+ oldAreaCaption = xpath.Evaluate('child::caption',
+ oldAreaNode)[0]
+ if newAreaCaption and oldAreaCaption:
+ xmlNewArea.replaceChild(oldAreaCaption,newAreaCaption)
+ self.setActionArea(xmlNewArea,"replace")
+ baseNode.replaceChild(xmlNewArea,
+ oldAreaNode)
+ continue
+ baseNodes.append(oName.parentNode.parentNode)
+
+ # Заменяем QUOTE
+ oldAreaNode = oName.parentNode.parentNode
+ oldAreaQuote = xpath.Evaluate('child::caption/quote',
+ oldAreaNode)[0]
+ if oldAreaQuote and\
+ not oldAreaQuote.firstChild:
+ newAreaQuote = xpath.Evaluate('child::caption/quote',
+ xmlNewArea)[0]
+ oldAreaCaption = xpath.Evaluate('child::caption',
+ oldAreaNode)[0]
+ if newAreaQuote and oldAreaCaption:
+ oldAreaCaption.replaceChild(newAreaQuote, oldAreaQuote)
+
+ newFields = xpath.Evaluate('child::field',xmlNewArea)
+
+ joinNewFields = xpath.Evaluate(\
+ "child::field[child::action='join']"
+ ,xmlNewArea)
+ self.addNewFielsOldArea(newFields, joinNewFields, oArea)
+
+
+ if not flagFindArea:
+ # Добавляем область
+ if not (newAreaAction == "drop"):
+ appendArea(baseNode, xmlNewArea)
+ else:
+ tmpXmlNewAreas = xpath.Evaluate('child::area',xmlNewArea)
+ for na in tmpXmlNewAreas:
+ for bn in baseNodes:
+ self.joinArea(bn, na)
+ return True
+
+class plasma(samba):
+ """Класс для обработки конфигурационного файла типа kde
+
+ """
+ _comment = "#"
+ configName = "plasma"
+ configVersion = "0.1"
+ reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n?",re.M)
+ reBody = re.compile(".+",re.M|re.S)
+ reComment = re.compile("^\s*%s.*"%(_comment))
+ reSeparator = re.compile("=")
+ sepFields = "\n"
+ reSepFields = re.compile(sepFields)
+
+ def __init__(self,text):
+ samba.__init__(self,text)
+
+ # Делим текст на области включая вложенные (areas массив областей)
+ def splitToAllArea(self, text, areas):
+ """Делит текст на области включая вложенные
+
+ возвращает список объектов областей (переменная areas)
+ """
+ class area:
+ def __init__(self):
+ self.header = False
+ self.start = False
+ self.fields = []
+ self.end = False
+
+
+ def findPathArea(listPath, areaF):
+ """Ищет путь в области
+
+ areaF - объект area
+ listPath - cписок названий областей
+ """
+ ret = False
+ if not listPath:
+ return ret
+ flagList = False
+ if type(areaF) == types.ListType:
+ fields = areaF
+ flagList = True
+ else:
+ fields = areaF.fields
+ if areaF.header == listPath[0]:
+ ret = areaF
+ else:
+ return ret
+ for i in fields:
+ if str(i.__class__.__name__) == "area":
+ add = False
+ if not flagList:
+ add = listPath.pop(0)
+ if not listPath:
+ break
+ ret = False
+ if i.header == listPath[0]:
+ ret = findPathArea(listPath, i)
+ break
+ else:
+ if add:
+ listPath.insert(0,add)
+ if ret == areaF and len(listPath)>1:
+ ret = False
+ return ret
+
+
+ blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody)
+ blocs = self.getFullAreas(blTmp)
+ reH = re.compile("\[([^\[\]]+)\]")
+ # Список имен блоков
+ namesBlockList = []
+ # Временные поля
+ fieldsTmp = []
+ # Добавляем заголовки
+ z = 0
+ for h in blocs[0]:
+ if not h:
+ if blocs[1][z] == "":
+ fieldsTmp.append("")
+ #fieldsTmp.append("\n")
+ else:
+ fieldsTmp.append(blocs[1][z])
+ #print '"' + blocs[1][z] + '"'
+ z += 1
+ continue
+ #print '"' + blocs[1][z] + '"'
+ z += 1
+ slpNamesBlock = reH.split(h)
+ # Отступ слева для заголовка
+ indentionLeft = slpNamesBlock[0]
+ namesBlock = filter(lambda x: x.strip(), slpNamesBlock)
+ #namesBlock = map(lambda x: self.removeSymbolTerm(x), namesBlock)
+ findArea = findPathArea(copy.copy(namesBlock), areas)
+ namesBlockList.append(namesBlock)
+ if findArea:
+ if len(namesBlock) > 1:
+ namesBlockView = map(lambda x: self.removeSymbolTerm(x),
+ namesBlock)
+ else:
+ namesBlockView = namesBlock
+ findArea.start = indentionLeft + "[" + \
+ "][".join(namesBlockView) + "]"
+ else:
+ i = 0
+ lenNamesBlock = len(namesBlock)
+ namesBlockTmp = []
+ for nameB in namesBlock:
+ namesBlockTmp.append(nameB)
+ findArea = findPathArea(copy.copy(namesBlockTmp), areas)
+ i += 1
+ if not findArea:
+ areaNew = area()
+ areaNew.header = nameB
+ if lenNamesBlock == i:
+ if len(namesBlock) > 1:
+ namesBlockView = map(\
+ lambda x: self.removeSymbolTerm(x),
+ namesBlock)
+ else:
+ namesBlockView = namesBlock
+ areaNew.start = indentionLeft + "[" + \
+ "][".join(namesBlockView) + "]"
+ else:
+ areaNew.start = ""
+ areaNew.end = ""
+ if i == 1:
+ if lenNamesBlock == i:
+ areas += fieldsTmp
+ areas.append(areaNew)
+ findAreaPrev = areas[-1]
+ else:
+ if lenNamesBlock == i:
+ findAreaPrev.fields += fieldsTmp
+ findAreaPrev.fields.append(areaNew)
+ findAreaPrev = findAreaPrev.fields[-1]
+ else:
+ findAreaPrev = findArea
+ fieldsTmp = []
+ i = 0
+ delt = 0
+ # Добавляем тела
+ for body in blocs[1]:
+ #print "#" + body + "#"
+ #print
+ if not blocs[0][i]:
+ i += 1
+ delt +=1
+ continue
+ ## В случае последнего комментария не добавляем перевод строки
+ #if self.reComment.search(body.splitlines()[-1]):
+ body = "\n" + body
+
+ namesBlock = namesBlockList[i-delt]
+ findArea = findPathArea(copy.copy(namesBlock), areas)
+ if findArea:
+ #if findArea.fields:
+ #if type(findArea.fields[0]) == types.StringType:
+ #findArea.fields.pop(0)
+ findArea.fields.insert(0, body)
+ i += 1
+
+ #eee = 1
+ #def prAreas(ar, eee):
+ #for a in ar:
+ #if type(a) == types.StringType:
+ #print 'field', a
+ #else:
+ #print "--------------------"
+ #print "HEADER =", a.header
+ #print "START =", a.start
+ #print "FIELDS =", a.fields
+ #print "LEVEL", eee
+ #if type(a) != types.StringType:
+ #if a.fields:
+ #eee += 1
+ #prAreas(a.fields, eee)
+
+ #prAreas(areas, eee)
+ return areas
+
+ def createCaptionTerm(self, header, start, end, docObj):
+ """Создание пустой области с заголовком
+
+ при создании области проверяется первый символ заголовка
+ и добавляется тег action
+ "!" - drop
+ "-" - replace
+ """
+ areaAction = False
+ if header:
+ if header[0] == "!":
+ docObj.createCaption(header[1:], [start,
+ end.replace("\n","")])
+ areaAction = "drop"
+ elif header[0] == "-":
+ docObj.createCaption(header[1:], [start,
+ end.replace("\n","")])
+ areaAction = "replace"
+ else:
+ docObj.createCaption(header, [start,
+ end.replace("\n","")])
+ else:
+ docObj.createCaption(header, [start,
+ end.replace("\n","")])
+
+ areaXML = docObj.createArea()
+ if areaAction:
+ docObj.setActionArea(areaXML, areaAction)
+ return areaXML
+
+ def createXML(self, areas, rootNode, docObj):
+ """Создаем из массивов областей XML"""
+ for i in areas:
+ if str(i.__class__.__name__) == "area":
+ if i.header:
+ areaXML = self.createCaptionTerm(i.header, i.start,
+ i.end.replace("\n",""),
+ docObj)
+ for f in i.fields:
+ if str(f.__class__.__name__) == "area":
+ if f.header:
+ areaXMLChild = self.createCaptionTerm(f.header,
+ f.start,
+ f.end.replace("\n",""),
+ docObj)
+
+ self.createXML(f.fields, areaXMLChild, docObj)
+
+ areaXML.appendChild(areaXMLChild)
+ else:
+ self.createXML(f.fields, areaXML, docObj)
+ if "\n" in f.end:
+ fieldXMLBr = docObj.createField("br",[],
+ "",[],
+ False, False)
+ areaXML.appendChild(fieldXMLBr)
+ else:
+ if not f:
+ continue
+ fields = self.splitToFields(f)
+ for field in fields:
+ if field.name != False:
+ fieldXML = self.createFieldTerm(field.name,
+ field.value,
+ field.br, docObj)
+ areaXML.appendChild(fieldXML)
+ if field.br[-1] == "\n":
+ fieldXMLBr = docObj.createField("br",[],
+ "",[],
+ False, False)
+ areaXML.appendChild(fieldXMLBr)
+ elif field.comment != False:
+ fieldXML = docObj.createField("comment",
+ [field.comment],
+ "", [],
+ False, False)
+ areaXML.appendChild(fieldXML)
+ elif field.br != False:
+ brText = field.br.replace("\n","")
+ if brText:
+ fieldXML = docObj.createField('br',
+ [brText],
+ "", [],
+ False, False)
+ else:
+ fieldXML = docObj.createField('br',
+ [],
+ "", [],
+ False, False)
+ if areaXML:
+ areaXML.appendChild(fieldXML)
+
+ if i.header:
+ rootNode.appendChild(areaXML)
+ if "\n" in i.end:
+ fieldXMLBr = docObj.createField("br",[],
+ "",[],
+ False, False)
+ rootNode.appendChild(fieldXMLBr)
+
+ else:
+ if not i:
+ continue
+ fields = self.splitToFields(i)
+ for field in fields:
+ if field.name != False:
+ fieldXML = self.createFieldTerm(field.name,
+ field.value,
+ field.br, docObj)
+ rootNode.appendChild(fieldXML)
+ if field.br[-1] == "\n":
+ fieldXMLBr = docObj.createField("br",[],"", [],
+ False, False)
+ rootNode.appendChild(fieldXMLBr)
+ elif field.comment != False:
+ fieldXML = docObj.createField("comment",
+ [field.comment],
+ "", [],
+ False, False)
+ rootNode.appendChild(fieldXML)
+ elif field.br != False:
+ brText = field.br.replace("\n","")
+ if brText:
+ fieldXML = docObj.createField('br', [brText],"",[],
+ False, False)
+ else:
+ fieldXML = docObj.createField('br', [], "", [],
+ False, False)
+ rootNode.appendChild(fieldXML)
+ #rootNode.appendChild(areaXML)
+
+
+ def createTxtConfig(self, strHeader, dictVar):
+ """Cоздает область с заголовком
+
+ создает текст конфигурационного файла в формате samba из
+ заголовка (строка) и словаря переменных
+ """
+ if not strHeader:
+ return ""
+ if type(strHeader) in (tuple, list):
+ outTxt = "".join(map(lambda x: "["+x+"]",strHeader))
+ if not outTxt:
+ return ""
+ outTxt += "\n"
+ else:
+ outTxt = "[" + strHeader + "]\n"
+ for key in dictVar.keys():
+ outTxt += "%s=%s\n" %(key,dictVar[key])
+ return outTxt
+
+ def _textToXML(self):
+ """Преобразуем текст в XML"""
+ areas = []
+ if self.text.strip():
+ self.splitToAllArea(self.text, areas)
+ #docObj = xmlDoc()
+ # Создаем новый класс xmlDoc с измененным методом joinArea
+ newClass = type("newXmlDocPlalma",(xmlDocPlasma,xmlDoc,object),{})
+ # Создаем экземпляр нового класса
+ docObj = newClass()
+ # Создание объекта документ c пустым разделителем между полями
+ docObj.createDoc(self.configName, self.configVersion)
+ if not areas:
+ return docObj
+ self.createXML(areas, docObj.getNodeBody(), docObj)
+ return docObj
+
+
+ def postXML(self):
+ """Последующая постобработка XML"""
+ # Для добавления перевода строки между областями если его нет
+ #print self.docObj.body.toprettyxml()
+ def getQuotesArea(xmlArea):
+ quotes = []
+ xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea)
+ for node in xmlQuotes:
+ if node.firstChild:
+ quotes.append(node.firstChild.nodeValue)
+ if len(quotes) == 0:
+ quotes.append("")
+ quotes.append("")
+ elif len(quotes) == 1:
+ quotes.append("")
+ return quotes
+
+ xmlAreas = xpath.Evaluate("descendant::area", self.docObj.body)
+ #print "-------------------------------------------------------"
+ #print xmlAreas
+ #if xmlAreas:
+ #prXmlArea = xmlAreas[0]
+ for xmlArea in xmlAreas:
+ # Перед пустой областью и после нее удаляем переводы строк
+ if getQuotesArea(xmlArea) == ["",""]:
+ #areaTXT = xpath.Evaluate("child::caption/name", xmlArea)[0]
+ #print "CL_AREA", areaTXT.firstChild
+ if xmlArea.previousSibling and\
+ self.docObj.getTypeField(xmlArea.previousSibling) == "br":
+ parentNode = xmlArea.previousSibling.parentNode
+ if xmlArea.previousSibling.previousSibling and\
+ self.docObj.getTypeField(xmlArea.previousSibling.previousSibling) == "br":
+ parentNode.removeChild(\
+ xmlArea.previousSibling.previousSibling)
+ parentNode.removeChild(xmlArea.previousSibling)
+ if xmlArea.nextSibling and\
+ self.docObj.getTypeField(xmlArea.nextSibling) == "br":
+ parentNode = xmlArea.nextSibling.parentNode
+ if xmlArea.nextSibling.nextSibling and\
+ self.docObj.getTypeField(xmlArea.nextSibling.nextSibling) == "br":
+ parentNode.removeChild(xmlArea.nextSibling.nextSibling)
+ parentNode.removeChild(xmlArea.nextSibling)
+ continue
+
+ # Собираем поля в кучку
+ xmlChildAreas = xpath.Evaluate("child::area", xmlArea)
+ if xmlChildAreas:
+ childNodes = self.docObj.getFieldsArea(xmlArea)
+ firstChildArea = xmlChildAreas[0]
+ if firstChildArea.previousSibling and\
+ self.docObj.getTypeField(firstChildArea.previousSibling)=="br":
+ if firstChildArea.previousSibling.previousSibling:
+ if self.docObj.getTypeField(\
+ firstChildArea.previousSibling.previousSibling)=="br":
+ firstChildArea = firstChildArea.previousSibling
+ flagFoundArea = False
+ it = 0
+ lenChild = len(childNodes)
+ for node in childNodes:
+ it += 1
+ if node.tagName == "area":
+ flagFoundArea = True
+ continue
+ if flagFoundArea and node.tagName == "field":
+ if self.docObj.getTypeField(node) == "var":
+ xmlArea.insertBefore(node, firstChildArea)
+ if it < lenChild:
+ if self.docObj.getTypeField(childNodes[it])==\
+ "br":
+ xmlArea.insertBefore(childNodes[it],
+ firstChildArea)
+ # Добавление перевода строк в если его нет между полями
+ if self.docObj.getTypeField(node) == "var" and\
+ node.previousSibling and\
+ not (self.docObj.getTypeField(node.previousSibling) in\
+ ("br","comment")):
+ xmlArea.insertBefore(self.docObj.createField("br",
+ [],"",[],
+ False,False),
+ node)
+
+ # Добавляем BR если его нет первым полем
+ xmlFields = xpath.Evaluate("child::field", xmlArea)
+ if not (xmlFields and\
+ (self.docObj.getTypeField(xmlFields[0]) == "br" or\
+ self.docObj.getTypeField(xmlFields[0]) == "comment")):
+ if xmlFields:
+ xmlArea.insertBefore(self.docObj.createField("br",
+ [],"",[],
+ False,False),
+ xmlFields[0])
+ # Если последним полем BR, удаляем его
+ if xmlFields and self.docObj.getTypeField(xmlFields[-1]) == "br":
+ #print "DEL_BR", xmlFields[-1].nextSibling
+ #and\
+ if not xmlFields[-1].nextSibling:
+ xmlArea.removeChild(xmlFields[-1])
+
+ # Если предыдущим полем не (BR или комментарий) - добавляем BR
+ if xmlArea.previousSibling and\
+ not (self.docObj.getTypeField(xmlArea.previousSibling) == "br" or\
+ self.docObj.getTypeField(xmlArea.previousSibling) == "comment"):
+ parentNode = xmlArea.parentNode
+ parentNode.insertBefore(self.docObj.createField("br",
+ [],"",[],
+ False,False),
+ xmlArea)
+ # Если есть предыдущее поле, и поле предыдущеее предыдущему
+ # не равно BR или комментарий то добавляем BR
+ if xmlArea.previousSibling:
+ prPrSibling = xmlArea.previousSibling.previousSibling
+ if prPrSibling and\
+ not (self.docObj.getTypeField(prPrSibling) == "br" or\
+ self.docObj.getTypeField(prPrSibling) == "comment"):
+ parentNode = xmlArea.parentNode
+ parentNode.insertBefore(self.docObj.createField("br",
+ [],"",[],
+ False,False),
+ xmlArea)
+ # Если после есть BR а за ним ничего нет, удаляем BR
+ if xmlArea.nextSibling and\
+ self.docObj.getTypeField(xmlArea.nextSibling) == "br":
+ if not xmlArea.nextSibling.nextSibling:
+ parentNode = xmlArea.nextSibling.parentNode
+ parentNode.removeChild(xmlArea.nextSibling)
+
+
+ def join(self, kdeObj):
+ """Объединяем конфигурации"""
+ if isinstance(kdeObj, plasma):
+ self.docObj.joinDoc(kdeObj.doc)
+ self.postXML()
+
+class xml_xfce(_error):
+ """Класс для объединения xfce-xml файлов"""
+ # root нода
+ rootNode = False
+ # body нода
+ bodyNode = False
+ # Документ
+ doc = False
+ # Текст профиля
+ text = ""
+ # Комментарий
+ _comment = ("")
+
+ def __init__(self, text):
+ self.text = text
+ # Создаем пустой объект
+ self.docObj = type("_empty_class", (object,), {})()
+ # Названия аттрибутов для пустого объекта
+ emptyMethods = ["getNodeBody","removeComment","insertBRtoBody",
+ "insertBeforeSepAreas"]
+ # Добавляем необходимые аттрибуты пустому объекту
+ for method in emptyMethods:
+ setattr(self.docObj, method, self.emptyMethod)
+ # Создаем XML документ
+ self.doc = self.textToXML()
+
+ def emptyMethod(self, *arg , **argv):
+ """Пустой метод"""
+ return True
+
+ def setNameBodyNode(self, name):
+ """Устанавливает название для корневой ноды документа"""
+ if not self.bodyNode:
+ return False
+ self.bodyNode.setAttribute("name", name)
+ return True
+
+ def textToXML(self):
+ """Создание из текста XML документа
+ Храним xml в своем формате
+ """
+ if not self.text.strip():
+ self.text = '''
+
+'''
+ try:
+ self.doc = xml.dom.minidom.parseString(self.text)
+ except:
+ self.setError(_("Can not text profile is XML"))
+ return False
+ self.rootNode = self.doc.documentElement
+ self.bodyNode = self.rootNode
+ return self.doc
+
+ def join(self, xml_xfceObj):
+ """Объединяем конфигурации"""
+ if isinstance(xml_xfceObj, xml_xfce):
+ try:
+ self.joinDoc(xml_xfceObj.doc)
+ except:
+ self.setError(_("Can not join profile"))
+ return False
+ return True
+
+ def _removeDropNodesAndAttrAction(self, xmlNode):
+ """Удаляет ноды с аттрибутом action='drop'
+
+ Также удаляет аттрибут action у всех нод
+ """
+ flagError = False
+ childNodes = xmlNode.childNodes
+ if xmlNode.nodeType ==xmlNode.ELEMENT_NODE:
+ if xmlNode.hasAttribute("action"):
+ nAction = xmlNode.getAttribute("action")
+ if not nAction in ("join","replace","drop"):
+ textError = _('''In the text, XML profile, look \
+for a reserved attribute 'action' with the incorrect value.\n\
+Valid values attribute 'action': \
+(action="join", action="replace", action="drop")''')
+ self.setError(textError)
+ return False
+ xmlNode.removeAttribute("action")
+ if nAction == "drop":
+ parentNode = xmlNode.parentNode
+ if parentNode:
+ parentNode.removeChild(xmlNode)
+ if childNodes:
+ for node in childNodes:
+ if not self._removeDropNodesAndAttrAction(node):
+ flagError = True
+ break
+ if flagError:
+ return False
+ return True
+
+ def postXML(self):
+ """Последующая постобработка XML"""
+ # Удаляем теги action и удаляемые ноды
+ self._removeDropNodesAndAttrAction(self.bodyNode)
+
+ def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True):
+ """Объединение корневой ноды профиля и корневой ноды файла"""
+ xmlNode = xmlNewNode
+ childNodes = xmlNode.childNodes
+ nextOldNode = xmlOldNode
+ flagError = False
+ if xmlNode.nodeType ==xmlNode.ELEMENT_NODE:
+ n = xmlNode
+ path = u''
+ nName = u''
+ nType = u''
+ nValue = u''
+ nAction = u''
+ attrName = ''
+ attrType = ''
+ path = n.tagName
+ if n.hasAttribute("name"):
+ nName = n.getAttribute("name")
+ attrName = u"attribute::name='%s'"%nName
+ if n.hasAttribute("type"):
+ nType = n.getAttribute("type")
+ attrType = u"attribute::type='%s'"%nType
+ if n.hasAttribute("value"):
+ nValue = n.getAttribute("value")
+ if n.hasAttribute("action"):
+ nAction = n.getAttribute("action")
+ if not nAction in ("join","replace","drop"):
+ textError = _('''In the text, XML profile, look \
+for a reserved attribute 'action' with the incorrect value.\n\
+Valid values attribute 'action': \
+(action="join", action="replace", action="drop")''')
+ self.setError(textError)
+ return False
+ if xmlOldNode.parentNode:
+ strAttr = [attrName, attrType]
+ findAttr = filter(lambda x: x, strAttr)
+ findAttrStr = ''
+ if findAttr:
+ strAttr = u' and '.join(findAttr)
+ findAttrStr = "[%s]"%strAttr
+ findPath = u"child::%s%s"%(path,findAttrStr)
+ # Рабочая нода
+ if flagRootNode:
+ workNode = xmlOldNode.parentNode
+ else:
+ workNode = xmlOldNode
+ oldNodes = xpath.Evaluate(findPath, workNode)
+ #print findPath
+ #print workNode
+ #print "----------------------------"
+ # Новая нода список
+ flagArray = False
+ if nType == "array":
+ flagArray = True
+ flagDrop = False
+ flagJoin = True
+ flagReplace = False
+ if nAction == "replace":
+ flagJoin = False
+ flagReplace = True
+ elif nAction == "drop":
+ flagJoin = False
+ flagDrop = True
+ if flagRootNode:
+ textError = _('Incorrect action="drop" in root node')
+ self.setError(textError)
+ return False
+ if oldNodes:
+ if len(oldNodes)>1:
+ textError = _("The uncertainty in this profile are \
+the same nodes at one level")
+ self.setError(textError)
+ return False
+ nextOldNode = oldNodes[0]
+ # Замещаем ноду в случае массива
+ if flagArray and not flagDrop:
+ replaceXmlNode = xmlNode.cloneNode(True)
+ if nAction:
+ replaceXmlNode.removeAttribute("action")
+ workNode.replaceChild(replaceXmlNode,
+ nextOldNode)
+ flagJoin = False
+ flagReplace = False
+ childNodes = False
+ # Объединение нод
+ if flagJoin:
+ if nextOldNode.hasAttribute("value"):
+ oValue = nextOldNode.getAttribute("value")
+ if nValue != oValue:
+ nextOldNode.setAttribute("value",nValue)
+ # Замещение ноды
+ elif flagReplace:
+ replaceXmlNode = xmlNode.cloneNode(True)
+ if not\
+ self._removeDropNodesAndAttrAction(replaceXmlNode):
+ return False
+ workNode.replaceChild(replaceXmlNode,
+ nextOldNode)
+ childNodes = False
+ # Удаление ноды
+ elif flagDrop:
+ workNode.removeChild(nextOldNode)
+ childNodes = False
+ else:
+ # Добавление ноды
+ childNodes = False
+ if not flagDrop:
+ appendXmlNode = xmlNode.cloneNode(True)
+ if not\
+ self._removeDropNodesAndAttrAction(appendXmlNode):
+ return False
+ workNode.appendChild(appendXmlNode)
+ if childNodes:
+ for node in childNodes:
+ if not self._join(node, nextOldNode, False):
+ flagError = True
+ break
+ if flagError:
+ return False
+ return True
+
+ def joinDoc(self, doc):
+ """Объединение документа профиля и документа файла"""
+ if not self.doc:
+ self.setError(_("Can not text file is XML"))
+ return False
+ if not doc:
+ self.setError(_("Can not text profile is XML"))
+ return False
+ # Импортируем корневую ноду нового документа в текущий документ
+ #newImportBodyNode = self.doc.importNode(doc.documentElement, True)
+ # Объединение корневой ноды профиля и корневой ноды файла
+ if not self._join(doc.documentElement, self.bodyNode):
+ return False
+ return True
+
+ def getConfig(self):
+ """Получение текстового файла из XML документа"""
+ data = self.doc.toprettyxml(encoding='UTF-8').split("\n")
+ data = filter(lambda x: x.strip(), data)
+ return "\n".join(data).replace("\t"," ").decode("UTF-8")
+
+class squid(procmail):
+ """Класс для обработки конфигурационного файла типа squid
+
+ """
+ configName = "squid"
+ configVersion = "0.1"
+ # разделитель названия и значения переменной
+ reSeparator = re.compile(" ")
+
+ def __init__(self, text):
+ procmail.__init__(self, text)
+ # Создаем поля-массивы
+ self.docObj.postParserList()
+ # Создаем поля разделенные массивы
+ self.docObj.postParserListSeplist(self.docObj.body)
+
+ def setDataField(self, txtLines, endtxtLines):
+ """Создаем список объектов с переменными"""
+ class fieldData:
+ def __init__(self):
+ self.name = False
+ self.value = False
+ self.comment = False
+ self.br = False
+ fields = []
+ field = fieldData()
+ z = 0
+ for k in txtLines:
+ textLine = k + endtxtLines[z]
+ z += 1
+ findComment = self.reComment.search(textLine)
+ flagVariable = True
+ if not textLine.strip():
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ flagVariable = False
+ elif findComment:
+ if textLine[:findComment.start()].strip():
+ field.comment = textLine[findComment.start():]
+ textLine = textLine[:findComment.start()]
+ else:
+ field.comment = textLine
+ flagVariable = False
+ fields.append(field)
+ field = fieldData()
+ if flagVariable:
+ pars = textLine.strip()
+ nameValue = self.reSeparator.split(pars)
+ if len(nameValue) > 2:
+ valueList = nameValue[1:]
+ nameValue =[nameValue[0]," ".join(valueList)]
+ if len(nameValue) == 2:
+ name = nameValue[0]
+ value = nameValue[1].replace(self.sepFields,"")
+ field.name = name.replace(" ","").replace("\t","")
+ field.value = value
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ return fields
+
+ def join(self, squidObj):
+ """Объединяем конфигурации"""
+ if isinstance(squidObj, squid):
+ #print squidObj.getConfig()
+ self.docObj.joinDoc(squidObj.doc)
+
+class xml_xfcepanel(xml_xfce):
+ """Класс для объединения xfce-panel файлов"""
+ def __init__(self, text):
+ xml_xfce.__init__(self, text)
+ self.panelNumbers = {}
+
+ def textToXML(self):
+ """Создание из текста XML документа
+ Храним xml в своем формате
+ """
+ if not self.text.strip():
+ self.text = '''
+
+
+'''
+ try:
+ self.doc = xml.dom.minidom.parseString(self.text)
+ except:
+ self.setError(_("Can not text profile is XML"))
+ return False
+ self.rootNode = self.doc.documentElement
+ self.bodyNode = self.rootNode
+ return self.doc
+
+ def setNameBodyNode(self, name):
+ """Пустой метод"""
+ return True
+
+ def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True, levelNumber=0):
+ """Объединение корневой ноды профиля и корневой ноды файла"""
+ xmlNode = xmlNewNode
+ childNodes = xmlNode.childNodes
+ nextOldNode = xmlOldNode
+ flagError = False
+ if xmlNode.nodeType ==xmlNode.ELEMENT_NODE:
+ n = xmlNode
+ path = u''
+ nName = u''
+ flagArray = False
+ nValue = u''
+ nAction = u''
+ attrName = ''
+ attrType = ''
+ path = n.tagName
+ if path == "items":
+ flagArray = True
+ if not flagArray:
+ if n.hasAttribute("name"):
+ nName = n.getAttribute("name")
+ attrName = u"attribute::name='%s'"%nName
+ if n.hasAttribute("value"):
+ nValue = n.getAttribute("value")
+ if n.hasAttribute("action"):
+ nAction = n.getAttribute("action")
+ if not nAction in ("join","replace","drop"):
+ textError = _('''In the text, XML profile, look \
+for a reserved attribute 'action' with the incorrect value.\n\
+Valid values attribute 'action': \
+(action="join", action="replace", action="drop")''')
+ self.setError(textError)
+ return False
+ if xmlOldNode.parentNode:
+ findAttrStr = ""
+ if attrName:
+ findAttrStr = "[%s]"%attrName
+ findPath = u"child::%s%s"%(path,findAttrStr)
+ # Рабочая нода
+ if flagRootNode:
+ workNode = xmlOldNode.parentNode
+ else:
+ workNode = xmlOldNode
+ oldNodes = xpath.Evaluate(findPath, workNode)
+ flagDrop = False
+ flagJoin = True
+ flagReplace = False
+ flagAppend = False
+ if nAction == "replace":
+ flagJoin = False
+ flagReplace = True
+ elif nAction == "drop":
+ flagJoin = False
+ flagDrop = True
+ if flagRootNode:
+ textError = _('Incorrect action="drop" in root node')
+ self.setError(textError)
+ return False
+ if path == "panel":
+ flagJoin = False
+ if levelNumber in self.panelNumbers.keys():
+ self.panelNumbers[levelNumber] += 1
+ else:
+ self.panelNumbers[levelNumber] = 0
+ if oldNodes:
+ if len(oldNodes)>1 and path != "panel":
+ textError = _("The uncertainty in this profile are \
+the same nodes at one level")
+ self.setError(textError)
+ return False
+ if path == "panel":
+ if len(oldNodes)<=self.panelNumbers[levelNumber]:
+ nextOldNode = oldNodes[-1]
+ # Добавляем ноду
+ if not flagDrop:
+ flagAppend = True
+ flagReplace = False
+ childNodes = False
+ else:
+ nextOldNode=oldNodes[self.panelNumbers[levelNumber]]
+ else:
+ nextOldNode = oldNodes[0]
+ # Замещаем ноду в случае массива
+ if flagArray and not flagDrop:
+ replaceXmlNode = xmlNode.cloneNode(True)
+ if nAction:
+ replaceXmlNode.removeAttribute("action")
+ workNode.replaceChild(replaceXmlNode,
+ nextOldNode)
+ flagJoin = False
+ flagReplace = False
+ childNodes = False
+ # Объединение нод
+ if flagJoin:
+ if nextOldNode.hasAttribute("value"):
+ oValue = nextOldNode.getAttribute("value")
+ if nValue != oValue:
+ nextOldNode.setAttribute("value",nValue)
+ # Замещение ноды
+ elif flagReplace:
+ replaceXmlNode = xmlNode.cloneNode(True)
+ if not\
+ self._removeDropNodesAndAttrAction(replaceXmlNode):
+ return False
+ workNode.replaceChild(replaceXmlNode,
+ nextOldNode)
+ childNodes = False
+ # Удаление ноды
+ elif flagDrop:
+ workNode.removeChild(nextOldNode)
+ childNodes = False
+ else:
+ flagAppend = True
+ flagDrop = False
+ if flagAppend and not flagDrop:
+ # Добавление ноды
+ childNodes = False
+ if not flagDrop:
+ appendXmlNode = xmlNode.cloneNode(True)
+ if not\
+ self._removeDropNodesAndAttrAction(appendXmlNode):
+ return False
+ workNode.appendChild(appendXmlNode)
+ if childNodes:
+ for node in childNodes:
+ levelNumber +=1
+ if not self._join(node, nextOldNode, False, levelNumber):
+ flagError = True
+ break
+ levelNumber -= 1
+ if flagError:
+ return False
+ return True
+
+ def join(self, xml_xfceObj):
+ """Объединяем конфигурации"""
+ if isinstance(xml_xfceObj, xml_xfcepanel):
+ try:
+ self.joinDoc(xml_xfceObj.doc)
+ except:
+ self.setError(_("Can not join profile"))
+ return False
+ return True
+
+
+class dhcp(bind):
+ """Класс для обработки конфигурационного файла типа dhcp
+
+ """
+ _comment = "#"
+ configName = "dhcp"
+ configVersion = "0.1"
+ __openArea = "{"
+ __closeArea = "[ \t]*\}[ \t]*"
+ sepFields = ";"
+ reOpen = re.compile(__openArea)
+ reClose = re.compile(__closeArea)
+ reCloseArea = re.compile(__closeArea + "\s*\Z")
+ reComment = re.compile("^[ \t]*%s"%(_comment))
+ reSepFields = re.compile(sepFields)
+ reSeparator = re.compile("[ \t]+")
+
+ def __init__(self,text):
+ bind.__init__(self,text)
+
+ def setDataField(self, txtLines, endtxtLines):
+ """Создаем список объектов с переменными"""
+ class fieldData:
+ def __init__(self):
+ self.name = False
+ self.value = False
+ self.comment = False
+ self.br = False
+ fields = []
+ field = fieldData()
+ z = 0
+ for k in txtLines:
+ textLine = k + endtxtLines[z]
+ z += 1
+ findComment = self.reComment.search(textLine)
+ if not textLine.strip():
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ elif findComment:
+ field.comment = textLine
+ fields.append(field)
+ field = fieldData()
+ else:
+ pars = textLine.strip()
+ nameValue = self.reSeparator.split(pars)
+ if len (nameValue) == 1:
+ field.name = textLine.replace(self.sepFields,"").strip()
+ field.value = ""
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+
+ if len(nameValue) > 2:
+ nameCheck = nameValue[0]
+ if nameValue[0][:1] in ["+","-","!"]:
+ nameCheck = nameValue[0][1:]
+ if nameCheck == "option" or nameCheck == "hardware" or\
+ nameCheck == "set":
+ valueList = nameValue[2:]
+ nameValue =[nameValue[0]+nameValue[1],
+ " ".join(valueList).replace(\
+ self.sepFields,"")]
+ else:
+ valueList = nameValue[1:]
+ nameValue =[nameValue[0]," ".join(valueList).replace(\
+ self.sepFields,"")]
+ if len(nameValue) == 2:
+ name = nameValue[0]
+ value = nameValue[1].replace(self.sepFields,"")
+ field.name = name.replace(" ","").replace("\t","")
+ field.value = value
+ field.br = textLine
+ fields.append(field)
+ field = fieldData()
+ return fields
+
+ def join(self, dhcpObj):
+ """Объединяем конфигурации"""
+ if isinstance(dhcpObj, dhcp):
+ self.docObj.joinDoc(dhcpObj.doc)
+
+
+class xml_gconf(xml_xfce):
+ """Класс для объединения gconf-xml файлов"""
+ # root нода
+ rootNode = False
+ # body нода
+ bodyNode = False
+ # Документ
+ doc = False
+ # Текст профиля
+ text = ""
+ # Текущее время в секундах
+ currentTime = ""
+ # Комментарий
+ _comment = ("")
+ # поддерживаемые аттрибуты тега entry. Пример
+ supportEntryTypes = ("int", "bool", "float", "string", "list", "pair")
+
+ def __init__(self, text):
+ self.text = text
+ # Создаем пустой объект
+ self.docObj = type("_empty_class", (object,), {})()
+ # Названия аттрибутов для пустого объекта
+ emptyMethods = ["getNodeBody","removeComment","insertBRtoBody",
+ "insertBeforeSepAreas"]
+ # Добавляем необходимые аттрибуты пустому объекту
+ for method in emptyMethods:
+ setattr(self.docObj, method, self.emptyMethod)
+ # Пустой метод (не нужно имя файла для корневой ноды)
+ setattr(self, "setNameBodyNode", self.emptyMethod)
+ # Создаем XML документ
+ self.doc = self.textToXML()
+
+ def getCurrentTime(self):
+ """Получение текущего времени в секундах"""
+ return str(int(time.time()))
+
+ def textToXML(self):
+ """Создание из текста XML документа
+ Храним xml в своем формате
+ """
+ if not self.text.strip():
+ self.text = ''''''
+ try:
+ self.doc = xml.dom.minidom.parseString(self.text)
+ except:
+ self.setError(_("Can not text profile is XML"))
+ return False
+ self.rootNode = self.doc.documentElement
+ self.bodyNode = self.rootNode
+ return self.doc
+
+ def cmpListsNodesEntry(self, listXmlA, listXmlB):
+ """Сравнение содержимого двух списков XML нод"""
+ getTextsNodes = lambda y: map(lambda x:\
+ x.toxml().replace(" ","").replace("\t","").replace("\n",""),
+ map(lambda x: x.hasAttribute("mtime") and\
+ x.removeAttribute("mtime") or x,
+ map(lambda x: x.cloneNode(True),
+ filter(lambda x: x.nodeType==x.ELEMENT_NODE, y))))
+ if set(getTextsNodes(listXmlA))==set(getTextsNodes(listXmlB)):
+ return True
+ return False
+
+ def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True, levelNumber=0):
+ """Объединение корневой ноды профиля и корневой ноды файла"""
+ if levelNumber>1:
+ return True
+ xmlNode = xmlNewNode
+ childNodes = xmlNode.childNodes
+ nextOldNode = xmlOldNode
+ flagError = False
+ if xmlNode.nodeType == xmlNode.ELEMENT_NODE:
+ n = xmlNode
+ tagName = n.tagName
+ nAction = u''
+ nName = u''
+ nType = u''
+ nValue = u''
+ nSchema = u''
+ attrName = ''
+ if flagRootNode:
+ if not tagName == "gconf":
+ self.setError(_("The text is not a valid gconf-XML format \
+(not found '...')"))
+ return False
+ flagType = False
+ flagValue = False
+ flagSchema = False
+ else:
+ if not tagName == "entry":
+ self.setError(_("The text is not a valid gconf-XML format \
+(found '<%s>..%s>'")%(tagName,tagName))
+ return False
+ if not n.hasAttribute("name"):
+ self.setError(_('Not found arrtibute "name" in tag entry'))
+ return False
+ flagType = n.hasAttribute("type")
+ flagValue = False
+ flagSchema = n.hasAttribute("schema")
+ if flagSchema:
+ nSchema = n.getAttribute("schema")
+ if not flagType and not flagSchema:
+ self.setError(_('Not found arrtibute "type" in tag entry'))
+ return False
+ nName = n.getAttribute("name")
+ attrName = u"attribute::name='%s'"%nName
+ if flagType:
+ flagValue = n.hasAttribute("value")
+ nType = n.getAttribute("type")
+ # Проверка правильности аттрибута type
+ if not nType in self.supportEntryTypes:
+ self.setError(\
+ _('Incorrect arrtibute "type" - ')\
+ %nType)
+ return False
+ if flagValue:
+ nValue = n.getAttribute("value")
+ if n.hasAttribute("action"):
+ nAction = n.getAttribute("action")
+ if not nAction in ("join","replace","drop"):
+ textError = _('''In the text, XML profile, look \
+for a reserved attribute 'action' with the incorrect value.\n\
+Valid values attribute 'action': \
+(action="join", action="replace", action="drop")''')
+ self.setError(textError)
+ return False
+ if xmlOldNode.parentNode:
+ findAttrStr = ""
+ if attrName:
+ findAttrStr = "[%s]"%attrName
+ findPath = u"child::%s%s"%(tagName,findAttrStr)
+ # Рабочая нода
+ if flagRootNode:
+ workNode = xmlOldNode.parentNode
+ else:
+ workNode = xmlOldNode
+ oldNodes = xpath.Evaluate(findPath, workNode)
+ # По умолчанию - объединение
+ flagJoin = True
+ flagReplace = False
+ flagDrop = False
+ # Замещаем ноду
+ if nType=="string" or nAction=="replace":
+ flagJoin = False
+ flagReplace = True
+ # Замещаем ноду в случае массива
+ elif nType == "list" or nType == "pair":
+ flagJoin = False
+ flagReplace = True
+ # Удаляем ноду
+ elif nAction == "drop":
+ flagJoin = False
+ flagDrop = True
+ if flagRootNode:
+ textError = _('Incorrect action="drop" in root node')
+ self.setError(textError)
+ return False
+ if oldNodes:
+ if len(oldNodes)>1:
+ textError = _("The uncertainty in this profile are \
+the same nodes at one level")
+ self.setError(textError)
+ return False
+ nextOldNode = oldNodes[0]
+ # Объединение нод
+ if flagJoin:
+ if flagType and flagValue:
+ flagChange = False
+ foundValue = nextOldNode.hasAttribute("value")
+ if foundValue:
+ oValue = nextOldNode.getAttribute("value")
+ if nValue != oValue:
+ flagChange = True
+ else:
+ flagChange = True
+ if flagChange:
+ nextOldNode.setAttribute("mtime",
+ self.currentTime)
+ nextOldNode.setAttribute("value",nValue)
+ elif flagSchema:
+ flagChange = False
+ foundValue = nextOldNode.hasAttribute("schema")
+ if foundValue:
+ oSchema = nextOldNode.getAttribute("schema")
+ if nSchema != oSchema:
+ flagChange = True
+ else:
+ flagChange = True
+ if flagChange:
+ nextOldNode.setAttribute("mtime",
+ self.currentTime)
+ nextOldNode.setAttribute("schema",nSchema)
+ # Замещение ноды
+ elif flagReplace:
+ replaceXmlNode = xmlNode.cloneNode(True)
+ # Сравнение содержимого нод
+ if not self.cmpListsNodesEntry([replaceXmlNode],
+ [nextOldNode]):
+ replaceXmlNode.setAttribute("mtime",
+ self.currentTime)
+ if not\
+ self._removeDropNodesAndAttrAction(\
+ replaceXmlNode):
+ return False
+ workNode.replaceChild(replaceXmlNode,
+ nextOldNode)
+ childNodes = False
+ # Удаление ноды
+ elif flagDrop:
+ workNode.removeChild(nextOldNode)
+ childNodes = False
+ else:
+ # Добавление ноды
+ childNodes = False
+ if not flagDrop:
+ appendXmlNode = xmlNode.cloneNode(True)
+ appendXmlNode.setAttribute("mtime", self.currentTime)
+ if not\
+ self._removeDropNodesAndAttrAction(appendXmlNode):
+ return False
+ workNode.appendChild(appendXmlNode)
+ if childNodes:
+ for node in childNodes:
+ levelNumber +=1
+ if not self._join(node, nextOldNode, False, levelNumber):
+ flagError = True
+ break
+ levelNumber -= 1
+ if flagError:
+ return False
+ return True
+
+ def join(self, xml_gconfObj):
+ """Объединяем конфигурации"""
+ # Получаем текущее время
+ self.currentTime = self.getCurrentTime()
+ if isinstance(xml_gconfObj, xml_gconf):
+ try:
+ self.joinDoc(xml_gconfObj.doc)
+ except:
+ self.setError(_("Can not join profile"))
+ return False
+ return True
+
+ def getConfig(self):
+ """Получение текстового файла из XML документа"""
+ def expand_start_tabs(s):
+ q = re.findall("^(\t+)(.*)$",s)
+ # if q:
+ return "".join((q[0][0].expand_start_tabs(),q[0][1]))
+ #else:
+ # return s
+ data = self.doc.toprettyxml().split("\n")
+ data = map(lambda x: expand_start_tabs(x),
+ filter(lambda x: x.strip(), data))
+ dataOut = []
+ z = 0
+ lenData = len(data)
+ lenM2 = lenData - 2
+ for i in xrange(lenData):
+ if z>0:
+ z -= 1
+ continue
+ if i < lenM2 and data[i].endswith(">") and not "<" in data[i+1]:
+ dataOut.append(data[i] + data[i+1].strip() + data[i+2].strip())
+ z = 2
+ continue
+ dataOut.append(data[i])
+ return "\n".join(dataOut)
diff --git a/build/lib/calculate-lib/pym/cl_utils.py b/build/lib/calculate-lib/pym/cl_utils.py
new file mode 100644
index 0000000..195d4d5
--- /dev/null
+++ b/build/lib/calculate-lib/pym/cl_utils.py
@@ -0,0 +1,510 @@
+#-*- coding: utf-8 -*-
+
+# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import filecmp
+import string
+from random import choice
+from re import search, compile, S
+import os
+import types
+import subprocess
+
+def getdirlist(s_path):
+ #Получить список директорий по указаному пути
+ fdir=filecmp.dircmp(s_path, s_path)
+ dir_list=fdir.common_dirs
+ return dir_list
+
+def prettyColumnStr(*cols):
+ '''Функция преобразования строк в текстовые колонки. Если указанный текст
+ не помещается в колонку, то строка переносится на следующую этой же колонки
+ перенос текста идет по словам, и текст выравнивается по ширине колонки за
+ счет дополнительных пробелов между словами. Если в строке используется
+ перенос строки, то текст переносится не просто на следующую строку, а также
+ на следующую строку колонки, причем если используется \r текст выравнива-
+ ется по ширине, а если \n, то просто перевод строки.
+
+ Параметры:
+ cols множестово пар: текст, ширина колонки, причем, если у последней
+ колонки не указывать ширину, то она будет выведена вся.
+
+ Возвращаемые параметры:
+ строка, которую можно использовать для вывода на экран
+
+ Пример: columnWrite( "Some text", 10, "Next column", 20 )
+ '''
+ # шаблон поиска переводов строк
+ wherenr = compile( '[\n\r]', S )
+ retstr = ""
+ # перевести кортеж в список, т.к. изменяется
+ cols = list(cols)
+ # перевести текст в юникод, заодно перевести числа в строку
+ noconvert = False
+ space = u' '
+ nospace = u''
+ for i in xrange(0,len(cols),2):
+ cols[i] = _toUNICODE(cols[i])
+ # флаг "есть еще текст для вывода"
+ repeat = True
+ while repeat:
+ # сбросить итератор на первый элемент
+ q = 0
+ repeat = False
+ # пока не закончили перебирать параметры (перебираем по парам)
+ while q < len(cols):
+ # если это последний параметр, и для него не указана ширина
+ if q == len(cols)-1:
+ # выводим его полностью не смотря на ширину окна
+ retstr += cols[q] + " "
+ cols[q] = ''
+ else:
+ # вывести часть строки не больше указанной ширины колонки
+ partstr = cols[q][:cols[q+1]]
+ # искать перевод строки с полученной части
+ brfind = wherenr.search(partstr)
+ # если это не последняя колонка
+ if q + 2 < len(cols):
+ # добавить разделитель между колонками
+ cellspacing = space
+ else:
+ # разделитель не нужен
+ cellspacing = nospace
+
+ # если перевод строки найден, то
+ if brfind != None:
+ # для текущего вывода в колонку
+ # берем часть строки до перевода
+ partstr = partstr[:brfind.start()]
+ # остальная часть идет в остаток (без перевода)
+ cols[q] = cols[q][brfind.start()+1:]
+# # если используется перевод каретки
+# if brfind.group() == '\r':
+# # то выравниваем по ширине колонки
+# partstr = partstr.ljust(cols[q+1], ' ')
+# else:
+# # добавить отступы чтобы закончить колонку
+ partstr = partstr.ljust(cols[q+1], ' ')
+ # если взята часть строки
+ elif len(partstr) == cols[q+1] and partstr != cols[q]:
+ # если взята часть строки (разрыв в слове)
+ if cols[q][cols[q+1]] != ' ':
+ # ищем ближайший пробел справа
+ spacepos = partstr.rfind(' ')
+ # если пробел найти не удалось
+ if spacepos == -1:
+ # то на вывод идет часть строки равной ширине
+ cols[q] = cols[q][cols[q+1]:]
+ # если пробел найден
+ else:
+ # обрезаем строку до найденного пробела
+ partstr = partstr[:spacepos]
+ cols[q] = cols[q][spacepos+1:]
+ # если взята часть строки (разрыв на пробеле)
+ else:
+ # ислючить переносной пробел
+ cols[q] = cols[q][cols[q+1]+1:]
+ # выровнить текст по ширине колонки
+ partstr = partstr.ljust(cols[q+1], ' ')
+ #partstr = justify(partstr, cols[q+1])
+ # остатки строки
+ else:
+ # добавить отступы чтобы закончить колонку
+ partstr = partstr.ljust(cols[q+1], ' ')
+ cols[q] = ''
+
+ retstr+= partstr + cellspacing
+
+ # остальную часть строки оставить на следующую итерацию
+ # если от строки что то осаталось
+ if len(cols[q]) > 0:
+ # отметить запуск еще одной итерации по параметрам
+ repeat = True
+ # следующая пара
+ q += 2
+ # колонки отображены
+ retstr += "\n"
+ return retstr.encode('utf8')
+
+def columnStr(*cols):
+ '''Вывод данных по колонкам, причем, если данные не вмещаются в указнаную
+ колонку, то они переносятся на следующую строку в нужную колонку. В строку.
+
+ Параметры:
+ cols множестово пар: текст, ширина колонки, причем, если у последней
+ колонки не указывать ширину, то она будет выведена вся.
+
+ Возвращаемые параметры:
+ строка, которую можно использовать для вывода на экран
+
+ Пример: columnWrite( "Some text", 10, "Next column", 20 )
+ '''
+ retstr = ""
+ # перевести кортеж в список, т.к. изменяется
+ cols = list(cols)
+ # перевести текст в юникод, заодно перевести числа в строку
+ for i in xrange(0,len(cols),2):
+ cols[i] = (str(cols[i])).decode('utf8')
+
+ # флаг "есть еще текст для вывода"
+ repeat = True
+ while repeat:
+ # сбросить итератор на первый элемент
+ q = 0
+ repeat = False
+ # пока не закончили перебирать параметры (перебираем по парам)
+ while q < len(cols):
+ # если это последний параметр, и для него не указана ширина
+ if q == len(cols)-1:
+ # выводим его полностью не смотря на ширину окна
+ retstr += cols[q] + " "
+ cols[q] = ''
+ else:
+ # вывести часть строки не больше указанной ширины колонки
+ retstr+=(cols[q][:cols[q+1]].ljust(cols[q+1])).encode('utf8') \
+ + " "
+ # остальную часть строки оставить на следующую итерацию
+ cols[q] = cols[q][cols[q+1]:]
+ # если от строки что то осаталось
+ if len(cols[q]) > 0:
+ # отметить запуск еще одной итерации по параметрам
+ repeat = True
+ # следующая пара
+ q += 2
+ # колонки отображены
+ retstr += "\n"
+ return retstr
+
+def columnWrite(*cols):
+ '''Вывод данных по колонкам, причем, если данные не вмещаются в указнаную
+ колонку, то они переносятся на следующую строку в нужную колонку.
+
+ Параметры:
+ cols множестово пар: текст, ширина колонки, причем, если у последней
+ колонки не указывать ширину, то она будет выведена вся.
+
+ Пример: columnWrite( "Some text", 10, "Next column", 20 )
+ '''
+ # перевести кортеж в список, т.к. изменяется
+ cols = list(cols)
+ # перевести текст в юникод, заодно перевести числа в строку
+ for i in xrange(0,len(cols),2):
+ cols[i] = (str(cols[i])).decode('utf8')
+
+ # флаг "есть еще текст для вывода"
+ repeat = True
+ while repeat:
+ # сбросить итератор на первый элемент
+ q = 0
+ repeat = False
+ # пока не закончили перебирать параметры (перебираем по парам)
+ while q < len(cols):
+ # если это последний параметр, и для него не указана ширина
+ if q == len(cols)-1:
+ # выводим его полностью не смотря на ширину окна
+ print cols[q].encode('utf8'),
+ cols[q] = ''
+ else:
+ # вывести часть строки не больше указанной ширины колонки
+ print (cols[q][:cols[q+1]].ljust(cols[q+1])).encode('utf8'),
+ # остальную часть строки оставить на следующую итерацию
+ cols[q] = cols[q][cols[q+1]:]
+ # если от строки что то осаталось
+ if len(cols[q]) > 0:
+ # отметить запуск еще одной итерации по параметрам
+ repeat = True
+ # следующая пара
+ q += 2
+ # колонки отображены
+ print
+
+def justify(s,width):
+ '''Выровнить текст по ширине
+
+ Параметры:
+ s выводимая строка
+ width ширина на которую надо выровнить строку
+
+ Возвращаямые параметры:
+ Выровненная строка
+ '''
+ # если подана строка без пробелов - прекратить обработку
+ if s.find(' ') == -1:
+ return s
+ pos = 0
+ # переводим в юникод для правильного вычисления длины
+ try:
+ s = s.decode( 'utf-8' )
+ # пропуск если это не utf-8
+ except UnicodeEncodeError:
+ pass
+ # пока длина строки меньше указанной
+ while len(s) < width:
+ # находим очередной пробел
+ pos = s.find( ' ', pos )
+ # если не найден искать сначала
+ if pos == -1:
+ pos = s.find(' ')
+ # вставить в позицию еще один пробел
+ s = s[:pos] +' ' +s[pos:]
+ # оставить удвоенный пробел
+ pos += 3
+ # вернуть строку в utf8 если она пришла в utf8
+ return s.encode('utf-8')
+
+def runOsCommand(cmd, inStr=None, ret_first=None, env_dict=None):
+ """Выполняет внешнюю программу
+
+ Параметры:
+ cmd внешняя программа
+ inStr данные передаваемые программе на страндартный вход.
+ ret_first вернуть только первую строку
+ env_dict словарь переменных окружения
+ Возвращаемые параметры:
+ строка/строки которую выведет внешняя программа
+ Возвращает код возврата, stdout+stderr
+ """
+ pipe = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env=env_dict,
+ close_fds=True,
+ shell=True)
+ fout, fin, ferr = (pipe.stdout, pipe.stdin, pipe.stderr)
+ # если есть данные на вход, передать их
+ if inStr:
+ fin.write(inStr)
+ fin.close()
+ # Код возврата
+ retcode = pipe.wait()
+ res = fout.readlines()
+ fout.close()
+ res += ferr.readlines()
+ ferr.close()
+ if res:
+ if len(res) == 1 or ret_first:
+ return retcode, res[0].strip()
+ else:
+ return retcode, res
+ return retcode, None
+
+
+def genpassword(passlen=9):
+ '''Вернуть случайный пассворд указанной длины
+
+ Параметры:
+ passlen длина пароля который нужно сгенерировать
+
+ Возвращаемые параметры:
+ Сгенерированный пароль указанной длины
+ '''
+ res=''.join([choice(string.ascii_letters+string.digits)\
+ for i in xrange(passlen)])
+ return res
+
+def fillstr(char, width):
+ '''Заполнить строку указанным числом символов. Псеводоним символ*кол-во'''
+ return str(char) * width
+
+ #вернуть пути для запуска утилит
+def getpathenv():
+ bindir=['/sbin','/bin','/usr/sbin','/usr/bin']
+ env=os.environ
+ if env and env.has_key('PATH'):
+ lpath=env['PATH'].split(":")
+ npath=[]
+ for dirname in bindir:
+ if os.path.exists(dirname) and dirname not in lpath:
+ npath.append(dirname)
+ lpath=npath+lpath
+ return ":".join(lpath)
+
+#класс для работы с установленными пакетами
+class pakages:
+ #путь к директории установленнх пакетов
+ pkgdir="/var/db/pkg/"
+ #список установленных пакетов
+ pkglist={}
+ #Объект содержащий параметры пакета
+ class pakage(object):
+ #имя пакета с версией
+ fullname=""
+ #имя пакета
+ name=""
+ #версия
+ ver=""
+ #тип пакета в портежах
+ portdir=""
+ def __init__(self, **args):
+ for atname,atvalue in args.items():
+ setattr(self,atname, atvalue)
+
+ def __init__(self):
+ self.pkglist=self.__getpkglist()
+
+ #разбить имя пакета на тип и имя
+ def __getpkgver(self, fname):
+ res=search('^(.+)\-([0-9]+.*)$',fname)
+ if res:
+ return res.groups()
+ else:
+ return (None,None)
+
+ #собрать установленные в системе пакеты
+ def __getpkglist(self):
+ portageDirs=[]
+ instaledPkg={}
+ #проверим на существование директории с установленными пакетами
+ if os.path.exists(self.pkgdir):
+ #получим список типов пакетов
+ portageDirs=getdirlist(self.pkgdir)
+ if len(portageDirs)>0:
+ #обрабатываем содержимое каждого из типов
+ for portageDir in portageDirs:
+ pkgList=getdirlist(self.pkgdir+portageDir)
+ for pkg in pkgList:
+ fullname=pkg
+ pkgName,pkgVer= self.__getpkgver(pkg)
+ pobj=self.pakage(fullname=fullname,
+ name=pkgName, \
+ ver=pkgVer,\
+ portdir=portageDir)
+ fpkg=portageDir+"/"+pkgName
+ if instaledPkg.has_key(fpkg):
+ instaledPkg[fpkg].append(pobj)
+ else:
+ instaledPkg[fpkg]=[pobj]
+ return instaledPkg
+
+ #разбить pkgname на составляющие имени пакета
+ def __partname(self, pkgname):
+ if not pkgname.strip():
+ return False
+ res=search('^(.+\/)?(.+)',pkgname)
+ tname=None
+ if res.group(1):
+ tname=res.group(1)
+ if res.group(2):
+ res2=search('^(.+)(\-[0-9]+.+$)',res.group(2))
+ if res2:
+ name=res2.group(1)
+ ver=res2.group(2)
+ else:
+ name=res.group(2)
+ ver=None
+ if res:
+ if name and name[-1:]=='-':
+ name=name[:-1]
+ if tname and tname[-1:]=='/':
+ tname=tname[:-1]
+ if ver and ver[0]=='-':
+ ver=ver[1:]
+ return [tname, name, ver]
+
+
+ #проверить установленн ли пакет
+ #isinstalled('dev-db/postgresql')
+ def isinstalled(self, pkgname):
+ res=self.getinstpkg(pkgname)
+ if len(res)>0:
+ return True
+ else:
+ return False
+
+ #вернуть список объектов pakage() соответствующих pkgname
+ #getinstpkg('dev-db/postgresql')
+ #в случае отсутствия пакетов возвращает пустой список
+ def getinstpkg(self, pkgname):
+ pinfo=self.__partname(pkgname)
+ if pinfo:
+ ret=[]
+ if pinfo[0] and pinfo[1] and pinfo[2]:
+ if not self.pkglist.has_key(pinfo[0]+'/'+pinfo[1]):
+ return []
+ fpkg=self.pkglist[pinfo[0]+'/'+pinfo[1]]
+ ret=[]
+ for i in fpkg:
+ if i.ver==pinfo[2]:
+ ret.append(i)
+ return ret
+ elif pinfo[0] and pinfo[1]:
+ if not self.pkglist.has_key(pinfo[0]+'/'+pinfo[1]):
+ return []
+ return self.pkglist[pinfo[0]+'/'+pinfo[1]]
+ elif pinfo[1] and pinfo[2]:
+ for i in self.pkglist.keys():
+ if search('^.+\/%s$'%(pinfo[1]),i):
+ for el in self.pkglist[i]:
+ if el.ver==pinfo[2]:
+ ret.append(el)
+ return ret
+ elif pinfo[1]:
+ for i in self.pkglist.keys():
+ if search('^.+\/%s$'%(pinfo[1]),i):
+ ret+=self.pkglist[i]
+ return ret
+ return []
+
+ def getListPkg(self):
+ return self.pkglist
+
+def list2str(list):
+ '''Функция переводит список в строку'''
+ return '['+','.join(list)+']'
+
+def str2list(s):
+ '''Функция переводит строку в список'''
+ return s[1:-1].split(',')
+
+def dict2str(dict):
+ '''Функция перводит словарь в строку'''
+ return '{'+','.join(["%s:%s" % (str(k),str(v)) \
+ for (k,v) in dict.items()])+'}' #:
+
+def str2dict(s):
+ '''Функция переводит строку в словарь'''
+ dict = {}
+ for i in s[1:-1].split(','):
+ k,v = i.split(':')
+ dict[k] = v
+ return dict
+
+def convertStrListDict(val):
+ '''Функция определеяется что на входе (строка, список, словарь)
+ и переводит их в строку и обратно'''
+ # если подан список
+ if type(val) == types.ListType:
+ return list2str(val)
+ # если подан словарь
+ elif type(val) == types.DictType:
+ return dict2str(val)
+ # если подана строка
+ else:
+ # если поданная строка содержит словарь
+ if ':' in val and '{' in val:
+ return str2dict(val)
+ # если поданная строка содержит список
+ elif ',' in val and '[' in val:
+ return str2list(val)
+ # если это просто строка
+ else:
+ return val
+
+def _toUNICODE(val):
+ """перевод текста в юникод"""
+ if type(val) == types.UnicodeType:
+ return val
+ else:
+ return str(val).decode('UTF-8')
diff --git a/build/lib/calculate-lib/pym/cl_utils2.py b/build/lib/calculate-lib/pym/cl_utils2.py
new file mode 100644
index 0000000..330e7dd
--- /dev/null
+++ b/build/lib/calculate-lib/pym/cl_utils2.py
@@ -0,0 +1,563 @@
+#-*- coding: utf-8 -*-
+
+# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+import struct
+import termios
+import fcntl
+import cl_utils
+
+import cl_profile
+import ldap
+class ldapFun(cl_profile._error):
+ '''Объект для работы с LDAP сервером
+
+ подключение к серверу и поиск данных
+ '''
+ def __init__(self, dnUser, password, host="localhost"):
+ self.conLdap = False
+ # Получаем соединение с LDAP
+ try:
+ self.conLdap = self.__ldapConnect(dnUser, password, host)
+ except ldap.LDAPError, e:
+ self.setError(e[0]['desc'])
+
+ def __ldapConnect(self, dnUser, password, host):
+ """Соединение с LDAP сервером"""
+ conLdap = ldap.initialize('ldap://%s'%host)
+ conLdap.simple_bind_s(dnUser, password)
+ return conLdap
+
+ def ldapSearch(self,baseDN, searchScope, searchFilter, retrieveAttributes):
+ try:
+ ldap_result_id = self.conLdap.search(baseDN, searchScope,
+ searchFilter,
+ retrieveAttributes)
+ result_set = []
+ while 1:
+ result_type, result_data = self.conLdap.result(ldap_result_id,
+ 0)
+ if (result_data == []):
+ break
+ else:
+ if result_type == ldap.RES_SEARCH_ENTRY:
+ result_set.append(result_data)
+ except ldap.NO_SUCH_OBJECT:
+ return []
+ except:
+ return False
+ return result_set
+
+pcs = cl_utils.prettyColumnStr
+
+class cl_help:
+ """Объект для работы со справкой, и обработкой параметров.
+
+ Конструктор __init__ должен определить следующие переменные:
+
+ self.chapter список разделов справки, каждый элементы состоит из
+ имени раздела, флаг видимый/скрытый, кол-во переводов строк
+ после названия раздела, количество строк после раздела,
+ тип раздела
+ Пример: [("Copyright",False,0,2),"options"]
+ self.relService словарь связей сервисов и действующих опций
+ ключ - название сервиса, значение - список отображаемых
+ разделов отмеченных как "options"
+ Пример: {"samba":[_("Common options"),
+ _("Service Samba options")]}
+ self.relOptions словарь связей длинных опций помощи и выводимых разделов
+ помощи с опциями
+ ключ - параметр справки, значение список отображаемых
+ разделов справки
+ Пример: {"help-ldap":[_("Common options"),
+ _("Service LDAP options)]}
+ self.progName словарь имена используемых программ и их номера для
+ доступа к переменным
+ Пример: {'cl-groupadd':0, 'cl-groupdel':1}
+ self.data список данных для справки, каждый элемент словарь:
+ progAccess: список номеров программ отображающих
+ Пример: {'progAccess':(0,),
+ 'shortOption':"g",
+ 'longOption':"gid",
+ 'optVal':"GID",
+ 'helpChapter':_("Options"),
+ 'help':_("use GID for the new group")
+ },
+ после заполнения параметров необходимо выполнить
+ self._cl_help__setParamHelp() для заполнения справки
+
+ """
+ def __init__(self, cmdName):
+ # ширина консоли взята за 80
+ # -1 чтобы компенсировать расстрояние между колонками
+ self.consolewidth = 79
+ self.column_width = 32
+ self.cmdName = cmdName
+ #короткие опции командной строки
+ self.shortOpt = []
+ #длинные опции командной строки
+ self.longOpt = []
+ # массив разделов (заполняется в __setParamHelp)
+ self.chapterBloc = []
+ #optEnd = ""
+ #if "user" in self.cmdName and not "mod" in self.cmdName:
+ #optEnd = _("user")
+ #elif "group" in self.cmdName and not "mod" in self.cmdName:
+ #optEnd = _("group")
+ #self.__setParamHelp()
+
+ def getChapterNumber(self,NameChapter):
+ """Получить номер раздела по имени"""
+ num = 0
+ for i in self.chapter:
+ if i[0] == NameChapter:
+ return num
+ num += 1
+ return False
+
+ def __setParamHelp(self):
+ """Внутренняя функция формирования справки по данным
+
+ Перебирает все элементы списка data, проверяет их на доступность
+ данной программы, разбирает опции на среди data и формирует
+ для по ним справку.
+ """
+ # сформировать нужное количество блоков раздела
+ self.chapterBloc = [""]*len(self.chapter)
+ #
+ sp = {}
+ i = 0
+ # перебираем все элементы справки собираем элементы опции
+ # так же формируем разделы не опции
+ for par in self.data:
+ # перебираем только те опции, которые принадлежат команде
+ if self.access(par):
+ # есть короткая (возможно есть и длинная)
+ if par.has_key("shortOption"):
+ sp[par["shortOption"]+":"+par["helpChapter"]] = i
+ # есть только длинная опция
+ elif par.has_key("longOption"):
+ sp[par["longOption"]+":"+par["helpChapter"]] = i
+ # формирование разделов не опций
+ else:
+ helpTxt = par['help']
+ numChapter = self.getChapterNumber(par['helpChapter'])
+ self.addChapterHelp(numChapter,helpTxt)
+ i += 1
+ # перебираем все "собранные" опции
+ # опции перебираются по порядку в списке date
+ # для сортировки по ключам следует применить код:
+ # for index in sorted(sp.keys()):
+ # par = self.data[sp[index]]
+ for index in sorted(sp.values()):
+ par = self.data[index]
+ numChapter = self.getChapterNumber(par['helpChapter'])
+ # если есть и короткая и длинная
+ if "shortOption" in par and "longOption" in par:
+ paraminfo = "-%s, --%s "%(par["shortOption"],par["longOption"])
+ # если есть только короткая
+ elif "shortOption" in par:
+ paraminfo = "-%s "%par["shortOption"]
+ # если только длинная
+ else:
+ paraminfo = "--%s "%par["longOption"]
+ # если указан параметр для опции
+ if "optVal" in par:
+ optVal = par["optVal"]
+ else:
+ optVal = ""
+
+ # вывод вида: " [-o, ][--option] [PARAM]" "helpstring"
+ helpTxt = pcs(" "+paraminfo+optVal, self.column_width, \
+ par['help'], self.consolewidth-self.column_width)
+ # добавить строку в нужный раздел
+ self.addChapterHelp(numChapter,helpTxt)
+
+ def getHelp(self, optionsChapters=False):
+ """Выдать справку.
+
+ Выдает справку в случае если указан optionsChapters, то фильтрует по
+ типу разделов.
+
+ Параметры:
+ optionsChapters Flase или список опциональных разделов для
+ отображения
+
+ Возвращаемые параметры:
+ Строка со справкой.
+ """
+ # Выдать справку
+ help = ""
+ # перебираем все элементы справочных блоков
+ iterChapterBloc = iter(self.chapterBloc)
+ # перебираем все разделы по параметрам
+ for (nameChapter, visibleChapter, beforeStrChapter, \
+ afterStrChapter, typeChapter) in self.chapter:
+ # получаем следующий блок (т.о. textChapterBloc соответ, chapter)
+ textChapterBloc = iterChapterBloc.next()
+ # если тип раздела опциональный
+ if optionsChapters and typeChapter=="options":
+ # проверяем нужно ли его отображать
+ if not (nameChapter in optionsChapters):
+ continue
+ bef = "\n"*beforeStrChapter
+ aft = "\n"*afterStrChapter
+ # если блок не пустой и раздел отображаемый
+ if len(textChapterBloc) > 0:
+ if visibleChapter:
+ help += nameChapter + ": " + bef
+ help += textChapterBloc + aft
+ help = help.rstrip()+"\n"
+ return help
+
+ def addChapterHelp(self, numChapter, helpTxt):
+ """Добавить в раздел помощи numChapteк тектстовую строку helpTxt
+
+ Параметры:
+ numChapter номер раздела в который нужно добавить данные справки
+ helpTxt строка, содержащая данные
+ """
+ self.chapterBloc[numChapter] += helpTxt
+ return True
+
+ def addData(self,dataHash):
+ # На будущее (добавляет опции)
+ self.data.append(dataHash)
+ return True
+
+ def handleCheckAccess(self,dataHash):
+ """Замещаемый дополнительный обработчик проверки
+ доступности опции.
+
+ Входные параметры:
+ dataHash элементы списка данных справки (self.data)
+ """
+ return True
+
+ def access(self,dataHash):
+ """Доступна ли опция вызывающей программе
+
+ Параметры:
+ dataHash словарь элемент типа self.data
+
+ Возвращаемые параметры:
+ True/False доступна/недоступна
+ """
+ # доступна ли опция вызывающей программе
+ # опция без progAccess доступна
+ numProg = self.progName[self.cmdName]
+ if 'progAccess' in dataHash:
+ if numProg in dataHash['progAccess']:
+ # вызов дополнительной проверки доступа к опции
+ return self.handleCheckAccess(dataHash)
+ else:
+ return False
+ else:
+ # вызов дополнительной проверки доступа к опции
+ return self.handleCheckAccess(dataHash)
+
+ def getTypeChapter(self, nameChapter):
+ """Получить тип раздела по его имени
+
+ Параметры:
+ nameChapter название раздела
+
+ Возвращаемые параметры:
+ строка тип раздела
+ Flase(Boolean) такой раздел отсутствует
+ """
+ # фильтруем список по имени раздела, помещаем в список тип раздела
+ filtered = [typeChapter for name, na, na, na, typeChapter \
+ in self.chapter if name == nameChapter]
+ # если среди фильтрованных есть хоть один элемент
+ if len(filtered) > 0:
+ # возвращаем - он запрашиваемый
+ return filtered[0]
+ else:
+ # такой раздел отсутствует
+ return False
+
+ def clearAllOpt(self):
+ """Очистить все опции, полученные посредством getAllOpt"""
+ if len(self.shortOpt) > 0:
+ self.shortOpt = []
+ if len(self.longOpt) > 0:
+ self.longOpt = []
+ return True
+
+ def getAllOpt(self,typeOpt="all", optionsChapters=False):
+ """Получить все доступные опции
+
+ Параметры:
+ typeOpt 'short'/'long'/'all', вернуть короткие или длинные
+ опции или все (возвращаются кортежем)
+ optionsChapters фильтр для опций по типам разделов (список,кортеж)
+
+ Возвращаемые параметры:
+ строка коротки или список строк длинных опций ('hb:c:wg:G:k:ms:u:')
+ """
+ # Выдать все действующие опции
+ if typeOpt=="short" or typeOpt=="all":
+ if len(self.shortOpt) == 0:
+ for par in self.data:
+ if optionsChapters and\
+ self.getTypeChapter(par['helpChapter'])=="options":
+ if not (par['helpChapter'] in optionsChapters):
+ continue
+ if par.has_key("shortOption") and self.access(par):
+ if par.has_key("optVal"):
+ self.shortOpt.append(par["shortOption"]+':')
+ else:
+ self.shortOpt.append(par["shortOption"])
+ if typeOpt=="long" or typeOpt=="all":
+ if len(self.longOpt) == 0:
+ for par in self.data:
+ if optionsChapters and\
+ self.getTypeChapter(par['helpChapter'])=="options":
+ #print par["longOption"]
+ if not (par['helpChapter'] in optionsChapters):
+ continue
+ if par.has_key("longOption") and self.access(par):
+ if par.has_key("optVal"):
+ self.longOpt.append(par["longOption"]+'=')
+ else:
+ self.longOpt.append(par["longOption"])
+ if typeOpt=="short":
+ return "".join(self.shortOpt)
+ elif typeOpt=="long":
+ return self.longOpt
+ elif typeOpt=="all":
+ return ("".join(self.shortOpt),self.longOpt)
+
+ def getShortOpt(self,option):
+ """Из любой опции получить короткую опцию.
+
+ Фильтрация также происходит и по названию команды.
+
+ Параметры:
+ option запрашиваемая опция
+
+ Возвращаемые параметры:
+ короткая опция, если же для длинной опции нет короткой, возвращается
+ пустая строка.
+ """
+ # Из любой опции получаем короткую опцию
+ for par in self.data:
+ if par.has_key("shortOption") and self.access(par):
+ if (par.has_key("longOption") and\
+ par["longOption"] == option) or \
+ par["shortOption"] == option:
+ return par["shortOption"]
+ break
+ return ""
+
+class cl_smartcon(object):
+
+ def getconsolewidth(self):
+ """Получить ширину текущей консоли"""
+ s = struct.pack("HHHH", 0, 0, 0, 0)
+ fd_stdout = sys.stdout.fileno()
+ try:
+ x = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s)
+ except IOError:
+ # если ошибка то ширина 80 символов
+ return 80
+ #(rows, cols, x pixels, y pixels)
+ return struct.unpack("HHHH", x)[1]
+
+ def printRight(self, offsetLeft, offsetRight):
+ """Добавляет необходимое количество пробелов:
+
+ количество пробелов = (ширина консоли - offsetLeft - offsetRight)
+ """
+ cols = self.getconsolewidth()
+ for i in range(cols - offsetLeft - offsetRight):
+ sys.stdout.write(" ")
+
+ def colorPrint(self,attr,fg,bg,string):
+ """Раскрашивает выводимое сообщение
+
+ Параметры:
+ attr - это атрибут
+ fg - цвет символа
+ bg - цвет фона
+
+ в случае если параметр равен "" то он не изменяется
+
+ attr может принимать следующие значения:
+ 0 сбросить все атрибуты (вернуться в нормальный режим)
+ 1 яркий (обычно включает толстый шрифт)
+ 2 тусклый
+ 3 подчёркнутый
+ 5 мигающий
+ 7 реверсный
+ 8 невидимый
+
+ fg может принимать следующие значения:
+ 30 чёрный
+ 31 красный
+ 32 зелёный
+ 33 жёлтый
+ 34 синий
+ 35 фиолетовый
+ 36 голубой
+ 37 белый
+
+ bg может принимать следующие значения:
+ 40 чёрный
+ 41 красный
+ 42 зелёный
+ 43 жёлтый
+ 44 синий
+ 45 фиолетовый
+ 46 голубой
+ 47 белый
+ """
+ lst = []
+ if attr:
+ lst.append(attr)
+ if fg:
+ lst.append(fg)
+ if bg:
+ lst.append(bg)
+ sys.stdout.write("\033[%sm%s\033[0m" %(";".join(lst),string))
+
+ def redBrightPrint(self, string):
+ """Печатает яркое красное сообщение"""
+ self.colorPrint("1","31","",string)
+
+ def greenBrightPrint(self, string):
+ """Печатает яркое зеленое сообщение"""
+ self.colorPrint("1","32","",string)
+
+ def yellowBrightPrint(self, string):
+ """Печатает яркое желтое сообщение"""
+ self.colorPrint("1","33","",string)
+
+ def blueBrightPrint(self, string):
+ """Печатает яркое cинее сообщение"""
+ self.colorPrint("1","34","",string)
+
+ def lenString(self, string):
+ """Получаем длинну строки"""
+ stringUnicode = cl_utils._toUNICODE(string)
+ lenString = len(stringUnicode)
+ return lenString
+
+
+ def defaultPrint(self, string):
+ sys.stdout.write(string)
+ sys.stdout.flush()
+
+ def printLine(self, argL, argR, offsetL=0, printBR=True):
+ """Печатает справа и слева консоли цветные сообщения"""
+ #Допустимые цвета
+ colorDict = {\
+ # цвет по умолчанию
+ '':self.defaultPrint,
+ # ярко зеленый
+ 'greenBr':self.greenBrightPrint,
+ # ярко голубой
+ 'blueBr':self.blueBrightPrint,
+ # ярко красный
+ 'redBr':self.redBrightPrint,
+ # ярко желтый
+ 'yellowBr':self.yellowBrightPrint,
+ }
+ # cмещение от левого края консоли
+ #offsetL = 0
+ for color,leftString in argL:
+ offsetL += self.lenString(leftString)
+ if colorDict.has_key(color):
+ # печатаем и считаем смещение
+ colorDict[color](leftString)
+ else:
+ colorDict[''](leftString)
+ # cмещение от правого края консоли
+ offsetR = 0
+ for color,rightString in argR:
+ offsetR += self.lenString(rightString)
+ # Добавляем пробелы
+ if offsetR:
+ self.printRight(offsetL, offsetR)
+ for color,rightString in argR:
+ if colorDict.has_key(color):
+ # печатаем и считаем смещение
+ colorDict[color](rightString)
+ else:
+ colorDict[''](rightString)
+ if printBR:
+ print ""
+
+ def printNotOK(self, string, offsetL=0, printBR=True):
+ """Вывод на печать в случае сбоя"""
+ self.printLine((('greenBr',' * '),
+ ('',string),
+ ),
+ (('blueBr','['),
+ ('redBr',' !! '),
+ ('blueBr',']'),
+ ), offsetL, printBR)
+
+ def printOnlyNotOK(self, string, offsetL=0, printBR=True):
+ """Вывод на печать в случае сбоя"""
+ self.printLine((('', string),),
+ (('blueBr','['),
+ ('redBr',' !! '),
+ ('blueBr',']'),
+ ), offsetL, printBR)
+
+ def printOK(self, string, offsetL=0, printBR=True):
+ """Вывод на печать в случае успеха"""
+ self.printLine((('greenBr',' * '),
+ ('',string),
+ ),
+ (('blueBr','['),
+ ('greenBr',' ok '),
+ ('blueBr',']'),
+ ), offsetL, printBR)
+
+ def printOnlyOK(self, string, offsetL=0, printBR=True):
+ """Вывод на печать в случае успеха"""
+ self.printLine((('',string),),
+ (('blueBr','['),
+ ('greenBr',' ok '),
+ ('blueBr',']'),
+ ), offsetL, printBR)
+
+ def printWARNING(self, string, offsetL=0, printBR=True):
+ """Вывод на печать предупреждения"""
+ self.printLine((('yellowBr',' * '),
+ ('',string),
+ ),
+ (('',''),
+ ), offsetL, printBR)
+
+ def printERROR(self, string, offsetL=0, printBR=True):
+ """Вывод на печать предупреждения"""
+ self.printLine((('redBr',' * '),
+ ('',string),
+ ),
+ (('',''),
+ ), offsetL, printBR)
+
+ def printSUCCESS(self, string, offsetL=0, printBR=True):
+ """Вывод на печать в случае успеха без [ok] справа"""
+ self.printLine((('greenBr',' * '),
+ ('',string),
+ ),
+ (('',''),
+ ), offsetL, printBR)
diff --git a/build/lib/calculate-lib/pym/cl_vars.py b/build/lib/calculate-lib/pym/cl_vars.py
new file mode 100644
index 0000000..be174fd
--- /dev/null
+++ b/build/lib/calculate-lib/pym/cl_vars.py
@@ -0,0 +1,91 @@
+#-*- coding: utf-8 -*-
+
+# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#Допустимые ключи значений
+# mode - режим переменной r-не переназначается из командной строки,
+# w-переназначается из командной строки
+# type - тип переменной состоит из двух элементов(что это и для чего
+# это)
+# value - значение переменной
+
+class Data:
+
+ # имя компьютера
+ os_net_hostname = {'mode':"w"}
+ # разрешенные сети
+ os_net_allow ={}
+ # ip на всех интерфейсах
+ os_net_ip ={}
+
+ #короткое название системы (CLD)
+ os_linux_shortname={}
+
+ #домен
+ os_net_domain = {'mode':"w"}
+
+ # Пути к ini файлам
+ cl_env_path = {'value':['/var/calculate/remote/calculate.env',
+ '/var/calculate/calculate.env',
+ '/etc/calculate/calculate.env']}
+
+ # локаль (прим: ru_RU.UTF-8)
+ os_locale_locale = {}
+ # язык (прим: ru_RU)
+ os_locale_lang = {}
+ # язык (прим: ru)
+ os_locale_language = {}
+
+ # раскладка клавиатуры для X
+ os_locale_xkb = {}
+
+ # названия используемых раскладок клавиатуры для X
+ os_locale_xkbname = {}
+
+ # архитектура компьютера (i686,x86_64)
+ os_arch_machine = {}
+
+ #проход при наложении профилей 1,2,3,4,5 и.т д
+ cl_pass_step = {'mode':"w"}
+
+ # обрабатываемый файл профиля
+ cl_pass_file = {'mode':"w"}
+
+ # корневой раздел файловой системы
+ os_root_dev = {}
+
+ # тип носителя (ram, hdd, usb-hdd, livecd)
+ os_root_type = {}
+
+ # полное название системы
+ os_linux_name = {}
+
+ # постфикс к названию системы
+ os_linux_subname = {}
+
+ # название виртуальной машины (virtualbox, vmware, qemu)
+ hr_virtual = {}
+
+ # версия системы
+ os_linux_ver = {}
+
+ # Тип профиля
+ cl_pass_type = {'mode':"w"}
+
+ # Действие программы
+ cl_pass_run = {'mode':"w"}
+
+ #Логин пользователя
+ ur_login = {'mode':"w"}
diff --git a/pym/cl_profile.py b/pym/cl_profile.py
index db47e78..cad373a 100644
--- a/pym/cl_profile.py
+++ b/pym/cl_profile.py
@@ -6881,6 +6881,7 @@ class xml_gconf(xml_xfce):
_comment = ("")
# поддерживаемые аттрибуты тега entry. Пример
supportEntryTypes = ("int", "bool", "float", "string", "list", "pair")
+ reStartTabs = re.compile("^(\t+)(.*)$")
def __init__(self, text):
self.text = text
@@ -7111,8 +7112,14 @@ the same nodes at one level")
def getConfig(self):
"""Получение текстового файла из XML документа"""
+ def expandStartTabs(s):
+ if s.startswith("\t"):
+ res = self.reStartTabs.findall(s)
+ return "".join((res[0][0].replace("\t"," "),res[0][1]))
+ else:
+ return s
data = self.doc.toprettyxml().split("\n")
- data = map(lambda x: x.replace("\t"," "),
+ data = map(lambda x: expandStartTabs(x),
filter(lambda x: x.strip(), data))
dataOut = []
z = 0