From 538372b42aa954a085b9ef82392d6f68d9413805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B0=D0=BC=D0=BE=D1=83=D0=BA=D0=B8=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9?= Date: Wed, 27 Jan 2010 15:32:56 +0300 Subject: [PATCH 1/7] Create develop branch --- build/lib/calculate-lib/pym/__init__.py | 0 build/lib/calculate-lib/pym/cl_data.py | 624 +++ build/lib/calculate-lib/pym/cl_fill.py | 346 ++ build/lib/calculate-lib/pym/cl_help.py | 375 ++ build/lib/calculate-lib/pym/cl_lang.py | 168 + build/lib/calculate-lib/pym/cl_ldap.py | 58 + build/lib/calculate-lib/pym/cl_log.py | 60 + build/lib/calculate-lib/pym/cl_overriding.py | 58 + build/lib/calculate-lib/pym/cl_print.py | 217 + build/lib/calculate-lib/pym/cl_string.py | 254 ++ build/lib/calculate-lib/pym/cl_template.py | 3774 +++++++++++++++++ build/lib/calculate-lib/pym/cl_utils.py | 214 + build/lib/calculate-lib/pym/cl_vars.py | 89 + .../lib/calculate-lib/pym/format/__init__.py | 0 build/lib/calculate-lib/pym/format/apache.py | 218 + build/lib/calculate-lib/pym/format/bind.py | 315 ++ build/lib/calculate-lib/pym/format/compiz.py | 41 + build/lib/calculate-lib/pym/format/dhcp.py | 100 + build/lib/calculate-lib/pym/format/dovecot.py | 65 + build/lib/calculate-lib/pym/format/kde.py | 160 + build/lib/calculate-lib/pym/format/ldap.py | 183 + build/lib/calculate-lib/pym/format/plasma.py | 597 +++ build/lib/calculate-lib/pym/format/postfix.py | 117 + .../lib/calculate-lib/pym/format/procmail.py | 115 + build/lib/calculate-lib/pym/format/samba.py | 261 ++ build/lib/calculate-lib/pym/format/squid.py | 86 + .../lib/calculate-lib/pym/format/xml_gconf.py | 262 ++ .../lib/calculate-lib/pym/format/xml_xfce.py | 268 ++ .../calculate-lib/pym/format/xml_xfcepanel.py | 199 + pym/cl_data.py | 624 +++ pym/cl_fill.py | 11 +- pym/cl_help.py | 375 ++ pym/cl_lang.py | 168 + pym/cl_ldap.py | 58 + pym/cl_log.py | 3 +- pym/cl_overriding.py | 58 + pym/cl_print.py | 217 + pym/cl_string.py | 254 ++ pym/cl_template.py | 3774 +++++++++++++++++ pym/cl_utils.py | 490 +-- pym/cl_vars.py | 9 +- pym/format/__init__.py | 0 pym/format/apache.py | 218 + pym/format/bind.py | 315 ++ pym/format/compiz.py | 41 + pym/format/dhcp.py | 100 + pym/format/dovecot.py | 65 + pym/format/kde.py | 160 + pym/format/ldap.py | 183 + pym/format/plasma.py | 597 +++ pym/format/postfix.py | 117 + pym/format/procmail.py | 115 + pym/format/samba.py | 261 ++ pym/format/squid.py | 86 + pym/format/xml_gconf.py | 262 ++ pym/format/xml_xfce.py | 268 ++ pym/format/xml_xfcepanel.py | 199 + setup.py | 6 +- 58 files changed, 17852 insertions(+), 406 deletions(-) create mode 100644 build/lib/calculate-lib/pym/__init__.py create mode 100644 build/lib/calculate-lib/pym/cl_data.py create mode 100644 build/lib/calculate-lib/pym/cl_fill.py create mode 100644 build/lib/calculate-lib/pym/cl_help.py create mode 100644 build/lib/calculate-lib/pym/cl_lang.py create mode 100644 build/lib/calculate-lib/pym/cl_ldap.py create mode 100644 build/lib/calculate-lib/pym/cl_log.py create mode 100644 build/lib/calculate-lib/pym/cl_overriding.py create mode 100644 build/lib/calculate-lib/pym/cl_print.py create mode 100644 build/lib/calculate-lib/pym/cl_string.py create mode 100644 build/lib/calculate-lib/pym/cl_template.py create mode 100644 build/lib/calculate-lib/pym/cl_utils.py create mode 100644 build/lib/calculate-lib/pym/cl_vars.py create mode 100644 build/lib/calculate-lib/pym/format/__init__.py create mode 100644 build/lib/calculate-lib/pym/format/apache.py create mode 100644 build/lib/calculate-lib/pym/format/bind.py create mode 100644 build/lib/calculate-lib/pym/format/compiz.py create mode 100644 build/lib/calculate-lib/pym/format/dhcp.py create mode 100644 build/lib/calculate-lib/pym/format/dovecot.py create mode 100644 build/lib/calculate-lib/pym/format/kde.py create mode 100644 build/lib/calculate-lib/pym/format/ldap.py create mode 100644 build/lib/calculate-lib/pym/format/plasma.py create mode 100644 build/lib/calculate-lib/pym/format/postfix.py create mode 100644 build/lib/calculate-lib/pym/format/procmail.py create mode 100644 build/lib/calculate-lib/pym/format/samba.py create mode 100644 build/lib/calculate-lib/pym/format/squid.py create mode 100644 build/lib/calculate-lib/pym/format/xml_gconf.py create mode 100644 build/lib/calculate-lib/pym/format/xml_xfce.py create mode 100644 build/lib/calculate-lib/pym/format/xml_xfcepanel.py create mode 100644 pym/cl_data.py create mode 100644 pym/cl_help.py create mode 100644 pym/cl_lang.py create mode 100644 pym/cl_ldap.py create mode 100644 pym/cl_overriding.py create mode 100644 pym/cl_print.py create mode 100644 pym/cl_string.py create mode 100644 pym/cl_template.py create mode 100644 pym/format/__init__.py create mode 100644 pym/format/apache.py create mode 100644 pym/format/bind.py create mode 100644 pym/format/compiz.py create mode 100644 pym/format/dhcp.py create mode 100644 pym/format/dovecot.py create mode 100644 pym/format/kde.py create mode 100644 pym/format/ldap.py create mode 100644 pym/format/plasma.py create mode 100644 pym/format/postfix.py create mode 100644 pym/format/procmail.py create mode 100644 pym/format/samba.py create mode 100644 pym/format/squid.py create mode 100644 pym/format/xml_gconf.py create mode 100644 pym/format/xml_xfce.py create mode 100644 pym/format/xml_xfcepanel.py 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_data.py b/build/lib/calculate-lib/pym/cl_data.py new file mode 100644 index 0000000..926c224 --- /dev/null +++ b/build/lib/calculate-lib/pym/cl_data.py @@ -0,0 +1,624 @@ +#-*- 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 sys +import cl_utils +from cl_lang import lang +from cl_template import iniParser +from cl_string import columnWrite + +# Перевод модуля на другой язык +tr = lang() +tr.setLocalDomain('cl_lib') +tr.setLanguage(sys.modules[__name__]) + +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 self.__dict__.has_key(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 self.__dict__.has_key(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 self.__dict__.has_key(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 self.__dict__.has_key(vname): + if self.__dict__[vname].service == 'Global': + return 'calculate' + else: + return self.__dict__[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') + + Возвращаемые значение: + 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) + # Удаляем переменную + 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): + #if vname: + #if self.__dict__.has_key(vname): + #return True + #return False + def defined(self, vname): + return True + + + + def exists(self, nameVar): + """ Определяет существует ли переменная с таким имененм + """ + if self.__dict__.has_key(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 + 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..4d3b598 --- /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 +from cl_overriding import exit +import cl_utils +import cl_data + +class fillVars(object, cl_data.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") + 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", + "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"} + 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.template" + 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_help.py b/build/lib/calculate-lib/pym/cl_help.py new file mode 100644 index 0000000..20ca654 --- /dev/null +++ b/build/lib/calculate-lib/pym/cl_help.py @@ -0,0 +1,375 @@ +#-*- 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 getopt +import sys +from cl_string import prettyColumnStr + +pcs = prettyColumnStr + +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 + +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"] + return "" diff --git a/build/lib/calculate-lib/pym/cl_lang.py b/build/lib/calculate-lib/pym/cl_lang.py new file mode 100644 index 0000000..eb0cf69 --- /dev/null +++ b/build/lib/calculate-lib/pym/cl_lang.py @@ -0,0 +1,168 @@ +#-*- 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, gettext +from cl_overriding import __findFileMO + +class GlobalParam(type): + """ Метакласс для глобальных параметров + """ + def __init__(cls, *args): + cls.GP = [] + cls.GP.append("") + +gettext.find = __findFileMO + +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 + diff --git a/build/lib/calculate-lib/pym/cl_ldap.py b/build/lib/calculate-lib/pym/cl_ldap.py new file mode 100644 index 0000000..bea5fae --- /dev/null +++ b/build/lib/calculate-lib/pym/cl_ldap.py @@ -0,0 +1,58 @@ +#-*- 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 ldap +from cl_utils import _error + +class ldapFun(_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 + 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..ab65d0e --- /dev/null +++ b/build/lib/calculate-lib/pym/cl_log.py @@ -0,0 +1,60 @@ +#-*- 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_overriding.py b/build/lib/calculate-lib/pym/cl_overriding.py new file mode 100644 index 0000000..0c6ca8e --- /dev/null +++ b/build/lib/calculate-lib/pym/cl_overriding.py @@ -0,0 +1,58 @@ +#-*- 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,sys,gettext + +def __findFileMO(domain, localedir=None, languages=None, all=0): + """Модифицированный метод, ищет файл перевода + + замена gettext.find""" + 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 gettext._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 + +def exit(codeExit): + """Метод выхода из программы""" + sys.exit(codeExit) \ No newline at end of file diff --git a/build/lib/calculate-lib/pym/cl_print.py b/build/lib/calculate-lib/pym/cl_print.py new file mode 100644 index 0000000..1298357 --- /dev/null +++ b/build/lib/calculate-lib/pym/cl_print.py @@ -0,0 +1,217 @@ +#-*- 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, struct, termios, fcntl +from cl_utils import _toUNICODE + +class color_print(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 = _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_string.py b/build/lib/calculate-lib/pym/cl_string.py new file mode 100644 index 0000000..757cbfb --- /dev/null +++ b/build/lib/calculate-lib/pym/cl_string.py @@ -0,0 +1,254 @@ +#-*- 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. + +from re import search, compile, S +from cl_utils import _toUNICODE + +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') diff --git a/build/lib/calculate-lib/pym/cl_template.py b/build/lib/calculate-lib/pym/cl_template.py new file mode 100644 index 0000000..68f0c0f --- /dev/null +++ b/build/lib/calculate-lib/pym/cl_template.py @@ -0,0 +1,3774 @@ +#-*- coding: utf-8 -*- + +# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os +import stat +import re +import xml.dom.minidom +from xml import xpath +import subprocess +import types +import random +import string +from cl_utils import _error, scan, _toUNICODE +from cl_overriding import exit +import cl_lang + +tr = cl_lang.lang() +tr.setLocalDomain('cl_lib') +tr.setLanguage(sys.modules[__name__]) + +class _terms(_error): + """Вычисление условий применяемых в шаблонах + + """ + def _convertVers(self, verA, verB): + """Конвертирование номеров версий для корректного сравнения + """ + elemA = verA.split(".") + elemB = verB.split(".") + if len(elemA) > len(elemB): + maxElemB = len(elemB)-1 + for i in range(len(elemA)): + if i > maxElemB: + elemB.append("0") + else: + maxElemA = len(elemA)-1 + for i in range(len(elemB)): + if i > maxElemA: + elemA.append("0") + for i in range(len(elemB)): + lenA = len(elemA[i]) + lenB = len(elemB[i]) + if lenA == lenB: + pass + elif lenA > lenB: + res = lenA - lenB + for z in range(res): + elemB[i] = "0" + elemB[i] + elif lenB > lenA: + res = lenB - lenA + for z in range(res): + elemA[i] = "0" + elemA[i] + return (".".join(elemA), ".".join(elemB)) + + def executeListEqual(self, listEqual): + """Вычисляет список выражений + + пример списка: + listEqual = [False, True, ' or ', True , True] + (если нет or между логическими выражениями то между ними and) + результат True + """ + lenOr = listEqual.count(" or ") + for i in xrange(lenOr): + ind = listEqual.index(' or ') + if False in listEqual[:ind]: + listEqual = listEqual[ind+1:] + continue + else: + return True + if False in listEqual: + return False + else: + return True + + + def _equalTerm(self, term, textError, function=False): + """Вычисление логических выражений для условий + + Для корректной работы в классе который наследует этот класс + должен быть объявлен аттрибут self.objVar + (объект для работы с переменными) + function - функция для для обработки функций в заголовке блока + """ + trm = {"&&":" and ","||":" or "} + rule = ["==", "!=", ">=", "<=", ">", "<"] + listEqual = [] + for k in trm.keys(): + if k in term: + term = term.replace(k,trm[k]) + trs = term.split(" ") + for t in trs: + flagRule = False + for sepF in rule: + if sepF in t: + flagRule = True + vals = t.split(sepF) + break + + if not flagRule: + flagLog = False + for k in trm.values(): + if k.strip() == t: + flagLog = True + break + if not flagLog: + self.setError("'%s'"%term + " " + _("incorrect")) + self.setError (textError) + return False + elif k == " or ": + listEqual.append(k) + else: + #проверка на допустимость названия переменной + reDenyName = re.compile("[^a-zA-Z0-9\_\-]") + flagFunction = False + if reDenyName.search(vals[0]): + #проверка на допустимость функции + flagError = True + if function: + reFunction = re.compile(\ + "([a-zA-Z0-9\_\-]+)\([a-zA-Z0-9_\-\+\,\*\/\.]+\)") + searchFunct = reFunction.search(vals[0]) + if searchFunct: + flagError = False + flagFunction = True + if flagError: + self.setError("'%s'"%term + " " + _("incorrect")) + self.setError(textError) + return False + #проверка на допустимость значения + reDenyValue = re.compile("[^0-9a-zA-Z_\.-]") + if reDenyValue.search(vals[1]): + self.setError("'%s'"%term + " " + _("incorrect")) + self.setError(textError) + return False + flagIntTypeVar = None + if flagFunction: + valVars = function("#-%s-#"%vals[0]) + if valVars == "": + flagFunction = False + if valVars == False: + self.setError("'%s'"%term + " " + _("incorrect")) + self.setError(textError) + return False + if "load" == searchFunct.group(1): + if re.search("\(\s*num\s*,",vals[0]): + if valVars: + try: + valVars = int(valVars) + except: + self.setError("'%s'"%term + " " + \ + _("incorrect")) + self.setError (textError) + return False + flagIntTypeVar = True + else: + flagIntTypeVar = False + else: + try: + valVars = self.objVar.Get(vals[0]) + except self.objVar.DataVarsError, e: + print textError + print e + exit(1) + # Cравниваем номера версий + if "_ver" in vals[0] or \ + (flagFunction and "pkg" == searchFunct.group(1)) or\ + (flagFunction and "load" == searchFunct.group(1) and\ + re.search("\(\s*ver\s*,",vals[0])): + verFile, verVar = self._convertVers(vals[1],valVars) + exec("res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")") + if res: + listEqual.append(True) + else: + listEqual.append(False) + else: + if flagIntTypeVar == None: + flagIntTypeVar = True + try: + valVars = int(valVars) + except: + flagIntTypeVar = False + if flagIntTypeVar: + if not vals[1].strip(): + vals[1] = 0 + try: + valFile = int(vals[1]) + except: + self.setError("'%s'"%term + " " + _("incorrect")) + self.setError (textError) + return False + valVar = valVars + exec("res=(%d%s%d)"%(valVar,sepF,valFile)) + if res: + listEqual.append(True) + else: + listEqual.append(False) + else: + if sepF == "!=" or sepF == "==": + if not vals[1].strip(): + vals[1] = "" + valFile = vals[1] + valVar = valVars + exec("res=("+'"""'+valVar+'"""'+sepF+"'"+valFile+\ + "'"+")") + if res: + listEqual.append(True) + else: + listEqual.append(False) + else: + if valVars == "": + listEqual.append(False) + else: + self.setError("'%s'"%term + " "\ + + _("incorrect")) + self.setError (textError) + return False + #exec("res=(%s)"%("".join(listEqual))) + res = self.executeListEqual(listEqual) + return res + + +class shareHeader: + """Общие методы для обработки заголовков""" + reSplParHeader = re.compile("\s+",re.I) + reHeader=re.compile(r"\A\s*#\s*calculate(\s+)?\\?([^\\\n]*\\\n)+[^\\\n]*\n?\ +|\s*#\s*calculate\s+([^\\\n]*\n?)",re.I|re.M) + + def getHeader(self, text): + """Получаем результат поиска и заголовок файла""" + sHeader = self.reHeader.search(text) + if sHeader: + return (sHeader, sHeader.group()) + else: + return (False, "") + + def getParamsHeader(self, textHeader): + """Получаем параметры заголовка в виде списка""" + listParams = self.reSplParHeader.split(textHeader.replace("\\"," ")) + if listParams[0] == "#": + return filter(lambda x: x, listParams[2:]) + else: + return filter(lambda x: x, listParams[1:]) + +class fileHeader(shareHeader, _terms): + """Обработка заголовков шаблонов и конфигурационных файлов + + """ + # Допустимые параметры заголовка + allowParam = ("format", "comment", "append", "force", "link", "mirror", + "symbolic", "chmod", "chown", "path", "name") + + # параметры без значения + listParNotVal = ("symbolic", "force", "mirror") + + # Возможные типы вставки шаблонов + _fileAppend = ("join", "before", "after", "replace", "remove", "skip") + + + # условные операторы + terms = ('>', '<', '==', '!=', '>=', '<=') + + # параметры без значения + #listParNotVal = ("symbolic", "force", "mirror") + # Форматы файлов для которых метод объединения replace если он не задан + #replaceFormats = ("raw","bin") + + def delHeaderConfFile(self, text, comment): + """Удаляет заголовок в тексте конфигурационного файла""" + if comment and text: + # Удаление Заголовка Calculate в конфигурационном файле + # В случае текста XML + if type(comment) == types.TupleType and len(comment) == 2: + _titleList = (_("Modified"), _("File of a template")) + reCalcHeader =\ + re.compile(u"\s*%s\s+%s.+Calculate.+\s+%s.+\s+%s\s?"%(\ + comment[0], + _titleList[0].decode("UTF-8"), + _titleList[1].decode("UTF-8"), + comment[1], + ), + re.M|re.I|re.U) + textUnicode = text.decode("UTF-8") + reS = reCalcHeader.search(textUnicode) + if reS: + textBody = textUnicode[:reS.start()]+textUnicode[reS.end():] + if textBody: + return textBody.encode("UTF-8") + else: + # В остальных случаях + reCalcHeader =\ + re.compile("\s*%s\-+\s+%s.+Calculate.+\s+%s.+\s+%s\-+\s?"%(\ + comment, + comment, + comment, + comment, + ), + re.M|re.I) + reS = reCalcHeader.search(text) + if reS: + return text[reS.end():] + return text + + def getPropertyTemplate(self, textHeader, foundHeader, fileType, objVar, + function, fileName): + """Получаем свойства шаблона из текста заголовка шаблона""" + # Объект с переменными + self.objVar=objVar + # Параметры файла шаблона + params = {} + # Будет ли шаблон применен + headerTerm = True + # Бинарный шаблон + if fileType=="bin": + params["format"] = fileType + params["_position"] = 0 + params["append"] = "replace" + params["_apply"] = headerTerm + # текстовый шаблон с заголовком + elif foundHeader: + # некорректные параметры + incorrectParams = set([]) + # Получаем список параметров шаблона + paramList = self.getParamsHeader(textHeader) + if paramList: + errTerm = _("header template '%s' not valid")%fileName + for i in paramList: + foundTerm = False + for term in self.terms: + if term in i: + foundTerm = True + rezTerm = self._equalTerm(i, "%s: %s"%(errTerm,i), + function) + if not rezTerm: + headerTerm = False + break + if not foundTerm: + par = i.split("=") + if len(par) == 1: + ret = self.checkParams(i, None, params) + if not ret: + incorrectParams = set([i]) + break + elif len(par) == 2: + ret = self.checkParams(par[0], par[1], params) + if not ret: + incorrectParams = set([i]) + break + if not "format" in params: + # format - raw + params["format"] = "raw" + if not "append" in params: + params["append"] = "replace" + else: + if not "append" in params: + # в зависимости от формата - join или replace + formatTemplate = params["format"] + if formatTemplate in ("raw", "bin", ""): + params["append"] = "replace" + else: + params["append"] = "join" + if incorrectParams: + headerTerm = False + self.setError(_("incorrect header parameters - '%s'")\ + %" ".join(list(incorrectParams))) + params["_position"] = foundHeader.end() + params["_apply"] = headerTerm + # текстовый шаблон без заголовка + else: + params["format"] = "raw" + params["_position"] = 0 + params["append"] = "replace" + params["_apply"] = headerTerm + return params + + def checkParams(self, name, value, dictPar): + """Проверка параметра заголовка, при успехе запись в словарь dictPar""" + # Проверка на допустимые параметры заголовка + if not name in self.allowParam: + return False + if name in self.listParNotVal and not value is None: + return False + if name == "append": + if not value in self._fileAppend: + return False + dictPar[name] = value + return True + + + +class dirHeader(shareHeader, _terms): + """Обработка заголовков шаблонов директорий + + """ + # Допустимые параметры заголовка + allowParam = ("append", "chmod", "chown", "path", "name") + # Возможные типы вставки шаблонов + _fileAppend = ("join", "remove", "skip") + # условные операторы + terms = ('>', '<', '==', '!=', '>=', '<=') + + + def getPropertyTemplate(self, text, objVar, function, fileName): + """Получаем свойства шаблона из текста шаблона""" + # Объект с переменными + self.objVar=objVar + # Параметры описанные в заголовке файла шаблона + params = {} + # Некорректные параметры + incorrectParams = set([]) + # Будет ли шаблон применен + headerTerm = True + foundHeader, textHeader = self.getHeader(text) + if foundHeader: + paramList = self.getParamsHeader(textHeader) + if paramList: + errTerm = _("header template '%s' not valid")%fileName + for i in paramList: + foundTerm = False + for term in self.terms: + if term in i: + foundTerm = True + rezTerm = self._equalTerm(i, "%s: %s"%(errTerm,i), + function) + if not rezTerm: + headerTerm = False + break + if not foundTerm: + par = i.split("=") + if len(par) == 1: + ret = self.checkParams(i, None, params) + if not ret: + incorrectParams = set([i]) + break + elif len(par) == 2: + ret = self.checkParams(par[0], par[1], params) + if not ret: + incorrectParams = set([i]) + break + if not "append" in params: + # По умолчанию join + params["append"] = "join" + if incorrectParams: + headerTerm = False + self.setError(_("incorrect header parameters - '%s'")\ + %" ".join(list(incorrectParams))) + params["_apply"] = headerTerm + # текстовый шаблон без заголовка + else: + headerTerm = False + self.setError(_("Can not found header in template")) + params["_apply"] = headerTerm + return params + + def checkParams(self, name, value, dictPar): + """Проверка параметра заголовка, при успехе запись в словарь dictPar""" + # Проверка на допустимые параметры заголовка + if not name in self.allowParam: + return False + if name == "append": + if not value in self._fileAppend: + return False + if value is None: + return False + dictPar[name] = value + return True + + +class objShare: + """Общий клас для объектов, наследуем + + """ + + def createFieldTerm(self, name, value, quote, docObj): + """Создание поля переменная - значение + + при создании поля проверяется первый символ названия переменной + и добавляется тег action + "!" - 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(_toUNICODE(text)) + element.appendChild(txtNode) + for attr in attributes.keys(): + attribute = doc.createAttribute(attr) + attribute.nodeValue = attributes[attr] + element.setAttributeNode(attribute) + return element + + +class xmlNode(xmlShare): + """Класс для создания нод без аттрибутов + + """ + def __init__(self): + self.node = False + + + def createNode(self, doc, tagName, text=""): + """Создает XML элемент без аттрибутов""" + self.node=self._createElement(doc, tagName, text) + return self.node + + def getNode(self): + return self.node + + +class xmlCaption: + """Класс XML заголовок + + """ + def __init__(self): + #Заголовок области XML нода + self.caption = False + + def createCaption(self, doc, name, quotes, action=False): + """Создание заголовка области""" + tmpNode = xmlNode() + self.caption = tmpNode.createNode(doc, "caption") + nameNode = tmpNode.createNode(doc, "name",name) + self.caption.appendChild(nameNode) + if action: + actNode = tmpNode.createNode(doc, "action", action) + self.caption.appendChild(actNode) + for q in quotes: + quoteNode = tmpNode.createNode(doc, "quote", q) + self.caption.appendChild(quoteNode) + return self.caption + + def getCaption(self): + """Выдает XML ноду заголовка области""" + return self.caption + +class xmlField(xmlShare): + """Класс для работы с XML полем + + """ + def __init__(self): + # XML нода поле + self.field = False + + + def createField(self, doc, typeField, quotes, name="", + values=[],action=False): + """Cоздание XML ноды поле""" + self.field = self._createElement(doc, "field", "", {"type":typeField}) + if name: + nameNode = self._createElement(doc, "name", name) + self.field.appendChild(nameNode) + for v in values: + valueNode = self._createElement(doc, "value", v) + self.field.appendChild(valueNode) + if action: + actNode = self._createElement(doc, "action", action) + self.field.appendChild(actNode) + for q in quotes: + quoteNode = self._createElement(doc, "quote", q) + self.field.appendChild(quoteNode) + return self.field + + + +class xmlFields: + """Класс, в котором находится список ХМL нод field + + """ + def __init__(self): + self.fields = [] + + def appendField(self, field): + """Добавить XML ноду field""" + self.fields.append(field) + return self.fields + + def getFields(self): + """Выдать список XML нод""" + return self.fields + + +class xmlArea: + """Класс для работы с XML областью + + """ + def __init__(self): + # Область + self.area = False + + def createArea(self, doc, xmlCaption, xmlFields): + """Создание XML области""" + tmpNode = xmlNode() + self.area = tmpNode.createNode(doc, "area") + if xmlCaption and xmlCaption.getCaption(): + self.area.appendChild(xmlCaption.getCaption()) + if xmlFields: + fields = xmlFields.getFields() + for field in fields: + self.area.appendChild(field) + return self.area + +class xmlDoc: + """Класс для работы с XML документом + + """ + def __init__(self): + # документ + self.doc = False + # главная нода + self.root = False + # тело документа + self.body = False + # Заголовок области - временный (в реальности один объект заголовок) + self.tmpCaption = False + # Поля - временные (в реальности один объект поля) + self.tmpFields = False + # Разделитель областей - по умолчанию перевод строки "\n" + self.sepAreas = False + # Разделитель разделенных списков - по умолчанию перевод строки "\n" + #self.sepSplitFields = False + + + def createDoc(self, typeDoc, version): + """Создание нового документа новый документ""" + docTxt = '' + 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 + i += 1 + if lenTail>1 and lenTail != i: + return (False,1) + if i > 0: + result = True + return (result, i) + + def encode(self, text): + """Кодирует смешанный формат в UTF-8""" + ind = 0 + l = 0 + utf = [] + lenUtf = [] + indErr = [] + i = 0 + for ch in text: + r, l = self._retUTF(ch) + utf.append(r) + lenUtf.append(l) + i+=1 + while 1: + if utf[ind] == '_fb_': + res, l = self._sumbUtf(utf[ind:(ind+lenUtf[ind])],lenUtf[ind]) + if res == False: + indErr.append(ind) + if l>0: + ind +=l + if ind >= len(utf): + break + else: + if utf[ind] != '_ch_': + indErr.append(ind) + ind +=1 + if ind >= len(utf): + break + if indErr: + lenIndErr = len(indErr) + block = [] + blocks = [] + if lenIndErr > 1: + i = 1 + while 1: + if i == 1: + block.append(indErr[i-1]) + if indErr[i] - indErr[i-1] == 1: + block.append(indErr[i]) + else: + if block: + blocks.append(block) + block = [] + block.append(indErr[i]) + i +=1 + if i >= lenIndErr: + break + else: + block.append(indErr[0]) + if block: + blocks.append(block) + listErr = [] + for block in blocks: + string = "" + for elem in block: + string += hex(ord(text[elem]))[-2:] + listErr.append((block[0],"__hex__?%s?__hex__" %string,elem)) + textOut = text + deltaInd = 0 + for erEl in listErr: + startInd = erEl[0] + deltaInd + endInd = erEl[2] + 1 + deltaInd + textOut = textOut[:startInd] + erEl[1] + textOut[endInd:] + deltaInd += len(erEl[1])-(erEl[2]-erEl[0]+1) + return textOut + + def decode(self, text): + """Декодирует UTF-8 в смешанный формат""" + varStart = "__hex__\?" + varEnd = "\?__hex__" + # -1 Это экранирование '?' которое тоже считается + deltVarStart = len(varStart)-1 + deltVarEnd = len(varEnd)-1 + reVar = re.compile(("%s[a-f0-9]+%s")%(varStart,varEnd),re.M) + resS = reVar.search(text) + textTemplateTmp = text + while resS: + mark = textTemplateTmp[resS.start():resS.end()] + hexString = mark[deltVarStart:-deltVarEnd] + i = 0 + stringInsert = "" + hexCode = "" + for ch in hexString: + if i>=1: + hexCode += ch + stringInsert += chr(int(hexCode, 16)) + hexCode = "" + i = 0 + else: + hexCode += ch + i += 1 + textTemplateTmp = textTemplateTmp.replace(mark, stringInsert) + resS = reVar.search(textTemplateTmp) + return textTemplateTmp + +class template(_file, _terms, xmlShare): + """Класс для работы с шаблонами + + На вход 2 параметра: объект хранения переменных, имя сервиса - не + обязательный параметр + + """ + # Импортированные классы поддерживаемых форматов шаблонов + importFormats = {} + # Имена установленных программ + installProg = [] + # Версии установленных программ + installProgVersions = [] + # кеш вызванных значений программа, номер версии + cacheInstallProg = {} + # Название файла шаблона директории + templDirNameFile = ".calculate_directory" + + def __init__(self, objVar, dirsFilter=[], filesFilter=[]): + # Необрабатываемые директории + self.dirsFilter = dirsFilter + # Необрабатываемые файлы + self.filesFilter = filesFilter + _file.__init__(self) + # Словарь для создания объектов новых классов по образцу + # (proftpd создается на основе apache) + self.newObjProt = {'proftpd':'apache'} + # Заголовок title + self.__titleHead = "--------------------------------------\ +----------------------------------------" + self._titleBody = "" + self._titleList = (_("Modified"), _("File of a template")) + + # Метки + varStart = "#-" + varEnd = "-#" + self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")%(varStart,varEnd),re.M) + self._reFunc = re.compile(("%s[a-zA-Z0-9_\-\+\(\)\, \*\/\.]+%s")\ + %(varStart,varEnd),re.M) + self._deltVarStart = len(varStart) + self._deltVarEnd = len(varEnd) + # Условия + self._reTermBloc = re.compile("#\?(?P[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 = "" + + def __octToInt(self, strOct): + """Преобразование восьмеричного в целое (ввод строка, вывод число)""" + if strOct: + z = 0 + i = 0 + lst = list(strOct) + lst.reverse() + for ch in lst: + try: + v = int(ch) + except: + self.setError(_("Not valid oct value: ") + str(strOct)) + return False + if v > 7: + self.setError (_("Not valid oct value: ") + str(strOct)) + return False + z = z + v*8**i + i = i +1 + return z + else: + self.setError (_("Empty oct value")) + return False + + def getFormatObj(self, formatTemplate, textTemplate): + """Создание объекта формата шаблона. + + Объект создается на основании формата шаблона и текста шаблона""" + if formatTemplate in self.importFormats: + classFormat = self.importFormats[formatTemplate] + else: + try: + classFormat = getattr(__import__("format.%s"%formatTemplate, + globals(), locals(), + [formatTemplate]), + formatTemplate) + except (ImportError, AttributeError): + #Создаем объект из self.newObjProt с помощью + # метаклассов + if formatTemplate in self.newObjProt: + # Прототип класса + nameProt = self.newObjProt[formatTemplate] + try: + classProt = getattr(__import__("format.%s"%nameProt, + globals(), locals(), + [nameProt]), + nameProt) + except (ImportError, AttributeError): + return False + newCl = self.createNewClass(formatTemplate, (classProt,)) + self.importFormats[formatTemplate] = newCl + return newCl(textTemplate) + else: + return False + self.importFormats[formatTemplate] = classFormat + return classFormat(textTemplate) + + def removeDir(self, rmDir): + """Рекурсивное удаление директории + + входной параметр директория + """ + if not os.path.exists(rmDir): + self.printERROR(_("Not found remove dir %s") %rmDir) + return False + fileObj = _file() + # Сканируем директорию + scanObjs = fileObj.scanDirs([rmDir]) + for socketRm in scanObjs[0].sockets: + # Удаляем сокеты + if os.path.exists(socketRm): + os.remove(socketRm) + for linkRm in scanObjs[0].links: + # Удаляем ссылки + os.unlink(linkRm[1]) + for fileRm in scanObjs[0].files: + # Удаляем файлы + os.remove(fileRm) + scanObjs[0].dirs.sort(lambda x, y: cmp(len(y), len(x))) + for dirRm in scanObjs[0].dirs: + # Удаляем директории + os.rmdir(dirRm) + if rmDir: + os.rmdir(rmDir) + return True + + + def createConfFile(self, pathTemplate, path=False): + """Создает конфигурационный файл если его нет""" + # Создаем директорию если ее нет + if not path: + path = os.path.split(pathTemplate)[0] + if not os.path.exists(path): + createDirs = self.createDir(path) + if not createDirs: + self.setError (_("Can not create file:" ) + pathTemplate) + return False + # Создаем файл если его нет + if not os.path.exists(pathTemplate): + try: + dMode, uid, gid = self.getModeFile(path) + #mode = dMode & ~0111 + # Создаем файл + open(pathTemplate,"w").close() + #os.chmod(pathTemplate, mode) + os.chown(pathTemplate, uid, gid) + except: + self.setError (_("Can not create file:" ) + pathTemplate) + return False + return True + + def createDir(self, dirName, mode=False, uid=False, gid=False): + """Создает директорию""" + if os.access(dirName, os.F_OK): + return [dirName] + else: + dMode = False + prevDir, tmpSubdir = os.path.split(dirName) + createDirs = [] + while not os.access(prevDir, os.F_OK): + createDirs.append(prevDir) + prevDir = os.path.split(prevDir)[0] + try: + tmpMode,dUid,dGid = self.getModeFile(prevDir) + except OSError: + self.setError (_("Not access dir: " ) + prevDir) + return False + if not mode is False: + dMode = mode + if not uid is False: + dUid = uid + if not gid is False: + dGid = gid + createDirs.reverse() + for nameDir in createDirs: + try: + if dMode: + os.mkdir(nameDir, dMode) + else: + os.mkdir(nameDir) + os.chown(nameDir, dUid, dGid) + except: + self.setError (_("Can not create dir: " ) + nameDir) + return False + try: + if dMode: + os.mkdir(dirName, dMode) + else: + os.mkdir(dirName) + os.chown(dirName, dUid, dGid) + createDirs.append(dirName) + except: + self.setError (_("Can not create dir: " ) + dirName) + return False + return createDirs + + + def applyVarsTemplate(self, textTemplate, nameTemplate): + """ Заменяет переменные на их значения + """ + resS = self._reVar.search(textTemplate) + textTemplateTmp = textTemplate + while resS: + mark = textTemplateTmp[resS.start():resS.end()] + varName = mark[self._deltVarStart:-self._deltVarEnd] + varValue = "" + try: + varValue = str(self.objVar.Get(varName)) + except self.objVar.DataVarsError, e: + print _("error in template %s")%nameTemplate + print e + exit(1) + textTemplateTmp = textTemplateTmp.replace(mark, varValue) + resS = self._reVar.search(textTemplateTmp) + return textTemplateTmp + + + def applyFuncTemplate(self, textTemplate, nameTemplate): + """ Применяет функции к тексту шаблона + """ + def equalTerm(term, sNum, sMD, localVars): + """Локальная функция для вычисления выражения""" + terms = sNum.findall(term) + if terms: + strNumers = [] + for n in terms: + strNum = n.strip() + if "*" in strNum or "/" in strNum: + strNum = multAndDiv(strNum,sNum,sMD,localVars) + try: + num = int(strNum) + except: + minus = False + if strNum[:1] == "-": + minus = True + strNum = strNum[1:] + if localVars.has_key(strNum): + num = localVars[strNum] + elif self.objVar.exists(strNum): + try: + num = int(self.objVar.Get(strNum)) + except: + print _("error in template %s")%nameTemplate + print _("error var %s not int")%str(strNum) + exit(1) + else: + print _("error in template %s")%nameTemplate + print _("error local var %s not defined")\ + %str(strNum) + exit(1) + if minus: + num =-num + strNumers.append(num) + return sum(strNumers) + print _("error in template %s")%nameTemplate + print _("error template term %s, incorrect data")%str(term) + exit(1) + + def multAndDiv(term,sNum,sMD,localVars): + """локальная функция для умножения и деления""" + termTmp = term + varsLocal = sMD.findall(term) + for var in varsLocal: + flagVarTxt = True + try: + int(var) + except: + flagVarTxt = False + if flagVarTxt: + continue + varReplace = str(equalTerm(var,sNum,sMD,localVars)) + termTmp = termTmp.replace(var,varReplace) + ret = eval(termTmp) + return ret + + def funcSum(funTxt,resS,localVars,textTemplateTmp): + """локальная функция вычисляет первую функцию sum() в шаблоне""" + terms = funTxt[4:-1].replace(" ","").split(",") + # Название локальной переменной + nameLocVar = terms[0] + if not localVars.has_key(nameLocVar): + localVars[nameLocVar] = 0 + if len(terms) == 2: + if terms[1].strip(): + localVars[nameLocVar] = equalTerm(terms[1],sNum,sMD, + localVars) + replace = str(localVars[nameLocVar]) + else: + replace = "" + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + elif len(terms) == 3: + if terms[1].strip(): + replaceInt = equalTerm(terms[1],sNum,sMD,localVars) + replace = str(replaceInt) + else: + replace = "" + localVars[nameLocVar] = equalTerm(terms[2], + sNum,sMD,localVars) + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + else: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + exit(1) + return textTemplateTmp + + def funcLoad(funTxt,resS,textTemplateTmp): + """если файл существует читает из файла локальную переменную + + если один параметр - выводит значение локальной переменной + """ + terms = funTxt[5:-1].replace(" ","").split(",") + if not terms[0].strip() or\ + (len(terms)==2 and not terms[1].strip()) or\ + len(terms)>2: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + exit(1) + if len(terms) == 2: + if not terms[0] in ["ver","num","char","key"]: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + print _("first argument function is not 'ver' or 'num' or\ + 'char'") + exit(1) + if len(terms) == 1: + fileName = terms[0].strip() + if fileName[0] != "/": + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + print _("incorrect path %s")%fileName + exit(1) + else: + fileName = terms[1].strip() + if fileName[0] != "/": + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + print _("incorrect path %s")%fileName + exit(1) + replace = "" + if os.path.exists(fileName): + FD = open(fileName) + replace = FD.read().strip() + FD.close + if not replace and len(terms) == 2 and terms[0] in ["ver","num"]: + replace = "0" + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + return textTemplateTmp + + def getInstallPkgGentoo(names = [], versions = []): + """Выдает два списка, инсталлированные программы и номера версий""" + baseDir = "/var/db/pkg" + pkgs = [] + reVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*") + def getFilesDir(pkgs, dirname, names): + for nameFile in names: + absNameFile = os.path.join(dirname,nameFile) + if os.path.isdir(absNameFile): + tail = absNameFile.split(baseDir) + if len(tail)==2: + tail = tail[1].split('/') + if len(tail)==3 and tail[1]!='virtual': + pkgs.append(tail[2]) + return True + os.path.walk(baseDir,getFilesDir, pkgs) + pkgs.sort() + for pkg in pkgs: + findVer = reVer.search(pkg) + if findVer: + ver = findVer.group() + versions.append(ver) + names.append(pkg.split(ver)[0][:-1]) + #return pkgs + return names, versions + + def pkg(nameProg, names, versions): + """Выдает установленные версии по имени программы""" + # Значение версии из кеша + if nameProg in self.cacheInstallProg: + return self.cacheInstallProg[nameProg] + i = 0 + vers = [] + for name in names: + if nameProg == name: + while nameProg == names[i]: + vers.append(versions[i]) + i += 1 + break + i += 1 + if vers: + version = vers[-1] + # Запись значения версии в кеш + self.cacheInstallProg[nameProg] = version + return version + else: + return "" + + def funcPkg(funTxt,resS,textTemplateTmp): + """локальная функция выдает номер версии программы""" + terms = funTxt[4:-1].replace(" ","") + # Название программы + nameProg = terms + if not self.installProg: + # Получение всех названий и версий установленных программ + self.installProg,self.installProgVersions =\ + getInstallPkgGentoo(names=self.installProg, + versions=self.installProgVersions) + replace = pkg(nameProg,self.installProg,self.installProgVersions) + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + return textTemplateTmp + + def funcRnd(funTxt,resS,textTemplateTmp): + """локальная функция выдает строку случайных символов + + первый аргумент: + 'num' - числа, + 'pas' - цифры и буквы + второй аргумент: + количество символов + """ + terms = funTxt[4:-1].replace(" ","").split(",") + if not terms[0].strip() or\ + (len(terms)==2 and not terms[1].strip()) or\ + len(terms)!=2: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + exit(1) + fArgvNames = ['num','pas'] + if not terms[0] in fArgvNames: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + print _("first argument function is not 'num' or 'pas'") + exit(1) + try: + lenStr = int(terms[1]) + except: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + print _("two argument function is not number") + exit(1) + if terms[0] == fArgvNames[0]: + replace=''.join([random.choice(string.digits)\ + for i in xrange(lenStr)]) + elif terms[0] == fArgvNames[1]: + replace=''.join([random.choice(string.ascii_letters + \ + string.digits) for i in xrange(lenStr)]) + else: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + exit(1) + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + return textTemplateTmp + + def funcCase(funTxt,resS,textTemplateTmp): + """локальная функция выдает переменную в определенном регистре + + первый аргумент: + 'upper' - верхний регистр, + 'lower' - нижний регистр, + 'capitalize' - первая буква в верхнем регистре + второй аргумент: + название переменной + """ + terms = funTxt[5:-1].replace(" ","").split(",") + if not terms[0].strip() or\ + (len(terms)==2 and not terms[1].strip()) or len(terms)!=2: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + exit(1) + fArgvNames = ['upper','lower','capitalize'] + if not terms[0] in fArgvNames: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + print _("first argument function is not 'upper' or 'lower' or\ + 'capitalize'") + exit(1) + try: + strValue = str(self.objVar.Get(terms[1])) + except: + print _("error in template %s")%nameTemplate + print _("error var %s not found")%str(terms[1]) + exit(1) + replace = "" + strValue = _toUNICODE(strValue) + if terms[0] == 'upper': + replace = strValue.upper() + elif terms[0] == 'lower': + replace = strValue.lower() + elif terms[0] == 'capitalize': + replace = strValue.capitalize() + if replace: + replace = replace.encode("UTF-8") + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + return textTemplateTmp + + # Локальные переменные + localVars = {} + # Регулярное выражние для сложения + sNum = re.compile("\-[^\-\+]+|[^\-\+]+") + # Регулярное выражение для умножениея и деления + sMD = re.compile("[^\-\+\*\/]+") + resS = self._reFunc.search(textTemplate) + textTemplateTmp = textTemplate + while resS: + mark = textTemplateTmp[resS.start():resS.end()] + funTxt = mark[self._deltVarStart:-self._deltVarEnd] + # Функция sum + if funTxt[:4] == "sum(": + textTemplateTmp = funcSum(funTxt,resS,localVars,textTemplateTmp) + resS = self._reFunc.search(textTemplateTmp) + # Функция load + elif funTxt[:5] == "load(": + textTemplateTmp = funcLoad(funTxt,resS,textTemplateTmp) + resS = self._reFunc.search(textTemplateTmp) + elif funTxt[:4] == "pkg(": + textTemplateTmp = funcPkg(funTxt,resS,textTemplateTmp) + resS = self._reFunc.search(textTemplateTmp) + elif funTxt[:4] == "rnd(": + textTemplateTmp = funcRnd(funTxt,resS,textTemplateTmp) + resS = self._reFunc.search(textTemplateTmp) + elif funTxt[:5] == "case(": + textTemplateTmp = funcCase(funTxt,resS,textTemplateTmp) + resS = self._reFunc.search(textTemplateTmp) + else: + resS = False + return textTemplateTmp + + def applyTermsTemplate(self,textTemplate,nameTemplate,nameSystemFile=False): + """ Применяет условия, к условным блокам текста + """ + textTerm = "" + resS = self._reTermBloc.search(textTemplate) + textTemplateTmp = textTemplate + def function(text): + """Функция обработки функций в заголовке""" + return self.applyFuncTemplate(text, nameTemplate) + if nameSystemFile: + while resS: + mark = resS.group(0) + body = resS.group("body") + end = resS.group("end") + parent = resS.group("func") + if not parent: + parent = "" + term = resS.group("rTerm") + parent +\ + resS.group("lTerm") + if self._equalTerm(term, _("content template not valid: ")+\ + nameTemplate, function): + textTemplateTmp = textTemplateTmp.replace(mark, body+end) + else: + textTemplateTmp = textTemplateTmp.replace(mark, "") + resS = self._reTermBloc.search(textTemplateTmp) + else: + while resS: + mark = resS.group(0) + body = resS.group("body") + end = resS.group("end") + term = resS.group("rTerm") + resS.group("lTerm") + if self._equalTerm(term, _("content template not valid: ")+\ + nameTemplate): + textTemplateTmp = textTemplateTmp.replace(mark, body+end) + else: + textTemplateTmp = textTemplateTmp.replace(mark, "") + resS = self._reTermBloc.search(textTemplateTmp) + return textTemplateTmp + + def getTitle(self, comment, commentList): + """Выдает заголовок шаблона ( версия и.т.д)""" + if comment: + commentFirst = comment + commentInsert = comment + commentLast = comment + flagList = False + # В случае открывающего и закрывающего комментария + if type(comment) == types.TupleType and len(comment) == 2: + commentFirst = comment[0] + commentInsert = "" + commentLast = comment[1] + flagList = True + if flagList: + self._titleBody = commentFirst + "\n" + else: + self._titleBody = commentFirst + self.__titleHead + "\n" + z = 0 + lenCommentList = len(commentList) - 1 + for com in self._titleList: + if lenCommentList < z: + self._titleBody += commentInsert + " " + com + "\n" + else: + self._titleBody += commentInsert + " " + com +\ + " " + commentList[z] + "\n" + z += 1 + if flagList: + self._titleBody += commentLast +"\n" + else: + self._titleBody += commentLast + self.__titleHead + "\n" + return self._titleBody + else: + return "" + + def numberAllTemplates(self, number): + """Количество шаблонов + + Вызов происходит перед наложением шаблонов + в момент вызова в number находится количество обрабатываемых файлов + Наследуемая функция + Используется для отображения прогресса при наложениии шаблонов + """ + return True + + def numberProcessTemplates(self, number): + """Номер текущего обрабатываемого шаблона + + Вызов происходит при наложении шаблона + в момент вызова в number находится номер обрабатываемого шаблона + Наследуемая функция + Используется для отображения прогресса при наложениии шаблонов + """ + return True + + def __clearInErrorDirObj(self, dirObj): + """Очищает объект директории при ошибке""" + # директории [(путь к директории, свойства директории)...] + dirObj.dirs = [] + # файлы [(путь к файлу, свойства файла)...] + dirObj.files = [] + # Ошибка + dirObj.flagError = True + return dirObj + + def __scanDir(self, templatesDir, dirObj, dirProperties=()): + """Измененное cканирование одной директории""" + # сканирование файлов и директорий (следующие сканирования) + if dirProperties: + # Выход при ошибке + if dirObj.flagError: + return dirObj + dirName, prop = dirProperties + # В случае удаления не смотрим внутренние директории + if "append" in prop and prop["append"] == "remove": + return dirObj + filesOrDirs = os.listdir(dirName) + # Сортируем файлы и директории + filesOrDirs.sort() + # Добавляем директорию и ее свойства + dirObj.dirs.append((dirName, prop)) + if self.templDirNameFile in filesOrDirs: + # Удаляем файл описания директории из списка файлов + filesOrDirs.remove(self.templDirNameFile) + for fileOrDir in filesOrDirs: + # Выход при ошибке + if dirObj.flagError: + return dirObj + absPath = os.path.join(dirName,fileOrDir) + statInfo = os.stat(absPath)[stat.ST_MODE] + if stat.S_ISREG(statInfo): + # Свойства файла + propF, applyFile=self.__isApplyHeadTemplate(dirObj.fHeadObj, + absPath) + if self.getError(): + self.setError(_("Incorrect template: " ) + absPath) + return self.__clearInErrorDirObj(dirObj) + if not applyFile: + continue + # Обработка skip + if "append" in propF and propF["append"] == "skip": + continue + if not "path" in propF: + propF["path"] = prop["_real_path"] + if not "name" in propF: + propF["name"] = os.path.split(absPath)[1] + propF["_real_path"] = os.path.join(propF["path"], + propF["name"]) + dirObj.files.append((absPath, propF)) + elif stat.S_ISDIR(statInfo): + # Информация о директории + pDir = {} + # Файл информации о директории + dirInfoFile = os.path.join(absPath, + self.templDirNameFile) + if os.path.exists(dirInfoFile) and\ + stat.S_ISREG(os.stat(dirInfoFile)[stat.ST_MODE]): + # Настройки директории и применение + pDir, applyDir = self.__isApplyHeadDir(dirObj.dHeadObj, + dirInfoFile) + if self.getError(): + self.setError(_("Incorrect template: " ) +\ + dirInfoFile) + return self.__clearInErrorDirObj(dirObj) + if not applyDir: + continue + if not "path" in pDir: + pDir["path"] = prop["_real_path"] + if not "name" in pDir: + pDir["name"] = os.path.split(absPath)[1] + # Обработка skip + if "append" in pDir and pDir["append"] == "skip": + pDir["_real_path"] = pDir["path"] + else: + pDir["_real_path"] = os.path.join(pDir["path"], + pDir["name"]) + self.__scanDir(False, dirObj, (absPath, pDir)) + return dirObj + # Сканирование для получения настроек директории (первое) + else: + if templatesDir and stat.S_ISDIR(os.stat(templatesDir)[stat.ST_MODE]): + # настройки директории + pDir = {} + # Файл информации о директории + dirInfoFile = os.path.join(templatesDir, self.templDirNameFile) + if os.path.exists(dirInfoFile) and\ + stat.S_ISREG(os.stat(dirInfoFile)[stat.ST_MODE]): + # Настройки директории и применение + pDir,applyDir = self.__isApplyHeadDir(dirObj.dHeadObj, + dirInfoFile) + if self.getError(): + self.setError(_("Incorrect template: " ) +\ + dirInfoFile) + return self.__clearInErrorDirObj(dirObj) + if not applyDir: + return dirObj + if not "path" in pDir: + pDir["path"] = "/" + if not "name" in pDir: + pDir["name"] = os.path.split(templatesDir)[1] + # Обработка skip + if "append" in pDir and pDir["append"] == "skip": + pDir["_real_path"] = pDir["path"] + else: + pDir["_real_path"] = os.path.join(pDir["path"], + pDir["name"]) + self.__scanDir(False, dirObj, (templatesDir, pDir)) + return dirObj + + + def scanDirs(self, templatesDirs, objVar): + """Измененное cканирование директорий на вход список + + Выход список объктов _dir + """ + dirs = [] + # Объект заголовка файла + fHeadObj = fileHeader() + # Объект заголовка директории + dHeadObj = dirHeader() + # Объект переменных + for templateDir in templatesDirs: + dirP = scan._dir() + dirP.baseDir = templateDir + # Ошибка при сканировании + dirP.flagError = False + # Объект заголовка файла + dirP.fHeadObj = fHeadObj + # Объект заголовка директории + dirP.dHeadObj = dHeadObj + # Объект переменных + dirP.objVar = objVar + try: + self.__scanDir(templateDir, dirP) + except OSError, e: + print e.strerror, e.filename + self.__clearInErrorDirObj(dirP) + return [dirP] + if dirP.flagError: + return [dirP] + dirs.append(dirP) + return dirs + + def applyTemplates(self): + """Применяет шаблоны к конфигурационным файлам""" + if not self.objVar.defined("cl_template_path"): + self.setError (_("not defined Var: ") + "cl_template_path") + return False + dirsTemplates = self.objVar.Get("cl_template_path") + dirsTemplates.sort() + dirObjs = self.scanDirs(dirsTemplates,self.objVar) + #файлы к которым были применены шаблоны + filesApply = [] + #созданные директории + createdDirs = [] + # Получаем общее количество шаблонов (нужно для прогресбара) + allApplyFiles = self.scanTemplates(dirObjs) + if allApplyFiles == False: + return False + numberAllTemplates = len(allApplyFiles) + # Вызываем пустой метод с параметром общее количество шаблонов + self.numberAllTemplates(numberAllTemplates) + # номер обрабатываемого файла + numberProcessTemplates = 0 + # имя текущей программы + _nameProgram = self.objVar.Get("cl_name").capitalize() + # версия текущей программы + _versionProgram = self.objVar.Get("cl_ver") + # имя и версия текущей программы + programVersion = "%s %s"%(_nameProgram, _versionProgram) + # Объект обработки заголовков файлов шаблонов + fileHeadObj = fileHeader() + # Проверка на ошибки + for dirObj in dirObjs: + if dirObj.flagError: + return False + for dirObj in dirObjs: + # сортируем файлы по названию + if dirObj.files: + dirObj.files.sort() + # сортируем директории по названию + if dirObj.dirs: + dirObj.dirs.sort() + blockDirs = [] + propDir = {} + for dirTemplate, pDirs in dirObj.dirs: + # Получаем реальный путь директории + pathDir = pDirs["_real_path"] + # Фильтрация шаблонов по названию директории + if pathDir in self.dirsFilter: + blockDirs.append(dirTemplate) + continue + dirInfoFile = os.path.join(dirTemplate, self.templDirNameFile) + pathDir, propDir, crDirs = self.__getApplyHeadDir(pDirs) + if not propDir and self.getError(): + self.setError(_("Error in apply template: " ) +\ + dirInfoFile) + return False + if crDirs: + createdDirs += crDirs + for fileTemplate, propFile in dirObj.files: + findBlock = False + pathFile = propFile["_real_path"] + for blDir in blockDirs: + st,mid,end = pathFile.partition(blDir) + if (not st) and mid and end: + findBlock = True + break + if findBlock: + continue + numberProcessTemplates += 1 + self.numberProcessTemplates(numberProcessTemplates) + # Фильтрация шаблонов по названию файла + if pathFile in self.filesFilter: + continue + titleBaseDir = os.path.split(dirObj.baseDir)[0] + titlePath = fileTemplate.partition(titleBaseDir)[2] + templTitle = '"' + titlePath[1:] + '"' + # Записываем в переменную обрабатываемый файл + self.objVar.Set("cl_pass_file",pathFile) + filesApl = self.join(fileTemplate, propFile, + (programVersion,templTitle), fileHeadObj) + if filesApl: + filesApply += filesApl + else: + if self.getError(): + #print self.getError() + return False + self.closeFiles() + return (createdDirs, filesApply) + + def scanTemplates(self, dirObjs=False): + """Сканирует директории шаблонов - выводит список файлов""" + if not self.objVar.defined("cl_template_path"): + self.setError (_("not defined Var: ") + "cl_template_path") + return False + if not dirObjs: + dirsTemplates = self.objVar.Get("cl_template_path") + dirObjs = self.scanDirs(dirsTemplates, self.objVar) + #файлы к которым были применены шаблоны + filesApply = [] + # Проверка на ошибки + for dirObj in dirObjs: + if dirObj.flagError: + return False + for dirObj in dirObjs: + # сортируем файлы по названию + if dirObj.files: + dirObj.files.sort() + # сортируем директории по названию + if dirObj.dirs: + dirObj.dirs.sort() + blockDirs = [] + for dirTemplate, pDirs in dirObj.dirs: + pathDir = pDirs["_real_path"] + # Фильтрация шаблонов по названию директории + if pathDir in self.dirsFilter: + blockDirs.append(dirTemplate) + continue + for fileTemplate, propFile in dirObj.files: + findBlock = False + pathFile = propFile["_real_path"] + # Фильтрация файлов по названию директории + for blDir in blockDirs: + st,mid,end = pathFile.partition(blDir) + if (not st) and mid and end: + findBlock = True + break + if findBlock: + continue + # Фильтрация шаблонов по названию файла + if pathFile in self.filesFilter: + continue + filesApply.append(pathFile) + return filesApply + + + def __isApplyHeadDir(self, headerObj, templateDirFile): + """Будет ли применен шаблон корневой директории + + Возвращает: + (Настройки директории, и будет ли она применена (True, False)) + """ + # Настройки для директории + dPrefs = {} + + def function(text): + """Функция обработки функций в заголовке""" + return self.applyFuncTemplate(text, templateDirFile) + + if not os.path.exists(templateDirFile): + return (dPrefs, True) + try: + FD = open(templateDirFile) + textTemplate = FD.read() + FD.close() + except: + self.setError(_("Error open template: " ) + templateDirFile) + return (dPrefs, False) + # Заменяем переменные на их значения + textTemplate = self.applyVarsTemplate(textTemplate, templateDirFile) + # Обработка заголовка + propDir = headerObj.getPropertyTemplate(textTemplate,self.objVar, + function, templateDirFile) + if not propDir["_apply"]: + if headerObj.getError(): + self.setError(_("Incorrect template: " ) + templateDirFile) + return (dPrefs, False) + # Записываем настройки + dPrefs.update(propDir) + # Тип добавления + if dPrefs['append'] == "remove": + # Удаление конфигурационного файла + return (dPrefs, False) + # chmod - изменяем права + if "chmod" in dPrefs: + mode = self.__octToInt(dPrefs["chmod"]) + if mode: + dPrefs["chmod"] = mode + else: + self.setError (_("False value 'chmod' in template: " ) +\ + templateDirFile) + return (dPrefs, False) + # chown - изменяем владельца и группу + if "chown" in dPrefs: + owner = dPrefs["chown"] + uid = False + gid = False + if ":" in owner: + strUid, strGid = owner.split(":") + import pwd + try: + uid = pwd.getpwnam(strUid)[2] + except: + self.setError (_("Not user in this system: ") + strUid) + self.setError (_("False value 'chown' in template: " )+\ + templateDirFile) + return (dPrefs, False) + try: + import grp + gid = grp.getgrnam(strGid)[2] + except: + self.setError (_("Not group in this system: ")+strGid) + self.setError (_("False value 'chown' in template: " )+\ + templateDirFile) + return (dPrefs, False) + dPrefs["chown"] = [uid, gid] + else: + self.setError (_("False value 'chown' in template: " ) +\ + templateDirFile) + return (dPrefs, False) + # Проверяем path + if "path" in dPrefs and\ + (not dPrefs["path"] or not dPrefs["path"][0] == "/"): + self.setError (_("False value 'path' in template: " )+\ + templateDirFile) + return (dPrefs, False) + # Проверяем name + if "name" in dPrefs and\ + (dPrefs["name"] and dPrefs["name"][0] == "/"): + self.setError (_("False value 'name' in template: " )+\ + templateDirFile) + return (dPrefs, False) + return (dPrefs, True) + + def __getApplyHeadDir(self, dictPropDir): + """Применяет шаблон к директории (права, владелец, и.т. д)""" + newDirMv = dictPropDir["_real_path"] + applyDir = newDirMv + # Созданные директории + createDirs = [] + + if "append" in dictPropDir: + if dictPropDir["append"]=="skip": + return (applyDir, dictPropDir, createDirs) + # Удаляем директорию + elif dictPropDir["append"]=="remove": + if os.path.isdir(newDirMv): + # удаляем директорию + try: + self.removeDir(newDirMv) + except: + self.setError(_("Can not delete dir: " ) +\ + newDirMv) + return (applyDir, False, createDirs) + + # Флаг проверки существования директории + flagFoundDir = os.path.exists(newDirMv) + mode = False + uid = False + gid = False + # chmod - изменяем права + if "chmod" in dictPropDir: + mode = dictPropDir['chmod'] + if flagFoundDir: + os.chmod(newDirMv, mode) + # chown - изменяем владельца и группу + if "chown" in dictPropDir: + uid, gid = dictPropDir['chown'] + if flagFoundDir: + os.chown(newDirMv, uid, gid) + if not flagFoundDir: + createDirs = self.createDir(newDirMv, mode, uid, gid) + if not createDirs: + return (applyDir, False, createDirs) + return (applyDir, dictPropDir, createDirs) + + + def __isApplyHeadTemplate(self, headerObj, templateName): + """Будет ли применен файл шаблона + + Возвращает: + (Настройки файла, и будет ли он применен (True, False)) + """ + # Настройки для файла + fPrefs = {} + def function(text): + """Функция обработки функций в заголовке""" + return self.applyFuncTemplate(text, templateName) + + if not os.path.exists(templateName): + return (fPrefs, True) + try: + FD = open(templateName) + textTemplate = FD.read() + FD.close() + except: + self.setError(_("Error open template: " ) + templateName) + return (fPrefs, False) + # Бинарный или текстовый файл шаблона + templateType = self.getFileType(templateName) + foundHeader = False + textHeader = "" + if templateType != "bin": + # Получаем заголовок файла шаблона + foundHeader, textHeader = headerObj.getHeader(textTemplate) + # Заменяем переменные на их значения + textHeader = self.applyVarsTemplate(textHeader, templateName) + propFile = headerObj.getPropertyTemplate(textHeader, foundHeader, + templateType, self.objVar, + function,templateName) + if not propFile["_apply"]: + if headerObj.getError(): + self.setError(_("Incorrect template: " ) + templateName) + return (fPrefs, False) + if propFile["append"] == "remove": + # Удаление конфигурационного файла + return (propFile, False) + # Записываем настройки + fPrefs.update(propFile) + # chmod - изменяем права + if "chmod" in fPrefs: + mode = self.__octToInt(fPrefs["chmod"]) + if mode: + fPrefs["chmod"] = mode + else: + self.setError (_("False value 'chmod' in template: " ) +\ + templateName) + return (fPrefs, False) + # chown - изменяем владельца и группу + if "chown" in fPrefs: + owner = fPrefs["chown"] + uid = False + gid = False + if ":" in owner: + strUid, strGid = owner.split(":") + import pwd + try: + uid = pwd.getpwnam(strUid)[2] + except: + self.setError (_("Not user in this system: ") + strUid) + self.setError (_("False value 'chown' in template: " )+\ + templateName) + return (fPrefs, False) + try: + import grp + gid = grp.getgrnam(strGid)[2] + except: + self.setError (_("Not group in this system: ")+strGid) + self.setError (_("False value 'chown' in template: " )+\ + templateName) + return (fPrefs, False) + fPrefs["chown"] = [uid, gid] + else: + self.setError (_("False value 'chown' in template: " ) +\ + templateName) + return (fPrefs, False) + # Проверяем path + if "path" in fPrefs and\ + (not fPrefs["path"] or not fPrefs["path"][0] == "/"): + self.setError (_("False value 'path' in template: " )+\ + templateDirFile) + return (fPrefs, False) + # Проверяем name + if "name" in fPrefs and\ + (not fPrefs["name"] or fPrefs["name"][0] == "/"): + self.setError (_("False value 'name' in template: " )+\ + templateDirFile) + return (fPrefs, False) + return (fPrefs, True) + + def __getApplyHeadTemplate(self, newFile, dictPropFile): + """Применяет заголовок к шаблону (права, владелец, и.т. д)""" + # Конфигурационный файл в системе + pathOldFile = dictPropFile["_real_path"] + # Директория в которой находится шаблон + newDir = dictPropFile["path"] + # Файлы в системе к которым были применены шаблоны + applyFiles = [pathOldFile] + pathProg = "" + # В случае force + if "force" in dictPropFile: + if os.path.islink(pathOldFile): + # удаляем ссылку + try: + os.unlink(pathOldFile) + except: + self.setError(_("Can not delete link: " ) +\ + pathOldFile) + return (applyFiles, False) + if os.path.isfile(pathOldFile): + # удаляем файл + try: + os.remove(pathOldFile) + except: + self.setError(_("Can not delete file: " ) +\ + pathOldFile) + return (applyFiles, False) + + # Удаляем оригинальный файл + if dictPropFile["append"] == "remove": + if os.path.islink(pathOldFile): + # удаляем ссылку + try: + os.unlink(pathOldFile) + except: + self.setError(_("Can not delete link: " ) +\ + pathOldFile) + if os.path.isfile(pathOldFile): + # удаляем файл + try: + os.remove(pathOldFile) + except: + self.setError(_("Can not delete file: " ) +\ + pathOldFile) + return (applyFiles, False) + + flagSymlink = False + flagForce = False + # Если есть параметр mirror + if "mirror" in dictPropFile: + if "link" in dictPropFile: + templateFile = dictPropFile['link'] + if not os.path.exists(templateFile): + if os.path.exists(pathOldFile): + os.remove(pathOldFile) + return (applyFiles, False) + elif not os.path.exists(pathOldFile): + return (applyFiles, False) + + # Если есть указатель на файл шаблона (link) + if "link" in dictPropFile and\ + not "symbolic" in dictPropFile: + templateFile = dictPropFile['link'] + foundTemplateFile = os.path.exists(templateFile) + if foundTemplateFile: + FO = self.openNewFile(templateFile) + buff = FO.read() + FO.close() + if os.path.exists(pathOldFile): + os.remove(pathOldFile) + if foundTemplateFile: + if not self.createConfFile(pathOldFile, newDir): + return (applyFiles, False) + FON = open (pathOldFile, "r+") + FON.write(buff) + FON.close() + + # Если символическая ссылка + if "symbolic" in dictPropFile: + prevOldFile = pathOldFile + if "link" in dictPropFile: + pathOldFile = dictPropFile['link'] + flagSymlink = True + if not "/" == pathOldFile[0]: + pathLink = os.path.split(os.path.abspath(prevOldFile))[0] + pathProg = os.getcwd() + os.chdir(pathLink) + + # Флаг - создан конфигурационный файл + flagCreateFile = False + # chmod - изменяем права + if "chmod" in dictPropFile: + mode = dictPropFile['chmod'] + if not os.path.exists(pathOldFile): + if not self.createConfFile(pathOldFile, newDir): + return (applyFiles, False) + flagCreateFile = True + os.chmod(pathOldFile, mode) + + # chown - изменяем владельца и группу + if "chown" in dictPropFile: + uid, gid = dictPropFile['chown'] + if not flagCreateFile and not os.path.exists(pathOldFile): + if not self.createConfFile(pathOldFile, newDir): + return (applyFiles, False) + os.chown(pathOldFile, uid, gid) + + if flagSymlink: + if os.path.exists(prevOldFile) or os.path.islink(prevOldFile): + if os.path.islink(prevOldFile): + # если ссылка то удаляем её + os.unlink(prevOldFile) + else: + # иначе удаляем файл + os.remove(prevOldFile) + if not "/" == pathOldFile[0]: + os.symlink(pathOldFile, prevOldFile) + applyFiles = [prevOldFile,os.path.join(pathLink,pathOldFile)] + else: + os.symlink(pathOldFile, prevOldFile) + applyFiles = [prevOldFile,pathOldFile] + removeLink = not flagSymlink + # Создаем конфигурационный файл если он отсутствует + # открываем файл шаблона и конфигурационный файл + # указатель начала файла шаблона указыввает на текст после заголовка + # файла + if not self.openFiles(newFile, pathOldFile, self.createConfFile, + dictPropFile["_position"], removeLink): + return (applyFiles, False) + if pathProg: + os.chdir(pathProg) + # Если файлы заменяются не нужно их обрабатывать дальше + if "replace" in dictPropFile and\ + not "symbolic" in dictPropFile and\ + "link" in dictPropFile: + return (applyFiles, False) + return (applyFiles, dictPropFile) + + def createNewClass(self, name, bases, attrs={}): + """Создает объект нового класса + + createNewClass(self, name, bases, attrs) + name - имя класса - str, + bases - cписок наследуемых классов - (tuple), + attrs - аттрибуты класса - {dict} + """ + class newMethod: + #Объединяем конфигурации + def join(self, newObj): + if newObj.__class__.__name__ == self.__class__.__name__: + self.docObj.joinDoc(newObj.doc) + # Пост обработка + if 'postXML' in dir(self): + self.postXML() + attrsNew = {} + attrsNew["configName"] = name + if attrs: + for key in attrs.keys(): + attrsNew[key] = attrs[key] + newCl = type(name, bases + (newMethod, object), attrsNew) + return newCl + + def textIsUtf8(self, text): + """Проверяет текст на кодировку UTF-8""" + try: + text.decode("UTF-8") + except: + return False + return True + + def setTemplateRules(self, templateProp, textTemplate, templFile, confFile): + """Устанавливаем значения переменных, условий, функций для текста""" + # Вычисляем условные блоки + textTemplate = self.applyTermsTemplate(textTemplate, + templFile, confFile) + # Заменяем переменные на их значения + textTemplate = self.applyVarsTemplate(textTemplate, + templFile) + # Вычисляем функции + textTemplate = self.applyFuncTemplate(textTemplate, templFile) + return textTemplate + + def join(self, newFile, propFile, ListOptTitle, fileHeadObj): + """Объединения шаблона и конф. файла + + join(newFile, oldFile, ListOptTitle) + Объединение шаблона newFile и конф. файла oldFile, + propFile - словарь свойств конфигурационного файла + ListOptTitle - список строк которые добавятся в заголовок + """ + # Применяем свойства к конфигурационному файлу + # Открываем файл шаблона и конфигурационный файл + + # В случае type=print (печатаем содержимое шаблона) + flagPrintTemplate = False + filesApply, templateProp = self.__getApplyHeadTemplate(newFile,propFile) + if not templateProp: + if self.getError(): + return [] + return filesApply + # Путь к конфигурационному файлу + oldFile = templateProp["_real_path"] + # Формат шаблона + formatTemplate = templateProp["format"] + # Тип объединение шаблона + appendTemplate = templateProp["append"] + if formatTemplate != "bin": + # Применение условий, переменных, функций и переменных заголовка + self.newTemplate = self.setTemplateRules(templateProp, + self.newTemplate, newFile, + oldFile) + else: + # Копируем содержимое шаблона в содержимое конфигурационного файла + self.oldTemplate = self.newTemplate + # Если файл шаблона имеет поддерживаемый формат + if not formatTemplate in ["raw", "bin"]: + # Флаг- кодировка с бинарными примесями у файла шаблона включаем при + # условии текстового файла и кодировки отличной от UTF-8 + flagNotUtf8New = False + # Флаг - кодировка с бинарными примесями у оригинального файла + flagNotUtf8Old = False + # проверяем кодировку шаблона + if not self.textIsUtf8(self.newTemplate): + flagNotUtf8New = True + if not ("link" in templateProp and "symbolic" in templateProp): + # проверяем кодировку оригинального файла + if not self.textIsUtf8(self.oldTemplate): + flagNotUtf8Old = True + # Титл конфигурационного файла + title = "" + if ListOptTitle and "comment" in templateProp: + title = self.getTitle(templateProp["comment"], + ListOptTitle) + title = title.encode("UTF-8") + # Удаляем заголовок Calculate из конфигурационного файла + if "comment" in templateProp: + self.oldTemplate = fileHeadObj.delHeaderConfFile(self.oldTemplate, + templateProp["comment"]) + # Создаем объект в случае параметра format в заголовке + if not formatTemplate in ["raw", "bin"] and\ + appendTemplate in ["replace", "before", "after"]: + # Преобразовываем бинарные файлы + if flagNotUtf8New: + objTxtCoder = utfBin() + self.newTemplate = objTxtCoder.encode(self.newTemplate) + # создаем объект формата шаблона + objTemplNew = self.getFormatObj(formatTemplate, self.newTemplate) + if not objTemplNew: + self.setError (\ + _("Incorrect header parmeter format=%s in template")\ + %formatTemplate + " " + newFile) + return False + + if "xml_" in formatTemplate: + if objTemplNew.getError(): + self.setError (_("False template: " ) + newFile) + return False + nameRootNode = oldFile.rpartition("/")[2].split(".")[0] + objTemplNew.setNameBodyNode(nameRootNode) + # Объект Документ + docObj = objTemplNew.docObj + # Удаление комментариев из документа + docObj.removeComment(docObj.getNodeBody()) + # Добавление необходимых переводов строк + docObj.insertBRtoBody(docObj.getNodeBody()) + # Добавление необходимых разделителей между областями + docObj.insertBeforeSepAreas(docObj.getNodeBody()) + # Пост обработка + if 'postXML' in dir(objTemplNew): + objTemplNew.postXML() + # Получение текстового файла из XML документа + self.newTemplate = objTemplNew.getConfig().encode("UTF-8") + # Если не UTF-8 производим преобразование + if flagNotUtf8New: + self.newTemplate = objTxtCoder.decode(self.newTemplate) + # Титл для объединения + if ListOptTitle: + title = self.getTitle(objTemplNew._comment, + ListOptTitle) + title = title.encode("UTF-8") + # Замена + if appendTemplate == "replace": + if "xml_" in formatTemplate: + data = self.newTemplate.split("\n") + data.insert(1,title) + self.oldTemplate = "\n".join(data) + else: + self.oldTemplate = title + self.newTemplate + self.saveOldFile() + return filesApply + # Впереди + elif appendTemplate == "before": + if "xml_" in formatTemplate: + self.setError (\ + _("False option append=before in template %s") %newFile) + return False + if self.newTemplate: + if self.newTemplate[-1] == "\n": + tmpTemplate = self.newTemplate + self.oldTemplate + else: + tmpTemplate = self.newTemplate + "\n" + self.oldTemplate + else: + tmpTemplate = self.oldTemplate + self.oldTemplate = title + tmpTemplate + self.saveOldFile() + return filesApply + # Cзади + elif appendTemplate == "after": + if "xml_" in formatTemplate: + self.setError (\ + _("False option append=after in template %s") %newFile) + return False + if self.newTemplate: + if self.newTemplate[-1] == "\n": + tmpTemplate = self.oldTemplate + self.newTemplate + else: + tmpTemplate = self.oldTemplate + "\n" + self.newTemplate + else: + tmpTemplate = self.oldTemplate + self.oldTemplate = title + tmpTemplate + self.saveOldFile() + return filesApply + # Объединение + elif appendTemplate == "join": + if flagNotUtf8New: + objTxtCoder = utfBin() + self.newTemplate = objTxtCoder.encode(self.newTemplate) + # создаем объект формата шаблона + objTemplNew = self.getFormatObj(formatTemplate, self.newTemplate) + if not objTemplNew: + self.setError (\ + _("Incorrect header parmeter format=%s in template")\ + %formatTemplate + " " + newFile) + return False + if "xml_" in formatTemplate: + if objTemplNew.getError(): + self.setError (_("False template: " ) + newFile) + return False + nameRootNode = oldFile.rpartition("/")[2].split(".")[0] + objTemplNew.setNameBodyNode(nameRootNode) + # Титл для объединения + if ListOptTitle: + title = self.getTitle(objTemplNew._comment, + ListOptTitle) + title = title.encode("UTF-8") + # В случае пустого конфигурационного файла + reNoClean = re.compile("[^\s]",re.M) + if not self.oldTemplate or\ + not reNoClean.search(self.oldTemplate): + self.oldTemplate = "" + # Удаляем заголовок Calculate из конфигурационного файла + self.oldTemplate = fileHeadObj.delHeaderConfFile(self.oldTemplate, + objTemplNew._comment) + if flagNotUtf8Old: + objTxtCoder = utfBin() + self.oldTemplate = objTxtCoder.encode(self.oldTemplate) + # создаем объект формата шаблона для конфигурационного файла + objTemplOld = self.getFormatObj(formatTemplate, self.oldTemplate) + if not objTemplOld: + self.setError (_("Error in template %s") %oldFile) + return False + if "xml_" in formatTemplate: + if objTemplOld.getError(): + self.setError (_("False template: " ) + oldFile) + return False + nameRootNode = oldFile.rpartition("/")[2].split(".")[0] + objTemplOld.setNameBodyNode(nameRootNode) + + #print "#%s#" %(objTemplOld.docObj.body.toprettyxml()) + #print "#%s#" %(objTemplNew.docObj.body.toprettyxml()) + objTemplOld.join(objTemplNew) + if "xml_" in formatTemplate: + if objTemplOld.getError(): + self.setError (_("False template: " ) + newFile) + return False + data = \ + objTemplOld.getConfig().encode("UTF-8").split("\n") + data.insert(1,title) + self.oldTemplate = "\n".join(data) + else: + self.oldTemplate = title +\ + objTemplOld.getConfig().encode("UTF-8") + # Декодируем если кодировка не UTF-8 + if flagNotUtf8New or flagNotUtf8Old: + self.newTemplate = objTxtCoder.decode(self.newTemplate) + self.oldTemplate = objTxtCoder.decode(self.oldTemplate) + self.saveOldFile() + return filesApply + else: + self.setError (_("False (type append) template: " )+appendTemplate) + return False + +class iniParser(_error): + """Класс для работы с ini файлами + + """ + def __init__(self, iniFile): + # Класс samba + self.samba = getattr(__import__("format.samba", + globals(), locals(), + ["samba"]), "samba") + # название ini файла + self.iniFile = iniFile + # права создаваемого ini-файла + self.mode = 0640 + # Cоответствует ли формат файла нужному + self.checkIni = None + + def setMode(self, mode): + """установка прав создаваемого ini-файла""" + self.mode = mode + + def openIniFile(self): + if not os.access(self.iniFile, os.R_OK): + return "" + FD = open(self.iniFile, "r") + textIni = FD.read() + FD.close() + return textIni + + def writeIniFile(self, txtConfig): + if not os.path.exists(self.iniFile): + fd = os.open(self.iniFile, os.O_CREAT) + os.close(fd) + os.chmod(self.iniFile, self.mode) + if not os.path.exists(self.iniFile): + self.setError(_("Unable to create file") + ": " + self.iniFile) + return False + FD = open(self.iniFile, "r+") + FD.truncate(0) + FD.seek(0) + FD.write(txtConfig) + FD.close() + + def setVar(self, strHeader, dictVar): + """Заменяет или добавляет область и переменные + + Добавляет область в ini-файл или объединяет с существующей + strHeader - имя области + dictVar - словарь переменных + """ + textIni = self.openIniFile() + if not self.checkIniFile(textIni): + return False + # создаем объект типа samba и записываем в него содержимое ini-файла + objIni = self.samba(textIni) + # создаем текст в формате samba из строки заголовка и + # словаря переменных области + txtConfig = objIni.createTxtConfig(strHeader, dictVar) + # создаем объект типа samba и записываем в него текст + objIniAdd = self.samba(txtConfig) + # объединяем объекты для получения результирующего текста + objIni.join(objIniAdd) + # получаем текст + txtConfig = objIni.getConfig().encode("UTF-8") + # записываем его в ini файл + self.writeIniFile(txtConfig) + return True + + def isEmptyFile(self, textIni): + """Является ли файл пустым""" + if not textIni.strip(): + return True + else: + return False + + def checkIniFile(self, textIni): + """Проверка на правильность формата файла""" + if self.checkIni == None: + # Ошибка + if textIni == False: + self.checkIni = False + return False + self.checkIni = True + # В файле есть данные + if not self.isEmptyFile(textIni): + objIni = self.samba(textIni) + xmlBody = objIni.docObj.getNodeBody() + if not xmlBody.firstChild: + self.checkIni = False + return self.checkIni + + def delVar(self, strHeader, nameVar): + """Удаляем переменную из ini файла""" + delNameVar = "!%s" %(nameVar) + dictVar = {delNameVar:"del"} + res = self.setVar(strHeader, dictVar) + return res + + def delArea(self, strHeader): + """Удаляем область из ini файла""" + delStrHeader = "!%s" %(strHeader) + dictVar = {"del":"del"} + res = self.setVar(delStrHeader, dictVar) + return res + + def getVar(self, strHeader, nameVar): + """Получаем значение переменной из ini-файла""" + textIni = self.openIniFile() + if not self.checkIniFile(textIni): + return False + # создаем объект типа samba и записываем в него содержимое ini-файла + objIni = self.samba(textIni) + # получаем ноду body + xmlBody = objIni.docObj.getNodeBody() + # находим в области переменную + res = objIni.docObj.getAreaFieldValues(strHeader, nameVar, xmlBody) + if res == False: + return "" + else: + return res + + def getAreaVars(self,strHeader): + """Получаем все переменнные области из ini-файла""" + textIni = self.openIniFile() + if not self.checkIniFile(textIni): + return False + # создаем объект типа samba и записываем в него содержимое ini-файла + objIni = self.samba(textIni) + # получаем ноду body + xmlBody = objIni.docObj.getNodeBody() + # если находим область то выдаем словарем все переменные иначе False + res = objIni.docObj.getAreaFields(strHeader, xmlBody) + if res == False: + return {} + else: + return res + + def getAllSectionNames(self): + """Получаем все имена секций определенных в ini файле""" + textIni = self.openIniFile() + if not self.checkIniFile(textIni): + return False + # создаем объект типа samba и записываем в него содержимое ini-файла + objIni = self.samba(textIni) + # получаем ноду body + xmlBody = objIni.docObj.getNodeBody() + xmlNodes = objIni.docObj.getFieldsArea(xmlBody) + # Имена секций ini файла + namesSection = [] + for xmlNode in xmlNodes: + if xmlNode.tagName == "area": + nSect = objIni.docObj.getNameArea(xmlNode) + if nSect: + namesSection.append(nSect) + return namesSection 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..5a29f48 --- /dev/null +++ b/build/lib/calculate-lib/pym/cl_utils.py @@ -0,0 +1,214 @@ +#-*- 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 subprocess +import string +from random import choice +import os +import types +import stat + + +def _toUNICODE(val): + """перевод текста в юникод""" + if type(val) == types.UnicodeType: + return val + else: + return str(val).decode('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 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) + +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 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 getdirlist(s_path): + """Получить список директорий по указаному пути""" + return filter(lambda x: os.path.isdir(x), os.listdir(s_path)) + +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): + """Установка ошибки""" + if not error in self.error: + self.error.append(error) + return True + +class scan: + """Класс для сканирования директорий""" + class _dir: + """Класс для хранения директорий""" + def __init__(self): + # Базовая директория + self.baseDir = False + # Все директории в базовой включая вложенные + self.dirs = [] + # Все файлы внутри базовой директории + self.files = [] + # Все ссылки внутри базовой директории + self.links = [] + # Все сокеты внутри базовой директории + self.sockets = [] + + + def __scanDir(self, scanDir, dirObj, flagDir=False): + """Сканирование одной директории""" + if flagDir or stat.S_ISDIR(os.stat(scanDir)[stat.ST_MODE]): + for fileOrDir in os.listdir(scanDir): + absPath = os.path.join(scanDir,fileOrDir) + statInfo = os.stat(absPath)[stat.ST_MODE] + if stat.S_ISDIR(statInfo): + dirObj.dirs.append(absPath) + self.__scanDir(absPath, dirObj, True) + elif stat.S_ISLNK(statInfo): + dest = absPath + src = os.readlink(absPath) + dirObj.links.append((src,dest)) + elif stat.S_ISREG(statInfo): + dirObj.files.append(absPath) + elif stat.S_ISSOCK(statInfo): + dirObj.sockets.append(absPath) + return dirObj + + def scanDirs(self, scanDirs): + """Сканирование директорий на вход список + + Выход список объктов _dirProf + """ + dirs = [] + for scanDir in scanDirs: + dirP = scan._dir() + try: + self.__scanDir(scanDir, dirP) + except OSError, e: + print e.strerror, e.filename + return [] + dirP.baseDir = scanDir + dirs.append(dirP) + return dirs \ No newline at end of file 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..4097326 --- /dev/null +++ b/build/lib/calculate-lib/pym/cl_vars.py @@ -0,0 +1,89 @@ +#-*- 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"} diff --git a/build/lib/calculate-lib/pym/format/__init__.py b/build/lib/calculate-lib/pym/format/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/build/lib/calculate-lib/pym/format/apache.py b/build/lib/calculate-lib/pym/format/apache.py new file mode 100644 index 0000000..0b1ffc2 --- /dev/null +++ b/build/lib/calculate-lib/pym/format/apache.py @@ -0,0 +1,218 @@ +#-*- 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 +from xml import xpath +from cl_template import blocText, xmlDoc +from format.bind import bind + +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 \ No newline at end of file diff --git a/build/lib/calculate-lib/pym/format/bind.py b/build/lib/calculate-lib/pym/format/bind.py new file mode 100644 index 0000000..7028196 --- /dev/null +++ b/build/lib/calculate-lib/pym/format/bind.py @@ -0,0 +1,315 @@ +#-*- 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 +from cl_template import objShare, blocText, xmlDoc + +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) diff --git a/build/lib/calculate-lib/pym/format/compiz.py b/build/lib/calculate-lib/pym/format/compiz.py new file mode 100644 index 0000000..40ae487 --- /dev/null +++ b/build/lib/calculate-lib/pym/format/compiz.py @@ -0,0 +1,41 @@ +#-*- 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 +from format.samba import samba + +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() diff --git a/build/lib/calculate-lib/pym/format/dhcp.py b/build/lib/calculate-lib/pym/format/dhcp.py new file mode 100644 index 0000000..4f47666 --- /dev/null +++ b/build/lib/calculate-lib/pym/format/dhcp.py @@ -0,0 +1,100 @@ +#-*- 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 +from format.bind import bind + +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) diff --git a/build/lib/calculate-lib/pym/format/dovecot.py b/build/lib/calculate-lib/pym/format/dovecot.py new file mode 100644 index 0000000..5130771 --- /dev/null +++ b/build/lib/calculate-lib/pym/format/dovecot.py @@ -0,0 +1,65 @@ +#-*- 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 +from xml import xpath +from format.bind import bind + +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() \ No newline at end of file diff --git a/build/lib/calculate-lib/pym/format/kde.py b/build/lib/calculate-lib/pym/format/kde.py new file mode 100644 index 0000000..5c9b3fd --- /dev/null +++ b/build/lib/calculate-lib/pym/format/kde.py @@ -0,0 +1,160 @@ +#-*- 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 +from xml import xpath +from cl_template import xmlDoc +from format.samba import samba + +class kde(samba): + """Класс для обработки конфигурационного файла типа kde + + """ + _comment = "#" + configName = "kde" + configVersion = "0.1" + reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n?",re.M) + reBody = re.compile(".+",re.M|re.S) + reComment = re.compile("^\s*%s.*"%(_comment)) + reSeparator = re.compile("=") + sepFields = "\n" + reSepFields = re.compile(sepFields) + + def __init__(self,text): + samba.__init__(self,text) + + + def _textToXML(self): + """Преобразует текст в XML""" + blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody) + blocs = self.getFullAreas(blTmp) + headers = [] + startHeaders = [] + finHeaders = [] + docObj = xmlDoc() + docObj.createDoc(self.configName, self.configVersion) + rootNode = docObj.getNodeBody() + # Если пустой текст то создаем пустой документ + if not blocs: + return docObj + + for h in blocs[0]: + reH = re.compile("]\s*$") + #listfinH = h.split("]") + listfinH = reH.split(h) + finH = listfinH[0] + if "[" in finH: + startHeaders.append(finH + "]") + else: + startHeaders.append(finH) + if len(listfinH) == 2: + finHeaders.append(listfinH[1]) + else: + finHeaders.append("") + head=finH.replace("][",".").replace("[","").replace("]","").strip() + headers.append(head) + bodys = blocs[1] + + z = 0 + for h in headers: + if not bodys[z]: + z += 1 + continue + areaAction = False + if h: + if h[0] == "!": + docObj.createCaption(h[1:], [startHeaders[z],""]) + areaAction = "drop" + elif h[0] == "-": + docObj.createCaption(h[1:], [startHeaders[z],""]) + areaAction = "replace" + else: + docObj.createCaption(h, [startHeaders[z],""]) + else: + docObj.createCaption(h, [startHeaders[z],""]) + + if "\n" in blocs[0][z]: + if self.reComment.search(finHeaders[z]): + docObj.createField('comment', [finHeaders[z]]) + elif not finHeaders[z].strip() and\ + finHeaders[z].replace("\n",""): + docObj.createField('br', + [finHeaders[z].replace("\n","")]) + else: + docObj.createField('br') + fields = self._splitToFields(bodys[z]) + for f in fields: + if f.name != False and f.value!=False and f.br!=False: + # Обработка условий для samba + if f.name[0] == "!" or f.name[0] == "-" or\ + f.name[0] == "+": + qns = self.removeSymbolTerm(f.br) + xmlField = docObj.createField("var", + [qns], + f.name[1:], [f.value]) + if f.name[0] == "!": + # Удаляемое в дальнейшем поле + docObj.setActionField(xmlField, "drop") + else: + docObj.createField("var",[f.br.replace("\n","")], + f.name, [f.value]) + docObj.createField('br') + elif f.comment != False: + docObj.createField('comment', [f.comment]) + elif f.br != False: + docObj.createField('br', [f.br.replace("\n","")]) + if h.strip(): + area = docObj.createArea() + if areaAction: + docObj.setActionArea(area, areaAction) + rootNode.appendChild(area) + else: + fieldsNodes = docObj.tmpFields.getFields() + for fieldNode in fieldsNodes: + rootNode.appendChild(fieldNode) + docObj.clearTmpFields() + z += 1 + #print docObj.doc.toprettyxml() + return docObj + + def postXML(self): + """Последующая постобработка XML""" + # Для добавления перевода строки между областями если его нет + #print self.docObj.body.toprettyxml() + xmlAreas = xpath.Evaluate("child::area", self.docObj.body) + for xmlArea in xmlAreas: + if xmlArea.previousSibling and\ + self.docObj.getTypeField(xmlArea.previousSibling) == "br": + continue + firstArea = False + xmlFields = xpath.Evaluate("child::field", xmlArea) + if not (xmlFields and\ + (self.docObj.getTypeField(xmlFields[-1]) == "br" or\ + self.docObj.getTypeField(xmlFields[-1]) == "comment")): + if xmlArea.nextSibling: + parentNode = xmlArea.parentNode + nextNode = xmlArea.nextSibling + parentNode.insertBefore(self.docObj.createField("br", + [],"",[], + False,False), + nextNode) + + def join(self, kdeObj): + """Объединяем конфигурации""" + if isinstance(kdeObj, kde): + self.docObj.joinDoc(kdeObj.doc) + self.postXML() + diff --git a/build/lib/calculate-lib/pym/format/ldap.py b/build/lib/calculate-lib/pym/format/ldap.py new file mode 100644 index 0000000..5df868c --- /dev/null +++ b/build/lib/calculate-lib/pym/format/ldap.py @@ -0,0 +1,183 @@ +#-*- 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 +from cl_template import blocText, xmlDoc +from format.samba import samba + +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 diff --git a/build/lib/calculate-lib/pym/format/plasma.py b/build/lib/calculate-lib/pym/format/plasma.py new file mode 100644 index 0000000..d5e9500 --- /dev/null +++ b/build/lib/calculate-lib/pym/format/plasma.py @@ -0,0 +1,597 @@ +#-*- 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 types +import copy +from xml import xpath +from cl_template import xmlDoc +from format.samba import samba + +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 _textToXML(self): + """Преобразуем текст в XML""" + areas = [] + if self.text.strip(): + self.splitToAllArea(self.text, areas) + #docObj = xmlDoc() + # Создаем новый класс xmlDoc с измененным методом joinArea + newClass = type("newXmlDocPlalma",(xmlDocPlasma,xmlDoc,object),{}) + # Создаем экземпляр нового класса + docObj = newClass() + # Создание объекта документ c пустым разделителем между полями + docObj.createDoc(self.configName, self.configVersion) + if not areas: + return docObj + self.createXML(areas, docObj.getNodeBody(), docObj) + return docObj + + + def postXML(self): + """Последующая постобработка XML""" + # Для добавления перевода строки между областями если его нет + #print self.docObj.body.toprettyxml() + def getQuotesArea(xmlArea): + quotes = [] + xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea) + for node in xmlQuotes: + if node.firstChild: + quotes.append(node.firstChild.nodeValue) + if len(quotes) == 0: + quotes.append("") + quotes.append("") + elif len(quotes) == 1: + quotes.append("") + return quotes + + xmlAreas = xpath.Evaluate("descendant::area", self.docObj.body) + #print "-------------------------------------------------------" + #print xmlAreas + #if xmlAreas: + #prXmlArea = xmlAreas[0] + for xmlArea in xmlAreas: + # Перед пустой областью и после нее удаляем переводы строк + if getQuotesArea(xmlArea) == ["",""]: + #areaTXT = xpath.Evaluate("child::caption/name", xmlArea)[0] + #print "CL_AREA", areaTXT.firstChild + if xmlArea.previousSibling and\ + self.docObj.getTypeField(xmlArea.previousSibling) == "br": + parentNode = xmlArea.previousSibling.parentNode + if xmlArea.previousSibling.previousSibling and\ + self.docObj.getTypeField(xmlArea.previousSibling.previousSibling) == "br": + parentNode.removeChild(\ + xmlArea.previousSibling.previousSibling) + parentNode.removeChild(xmlArea.previousSibling) + if xmlArea.nextSibling and\ + self.docObj.getTypeField(xmlArea.nextSibling) == "br": + parentNode = xmlArea.nextSibling.parentNode + if xmlArea.nextSibling.nextSibling and\ + self.docObj.getTypeField(xmlArea.nextSibling.nextSibling) == "br": + parentNode.removeChild(xmlArea.nextSibling.nextSibling) + parentNode.removeChild(xmlArea.nextSibling) + continue + + # Собираем поля в кучку + xmlChildAreas = xpath.Evaluate("child::area", xmlArea) + if xmlChildAreas: + childNodes = self.docObj.getFieldsArea(xmlArea) + firstChildArea = xmlChildAreas[0] + if firstChildArea.previousSibling and\ + self.docObj.getTypeField(firstChildArea.previousSibling)=="br": + if firstChildArea.previousSibling.previousSibling: + if self.docObj.getTypeField(\ + firstChildArea.previousSibling.previousSibling)=="br": + firstChildArea = firstChildArea.previousSibling + flagFoundArea = False + it = 0 + lenChild = len(childNodes) + for node in childNodes: + it += 1 + if node.tagName == "area": + flagFoundArea = True + continue + if flagFoundArea and node.tagName == "field": + if self.docObj.getTypeField(node) == "var": + xmlArea.insertBefore(node, firstChildArea) + if it < lenChild: + if self.docObj.getTypeField(childNodes[it])==\ + "br": + xmlArea.insertBefore(childNodes[it], + firstChildArea) + + # Добавляем BR если его нет первым полем + xmlFields = xpath.Evaluate("child::field", xmlArea) + if not (xmlFields and\ + (self.docObj.getTypeField(xmlFields[0]) == "br" or\ + self.docObj.getTypeField(xmlFields[0]) == "comment")): + if xmlFields: + xmlArea.insertBefore(self.docObj.createField("br", + [],"",[], + False,False), + xmlFields[0]) + # Если последним полем BR, удаляем его + if xmlFields and self.docObj.getTypeField(xmlFields[-1]) == "br": + #print "DEL_BR", xmlFields[-1].nextSibling + #and\ + if not xmlFields[-1].nextSibling: + xmlArea.removeChild(xmlFields[-1]) + + # Если предыдущим полем не (BR или комментарий) - добавляем BR + if xmlArea.previousSibling and\ + not (self.docObj.getTypeField(xmlArea.previousSibling) == "br" or\ + self.docObj.getTypeField(xmlArea.previousSibling) == "comment"): + parentNode = xmlArea.parentNode + parentNode.insertBefore(self.docObj.createField("br", + [],"",[], + False,False), + xmlArea) + # Если есть предыдущее поле, и поле предыдущеее предыдущему + # не равно BR или комментарий то добавляем BR + if xmlArea.previousSibling: + prPrSibling = xmlArea.previousSibling.previousSibling + if prPrSibling and\ + not (self.docObj.getTypeField(prPrSibling) == "br" or\ + self.docObj.getTypeField(prPrSibling) == "comment"): + parentNode = xmlArea.parentNode + parentNode.insertBefore(self.docObj.createField("br", + [],"",[], + False,False), + xmlArea) + # Если после есть BR а за ним ничего нет, удаляем BR + if xmlArea.nextSibling and\ + self.docObj.getTypeField(xmlArea.nextSibling) == "br": + if not xmlArea.nextSibling.nextSibling: + parentNode = xmlArea.nextSibling.parentNode + parentNode.removeChild(xmlArea.nextSibling) + + #xmlName = xpath.Evaluate("child::caption/name", xmlArea)[0] + #print "------------------------------------" + #print "Name =", xmlName.firstChild + #if xmlArea.previousSibling: + #print "PR_TYPE =", self.docObj.getTypeField(xmlArea.previousSibling) + + + def join(self, kdeObj): + """Объединяем конфигурации""" + if isinstance(kdeObj, plasma): + self.docObj.joinDoc(kdeObj.doc) + self.postXML() + + diff --git a/build/lib/calculate-lib/pym/format/postfix.py b/build/lib/calculate-lib/pym/format/postfix.py new file mode 100644 index 0000000..4dc2a34 --- /dev/null +++ b/build/lib/calculate-lib/pym/format/postfix.py @@ -0,0 +1,117 @@ +#-*- 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 +from cl_template import xmlDoc +from format.apache import apache + +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 diff --git a/build/lib/calculate-lib/pym/format/procmail.py b/build/lib/calculate-lib/pym/format/procmail.py new file mode 100644 index 0000000..50fa05f --- /dev/null +++ b/build/lib/calculate-lib/pym/format/procmail.py @@ -0,0 +1,115 @@ +#-*- 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 +from cl_template import objShare, xmlDoc + +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) diff --git a/build/lib/calculate-lib/pym/format/samba.py b/build/lib/calculate-lib/pym/format/samba.py new file mode 100644 index 0000000..981cc52 --- /dev/null +++ b/build/lib/calculate-lib/pym/format/samba.py @@ -0,0 +1,261 @@ +#-*- 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 +from xml import xpath +from cl_template import objShare, blocText, xmlDoc + +class samba(objShare): + """Класс для обработки конфигурационного файла типа samba + + """ + _comment = "#" + configName = "samba" + configVersion = "0.1" + reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n",re.M) + reBody = re.compile(".+",re.M|re.S) + reComment = re.compile("\s*%s.*|\s*;.*"%(_comment)) + reSeparator = re.compile("\s*=\s*") + sepFields = "\n" + reSepFields = re.compile(sepFields) + + def __init__(self,text): + self.text = text + self.blocTextObj = blocText() + self._splitToFields = self.splitToFields + # Объект документ + self.docObj = self._textToXML() + # XML документ + self.doc = self.docObj.doc + + def postXML(self): + """Последующая постобработка XML""" + # Для добавления перевода строки между областями если его нет + #print self.docObj.body.toprettyxml() + xmlAreas = xpath.Evaluate("child::area", self.docObj.body) + for xmlArea in xmlAreas: + if xmlArea.previousSibling and\ + self.docObj.getTypeField(xmlArea.previousSibling) == "br": + continue + firstArea = False + xmlFields = xpath.Evaluate("child::field", xmlArea) + if not (xmlFields and\ + (self.docObj.getTypeField(xmlFields[-1]) == "br" or\ + self.docObj.getTypeField(xmlFields[-1]) == "comment")): + if xmlArea.nextSibling: + parentNode = xmlArea.parentNode + nextNode = xmlArea.nextSibling + parentNode.insertBefore(self.docObj.createField("br", + [],"",[], + False,False), + nextNode) + + + def join(self, sambaObj): + """Объединяем конфигурации""" + if isinstance(sambaObj, samba): + self.docObj.joinDoc(sambaObj.doc) + self.postXML() + + def setDataField(self, txtLines, endtxtLines): + """Создаем список объектов с переменными""" + class fieldData: + def __init__(self): + self.name = False + self.value = False + self.comment = False + self.br = False + fields = [] + field = fieldData() + z = 0 + for k in txtLines: + textLine = k + endtxtLines[z] + z += 1 + findComment = self.reComment.search(textLine) + if not textLine.strip(): + field.br = textLine + fields.append(field) + field = fieldData() + elif findComment: + field.comment = textLine + fields.append(field) + field = fieldData() + else: + pars = textLine.strip() + nameValue = self.reSeparator.split(pars) + if len(nameValue) > 2: + valueList = nameValue[1:] + nameValue =[nameValue[0],"=".join(valueList)] + if len(nameValue) == 2: + name = nameValue[0] + value = nameValue[1].replace(self.sepFields,"") + field.name = name.replace(" ","").replace("\t","") + field.value = value + field.br = textLine + fields.append(field) + field = fieldData() + return fields + + + def splitCleanBloc(self, txtBloc): + """Делим блок на две части (переменные, пустые строки в конце)""" + txtLines = txtBloc.split("\n") + firstBloc = [] + nextBloc = [] + txtLines.reverse() + z = 0 + for txtLine in txtLines: + if not txtLine.strip(): + nextBloc.append(txtLine) + else: + break + z += 1 + txtLines.reverse() + firstBloc = txtLines[:-z] + nextBloc.reverse() + if nextBloc: + firstBloc.append("") + if nextBloc and "\n".join(nextBloc): + return ("\n".join(firstBloc), "\n".join(nextBloc)) + else: + return False + + def getFullAreas(self, blocs): + """Делит текст на области, (Заголовок, тело) + + Возвращает два списка: заголовки, тела + """ + headsAreas = [] + bodyAreas = [] + if not blocs: + return [] + lenBlocs = len(blocs[0]) + for i in range(lenBlocs): + txtBloc = blocs[1][i] + clean = self.splitCleanBloc(txtBloc) + if clean: + headsAreas.append(blocs[0][i]) + bodyAreas.append(clean[0]) + headsAreas.append("") + bodyAreas.append(clean[1]) + else: + headsAreas.append(blocs[0][i]) + bodyAreas.append(blocs[1][i]) + return (headsAreas, bodyAreas) + + def createTxtConfig(self, strHeader, dictVar): + """Cоздает область с заголовком + + создает текст конфигурационного файла в формате samba из + заголовка (строка) и словаря переменных + """ + if not strHeader: + return "" + outTxt = "[" + strHeader + "]\n" + for key in dictVar.keys(): + outTxt += "%s = %s\n" %(key,dictVar[key]) + return outTxt + + def _textToXML(self): + """Преобразует текст в XML""" + blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody) + blocs = self.getFullAreas(blTmp) + headers = [] + startHeaders = [] + finHeaders = [] + docObj = xmlDoc() + docObj.createDoc(self.configName, self.configVersion) + rootNode = docObj.getNodeBody() + # Если пустой текст то создаем пустой документ + if not blocs: + return docObj + + for h in blocs[0]: + listfinH = h.split("]") + finH = listfinH[0] + if "[" in finH: + startHeaders.append(finH + "]") + else: + startHeaders.append(finH) + if len(listfinH) == 2: + finHeaders.append(listfinH[1]) + else: + finHeaders.append("") + headers.append(finH.replace("[","").replace("]","").strip()) + bodys = blocs[1] + + z = 0 + for h in headers: + if not bodys[z]: + z += 1 + continue + areaAction = False + if h: + if h[0] == "!": + docObj.createCaption(h[1:], [startHeaders[z],""]) + areaAction = "drop" + elif h[0] == "-": + docObj.createCaption(h[1:], [startHeaders[z],""]) + areaAction = "replace" + else: + docObj.createCaption(h, [startHeaders[z],""]) + else: + docObj.createCaption(h, [startHeaders[z],""]) + + if "\n" in blocs[0][z]: + if self.reComment.search(finHeaders[z]): + docObj.createField('comment', [finHeaders[z]]) + elif not finHeaders[z].strip() and\ + finHeaders[z].replace("\n",""): + docObj.createField('br', + [finHeaders[z].replace("\n","")]) + else: + docObj.createField('br') + fields = self._splitToFields(bodys[z]) + for f in fields: + if f.name != False and f.value!=False and f.br!=False: + # Обработка условий для samba + if f.name[0] == "!" or f.name[0] == "-" or\ + f.name[0] == "+": + qns = self.removeSymbolTerm(f.br) + xmlField = docObj.createField("var", + [qns], + f.name[1:], [f.value]) + if f.name[0] == "!": + # Удаляемое в дальнейшем поле + docObj.setActionField(xmlField, "drop") + else: + docObj.createField("var",[f.br.replace("\n","")], + f.name, [f.value]) + docObj.createField('br') + elif f.comment != False: + docObj.createField('comment', [f.comment]) + elif f.br != False: + docObj.createField('br', [f.br.replace("\n","")]) + if h.strip(): + area = docObj.createArea() + if areaAction: + docObj.setActionArea(area, areaAction) + rootNode.appendChild(area) + else: + fieldsNodes = docObj.tmpFields.getFields() + for fieldNode in fieldsNodes: + rootNode.appendChild(fieldNode) + docObj.clearTmpFields() + z += 1 + #print docObj.doc.toprettyxml() + return docObj + diff --git a/build/lib/calculate-lib/pym/format/squid.py b/build/lib/calculate-lib/pym/format/squid.py new file mode 100644 index 0000000..fba8153 --- /dev/null +++ b/build/lib/calculate-lib/pym/format/squid.py @@ -0,0 +1,86 @@ +#-*- 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 +from format.procmail import procmail + +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) diff --git a/build/lib/calculate-lib/pym/format/xml_gconf.py b/build/lib/calculate-lib/pym/format/xml_gconf.py new file mode 100644 index 0000000..84894bd --- /dev/null +++ b/build/lib/calculate-lib/pym/format/xml_gconf.py @@ -0,0 +1,262 @@ +#-*- 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 time +from xml import xpath +import xml.dom.minidom +from format.xml_xfce import xml_xfce +# Перевод cообщений модуля +from cl_lang import lang +tr = lang() +tr.setLocalDomain('cl_lib') +tr.setLanguage(sys.modules[__name__]) + + +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 template is XML")) + return False + self.rootNode = self.doc.documentElement + self.bodyNode = self.rootNode + return self.doc + + def cmpListsNodesEntry(self, listXmlA, listXmlB): + """Сравнение содержимого двух списков XML нод""" + getTextsNodes = lambda y: map(lambda x:\ + x.toxml().replace(" ","").replace("\t","").replace("\n",""), + map(lambda x: x.removeAttribute("mtime") or x, + map(lambda x: x.cloneNode(True), + filter(lambda x: x.nodeType==x.ELEMENT_NODE, y)))) + if set(getTextsNodes(listXmlA))==set(getTextsNodes(listXmlB)): + return True + return False + + def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True, levelNumber=0): + """Объединение корневой ноды шаблона и корневой ноды файла""" + if levelNumber>1: + return True + xmlNode = xmlNewNode + childNodes = xmlNode.childNodes + nextOldNode = xmlOldNode + flagError = False + if xmlNode.nodeType == xmlNode.ELEMENT_NODE: + n = xmlNode + tagName = n.tagName + nAction = u'' + nName = u'' + nType = u'' + nValue = u'' + attrName = '' + attrType = '' + if flagRootNode: + if not tagName == "gconf": + self.setError(_("The text is not a valid gconf-XML format \ +(not found '...')")) + return False + else: + if not tagName == "entry": + self.setError(_("The text is not a valid gconf-XML format \ +(found '<%s>..'")%(tagName,tagName)) + return False + if not n.hasAttribute("name"): + self.setError(_('Not found arrtibute "name" in tag entry')) + return False + if not n.hasAttribute("type"): + self.setError(_('Not found arrtibute "type" in tag entry')) + return False + nName = n.getAttribute("name") + attrName = u"attribute::name='%s'"%nName + nType = n.getAttribute("type") + # Проверка правильности аттрибута type + if not nType in self.supportEntryTypes: + self.setError(\ + _('Incorrect arrtibute "type" - ')%nType) + return False + attrType = u"attribute::type='%s'"%nType + if n.hasAttribute("value"): + nValue = n.getAttribute("value") + if n.hasAttribute("action"): + nAction = n.getAttribute("action") + if not nAction in ("join","replace","drop"): + textError = _('''In the text, XML template, look \ +for a reserved attribute 'action' with the incorrect value.\n\ +Valid values attribute 'action': \ +(action="join", action="replace", action="drop")''') + self.setError(textError) + return False + if xmlOldNode.parentNode: + findStr = u"child::%s"%tagName + strAttr = [attrName, attrType] + findAttr = filter(lambda x: x, strAttr) + findAttrStr = '' + if findAttr: + strAttr = u' and '.join(findAttr) + findAttrStr = "[%s]"%strAttr + findPath = u"child::%s%s"%(tagName,findAttrStr) + # Рабочая нода + if flagRootNode: + workNode = xmlOldNode.parentNode + else: + workNode = xmlOldNode + oldNodes = xpath.Evaluate(findPath, workNode) + # Новая нода список + flagArray = False + if nType == "list" or nType == "pair": + flagArray = True + flagDrop = False + flagJoin = True + flagReplace = False + if nType=="string" or nAction=="replace": + flagJoin = False + flagReplace = True + elif nAction == "drop": + flagJoin = False + flagDrop = True + if flagRootNode: + textError = _('Incorrect action="drop" in root node') + self.setError(textError) + return False + if oldNodes: + if len(oldNodes)>1: + textError = _("The uncertainty in this template are \ +the same nodes at one level") + self.setError(textError) + return False + nextOldNode = oldNodes[0] + # Замещаем ноду в случае массива + if flagArray and not flagDrop: + replaceXmlNode = xmlNode.cloneNode(True) + # Сравнение содержимого нод + if not self.cmpListsNodesEntry([replaceXmlNode], + [nextOldNode]): + replaceXmlNode.setAttribute("mtime", + self.currentTime) + if nAction: + replaceXmlNode.removeAttribute("action") + workNode.replaceChild(replaceXmlNode, + nextOldNode) + flagJoin = False + flagReplace = False + childNodes = False + # Объединение нод + if flagJoin: + if nextOldNode.hasAttribute("value"): + oValue = nextOldNode.getAttribute("value") + if nValue != oValue: + nextOldNode.setAttribute("mtime", + self.currentTime) + nextOldNode.setAttribute("value",nValue) + # Замещение ноды + elif flagReplace: + replaceXmlNode = xmlNode.cloneNode(True) + # Сравнение содержимого нод + if not self.cmpListsNodesEntry([replaceXmlNode], + [nextOldNode]): + replaceXmlNode.setAttribute("mtime", + self.currentTime) + if not\ + self._removeDropNodesAndAttrAction(\ + replaceXmlNode): + return False + workNode.replaceChild(replaceXmlNode, + nextOldNode) + childNodes = False + # Удаление ноды + elif flagDrop: + workNode.removeChild(nextOldNode) + childNodes = False + else: + # Добавление ноды + childNodes = False + if not flagDrop: + appendXmlNode = xmlNode.cloneNode(True) + appendXmlNode.setAttribute("mtime", self.currentTime) + if not\ + self._removeDropNodesAndAttrAction(appendXmlNode): + return False + workNode.appendChild(appendXmlNode) + if childNodes: + for node in childNodes: + levelNumber +=1 + if not self._join(node, nextOldNode, False, levelNumber): + flagError = True + break + levelNumber -= 1 + if flagError: + return False + return True + + def join(self, xml_gconfObj): + """Объединяем конфигурации""" + # Получаем текущее время + self.currentTime = self.getCurrentTime() + if isinstance(xml_gconfObj, xml_gconf): + try: + self.joinDoc(xml_gconfObj.doc) + except: + self.setError(_("Can not join template")) + return False + return True + + def getConfig(self): + """Получение текстового файла из XML документа""" + data = self.doc.toprettyxml().split("\n") + data = filter(lambda x: x.strip(), data) + return "\n".join(data).replace("\t"," ") diff --git a/build/lib/calculate-lib/pym/format/xml_xfce.py b/build/lib/calculate-lib/pym/format/xml_xfce.py new file mode 100644 index 0000000..9acc947 --- /dev/null +++ b/build/lib/calculate-lib/pym/format/xml_xfce.py @@ -0,0 +1,268 @@ +#-*- 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 +from xml import xpath +import xml.dom.minidom +from cl_utils import _error +# Перевод cообщений модуля +from cl_lang import lang +tr = lang() +tr.setLocalDomain('cl_lib') +tr.setLanguage(sys.modules[__name__]) + +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 template 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 template")) + 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 template, 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 template, look \ +for a reserved attribute 'action' with the incorrect value.\n\ +Valid values attribute 'action': \ +(action="join", action="replace", action="drop")''') + self.setError(textError) + return False + if xmlOldNode.parentNode: + findStr = u"child::%s"%path + strAttr = [attrName, attrType] + findAttr = filter(lambda x: x, strAttr) + findAttrStr = '' + if findAttr: + strAttr = u' and '.join(findAttr) + findAttrStr = "[%s]"%strAttr + findPath = u"child::%s%s"%(path,findAttrStr) + # Рабочая нода + if flagRootNode: + workNode = xmlOldNode.parentNode + else: + workNode = xmlOldNode + oldNodes = xpath.Evaluate(findPath, workNode) + #print findPath + #print workNode + #print "----------------------------" + # Новая нода список + flagArray = False + if nType == "array": + flagArray = True + flagDrop = False + flagJoin = True + flagReplace = False + if nAction == "replace": + flagJoin = False + flagReplace = True + elif nAction == "drop": + flagJoin = False + flagDrop = True + if flagRootNode: + textError = _('Incorrect action="drop" in root node') + self.setError(textError) + return False + if oldNodes: + if len(oldNodes)>1: + textError = _("The uncertainty in this template 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 template 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") diff --git a/build/lib/calculate-lib/pym/format/xml_xfcepanel.py b/build/lib/calculate-lib/pym/format/xml_xfcepanel.py new file mode 100644 index 0000000..4e9eb06 --- /dev/null +++ b/build/lib/calculate-lib/pym/format/xml_xfcepanel.py @@ -0,0 +1,199 @@ +#-*- 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 +from xml import xpath +import xml.dom.minidom +from format.xml_xfce import xml_xfce + +# Перевод cообщений модуля +from cl_lang import lang +tr = lang() +tr.setLocalDomain('cl_lib') +tr.setLanguage(sys.modules[__name__]) + +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: + findStr = u"child::%s"%path + findAttrStr = "" + if attrName: + findAttrStr = "[%s]"%attrName + findPath = u"child::%s%s"%(path,findAttrStr) + # Рабочая нода + if flagRootNode: + workNode = xmlOldNode.parentNode + else: + workNode = xmlOldNode + oldNodes = xpath.Evaluate(findPath, workNode) + flagDrop = False + flagJoin = True + flagReplace = False + flagAppend = False + if nAction == "replace": + flagJoin = False + flagReplace = True + elif nAction == "drop": + flagJoin = False + flagDrop = True + if flagRootNode: + textError = _('Incorrect action="drop" in root node') + self.setError(textError) + return False + if path == "panel": + flagJoin = False + if levelNumber in self.panelNumbers.keys(): + self.panelNumbers[levelNumber] += 1 + else: + self.panelNumbers[levelNumber] = 0 + if oldNodes: + if len(oldNodes)>1 and path != "panel": + textError = _("The uncertainty in this profile are \ +the same nodes at one level") + self.setError(textError) + return False + if path == "panel": + if len(oldNodes)<=self.panelNumbers[levelNumber]: + nextOldNode = oldNodes[-1] + # Добавляем ноду + if not flagDrop: + flagAppend = True + flagReplace = False + childNodes = False + else: + nextOldNode=oldNodes[self.panelNumbers[levelNumber]] + else: + nextOldNode = oldNodes[0] + # Замещаем ноду в случае массива + if flagArray and not flagDrop: + replaceXmlNode = xmlNode.cloneNode(True) + if nAction: + replaceXmlNode.removeAttribute("action") + workNode.replaceChild(replaceXmlNode, + nextOldNode) + flagJoin = False + flagReplace = False + childNodes = False + # Объединение нод + if flagJoin: + if nextOldNode.hasAttribute("value"): + oValue = nextOldNode.getAttribute("value") + if nValue != oValue: + nextOldNode.setAttribute("value",nValue) + # Замещение ноды + elif flagReplace: + replaceXmlNode = xmlNode.cloneNode(True) + if not\ + self._removeDropNodesAndAttrAction(replaceXmlNode): + return False + workNode.replaceChild(replaceXmlNode, + nextOldNode) + childNodes = False + # Удаление ноды + elif flagDrop: + workNode.removeChild(nextOldNode) + childNodes = False + else: + flagAppend = True + flagDrop = False + if flagAppend and not flagDrop: + # Добавление ноды + childNodes = False + if not flagDrop: + appendXmlNode = xmlNode.cloneNode(True) + if not\ + self._removeDropNodesAndAttrAction(appendXmlNode): + return False + workNode.appendChild(appendXmlNode) + if childNodes: + for node in childNodes: + levelNumber +=1 + if not self._join(node, nextOldNode, False, levelNumber): + flagError = True + break + levelNumber -= 1 + if flagError: + return False + return True + + def join(self, xml_xfceObj): + """Объединяем конфигурации""" + if isinstance(xml_xfceObj, xml_xfcepanel): + try: + self.joinDoc(xml_xfceObj.doc) + except: + self.setError(_("Can not join profile")) + return False + return True diff --git a/pym/cl_data.py b/pym/cl_data.py new file mode 100644 index 0000000..926c224 --- /dev/null +++ b/pym/cl_data.py @@ -0,0 +1,624 @@ +#-*- 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 sys +import cl_utils +from cl_lang import lang +from cl_template import iniParser +from cl_string import columnWrite + +# Перевод модуля на другой язык +tr = lang() +tr.setLocalDomain('cl_lib') +tr.setLanguage(sys.modules[__name__]) + +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 self.__dict__.has_key(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 self.__dict__.has_key(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 self.__dict__.has_key(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 self.__dict__.has_key(vname): + if self.__dict__[vname].service == 'Global': + return 'calculate' + else: + return self.__dict__[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') + + Возвращаемые значение: + 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) + # Удаляем переменную + 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): + #if vname: + #if self.__dict__.has_key(vname): + #return True + #return False + def defined(self, vname): + return True + + + + def exists(self, nameVar): + """ Определяет существует ли переменная с таким имененм + """ + if self.__dict__.has_key(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 + 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/pym/cl_fill.py b/pym/cl_fill.py index 59beef4..4d3b598 100644 --- a/pym/cl_fill.py +++ b/pym/cl_fill.py @@ -1,6 +1,6 @@ #-*- coding: utf-8 -*- -#Copyright 2008 Calculate Pack, http://www.calculate-linux.org +# 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. @@ -17,10 +17,11 @@ import re import os import types +from cl_overriding import exit import cl_utils -import cl_base +import cl_data -class fillVars(object, cl_base.glob_attr): +class fillVars(object, cl_data.glob_attr): def get_os_net_domain(self): ''' Определим домен''' @@ -28,7 +29,7 @@ class fillVars(object, cl_base.glob_attr): if not domain: print _("Error:") + " " +_("Not found domain name") print _("Command 'hostname -d' returns an empty value") - cl_base.exit(1) + exit(1) elif re.search("^hostname: ",domain): return "local" else: @@ -99,7 +100,7 @@ class fillVars(object, cl_base.glob_attr): systemVersion = "" flagGentoo = False if os.path.exists(gentooFile): - gentooLink = "/etc/make.profile" + gentooLink = "/etc/make.template" if os.path.islink(gentooLink): systemVersion = os.readlink(gentooLink).rpartition("/")[2] flagGentoo = True diff --git a/pym/cl_help.py b/pym/cl_help.py new file mode 100644 index 0000000..20ca654 --- /dev/null +++ b/pym/cl_help.py @@ -0,0 +1,375 @@ +#-*- 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 getopt +import sys +from cl_string import prettyColumnStr + +pcs = prettyColumnStr + +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 + +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"] + return "" diff --git a/pym/cl_lang.py b/pym/cl_lang.py new file mode 100644 index 0000000..eb0cf69 --- /dev/null +++ b/pym/cl_lang.py @@ -0,0 +1,168 @@ +#-*- 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, gettext +from cl_overriding import __findFileMO + +class GlobalParam(type): + """ Метакласс для глобальных параметров + """ + def __init__(cls, *args): + cls.GP = [] + cls.GP.append("") + +gettext.find = __findFileMO + +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 + diff --git a/pym/cl_ldap.py b/pym/cl_ldap.py new file mode 100644 index 0000000..bea5fae --- /dev/null +++ b/pym/cl_ldap.py @@ -0,0 +1,58 @@ +#-*- 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 ldap +from cl_utils import _error + +class ldapFun(_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 + diff --git a/pym/cl_log.py b/pym/cl_log.py index 5c23348..ab65d0e 100644 --- a/pym/cl_log.py +++ b/pym/cl_log.py @@ -1,6 +1,6 @@ #-*- coding: utf-8 -*- -#Copyright 2008 Calculate Pack, http://www.calculate-linux.org +# 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. @@ -13,6 +13,7 @@ # 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 diff --git a/pym/cl_overriding.py b/pym/cl_overriding.py new file mode 100644 index 0000000..0c6ca8e --- /dev/null +++ b/pym/cl_overriding.py @@ -0,0 +1,58 @@ +#-*- 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,sys,gettext + +def __findFileMO(domain, localedir=None, languages=None, all=0): + """Модифицированный метод, ищет файл перевода + + замена gettext.find""" + 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 gettext._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 + +def exit(codeExit): + """Метод выхода из программы""" + sys.exit(codeExit) \ No newline at end of file diff --git a/pym/cl_print.py b/pym/cl_print.py new file mode 100644 index 0000000..1298357 --- /dev/null +++ b/pym/cl_print.py @@ -0,0 +1,217 @@ +#-*- 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, struct, termios, fcntl +from cl_utils import _toUNICODE + +class color_print(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 = _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/pym/cl_string.py b/pym/cl_string.py new file mode 100644 index 0000000..757cbfb --- /dev/null +++ b/pym/cl_string.py @@ -0,0 +1,254 @@ +#-*- 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. + +from re import search, compile, S +from cl_utils import _toUNICODE + +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') diff --git a/pym/cl_template.py b/pym/cl_template.py new file mode 100644 index 0000000..68f0c0f --- /dev/null +++ b/pym/cl_template.py @@ -0,0 +1,3774 @@ +#-*- coding: utf-8 -*- + +# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import sys +import os +import stat +import re +import xml.dom.minidom +from xml import xpath +import subprocess +import types +import random +import string +from cl_utils import _error, scan, _toUNICODE +from cl_overriding import exit +import cl_lang + +tr = cl_lang.lang() +tr.setLocalDomain('cl_lib') +tr.setLanguage(sys.modules[__name__]) + +class _terms(_error): + """Вычисление условий применяемых в шаблонах + + """ + def _convertVers(self, verA, verB): + """Конвертирование номеров версий для корректного сравнения + """ + elemA = verA.split(".") + elemB = verB.split(".") + if len(elemA) > len(elemB): + maxElemB = len(elemB)-1 + for i in range(len(elemA)): + if i > maxElemB: + elemB.append("0") + else: + maxElemA = len(elemA)-1 + for i in range(len(elemB)): + if i > maxElemA: + elemA.append("0") + for i in range(len(elemB)): + lenA = len(elemA[i]) + lenB = len(elemB[i]) + if lenA == lenB: + pass + elif lenA > lenB: + res = lenA - lenB + for z in range(res): + elemB[i] = "0" + elemB[i] + elif lenB > lenA: + res = lenB - lenA + for z in range(res): + elemA[i] = "0" + elemA[i] + return (".".join(elemA), ".".join(elemB)) + + def executeListEqual(self, listEqual): + """Вычисляет список выражений + + пример списка: + listEqual = [False, True, ' or ', True , True] + (если нет or между логическими выражениями то между ними and) + результат True + """ + lenOr = listEqual.count(" or ") + for i in xrange(lenOr): + ind = listEqual.index(' or ') + if False in listEqual[:ind]: + listEqual = listEqual[ind+1:] + continue + else: + return True + if False in listEqual: + return False + else: + return True + + + def _equalTerm(self, term, textError, function=False): + """Вычисление логических выражений для условий + + Для корректной работы в классе который наследует этот класс + должен быть объявлен аттрибут self.objVar + (объект для работы с переменными) + function - функция для для обработки функций в заголовке блока + """ + trm = {"&&":" and ","||":" or "} + rule = ["==", "!=", ">=", "<=", ">", "<"] + listEqual = [] + for k in trm.keys(): + if k in term: + term = term.replace(k,trm[k]) + trs = term.split(" ") + for t in trs: + flagRule = False + for sepF in rule: + if sepF in t: + flagRule = True + vals = t.split(sepF) + break + + if not flagRule: + flagLog = False + for k in trm.values(): + if k.strip() == t: + flagLog = True + break + if not flagLog: + self.setError("'%s'"%term + " " + _("incorrect")) + self.setError (textError) + return False + elif k == " or ": + listEqual.append(k) + else: + #проверка на допустимость названия переменной + reDenyName = re.compile("[^a-zA-Z0-9\_\-]") + flagFunction = False + if reDenyName.search(vals[0]): + #проверка на допустимость функции + flagError = True + if function: + reFunction = re.compile(\ + "([a-zA-Z0-9\_\-]+)\([a-zA-Z0-9_\-\+\,\*\/\.]+\)") + searchFunct = reFunction.search(vals[0]) + if searchFunct: + flagError = False + flagFunction = True + if flagError: + self.setError("'%s'"%term + " " + _("incorrect")) + self.setError(textError) + return False + #проверка на допустимость значения + reDenyValue = re.compile("[^0-9a-zA-Z_\.-]") + if reDenyValue.search(vals[1]): + self.setError("'%s'"%term + " " + _("incorrect")) + self.setError(textError) + return False + flagIntTypeVar = None + if flagFunction: + valVars = function("#-%s-#"%vals[0]) + if valVars == "": + flagFunction = False + if valVars == False: + self.setError("'%s'"%term + " " + _("incorrect")) + self.setError(textError) + return False + if "load" == searchFunct.group(1): + if re.search("\(\s*num\s*,",vals[0]): + if valVars: + try: + valVars = int(valVars) + except: + self.setError("'%s'"%term + " " + \ + _("incorrect")) + self.setError (textError) + return False + flagIntTypeVar = True + else: + flagIntTypeVar = False + else: + try: + valVars = self.objVar.Get(vals[0]) + except self.objVar.DataVarsError, e: + print textError + print e + exit(1) + # Cравниваем номера версий + if "_ver" in vals[0] or \ + (flagFunction and "pkg" == searchFunct.group(1)) or\ + (flagFunction and "load" == searchFunct.group(1) and\ + re.search("\(\s*ver\s*,",vals[0])): + verFile, verVar = self._convertVers(vals[1],valVars) + exec("res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")") + if res: + listEqual.append(True) + else: + listEqual.append(False) + else: + if flagIntTypeVar == None: + flagIntTypeVar = True + try: + valVars = int(valVars) + except: + flagIntTypeVar = False + if flagIntTypeVar: + if not vals[1].strip(): + vals[1] = 0 + try: + valFile = int(vals[1]) + except: + self.setError("'%s'"%term + " " + _("incorrect")) + self.setError (textError) + return False + valVar = valVars + exec("res=(%d%s%d)"%(valVar,sepF,valFile)) + if res: + listEqual.append(True) + else: + listEqual.append(False) + else: + if sepF == "!=" or sepF == "==": + if not vals[1].strip(): + vals[1] = "" + valFile = vals[1] + valVar = valVars + exec("res=("+'"""'+valVar+'"""'+sepF+"'"+valFile+\ + "'"+")") + if res: + listEqual.append(True) + else: + listEqual.append(False) + else: + if valVars == "": + listEqual.append(False) + else: + self.setError("'%s'"%term + " "\ + + _("incorrect")) + self.setError (textError) + return False + #exec("res=(%s)"%("".join(listEqual))) + res = self.executeListEqual(listEqual) + return res + + +class shareHeader: + """Общие методы для обработки заголовков""" + reSplParHeader = re.compile("\s+",re.I) + reHeader=re.compile(r"\A\s*#\s*calculate(\s+)?\\?([^\\\n]*\\\n)+[^\\\n]*\n?\ +|\s*#\s*calculate\s+([^\\\n]*\n?)",re.I|re.M) + + def getHeader(self, text): + """Получаем результат поиска и заголовок файла""" + sHeader = self.reHeader.search(text) + if sHeader: + return (sHeader, sHeader.group()) + else: + return (False, "") + + def getParamsHeader(self, textHeader): + """Получаем параметры заголовка в виде списка""" + listParams = self.reSplParHeader.split(textHeader.replace("\\"," ")) + if listParams[0] == "#": + return filter(lambda x: x, listParams[2:]) + else: + return filter(lambda x: x, listParams[1:]) + +class fileHeader(shareHeader, _terms): + """Обработка заголовков шаблонов и конфигурационных файлов + + """ + # Допустимые параметры заголовка + allowParam = ("format", "comment", "append", "force", "link", "mirror", + "symbolic", "chmod", "chown", "path", "name") + + # параметры без значения + listParNotVal = ("symbolic", "force", "mirror") + + # Возможные типы вставки шаблонов + _fileAppend = ("join", "before", "after", "replace", "remove", "skip") + + + # условные операторы + terms = ('>', '<', '==', '!=', '>=', '<=') + + # параметры без значения + #listParNotVal = ("symbolic", "force", "mirror") + # Форматы файлов для которых метод объединения replace если он не задан + #replaceFormats = ("raw","bin") + + def delHeaderConfFile(self, text, comment): + """Удаляет заголовок в тексте конфигурационного файла""" + if comment and text: + # Удаление Заголовка Calculate в конфигурационном файле + # В случае текста XML + if type(comment) == types.TupleType and len(comment) == 2: + _titleList = (_("Modified"), _("File of a template")) + reCalcHeader =\ + re.compile(u"\s*%s\s+%s.+Calculate.+\s+%s.+\s+%s\s?"%(\ + comment[0], + _titleList[0].decode("UTF-8"), + _titleList[1].decode("UTF-8"), + comment[1], + ), + re.M|re.I|re.U) + textUnicode = text.decode("UTF-8") + reS = reCalcHeader.search(textUnicode) + if reS: + textBody = textUnicode[:reS.start()]+textUnicode[reS.end():] + if textBody: + return textBody.encode("UTF-8") + else: + # В остальных случаях + reCalcHeader =\ + re.compile("\s*%s\-+\s+%s.+Calculate.+\s+%s.+\s+%s\-+\s?"%(\ + comment, + comment, + comment, + comment, + ), + re.M|re.I) + reS = reCalcHeader.search(text) + if reS: + return text[reS.end():] + return text + + def getPropertyTemplate(self, textHeader, foundHeader, fileType, objVar, + function, fileName): + """Получаем свойства шаблона из текста заголовка шаблона""" + # Объект с переменными + self.objVar=objVar + # Параметры файла шаблона + params = {} + # Будет ли шаблон применен + headerTerm = True + # Бинарный шаблон + if fileType=="bin": + params["format"] = fileType + params["_position"] = 0 + params["append"] = "replace" + params["_apply"] = headerTerm + # текстовый шаблон с заголовком + elif foundHeader: + # некорректные параметры + incorrectParams = set([]) + # Получаем список параметров шаблона + paramList = self.getParamsHeader(textHeader) + if paramList: + errTerm = _("header template '%s' not valid")%fileName + for i in paramList: + foundTerm = False + for term in self.terms: + if term in i: + foundTerm = True + rezTerm = self._equalTerm(i, "%s: %s"%(errTerm,i), + function) + if not rezTerm: + headerTerm = False + break + if not foundTerm: + par = i.split("=") + if len(par) == 1: + ret = self.checkParams(i, None, params) + if not ret: + incorrectParams = set([i]) + break + elif len(par) == 2: + ret = self.checkParams(par[0], par[1], params) + if not ret: + incorrectParams = set([i]) + break + if not "format" in params: + # format - raw + params["format"] = "raw" + if not "append" in params: + params["append"] = "replace" + else: + if not "append" in params: + # в зависимости от формата - join или replace + formatTemplate = params["format"] + if formatTemplate in ("raw", "bin", ""): + params["append"] = "replace" + else: + params["append"] = "join" + if incorrectParams: + headerTerm = False + self.setError(_("incorrect header parameters - '%s'")\ + %" ".join(list(incorrectParams))) + params["_position"] = foundHeader.end() + params["_apply"] = headerTerm + # текстовый шаблон без заголовка + else: + params["format"] = "raw" + params["_position"] = 0 + params["append"] = "replace" + params["_apply"] = headerTerm + return params + + def checkParams(self, name, value, dictPar): + """Проверка параметра заголовка, при успехе запись в словарь dictPar""" + # Проверка на допустимые параметры заголовка + if not name in self.allowParam: + return False + if name in self.listParNotVal and not value is None: + return False + if name == "append": + if not value in self._fileAppend: + return False + dictPar[name] = value + return True + + + +class dirHeader(shareHeader, _terms): + """Обработка заголовков шаблонов директорий + + """ + # Допустимые параметры заголовка + allowParam = ("append", "chmod", "chown", "path", "name") + # Возможные типы вставки шаблонов + _fileAppend = ("join", "remove", "skip") + # условные операторы + terms = ('>', '<', '==', '!=', '>=', '<=') + + + def getPropertyTemplate(self, text, objVar, function, fileName): + """Получаем свойства шаблона из текста шаблона""" + # Объект с переменными + self.objVar=objVar + # Параметры описанные в заголовке файла шаблона + params = {} + # Некорректные параметры + incorrectParams = set([]) + # Будет ли шаблон применен + headerTerm = True + foundHeader, textHeader = self.getHeader(text) + if foundHeader: + paramList = self.getParamsHeader(textHeader) + if paramList: + errTerm = _("header template '%s' not valid")%fileName + for i in paramList: + foundTerm = False + for term in self.terms: + if term in i: + foundTerm = True + rezTerm = self._equalTerm(i, "%s: %s"%(errTerm,i), + function) + if not rezTerm: + headerTerm = False + break + if not foundTerm: + par = i.split("=") + if len(par) == 1: + ret = self.checkParams(i, None, params) + if not ret: + incorrectParams = set([i]) + break + elif len(par) == 2: + ret = self.checkParams(par[0], par[1], params) + if not ret: + incorrectParams = set([i]) + break + if not "append" in params: + # По умолчанию join + params["append"] = "join" + if incorrectParams: + headerTerm = False + self.setError(_("incorrect header parameters - '%s'")\ + %" ".join(list(incorrectParams))) + params["_apply"] = headerTerm + # текстовый шаблон без заголовка + else: + headerTerm = False + self.setError(_("Can not found header in template")) + params["_apply"] = headerTerm + return params + + def checkParams(self, name, value, dictPar): + """Проверка параметра заголовка, при успехе запись в словарь dictPar""" + # Проверка на допустимые параметры заголовка + if not name in self.allowParam: + return False + if name == "append": + if not value in self._fileAppend: + return False + if value is None: + return False + dictPar[name] = value + return True + + +class objShare: + """Общий клас для объектов, наследуем + + """ + + def createFieldTerm(self, name, value, quote, docObj): + """Создание поля переменная - значение + + при создании поля проверяется первый символ названия переменной + и добавляется тег action + "!" - 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(_toUNICODE(text)) + element.appendChild(txtNode) + for attr in attributes.keys(): + attribute = doc.createAttribute(attr) + attribute.nodeValue = attributes[attr] + element.setAttributeNode(attribute) + return element + + +class xmlNode(xmlShare): + """Класс для создания нод без аттрибутов + + """ + def __init__(self): + self.node = False + + + def createNode(self, doc, tagName, text=""): + """Создает XML элемент без аттрибутов""" + self.node=self._createElement(doc, tagName, text) + return self.node + + def getNode(self): + return self.node + + +class xmlCaption: + """Класс XML заголовок + + """ + def __init__(self): + #Заголовок области XML нода + self.caption = False + + def createCaption(self, doc, name, quotes, action=False): + """Создание заголовка области""" + tmpNode = xmlNode() + self.caption = tmpNode.createNode(doc, "caption") + nameNode = tmpNode.createNode(doc, "name",name) + self.caption.appendChild(nameNode) + if action: + actNode = tmpNode.createNode(doc, "action", action) + self.caption.appendChild(actNode) + for q in quotes: + quoteNode = tmpNode.createNode(doc, "quote", q) + self.caption.appendChild(quoteNode) + return self.caption + + def getCaption(self): + """Выдает XML ноду заголовка области""" + return self.caption + +class xmlField(xmlShare): + """Класс для работы с XML полем + + """ + def __init__(self): + # XML нода поле + self.field = False + + + def createField(self, doc, typeField, quotes, name="", + values=[],action=False): + """Cоздание XML ноды поле""" + self.field = self._createElement(doc, "field", "", {"type":typeField}) + if name: + nameNode = self._createElement(doc, "name", name) + self.field.appendChild(nameNode) + for v in values: + valueNode = self._createElement(doc, "value", v) + self.field.appendChild(valueNode) + if action: + actNode = self._createElement(doc, "action", action) + self.field.appendChild(actNode) + for q in quotes: + quoteNode = self._createElement(doc, "quote", q) + self.field.appendChild(quoteNode) + return self.field + + + +class xmlFields: + """Класс, в котором находится список ХМL нод field + + """ + def __init__(self): + self.fields = [] + + def appendField(self, field): + """Добавить XML ноду field""" + self.fields.append(field) + return self.fields + + def getFields(self): + """Выдать список XML нод""" + return self.fields + + +class xmlArea: + """Класс для работы с XML областью + + """ + def __init__(self): + # Область + self.area = False + + def createArea(self, doc, xmlCaption, xmlFields): + """Создание XML области""" + tmpNode = xmlNode() + self.area = tmpNode.createNode(doc, "area") + if xmlCaption and xmlCaption.getCaption(): + self.area.appendChild(xmlCaption.getCaption()) + if xmlFields: + fields = xmlFields.getFields() + for field in fields: + self.area.appendChild(field) + return self.area + +class xmlDoc: + """Класс для работы с XML документом + + """ + def __init__(self): + # документ + self.doc = False + # главная нода + self.root = False + # тело документа + self.body = False + # Заголовок области - временный (в реальности один объект заголовок) + self.tmpCaption = False + # Поля - временные (в реальности один объект поля) + self.tmpFields = False + # Разделитель областей - по умолчанию перевод строки "\n" + self.sepAreas = False + # Разделитель разделенных списков - по умолчанию перевод строки "\n" + #self.sepSplitFields = False + + + def createDoc(self, typeDoc, version): + """Создание нового документа новый документ""" + docTxt = '' + 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 + i += 1 + if lenTail>1 and lenTail != i: + return (False,1) + if i > 0: + result = True + return (result, i) + + def encode(self, text): + """Кодирует смешанный формат в UTF-8""" + ind = 0 + l = 0 + utf = [] + lenUtf = [] + indErr = [] + i = 0 + for ch in text: + r, l = self._retUTF(ch) + utf.append(r) + lenUtf.append(l) + i+=1 + while 1: + if utf[ind] == '_fb_': + res, l = self._sumbUtf(utf[ind:(ind+lenUtf[ind])],lenUtf[ind]) + if res == False: + indErr.append(ind) + if l>0: + ind +=l + if ind >= len(utf): + break + else: + if utf[ind] != '_ch_': + indErr.append(ind) + ind +=1 + if ind >= len(utf): + break + if indErr: + lenIndErr = len(indErr) + block = [] + blocks = [] + if lenIndErr > 1: + i = 1 + while 1: + if i == 1: + block.append(indErr[i-1]) + if indErr[i] - indErr[i-1] == 1: + block.append(indErr[i]) + else: + if block: + blocks.append(block) + block = [] + block.append(indErr[i]) + i +=1 + if i >= lenIndErr: + break + else: + block.append(indErr[0]) + if block: + blocks.append(block) + listErr = [] + for block in blocks: + string = "" + for elem in block: + string += hex(ord(text[elem]))[-2:] + listErr.append((block[0],"__hex__?%s?__hex__" %string,elem)) + textOut = text + deltaInd = 0 + for erEl in listErr: + startInd = erEl[0] + deltaInd + endInd = erEl[2] + 1 + deltaInd + textOut = textOut[:startInd] + erEl[1] + textOut[endInd:] + deltaInd += len(erEl[1])-(erEl[2]-erEl[0]+1) + return textOut + + def decode(self, text): + """Декодирует UTF-8 в смешанный формат""" + varStart = "__hex__\?" + varEnd = "\?__hex__" + # -1 Это экранирование '?' которое тоже считается + deltVarStart = len(varStart)-1 + deltVarEnd = len(varEnd)-1 + reVar = re.compile(("%s[a-f0-9]+%s")%(varStart,varEnd),re.M) + resS = reVar.search(text) + textTemplateTmp = text + while resS: + mark = textTemplateTmp[resS.start():resS.end()] + hexString = mark[deltVarStart:-deltVarEnd] + i = 0 + stringInsert = "" + hexCode = "" + for ch in hexString: + if i>=1: + hexCode += ch + stringInsert += chr(int(hexCode, 16)) + hexCode = "" + i = 0 + else: + hexCode += ch + i += 1 + textTemplateTmp = textTemplateTmp.replace(mark, stringInsert) + resS = reVar.search(textTemplateTmp) + return textTemplateTmp + +class template(_file, _terms, xmlShare): + """Класс для работы с шаблонами + + На вход 2 параметра: объект хранения переменных, имя сервиса - не + обязательный параметр + + """ + # Импортированные классы поддерживаемых форматов шаблонов + importFormats = {} + # Имена установленных программ + installProg = [] + # Версии установленных программ + installProgVersions = [] + # кеш вызванных значений программа, номер версии + cacheInstallProg = {} + # Название файла шаблона директории + templDirNameFile = ".calculate_directory" + + def __init__(self, objVar, dirsFilter=[], filesFilter=[]): + # Необрабатываемые директории + self.dirsFilter = dirsFilter + # Необрабатываемые файлы + self.filesFilter = filesFilter + _file.__init__(self) + # Словарь для создания объектов новых классов по образцу + # (proftpd создается на основе apache) + self.newObjProt = {'proftpd':'apache'} + # Заголовок title + self.__titleHead = "--------------------------------------\ +----------------------------------------" + self._titleBody = "" + self._titleList = (_("Modified"), _("File of a template")) + + # Метки + varStart = "#-" + varEnd = "-#" + self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")%(varStart,varEnd),re.M) + self._reFunc = re.compile(("%s[a-zA-Z0-9_\-\+\(\)\, \*\/\.]+%s")\ + %(varStart,varEnd),re.M) + self._deltVarStart = len(varStart) + self._deltVarEnd = len(varEnd) + # Условия + self._reTermBloc = re.compile("#\?(?P[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 = "" + + def __octToInt(self, strOct): + """Преобразование восьмеричного в целое (ввод строка, вывод число)""" + if strOct: + z = 0 + i = 0 + lst = list(strOct) + lst.reverse() + for ch in lst: + try: + v = int(ch) + except: + self.setError(_("Not valid oct value: ") + str(strOct)) + return False + if v > 7: + self.setError (_("Not valid oct value: ") + str(strOct)) + return False + z = z + v*8**i + i = i +1 + return z + else: + self.setError (_("Empty oct value")) + return False + + def getFormatObj(self, formatTemplate, textTemplate): + """Создание объекта формата шаблона. + + Объект создается на основании формата шаблона и текста шаблона""" + if formatTemplate in self.importFormats: + classFormat = self.importFormats[formatTemplate] + else: + try: + classFormat = getattr(__import__("format.%s"%formatTemplate, + globals(), locals(), + [formatTemplate]), + formatTemplate) + except (ImportError, AttributeError): + #Создаем объект из self.newObjProt с помощью + # метаклассов + if formatTemplate in self.newObjProt: + # Прототип класса + nameProt = self.newObjProt[formatTemplate] + try: + classProt = getattr(__import__("format.%s"%nameProt, + globals(), locals(), + [nameProt]), + nameProt) + except (ImportError, AttributeError): + return False + newCl = self.createNewClass(formatTemplate, (classProt,)) + self.importFormats[formatTemplate] = newCl + return newCl(textTemplate) + else: + return False + self.importFormats[formatTemplate] = classFormat + return classFormat(textTemplate) + + def removeDir(self, rmDir): + """Рекурсивное удаление директории + + входной параметр директория + """ + if not os.path.exists(rmDir): + self.printERROR(_("Not found remove dir %s") %rmDir) + return False + fileObj = _file() + # Сканируем директорию + scanObjs = fileObj.scanDirs([rmDir]) + for socketRm in scanObjs[0].sockets: + # Удаляем сокеты + if os.path.exists(socketRm): + os.remove(socketRm) + for linkRm in scanObjs[0].links: + # Удаляем ссылки + os.unlink(linkRm[1]) + for fileRm in scanObjs[0].files: + # Удаляем файлы + os.remove(fileRm) + scanObjs[0].dirs.sort(lambda x, y: cmp(len(y), len(x))) + for dirRm in scanObjs[0].dirs: + # Удаляем директории + os.rmdir(dirRm) + if rmDir: + os.rmdir(rmDir) + return True + + + def createConfFile(self, pathTemplate, path=False): + """Создает конфигурационный файл если его нет""" + # Создаем директорию если ее нет + if not path: + path = os.path.split(pathTemplate)[0] + if not os.path.exists(path): + createDirs = self.createDir(path) + if not createDirs: + self.setError (_("Can not create file:" ) + pathTemplate) + return False + # Создаем файл если его нет + if not os.path.exists(pathTemplate): + try: + dMode, uid, gid = self.getModeFile(path) + #mode = dMode & ~0111 + # Создаем файл + open(pathTemplate,"w").close() + #os.chmod(pathTemplate, mode) + os.chown(pathTemplate, uid, gid) + except: + self.setError (_("Can not create file:" ) + pathTemplate) + return False + return True + + def createDir(self, dirName, mode=False, uid=False, gid=False): + """Создает директорию""" + if os.access(dirName, os.F_OK): + return [dirName] + else: + dMode = False + prevDir, tmpSubdir = os.path.split(dirName) + createDirs = [] + while not os.access(prevDir, os.F_OK): + createDirs.append(prevDir) + prevDir = os.path.split(prevDir)[0] + try: + tmpMode,dUid,dGid = self.getModeFile(prevDir) + except OSError: + self.setError (_("Not access dir: " ) + prevDir) + return False + if not mode is False: + dMode = mode + if not uid is False: + dUid = uid + if not gid is False: + dGid = gid + createDirs.reverse() + for nameDir in createDirs: + try: + if dMode: + os.mkdir(nameDir, dMode) + else: + os.mkdir(nameDir) + os.chown(nameDir, dUid, dGid) + except: + self.setError (_("Can not create dir: " ) + nameDir) + return False + try: + if dMode: + os.mkdir(dirName, dMode) + else: + os.mkdir(dirName) + os.chown(dirName, dUid, dGid) + createDirs.append(dirName) + except: + self.setError (_("Can not create dir: " ) + dirName) + return False + return createDirs + + + def applyVarsTemplate(self, textTemplate, nameTemplate): + """ Заменяет переменные на их значения + """ + resS = self._reVar.search(textTemplate) + textTemplateTmp = textTemplate + while resS: + mark = textTemplateTmp[resS.start():resS.end()] + varName = mark[self._deltVarStart:-self._deltVarEnd] + varValue = "" + try: + varValue = str(self.objVar.Get(varName)) + except self.objVar.DataVarsError, e: + print _("error in template %s")%nameTemplate + print e + exit(1) + textTemplateTmp = textTemplateTmp.replace(mark, varValue) + resS = self._reVar.search(textTemplateTmp) + return textTemplateTmp + + + def applyFuncTemplate(self, textTemplate, nameTemplate): + """ Применяет функции к тексту шаблона + """ + def equalTerm(term, sNum, sMD, localVars): + """Локальная функция для вычисления выражения""" + terms = sNum.findall(term) + if terms: + strNumers = [] + for n in terms: + strNum = n.strip() + if "*" in strNum or "/" in strNum: + strNum = multAndDiv(strNum,sNum,sMD,localVars) + try: + num = int(strNum) + except: + minus = False + if strNum[:1] == "-": + minus = True + strNum = strNum[1:] + if localVars.has_key(strNum): + num = localVars[strNum] + elif self.objVar.exists(strNum): + try: + num = int(self.objVar.Get(strNum)) + except: + print _("error in template %s")%nameTemplate + print _("error var %s not int")%str(strNum) + exit(1) + else: + print _("error in template %s")%nameTemplate + print _("error local var %s not defined")\ + %str(strNum) + exit(1) + if minus: + num =-num + strNumers.append(num) + return sum(strNumers) + print _("error in template %s")%nameTemplate + print _("error template term %s, incorrect data")%str(term) + exit(1) + + def multAndDiv(term,sNum,sMD,localVars): + """локальная функция для умножения и деления""" + termTmp = term + varsLocal = sMD.findall(term) + for var in varsLocal: + flagVarTxt = True + try: + int(var) + except: + flagVarTxt = False + if flagVarTxt: + continue + varReplace = str(equalTerm(var,sNum,sMD,localVars)) + termTmp = termTmp.replace(var,varReplace) + ret = eval(termTmp) + return ret + + def funcSum(funTxt,resS,localVars,textTemplateTmp): + """локальная функция вычисляет первую функцию sum() в шаблоне""" + terms = funTxt[4:-1].replace(" ","").split(",") + # Название локальной переменной + nameLocVar = terms[0] + if not localVars.has_key(nameLocVar): + localVars[nameLocVar] = 0 + if len(terms) == 2: + if terms[1].strip(): + localVars[nameLocVar] = equalTerm(terms[1],sNum,sMD, + localVars) + replace = str(localVars[nameLocVar]) + else: + replace = "" + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + elif len(terms) == 3: + if terms[1].strip(): + replaceInt = equalTerm(terms[1],sNum,sMD,localVars) + replace = str(replaceInt) + else: + replace = "" + localVars[nameLocVar] = equalTerm(terms[2], + sNum,sMD,localVars) + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + else: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + exit(1) + return textTemplateTmp + + def funcLoad(funTxt,resS,textTemplateTmp): + """если файл существует читает из файла локальную переменную + + если один параметр - выводит значение локальной переменной + """ + terms = funTxt[5:-1].replace(" ","").split(",") + if not terms[0].strip() or\ + (len(terms)==2 and not terms[1].strip()) or\ + len(terms)>2: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + exit(1) + if len(terms) == 2: + if not terms[0] in ["ver","num","char","key"]: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + print _("first argument function is not 'ver' or 'num' or\ + 'char'") + exit(1) + if len(terms) == 1: + fileName = terms[0].strip() + if fileName[0] != "/": + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + print _("incorrect path %s")%fileName + exit(1) + else: + fileName = terms[1].strip() + if fileName[0] != "/": + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + print _("incorrect path %s")%fileName + exit(1) + replace = "" + if os.path.exists(fileName): + FD = open(fileName) + replace = FD.read().strip() + FD.close + if not replace and len(terms) == 2 and terms[0] in ["ver","num"]: + replace = "0" + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + return textTemplateTmp + + def getInstallPkgGentoo(names = [], versions = []): + """Выдает два списка, инсталлированные программы и номера версий""" + baseDir = "/var/db/pkg" + pkgs = [] + reVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*") + def getFilesDir(pkgs, dirname, names): + for nameFile in names: + absNameFile = os.path.join(dirname,nameFile) + if os.path.isdir(absNameFile): + tail = absNameFile.split(baseDir) + if len(tail)==2: + tail = tail[1].split('/') + if len(tail)==3 and tail[1]!='virtual': + pkgs.append(tail[2]) + return True + os.path.walk(baseDir,getFilesDir, pkgs) + pkgs.sort() + for pkg in pkgs: + findVer = reVer.search(pkg) + if findVer: + ver = findVer.group() + versions.append(ver) + names.append(pkg.split(ver)[0][:-1]) + #return pkgs + return names, versions + + def pkg(nameProg, names, versions): + """Выдает установленные версии по имени программы""" + # Значение версии из кеша + if nameProg in self.cacheInstallProg: + return self.cacheInstallProg[nameProg] + i = 0 + vers = [] + for name in names: + if nameProg == name: + while nameProg == names[i]: + vers.append(versions[i]) + i += 1 + break + i += 1 + if vers: + version = vers[-1] + # Запись значения версии в кеш + self.cacheInstallProg[nameProg] = version + return version + else: + return "" + + def funcPkg(funTxt,resS,textTemplateTmp): + """локальная функция выдает номер версии программы""" + terms = funTxt[4:-1].replace(" ","") + # Название программы + nameProg = terms + if not self.installProg: + # Получение всех названий и версий установленных программ + self.installProg,self.installProgVersions =\ + getInstallPkgGentoo(names=self.installProg, + versions=self.installProgVersions) + replace = pkg(nameProg,self.installProg,self.installProgVersions) + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + return textTemplateTmp + + def funcRnd(funTxt,resS,textTemplateTmp): + """локальная функция выдает строку случайных символов + + первый аргумент: + 'num' - числа, + 'pas' - цифры и буквы + второй аргумент: + количество символов + """ + terms = funTxt[4:-1].replace(" ","").split(",") + if not terms[0].strip() or\ + (len(terms)==2 and not terms[1].strip()) or\ + len(terms)!=2: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + exit(1) + fArgvNames = ['num','pas'] + if not terms[0] in fArgvNames: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + print _("first argument function is not 'num' or 'pas'") + exit(1) + try: + lenStr = int(terms[1]) + except: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + print _("two argument function is not number") + exit(1) + if terms[0] == fArgvNames[0]: + replace=''.join([random.choice(string.digits)\ + for i in xrange(lenStr)]) + elif terms[0] == fArgvNames[1]: + replace=''.join([random.choice(string.ascii_letters + \ + string.digits) for i in xrange(lenStr)]) + else: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + exit(1) + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + return textTemplateTmp + + def funcCase(funTxt,resS,textTemplateTmp): + """локальная функция выдает переменную в определенном регистре + + первый аргумент: + 'upper' - верхний регистр, + 'lower' - нижний регистр, + 'capitalize' - первая буква в верхнем регистре + второй аргумент: + название переменной + """ + terms = funTxt[5:-1].replace(" ","").split(",") + if not terms[0].strip() or\ + (len(terms)==2 and not terms[1].strip()) or len(terms)!=2: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + exit(1) + fArgvNames = ['upper','lower','capitalize'] + if not terms[0] in fArgvNames: + print _("error in template %s")%nameTemplate + print _("error template term %s")%str(funTxt) + print _("first argument function is not 'upper' or 'lower' or\ + 'capitalize'") + exit(1) + try: + strValue = str(self.objVar.Get(terms[1])) + except: + print _("error in template %s")%nameTemplate + print _("error var %s not found")%str(terms[1]) + exit(1) + replace = "" + strValue = _toUNICODE(strValue) + if terms[0] == 'upper': + replace = strValue.upper() + elif terms[0] == 'lower': + replace = strValue.lower() + elif terms[0] == 'capitalize': + replace = strValue.capitalize() + if replace: + replace = replace.encode("UTF-8") + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + return textTemplateTmp + + # Локальные переменные + localVars = {} + # Регулярное выражние для сложения + sNum = re.compile("\-[^\-\+]+|[^\-\+]+") + # Регулярное выражение для умножениея и деления + sMD = re.compile("[^\-\+\*\/]+") + resS = self._reFunc.search(textTemplate) + textTemplateTmp = textTemplate + while resS: + mark = textTemplateTmp[resS.start():resS.end()] + funTxt = mark[self._deltVarStart:-self._deltVarEnd] + # Функция sum + if funTxt[:4] == "sum(": + textTemplateTmp = funcSum(funTxt,resS,localVars,textTemplateTmp) + resS = self._reFunc.search(textTemplateTmp) + # Функция load + elif funTxt[:5] == "load(": + textTemplateTmp = funcLoad(funTxt,resS,textTemplateTmp) + resS = self._reFunc.search(textTemplateTmp) + elif funTxt[:4] == "pkg(": + textTemplateTmp = funcPkg(funTxt,resS,textTemplateTmp) + resS = self._reFunc.search(textTemplateTmp) + elif funTxt[:4] == "rnd(": + textTemplateTmp = funcRnd(funTxt,resS,textTemplateTmp) + resS = self._reFunc.search(textTemplateTmp) + elif funTxt[:5] == "case(": + textTemplateTmp = funcCase(funTxt,resS,textTemplateTmp) + resS = self._reFunc.search(textTemplateTmp) + else: + resS = False + return textTemplateTmp + + def applyTermsTemplate(self,textTemplate,nameTemplate,nameSystemFile=False): + """ Применяет условия, к условным блокам текста + """ + textTerm = "" + resS = self._reTermBloc.search(textTemplate) + textTemplateTmp = textTemplate + def function(text): + """Функция обработки функций в заголовке""" + return self.applyFuncTemplate(text, nameTemplate) + if nameSystemFile: + while resS: + mark = resS.group(0) + body = resS.group("body") + end = resS.group("end") + parent = resS.group("func") + if not parent: + parent = "" + term = resS.group("rTerm") + parent +\ + resS.group("lTerm") + if self._equalTerm(term, _("content template not valid: ")+\ + nameTemplate, function): + textTemplateTmp = textTemplateTmp.replace(mark, body+end) + else: + textTemplateTmp = textTemplateTmp.replace(mark, "") + resS = self._reTermBloc.search(textTemplateTmp) + else: + while resS: + mark = resS.group(0) + body = resS.group("body") + end = resS.group("end") + term = resS.group("rTerm") + resS.group("lTerm") + if self._equalTerm(term, _("content template not valid: ")+\ + nameTemplate): + textTemplateTmp = textTemplateTmp.replace(mark, body+end) + else: + textTemplateTmp = textTemplateTmp.replace(mark, "") + resS = self._reTermBloc.search(textTemplateTmp) + return textTemplateTmp + + def getTitle(self, comment, commentList): + """Выдает заголовок шаблона ( версия и.т.д)""" + if comment: + commentFirst = comment + commentInsert = comment + commentLast = comment + flagList = False + # В случае открывающего и закрывающего комментария + if type(comment) == types.TupleType and len(comment) == 2: + commentFirst = comment[0] + commentInsert = "" + commentLast = comment[1] + flagList = True + if flagList: + self._titleBody = commentFirst + "\n" + else: + self._titleBody = commentFirst + self.__titleHead + "\n" + z = 0 + lenCommentList = len(commentList) - 1 + for com in self._titleList: + if lenCommentList < z: + self._titleBody += commentInsert + " " + com + "\n" + else: + self._titleBody += commentInsert + " " + com +\ + " " + commentList[z] + "\n" + z += 1 + if flagList: + self._titleBody += commentLast +"\n" + else: + self._titleBody += commentLast + self.__titleHead + "\n" + return self._titleBody + else: + return "" + + def numberAllTemplates(self, number): + """Количество шаблонов + + Вызов происходит перед наложением шаблонов + в момент вызова в number находится количество обрабатываемых файлов + Наследуемая функция + Используется для отображения прогресса при наложениии шаблонов + """ + return True + + def numberProcessTemplates(self, number): + """Номер текущего обрабатываемого шаблона + + Вызов происходит при наложении шаблона + в момент вызова в number находится номер обрабатываемого шаблона + Наследуемая функция + Используется для отображения прогресса при наложениии шаблонов + """ + return True + + def __clearInErrorDirObj(self, dirObj): + """Очищает объект директории при ошибке""" + # директории [(путь к директории, свойства директории)...] + dirObj.dirs = [] + # файлы [(путь к файлу, свойства файла)...] + dirObj.files = [] + # Ошибка + dirObj.flagError = True + return dirObj + + def __scanDir(self, templatesDir, dirObj, dirProperties=()): + """Измененное cканирование одной директории""" + # сканирование файлов и директорий (следующие сканирования) + if dirProperties: + # Выход при ошибке + if dirObj.flagError: + return dirObj + dirName, prop = dirProperties + # В случае удаления не смотрим внутренние директории + if "append" in prop and prop["append"] == "remove": + return dirObj + filesOrDirs = os.listdir(dirName) + # Сортируем файлы и директории + filesOrDirs.sort() + # Добавляем директорию и ее свойства + dirObj.dirs.append((dirName, prop)) + if self.templDirNameFile in filesOrDirs: + # Удаляем файл описания директории из списка файлов + filesOrDirs.remove(self.templDirNameFile) + for fileOrDir in filesOrDirs: + # Выход при ошибке + if dirObj.flagError: + return dirObj + absPath = os.path.join(dirName,fileOrDir) + statInfo = os.stat(absPath)[stat.ST_MODE] + if stat.S_ISREG(statInfo): + # Свойства файла + propF, applyFile=self.__isApplyHeadTemplate(dirObj.fHeadObj, + absPath) + if self.getError(): + self.setError(_("Incorrect template: " ) + absPath) + return self.__clearInErrorDirObj(dirObj) + if not applyFile: + continue + # Обработка skip + if "append" in propF and propF["append"] == "skip": + continue + if not "path" in propF: + propF["path"] = prop["_real_path"] + if not "name" in propF: + propF["name"] = os.path.split(absPath)[1] + propF["_real_path"] = os.path.join(propF["path"], + propF["name"]) + dirObj.files.append((absPath, propF)) + elif stat.S_ISDIR(statInfo): + # Информация о директории + pDir = {} + # Файл информации о директории + dirInfoFile = os.path.join(absPath, + self.templDirNameFile) + if os.path.exists(dirInfoFile) and\ + stat.S_ISREG(os.stat(dirInfoFile)[stat.ST_MODE]): + # Настройки директории и применение + pDir, applyDir = self.__isApplyHeadDir(dirObj.dHeadObj, + dirInfoFile) + if self.getError(): + self.setError(_("Incorrect template: " ) +\ + dirInfoFile) + return self.__clearInErrorDirObj(dirObj) + if not applyDir: + continue + if not "path" in pDir: + pDir["path"] = prop["_real_path"] + if not "name" in pDir: + pDir["name"] = os.path.split(absPath)[1] + # Обработка skip + if "append" in pDir and pDir["append"] == "skip": + pDir["_real_path"] = pDir["path"] + else: + pDir["_real_path"] = os.path.join(pDir["path"], + pDir["name"]) + self.__scanDir(False, dirObj, (absPath, pDir)) + return dirObj + # Сканирование для получения настроек директории (первое) + else: + if templatesDir and stat.S_ISDIR(os.stat(templatesDir)[stat.ST_MODE]): + # настройки директории + pDir = {} + # Файл информации о директории + dirInfoFile = os.path.join(templatesDir, self.templDirNameFile) + if os.path.exists(dirInfoFile) and\ + stat.S_ISREG(os.stat(dirInfoFile)[stat.ST_MODE]): + # Настройки директории и применение + pDir,applyDir = self.__isApplyHeadDir(dirObj.dHeadObj, + dirInfoFile) + if self.getError(): + self.setError(_("Incorrect template: " ) +\ + dirInfoFile) + return self.__clearInErrorDirObj(dirObj) + if not applyDir: + return dirObj + if not "path" in pDir: + pDir["path"] = "/" + if not "name" in pDir: + pDir["name"] = os.path.split(templatesDir)[1] + # Обработка skip + if "append" in pDir and pDir["append"] == "skip": + pDir["_real_path"] = pDir["path"] + else: + pDir["_real_path"] = os.path.join(pDir["path"], + pDir["name"]) + self.__scanDir(False, dirObj, (templatesDir, pDir)) + return dirObj + + + def scanDirs(self, templatesDirs, objVar): + """Измененное cканирование директорий на вход список + + Выход список объктов _dir + """ + dirs = [] + # Объект заголовка файла + fHeadObj = fileHeader() + # Объект заголовка директории + dHeadObj = dirHeader() + # Объект переменных + for templateDir in templatesDirs: + dirP = scan._dir() + dirP.baseDir = templateDir + # Ошибка при сканировании + dirP.flagError = False + # Объект заголовка файла + dirP.fHeadObj = fHeadObj + # Объект заголовка директории + dirP.dHeadObj = dHeadObj + # Объект переменных + dirP.objVar = objVar + try: + self.__scanDir(templateDir, dirP) + except OSError, e: + print e.strerror, e.filename + self.__clearInErrorDirObj(dirP) + return [dirP] + if dirP.flagError: + return [dirP] + dirs.append(dirP) + return dirs + + def applyTemplates(self): + """Применяет шаблоны к конфигурационным файлам""" + if not self.objVar.defined("cl_template_path"): + self.setError (_("not defined Var: ") + "cl_template_path") + return False + dirsTemplates = self.objVar.Get("cl_template_path") + dirsTemplates.sort() + dirObjs = self.scanDirs(dirsTemplates,self.objVar) + #файлы к которым были применены шаблоны + filesApply = [] + #созданные директории + createdDirs = [] + # Получаем общее количество шаблонов (нужно для прогресбара) + allApplyFiles = self.scanTemplates(dirObjs) + if allApplyFiles == False: + return False + numberAllTemplates = len(allApplyFiles) + # Вызываем пустой метод с параметром общее количество шаблонов + self.numberAllTemplates(numberAllTemplates) + # номер обрабатываемого файла + numberProcessTemplates = 0 + # имя текущей программы + _nameProgram = self.objVar.Get("cl_name").capitalize() + # версия текущей программы + _versionProgram = self.objVar.Get("cl_ver") + # имя и версия текущей программы + programVersion = "%s %s"%(_nameProgram, _versionProgram) + # Объект обработки заголовков файлов шаблонов + fileHeadObj = fileHeader() + # Проверка на ошибки + for dirObj in dirObjs: + if dirObj.flagError: + return False + for dirObj in dirObjs: + # сортируем файлы по названию + if dirObj.files: + dirObj.files.sort() + # сортируем директории по названию + if dirObj.dirs: + dirObj.dirs.sort() + blockDirs = [] + propDir = {} + for dirTemplate, pDirs in dirObj.dirs: + # Получаем реальный путь директории + pathDir = pDirs["_real_path"] + # Фильтрация шаблонов по названию директории + if pathDir in self.dirsFilter: + blockDirs.append(dirTemplate) + continue + dirInfoFile = os.path.join(dirTemplate, self.templDirNameFile) + pathDir, propDir, crDirs = self.__getApplyHeadDir(pDirs) + if not propDir and self.getError(): + self.setError(_("Error in apply template: " ) +\ + dirInfoFile) + return False + if crDirs: + createdDirs += crDirs + for fileTemplate, propFile in dirObj.files: + findBlock = False + pathFile = propFile["_real_path"] + for blDir in blockDirs: + st,mid,end = pathFile.partition(blDir) + if (not st) and mid and end: + findBlock = True + break + if findBlock: + continue + numberProcessTemplates += 1 + self.numberProcessTemplates(numberProcessTemplates) + # Фильтрация шаблонов по названию файла + if pathFile in self.filesFilter: + continue + titleBaseDir = os.path.split(dirObj.baseDir)[0] + titlePath = fileTemplate.partition(titleBaseDir)[2] + templTitle = '"' + titlePath[1:] + '"' + # Записываем в переменную обрабатываемый файл + self.objVar.Set("cl_pass_file",pathFile) + filesApl = self.join(fileTemplate, propFile, + (programVersion,templTitle), fileHeadObj) + if filesApl: + filesApply += filesApl + else: + if self.getError(): + #print self.getError() + return False + self.closeFiles() + return (createdDirs, filesApply) + + def scanTemplates(self, dirObjs=False): + """Сканирует директории шаблонов - выводит список файлов""" + if not self.objVar.defined("cl_template_path"): + self.setError (_("not defined Var: ") + "cl_template_path") + return False + if not dirObjs: + dirsTemplates = self.objVar.Get("cl_template_path") + dirObjs = self.scanDirs(dirsTemplates, self.objVar) + #файлы к которым были применены шаблоны + filesApply = [] + # Проверка на ошибки + for dirObj in dirObjs: + if dirObj.flagError: + return False + for dirObj in dirObjs: + # сортируем файлы по названию + if dirObj.files: + dirObj.files.sort() + # сортируем директории по названию + if dirObj.dirs: + dirObj.dirs.sort() + blockDirs = [] + for dirTemplate, pDirs in dirObj.dirs: + pathDir = pDirs["_real_path"] + # Фильтрация шаблонов по названию директории + if pathDir in self.dirsFilter: + blockDirs.append(dirTemplate) + continue + for fileTemplate, propFile in dirObj.files: + findBlock = False + pathFile = propFile["_real_path"] + # Фильтрация файлов по названию директории + for blDir in blockDirs: + st,mid,end = pathFile.partition(blDir) + if (not st) and mid and end: + findBlock = True + break + if findBlock: + continue + # Фильтрация шаблонов по названию файла + if pathFile in self.filesFilter: + continue + filesApply.append(pathFile) + return filesApply + + + def __isApplyHeadDir(self, headerObj, templateDirFile): + """Будет ли применен шаблон корневой директории + + Возвращает: + (Настройки директории, и будет ли она применена (True, False)) + """ + # Настройки для директории + dPrefs = {} + + def function(text): + """Функция обработки функций в заголовке""" + return self.applyFuncTemplate(text, templateDirFile) + + if not os.path.exists(templateDirFile): + return (dPrefs, True) + try: + FD = open(templateDirFile) + textTemplate = FD.read() + FD.close() + except: + self.setError(_("Error open template: " ) + templateDirFile) + return (dPrefs, False) + # Заменяем переменные на их значения + textTemplate = self.applyVarsTemplate(textTemplate, templateDirFile) + # Обработка заголовка + propDir = headerObj.getPropertyTemplate(textTemplate,self.objVar, + function, templateDirFile) + if not propDir["_apply"]: + if headerObj.getError(): + self.setError(_("Incorrect template: " ) + templateDirFile) + return (dPrefs, False) + # Записываем настройки + dPrefs.update(propDir) + # Тип добавления + if dPrefs['append'] == "remove": + # Удаление конфигурационного файла + return (dPrefs, False) + # chmod - изменяем права + if "chmod" in dPrefs: + mode = self.__octToInt(dPrefs["chmod"]) + if mode: + dPrefs["chmod"] = mode + else: + self.setError (_("False value 'chmod' in template: " ) +\ + templateDirFile) + return (dPrefs, False) + # chown - изменяем владельца и группу + if "chown" in dPrefs: + owner = dPrefs["chown"] + uid = False + gid = False + if ":" in owner: + strUid, strGid = owner.split(":") + import pwd + try: + uid = pwd.getpwnam(strUid)[2] + except: + self.setError (_("Not user in this system: ") + strUid) + self.setError (_("False value 'chown' in template: " )+\ + templateDirFile) + return (dPrefs, False) + try: + import grp + gid = grp.getgrnam(strGid)[2] + except: + self.setError (_("Not group in this system: ")+strGid) + self.setError (_("False value 'chown' in template: " )+\ + templateDirFile) + return (dPrefs, False) + dPrefs["chown"] = [uid, gid] + else: + self.setError (_("False value 'chown' in template: " ) +\ + templateDirFile) + return (dPrefs, False) + # Проверяем path + if "path" in dPrefs and\ + (not dPrefs["path"] or not dPrefs["path"][0] == "/"): + self.setError (_("False value 'path' in template: " )+\ + templateDirFile) + return (dPrefs, False) + # Проверяем name + if "name" in dPrefs and\ + (dPrefs["name"] and dPrefs["name"][0] == "/"): + self.setError (_("False value 'name' in template: " )+\ + templateDirFile) + return (dPrefs, False) + return (dPrefs, True) + + def __getApplyHeadDir(self, dictPropDir): + """Применяет шаблон к директории (права, владелец, и.т. д)""" + newDirMv = dictPropDir["_real_path"] + applyDir = newDirMv + # Созданные директории + createDirs = [] + + if "append" in dictPropDir: + if dictPropDir["append"]=="skip": + return (applyDir, dictPropDir, createDirs) + # Удаляем директорию + elif dictPropDir["append"]=="remove": + if os.path.isdir(newDirMv): + # удаляем директорию + try: + self.removeDir(newDirMv) + except: + self.setError(_("Can not delete dir: " ) +\ + newDirMv) + return (applyDir, False, createDirs) + + # Флаг проверки существования директории + flagFoundDir = os.path.exists(newDirMv) + mode = False + uid = False + gid = False + # chmod - изменяем права + if "chmod" in dictPropDir: + mode = dictPropDir['chmod'] + if flagFoundDir: + os.chmod(newDirMv, mode) + # chown - изменяем владельца и группу + if "chown" in dictPropDir: + uid, gid = dictPropDir['chown'] + if flagFoundDir: + os.chown(newDirMv, uid, gid) + if not flagFoundDir: + createDirs = self.createDir(newDirMv, mode, uid, gid) + if not createDirs: + return (applyDir, False, createDirs) + return (applyDir, dictPropDir, createDirs) + + + def __isApplyHeadTemplate(self, headerObj, templateName): + """Будет ли применен файл шаблона + + Возвращает: + (Настройки файла, и будет ли он применен (True, False)) + """ + # Настройки для файла + fPrefs = {} + def function(text): + """Функция обработки функций в заголовке""" + return self.applyFuncTemplate(text, templateName) + + if not os.path.exists(templateName): + return (fPrefs, True) + try: + FD = open(templateName) + textTemplate = FD.read() + FD.close() + except: + self.setError(_("Error open template: " ) + templateName) + return (fPrefs, False) + # Бинарный или текстовый файл шаблона + templateType = self.getFileType(templateName) + foundHeader = False + textHeader = "" + if templateType != "bin": + # Получаем заголовок файла шаблона + foundHeader, textHeader = headerObj.getHeader(textTemplate) + # Заменяем переменные на их значения + textHeader = self.applyVarsTemplate(textHeader, templateName) + propFile = headerObj.getPropertyTemplate(textHeader, foundHeader, + templateType, self.objVar, + function,templateName) + if not propFile["_apply"]: + if headerObj.getError(): + self.setError(_("Incorrect template: " ) + templateName) + return (fPrefs, False) + if propFile["append"] == "remove": + # Удаление конфигурационного файла + return (propFile, False) + # Записываем настройки + fPrefs.update(propFile) + # chmod - изменяем права + if "chmod" in fPrefs: + mode = self.__octToInt(fPrefs["chmod"]) + if mode: + fPrefs["chmod"] = mode + else: + self.setError (_("False value 'chmod' in template: " ) +\ + templateName) + return (fPrefs, False) + # chown - изменяем владельца и группу + if "chown" in fPrefs: + owner = fPrefs["chown"] + uid = False + gid = False + if ":" in owner: + strUid, strGid = owner.split(":") + import pwd + try: + uid = pwd.getpwnam(strUid)[2] + except: + self.setError (_("Not user in this system: ") + strUid) + self.setError (_("False value 'chown' in template: " )+\ + templateName) + return (fPrefs, False) + try: + import grp + gid = grp.getgrnam(strGid)[2] + except: + self.setError (_("Not group in this system: ")+strGid) + self.setError (_("False value 'chown' in template: " )+\ + templateName) + return (fPrefs, False) + fPrefs["chown"] = [uid, gid] + else: + self.setError (_("False value 'chown' in template: " ) +\ + templateName) + return (fPrefs, False) + # Проверяем path + if "path" in fPrefs and\ + (not fPrefs["path"] or not fPrefs["path"][0] == "/"): + self.setError (_("False value 'path' in template: " )+\ + templateDirFile) + return (fPrefs, False) + # Проверяем name + if "name" in fPrefs and\ + (not fPrefs["name"] or fPrefs["name"][0] == "/"): + self.setError (_("False value 'name' in template: " )+\ + templateDirFile) + return (fPrefs, False) + return (fPrefs, True) + + def __getApplyHeadTemplate(self, newFile, dictPropFile): + """Применяет заголовок к шаблону (права, владелец, и.т. д)""" + # Конфигурационный файл в системе + pathOldFile = dictPropFile["_real_path"] + # Директория в которой находится шаблон + newDir = dictPropFile["path"] + # Файлы в системе к которым были применены шаблоны + applyFiles = [pathOldFile] + pathProg = "" + # В случае force + if "force" in dictPropFile: + if os.path.islink(pathOldFile): + # удаляем ссылку + try: + os.unlink(pathOldFile) + except: + self.setError(_("Can not delete link: " ) +\ + pathOldFile) + return (applyFiles, False) + if os.path.isfile(pathOldFile): + # удаляем файл + try: + os.remove(pathOldFile) + except: + self.setError(_("Can not delete file: " ) +\ + pathOldFile) + return (applyFiles, False) + + # Удаляем оригинальный файл + if dictPropFile["append"] == "remove": + if os.path.islink(pathOldFile): + # удаляем ссылку + try: + os.unlink(pathOldFile) + except: + self.setError(_("Can not delete link: " ) +\ + pathOldFile) + if os.path.isfile(pathOldFile): + # удаляем файл + try: + os.remove(pathOldFile) + except: + self.setError(_("Can not delete file: " ) +\ + pathOldFile) + return (applyFiles, False) + + flagSymlink = False + flagForce = False + # Если есть параметр mirror + if "mirror" in dictPropFile: + if "link" in dictPropFile: + templateFile = dictPropFile['link'] + if not os.path.exists(templateFile): + if os.path.exists(pathOldFile): + os.remove(pathOldFile) + return (applyFiles, False) + elif not os.path.exists(pathOldFile): + return (applyFiles, False) + + # Если есть указатель на файл шаблона (link) + if "link" in dictPropFile and\ + not "symbolic" in dictPropFile: + templateFile = dictPropFile['link'] + foundTemplateFile = os.path.exists(templateFile) + if foundTemplateFile: + FO = self.openNewFile(templateFile) + buff = FO.read() + FO.close() + if os.path.exists(pathOldFile): + os.remove(pathOldFile) + if foundTemplateFile: + if not self.createConfFile(pathOldFile, newDir): + return (applyFiles, False) + FON = open (pathOldFile, "r+") + FON.write(buff) + FON.close() + + # Если символическая ссылка + if "symbolic" in dictPropFile: + prevOldFile = pathOldFile + if "link" in dictPropFile: + pathOldFile = dictPropFile['link'] + flagSymlink = True + if not "/" == pathOldFile[0]: + pathLink = os.path.split(os.path.abspath(prevOldFile))[0] + pathProg = os.getcwd() + os.chdir(pathLink) + + # Флаг - создан конфигурационный файл + flagCreateFile = False + # chmod - изменяем права + if "chmod" in dictPropFile: + mode = dictPropFile['chmod'] + if not os.path.exists(pathOldFile): + if not self.createConfFile(pathOldFile, newDir): + return (applyFiles, False) + flagCreateFile = True + os.chmod(pathOldFile, mode) + + # chown - изменяем владельца и группу + if "chown" in dictPropFile: + uid, gid = dictPropFile['chown'] + if not flagCreateFile and not os.path.exists(pathOldFile): + if not self.createConfFile(pathOldFile, newDir): + return (applyFiles, False) + os.chown(pathOldFile, uid, gid) + + if flagSymlink: + if os.path.exists(prevOldFile) or os.path.islink(prevOldFile): + if os.path.islink(prevOldFile): + # если ссылка то удаляем её + os.unlink(prevOldFile) + else: + # иначе удаляем файл + os.remove(prevOldFile) + if not "/" == pathOldFile[0]: + os.symlink(pathOldFile, prevOldFile) + applyFiles = [prevOldFile,os.path.join(pathLink,pathOldFile)] + else: + os.symlink(pathOldFile, prevOldFile) + applyFiles = [prevOldFile,pathOldFile] + removeLink = not flagSymlink + # Создаем конфигурационный файл если он отсутствует + # открываем файл шаблона и конфигурационный файл + # указатель начала файла шаблона указыввает на текст после заголовка + # файла + if not self.openFiles(newFile, pathOldFile, self.createConfFile, + dictPropFile["_position"], removeLink): + return (applyFiles, False) + if pathProg: + os.chdir(pathProg) + # Если файлы заменяются не нужно их обрабатывать дальше + if "replace" in dictPropFile and\ + not "symbolic" in dictPropFile and\ + "link" in dictPropFile: + return (applyFiles, False) + return (applyFiles, dictPropFile) + + def createNewClass(self, name, bases, attrs={}): + """Создает объект нового класса + + createNewClass(self, name, bases, attrs) + name - имя класса - str, + bases - cписок наследуемых классов - (tuple), + attrs - аттрибуты класса - {dict} + """ + class newMethod: + #Объединяем конфигурации + def join(self, newObj): + if newObj.__class__.__name__ == self.__class__.__name__: + self.docObj.joinDoc(newObj.doc) + # Пост обработка + if 'postXML' in dir(self): + self.postXML() + attrsNew = {} + attrsNew["configName"] = name + if attrs: + for key in attrs.keys(): + attrsNew[key] = attrs[key] + newCl = type(name, bases + (newMethod, object), attrsNew) + return newCl + + def textIsUtf8(self, text): + """Проверяет текст на кодировку UTF-8""" + try: + text.decode("UTF-8") + except: + return False + return True + + def setTemplateRules(self, templateProp, textTemplate, templFile, confFile): + """Устанавливаем значения переменных, условий, функций для текста""" + # Вычисляем условные блоки + textTemplate = self.applyTermsTemplate(textTemplate, + templFile, confFile) + # Заменяем переменные на их значения + textTemplate = self.applyVarsTemplate(textTemplate, + templFile) + # Вычисляем функции + textTemplate = self.applyFuncTemplate(textTemplate, templFile) + return textTemplate + + def join(self, newFile, propFile, ListOptTitle, fileHeadObj): + """Объединения шаблона и конф. файла + + join(newFile, oldFile, ListOptTitle) + Объединение шаблона newFile и конф. файла oldFile, + propFile - словарь свойств конфигурационного файла + ListOptTitle - список строк которые добавятся в заголовок + """ + # Применяем свойства к конфигурационному файлу + # Открываем файл шаблона и конфигурационный файл + + # В случае type=print (печатаем содержимое шаблона) + flagPrintTemplate = False + filesApply, templateProp = self.__getApplyHeadTemplate(newFile,propFile) + if not templateProp: + if self.getError(): + return [] + return filesApply + # Путь к конфигурационному файлу + oldFile = templateProp["_real_path"] + # Формат шаблона + formatTemplate = templateProp["format"] + # Тип объединение шаблона + appendTemplate = templateProp["append"] + if formatTemplate != "bin": + # Применение условий, переменных, функций и переменных заголовка + self.newTemplate = self.setTemplateRules(templateProp, + self.newTemplate, newFile, + oldFile) + else: + # Копируем содержимое шаблона в содержимое конфигурационного файла + self.oldTemplate = self.newTemplate + # Если файл шаблона имеет поддерживаемый формат + if not formatTemplate in ["raw", "bin"]: + # Флаг- кодировка с бинарными примесями у файла шаблона включаем при + # условии текстового файла и кодировки отличной от UTF-8 + flagNotUtf8New = False + # Флаг - кодировка с бинарными примесями у оригинального файла + flagNotUtf8Old = False + # проверяем кодировку шаблона + if not self.textIsUtf8(self.newTemplate): + flagNotUtf8New = True + if not ("link" in templateProp and "symbolic" in templateProp): + # проверяем кодировку оригинального файла + if not self.textIsUtf8(self.oldTemplate): + flagNotUtf8Old = True + # Титл конфигурационного файла + title = "" + if ListOptTitle and "comment" in templateProp: + title = self.getTitle(templateProp["comment"], + ListOptTitle) + title = title.encode("UTF-8") + # Удаляем заголовок Calculate из конфигурационного файла + if "comment" in templateProp: + self.oldTemplate = fileHeadObj.delHeaderConfFile(self.oldTemplate, + templateProp["comment"]) + # Создаем объект в случае параметра format в заголовке + if not formatTemplate in ["raw", "bin"] and\ + appendTemplate in ["replace", "before", "after"]: + # Преобразовываем бинарные файлы + if flagNotUtf8New: + objTxtCoder = utfBin() + self.newTemplate = objTxtCoder.encode(self.newTemplate) + # создаем объект формата шаблона + objTemplNew = self.getFormatObj(formatTemplate, self.newTemplate) + if not objTemplNew: + self.setError (\ + _("Incorrect header parmeter format=%s in template")\ + %formatTemplate + " " + newFile) + return False + + if "xml_" in formatTemplate: + if objTemplNew.getError(): + self.setError (_("False template: " ) + newFile) + return False + nameRootNode = oldFile.rpartition("/")[2].split(".")[0] + objTemplNew.setNameBodyNode(nameRootNode) + # Объект Документ + docObj = objTemplNew.docObj + # Удаление комментариев из документа + docObj.removeComment(docObj.getNodeBody()) + # Добавление необходимых переводов строк + docObj.insertBRtoBody(docObj.getNodeBody()) + # Добавление необходимых разделителей между областями + docObj.insertBeforeSepAreas(docObj.getNodeBody()) + # Пост обработка + if 'postXML' in dir(objTemplNew): + objTemplNew.postXML() + # Получение текстового файла из XML документа + self.newTemplate = objTemplNew.getConfig().encode("UTF-8") + # Если не UTF-8 производим преобразование + if flagNotUtf8New: + self.newTemplate = objTxtCoder.decode(self.newTemplate) + # Титл для объединения + if ListOptTitle: + title = self.getTitle(objTemplNew._comment, + ListOptTitle) + title = title.encode("UTF-8") + # Замена + if appendTemplate == "replace": + if "xml_" in formatTemplate: + data = self.newTemplate.split("\n") + data.insert(1,title) + self.oldTemplate = "\n".join(data) + else: + self.oldTemplate = title + self.newTemplate + self.saveOldFile() + return filesApply + # Впереди + elif appendTemplate == "before": + if "xml_" in formatTemplate: + self.setError (\ + _("False option append=before in template %s") %newFile) + return False + if self.newTemplate: + if self.newTemplate[-1] == "\n": + tmpTemplate = self.newTemplate + self.oldTemplate + else: + tmpTemplate = self.newTemplate + "\n" + self.oldTemplate + else: + tmpTemplate = self.oldTemplate + self.oldTemplate = title + tmpTemplate + self.saveOldFile() + return filesApply + # Cзади + elif appendTemplate == "after": + if "xml_" in formatTemplate: + self.setError (\ + _("False option append=after in template %s") %newFile) + return False + if self.newTemplate: + if self.newTemplate[-1] == "\n": + tmpTemplate = self.oldTemplate + self.newTemplate + else: + tmpTemplate = self.oldTemplate + "\n" + self.newTemplate + else: + tmpTemplate = self.oldTemplate + self.oldTemplate = title + tmpTemplate + self.saveOldFile() + return filesApply + # Объединение + elif appendTemplate == "join": + if flagNotUtf8New: + objTxtCoder = utfBin() + self.newTemplate = objTxtCoder.encode(self.newTemplate) + # создаем объект формата шаблона + objTemplNew = self.getFormatObj(formatTemplate, self.newTemplate) + if not objTemplNew: + self.setError (\ + _("Incorrect header parmeter format=%s in template")\ + %formatTemplate + " " + newFile) + return False + if "xml_" in formatTemplate: + if objTemplNew.getError(): + self.setError (_("False template: " ) + newFile) + return False + nameRootNode = oldFile.rpartition("/")[2].split(".")[0] + objTemplNew.setNameBodyNode(nameRootNode) + # Титл для объединения + if ListOptTitle: + title = self.getTitle(objTemplNew._comment, + ListOptTitle) + title = title.encode("UTF-8") + # В случае пустого конфигурационного файла + reNoClean = re.compile("[^\s]",re.M) + if not self.oldTemplate or\ + not reNoClean.search(self.oldTemplate): + self.oldTemplate = "" + # Удаляем заголовок Calculate из конфигурационного файла + self.oldTemplate = fileHeadObj.delHeaderConfFile(self.oldTemplate, + objTemplNew._comment) + if flagNotUtf8Old: + objTxtCoder = utfBin() + self.oldTemplate = objTxtCoder.encode(self.oldTemplate) + # создаем объект формата шаблона для конфигурационного файла + objTemplOld = self.getFormatObj(formatTemplate, self.oldTemplate) + if not objTemplOld: + self.setError (_("Error in template %s") %oldFile) + return False + if "xml_" in formatTemplate: + if objTemplOld.getError(): + self.setError (_("False template: " ) + oldFile) + return False + nameRootNode = oldFile.rpartition("/")[2].split(".")[0] + objTemplOld.setNameBodyNode(nameRootNode) + + #print "#%s#" %(objTemplOld.docObj.body.toprettyxml()) + #print "#%s#" %(objTemplNew.docObj.body.toprettyxml()) + objTemplOld.join(objTemplNew) + if "xml_" in formatTemplate: + if objTemplOld.getError(): + self.setError (_("False template: " ) + newFile) + return False + data = \ + objTemplOld.getConfig().encode("UTF-8").split("\n") + data.insert(1,title) + self.oldTemplate = "\n".join(data) + else: + self.oldTemplate = title +\ + objTemplOld.getConfig().encode("UTF-8") + # Декодируем если кодировка не UTF-8 + if flagNotUtf8New or flagNotUtf8Old: + self.newTemplate = objTxtCoder.decode(self.newTemplate) + self.oldTemplate = objTxtCoder.decode(self.oldTemplate) + self.saveOldFile() + return filesApply + else: + self.setError (_("False (type append) template: " )+appendTemplate) + return False + +class iniParser(_error): + """Класс для работы с ini файлами + + """ + def __init__(self, iniFile): + # Класс samba + self.samba = getattr(__import__("format.samba", + globals(), locals(), + ["samba"]), "samba") + # название ini файла + self.iniFile = iniFile + # права создаваемого ini-файла + self.mode = 0640 + # Cоответствует ли формат файла нужному + self.checkIni = None + + def setMode(self, mode): + """установка прав создаваемого ini-файла""" + self.mode = mode + + def openIniFile(self): + if not os.access(self.iniFile, os.R_OK): + return "" + FD = open(self.iniFile, "r") + textIni = FD.read() + FD.close() + return textIni + + def writeIniFile(self, txtConfig): + if not os.path.exists(self.iniFile): + fd = os.open(self.iniFile, os.O_CREAT) + os.close(fd) + os.chmod(self.iniFile, self.mode) + if not os.path.exists(self.iniFile): + self.setError(_("Unable to create file") + ": " + self.iniFile) + return False + FD = open(self.iniFile, "r+") + FD.truncate(0) + FD.seek(0) + FD.write(txtConfig) + FD.close() + + def setVar(self, strHeader, dictVar): + """Заменяет или добавляет область и переменные + + Добавляет область в ini-файл или объединяет с существующей + strHeader - имя области + dictVar - словарь переменных + """ + textIni = self.openIniFile() + if not self.checkIniFile(textIni): + return False + # создаем объект типа samba и записываем в него содержимое ini-файла + objIni = self.samba(textIni) + # создаем текст в формате samba из строки заголовка и + # словаря переменных области + txtConfig = objIni.createTxtConfig(strHeader, dictVar) + # создаем объект типа samba и записываем в него текст + objIniAdd = self.samba(txtConfig) + # объединяем объекты для получения результирующего текста + objIni.join(objIniAdd) + # получаем текст + txtConfig = objIni.getConfig().encode("UTF-8") + # записываем его в ini файл + self.writeIniFile(txtConfig) + return True + + def isEmptyFile(self, textIni): + """Является ли файл пустым""" + if not textIni.strip(): + return True + else: + return False + + def checkIniFile(self, textIni): + """Проверка на правильность формата файла""" + if self.checkIni == None: + # Ошибка + if textIni == False: + self.checkIni = False + return False + self.checkIni = True + # В файле есть данные + if not self.isEmptyFile(textIni): + objIni = self.samba(textIni) + xmlBody = objIni.docObj.getNodeBody() + if not xmlBody.firstChild: + self.checkIni = False + return self.checkIni + + def delVar(self, strHeader, nameVar): + """Удаляем переменную из ini файла""" + delNameVar = "!%s" %(nameVar) + dictVar = {delNameVar:"del"} + res = self.setVar(strHeader, dictVar) + return res + + def delArea(self, strHeader): + """Удаляем область из ini файла""" + delStrHeader = "!%s" %(strHeader) + dictVar = {"del":"del"} + res = self.setVar(delStrHeader, dictVar) + return res + + def getVar(self, strHeader, nameVar): + """Получаем значение переменной из ini-файла""" + textIni = self.openIniFile() + if not self.checkIniFile(textIni): + return False + # создаем объект типа samba и записываем в него содержимое ini-файла + objIni = self.samba(textIni) + # получаем ноду body + xmlBody = objIni.docObj.getNodeBody() + # находим в области переменную + res = objIni.docObj.getAreaFieldValues(strHeader, nameVar, xmlBody) + if res == False: + return "" + else: + return res + + def getAreaVars(self,strHeader): + """Получаем все переменнные области из ini-файла""" + textIni = self.openIniFile() + if not self.checkIniFile(textIni): + return False + # создаем объект типа samba и записываем в него содержимое ini-файла + objIni = self.samba(textIni) + # получаем ноду body + xmlBody = objIni.docObj.getNodeBody() + # если находим область то выдаем словарем все переменные иначе False + res = objIni.docObj.getAreaFields(strHeader, xmlBody) + if res == False: + return {} + else: + return res + + def getAllSectionNames(self): + """Получаем все имена секций определенных в ini файле""" + textIni = self.openIniFile() + if not self.checkIniFile(textIni): + return False + # создаем объект типа samba и записываем в него содержимое ini-файла + objIni = self.samba(textIni) + # получаем ноду body + xmlBody = objIni.docObj.getNodeBody() + xmlNodes = objIni.docObj.getFieldsArea(xmlBody) + # Имена секций ini файла + namesSection = [] + for xmlNode in xmlNodes: + if xmlNode.tagName == "area": + nSect = objIni.docObj.getNameArea(xmlNode) + if nSect: + namesSection.append(nSect) + return namesSection diff --git a/pym/cl_utils.py b/pym/cl_utils.py index b9a56d2..5a29f48 100644 --- a/pym/cl_utils.py +++ b/pym/cl_utils.py @@ -1,6 +1,6 @@ #-*- coding: utf-8 -*- -#Copyright 2008 Calculate Pack, http://www.calculate-linux.org +# 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. @@ -14,255 +14,20 @@ # See the License for the specific language governing permissions and # limitations under the License. -import filecmp +import subprocess 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') +import stat - # флаг "есть еще текст для вывода" - 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 _toUNICODE(val): + """перевод текста в юникод""" + if type(val) == types.UnicodeType: + return val + else: + return str(val).decode('UTF-8') def runOsCommand(cmd, inStr=None, ret_first=None, env_dict=None): """Выполняет внешнюю программу @@ -299,27 +64,9 @@ def runOsCommand(cmd, inStr=None, ret_first=None, env_dict=None): 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'): @@ -331,134 +78,23 @@ def getpathenv(): 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] +def genpassword(passlen=9): + '''Вернуть случайный пароль указанной длины + Параметры: + passlen длина пароля который нужно сгенерировать - #проверить установленн ли пакет - #isinstalled('dev-db/postgresql') - def isinstalled(self, pkgname): - res=self.getinstpkg(pkgname) - if len(res)>0: - return True - else: - return False + Возвращаемые параметры: + Сгенерированный пароль указанной длины + ''' + res=''.join([choice(string.ascii_letters+string.digits)\ + for i in xrange(passlen)]) + return res - #вернуть список объектов 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 fillstr(char, width): + '''Заполнить строку указанным числом символов. Псеводоним символ*кол-во''' + return str(char) * width - def getListPkg(self): - return self.pkglist def list2str(list): '''Функция переводит список в строку''' @@ -502,9 +138,77 @@ def convertStrListDict(val): else: return val -def _toUNICODE(val): - """перевод текста в юникод""" - if type(val) == types.UnicodeType: - return val - else: - return str(val).decode('UTF-8') +def getdirlist(s_path): + """Получить список директорий по указаному пути""" + return filter(lambda x: os.path.isdir(x), os.listdir(s_path)) + +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): + """Установка ошибки""" + if not error in self.error: + self.error.append(error) + return True + +class scan: + """Класс для сканирования директорий""" + class _dir: + """Класс для хранения директорий""" + def __init__(self): + # Базовая директория + self.baseDir = False + # Все директории в базовой включая вложенные + self.dirs = [] + # Все файлы внутри базовой директории + self.files = [] + # Все ссылки внутри базовой директории + self.links = [] + # Все сокеты внутри базовой директории + self.sockets = [] + + + def __scanDir(self, scanDir, dirObj, flagDir=False): + """Сканирование одной директории""" + if flagDir or stat.S_ISDIR(os.stat(scanDir)[stat.ST_MODE]): + for fileOrDir in os.listdir(scanDir): + absPath = os.path.join(scanDir,fileOrDir) + statInfo = os.stat(absPath)[stat.ST_MODE] + if stat.S_ISDIR(statInfo): + dirObj.dirs.append(absPath) + self.__scanDir(absPath, dirObj, True) + elif stat.S_ISLNK(statInfo): + dest = absPath + src = os.readlink(absPath) + dirObj.links.append((src,dest)) + elif stat.S_ISREG(statInfo): + dirObj.files.append(absPath) + elif stat.S_ISSOCK(statInfo): + dirObj.sockets.append(absPath) + return dirObj + + def scanDirs(self, scanDirs): + """Сканирование директорий на вход список + + Выход список объктов _dirProf + """ + dirs = [] + for scanDir in scanDirs: + dirP = scan._dir() + try: + self.__scanDir(scanDir, dirP) + except OSError, e: + print e.strerror, e.filename + return [] + dirP.baseDir = scanDir + dirs.append(dirP) + return dirs \ No newline at end of file diff --git a/pym/cl_vars.py b/pym/cl_vars.py index 48f8e54..4097326 100644 --- a/pym/cl_vars.py +++ b/pym/cl_vars.py @@ -1,6 +1,6 @@ #-*- coding: utf-8 -*- -#Copyright 2008 Calculate Pack, http://www.calculate-linux.org +# 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. @@ -14,6 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. + #Допустимые ключи значений # mode - режим переменной r-не переназначается из командной строки, # w-переназначается из командной строки @@ -57,10 +58,10 @@ class Data: # архитектура компьютера (i686,x86_64) os_arch_machine = {} - #проход при наложении профилей 1,2,3,4,5 и.т д + #проход при наложении шаблонов 1,2,3,4,5 и.т д cl_pass_step = {'mode':"w"} - # обрабатываемый файл профиля + # обрабатываемый файл шаблона cl_pass_file = {'mode':"w"} # корневой раздел файловой системы @@ -81,7 +82,7 @@ class Data: # версия системы os_linux_ver = {} - # Тип профиля + # Тип шаблона cl_pass_type = {'mode':"w"} # Действие программы diff --git a/pym/format/__init__.py b/pym/format/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pym/format/apache.py b/pym/format/apache.py new file mode 100644 index 0000000..0b1ffc2 --- /dev/null +++ b/pym/format/apache.py @@ -0,0 +1,218 @@ +#-*- 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 +from xml import xpath +from cl_template import blocText, xmlDoc +from format.bind import bind + +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 \ No newline at end of file diff --git a/pym/format/bind.py b/pym/format/bind.py new file mode 100644 index 0000000..7028196 --- /dev/null +++ b/pym/format/bind.py @@ -0,0 +1,315 @@ +#-*- 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 +from cl_template import objShare, blocText, xmlDoc + +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) diff --git a/pym/format/compiz.py b/pym/format/compiz.py new file mode 100644 index 0000000..40ae487 --- /dev/null +++ b/pym/format/compiz.py @@ -0,0 +1,41 @@ +#-*- 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 +from format.samba import samba + +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() diff --git a/pym/format/dhcp.py b/pym/format/dhcp.py new file mode 100644 index 0000000..4f47666 --- /dev/null +++ b/pym/format/dhcp.py @@ -0,0 +1,100 @@ +#-*- 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 +from format.bind import bind + +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) diff --git a/pym/format/dovecot.py b/pym/format/dovecot.py new file mode 100644 index 0000000..5130771 --- /dev/null +++ b/pym/format/dovecot.py @@ -0,0 +1,65 @@ +#-*- 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 +from xml import xpath +from format.bind import bind + +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() \ No newline at end of file diff --git a/pym/format/kde.py b/pym/format/kde.py new file mode 100644 index 0000000..5c9b3fd --- /dev/null +++ b/pym/format/kde.py @@ -0,0 +1,160 @@ +#-*- 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 +from xml import xpath +from cl_template import xmlDoc +from format.samba import samba + +class kde(samba): + """Класс для обработки конфигурационного файла типа kde + + """ + _comment = "#" + configName = "kde" + configVersion = "0.1" + reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n?",re.M) + reBody = re.compile(".+",re.M|re.S) + reComment = re.compile("^\s*%s.*"%(_comment)) + reSeparator = re.compile("=") + sepFields = "\n" + reSepFields = re.compile(sepFields) + + def __init__(self,text): + samba.__init__(self,text) + + + def _textToXML(self): + """Преобразует текст в XML""" + blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody) + blocs = self.getFullAreas(blTmp) + headers = [] + startHeaders = [] + finHeaders = [] + docObj = xmlDoc() + docObj.createDoc(self.configName, self.configVersion) + rootNode = docObj.getNodeBody() + # Если пустой текст то создаем пустой документ + if not blocs: + return docObj + + for h in blocs[0]: + reH = re.compile("]\s*$") + #listfinH = h.split("]") + listfinH = reH.split(h) + finH = listfinH[0] + if "[" in finH: + startHeaders.append(finH + "]") + else: + startHeaders.append(finH) + if len(listfinH) == 2: + finHeaders.append(listfinH[1]) + else: + finHeaders.append("") + head=finH.replace("][",".").replace("[","").replace("]","").strip() + headers.append(head) + bodys = blocs[1] + + z = 0 + for h in headers: + if not bodys[z]: + z += 1 + continue + areaAction = False + if h: + if h[0] == "!": + docObj.createCaption(h[1:], [startHeaders[z],""]) + areaAction = "drop" + elif h[0] == "-": + docObj.createCaption(h[1:], [startHeaders[z],""]) + areaAction = "replace" + else: + docObj.createCaption(h, [startHeaders[z],""]) + else: + docObj.createCaption(h, [startHeaders[z],""]) + + if "\n" in blocs[0][z]: + if self.reComment.search(finHeaders[z]): + docObj.createField('comment', [finHeaders[z]]) + elif not finHeaders[z].strip() and\ + finHeaders[z].replace("\n",""): + docObj.createField('br', + [finHeaders[z].replace("\n","")]) + else: + docObj.createField('br') + fields = self._splitToFields(bodys[z]) + for f in fields: + if f.name != False and f.value!=False and f.br!=False: + # Обработка условий для samba + if f.name[0] == "!" or f.name[0] == "-" or\ + f.name[0] == "+": + qns = self.removeSymbolTerm(f.br) + xmlField = docObj.createField("var", + [qns], + f.name[1:], [f.value]) + if f.name[0] == "!": + # Удаляемое в дальнейшем поле + docObj.setActionField(xmlField, "drop") + else: + docObj.createField("var",[f.br.replace("\n","")], + f.name, [f.value]) + docObj.createField('br') + elif f.comment != False: + docObj.createField('comment', [f.comment]) + elif f.br != False: + docObj.createField('br', [f.br.replace("\n","")]) + if h.strip(): + area = docObj.createArea() + if areaAction: + docObj.setActionArea(area, areaAction) + rootNode.appendChild(area) + else: + fieldsNodes = docObj.tmpFields.getFields() + for fieldNode in fieldsNodes: + rootNode.appendChild(fieldNode) + docObj.clearTmpFields() + z += 1 + #print docObj.doc.toprettyxml() + return docObj + + def postXML(self): + """Последующая постобработка XML""" + # Для добавления перевода строки между областями если его нет + #print self.docObj.body.toprettyxml() + xmlAreas = xpath.Evaluate("child::area", self.docObj.body) + for xmlArea in xmlAreas: + if xmlArea.previousSibling and\ + self.docObj.getTypeField(xmlArea.previousSibling) == "br": + continue + firstArea = False + xmlFields = xpath.Evaluate("child::field", xmlArea) + if not (xmlFields and\ + (self.docObj.getTypeField(xmlFields[-1]) == "br" or\ + self.docObj.getTypeField(xmlFields[-1]) == "comment")): + if xmlArea.nextSibling: + parentNode = xmlArea.parentNode + nextNode = xmlArea.nextSibling + parentNode.insertBefore(self.docObj.createField("br", + [],"",[], + False,False), + nextNode) + + def join(self, kdeObj): + """Объединяем конфигурации""" + if isinstance(kdeObj, kde): + self.docObj.joinDoc(kdeObj.doc) + self.postXML() + diff --git a/pym/format/ldap.py b/pym/format/ldap.py new file mode 100644 index 0000000..5df868c --- /dev/null +++ b/pym/format/ldap.py @@ -0,0 +1,183 @@ +#-*- 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 +from cl_template import blocText, xmlDoc +from format.samba import samba + +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 diff --git a/pym/format/plasma.py b/pym/format/plasma.py new file mode 100644 index 0000000..d5e9500 --- /dev/null +++ b/pym/format/plasma.py @@ -0,0 +1,597 @@ +#-*- 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 types +import copy +from xml import xpath +from cl_template import xmlDoc +from format.samba import samba + +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 _textToXML(self): + """Преобразуем текст в XML""" + areas = [] + if self.text.strip(): + self.splitToAllArea(self.text, areas) + #docObj = xmlDoc() + # Создаем новый класс xmlDoc с измененным методом joinArea + newClass = type("newXmlDocPlalma",(xmlDocPlasma,xmlDoc,object),{}) + # Создаем экземпляр нового класса + docObj = newClass() + # Создание объекта документ c пустым разделителем между полями + docObj.createDoc(self.configName, self.configVersion) + if not areas: + return docObj + self.createXML(areas, docObj.getNodeBody(), docObj) + return docObj + + + def postXML(self): + """Последующая постобработка XML""" + # Для добавления перевода строки между областями если его нет + #print self.docObj.body.toprettyxml() + def getQuotesArea(xmlArea): + quotes = [] + xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea) + for node in xmlQuotes: + if node.firstChild: + quotes.append(node.firstChild.nodeValue) + if len(quotes) == 0: + quotes.append("") + quotes.append("") + elif len(quotes) == 1: + quotes.append("") + return quotes + + xmlAreas = xpath.Evaluate("descendant::area", self.docObj.body) + #print "-------------------------------------------------------" + #print xmlAreas + #if xmlAreas: + #prXmlArea = xmlAreas[0] + for xmlArea in xmlAreas: + # Перед пустой областью и после нее удаляем переводы строк + if getQuotesArea(xmlArea) == ["",""]: + #areaTXT = xpath.Evaluate("child::caption/name", xmlArea)[0] + #print "CL_AREA", areaTXT.firstChild + if xmlArea.previousSibling and\ + self.docObj.getTypeField(xmlArea.previousSibling) == "br": + parentNode = xmlArea.previousSibling.parentNode + if xmlArea.previousSibling.previousSibling and\ + self.docObj.getTypeField(xmlArea.previousSibling.previousSibling) == "br": + parentNode.removeChild(\ + xmlArea.previousSibling.previousSibling) + parentNode.removeChild(xmlArea.previousSibling) + if xmlArea.nextSibling and\ + self.docObj.getTypeField(xmlArea.nextSibling) == "br": + parentNode = xmlArea.nextSibling.parentNode + if xmlArea.nextSibling.nextSibling and\ + self.docObj.getTypeField(xmlArea.nextSibling.nextSibling) == "br": + parentNode.removeChild(xmlArea.nextSibling.nextSibling) + parentNode.removeChild(xmlArea.nextSibling) + continue + + # Собираем поля в кучку + xmlChildAreas = xpath.Evaluate("child::area", xmlArea) + if xmlChildAreas: + childNodes = self.docObj.getFieldsArea(xmlArea) + firstChildArea = xmlChildAreas[0] + if firstChildArea.previousSibling and\ + self.docObj.getTypeField(firstChildArea.previousSibling)=="br": + if firstChildArea.previousSibling.previousSibling: + if self.docObj.getTypeField(\ + firstChildArea.previousSibling.previousSibling)=="br": + firstChildArea = firstChildArea.previousSibling + flagFoundArea = False + it = 0 + lenChild = len(childNodes) + for node in childNodes: + it += 1 + if node.tagName == "area": + flagFoundArea = True + continue + if flagFoundArea and node.tagName == "field": + if self.docObj.getTypeField(node) == "var": + xmlArea.insertBefore(node, firstChildArea) + if it < lenChild: + if self.docObj.getTypeField(childNodes[it])==\ + "br": + xmlArea.insertBefore(childNodes[it], + firstChildArea) + + # Добавляем BR если его нет первым полем + xmlFields = xpath.Evaluate("child::field", xmlArea) + if not (xmlFields and\ + (self.docObj.getTypeField(xmlFields[0]) == "br" or\ + self.docObj.getTypeField(xmlFields[0]) == "comment")): + if xmlFields: + xmlArea.insertBefore(self.docObj.createField("br", + [],"",[], + False,False), + xmlFields[0]) + # Если последним полем BR, удаляем его + if xmlFields and self.docObj.getTypeField(xmlFields[-1]) == "br": + #print "DEL_BR", xmlFields[-1].nextSibling + #and\ + if not xmlFields[-1].nextSibling: + xmlArea.removeChild(xmlFields[-1]) + + # Если предыдущим полем не (BR или комментарий) - добавляем BR + if xmlArea.previousSibling and\ + not (self.docObj.getTypeField(xmlArea.previousSibling) == "br" or\ + self.docObj.getTypeField(xmlArea.previousSibling) == "comment"): + parentNode = xmlArea.parentNode + parentNode.insertBefore(self.docObj.createField("br", + [],"",[], + False,False), + xmlArea) + # Если есть предыдущее поле, и поле предыдущеее предыдущему + # не равно BR или комментарий то добавляем BR + if xmlArea.previousSibling: + prPrSibling = xmlArea.previousSibling.previousSibling + if prPrSibling and\ + not (self.docObj.getTypeField(prPrSibling) == "br" or\ + self.docObj.getTypeField(prPrSibling) == "comment"): + parentNode = xmlArea.parentNode + parentNode.insertBefore(self.docObj.createField("br", + [],"",[], + False,False), + xmlArea) + # Если после есть BR а за ним ничего нет, удаляем BR + if xmlArea.nextSibling and\ + self.docObj.getTypeField(xmlArea.nextSibling) == "br": + if not xmlArea.nextSibling.nextSibling: + parentNode = xmlArea.nextSibling.parentNode + parentNode.removeChild(xmlArea.nextSibling) + + #xmlName = xpath.Evaluate("child::caption/name", xmlArea)[0] + #print "------------------------------------" + #print "Name =", xmlName.firstChild + #if xmlArea.previousSibling: + #print "PR_TYPE =", self.docObj.getTypeField(xmlArea.previousSibling) + + + def join(self, kdeObj): + """Объединяем конфигурации""" + if isinstance(kdeObj, plasma): + self.docObj.joinDoc(kdeObj.doc) + self.postXML() + + diff --git a/pym/format/postfix.py b/pym/format/postfix.py new file mode 100644 index 0000000..4dc2a34 --- /dev/null +++ b/pym/format/postfix.py @@ -0,0 +1,117 @@ +#-*- 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 +from cl_template import xmlDoc +from format.apache import apache + +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 diff --git a/pym/format/procmail.py b/pym/format/procmail.py new file mode 100644 index 0000000..50fa05f --- /dev/null +++ b/pym/format/procmail.py @@ -0,0 +1,115 @@ +#-*- 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 +from cl_template import objShare, xmlDoc + +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) diff --git a/pym/format/samba.py b/pym/format/samba.py new file mode 100644 index 0000000..981cc52 --- /dev/null +++ b/pym/format/samba.py @@ -0,0 +1,261 @@ +#-*- 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 +from xml import xpath +from cl_template import objShare, blocText, xmlDoc + +class samba(objShare): + """Класс для обработки конфигурационного файла типа samba + + """ + _comment = "#" + configName = "samba" + configVersion = "0.1" + reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n",re.M) + reBody = re.compile(".+",re.M|re.S) + reComment = re.compile("\s*%s.*|\s*;.*"%(_comment)) + reSeparator = re.compile("\s*=\s*") + sepFields = "\n" + reSepFields = re.compile(sepFields) + + def __init__(self,text): + self.text = text + self.blocTextObj = blocText() + self._splitToFields = self.splitToFields + # Объект документ + self.docObj = self._textToXML() + # XML документ + self.doc = self.docObj.doc + + def postXML(self): + """Последующая постобработка XML""" + # Для добавления перевода строки между областями если его нет + #print self.docObj.body.toprettyxml() + xmlAreas = xpath.Evaluate("child::area", self.docObj.body) + for xmlArea in xmlAreas: + if xmlArea.previousSibling and\ + self.docObj.getTypeField(xmlArea.previousSibling) == "br": + continue + firstArea = False + xmlFields = xpath.Evaluate("child::field", xmlArea) + if not (xmlFields and\ + (self.docObj.getTypeField(xmlFields[-1]) == "br" or\ + self.docObj.getTypeField(xmlFields[-1]) == "comment")): + if xmlArea.nextSibling: + parentNode = xmlArea.parentNode + nextNode = xmlArea.nextSibling + parentNode.insertBefore(self.docObj.createField("br", + [],"",[], + False,False), + nextNode) + + + def join(self, sambaObj): + """Объединяем конфигурации""" + if isinstance(sambaObj, samba): + self.docObj.joinDoc(sambaObj.doc) + self.postXML() + + def setDataField(self, txtLines, endtxtLines): + """Создаем список объектов с переменными""" + class fieldData: + def __init__(self): + self.name = False + self.value = False + self.comment = False + self.br = False + fields = [] + field = fieldData() + z = 0 + for k in txtLines: + textLine = k + endtxtLines[z] + z += 1 + findComment = self.reComment.search(textLine) + if not textLine.strip(): + field.br = textLine + fields.append(field) + field = fieldData() + elif findComment: + field.comment = textLine + fields.append(field) + field = fieldData() + else: + pars = textLine.strip() + nameValue = self.reSeparator.split(pars) + if len(nameValue) > 2: + valueList = nameValue[1:] + nameValue =[nameValue[0],"=".join(valueList)] + if len(nameValue) == 2: + name = nameValue[0] + value = nameValue[1].replace(self.sepFields,"") + field.name = name.replace(" ","").replace("\t","") + field.value = value + field.br = textLine + fields.append(field) + field = fieldData() + return fields + + + def splitCleanBloc(self, txtBloc): + """Делим блок на две части (переменные, пустые строки в конце)""" + txtLines = txtBloc.split("\n") + firstBloc = [] + nextBloc = [] + txtLines.reverse() + z = 0 + for txtLine in txtLines: + if not txtLine.strip(): + nextBloc.append(txtLine) + else: + break + z += 1 + txtLines.reverse() + firstBloc = txtLines[:-z] + nextBloc.reverse() + if nextBloc: + firstBloc.append("") + if nextBloc and "\n".join(nextBloc): + return ("\n".join(firstBloc), "\n".join(nextBloc)) + else: + return False + + def getFullAreas(self, blocs): + """Делит текст на области, (Заголовок, тело) + + Возвращает два списка: заголовки, тела + """ + headsAreas = [] + bodyAreas = [] + if not blocs: + return [] + lenBlocs = len(blocs[0]) + for i in range(lenBlocs): + txtBloc = blocs[1][i] + clean = self.splitCleanBloc(txtBloc) + if clean: + headsAreas.append(blocs[0][i]) + bodyAreas.append(clean[0]) + headsAreas.append("") + bodyAreas.append(clean[1]) + else: + headsAreas.append(blocs[0][i]) + bodyAreas.append(blocs[1][i]) + return (headsAreas, bodyAreas) + + def createTxtConfig(self, strHeader, dictVar): + """Cоздает область с заголовком + + создает текст конфигурационного файла в формате samba из + заголовка (строка) и словаря переменных + """ + if not strHeader: + return "" + outTxt = "[" + strHeader + "]\n" + for key in dictVar.keys(): + outTxt += "%s = %s\n" %(key,dictVar[key]) + return outTxt + + def _textToXML(self): + """Преобразует текст в XML""" + blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody) + blocs = self.getFullAreas(blTmp) + headers = [] + startHeaders = [] + finHeaders = [] + docObj = xmlDoc() + docObj.createDoc(self.configName, self.configVersion) + rootNode = docObj.getNodeBody() + # Если пустой текст то создаем пустой документ + if not blocs: + return docObj + + for h in blocs[0]: + listfinH = h.split("]") + finH = listfinH[0] + if "[" in finH: + startHeaders.append(finH + "]") + else: + startHeaders.append(finH) + if len(listfinH) == 2: + finHeaders.append(listfinH[1]) + else: + finHeaders.append("") + headers.append(finH.replace("[","").replace("]","").strip()) + bodys = blocs[1] + + z = 0 + for h in headers: + if not bodys[z]: + z += 1 + continue + areaAction = False + if h: + if h[0] == "!": + docObj.createCaption(h[1:], [startHeaders[z],""]) + areaAction = "drop" + elif h[0] == "-": + docObj.createCaption(h[1:], [startHeaders[z],""]) + areaAction = "replace" + else: + docObj.createCaption(h, [startHeaders[z],""]) + else: + docObj.createCaption(h, [startHeaders[z],""]) + + if "\n" in blocs[0][z]: + if self.reComment.search(finHeaders[z]): + docObj.createField('comment', [finHeaders[z]]) + elif not finHeaders[z].strip() and\ + finHeaders[z].replace("\n",""): + docObj.createField('br', + [finHeaders[z].replace("\n","")]) + else: + docObj.createField('br') + fields = self._splitToFields(bodys[z]) + for f in fields: + if f.name != False and f.value!=False and f.br!=False: + # Обработка условий для samba + if f.name[0] == "!" or f.name[0] == "-" or\ + f.name[0] == "+": + qns = self.removeSymbolTerm(f.br) + xmlField = docObj.createField("var", + [qns], + f.name[1:], [f.value]) + if f.name[0] == "!": + # Удаляемое в дальнейшем поле + docObj.setActionField(xmlField, "drop") + else: + docObj.createField("var",[f.br.replace("\n","")], + f.name, [f.value]) + docObj.createField('br') + elif f.comment != False: + docObj.createField('comment', [f.comment]) + elif f.br != False: + docObj.createField('br', [f.br.replace("\n","")]) + if h.strip(): + area = docObj.createArea() + if areaAction: + docObj.setActionArea(area, areaAction) + rootNode.appendChild(area) + else: + fieldsNodes = docObj.tmpFields.getFields() + for fieldNode in fieldsNodes: + rootNode.appendChild(fieldNode) + docObj.clearTmpFields() + z += 1 + #print docObj.doc.toprettyxml() + return docObj + diff --git a/pym/format/squid.py b/pym/format/squid.py new file mode 100644 index 0000000..fba8153 --- /dev/null +++ b/pym/format/squid.py @@ -0,0 +1,86 @@ +#-*- 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 +from format.procmail import procmail + +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) diff --git a/pym/format/xml_gconf.py b/pym/format/xml_gconf.py new file mode 100644 index 0000000..84894bd --- /dev/null +++ b/pym/format/xml_gconf.py @@ -0,0 +1,262 @@ +#-*- 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 time +from xml import xpath +import xml.dom.minidom +from format.xml_xfce import xml_xfce +# Перевод cообщений модуля +from cl_lang import lang +tr = lang() +tr.setLocalDomain('cl_lib') +tr.setLanguage(sys.modules[__name__]) + + +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 template is XML")) + return False + self.rootNode = self.doc.documentElement + self.bodyNode = self.rootNode + return self.doc + + def cmpListsNodesEntry(self, listXmlA, listXmlB): + """Сравнение содержимого двух списков XML нод""" + getTextsNodes = lambda y: map(lambda x:\ + x.toxml().replace(" ","").replace("\t","").replace("\n",""), + map(lambda x: x.removeAttribute("mtime") or x, + map(lambda x: x.cloneNode(True), + filter(lambda x: x.nodeType==x.ELEMENT_NODE, y)))) + if set(getTextsNodes(listXmlA))==set(getTextsNodes(listXmlB)): + return True + return False + + def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True, levelNumber=0): + """Объединение корневой ноды шаблона и корневой ноды файла""" + if levelNumber>1: + return True + xmlNode = xmlNewNode + childNodes = xmlNode.childNodes + nextOldNode = xmlOldNode + flagError = False + if xmlNode.nodeType == xmlNode.ELEMENT_NODE: + n = xmlNode + tagName = n.tagName + nAction = u'' + nName = u'' + nType = u'' + nValue = u'' + attrName = '' + attrType = '' + if flagRootNode: + if not tagName == "gconf": + self.setError(_("The text is not a valid gconf-XML format \ +(not found '...')")) + return False + else: + if not tagName == "entry": + self.setError(_("The text is not a valid gconf-XML format \ +(found '<%s>..'")%(tagName,tagName)) + return False + if not n.hasAttribute("name"): + self.setError(_('Not found arrtibute "name" in tag entry')) + return False + if not n.hasAttribute("type"): + self.setError(_('Not found arrtibute "type" in tag entry')) + return False + nName = n.getAttribute("name") + attrName = u"attribute::name='%s'"%nName + nType = n.getAttribute("type") + # Проверка правильности аттрибута type + if not nType in self.supportEntryTypes: + self.setError(\ + _('Incorrect arrtibute "type" - ')%nType) + return False + attrType = u"attribute::type='%s'"%nType + if n.hasAttribute("value"): + nValue = n.getAttribute("value") + if n.hasAttribute("action"): + nAction = n.getAttribute("action") + if not nAction in ("join","replace","drop"): + textError = _('''In the text, XML template, look \ +for a reserved attribute 'action' with the incorrect value.\n\ +Valid values attribute 'action': \ +(action="join", action="replace", action="drop")''') + self.setError(textError) + return False + if xmlOldNode.parentNode: + findStr = u"child::%s"%tagName + strAttr = [attrName, attrType] + findAttr = filter(lambda x: x, strAttr) + findAttrStr = '' + if findAttr: + strAttr = u' and '.join(findAttr) + findAttrStr = "[%s]"%strAttr + findPath = u"child::%s%s"%(tagName,findAttrStr) + # Рабочая нода + if flagRootNode: + workNode = xmlOldNode.parentNode + else: + workNode = xmlOldNode + oldNodes = xpath.Evaluate(findPath, workNode) + # Новая нода список + flagArray = False + if nType == "list" or nType == "pair": + flagArray = True + flagDrop = False + flagJoin = True + flagReplace = False + if nType=="string" or nAction=="replace": + flagJoin = False + flagReplace = True + elif nAction == "drop": + flagJoin = False + flagDrop = True + if flagRootNode: + textError = _('Incorrect action="drop" in root node') + self.setError(textError) + return False + if oldNodes: + if len(oldNodes)>1: + textError = _("The uncertainty in this template are \ +the same nodes at one level") + self.setError(textError) + return False + nextOldNode = oldNodes[0] + # Замещаем ноду в случае массива + if flagArray and not flagDrop: + replaceXmlNode = xmlNode.cloneNode(True) + # Сравнение содержимого нод + if not self.cmpListsNodesEntry([replaceXmlNode], + [nextOldNode]): + replaceXmlNode.setAttribute("mtime", + self.currentTime) + if nAction: + replaceXmlNode.removeAttribute("action") + workNode.replaceChild(replaceXmlNode, + nextOldNode) + flagJoin = False + flagReplace = False + childNodes = False + # Объединение нод + if flagJoin: + if nextOldNode.hasAttribute("value"): + oValue = nextOldNode.getAttribute("value") + if nValue != oValue: + nextOldNode.setAttribute("mtime", + self.currentTime) + nextOldNode.setAttribute("value",nValue) + # Замещение ноды + elif flagReplace: + replaceXmlNode = xmlNode.cloneNode(True) + # Сравнение содержимого нод + if not self.cmpListsNodesEntry([replaceXmlNode], + [nextOldNode]): + replaceXmlNode.setAttribute("mtime", + self.currentTime) + if not\ + self._removeDropNodesAndAttrAction(\ + replaceXmlNode): + return False + workNode.replaceChild(replaceXmlNode, + nextOldNode) + childNodes = False + # Удаление ноды + elif flagDrop: + workNode.removeChild(nextOldNode) + childNodes = False + else: + # Добавление ноды + childNodes = False + if not flagDrop: + appendXmlNode = xmlNode.cloneNode(True) + appendXmlNode.setAttribute("mtime", self.currentTime) + if not\ + self._removeDropNodesAndAttrAction(appendXmlNode): + return False + workNode.appendChild(appendXmlNode) + if childNodes: + for node in childNodes: + levelNumber +=1 + if not self._join(node, nextOldNode, False, levelNumber): + flagError = True + break + levelNumber -= 1 + if flagError: + return False + return True + + def join(self, xml_gconfObj): + """Объединяем конфигурации""" + # Получаем текущее время + self.currentTime = self.getCurrentTime() + if isinstance(xml_gconfObj, xml_gconf): + try: + self.joinDoc(xml_gconfObj.doc) + except: + self.setError(_("Can not join template")) + return False + return True + + def getConfig(self): + """Получение текстового файла из XML документа""" + data = self.doc.toprettyxml().split("\n") + data = filter(lambda x: x.strip(), data) + return "\n".join(data).replace("\t"," ") diff --git a/pym/format/xml_xfce.py b/pym/format/xml_xfce.py new file mode 100644 index 0000000..9acc947 --- /dev/null +++ b/pym/format/xml_xfce.py @@ -0,0 +1,268 @@ +#-*- 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 +from xml import xpath +import xml.dom.minidom +from cl_utils import _error +# Перевод cообщений модуля +from cl_lang import lang +tr = lang() +tr.setLocalDomain('cl_lib') +tr.setLanguage(sys.modules[__name__]) + +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 template 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 template")) + 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 template, 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 template, look \ +for a reserved attribute 'action' with the incorrect value.\n\ +Valid values attribute 'action': \ +(action="join", action="replace", action="drop")''') + self.setError(textError) + return False + if xmlOldNode.parentNode: + findStr = u"child::%s"%path + strAttr = [attrName, attrType] + findAttr = filter(lambda x: x, strAttr) + findAttrStr = '' + if findAttr: + strAttr = u' and '.join(findAttr) + findAttrStr = "[%s]"%strAttr + findPath = u"child::%s%s"%(path,findAttrStr) + # Рабочая нода + if flagRootNode: + workNode = xmlOldNode.parentNode + else: + workNode = xmlOldNode + oldNodes = xpath.Evaluate(findPath, workNode) + #print findPath + #print workNode + #print "----------------------------" + # Новая нода список + flagArray = False + if nType == "array": + flagArray = True + flagDrop = False + flagJoin = True + flagReplace = False + if nAction == "replace": + flagJoin = False + flagReplace = True + elif nAction == "drop": + flagJoin = False + flagDrop = True + if flagRootNode: + textError = _('Incorrect action="drop" in root node') + self.setError(textError) + return False + if oldNodes: + if len(oldNodes)>1: + textError = _("The uncertainty in this template 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 template 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") diff --git a/pym/format/xml_xfcepanel.py b/pym/format/xml_xfcepanel.py new file mode 100644 index 0000000..4e9eb06 --- /dev/null +++ b/pym/format/xml_xfcepanel.py @@ -0,0 +1,199 @@ +#-*- 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 +from xml import xpath +import xml.dom.minidom +from format.xml_xfce import xml_xfce + +# Перевод cообщений модуля +from cl_lang import lang +tr = lang() +tr.setLocalDomain('cl_lib') +tr.setLanguage(sys.modules[__name__]) + +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: + findStr = u"child::%s"%path + findAttrStr = "" + if attrName: + findAttrStr = "[%s]"%attrName + findPath = u"child::%s%s"%(path,findAttrStr) + # Рабочая нода + if flagRootNode: + workNode = xmlOldNode.parentNode + else: + workNode = xmlOldNode + oldNodes = xpath.Evaluate(findPath, workNode) + flagDrop = False + flagJoin = True + flagReplace = False + flagAppend = False + if nAction == "replace": + flagJoin = False + flagReplace = True + elif nAction == "drop": + flagJoin = False + flagDrop = True + if flagRootNode: + textError = _('Incorrect action="drop" in root node') + self.setError(textError) + return False + if path == "panel": + flagJoin = False + if levelNumber in self.panelNumbers.keys(): + self.panelNumbers[levelNumber] += 1 + else: + self.panelNumbers[levelNumber] = 0 + if oldNodes: + if len(oldNodes)>1 and path != "panel": + textError = _("The uncertainty in this profile are \ +the same nodes at one level") + self.setError(textError) + return False + if path == "panel": + if len(oldNodes)<=self.panelNumbers[levelNumber]: + nextOldNode = oldNodes[-1] + # Добавляем ноду + if not flagDrop: + flagAppend = True + flagReplace = False + childNodes = False + else: + nextOldNode=oldNodes[self.panelNumbers[levelNumber]] + else: + nextOldNode = oldNodes[0] + # Замещаем ноду в случае массива + if flagArray and not flagDrop: + replaceXmlNode = xmlNode.cloneNode(True) + if nAction: + replaceXmlNode.removeAttribute("action") + workNode.replaceChild(replaceXmlNode, + nextOldNode) + flagJoin = False + flagReplace = False + childNodes = False + # Объединение нод + if flagJoin: + if nextOldNode.hasAttribute("value"): + oValue = nextOldNode.getAttribute("value") + if nValue != oValue: + nextOldNode.setAttribute("value",nValue) + # Замещение ноды + elif flagReplace: + replaceXmlNode = xmlNode.cloneNode(True) + if not\ + self._removeDropNodesAndAttrAction(replaceXmlNode): + return False + workNode.replaceChild(replaceXmlNode, + nextOldNode) + childNodes = False + # Удаление ноды + elif flagDrop: + workNode.removeChild(nextOldNode) + childNodes = False + else: + flagAppend = True + flagDrop = False + if flagAppend and not flagDrop: + # Добавление ноды + childNodes = False + if not flagDrop: + appendXmlNode = xmlNode.cloneNode(True) + if not\ + self._removeDropNodesAndAttrAction(appendXmlNode): + return False + workNode.appendChild(appendXmlNode) + if childNodes: + for node in childNodes: + levelNumber +=1 + if not self._join(node, nextOldNode, False, levelNumber): + flagError = True + break + levelNumber -= 1 + if flagError: + return False + return True + + def join(self, xml_xfceObj): + """Объединяем конфигурации""" + if isinstance(xml_xfceObj, xml_xfcepanel): + try: + self.joinDoc(xml_xfceObj.doc) + except: + self.setError(_("Can not join profile")) + return False + return True diff --git a/setup.py b/setup.py index f074608..c3e9359 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ # setup.py --- Setup script for calculate-server -#Copyright 2008 Calculate Pack, http://www.calculate-linux.org +# 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. @@ -23,14 +23,14 @@ from distutils.core import setup setup( name = 'calculate-lib', - version = "2.1.4", + version = "2.2.0", description = "The library for Calculate 2", author = "Calculate Pack", author_email = "support@calculate.ru", url = "http://calculate-linux.org", license = "http://www.apache.org/licenses/LICENSE-2.0", package_dir = {'calculate-lib': "."}, - packages = ['calculate-lib.pym'], + packages = ['calculate-lib.pym','calculate-lib.pym.format'], data_files = [("/usr/share/calculate/i18n",['i18n/cl_lib_ru.mo']), ("/var/calculate/remote",[])], ) From 735db258f06643d8101ae3265ea99b9bc7b8608d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A5=D0=B8=D1=80=D0=B5=D1=86=D0=BA=D0=B8=D0=B9=20=D0=9C?= =?UTF-8?q?=D0=B8=D1=85=D0=B0=D0=B8=D0=BB?= Date: Wed, 27 Jan 2010 16:28:11 +0300 Subject: [PATCH 2/7] Removed some files in branch develop --- pym/cl_base.py | 1038 ------- pym/cl_profile.py | 6568 --------------------------------------------- pym/cl_utils2.py | 563 ---- 3 files changed, 8169 deletions(-) delete mode 100644 pym/cl_base.py delete mode 100644 pym/cl_profile.py delete mode 100644 pym/cl_utils2.py diff --git a/pym/cl_base.py b/pym/cl_base.py deleted file mode 100644 index 5aa3b64..0000000 --- a/pym/cl_base.py +++ /dev/null @@ -1,1038 +0,0 @@ -#-*- coding: utf-8 -*- - -#Copyright 2008 Calculate Pack, http://www.calculate-linux.org -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import 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() - if not self.checkIniFile(textIni): - return False - # создаем объект типа samba и записываем в него содержимое ini-файла - objIni = cl_profile.samba(textIni) - # создаем текст в формате samba из строки заголовка и - # словаря переменных области - txtConfig = objIni.createTxtConfig(strHeader, dictVar) - # создаем объект типа samba и записываем в него текст - objIniAdd = cl_profile.samba(txtConfig) - # объединяем объекты для получения результирующего текста - objIni.join(objIniAdd) - # получаем текст - txtConfig = objIni.getConfig().encode("UTF-8") - # записываем его в ini файл - self.writeIniFile(txtConfig) - return True - - def isEmptyFile(self, textIni): - """Является ли файл пустым""" - if not textIni.strip(): - return True - else: - return False - - def checkIniFile(self, textIni): - """Проверка на правильность формата файла""" - if self.checkIni == None: - # Ошибка - if textIni == False: - self.checkIni = False - return False - self.checkIni = True - # В файле есть данные - if not self.isEmptyFile(textIni): - objIni = 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 файла""" - delStrHeader = "!%s" %(strHeader) - dictVar = {"del":"del"} - res = self.setVar(delStrHeader, dictVar) - return res - - def getVar(self, strHeader, nameVar): - """Получаем значение переменной из ini-файла""" - textIni = self.openIniFile() - if not self.checkIniFile(textIni): - return False - # создаем объект типа samba и записываем в него содержимое ini-файла - objIni = cl_profile.samba(textIni) - # получаем ноду body - xmlBody = objIni.docObj.getNodeBody() - # находим в области переменную - res = objIni.docObj.getAreaFieldValues(strHeader, nameVar, xmlBody) - if res == False: - return "" - else: - return res - - def getAreaVars(self,strHeader): - """Получаем все переменнные области из ini-файла""" - textIni = self.openIniFile() - if not self.checkIniFile(textIni): - return False - # создаем объект типа samba и записываем в него содержимое ini-файла - objIni = cl_profile.samba(textIni) - # получаем ноду body - xmlBody = objIni.docObj.getNodeBody() - # если находим область то выдаем словарем все переменные иначе False - res = objIni.docObj.getAreaFields(strHeader, xmlBody) - if res == False: - return {} - else: - return res - - def getAllSectionNames(self): - """Получаем все имена секций определенных в ini файле""" - textIni = self.openIniFile() - if not self.checkIniFile(textIni): - return False - # создаем объект типа samba и записываем в него содержимое ini-файла - objIni = cl_profile.samba(textIni) - # получаем ноду body - xmlBody = objIni.docObj.getNodeBody() - xmlNodes = objIni.docObj.getFieldsArea(xmlBody) - # Имена секций ini файла - namesSection = [] - for xmlNode in xmlNodes: - if xmlNode.tagName == "area": - nSect = objIni.docObj.getNameArea(xmlNode) - if nSect: - namesSection.append(nSect) - return namesSection - -############################################################################## - -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 self.__dict__.has_key(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 self.__dict__.has_key(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 self.__dict__.has_key(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 self.__dict__.has_key(vname): - if self.__dict__[vname].service == 'Global': - return 'calculate' - else: - return self.__dict__[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') - - Возвращаемые значение: - 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) - # Удаляем переменную - 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): - #if vname: - #if self.__dict__.has_key(vname): - #return True - #return False - def defined(self, vname): - return True - - - - def exists(self, nameVar): - """ Определяет существует ли переменная с таким имененм - """ - if self.__dict__.has_key(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/pym/cl_profile.py b/pym/cl_profile.py deleted file mode 100644 index 4cc9070..0000000 --- a/pym/cl_profile.py +++ /dev/null @@ -1,6568 +0,0 @@ -#-*- coding: utf-8 -*- - -#Copyright 2008 Calculate Pack, http://www.calculate-linux.org -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys -import os -import cl_base -import stat -import re -import xml.dom.minidom -from xml import xpath -import subprocess -import types -import copy -import random -import string -import time - -tr = cl_base.lang() -tr.setLocalDomain('cl_lib') -tr.setLanguage(sys.modules[__name__]) - - -class _error: - # Здесь ошибки, если они есть - error = [] - def getError(self): - """Выдать ошибки""" - if not self.error: - return False - error = "" - for e in self.error: - error += e + "\n" - return error - - def setError(self, error): - """Установка ошибки""" - self.error.append(error) - return True - - -class _terms(_error): - """Вычисление условий применяемых в профилях - - """ - def _convertVers(self, verA, verB): - """Конвертирование номеров версий для корректного сравнения - """ - elemA = verA.split(".") - elemB = verB.split(".") - if len(elemA) > len(elemB): - maxElemB = len(elemB)-1 - for i in range(len(elemA)): - if i > maxElemB: - elemB.append("0") - else: - maxElemA = len(elemA)-1 - for i in range(len(elemB)): - if i > maxElemA: - elemA.append("0") - for i in range(len(elemB)): - lenA = len(elemA[i]) - lenB = len(elemB[i]) - if lenA == lenB: - pass - elif lenA > lenB: - res = lenA - lenB - for z in range(res): - elemB[i] = "0" + elemB[i] - elif lenB > lenA: - res = lenB - lenA - for z in range(res): - elemA[i] = "0" + elemA[i] - return (".".join(elemA), ".".join(elemB)) - - def _equalTerm(self, term, textError, function=False): - """Вычисление логических выражений для условий - - Для корректной работы в классе который наследует этот класс - должен быть объявлен аттрибут self.objVar - (объект для работы с переменными) - function - функция для для обработки функций в заголовке блока - """ - trm = {"&":" and ","||":" or "} - rule = ["==", "!=", ">=", "<=", ">", "<"] - listEqual = [] - for k in trm.keys(): - if k in term: - term = term.replace(k,trm[k]) - trs = term.split(" ") - for t in trs: - flagRule = False - for sepF in rule: - if sepF in t: - flagRule = True - vals = t.split(sepF) - break - - if not flagRule: - flagLog = False - for k in trm.values(): - if k.strip() == t: - flagLog = True - break - if not flagLog: - self.setError("'%s'"%term + " " + _("incorrect")) - self.setError (textError) - return False - else: - listEqual.append(k) - else: - #проверка на допустимость названия переменной - reDenyName = re.compile("[^a-zA-Z0-9\_\-]") - flagFunction = False - if reDenyName.search(vals[0]): - #проверка на допустимость функции - flagError = True - if function: - reFunction = re.compile(\ - "([a-zA-Z0-9\_\-]+)\([a-zA-Z0-9_\-\+\,\*\/\.]+\)") - searchFunct = reFunction.search(vals[0]) - if searchFunct: - flagError = False - flagFunction = True - if flagError: - self.setError("'%s'"%term + " " + _("incorrect")) - self.setError(textError) - return False - #проверка на допустимость значения - reDenyValue = re.compile("[^0-9a-zA-Z_\.-]") - if reDenyValue.search(vals[1]): - self.setError("'%s'"%term + " " + _("incorrect")) - self.setError(textError) - return False - flagIntTypeVar = None - if flagFunction: - valVars = function("#-%s-#"%vals[0]) - if valVars == "": - flagFunction = False - if valVars == False: - self.setError("'%s'"%term + " " + _("incorrect")) - self.setError(textError) - return False - if "load" == searchFunct.group(1): - if re.search("\(\s*num\s*,",vals[0]): - if valVars: - try: - valVars = int(valVars) - except: - self.setError("'%s'"%term + " " + \ - _("incorrect")) - self.setError (textError) - return False - flagIntTypeVar = True - else: - flagIntTypeVar = False - else: - try: - valVars = self.objVar.Get(vals[0]) - except self.objVar.DataVarsError, e: - print textError - print e - cl_base.exit(1) - # Cравниваем номера версий - if "_ver" in vals[0] or \ - (flagFunction and "pkg" == searchFunct.group(1)) or\ - (flagFunction and "load" == searchFunct.group(1) and\ - re.search("\(\s*ver\s*,",vals[0])): - verFile, verVar = self._convertVers(vals[1],valVars) - exec("res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")") - if res: - listEqual.append("1") - else: - listEqual.append("0") - else: - if flagIntTypeVar == None: - flagIntTypeVar = True - try: - valVars = int(valVars) - except: - flagIntTypeVar = False - if flagIntTypeVar: - if not vals[1].strip(): - vals[1] = 0 - try: - valFile = int(vals[1]) - except: - self.setError("'%s'"%term + " " + _("incorrect")) - self.setError (textError) - return False - valVar = valVars - exec("res=(%d%s%d)"%(valVar,sepF,valFile)) - if res: - listEqual.append("1") - else: - listEqual.append("0") - else: - if sepF == "!=" or sepF == "==": - if not vals[1].strip(): - vals[1] = "" - valFile = vals[1] - valVar = valVars - exec("res=("+'"""'+valVar+'"""'+sepF+"'"+valFile+\ - "'"+")") - if res: - listEqual.append("1") - else: - listEqual.append("0") - else: - if valVars == "": - listEqual.append("0") - else: - self.setError("'%s'"%term + " "\ - + _("incorrect")) - self.setError (textError) - return False - exec("res=(%s)"%("".join(listEqual))) - return res - -class fileHeader(_terms): - """Обработка заголовков профилей и конфигурационных файлов - - """ - # Допустимые параметры заголовка - allowParam = ["format", "format_conf", "comment", "append", "force", - "link", "mirror", "symbolic", "chmod", "chown", "name"] - # Корректность заголовка - headerCorrect = True - - # Тип профиля - fileType = "" - # Тип вставки профиля - typeAppend = "" - # Возможные типы вставки профилей - _fileAppend = "join", "before", "after", "replace", "remove" - # Интерпретатор (#!/bin/bash) (#!/usr/bin/python) - execStr = "" - # Символ комментария - comment = False - # Выражение для поиска строки интерпретатора - reExecStr = re.compile("^#!.+\s*",re.I) - # условные операторы - terms = ('>', '<', '==', '!=', '>=', '<=') - # параметры без значения - listParNotVal = ("symbolic", "force", "mirror") - # Результат вычисления условия в заголовке - headerTerm = True - # Сообщение о ошибке - errorMessage = "" - - def __init__(self, text, comment=False, fileType=False, objVar=False, - function=False): - self.body = text - # Объект с переменными - self.objVar=objVar - # Параметры описанные в заголовке файла профиля - self.params = {} - # некорректные параметры - incorrectParams = set([]) - # Удаление Заголовка Calculate - if comment: - # В случае текста XML - if type(comment) == types.TupleType and len(comment) == 2: - _titleList = (_("Modified"), _("File of a profile")) - reCalcHeader =\ - re.compile(u"\s*%s\s+%s.+Calculate.+\s+%s.+\s+%s\s?"%(\ - comment[0], - _titleList[0].decode("UTF-8"), - _titleList[1].decode("UTF-8"), - comment[1], - ), - re.M|re.I|re.U) - textUnicode = text.decode("UTF-8") - reS = reCalcHeader.search(textUnicode) - if reS: - textBody = textUnicode[:reS.start()]+textUnicode[reS.end():] - if textBody: - self.body = textBody.encode("UTF-8") - else: - reCalcHeader =\ - re.compile("\s*%s\-+\s+%s.+Calculate.+\s+%s.+\s+%s\-+\s?"%(\ - comment, - comment, - comment, - comment, - ), - re.M|re.I) - reS = reCalcHeader.search(text) - if reS: - self.body = text[reS.end():] - - if fileType != False: - if fileType=="bin": - self.params["format"] = fileType - self.fileType = self._getType() - self.typeAppend = self._getAppend() - else: - textLines = text.splitlines() - if textLines: - textLine = textLines[0] - rePar = re.compile("\s*#\s*calculate\s+",re.I) - reP = rePar.search(textLine) - if reP: - reL = False - reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M) - reLs = reLns.search(text) - if reLs: - reL = reLs - paramLine = text[reP.end():reLs.end()] - paramLine = paramLine.replace("\\"," ") - else: - reLn = re.compile("\n") - reL = reLn.search(text) - paramLine = textLine[reP.end():] - if reL: - self.body = text[reL.end():] - else: - self.body = "" - paramList = re.split("\s+",paramLine) - if paramList: - for i in paramList: - foundTerm = False - for term in self.terms: - if term in i: - foundTerm = True - if function: - rezTerm = self._equalTerm(i,\ - _("header profile not valid: ") + \ - i,function) - else: - rezTerm = self._equalTerm(i,\ - _("header profile not valid: ") + \ - i) - if not rezTerm: - self.headerTerm = False - break - if not foundTerm: - par = i.split("=") - if len(par) == 1: - if i in self.listParNotVal: - self.params[i] = "True" - else: - if i.strip(): - incorrectParams = set([i]) - elif len(par) == 2: - self.params[par[0]] = par[1] - - self.comment = self._getComment() - self.fileType = self._getType() - self.typeAppend = self._getAppend() - reExecRes = self.reExecStr.search(self.body) - if reExecRes: - self.execStr = self.body[reExecRes.start():reExecRes.end()] - self.body = self.body[reExecRes.end():] - if not incorrectParams: - incorrectParams = set(self.params.keys()) - set(self.allowParam) - if incorrectParams: - self.headerTerm = False - self.headerCorrect = False - self.errorMessage = _("incorrect header parameters - '%s'")\ - % " ".join(list(incorrectParams)) - - def _getType(self): - """Выдать тип файла""" - if self.params.has_key("format"): - return self.params["format"] - else: - return "raw" - - def _getAppend(self): - """Выдать тип добавления файла""" - if self.params.has_key("append") and self.params["append"] in\ - self._fileAppend: - return self.params["append"] - else: - if self.fileType != "raw" and self.fileType != "bin" and\ - self.fileType != "": - self.params["append"] = "join" - return "join" - self.params["append"] = "replace" - return "replace" - - def _getComment(self): - """Выдать символ комментария файла""" - if self.params.has_key("comment"): - return self.params["comment"] - else: - return False - - -class dirHeader(_terms): - """Обработка заголовков профилей директорий - - """ - # Допустимые параметры заголовка - allowParam = ["append", "chmod", "chown", "name"] - # Корректность заголовка - headerCorrect = True - - # Тип вставки профиля - typeAppend = "" - # Возможные типы вставки профилей - _fileAppend = "join", "remove" - # условные операторы - terms = ('>', '<', '==', '!=', '>=', '<=') - # параметры без значения - listParNotVal = ("symbolic", "force") - # Результат вычисления условия в заголовке - headerTerm = True - # Сообщение о ошибке - errorMessage = "" - - def __init__(self, text, objVar=False, function=False): - self.body = text - # Объект с переменными - self.objVar=objVar - # Параметры описанные в заголовке файла профиля - self.params = {} - # некорректные параметры - incorrectParams = set([]) - - textLines = text.splitlines() - flagErrorBody = False - if textLines: - textLine = textLines[0] - rePar = re.compile("\s*#\s*calculate\s+",re.I) - reP = rePar.search(textLine) - if reP: - reL = False - reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M) - reLs = reLns.search(text) - if reLs: - reL = reLs - paramLine = text[reP.end():reLs.end()] - paramLine = paramLine.replace("\\"," ") - else: - reLn = re.compile("\n") - reL = reLn.search(text) - paramLine = textLine[reP.end():] - if reL: - self.body = text[reL.end():] - else: - self.body = "" - if self.body.strip(): - self.headerTerm = False - self.headerCorrect = False - self.errorMessage = _("incorrect text in profile: '%s'")\ - %self.body - flagErrorBody = True - if not flagErrorBody: - paramList = re.split("\s+",paramLine) - if paramList: - for i in paramList: - foundTerm = False - for term in self.terms: - if term in i: - foundTerm = True - if function: - rezTerm = self._equalTerm(i,\ - _("header profile not valid: ") + \ - i,function) - else: - rezTerm = self._equalTerm(i,\ - _("header profile not valid: ") + \ - i) - if not rezTerm: - self.headerTerm = False - break - if not foundTerm: - par = i.split("=") - if len(par) == 1: - if i in self.listParNotVal: - self.params[i] = "True" - else: - if i.strip(): - incorrectParams = set([i]) - elif len(par) == 2: - self.params[par[0]] = par[1] - self.typeAppend = self._getAppend() - if not flagErrorBody: - if not incorrectParams: - incorrectParams = set(self.params.keys()) - set(self.allowParam) - if incorrectParams: - self.headerTerm = False - self.headerCorrect = False - self.errorMessage = _("incorrect header parameters - '%s'")\ - % " ".join(list(incorrectParams)) - - def _getAppend(self): - """Выдать тип добавления директории""" - if self.params.has_key("append") and self.params["append"] in\ - self._fileAppend: - return self.params["append"] - else: - return "join" - -class objShare: - """Общий клас для объектов, наследуем - - """ - - def createFieldTerm(self, name, value, quote, docObj): - """Создание поля переменная - значение - - при создании поля проверяется первый символ названия переменной - и добавляется тег action - "!" - 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 == False: - indErr.append(ind) - if l>0: - ind +=l - if ind >= len(utf): - break - else: - if utf[ind] != '_ch_': - indErr.append(ind) - ind +=1 - if ind >= len(utf): - break - if indErr: - lenIndErr = len(indErr) - block = [] - blocks = [] - if lenIndErr > 1: - i = 1 - while 1: - if i == 1: - block.append(indErr[i-1]) - if indErr[i] - indErr[i-1] == 1: - block.append(indErr[i]) - else: - if block: - blocks.append(block) - block = [] - block.append(indErr[i]) - i +=1 - if i >= lenIndErr: - break - else: - block.append(indErr[0]) - if block: - blocks.append(block) - listErr = [] - for block in blocks: - string = "" - for elem in block: - string += hex(ord(text[elem]))[-2:] - listErr.append((block[0],"__hex__?%s?__hex__" %string,elem)) - textOut = text - deltaInd = 0 - for erEl in listErr: - startInd = erEl[0] + deltaInd - endInd = erEl[2] + 1 + deltaInd - textOut = textOut[:startInd] + erEl[1] + textOut[endInd:] - deltaInd += len(erEl[1])-(erEl[2]-erEl[0]+1) - #if i == 1: - #break - #i += 1 - return textOut - - def decode(self, text): - """Декодирует UTF-8 в смешанный формат""" - varStart = "__hex__\?" - varEnd = "\?__hex__" - # -1 Это экранирование '?' которое тоже считается - deltVarStart = len(varStart)-1 - deltVarEnd = len(varEnd)-1 - reVar = re.compile(("%s[a-f0-9]+%s")%(varStart,varEnd),re.M) - resS = reVar.search(text) - textProfileTmp = text - while resS: - mark = textProfileTmp[resS.start():resS.end()] - hexString = mark[deltVarStart:-deltVarEnd] - i = 0 - stringInsert = "" - hexCode = "" - for ch in hexString: - if i>=1: - hexCode += ch - stringInsert += self._hexToChar(hexCode) - hexCode = "" - i = 0 - else: - hexCode += ch - i += 1 - textProfileTmp = textProfileTmp.replace(mark, stringInsert) - resS = reVar.search(textProfileTmp) - return textProfileTmp - -class profile(_file, _terms, xmlShare): - """Класс для работы с профилями - - На вход 2 параметра: объект хранения переменных, имя сервиса - не - обязательный параметр - - """ - # Имена установленных программ - installProg = [] - # Версии установленных программ - installProgVersions = [] - - # Название файла профиля директории - profDirNameFile = ".calculate_directory" - - def __init__(self, objVar, servDir=False, dirsFilter=[], filesFilter=[]): - # Необрабатываемые директории - self.dirsFilter = dirsFilter - # Необрабатываемые файлы - self.filesFilter = filesFilter - _file.__init__(self) - # Словарь для создания объектов новых классов по образцу - self.newObjProt = {'proftpd':(apache,),} - # Заголовок title - self.__titleHead = "--------------------------------------\ -----------------------------------------" - self._titleBody = "" - self._titleList = (_("Modified"), _("File of a profile")) - - # Метки - varStart = "#-" - varEnd = "-#" - self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")%(varStart,varEnd),re.M) - self._reFunc = re.compile(("%s[a-zA-Z0-9_\-\+\(\)\, \*\/\.]+%s")\ - %(varStart,varEnd),re.M) - self._deltVarStart = len(varStart) - self._deltVarEnd = len(varEnd) - # Условия - self._reTermBloc = re.compile("#\?(?P[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] - # Преобразование восьмеричного в целое (ввод строка, вывод число) - def __octToInt(self, strOct): - if strOct: - try: - exec("res =" + "0" + strOct) - except: - self.setError (_("Not valid oct value: ") + str(strOct)) - return False - return res - else: - self.setError (_("Empty oct value")) - return False - - def removeDir(self, rmDir): - """Рекурсивное удаление директории - - входной параметр директория - """ - if not os.path.exists(rmDir): - self.printERROR(_("Not found remove dir %s") %rmDir) - return False - fileObj = _file() - # Сканируем директорию - scanObjs = fileObj.scanDirs([rmDir]) - for socketRm in scanObjs[0].sockets: - # Удаляем сокеты - if os.path.exists(socketRm): - os.remove(socketRm) - for linkRm in scanObjs[0].links: - # Удаляем ссылки - os.unlink(linkRm[1]) - for fileRm in scanObjs[0].files: - # Удаляем файлы - os.remove(fileRm) - scanObjs[0].dirs.sort(lambda x, y: cmp(len(y), len(x))) - for dirRm in scanObjs[0].dirs: - # Удаляем директории - os.rmdir(dirRm) - if rmDir: - os.rmdir(rmDir) - return True - - - def createDir(self, baseProfDir, profDir, baseDirMv, createDir): - """Создает директорию - - baseDirMv + результат вычитания из profDir baseProfDir - createDir - создаваемая директория - """ - if baseDirMv and not os.access(baseDirMv, os.F_OK): - os.makedirs(baseDirMv) - # Созданные директории - createDirs = [] - baseDir = baseProfDir - if baseProfDir[-1] == "/": - baseDir = baseProfDir[:-1] - # Директория в системе относительно baseDirMv без условий - if baseDirMv: - dirMvNoTerm = createDir.partition(baseDirMv)[2] - else: - dirMvNoTerm = createDir - # директория в системе - dirMv = profDir.partition(baseDir)[2] - if len(dirMv)>1 and dirMv[-1] == "/": - dirMv = dirMv[:-1] - ## директория в системе без условий - #dirMvNoTerm = "/".join(map(lambda x:x.split("?")[0],\ - #dirMv.split("/"))) - listDirMv = dirMv.split("/") - listDirMvNoTerm = dirMvNoTerm.split("/") - if len(listDirMv) != len(listDirMvNoTerm): - self.setError (_("Error in profile") + " :" + profDir) - return False - genIn = listDirMv.__iter__() - genOut = listDirMvNoTerm.__iter__() - inAndOutDirs = map(lambda x: [x,genOut.next()], genIn) - createDirs = [] - createDir = [] - while (len(inAndOutDirs)>1): - tmpDirIn = baseDir+"/".join(map(lambda x:x[0], inAndOutDirs)) - tmpDirOut = baseDirMv + "/".join(map(lambda x:x[1],\ - inAndOutDirs)) - if os.access(tmpDirOut, os.F_OK): - break - else: - createDir.append((tmpDirIn, tmpDirOut)) - inAndOutDirs.pop() - createDir.reverse() - for crDirIn,crDirOut in createDir: - try: - mode,uid,gid = self.getModeFile(crDirIn) - except OSError: - self.setError (_("not access dir:" ) + crDirIn) - return False - createDirs.append(crDirOut) - os.mkdir(crDirOut, mode) - os.chown(crDirOut, uid, gid) - return createDirs - - - def applyVarsProfile(self, textProfile, nameProfile): - """ Заменяет переменные на их значения - """ - resS = self._reVar.search(textProfile) - textProfileTmp = textProfile - while resS: - mark = textProfileTmp[resS.start():resS.end()] - varName = mark[self._deltVarStart:-self._deltVarEnd] - varValue = "" - try: - varValue = str(self.objVar.Get(varName)) - except self.objVar.DataVarsError, e: - print _("error in profile %s")%nameProfile - print e - cl_base.exit(1) - textProfileTmp = textProfileTmp.replace(mark, varValue) - resS = self._reVar.search(textProfileTmp) - return textProfileTmp - - - def applyFuncProfile(self, textProfile, nameProfile, nameSystemFile): - """ Применяет функции к тексту профиля - """ - def equalTerm(term, sNum, sMD, localVars): - """Локальная функция для вычисления выражения""" - terms = sNum.findall(term) - if terms: - strNumers = [] - for n in terms: - strNum = n.strip() - if "*" in strNum or "/" in strNum: - strNum = multAndDiv(strNum,sNum,sMD,localVars) - try: - num = int(strNum) - except: - minus = False - if strNum[:1] == "-": - minus = True - strNum = strNum[1:] - if localVars.has_key(strNum): - num = localVars[strNum] - elif self.objVar.exists(strNum): - try: - num = int(self.objVar.Get(strNum)) - except: - print _("error in profile %s")%nameProfile - print _("error var %s not int")%str(strNum) - cl_base.exit(1) - else: - print _("error in profile %s")%nameProfile - print _("error local var %s not defined")\ - %str(strNum) - cl_base.exit(1) - if minus: - num =-num - strNumers.append(num) - return sum(strNumers) - print _("error in profile %s")%nameProfile - print _("error profile term %s, incorrect data")%str(term) - cl_base.exit(1) - - def multAndDiv(term,sNum,sMD,localVars): - """локальная функция для умножения и деления""" - termTmp = term - varsLocal = sMD.findall(term) - for var in varsLocal: - flagVarTxt = True - try: - int(var) - except: - flagVarTxt = False - if flagVarTxt: - continue - varReplace = str(equalTerm(var,sNum,sMD,localVars)) - termTmp = termTmp.replace(var,varReplace) - ret = eval(termTmp) - return ret - - def funcSum(funTxt,resS,localVars,textProfileTmp): - """локальная функция вычисляет первую функцию sum() в профиле""" - terms = funTxt[4:-1].replace(" ","").split(",") - # Название локальной переменной - nameLocVar = terms[0] - if not localVars.has_key(nameLocVar): - localVars[nameLocVar] = 0 - if len(terms) == 2: - if terms[1].strip(): - localVars[nameLocVar] = equalTerm(terms[1],sNum,sMD, - localVars) - replace = str(localVars[nameLocVar]) - else: - replace = "" - textProfileTmp = textProfileTmp[:resS.start()] + replace +\ - textProfileTmp[resS.end():] - elif len(terms) == 3: - if terms[1].strip(): - replaceInt = equalTerm(terms[1],sNum,sMD,localVars) - replace = str(replaceInt) - else: - replace = "" - localVars[nameLocVar] = equalTerm(terms[2], - sNum,sMD,localVars) - textProfileTmp = textProfileTmp[:resS.start()] + replace +\ - textProfileTmp[resS.end():] - else: - print _("error in profile %s")%nameProfile - print _("error profile term %s")%str(funTxt) - cl_base.exit(1) - return textProfileTmp - - def funcLoad(funTxt,resS,textProfileTmp): - """если файл существует читает из файла локальную переменную - - если один параметр - выводит значение локальной переменной - """ - terms = funTxt[5:-1].replace(" ","").split(",") - if not terms[0].strip() or\ - (len(terms)==2 and not terms[1].strip()) or\ - len(terms)>2: - print _("error in profile %s")%nameProfile - print _("error profile term %s")%str(funTxt) - cl_base.exit(1) - if len(terms) == 2: - if not terms[0] in ["ver","num","char","key"]: - print _("error in profile %s")%nameProfile - print _("error profile term %s")%str(funTxt) - print _("first argument function is not 'ver' or 'num' or\ - 'char'") - cl_base.exit(1) - if len(terms) == 1: - fileName = terms[0].strip() - if fileName[0] != "/": - path = os.path.split(nameSystemFile)[0] - fileName=os.path.join(path,fileName) - else: - fileName = terms[1].strip() - if fileName[1] != "/": - path = os.path.split(nameSystemFile)[0] - fileName=os.path.join(path,fileName) - replace = "" - if os.path.exists(fileName): - FD = open(fileName) - replace = FD.read().strip() - FD.close - if not replace and len(terms) == 2 and terms[0] in ["ver","num"]: - replace = "0" - textProfileTmp = textProfileTmp[:resS.start()] + replace +\ - textProfileTmp[resS.end():] - return textProfileTmp - - def getInstallPkgGentoo(): - """Выдает два списка, инсталлированные программы и номера версий""" - baseDir = "/var/db/pkg" - pkgs = [] - reVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*") - def getFilesDir(pkgs, dirname, names): - for nameFile in names: - absNameFile = os.path.join(dirname,nameFile) - if os.path.isdir(absNameFile): - tail = absNameFile.split(baseDir) - if len(tail)==2: - tail = tail[1].split('/') - if len(tail)==3 and tail[1]!='virtual': - pkgs.append(tail[2]) - return True - os.path.walk(baseDir,getFilesDir, pkgs) - pkgs.sort() - names = [] - versions = [] - for pkg in pkgs: - findVer = reVer.search(pkg) - if findVer: - ver = findVer.group() - versions.append(ver) - names.append(pkg.split(ver)[0][:-1]) - #return pkgs - return names, versions - - def pkg(nameProg, names, versions): - """Выдает установленные версии по имени программы""" - i = 0 - vers = [] - for name in names: - if nameProg == name: - while nameProg == names[i]: - vers.append(versions[i]) - i += 1 - break - i += 1 - if vers: - return vers[-1] - else: - return "" - - def funcPkg(funTxt,resS,textProfileTmp): - """локальная функция выдает номер версии программы""" - terms = funTxt[4:-1].replace(" ","") - # Название программы - nameProg = terms - if not self.installProg: - self.installProg,self.installProgVersions=getInstallPkgGentoo() - replace = pkg(nameProg,self.installProg,self.installProgVersions) - textProfileTmp = textProfileTmp[:resS.start()] + replace +\ - textProfileTmp[resS.end():] - return textProfileTmp - - def funcRnd(funTxt,resS,textProfileTmp): - """локальная функция выдает строку случайных символов - - первый аргумент: - 'num' - числа, - 'pas' - цифры и буквы - второй аргумент: - количество символов - """ - terms = funTxt[4:-1].replace(" ","").split(",") - if not terms[0].strip() or\ - (len(terms)==2 and not terms[1].strip()) or\ - len(terms)!=2: - print _("error in profile %s")%nameProfile - print _("error profile term %s")%str(funTxt) - cl_base.exit(1) - fArgvNames = ['num','pas'] - if not terms[0] in fArgvNames: - print _("error in profile %s")%nameProfile - print _("error profile term %s")%str(funTxt) - print _("first argument function is not 'num' or 'pas'") - cl_base.exit(1) - try: - lenStr = int(terms[1]) - except: - print _("error in profile %s")%nameProfile - print _("error profile term %s")%str(funTxt) - print _("two argument function is not number") - cl_base.exit(1) - if terms[0] == fArgvNames[0]: - replace=''.join([random.choice(string.digits)\ - for i in xrange(lenStr)]) - elif terms[0] == fArgvNames[1]: - replace=''.join([random.choice(string.ascii_letters + \ - string.digits) for i in xrange(lenStr)]) - else: - print _("error in profile %s")%nameProfile - print _("error profile term %s")%str(funTxt) - cl_base.exit(1) - textProfileTmp = textProfileTmp[:resS.start()] + replace +\ - textProfileTmp[resS.end():] - return textProfileTmp - - def funcCase(funTxt,resS,textProfileTmp): - """локальная функция выдает переменную в определенном регистре - - первый аргумент: - 'upper' - верхний регистр, - 'lower' - нижний регистр, - 'capitalize' - первая буква в верхнем регистре - второй аргумент: - название переменной - """ - terms = funTxt[5:-1].replace(" ","").split(",") - if not terms[0].strip() or\ - (len(terms)==2 and not terms[1].strip()) or len(terms)!=2: - print _("error in profile %s")%nameProfile - print _("error profile term %s")%str(funTxt) - cl_base.exit(1) - fArgvNames = ['upper','lower','capitalize'] - if not terms[0] in fArgvNames: - print _("error in profile %s")%nameProfile - print _("error profile term %s")%str(funTxt) - print _("first argument function is not 'upper' or 'lower' or\ - 'capitalize'") - cl_base.exit(1) - try: - strValue = str(self.objVar.Get(terms[1])) - except: - print _("error in profile %s")%nameProfile - print _("error var %s not found")%str(terms[1]) - cl_base.exit(1) - replace = "" - strValue = self._toUNICODE(strValue) - if terms[0] == 'upper': - replace = strValue.upper() - elif terms[0] == 'lower': - replace = strValue.lower() - elif terms[0] == 'capitalize': - replace = strValue.capitalize() - if replace: - replace = replace.encode("UTF-8") - textProfileTmp = textProfileTmp[:resS.start()] + replace +\ - textProfileTmp[resS.end():] - return textProfileTmp - - # Локальные переменные - localVars = {} - # Регулярное выражние для сложения - sNum = re.compile("\-[^\-\+]+|[^\-\+]+") - # Регулярное выражение для умножениея и деления - sMD = re.compile("[^\-\+\*\/]+") - resS = self._reFunc.search(textProfile) - textProfileTmp = textProfile - while resS: - mark = textProfileTmp[resS.start():resS.end()] - funTxt = mark[self._deltVarStart:-self._deltVarEnd] - # Функция sum - if funTxt[:4] == "sum(": - textProfileTmp = funcSum(funTxt,resS,localVars,textProfileTmp) - resS = self._reFunc.search(textProfileTmp) - # Функция load - elif funTxt[:5] == "load(": - textProfileTmp = funcLoad(funTxt,resS,textProfileTmp) - resS = self._reFunc.search(textProfileTmp) - elif funTxt[:4] == "pkg(": - textProfileTmp = funcPkg(funTxt,resS,textProfileTmp) - resS = self._reFunc.search(textProfileTmp) - elif funTxt[:4] == "rnd(": - textProfileTmp = funcRnd(funTxt,resS,textProfileTmp) - resS = self._reFunc.search(textProfileTmp) - elif funTxt[:5] == "case(": - textProfileTmp = funcCase(funTxt,resS,textProfileTmp) - resS = self._reFunc.search(textProfileTmp) - else: - resS = False - return textProfileTmp - - def applyTermsProfile(self, textProfile, nameProfile, nameSystemFile=False): - """ Применяет условия, к условным блокам текста - """ - textTerm = "" - resS = self._reTermBloc.search(textProfile) - textProfileTmp = textProfile - def function(text): - """Функция обработки функций в заголовке""" - return self.applyFuncProfile(text, nameProfile, nameSystemFile) - if nameSystemFile: - while resS: - mark = resS.group(0) - body = resS.group("body") - end = resS.group("end") - parent = resS.group("func") - if not parent: - parent = "" - term = resS.group("rTerm") + parent +\ - resS.group("lTerm") - if self._equalTerm(term, _("content profile not valid: ")+\ - nameProfile, function): - textProfileTmp = textProfileTmp.replace(mark, body+end) - else: - textProfileTmp = textProfileTmp.replace(mark, "") - resS = self._reTermBloc.search(textProfileTmp) - else: - while resS: - mark = resS.group(0) - body = resS.group("body") - end = resS.group("end") - term = resS.group("rTerm") + resS.group("lTerm") - if self._equalTerm(term, _("content profile not valid: ")+\ - nameProfile): - textProfileTmp = textProfileTmp.replace(mark, body+end) - else: - textProfileTmp = textProfileTmp.replace(mark, "") - resS = self._reTermBloc.search(textProfileTmp) - return textProfileTmp - - def getNeedProfile(self, fileProfile): - """Применяем правила к названию файла""" - dirP,fileP = os.path.split(fileProfile) - if fileP: - spFile = fileP.split("?") - realFileName = spFile[0] - if len(spFile)>1: - flagTrue = False - for term in spFile[1:]: - if self._equalTerm(term, _("name profile not valid: ")+\ - fileProfile): - flagTrue = True - break - if flagTrue: - return True - else: - return False - else: - return True - else: - self.setError (_("name profile not valid: ")+ str(fileProfile)) - return False - - def getTitle(self, comment, commentList): - """Выдает заголовок профиля ( версия и.т.д)""" - if comment: - commentFirst = comment - commentInsert = comment - commentLast = comment - flagList = False - # В случае открывающего и закрывающего комментария - if type(comment) == types.TupleType and len(comment) == 2: - commentFirst = comment[0] - commentInsert = "" - commentLast = comment[1] - flagList = True - if flagList: - self._titleBody = commentFirst + "\n" - else: - self._titleBody = commentFirst + self.__titleHead + "\n" - z = 0 - lenCommentList = len(commentList) - 1 - for com in self._titleList: - if lenCommentList < z: - self._titleBody += commentInsert + " " + com + "\n" - else: - self._titleBody += commentInsert + " " + com +\ - " " + commentList[z] + "\n" - z += 1 - if flagList: - self._titleBody += commentLast +"\n" - else: - self._titleBody += commentLast + self.__titleHead + "\n" - return self._titleBody - else: - return "" - - def numberAllProfiles(self, number): - """Количество профилей - - Вызов происходит перед наложением профилей - в момент вызова в number находится количество обрабатываемых файлов - Наследуемая функция - Используется для отображения прогресса при наложениии профилей - """ - return True - - def numberProcessProfiles(self, number): - """Номер текущего обрабатываемого профиля - - Вызов происходит при наложении профиля - в момент вызова в number находится номер обрабатываемого профиля - Наследуемая функция - Используется для отображения прогресса при наложениии профилей - """ - return True - - - def scanDirs(self, profilesDirs, objVar=False): - """Измененный метод сканирования директорий""" - dirs = [] - class dirProf: - def __init__(self): - self.baseDir = False - self.dirs = [] - self.files = [] - self.links = [] - self.sockets = [] - flagError = False - blockDirs = [] - def getFilesDir(dirP, dirname, names): - for nameFile in names: - absNameFile = dirname + "/" + nameFile - findBlock = False - for blDir in blockDirs: - st,mid,end = absNameFile.partition(blDir) - if (not st) and mid and end: - findBlock = True - break - if not findBlock: - if os.path.islink(absNameFile): - dest = absNameFile - src = os.readlink(absNameFile) - dirP.links.append((src,dest)) - elif os.path.isfile(absNameFile): - # Добавляем файлы кроме описаний директорий - if self.profDirNameFile != nameFile: - dirP.files.append(absNameFile) - elif os.path.isdir(absNameFile): - # Обработка условий в названии директории - if self.getNeedProfile(absNameFile): - if self.getError(): - blockDirs.append(absNameFile) - flagError = True - break - dirP.dirs.append(absNameFile) - else: - if self.getError(): - blockDirs.append(absNameFile) - flagError = True - break - blockDirs.append(absNameFile) - elif stat.S_ISSOCK(os.stat(absNameFile)[stat.ST_MODE]): - dirP.sockets.append(absNameFile) - for profileDir in profilesDirs: - if profileDir: - # Обработка условий в названии директории - if self.getNeedProfile(profileDir): - if self.getError(): - flagError = True - break - dirP = dirProf() - dirP.baseDir = profileDir - dirs.append(dirP) - os.path.walk(profileDir, getFilesDir, dirP) - else: - if self.getError(): - flagError = True - break - if flagError: - return [] - return dirs - - - def applyProfiles(self): - """Применяет профили к конфигурационным файлам""" - if not self.objVar.defined("cl_profile_path"): - self.setError (_("not defined Var: ") + "cl_profile_path") - return False - dirsProfiles = self.objVar.Get("cl_profile_path") - dirsProfiles.sort() - if self._servDir: - tmpDirsProfiles = [] - for dirP in dirsProfiles: - dirProf = dirP + self._servDir - if os.access(dirProf, os.F_OK): - # Если директория существует - tmpDirsProfiles.append(dirProf) - else: - tmpDirsProfiles.append(False) - dirsProfiles = tmpDirsProfiles - dirObjs = self.scanDirs(dirsProfiles,self.objVar) - #файлы к которым были применены профили - filesApply = [] - # Словарь измененных директорий - changeDirs = {} - #созданные директории - createdDirs = [] - # Получаем общее количество профилей (нужно для прогресбара) - allApplyFiles = self.scanProfiles(False, dirObjs) - if allApplyFiles == False: - return False - numberAllProfiles = len(allApplyFiles) - # Вызываем пустой метод с параметром общее количество профилей - self.numberAllProfiles(numberAllProfiles) - # номер обрабатываемого файла - numberProcessProfiles = 0 - # имя текущей программы - _nameProgram = self.objVar.Get("cl_name").capitalize() - # версия текущей программы - _versionProgram = self.objVar.Get("cl_ver") - # имя и версия текущей программы - programVersion = "%s %s"%(_nameProgram, _versionProgram) - dirObjsApply = [] - for dirObj in dirObjs: - dirInfoFile = os.path.join(dirObj.baseDir, self.profDirNameFile) - ret = self.__isApplyHeadDir(dirInfoFile) - if ret: - dirObjsApply.append(dirObj) - else: - if self.getError(): - self.setError(_("Incorrect profile: " ) +\ - dirInfoFile) - return False - for dirObj in dirObjsApply: - # сортируем файлы по названию - if dirObj.files: - dirObj.files.sort() - # сортируем директории по названию - if dirObj.dirs: - dirObj.dirs.sort() - blockDirs = [] - for dirProfile in dirObj.dirs: - newDir = self._baseDir + dirProfile.partition(dirObj.baseDir)[2] - newDir = "/".join(map(lambda x:x.split("?")[0],\ - newDir.split("/"))) - # Проверяем условие на директорию - dirInfoFile = os.path.join(dirProfile, self.profDirNameFile) - pathDir, objHeadDir = self.__getApplyHeadDir(newDir, - dirInfoFile, - changeDirs) - # Фильтрация профилей по названию директории - if pathDir in self.dirsFilter: - blockDirs.append(dirProfile) - continue - if objHeadDir: - if isinstance(objHeadDir, dirHeader): - if not objHeadDir.headerCorrect: - self.setError(_("Incorrect profile: " ) +\ - dirInfoFile) - self.setError(objHeadDir.errorMessage) - return False - if not objHeadDir.headerTerm: - if objHeadDir.getError(): - self.setError(_("Incorrect profile: " ) +\ - dirInfoFile) - return False - if objHeadDir.params.has_key("name"): - changeDirs[dirProfile] = pathDir - crDirs = self.createDir(dirObj.baseDir, dirProfile, - self._baseDir, pathDir) - if crDirs == False: - return False - createdDirs += crDirs - else: - if self.getError(): - self.setError(_("Incorrect profile: " ) +\ - dirInfoFile) - return False - blockDirs.append(dirProfile) - for fileProfile in dirObj.files: - findBlock = False - for blDir in blockDirs: - st,mid,end = fileProfile.partition(blDir) - if (not st) and mid and end: - findBlock = True - break - if findBlock: - continue - numberProcessProfiles += 1 - self.numberProcessProfiles(numberProcessProfiles) - if self.getNeedProfile(fileProfile): - if self.getError(): - #print self.getError() - return False - fileProfileChange = fileProfile - findChangeDir = False - listD = changeDirs.items() - listD.reverse() - for dirChangeIn, dirChangeOut in listD: - st,mid,end = fileProfile.partition(dirChangeIn) - if (not st) and mid and end: - findChangeDir = True - break - if findChangeDir: - oldFile = dirChangeOut + end - else: - oldFile = fileProfile.partition(dirObj.baseDir)[2] - # файл в системе без условий - oldFile = "/".join(map(lambda x:x.split("?")[0],\ - oldFile.split("/"))) - if not findChangeDir: - oldFile = self._baseDir + oldFile - # Фильтрация профилей по названию файла - if oldFile in self.filesFilter: - continue - listProfTitle = dirObj.baseDir.split("/")[-2:] - profTitle = '"' + "/".join(listProfTitle) + '"' - # Записываем в переменную обрабатываемый файл - self.objVar.Set("cl_pass_file",oldFile) - filesApl = self.join(fileProfile, oldFile, - (programVersion,profTitle)) - if filesApl: - filesApply += filesApl - else: - if self.getError(): - #print self.getError() - return False - self.closeFiles() - return (createdDirs, filesApply) - - def __getGenHeadDir(self, newDir, profileDirFile, changeDirs): - """Определяет название создаваемой директории""" - - def function(text): - """Функция обработки функций в заголовке""" - return self.applyFuncProfile(text, newDir, profileDirFile) - - newDirMv = newDir - findChangeDir = False - #Меняем путь к директории - listD = changeDirs.items() - listD.reverse() - for dirChangeIn, dirChangeOut in listD: - st,mid,end = profileDirFile.partition(dirChangeIn) - if (not st) and mid: - findChangeDir = True - break - if findChangeDir: - pathRel = dirChangeOut - lenPathRel = len(pathRel.split("/")) - lenNewDir = len(newDir.split("/")) - lenEndDir = lenNewDir - lenPathRel - tmpDir = newDir - namesDirs = [] - for i in range(lenEndDir): - namesDirs.append(os.path.split(tmpDir)[1]) - tmpDir = os.path.split(tmpDir)[0] - namesDirs.reverse() - nameDir = "/".join(namesDirs) - newDirMv = os.path.join(pathRel, nameDir) - applyDir = newDirMv - if not os.path.exists(profileDirFile): - return (applyDir, True) - try: - FD = open(profileDirFile) - textProfile = FD.read() - FD.close() - except: - self.setError(_("Error open profile: " ) +\ - profileDirFile) - return (applyDir, False) - objHead = dirHeader(textProfile, self.objVar,function) - if not objHead.headerCorrect: - self.setError(_("Incorrect profile: " ) +\ - profileDirFile) - self.setError(objHead.errorMessage) - return (applyDir, False) - if not objHead.headerTerm: - if objHead.getError(): - self.setError(_("Incorrect profile: " ) +\ - profileDirFile) - return (applyDir, False) - # Изменяем название директории - if objHead.params.has_key("name"): - nameDir = objHead.params['name'] - if "/" in nameDir or nameDir == ".." or nameDir == ".": - self.setError (_("False value 'name' in profile: " ) +\ - profileDirFile) - return (applyDir, False) - if not findChangeDir: - pathRel = os.path.split(os.path.abspath(newDirMv))[0] - # Новый путь к оригинальному файлу - newDirMv = os.path.join(pathRel, nameDir) - applyDir = newDirMv - # При удаленнии директории - if objHead.typeAppend == "remove": - return (applyDir, False) - return (applyDir, objHead) - - def scanProfiles(self, serviceName=False, dirObjs=False): - """Сканирует директории профилей - выводит список файлов""" - if not self.objVar.defined("cl_profile_path"): - self.setError (_("not defined Var: ") + "cl_profile_path") - return False - if not dirObjs: - if serviceName : - self._servDir = serviceName - if self._servDir: - if self._servDir[0] != "/": - self._servDir = "/" + self._servDir - if self._servDir[-1] != "/": - self._servDir += "/" - self._servDir = os.path.split(self._servDir)[0] - dirsProfiles = self.objVar.Get("cl_profile_path") - if self._servDir: - tmpDirsProfiles = [] - for dirP in dirsProfiles: - dirProf = dirP + self._servDir - if os.access(dirProf, os.F_OK): - # Если директория существует - tmpDirsProfiles.append(dirProf) - else: - tmpDirsProfiles.append(False) - dirsProfiles = tmpDirsProfiles - dirObjs = self.scanDirs(dirsProfiles,self.objVar) - #файлы к которым были применены профили - filesApply = [] - # Словарь измененных директорий - changeDirs = {} - dirObjsApply = [] - for dirObj in dirObjs: - dirInfoFile = os.path.join(dirObj.baseDir, self.profDirNameFile) - ret = self.__isApplyHeadDir(dirInfoFile) - if ret: - dirObjsApply.append(dirObj) - else: - if self.getError(): - self.setError(_("Incorrect profile: " ) +\ - dirInfoFile) - return False - for dirObj in dirObjsApply: - # сортируем файлы по названию - if dirObj.files: - dirObj.files.sort() - # сортируем директории по названию - if dirObj.dirs: - dirObj.dirs.sort() - blockDirs = [] - for dirProfile in dirObj.dirs: - newDir = self._baseDir + dirProfile.partition(dirObj.baseDir)[2] - newDir = "/".join(map(lambda x:x.split("?")[0],\ - newDir.split("/"))) - # Проверяем условие на директорию - dirInfoFile = os.path.join(dirProfile, self.profDirNameFile) - pathDir, objHeadDir = self.__getGenHeadDir(newDir, - dirInfoFile, - changeDirs) - # Фильтрация профилей по названию директории - if pathDir in self.dirsFilter: - blockDirs.append(dirProfile) - continue - if objHeadDir: - if isinstance(objHeadDir, dirHeader): - if not objHeadDir.headerCorrect: - self.setError(_("Incorrect profile: " ) +\ - dirInfoFile) - self.setError(objHeadDir.errorMessage) - return False - if not objHeadDir.headerTerm: - if objHeadDir.getError(): - self.setError(_("Incorrect profile: " ) +\ - dirInfoFile) - return False - if objHeadDir.params.has_key("name"): - changeDirs[dirProfile] = pathDir - else: - if self.getError(): - self.setError(_("Incorrect profile: " ) +\ - dirInfoFile) - return False - blockDirs.append(dirProfile) - for fileProfile in dirObj.files: - findBlock = False - for blDir in blockDirs: - st,mid,end = fileProfile.partition(blDir) - if (not st) and mid and end: - findBlock = True - break - if findBlock: - continue - if self.getNeedProfile(fileProfile): - if self.getError(): - #print self.getError() - return False - fileProfileChange = fileProfile - findChangeDir = False - listD = changeDirs.items() - listD.reverse() - for dirChangeIn, dirChangeOut in listD: - st,mid,end = fileProfile.partition(dirChangeIn) - if (not st) and mid and end: - findChangeDir = True - break - if findChangeDir: - oldFile = dirChangeOut + end - else: - oldFile = fileProfile.partition(dirObj.baseDir)[2] - # файл в системе без условий - oldFile = "/".join(map(lambda x:x.split("?")[0],\ - oldFile.split("/"))) - if not findChangeDir: - oldFile = self._baseDir + oldFile - # Фильтрация профилей по названию файла - if oldFile in self.filesFilter: - continue - filesApply.append(oldFile) - else: - if self.getError(): - return False - return filesApply - - def __isApplyHeadDir(self, profileDirFile): - """Будет ли применен профиль корневой директории - - Возвращает True, False - """ - - def function(text): - """Функция обработки функций в заголовке""" - return self.applyFuncProfile(text, "", profileDirFile) - - if not os.path.exists(profileDirFile): - return True - try: - FD = open(profileDirFile) - textProfile = FD.read() - FD.close() - except: - self.setError(_("Error open profile: " ) +\ - profileDirFile) - return False - # Заменяем переменные на их значения - textProfile = self.applyVarsProfile(textProfile, profileDirFile) - # Обработка заголовка - objHead = dirHeader(textProfile, self.objVar,function) - if not objHead.headerCorrect: - self.setError(_("Incorrect profile: " ) +\ - profileDirFile) - self.setError(objHead.errorMessage) - return False - if not objHead.headerTerm: - if objHead.getError(): - self.setError(_("Incorrect profile: " ) +\ - profileDirFile) - return False - - # Изменяем название директории - if objHead.params.has_key("name"): - self.setError (_("Invalid name 'name' in profile: " ) +\ - profileDirFile) - return False - - # Удаляем директорию - if objHead.typeAppend == "remove": - self.setError (_("Invalid name 'remove' in profile: " ) +\ - profileDirFile) - return False - - # chmod - изменяем права - if objHead.params.has_key("chmod"): - self.setError (_("Invalid name 'chmod' in profile: " ) +\ - profileDirFile) - return False - - # chown - изменяем владельца и группу - if objHead.params.has_key("chown"): - self.setError (_("Invalid name 'chown' in profile: " ) +\ - profileDirFile) - return False - return True - - def __getApplyHeadDir(self, newDir, profileDirFile, changeDirs): - """Применяет профиль к директории (права, владелец, и.т. д)""" - - def function(text): - """Функция обработки функций в заголовке""" - return self.applyFuncProfile(text, newDir, profileDirFile) - - newDirMv = newDir - findChangeDir = False - #Меняем путь к директории - listD = changeDirs.items() - listD.reverse() - for dirChangeIn, dirChangeOut in listD: - st,mid,end = profileDirFile.partition(dirChangeIn) - if (not st) and mid: - findChangeDir = True - break - if findChangeDir: - pathRel = dirChangeOut - lenPathRel = len(pathRel.split("/")) - lenNewDir = len(newDir.split("/")) - lenEndDir = lenNewDir - lenPathRel - tmpDir = newDir - namesDirs = [] - for i in range(lenEndDir): - namesDirs.append(os.path.split(tmpDir)[1]) - tmpDir = os.path.split(tmpDir)[0] - namesDirs.reverse() - nameDir = "/".join(namesDirs) - newDirMv = os.path.join(pathRel, nameDir) - applyDir = newDirMv - if not os.path.exists(profileDirFile): - return (applyDir, True) - try: - FD = open(profileDirFile) - textProfile = FD.read() - FD.close() - except: - self.setError(_("Error open profile: " ) +\ - profileDirFile) - return (applyDir, False) - # Заменяем переменные на их значения - textProfile = self.applyVarsProfile(textProfile, profileDirFile) - # Обработка заголовка - objHead = dirHeader(textProfile, self.objVar,function) - if not objHead.headerCorrect: - self.setError(_("Incorrect profile: " ) +\ - profileDirFile) - self.setError(objHead.errorMessage) - return (applyDir, False) - if not objHead.headerTerm: - if objHead.getError(): - self.setError(_("Incorrect profile: " ) +\ - profileDirFile) - return (applyDir, False) - - # Изменяем название директории - if objHead.params.has_key("name"): - nameDir = objHead.params['name'] - if "/" in nameDir or nameDir == ".." or nameDir == ".": - self.setError (_("False value 'name' in profile: " ) +\ - profileDirFile) - return (applyDir, False) - if not findChangeDir: - pathRel = os.path.split(os.path.abspath(newDirMv))[0] - # Новый путь к оригинальному файлу - newDirMv = os.path.join(pathRel, nameDir) - applyDir = newDirMv - - # Удаляем директорию - if objHead.typeAppend == "remove": - if os.path.isdir(newDirMv): - # удаляем директорию - try: - self.removeDir(newDirMv) - except: - self.setError(_("Can not delete dir: " ) +\ - newDirMv) - return (applyDir, False) - - # chmod - изменяем права - if objHead.params.has_key("chmod"): - mode = self.__octToInt(objHead.params['chmod']) - if mode: - if not os.path.exists(newDirMv): - os.mkdir(newDirMv, mode) - else: - os.chmod(newDirMv, mode) - else: - self.setError (_("False value 'chmod' in profile: " ) +\ - profileDirFile) - return (applyDir, False) - # chown - изменяем владельца и группу - if objHead.params.has_key("chown"): - owner = objHead.params['chown'] - if owner: - if ":" in owner: - strUid, strGid = owner.split(":") - import pwd - try: - uid = pwd.getpwnam(strUid)[2] - except: - self.setError (_("Not user in this system: ") + strUid) - self.setError (_("False value 'chown' in profile: " )+\ - profileDirFile) - return (applyDir, False) - try: - import grp - gid = grp.getgrnam(strGid)[2] - except: - self.setError (_("Not group in this system: ")+strGid) - self.setError (_("False value 'chown' in profile: " )+\ - profileDirFile) - return (applyDir, False) - - if not os.path.exists(newDirMv): - dirProfile = os.path.split(profileDirFile)[0] - try: - mode,uidTmp,gidTmp = self.getModeFile(dirProfile) - except OSError: - self.setError (_("not access dir:" ) + newDirMv) - return (applyDir, False) - os.mkdir(newDirMv, mode) - os.chown(newDirMv, uid, gid) - else: - self.setError (_("False value 'chown' in profile: " ) +\ - profileDirFile) - return (applyDir, False) - else: - self.setError (_("False value 'chown' in profile: " ) +\ - profileDirFile) - return (applyDir, False) - return (applyDir, objHead) - - def __getApplyHeadProfile(self ,newFile, oldFile, copyFile): - """Применяет заголовок к профилю (права, владелец, и.т. д)""" - - def function(text): - """Функция обработки функций в заголовке""" - return self.applyFuncProfile(text, newFile, oldFile) - - self.closeFiles() - # Файлы в системе к которым были применены профили - applyFiles = [oldFile] - if copyFile: - self.nameFileNew = self.absFileName(newFile) - self.FN = self.openNewFile(self.nameFileNew) - self.newProfile = self.FN.read() - self.closeNewFile() - objHeadNew = fileHeader(self.newProfile, False, - self.getFileType(),objVar=self.objVar, - function=function) - if not objHeadNew.headerCorrect: - self.setError(_("Incorrect profile: " ) +\ - newFile) - self.setError(objHeadNew.errorMessage) - return (applyFiles, False) - if not objHeadNew.headerTerm: - if objHeadNew.getError(): - self.setError(_("Incorrect profile: " ) +\ - newFile) - return (applyFiles, False) - - pathProg = "" - # Путь к оригинальному файлу - pathOldFile = oldFile - # Изменяем путь к оригинальному файлу - if objHeadNew.params.has_key("name"): - nameFile = objHeadNew.params['name'] - if "/" in nameFile or nameFile == ".." or nameFile == ".": - self.setError (_("False value 'name' in profile: " ) + newFile) - return False - pathRel = os.path.split(os.path.abspath(oldFile))[0] - # Новый путь к оригинальному файлу - pathOldFile = os.path.join(pathRel,nameFile) - - # В случае force - if objHeadNew.params.has_key("force"): - if os.path.islink(pathOldFile): - # удаляем ссылку - try: - os.unlink(pathOldFile) - except: - self.setError(_("Can not delete link: " ) +\ - pathOldFile) - return (applyFiles, False) - if os.path.isfile(pathOldFile): - # удаляем файл - try: - os.remove(pathOldFile) - except: - self.setError(_("Can not delete file: " ) +\ - pathOldFile) - return (applyFiles, False) - - # Удаляем оригинальный файл - if objHeadNew.typeAppend == "remove": - if os.path.islink(pathOldFile): - # удаляем ссылку - try: - os.unlink(pathOldFile) - except: - self.setError(_("Can not delete link: " ) +\ - pathOldFile) - if os.path.isfile(pathOldFile): - # удаляем файл - try: - os.remove(pathOldFile) - except: - self.setError(_("Can not delete file: " ) +\ - pathOldFile) - return (applyFiles, False) - - flagSymlink = False - flagForce = False - # Если есть параметр mirror - if objHeadNew.params.has_key("mirror"): - if objHeadNew.params.has_key("link"): - profileFile = objHeadNew.params['link'] - if not os.path.exists(profileFile): - if os.path.exists(pathOldFile): - os.remove(pathOldFile) - return (applyFiles, False) - elif not os.path.exists(pathOldFile): - return (applyFiles, False) - # Если есть указатель на файл профиля (link) - if objHeadNew.params.has_key("link") and\ - not objHeadNew.params.has_key("symbolic"): - profileFile = objHeadNew.params['link'] - foundProfileFile = os.path.exists(profileFile) - if foundProfileFile: - FO = self.openNewFile(profileFile) - buff = FO.read() - FO.close() - if os.path.exists(pathOldFile): - os.remove(pathOldFile) - if foundProfileFile: - fd = os.open(pathOldFile, os.O_CREAT) - os.close(fd) - os.chmod(pathOldFile, self._mode) - os.chown(pathOldFile, self._uid, self._gid) - FON = open (pathOldFile, "r+") - FON.write(buff) - FON.close() - - # Если символическая ссылка - if objHeadNew.params.has_key("symbolic"): - prevOldFile = pathOldFile - pathOldFile = objHeadNew.params['link'] - flagSymlink = True - if not "/" == pathOldFile[0]: - pathLink = os.path.split(os.path.abspath(prevOldFile))[0] - pathProg = os.getcwd() - os.chdir(pathLink) - - # chmod - изменяем права - if objHeadNew.params.has_key("chmod"): - mode = self.__octToInt(objHeadNew.params['chmod']) - if mode: - if not os.path.exists(pathOldFile): - fd = os.open(pathOldFile, os.O_CREAT) - os.close(fd) - os.chmod(pathOldFile, mode) - else: - self.setError (_("False value 'chmod' in profile: " ) +\ - newFile) - return (applyFiles, False) - - # chown - изменяем владельца и группу - if objHeadNew.params.has_key("chown"): - owner = objHeadNew.params['chown'] - if owner: - if ":" in owner: - strUid, strGid = owner.split(":") - import pwd - try: - uid = pwd.getpwnam(strUid)[2] - except: - self.setError (_("Not user in this system: ") + strUid) - self.setError (_("False value 'chown' in profile: " )+\ - newFile) - return (applyFiles, False) - try: - import grp - gid = grp.getgrnam(strGid)[2] - except: - self.setError (_("Not group in this system: ")+strGid) - self.setError (_("False value 'chown' in profile: " )+\ - newFile) - return (applyFiles, False) - - if not os.path.exists(pathOldFile): - FO = self.openNewFile(newFile) - FO.close() - fd = os.open(pathOldFile, os.O_CREAT) - os.close(fd) - os.chmod(pathOldFile, self._mode) - os.chown(pathOldFile, uid, gid) - else: - self.setError (_("False value 'chown' in profile: " ) +\ - newFile) - return (applyFiles, False) - else: - self.setError (_("False value 'chown' in profile: " ) +\ - newFile) - return (applyFiles, False) - - self.openFiles(newFile, pathOldFile) - if flagSymlink: - if os.path.exists(prevOldFile) or os.path.islink(prevOldFile): - if os.path.islink(prevOldFile): - # если ссылка то удаляем её - os.unlink(prevOldFile) - else: - # иначе удаляем файл - os.remove(prevOldFile) - if not "/" == pathOldFile[0]: - os.symlink(pathOldFile, prevOldFile) - applyFiles = [prevOldFile,os.path.join(pathLink,pathOldFile)] - else: - os.symlink(pathOldFile, prevOldFile) - applyFiles = [prevOldFile,pathOldFile] - if not objHeadNew.body.strip(): - return (applyFiles, False) - else: - applyFiles = [pathOldFile] - if pathProg: - os.chdir(pathProg) - # Если файлы заменяются не нужно их обрабатывать дальше - if objHeadNew.typeAppend == "replace" and\ - not objHeadNew.params.has_key("symbolic") and\ - objHeadNew.params.has_key("link"): - return (applyFiles, False) - return (applyFiles, objHeadNew) - - def createNewClass(self, name, bases, attrs={}): - """Создает объект нового класса - - createNewClass(self, name, bases, attrs) - name - имя класса - str, - bases - cписок наследуемых классов - (tuple), - attrs - аттрибуты класса - {dict} - """ - class newMethod: - #Объединяем конфигурации - def join(self, newObj): - if newObj.__class__.__name__ == self.__class__.__name__: - self.docObj.joinDoc(newObj.doc) - # Пост обработка - if 'postXML' in dir(self): - self.postXML() - attrsNew = {} - attrsNew["configName"] = name - if attrs: - for key in attrs.keys(): - attrsNew[key] = attrs[key] - newCl = type(name, bases + (newMethod, object,), attrsNew) - return newCl - - def fileIsUtf(self, fileName): - """Проверяет файл на кодировку UTF-8""" - if os.path.exists(fileName): - FD = open(self.absFileName(fileName)) - newProfile = FD.read() - FD.close() - try: - newProfile.decode("UTF-8") - except: - return False - return True - - def join(self, newFile, oldFile, ListOptTitle): - """Объединения профиля и конф. файла - - join(newFile, oldFile, ListOptTitle) - Объединение профиля newFile и конф. файла oldFile, - ListOptTitle - список строк которые добавятся в заголовок - """ - # Выполняем условия для блока текста а так-же заменяем переменные - self.nameFileNew = self.absFileName(newFile) - self.FN = self.openNewFile(self.nameFileNew) - self.newProfile = self.FN.read() - self.closeNewFile() - copyFile = True - if self.getFileType() != "bin": - # Вычисляем условные блоки - self.newProfile = self.applyTermsProfile(self.newProfile, - newFile, oldFile) - #print "|%s|" %(self.newProfile) - # Заменяем переменные на их значения - self.newProfile = self.applyVarsProfile(self.newProfile, - newFile) - # Вычисляем функции - self.newProfile = self.applyFuncProfile(self.newProfile, - newFile, oldFile) - copyFile = False - filesApply, objHeadNew = self.__getApplyHeadProfile(newFile, oldFile, - copyFile) - if not objHeadNew: - return filesApply - # Флаг - кодировка с бинарными примесями у файла профиля включаем при - # условии текстового файла и кодировки отличной от UTF-8 - flagNotUtf8New = False - # Флаг - кодировка с бинарными примесями у оригинального файла - flagNotUtf8Old = False - if not copyFile: - # проверяем кодировку профиля - if not self.fileIsUtf(newFile): - flagNotUtf8New = True - if not (objHeadNew.params.has_key("link") and\ - objHeadNew.params.has_key("symbolic")): - # проверяем кодировку оригинального файла - if not self.fileIsUtf(oldFile): - flagNotUtf8Old = True - self.newProfile = objHeadNew.body - #if objHeadNew.fileType != "bin": - #self.newProfile = self.applyTermsProfile(self.newProfile, - #newFile) - #self.newProfile = self.applyVarsProfile(self.newProfile) - - # Титл конфигурационного файла - title = "" - if ListOptTitle: - title = self.getTitle(objHeadNew.comment, - ListOptTitle) - title = title.encode("UTF-8") - - objHeadOld = False - if objHeadNew.comment: - objHeadOld = fileHeader(self.oldProfile, objHeadNew.comment) - # Тестирование - #print self.nameFileOld - #print objHeadNew.typeAppend - if objHeadNew.fileType: - # Создаем объект в случае параметра format в заголовке - if (objHeadNew.typeAppend == "replace" or\ - objHeadNew.typeAppend == "before" or\ - objHeadNew.typeAppend == "after") and\ - not (objHeadNew.fileType == "bin" or\ - objHeadNew.fileType == "raw"): - # Преобразовываем бинарные файлы - if flagNotUtf8New: - objTxtCoder = utfBin() - self.newProfile = objTxtCoder.encode(self.newProfile) - try: - exec ("objProfNew=%s(self.newProfile)"%\ - (objHeadNew.fileType)) - except NameError: - #Создаем объект из self.newObjProt с помощью - # метаклассов - if self.newObjProt.has_key(objHeadNew.fileType): - objProfNewCl = self.createNewClass(\ - objHeadNew.fileType, - self.newObjProt[objHeadNew.fileType]) - objProfNew = objProfNewCl(self.newProfile) - else: - self.setError (\ - _("False join profile for type profile: ")\ - + objHeadNew.fileType + " : " +\ - newFile) - return False - - if "xml_" in objHeadNew.fileType: - if objProfNew.getError(): - self.setError (_("False profile: " ) + newFile) - return False - nameRootNode = oldFile.rpartition("/")[2].split(".")[0] - objProfNew.setNameBodyNode(nameRootNode) - # Объект Документ - docObj = objProfNew.docObj - # Удаление комментариев из документа - docObj.removeComment(docObj.getNodeBody()) - # Добавление необходимых переводов строк - docObj.insertBRtoBody(docObj.getNodeBody()) - # Добавление необходимых разделителей между областями - docObj.insertBeforeSepAreas(docObj.getNodeBody()) - # Пост обработка - if 'postXML' in dir(objProfNew): - objProfNew.postXML() - # Получение текстового файла из XML документа - self.newProfile = objProfNew.getConfig().encode("UTF-8") - # Если не UTF-8 производим преобразование - if flagNotUtf8New: - self.newProfile = objTxtCoder.decode(self.newProfile) - # Титл для объединения - if ListOptTitle: - title = self.getTitle(objProfNew._comment, - ListOptTitle) - title = title.encode("UTF-8") - # Замена - if objHeadNew.typeAppend == "replace": - if "xml_" in objHeadNew.fileType: - data = self.newProfile.split("\n") - data.insert(1,title) - self.oldProfile = "\n".join(data) - else: - if objHeadNew.execStr: - self.oldProfile = objHeadNew.execStr+title+\ - self.newProfile - else: - self.oldProfile = title + self.newProfile - self.saveOldFile() - return filesApply - # Впереди - elif objHeadNew.typeAppend == "before": - if "xml_" in objHeadNew.fileType: - self.setError (\ - _("False option append=before in profile %s") %newFile) - return False - if objHeadOld and objHeadOld.body: - self.oldProfile = objHeadOld.body - if self.newProfile[-1] == "\n": - tmpProfile = self.newProfile + self.oldProfile - else: - tmpProfile = self.newProfile + "\n" + self.oldProfile - if objHeadNew.execStr: - self.oldProfile = objHeadNew.execStr + title + tmpProfile - elif objHeadOld.execStr: - self.oldProfile = objHeadOld.execStr + title + tmpProfile - else: - self.oldProfile = title + tmpProfile - - #print self.oldProfile - self.saveOldFile() - return filesApply - # Cзади - elif objHeadNew.typeAppend == "after": - if "xml_" in objHeadNew.fileType: - self.setError (\ - _("False option append=after in profile %s") %newFile) - return False - if objHeadOld and objHeadOld.body: - self.oldProfile = objHeadOld.body - if self.newProfile[-1] == "\n": - tmpProfile = self.oldProfile + self.newProfile - else: - tmpProfile = self.oldProfile + "\n" + self.newProfile - if objHeadNew.execStr: - self.oldProfile = objHeadNew.execStr + title + tmpProfile - elif objHeadOld.execStr: - self.oldProfile = objHeadOld.execStr + title + tmpProfile - else: - self.oldProfile = title + tmpProfile - self.saveOldFile() - return filesApply - # Объединение - elif objHeadNew.typeAppend == "join": - if flagNotUtf8New: - objTxtCoder = utfBin() - self.newProfile = objTxtCoder.encode(self.newProfile) - try: - exec ("objProfNew=%s(self.newProfile)"%\ - (objHeadNew.fileType)) - except NameError: - #Создаем объект из self.newObjProt с помощью - # метаклассов - if self.newObjProt.has_key(objHeadNew.fileType): - objProfNewCl = self.createNewClass(\ - objHeadNew.fileType, - self.newObjProt[objHeadNew.fileType]) - objProfNew = objProfNewCl(self.newProfile) - else: - self.setError (\ - _("False join profile for type profile: ")\ - + objHeadNew.fileType + " : " +\ - newFile) - return False - if "xml_" in objHeadNew.fileType: - if objProfNew.getError(): - self.setError (_("False profile: " ) + newFile) - return False - nameRootNode = oldFile.rpartition("/")[2].split(".")[0] - objProfNew.setNameBodyNode(nameRootNode) - # Титл для объединения - if ListOptTitle: - title = self.getTitle(objProfNew._comment, - ListOptTitle) - title = title.encode("UTF-8") - - # В случае пустого конфигурационного файла - reNoClean = re.compile("[^\s]",re.M) - if not self.oldProfile or\ - not reNoClean.search(self.oldProfile): - self.oldProfile = "" - #if objHeadNew.execStr: - #self.oldProfile = objHeadNew.execStr + \ - #title + objProfNew.getConfig().encode("UTF-8") - #else: - #self.oldProfile = title +\ - #objProfNew.getConfig().encode("UTF-8") - #self.saveOldFile() - #return True - - objHeadOld = fileHeader(self.oldProfile, objProfNew._comment) - if objHeadOld.body: - self.oldProfile = objHeadOld.body - else: - self.oldProfile = "" - if flagNotUtf8Old: - objTxtCoder = utfBin() - self.oldProfile = objTxtCoder.encode(self.oldProfile) - if self.newObjProt.has_key(objHeadNew.fileType): - objProfOldCl = self.createNewClass(\ - objHeadNew.fileType, - self.newObjProt[objHeadNew.fileType]) - objProfOld = objProfOldCl(self.oldProfile) - else: - exec ("objProfOld=%s(self.oldProfile)"%\ - (objHeadNew.fileType)) - if "xml_" in objHeadNew.fileType: - if objProfOld.getError(): - self.setError (_("False profile: " ) + oldFile) - return False - nameRootNode = oldFile.rpartition("/")[2].split(".")[0] - objProfOld.setNameBodyNode(nameRootNode) - - #print "#%s#" %(objProfOld.docObj.body.toprettyxml()) - #print "#%s#" %(objProfNew.docObj.body.toprettyxml()) - objProfOld.join(objProfNew) - #print objProfOld.doc.toprettyxml() - #print objProfNew.doc.toprettyxml() - if "xml_" in objHeadNew.fileType: - if objProfOld.getError(): - self.setError (_("False profile: " ) + newFile) - return False - data = \ - objProfOld.getConfig().encode("UTF-8").split("\n") - data.insert(1,title) - self.oldProfile = "\n".join(data) - else: - if objHeadNew.execStr: - self.oldProfile = objHeadNew.execStr + title +\ - objProfOld.getConfig().encode("UTF-8") - elif objHeadOld.execStr: - self.oldProfile = objHeadOld.execStr + title +\ - objProfOld.getConfig().encode("UTF-8") - else: - self.oldProfile = title +\ - objProfOld.getConfig().encode("UTF-8") - # Декодируем если кодировка не UTF-8 - if flagNotUtf8New or flagNotUtf8Old: - self.newProfile = objTxtCoder.decode(self.newProfile) - self.oldProfile = objTxtCoder.decode(self.oldProfile) - self.saveOldFile() - return filesApply - else: - self.setError (_("False (type append) profile: " ) +\ - objHeadNew.typeAppend) - return False - else: - self.setError (_("Type profile not found: ") + newFile) - return False - return filesApply - -class samba(objShare): - """Класс для обработки конфигурационного файла типа samba - - """ - _comment = "#" - configName = "samba" - configVersion = "0.1" - reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n",re.M) - reBody = re.compile(".+",re.M|re.S) - reComment = re.compile("\s*%s.*|\s*;.*"%(_comment)) - reSeparator = re.compile("\s*=\s*") - sepFields = "\n" - reSepFields = re.compile(sepFields) - - def __init__(self,text): - self.text = text - self.blocTextObj = blocText() - self._splitToFields = self.splitToFields - # Объект документ - self.docObj = self._textToXML() - # XML документ - self.doc = self.docObj.doc - - def postXML(self): - """Последующая постобработка XML""" - # Для добавления перевода строки между областями если его нет - #print self.docObj.body.toprettyxml() - xmlAreas = xpath.Evaluate("child::area", self.docObj.body) - for xmlArea in xmlAreas: - if xmlArea.previousSibling and\ - self.docObj.getTypeField(xmlArea.previousSibling) == "br": - continue - firstArea = False - xmlFields = xpath.Evaluate("child::field", xmlArea) - if not (xmlFields and\ - (self.docObj.getTypeField(xmlFields[-1]) == "br" or\ - self.docObj.getTypeField(xmlFields[-1]) == "comment")): - if xmlArea.nextSibling: - parentNode = xmlArea.parentNode - nextNode = xmlArea.nextSibling - parentNode.insertBefore(self.docObj.createField("br", - [],"",[], - False,False), - nextNode) - - - def join(self, sambaObj): - """Объединяем конфигурации""" - if isinstance(sambaObj, samba): - self.docObj.joinDoc(sambaObj.doc) - self.postXML() - - def setDataField(self, txtLines, endtxtLines): - """Создаем список объектов с переменными""" - class fieldData: - def __init__(self): - self.name = False - self.value = False - self.comment = False - self.br = False - fields = [] - field = fieldData() - z = 0 - for k in txtLines: - textLine = k + endtxtLines[z] - z += 1 - findComment = self.reComment.search(textLine) - if not textLine.strip(): - field.br = textLine - fields.append(field) - field = fieldData() - elif findComment: - field.comment = textLine - fields.append(field) - field = fieldData() - else: - pars = textLine.strip() - nameValue = self.reSeparator.split(pars) - if len(nameValue) > 2: - valueList = nameValue[1:] - nameValue =[nameValue[0],"=".join(valueList)] - if len(nameValue) == 2: - name = nameValue[0] - value = nameValue[1].replace(self.sepFields,"") - field.name = name.replace(" ","").replace("\t","") - field.value = value - field.br = textLine - fields.append(field) - field = fieldData() - return fields - - - def splitCleanBloc(self, txtBloc): - """Делим блок на две части (переменные, пустые строки в конце)""" - txtLines = txtBloc.split("\n") - firstBloc = [] - nextBloc = [] - txtLines.reverse() - z = 0 - for txtLine in txtLines: - if not txtLine.strip(): - nextBloc.append(txtLine) - else: - break - z += 1 - txtLines.reverse() - firstBloc = txtLines[:-z] - nextBloc.reverse() - if nextBloc: - firstBloc.append("") - if nextBloc and "\n".join(nextBloc): - return ("\n".join(firstBloc), "\n".join(nextBloc)) - else: - return False - - def getFullAreas(self, blocs): - """Делит текст на области, (Заголовок, тело) - - Возвращает два списка: заголовки, тела - """ - headsAreas = [] - bodyAreas = [] - if not blocs: - return [] - lenBlocs = len(blocs[0]) - for i in range(lenBlocs): - txtBloc = blocs[1][i] - clean = self.splitCleanBloc(txtBloc) - if clean: - headsAreas.append(blocs[0][i]) - bodyAreas.append(clean[0]) - headsAreas.append("") - bodyAreas.append(clean[1]) - else: - headsAreas.append(blocs[0][i]) - bodyAreas.append(blocs[1][i]) - return (headsAreas, bodyAreas) - - def createTxtConfig(self, strHeader, dictVar): - """Cоздает область с заголовком - - создает текст конфигурационного файла в формате samba из - заголовка (строка) и словаря переменных - """ - if not strHeader: - return "" - outTxt = "[" + strHeader + "]\n" - for key in dictVar.keys(): - outTxt += "%s = %s\n" %(key,dictVar[key]) - return outTxt - - def _textToXML(self): - """Преобразует текст в XML""" - blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody) - blocs = self.getFullAreas(blTmp) - headers = [] - startHeaders = [] - finHeaders = [] - docObj = xmlDoc() - docObj.createDoc(self.configName, self.configVersion) - rootNode = docObj.getNodeBody() - # Если пустой текст то создаем пустой документ - if not blocs: - return docObj - - for h in blocs[0]: - listfinH = h.split("]") - finH = listfinH[0] - if "[" in finH: - startHeaders.append(finH + "]") - else: - startHeaders.append(finH) - if len(listfinH) == 2: - finHeaders.append(listfinH[1]) - else: - finHeaders.append("") - headers.append(finH.replace("[","").replace("]","").strip()) - bodys = blocs[1] - - z = 0 - for h in headers: - if not bodys[z]: - z += 1 - continue - areaAction = False - if h: - if h[0] == "!": - docObj.createCaption(h[1:], [startHeaders[z],""]) - areaAction = "drop" - elif h[0] == "-": - docObj.createCaption(h[1:], [startHeaders[z],""]) - areaAction = "replace" - else: - docObj.createCaption(h, [startHeaders[z],""]) - else: - docObj.createCaption(h, [startHeaders[z],""]) - - if "\n" in blocs[0][z]: - if self.reComment.search(finHeaders[z]): - docObj.createField('comment', [finHeaders[z]]) - elif not finHeaders[z].strip() and\ - finHeaders[z].replace("\n",""): - docObj.createField('br', - [finHeaders[z].replace("\n","")]) - else: - docObj.createField('br') - fields = self._splitToFields(bodys[z]) - for f in fields: - if f.name != False and f.value!=False and f.br!=False: - # Обработка условий для samba - if f.name[0] == "!" or f.name[0] == "-" or\ - f.name[0] == "+": - qns = self.removeSymbolTerm(f.br) - xmlField = docObj.createField("var", - [qns], - f.name[1:], [f.value]) - if f.name[0] == "!": - # Удаляемое в дальнейшем поле - docObj.setActionField(xmlField, "drop") - else: - docObj.createField("var",[f.br.replace("\n","")], - f.name, [f.value]) - docObj.createField('br') - elif f.comment != False: - docObj.createField('comment', [f.comment]) - elif f.br != False: - docObj.createField('br', [f.br.replace("\n","")]) - if h.strip(): - area = docObj.createArea() - if areaAction: - docObj.setActionArea(area, areaAction) - rootNode.appendChild(area) - else: - fieldsNodes = docObj.tmpFields.getFields() - for fieldNode in fieldsNodes: - rootNode.appendChild(fieldNode) - docObj.clearTmpFields() - z += 1 - #print docObj.doc.toprettyxml() - return docObj - -class compiz(samba): - """Класс для обработки конфигурационного файла типа compiz - - """ - _comment = "#" - configName = "compiz" - configVersion = "0.1" - reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n",re.M) - reBody = re.compile(".+",re.M|re.S) - reComment = re.compile("\s*%s.*"%(_comment)) - reSeparator = re.compile("\s*=\s*") - sepFields = "\n" - reSepFields = re.compile(sepFields) - - def __init__(self,text): - samba.__init__(self,text) - - def join(self, compizObj): - """Объединяем конфигурации""" - if isinstance(compizObj, compiz): - self.docObj.joinDoc(compizObj.doc) - self.postXML() - -class bind(objShare): - """Класс для обработки конфигурационного файла типа bind - - """ - _comment = "//" - configName = "bind" - configVersion = "0.1" - __openArea = "{" - __closeArea = "[ \t]*\}[ \t]*;[ \t]*" - sepFields = ";" - reOpen = re.compile(__openArea) - reClose = re.compile(__closeArea) - reCloseArea = re.compile(__closeArea + "\s*\Z") - reComment = re.compile("[ \t]+%s|^%s|(?<=;)%s"%(_comment,_comment,_comment)) - reSepFields = re.compile(sepFields) - reSeparator = re.compile("[ \t]+") - - def __init__(self,text): - self.text = text - self.blocTextObj = blocText() - # Объект документ - self.docObj = self.textToXML() - # Создаем поля-массивы - self.docObj.postParserList() - # XML документ - self.doc = self.docObj.doc - - # Делим область на составные части - def findOpenClose(self, text, reOpen, reClose, reComment): - """Делит область на составные части - - начальный текстовый блок, - открывающий блок, - блок-тело, - закрывающий блок - """ - firstBloc = "" - startBloc = "" - bodyBloc = "" - endBloc = "" - textLines = text.splitlines() - findOpen = False - if textLines: - findOpen = reOpen.search(textLines[0]) - openBl = reOpen.search(text) - if findOpen and reComment.split(text)[0].strip(): - blocA = text[openBl.end():] - firstBloc = text[:openBl.start()] - startBloc = text[openBl.start():openBl.end()] - closeBl = reClose.search(blocA) - endBloc = blocA[closeBl.start():closeBl.end()] - bodyBloc = blocA[:closeBl.start()] - return (firstBloc, startBloc, bodyBloc, endBloc) - else: - return (firstBloc, startBloc, text, endBloc) - - - # Делим текст на области включая вложенные (areas массив областей) - def splitToAllArea(self, text, areas, reOpen, reClose, reCloseArea, - reComment, reSepFields): - """Делит текст на области включая вложенные - - возвращает список объектов областей (переменная areas) - """ - class area: - def __init__(self): - self.header = False - self.start = False - self.fields = [] - self.end = False - - blocs = self.blocTextObj.splitTxtToBloc(text,reOpen,reClose, - reComment,reSepFields) - for i in blocs: - areaA = area() - first,start,body,end = self.findOpenClose(i, reOpen, reCloseArea, - reComment) - areaA.header = first.replace(" ","").replace("\t","") - areaA.start = first + start - areaA.end = end - - if areaA.end: - blocsA = self.blocTextObj.splitTxtToBloc(body,reOpen,reClose, - reComment,reSepFields) - if blocsA and blocsA[0] == body: - areaA.fields.append(body) - areas.append(areaA) - else: - for ar in blocsA: - self.splitToAllArea(ar, areaA.fields, reOpen, - reClose, - reCloseArea, reComment, - reSepFields) - areas.append(areaA) - else: - areaA.fields.append(body) - areas.append(areaA) - return areas - - - def setDataField(self, txtLines, endtxtLines): - """Создаем список объектов с переменными""" - class fieldData: - def __init__(self): - self.name = False - self.value = False - self.comment = False - self.br = False - fields = [] - field = fieldData() - z = 0 - for k in txtLines: - textLine = k + endtxtLines[z] - z += 1 - findComment = self.reComment.search(textLine) - if not textLine.strip(): - field.br = textLine - fields.append(field) - field = fieldData() - elif findComment: - field.comment = textLine - fields.append(field) - field = fieldData() - else: - pars = textLine.strip() - nameValue = self.reSeparator.split(pars) - if len (nameValue) == 1: - field.name = "" - field.value = textLine.replace(self.sepFields,"") - field.br = textLine - fields.append(field) - field = fieldData() - - if len(nameValue) > 2: - valueList = nameValue[1:] - nameValue =[nameValue[0]," ".join(valueList).replace(\ - self.sepFields,"")] - if len(nameValue) == 2: - name = nameValue[0] - value = nameValue[1].replace(self.sepFields,"") - field.name = name.replace(" ","").replace("\t","") - field.value = value - field.br = textLine - fields.append(field) - field = fieldData() - return fields - - def createCaptionTerm(self, header, start, end, docObj): - """Создание пустой области с заголовком - - при создании области проверяется первый символ заголовка - и добавляется тег action - "!" - 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 postXML(self): - """Последующая постобработка XML""" - # Для добавления перевода строки между областями если его нет - #print self.docObj.body.toprettyxml() - xmlAreas = xpath.Evaluate("child::area", self.docObj.body) - for xmlArea in xmlAreas: - if xmlArea.previousSibling and\ - self.docObj.getTypeField(xmlArea.previousSibling) == "br": - continue - firstArea = False - xmlFields = xpath.Evaluate("child::field", xmlArea) - if not (xmlFields and\ - (self.docObj.getTypeField(xmlFields[-1]) == "br" or\ - self.docObj.getTypeField(xmlFields[-1]) == "comment")): - if xmlArea.nextSibling: - parentNode = xmlArea.parentNode - nextNode = xmlArea.nextSibling - parentNode.insertBefore(self.docObj.createField("br", - [],"",[], - False,False), - nextNode) - - def join(self, kdeObj): - """Объединяем конфигурации""" - if isinstance(kdeObj, kde): - self.docObj.joinDoc(kdeObj.doc) - self.postXML() - -class xmlDocPlasma: - """Класс для замены метода joinArea в xmlDoc для plasma""" - # заменяемый метод для xmlDoc - def joinArea(self, baseNode, xmlNewArea): - """Объединяет область c областью Body (xmlNewArea c baseNode)""" - def appendArea(baseNode, xmlNewArea): - fieldsRemove = xpath.Evaluate(\ - "descendant::field[child::action='drop']", xmlNewArea) - for rmNode in fieldsRemove: - parentNode = rmNode.parentNode - parentNode.removeChild(rmNode) - captionAreasRemove = xpath.Evaluate(\ - "descendant::area/child::caption[child::action='drop']", - xmlNewArea) - for rmNodeCapt in captionAreasRemove: - rmNode = rmNodeCapt.parentNode - parentNode = rmNode.parentNode - parentNode.removeChild(rmNode) - self.setActionArea(xmlNewArea, "append") - # Добавляем разделитель областей во вложенные области - areaNodes = xpath.Evaluate('descendant::area',xmlNewArea) - for areaNode in areaNodes: - self.setActionArea(areaNode,"append") - parentNode = areaNode.parentNode - parentNode.insertBefore(self.sepAreas.cloneNode(True), - areaNode) - baseNode.appendChild(xmlNewArea) - # Добавляем разделитель областей - baseNode.insertBefore(self.sepAreas.cloneNode(True), xmlNewArea) - - nodesNames = xpath.Evaluate('child::area/caption/name',baseNode) - nodesNewArea = xpath.Evaluate('child::caption/name',xmlNewArea) - if not nodesNames: - # Добавляем область - if nodesNewArea: - newAreaAction = self.getActionArea(xmlNewArea) - if not (newAreaAction == "drop"): - appendArea(baseNode, xmlNewArea) - return True - if not nodesNames or not nodesNewArea: - return False - nameArea = "" - if nodesNewArea[0].firstChild: - nameArea = nodesNewArea[0].firstChild.nodeValue.strip() - flagFindArea = False - baseNodes = [] - for oName in nodesNames: - newAreaAction = self.getActionArea(xmlNewArea) - oArea = oName.parentNode.parentNode - oNameTxt = "" - if oName.firstChild: - oNameTxt = oName.firstChild.nodeValue - if nameArea == oNameTxt: - flagFindArea = True - # При использовании удаления - if newAreaAction == "drop": - prevNode = oName.parentNode.parentNode.previousSibling - removePrevNodes = [] - while (prevNode) and self.getTypeField(prevNode) == "br": - removePrevNodes.append(prevNode) - prevNode = prevNode.previousSibling - for removeNode in removePrevNodes: - baseNode.removeChild(removeNode) - baseNode.removeChild(oName.parentNode.parentNode) - continue - elif newAreaAction == "replace": - oldAreaNode = oName.parentNode.parentNode - newAreaCaption = xpath.Evaluate('child::caption', - xmlNewArea)[0] - oldAreaCaption = xpath.Evaluate('child::caption', - oldAreaNode)[0] - if newAreaCaption and oldAreaCaption: - xmlNewArea.replaceChild(oldAreaCaption,newAreaCaption) - self.setActionArea(xmlNewArea,"replace") - baseNode.replaceChild(xmlNewArea, - oldAreaNode) - continue - baseNodes.append(oName.parentNode.parentNode) - - # Заменяем QUOTE - oldAreaNode = oName.parentNode.parentNode - oldAreaQuote = xpath.Evaluate('child::caption/quote', - oldAreaNode)[0] - if oldAreaQuote and\ - not oldAreaQuote.firstChild: - newAreaQuote = xpath.Evaluate('child::caption/quote', - xmlNewArea)[0] - oldAreaCaption = xpath.Evaluate('child::caption', - oldAreaNode)[0] - if newAreaQuote and oldAreaCaption: - oldAreaCaption.replaceChild(newAreaQuote, oldAreaQuote) - - newFields = xpath.Evaluate('child::field',xmlNewArea) - - joinNewFields = xpath.Evaluate(\ - "child::field[child::action='join']" - ,xmlNewArea) - self.addNewFielsOldArea(newFields, joinNewFields, oArea) - - - if not flagFindArea: - # Добавляем область - if not (newAreaAction == "drop"): - appendArea(baseNode, xmlNewArea) - else: - tmpXmlNewAreas = xpath.Evaluate('child::area',xmlNewArea) - for na in tmpXmlNewAreas: - for bn in baseNodes: - self.joinArea(bn, na) - return True - -class plasma(samba): - """Класс для обработки конфигурационного файла типа kde - - """ - _comment = "#" - configName = "plasma" - configVersion = "0.1" - reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n?",re.M) - reBody = re.compile(".+",re.M|re.S) - reComment = re.compile("^\s*%s.*"%(_comment)) - reSeparator = re.compile("=") - sepFields = "\n" - reSepFields = re.compile(sepFields) - - def __init__(self,text): - samba.__init__(self,text) - - # Делим текст на области включая вложенные (areas массив областей) - def splitToAllArea(self, text, areas): - """Делит текст на области включая вложенные - - возвращает список объектов областей (переменная areas) - """ - class area: - def __init__(self): - self.header = False - self.start = False - self.fields = [] - self.end = False - - - def findPathArea(listPath, areaF): - """Ищет путь в области - - areaF - объект area - listPath - cписок названий областей - """ - ret = False - if not listPath: - return ret - flagList = False - if type(areaF) == types.ListType: - fields = areaF - flagList = True - else: - fields = areaF.fields - if areaF.header == listPath[0]: - ret = areaF - else: - return ret - for i in fields: - if str(i.__class__.__name__) == "area": - add = False - if not flagList: - add = listPath.pop(0) - if not listPath: - break - ret = False - if i.header == listPath[0]: - ret = findPathArea(listPath, i) - break - else: - if add: - listPath.insert(0,add) - if ret == areaF and len(listPath)>1: - ret = False - return ret - - - blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody) - blocs = self.getFullAreas(blTmp) - reH = re.compile("\[([^\[\]]+)\]") - # Список имен блоков - namesBlockList = [] - # Временные поля - fieldsTmp = [] - # Добавляем заголовки - z = 0 - for h in blocs[0]: - if not h: - if blocs[1][z] == "": - fieldsTmp.append("") - #fieldsTmp.append("\n") - else: - fieldsTmp.append(blocs[1][z]) - #print '"' + blocs[1][z] + '"' - z += 1 - continue - #print '"' + blocs[1][z] + '"' - z += 1 - slpNamesBlock = reH.split(h) - # Отступ слева для заголовка - indentionLeft = slpNamesBlock[0] - namesBlock = filter(lambda x: x.strip(), slpNamesBlock) - #namesBlock = map(lambda x: self.removeSymbolTerm(x), namesBlock) - findArea = findPathArea(copy.copy(namesBlock), areas) - namesBlockList.append(namesBlock) - if findArea: - if len(namesBlock) > 1: - namesBlockView = map(lambda x: self.removeSymbolTerm(x), - namesBlock) - else: - namesBlockView = namesBlock - findArea.start = indentionLeft + "[" + \ - "][".join(namesBlockView) + "]" - else: - i = 0 - lenNamesBlock = len(namesBlock) - namesBlockTmp = [] - for nameB in namesBlock: - namesBlockTmp.append(nameB) - findArea = findPathArea(copy.copy(namesBlockTmp), areas) - i += 1 - if not findArea: - areaNew = area() - areaNew.header = nameB - if lenNamesBlock == i: - if len(namesBlock) > 1: - namesBlockView = map(\ - lambda x: self.removeSymbolTerm(x), - namesBlock) - else: - namesBlockView = namesBlock - areaNew.start = indentionLeft + "[" + \ - "][".join(namesBlockView) + "]" - else: - areaNew.start = "" - areaNew.end = "" - if i == 1: - if lenNamesBlock == i: - areas += fieldsTmp - areas.append(areaNew) - findAreaPrev = areas[-1] - else: - if lenNamesBlock == i: - findAreaPrev.fields += fieldsTmp - findAreaPrev.fields.append(areaNew) - findAreaPrev = findAreaPrev.fields[-1] - else: - findAreaPrev = findArea - fieldsTmp = [] - i = 0 - delt = 0 - # Добавляем тела - for body in blocs[1]: - #print "#" + body + "#" - #print - if not blocs[0][i]: - i += 1 - delt +=1 - continue - ## В случае последнего комментария не добавляем перевод строки - #if self.reComment.search(body.splitlines()[-1]): - body = "\n" + body - - namesBlock = namesBlockList[i-delt] - findArea = findPathArea(copy.copy(namesBlock), areas) - if findArea: - #if findArea.fields: - #if type(findArea.fields[0]) == types.StringType: - #findArea.fields.pop(0) - findArea.fields.insert(0, body) - i += 1 - - #eee = 1 - #def prAreas(ar, eee): - #for a in ar: - #if type(a) == types.StringType: - #print 'field', a - #else: - #print "--------------------" - #print "HEADER =", a.header - #print "START =", a.start - #print "FIELDS =", a.fields - #print "LEVEL", eee - #if type(a) != types.StringType: - #if a.fields: - #eee += 1 - #prAreas(a.fields, eee) - - #prAreas(areas, eee) - return areas - - def createCaptionTerm(self, header, start, end, docObj): - """Создание пустой области с заголовком - - при создании области проверяется первый символ заголовка - и добавляется тег action - "!" - 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 _textToXML(self): - """Преобразуем текст в XML""" - areas = [] - if self.text.strip(): - self.splitToAllArea(self.text, areas) - #docObj = xmlDoc() - # Создаем новый класс xmlDoc с измененным методом joinArea - newClass = type("newXmlDocPlalma",(xmlDocPlasma,xmlDoc,object),{}) - # Создаем экземпляр нового класса - docObj = newClass() - # Создание объекта документ c пустым разделителем между полями - docObj.createDoc(self.configName, self.configVersion) - if not areas: - return docObj - self.createXML(areas, docObj.getNodeBody(), docObj) - return docObj - - - def postXML(self): - """Последующая постобработка XML""" - # Для добавления перевода строки между областями если его нет - #print self.docObj.body.toprettyxml() - def getQuotesArea(xmlArea): - quotes = [] - xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea) - for node in xmlQuotes: - if node.firstChild: - quotes.append(node.firstChild.nodeValue) - if len(quotes) == 0: - quotes.append("") - quotes.append("") - elif len(quotes) == 1: - quotes.append("") - return quotes - - xmlAreas = xpath.Evaluate("descendant::area", self.docObj.body) - #print "-------------------------------------------------------" - #print xmlAreas - #if xmlAreas: - #prXmlArea = xmlAreas[0] - for xmlArea in xmlAreas: - # Перед пустой областью и после нее удаляем переводы строк - if getQuotesArea(xmlArea) == ["",""]: - #areaTXT = xpath.Evaluate("child::caption/name", xmlArea)[0] - #print "CL_AREA", areaTXT.firstChild - if xmlArea.previousSibling and\ - self.docObj.getTypeField(xmlArea.previousSibling) == "br": - parentNode = xmlArea.previousSibling.parentNode - if xmlArea.previousSibling.previousSibling and\ - self.docObj.getTypeField(xmlArea.previousSibling.previousSibling) == "br": - parentNode.removeChild(\ - xmlArea.previousSibling.previousSibling) - parentNode.removeChild(xmlArea.previousSibling) - if xmlArea.nextSibling and\ - self.docObj.getTypeField(xmlArea.nextSibling) == "br": - parentNode = xmlArea.nextSibling.parentNode - if xmlArea.nextSibling.nextSibling and\ - self.docObj.getTypeField(xmlArea.nextSibling.nextSibling) == "br": - parentNode.removeChild(xmlArea.nextSibling.nextSibling) - parentNode.removeChild(xmlArea.nextSibling) - continue - - # Собираем поля в кучку - xmlChildAreas = xpath.Evaluate("child::area", xmlArea) - if xmlChildAreas: - childNodes = self.docObj.getFieldsArea(xmlArea) - firstChildArea = xmlChildAreas[0] - if firstChildArea.previousSibling and\ - self.docObj.getTypeField(firstChildArea.previousSibling)=="br": - if firstChildArea.previousSibling.previousSibling: - if self.docObj.getTypeField(\ - firstChildArea.previousSibling.previousSibling)=="br": - firstChildArea = firstChildArea.previousSibling - flagFoundArea = False - it = 0 - lenChild = len(childNodes) - for node in childNodes: - it += 1 - if node.tagName == "area": - flagFoundArea = True - continue - if flagFoundArea and node.tagName == "field": - if self.docObj.getTypeField(node) == "var": - xmlArea.insertBefore(node, firstChildArea) - if it < lenChild: - if self.docObj.getTypeField(childNodes[it])==\ - "br": - xmlArea.insertBefore(childNodes[it], - firstChildArea) - - # Добавляем BR если его нет первым полем - xmlFields = xpath.Evaluate("child::field", xmlArea) - if not (xmlFields and\ - (self.docObj.getTypeField(xmlFields[0]) == "br" or\ - self.docObj.getTypeField(xmlFields[0]) == "comment")): - if xmlFields: - xmlArea.insertBefore(self.docObj.createField("br", - [],"",[], - False,False), - xmlFields[0]) - # Если последним полем BR, удаляем его - if xmlFields and self.docObj.getTypeField(xmlFields[-1]) == "br": - #print "DEL_BR", xmlFields[-1].nextSibling - #and\ - if not xmlFields[-1].nextSibling: - xmlArea.removeChild(xmlFields[-1]) - - # Если предыдущим полем не (BR или комментарий) - добавляем BR - if xmlArea.previousSibling and\ - not (self.docObj.getTypeField(xmlArea.previousSibling) == "br" or\ - self.docObj.getTypeField(xmlArea.previousSibling) == "comment"): - parentNode = xmlArea.parentNode - parentNode.insertBefore(self.docObj.createField("br", - [],"",[], - False,False), - xmlArea) - # Если есть предыдущее поле, и поле предыдущеее предыдущему - # не равно BR или комментарий то добавляем BR - if xmlArea.previousSibling: - prPrSibling = xmlArea.previousSibling.previousSibling - if prPrSibling and\ - not (self.docObj.getTypeField(prPrSibling) == "br" or\ - self.docObj.getTypeField(prPrSibling) == "comment"): - parentNode = xmlArea.parentNode - parentNode.insertBefore(self.docObj.createField("br", - [],"",[], - False,False), - xmlArea) - # Если после есть BR а за ним ничего нет, удаляем BR - if xmlArea.nextSibling and\ - self.docObj.getTypeField(xmlArea.nextSibling) == "br": - if not xmlArea.nextSibling.nextSibling: - parentNode = xmlArea.nextSibling.parentNode - parentNode.removeChild(xmlArea.nextSibling) - - #xmlName = xpath.Evaluate("child::caption/name", xmlArea)[0] - #print "------------------------------------" - #print "Name =", xmlName.firstChild - #if xmlArea.previousSibling: - #print "PR_TYPE =", self.docObj.getTypeField(xmlArea.previousSibling) - - - def join(self, kdeObj): - """Объединяем конфигурации""" - if isinstance(kdeObj, plasma): - self.docObj.joinDoc(kdeObj.doc) - self.postXML() - -class xml_xfce(_error): - """Класс для объединения xfce-xml файлов""" - # root нода - rootNode = False - # body нода - bodyNode = False - # Документ - doc = False - # Текст профиля - text = "" - # Комментарий - _comment = ("") - - def __init__(self, text): - self.text = text - # Создаем пустой объект - self.docObj = type("_empty_class", (object,), {})() - # Названия аттрибутов для пустого объекта - emptyMethods = ["getNodeBody","removeComment","insertBRtoBody", - "insertBeforeSepAreas"] - # Добавляем необходимые аттрибуты пустому объекту - for method in emptyMethods: - setattr(self.docObj, method, self.emptyMethod) - # Создаем XML документ - self.doc = self.textToXML() - - def emptyMethod(self, *arg , **argv): - """Пустой метод""" - return True - - def setNameBodyNode(self, name): - """Устанавливает название для корневой ноды документа""" - if not self.bodyNode: - return False - self.bodyNode.setAttribute("name", name) - return True - - def textToXML(self): - """Создание из текста XML документа - Храним xml в своем формате - """ - if not self.text.strip(): - self.text = ''' - -''' - try: - self.doc = xml.dom.minidom.parseString(self.text) - except: - self.setError(_("Can not text profile is XML")) - return False - self.rootNode = self.doc.documentElement - self.bodyNode = self.rootNode - return self.doc - - def join(self, xml_xfceObj): - """Объединяем конфигурации""" - if isinstance(xml_xfceObj, xml_xfce): - try: - self.joinDoc(xml_xfceObj.doc) - except: - self.setError(_("Can not join profile")) - return False - return True - - def _removeDropNodesAndAttrAction(self, xmlNode): - """Удаляет ноды с аттрибутом action='drop' - - Также удаляет аттрибут action у всех нод - """ - flagError = False - childNodes = xmlNode.childNodes - if xmlNode.nodeType ==xmlNode.ELEMENT_NODE: - if xmlNode.hasAttribute("action"): - nAction = xmlNode.getAttribute("action") - if not nAction in ("join","replace","drop"): - textError = _('''In the text, XML profile, look \ -for a reserved attribute 'action' with the incorrect value.\n\ -Valid values attribute 'action': \ -(action="join", action="replace", action="drop")''') - self.setError(textError) - return False - xmlNode.removeAttribute("action") - if nAction == "drop": - parentNode = xmlNode.parentNode - if parentNode: - parentNode.removeChild(xmlNode) - if childNodes: - for node in childNodes: - if not self._removeDropNodesAndAttrAction(node): - flagError = True - break - if flagError: - return False - return True - - def postXML(self): - """Последующая постобработка XML""" - # Удаляем теги action и удаляемые ноды - self._removeDropNodesAndAttrAction(self.bodyNode) - - def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True): - """Объединение корневой ноды профиля и корневой ноды файла""" - xmlNode = xmlNewNode - childNodes = xmlNode.childNodes - nextOldNode = xmlOldNode - flagError = False - if xmlNode.nodeType ==xmlNode.ELEMENT_NODE: - n = xmlNode - path = u'' - nName = u'' - nType = u'' - nValue = u'' - nAction = u'' - attrName = '' - attrType = '' - path = n.tagName - if n.hasAttribute("name"): - nName = n.getAttribute("name") - attrName = u"attribute::name='%s'"%nName - if n.hasAttribute("type"): - nType = n.getAttribute("type") - attrType = u"attribute::type='%s'"%nType - if n.hasAttribute("value"): - nValue = n.getAttribute("value") - if n.hasAttribute("action"): - nAction = n.getAttribute("action") - if not nAction in ("join","replace","drop"): - textError = _('''In the text, XML profile, look \ -for a reserved attribute 'action' with the incorrect value.\n\ -Valid values attribute 'action': \ -(action="join", action="replace", action="drop")''') - self.setError(textError) - return False - if xmlOldNode.parentNode: - findStr = u"child::%s"%path - strAttr = [attrName, attrType] - findAttr = filter(lambda x: x, strAttr) - findAttrStr = '' - if findAttr: - strAttr = u' and '.join(findAttr) - findAttrStr = "[%s]"%strAttr - findPath = u"child::%s%s"%(path,findAttrStr) - # Рабочая нода - if flagRootNode: - workNode = xmlOldNode.parentNode - else: - workNode = xmlOldNode - oldNodes = xpath.Evaluate(findPath, workNode) - #print findPath - #print workNode - #print "----------------------------" - # Новая нода список - flagArray = False - if nType == "array": - flagArray = True - flagDrop = False - flagJoin = True - flagReplace = False - if nAction == "replace": - flagJoin = False - flagReplace = True - elif nAction == "drop": - flagJoin = False - flagDrop = True - if flagRootNode: - textError = _('Incorrect action="drop" in root node') - self.setError(textError) - return False - if oldNodes: - if len(oldNodes)>1: - textError = _("The uncertainty in this profile are \ -the same nodes at one level") - self.setError(textError) - return False - nextOldNode = oldNodes[0] - # Замещаем ноду в случае массива - if flagArray and not flagDrop: - replaceXmlNode = xmlNode.cloneNode(True) - if nAction: - replaceXmlNode.removeAttribute("action") - workNode.replaceChild(replaceXmlNode, - nextOldNode) - flagJoin = False - flagReplace = False - childNodes = False - # Объединение нод - if flagJoin: - if nextOldNode.hasAttribute("value"): - oValue = nextOldNode.getAttribute("value") - if nValue != oValue: - nextOldNode.setAttribute("value",nValue) - # Замещение ноды - elif flagReplace: - replaceXmlNode = xmlNode.cloneNode(True) - if not\ - self._removeDropNodesAndAttrAction(replaceXmlNode): - return False - workNode.replaceChild(replaceXmlNode, - nextOldNode) - childNodes = False - # Удаление ноды - elif flagDrop: - workNode.removeChild(nextOldNode) - childNodes = False - else: - # Добавление ноды - childNodes = False - if not flagDrop: - appendXmlNode = xmlNode.cloneNode(True) - if not\ - self._removeDropNodesAndAttrAction(appendXmlNode): - return False - workNode.appendChild(appendXmlNode) - if childNodes: - for node in childNodes: - if not self._join(node, nextOldNode, False): - flagError = True - break - if flagError: - return False - return True - - def joinDoc(self, doc): - """Объединение документа профиля и документа файла""" - if not self.doc: - self.setError(_("Can not text file is XML")) - return False - if not doc: - self.setError(_("Can not text profile is XML")) - return False - # Импортируем корневую ноду нового документа в текущий документ - #newImportBodyNode = self.doc.importNode(doc.documentElement, True) - # Объединение корневой ноды профиля и корневой ноды файла - if not self._join(doc.documentElement, self.bodyNode): - return False - return True - - def getConfig(self): - """Получение текстового файла из XML документа""" - data = self.doc.toprettyxml(encoding='UTF-8').split("\n") - data = filter(lambda x: x.strip(), data) - return "\n".join(data).replace("\t"," ").decode("UTF-8") - -class squid(procmail): - """Класс для обработки конфигурационного файла типа squid - - """ - configName = "squid" - configVersion = "0.1" - # разделитель названия и значения переменной - reSeparator = re.compile(" ") - - def __init__(self, text): - procmail.__init__(self, text) - # Создаем поля-массивы - self.docObj.postParserList() - # Создаем поля разделенные массивы - self.docObj.postParserListSeplist(self.docObj.body) - - def setDataField(self, txtLines, endtxtLines): - """Создаем список объектов с переменными""" - class fieldData: - def __init__(self): - self.name = False - self.value = False - self.comment = False - self.br = False - fields = [] - field = fieldData() - z = 0 - for k in txtLines: - textLine = k + endtxtLines[z] - z += 1 - findComment = self.reComment.search(textLine) - flagVariable = True - if not textLine.strip(): - field.br = textLine - fields.append(field) - field = fieldData() - flagVariable = False - elif findComment: - if textLine[:findComment.start()].strip(): - field.comment = textLine[findComment.start():] - textLine = textLine[:findComment.start()] - else: - field.comment = textLine - flagVariable = False - fields.append(field) - field = fieldData() - if flagVariable: - pars = textLine.strip() - nameValue = self.reSeparator.split(pars) - if len(nameValue) > 2: - valueList = nameValue[1:] - nameValue =[nameValue[0]," ".join(valueList)] - if len(nameValue) == 2: - name = nameValue[0] - value = nameValue[1].replace(self.sepFields,"") - field.name = name.replace(" ","").replace("\t","") - field.value = value - field.br = textLine - fields.append(field) - field = fieldData() - return fields - - def join(self, squidObj): - """Объединяем конфигурации""" - if isinstance(squidObj, squid): - #print squidObj.getConfig() - self.docObj.joinDoc(squidObj.doc) - -class xml_xfcepanel(xml_xfce): - """Класс для объединения xfce-panel файлов""" - def __init__(self, text): - xml_xfce.__init__(self, text) - self.panelNumbers = {} - - def textToXML(self): - """Создание из текста XML документа - Храним xml в своем формате - """ - if not self.text.strip(): - self.text = ''' - - -''' - try: - self.doc = xml.dom.minidom.parseString(self.text) - except: - self.setError(_("Can not text profile is XML")) - return False - self.rootNode = self.doc.documentElement - self.bodyNode = self.rootNode - return self.doc - - def setNameBodyNode(self, name): - """Пустой метод""" - return True - - def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True, levelNumber=0): - """Объединение корневой ноды профиля и корневой ноды файла""" - xmlNode = xmlNewNode - childNodes = xmlNode.childNodes - nextOldNode = xmlOldNode - flagError = False - if xmlNode.nodeType ==xmlNode.ELEMENT_NODE: - n = xmlNode - path = u'' - nName = u'' - flagArray = False - nValue = u'' - nAction = u'' - attrName = '' - attrType = '' - path = n.tagName - if path == "items": - flagArray = True - if not flagArray: - if n.hasAttribute("name"): - nName = n.getAttribute("name") - attrName = u"attribute::name='%s'"%nName - if n.hasAttribute("value"): - nValue = n.getAttribute("value") - if n.hasAttribute("action"): - nAction = n.getAttribute("action") - if not nAction in ("join","replace","drop"): - textError = _('''In the text, XML profile, look \ -for a reserved attribute 'action' with the incorrect value.\n\ -Valid values attribute 'action': \ -(action="join", action="replace", action="drop")''') - self.setError(textError) - return False - if xmlOldNode.parentNode: - findStr = u"child::%s"%path - findAttrStr = "" - if attrName: - findAttrStr = "[%s]"%attrName - findPath = u"child::%s%s"%(path,findAttrStr) - # Рабочая нода - if flagRootNode: - workNode = xmlOldNode.parentNode - else: - workNode = xmlOldNode - oldNodes = xpath.Evaluate(findPath, workNode) - flagDrop = False - flagJoin = True - flagReplace = False - flagAppend = False - if nAction == "replace": - flagJoin = False - flagReplace = True - elif nAction == "drop": - flagJoin = False - flagDrop = True - if flagRootNode: - textError = _('Incorrect action="drop" in root node') - self.setError(textError) - return False - if path == "panel": - flagJoin = False - if levelNumber in self.panelNumbers.keys(): - self.panelNumbers[levelNumber] += 1 - else: - self.panelNumbers[levelNumber] = 0 - if oldNodes: - if len(oldNodes)>1 and path != "panel": - textError = _("The uncertainty in this profile are \ -the same nodes at one level") - self.setError(textError) - return False - if path == "panel": - if len(oldNodes)<=self.panelNumbers[levelNumber]: - nextOldNode = oldNodes[-1] - # Добавляем ноду - if not flagDrop: - flagAppend = True - flagReplace = False - childNodes = False - else: - nextOldNode=oldNodes[self.panelNumbers[levelNumber]] - else: - nextOldNode = oldNodes[0] - # Замещаем ноду в случае массива - if flagArray and not flagDrop: - replaceXmlNode = xmlNode.cloneNode(True) - if nAction: - replaceXmlNode.removeAttribute("action") - workNode.replaceChild(replaceXmlNode, - nextOldNode) - flagJoin = False - flagReplace = False - childNodes = False - # Объединение нод - if flagJoin: - if nextOldNode.hasAttribute("value"): - oValue = nextOldNode.getAttribute("value") - if nValue != oValue: - nextOldNode.setAttribute("value",nValue) - # Замещение ноды - elif flagReplace: - replaceXmlNode = xmlNode.cloneNode(True) - if not\ - self._removeDropNodesAndAttrAction(replaceXmlNode): - return False - workNode.replaceChild(replaceXmlNode, - nextOldNode) - childNodes = False - # Удаление ноды - elif flagDrop: - workNode.removeChild(nextOldNode) - childNodes = False - else: - flagAppend = True - flagDrop = False - if flagAppend and not flagDrop: - # Добавление ноды - childNodes = False - if not flagDrop: - appendXmlNode = xmlNode.cloneNode(True) - if not\ - self._removeDropNodesAndAttrAction(appendXmlNode): - return False - workNode.appendChild(appendXmlNode) - if childNodes: - for node in childNodes: - levelNumber +=1 - if not self._join(node, nextOldNode, False, levelNumber): - flagError = True - break - levelNumber -= 1 - if flagError: - return False - return True - - def join(self, xml_xfceObj): - """Объединяем конфигурации""" - if isinstance(xml_xfceObj, xml_xfcepanel): - try: - self.joinDoc(xml_xfceObj.doc) - except: - self.setError(_("Can not join profile")) - return False - return True - - -class dhcp(bind): - """Класс для обработки конфигурационного файла типа dhcp - - """ - _comment = "#" - configName = "dhcp" - configVersion = "0.1" - __openArea = "{" - __closeArea = "[ \t]*\}[ \t]*" - sepFields = ";" - reOpen = re.compile(__openArea) - reClose = re.compile(__closeArea) - reCloseArea = re.compile(__closeArea + "\s*\Z") - reComment = re.compile("^[ \t]*%s"%(_comment)) - reSepFields = re.compile(sepFields) - reSeparator = re.compile("[ \t]+") - - def __init__(self,text): - bind.__init__(self,text) - - def setDataField(self, txtLines, endtxtLines): - """Создаем список объектов с переменными""" - class fieldData: - def __init__(self): - self.name = False - self.value = False - self.comment = False - self.br = False - fields = [] - field = fieldData() - z = 0 - for k in txtLines: - textLine = k + endtxtLines[z] - z += 1 - findComment = self.reComment.search(textLine) - if not textLine.strip(): - field.br = textLine - fields.append(field) - field = fieldData() - elif findComment: - field.comment = textLine - fields.append(field) - field = fieldData() - else: - pars = textLine.strip() - nameValue = self.reSeparator.split(pars) - if len (nameValue) == 1: - field.name = textLine.replace(self.sepFields,"").strip() - field.value = "" - field.br = textLine - fields.append(field) - field = fieldData() - - if len(nameValue) > 2: - nameCheck = nameValue[0] - if nameValue[0][:1] in ["+","-","!"]: - nameCheck = nameValue[0][1:] - if nameCheck == "option" or nameCheck == "hardware" or\ - nameCheck == "set": - valueList = nameValue[2:] - nameValue =[nameValue[0]+nameValue[1], - " ".join(valueList).replace(\ - self.sepFields,"")] - else: - valueList = nameValue[1:] - nameValue =[nameValue[0]," ".join(valueList).replace(\ - self.sepFields,"")] - if len(nameValue) == 2: - name = nameValue[0] - value = nameValue[1].replace(self.sepFields,"") - field.name = name.replace(" ","").replace("\t","") - field.value = value - field.br = textLine - fields.append(field) - field = fieldData() - return fields - - def join(self, dhcpObj): - """Объединяем конфигурации""" - if isinstance(dhcpObj, dhcp): - self.docObj.joinDoc(dhcpObj.doc) - - -class xml_gconf(xml_xfce): - """Класс для объединения gconf-xml файлов""" - # root нода - rootNode = False - # body нода - bodyNode = False - # Документ - doc = False - # Текст профиля - text = "" - # Текущее время в секундах - currentTime = "" - # Комментарий - _comment = ("") - # поддерживаемые аттрибуты тега entry. Пример - 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.removeAttribute("mtime") or x, - map(lambda x: x.cloneNode(True), - filter(lambda x: x.nodeType==x.ELEMENT_NODE, y)))) - if set(getTextsNodes(listXmlA))==set(getTextsNodes(listXmlB)): - return True - return False - - def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True, levelNumber=0): - """Объединение корневой ноды профиля и корневой ноды файла""" - if levelNumber>1: - return True - xmlNode = xmlNewNode - childNodes = xmlNode.childNodes - nextOldNode = xmlOldNode - flagError = False - if xmlNode.nodeType == xmlNode.ELEMENT_NODE: - n = xmlNode - tagName = n.tagName - nAction = u'' - nName = u'' - nType = u'' - nValue = u'' - attrName = '' - attrType = '' - if flagRootNode: - if not tagName == "gconf": - self.setError(_("The text is not a valid gconf-XML format \ -(not found '...')")) - return False - else: - if not tagName == "entry": - self.setError(_("The text is not a valid gconf-XML format \ -(found '<%s>..'")%(tagName,tagName)) - return False - if not n.hasAttribute("name"): - self.setError(_('Not found arrtibute "name" in tag entry')) - return False - if not n.hasAttribute("type"): - self.setError(_('Not found arrtibute "type" in tag entry')) - return False - nName = n.getAttribute("name") - attrName = u"attribute::name='%s'"%nName - nType = n.getAttribute("type") - # Проверка правильности аттрибута type - if not nType in self.supportEntryTypes: - self.setError(\ - _('Incorrect arrtibute "type" - ')%nType) - return False - attrType = u"attribute::type='%s'"%nType - if n.hasAttribute("value"): - nValue = n.getAttribute("value") - if n.hasAttribute("action"): - nAction = n.getAttribute("action") - if not nAction in ("join","replace","drop"): - textError = _('''In the text, XML profile, look \ -for a reserved attribute 'action' with the incorrect value.\n\ -Valid values attribute 'action': \ -(action="join", action="replace", action="drop")''') - self.setError(textError) - return False - if xmlOldNode.parentNode: - findStr = u"child::%s"%tagName - strAttr = [attrName, attrType] - findAttr = filter(lambda x: x, strAttr) - findAttrStr = '' - if findAttr: - strAttr = u' and '.join(findAttr) - findAttrStr = "[%s]"%strAttr - findPath = u"child::%s%s"%(tagName,findAttrStr) - # Рабочая нода - if flagRootNode: - workNode = xmlOldNode.parentNode - else: - workNode = xmlOldNode - oldNodes = xpath.Evaluate(findPath, workNode) - # Новая нода список - flagArray = False - if nType == "list" or nType == "pair": - flagArray = True - flagDrop = False - flagJoin = True - flagReplace = False - if nType=="string" or nAction=="replace": - flagJoin = False - flagReplace = True - elif nAction == "drop": - flagJoin = False - flagDrop = True - if flagRootNode: - textError = _('Incorrect action="drop" in root node') - self.setError(textError) - return False - if oldNodes: - if len(oldNodes)>1: - textError = _("The uncertainty in this profile are \ -the same nodes at one level") - self.setError(textError) - return False - nextOldNode = oldNodes[0] - # Замещаем ноду в случае массива - if flagArray and not flagDrop: - replaceXmlNode = xmlNode.cloneNode(True) - # Сравнение содержимого нод - if not self.cmpListsNodesEntry([replaceXmlNode], - [nextOldNode]): - replaceXmlNode.setAttribute("mtime", - self.currentTime) - if nAction: - replaceXmlNode.removeAttribute("action") - workNode.replaceChild(replaceXmlNode, - nextOldNode) - flagJoin = False - flagReplace = False - childNodes = False - # Объединение нод - if flagJoin: - if nextOldNode.hasAttribute("value"): - oValue = nextOldNode.getAttribute("value") - if nValue != oValue: - nextOldNode.setAttribute("mtime", - self.currentTime) - nextOldNode.setAttribute("value",nValue) - # Замещение ноды - elif flagReplace: - replaceXmlNode = xmlNode.cloneNode(True) - # Сравнение содержимого нод - if not self.cmpListsNodesEntry([replaceXmlNode], - [nextOldNode]): - replaceXmlNode.setAttribute("mtime", - self.currentTime) - if not\ - self._removeDropNodesAndAttrAction(\ - replaceXmlNode): - return False - workNode.replaceChild(replaceXmlNode, - nextOldNode) - childNodes = False - # Удаление ноды - elif flagDrop: - workNode.removeChild(nextOldNode) - childNodes = False - else: - # Добавление ноды - childNodes = False - if not flagDrop: - appendXmlNode = xmlNode.cloneNode(True) - appendXmlNode.setAttribute("mtime", self.currentTime) - if not\ - self._removeDropNodesAndAttrAction(appendXmlNode): - return False - workNode.appendChild(appendXmlNode) - if childNodes: - for node in childNodes: - levelNumber +=1 - if not self._join(node, nextOldNode, False, levelNumber): - flagError = True - break - levelNumber -= 1 - if flagError: - return False - return True - - def join(self, xml_gconfObj): - """Объединяем конфигурации""" - # Получаем текущее время - self.currentTime = self.getCurrentTime() - if isinstance(xml_gconfObj, xml_gconf): - try: - self.joinDoc(xml_gconfObj.doc) - except: - self.setError(_("Can not join profile")) - return False - return True - - def getConfig(self): - """Получение текстового файла из XML документа""" - data = self.doc.toprettyxml().split("\n") - data = filter(lambda x: x.strip(), data) - return "\n".join(data).replace("\t"," ") diff --git a/pym/cl_utils2.py b/pym/cl_utils2.py deleted file mode 100644 index cd25463..0000000 --- a/pym/cl_utils2.py +++ /dev/null @@ -1,563 +0,0 @@ -#-*- coding: utf-8 -*- - -#Copyright 2008 Calculate Pack, http://www.calculate-linux.org -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys -import 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) From 0b1a15205eb0ca46f1b3b33e95b778becff65dd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A5=D0=B8=D1=80=D0=B5=D1=86=D0=BA=D0=B8=D0=B9=20=D0=9C?= =?UTF-8?q?=D0=B8=D1=85=D0=B0=D0=B8=D0=BB?= Date: Wed, 27 Jan 2010 16:30:19 +0300 Subject: [PATCH 3/7] Remove build directory --- build/lib/calculate-lib/pym/__init__.py | 0 build/lib/calculate-lib/pym/cl_data.py | 624 --- build/lib/calculate-lib/pym/cl_fill.py | 346 -- build/lib/calculate-lib/pym/cl_help.py | 375 -- build/lib/calculate-lib/pym/cl_lang.py | 168 - build/lib/calculate-lib/pym/cl_ldap.py | 58 - build/lib/calculate-lib/pym/cl_log.py | 60 - build/lib/calculate-lib/pym/cl_overriding.py | 58 - build/lib/calculate-lib/pym/cl_print.py | 217 - build/lib/calculate-lib/pym/cl_string.py | 254 -- build/lib/calculate-lib/pym/cl_template.py | 3774 ----------------- build/lib/calculate-lib/pym/cl_utils.py | 214 - build/lib/calculate-lib/pym/cl_vars.py | 89 - .../lib/calculate-lib/pym/format/__init__.py | 0 build/lib/calculate-lib/pym/format/apache.py | 218 - build/lib/calculate-lib/pym/format/bind.py | 315 -- build/lib/calculate-lib/pym/format/compiz.py | 41 - build/lib/calculate-lib/pym/format/dhcp.py | 100 - build/lib/calculate-lib/pym/format/dovecot.py | 65 - build/lib/calculate-lib/pym/format/kde.py | 160 - build/lib/calculate-lib/pym/format/ldap.py | 183 - build/lib/calculate-lib/pym/format/plasma.py | 597 --- build/lib/calculate-lib/pym/format/postfix.py | 117 - .../lib/calculate-lib/pym/format/procmail.py | 115 - build/lib/calculate-lib/pym/format/samba.py | 261 -- build/lib/calculate-lib/pym/format/squid.py | 86 - .../lib/calculate-lib/pym/format/xml_gconf.py | 262 -- .../lib/calculate-lib/pym/format/xml_xfce.py | 268 -- .../calculate-lib/pym/format/xml_xfcepanel.py | 199 - 29 files changed, 9224 deletions(-) delete mode 100644 build/lib/calculate-lib/pym/__init__.py delete mode 100644 build/lib/calculate-lib/pym/cl_data.py delete mode 100644 build/lib/calculate-lib/pym/cl_fill.py delete mode 100644 build/lib/calculate-lib/pym/cl_help.py delete mode 100644 build/lib/calculate-lib/pym/cl_lang.py delete mode 100644 build/lib/calculate-lib/pym/cl_ldap.py delete mode 100644 build/lib/calculate-lib/pym/cl_log.py delete mode 100644 build/lib/calculate-lib/pym/cl_overriding.py delete mode 100644 build/lib/calculate-lib/pym/cl_print.py delete mode 100644 build/lib/calculate-lib/pym/cl_string.py delete mode 100644 build/lib/calculate-lib/pym/cl_template.py delete mode 100644 build/lib/calculate-lib/pym/cl_utils.py delete mode 100644 build/lib/calculate-lib/pym/cl_vars.py delete mode 100644 build/lib/calculate-lib/pym/format/__init__.py delete mode 100644 build/lib/calculate-lib/pym/format/apache.py delete mode 100644 build/lib/calculate-lib/pym/format/bind.py delete mode 100644 build/lib/calculate-lib/pym/format/compiz.py delete mode 100644 build/lib/calculate-lib/pym/format/dhcp.py delete mode 100644 build/lib/calculate-lib/pym/format/dovecot.py delete mode 100644 build/lib/calculate-lib/pym/format/kde.py delete mode 100644 build/lib/calculate-lib/pym/format/ldap.py delete mode 100644 build/lib/calculate-lib/pym/format/plasma.py delete mode 100644 build/lib/calculate-lib/pym/format/postfix.py delete mode 100644 build/lib/calculate-lib/pym/format/procmail.py delete mode 100644 build/lib/calculate-lib/pym/format/samba.py delete mode 100644 build/lib/calculate-lib/pym/format/squid.py delete mode 100644 build/lib/calculate-lib/pym/format/xml_gconf.py delete mode 100644 build/lib/calculate-lib/pym/format/xml_xfce.py delete mode 100644 build/lib/calculate-lib/pym/format/xml_xfcepanel.py diff --git a/build/lib/calculate-lib/pym/__init__.py b/build/lib/calculate-lib/pym/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/build/lib/calculate-lib/pym/cl_data.py b/build/lib/calculate-lib/pym/cl_data.py deleted file mode 100644 index 926c224..0000000 --- a/build/lib/calculate-lib/pym/cl_data.py +++ /dev/null @@ -1,624 +0,0 @@ -#-*- 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 sys -import cl_utils -from cl_lang import lang -from cl_template import iniParser -from cl_string import columnWrite - -# Перевод модуля на другой язык -tr = lang() -tr.setLocalDomain('cl_lib') -tr.setLanguage(sys.modules[__name__]) - -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 self.__dict__.has_key(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 self.__dict__.has_key(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 self.__dict__.has_key(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 self.__dict__.has_key(vname): - if self.__dict__[vname].service == 'Global': - return 'calculate' - else: - return self.__dict__[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') - - Возвращаемые значение: - 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) - # Удаляем переменную - 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): - #if vname: - #if self.__dict__.has_key(vname): - #return True - #return False - def defined(self, vname): - return True - - - - def exists(self, nameVar): - """ Определяет существует ли переменная с таким имененм - """ - if self.__dict__.has_key(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 - 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 deleted file mode 100644 index 4d3b598..0000000 --- a/build/lib/calculate-lib/pym/cl_fill.py +++ /dev/null @@ -1,346 +0,0 @@ -#-*- 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 -from cl_overriding import exit -import cl_utils -import cl_data - -class fillVars(object, cl_data.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") - 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", - "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"} - 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.template" - 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_help.py b/build/lib/calculate-lib/pym/cl_help.py deleted file mode 100644 index 20ca654..0000000 --- a/build/lib/calculate-lib/pym/cl_help.py +++ /dev/null @@ -1,375 +0,0 @@ -#-*- 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 getopt -import sys -from cl_string import prettyColumnStr - -pcs = prettyColumnStr - -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 - -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"] - return "" diff --git a/build/lib/calculate-lib/pym/cl_lang.py b/build/lib/calculate-lib/pym/cl_lang.py deleted file mode 100644 index eb0cf69..0000000 --- a/build/lib/calculate-lib/pym/cl_lang.py +++ /dev/null @@ -1,168 +0,0 @@ -#-*- 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, gettext -from cl_overriding import __findFileMO - -class GlobalParam(type): - """ Метакласс для глобальных параметров - """ - def __init__(cls, *args): - cls.GP = [] - cls.GP.append("") - -gettext.find = __findFileMO - -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 - diff --git a/build/lib/calculate-lib/pym/cl_ldap.py b/build/lib/calculate-lib/pym/cl_ldap.py deleted file mode 100644 index bea5fae..0000000 --- a/build/lib/calculate-lib/pym/cl_ldap.py +++ /dev/null @@ -1,58 +0,0 @@ -#-*- 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 ldap -from cl_utils import _error - -class ldapFun(_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 - diff --git a/build/lib/calculate-lib/pym/cl_log.py b/build/lib/calculate-lib/pym/cl_log.py deleted file mode 100644 index ab65d0e..0000000 --- a/build/lib/calculate-lib/pym/cl_log.py +++ /dev/null @@ -1,60 +0,0 @@ -#-*- 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_overriding.py b/build/lib/calculate-lib/pym/cl_overriding.py deleted file mode 100644 index 0c6ca8e..0000000 --- a/build/lib/calculate-lib/pym/cl_overriding.py +++ /dev/null @@ -1,58 +0,0 @@ -#-*- 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,sys,gettext - -def __findFileMO(domain, localedir=None, languages=None, all=0): - """Модифицированный метод, ищет файл перевода - - замена gettext.find""" - 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 gettext._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 - -def exit(codeExit): - """Метод выхода из программы""" - sys.exit(codeExit) \ No newline at end of file diff --git a/build/lib/calculate-lib/pym/cl_print.py b/build/lib/calculate-lib/pym/cl_print.py deleted file mode 100644 index 1298357..0000000 --- a/build/lib/calculate-lib/pym/cl_print.py +++ /dev/null @@ -1,217 +0,0 @@ -#-*- 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, struct, termios, fcntl -from cl_utils import _toUNICODE - -class color_print(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 = _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_string.py b/build/lib/calculate-lib/pym/cl_string.py deleted file mode 100644 index 757cbfb..0000000 --- a/build/lib/calculate-lib/pym/cl_string.py +++ /dev/null @@ -1,254 +0,0 @@ -#-*- 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. - -from re import search, compile, S -from cl_utils import _toUNICODE - -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') diff --git a/build/lib/calculate-lib/pym/cl_template.py b/build/lib/calculate-lib/pym/cl_template.py deleted file mode 100644 index 68f0c0f..0000000 --- a/build/lib/calculate-lib/pym/cl_template.py +++ /dev/null @@ -1,3774 +0,0 @@ -#-*- coding: utf-8 -*- - -# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys -import os -import stat -import re -import xml.dom.minidom -from xml import xpath -import subprocess -import types -import random -import string -from cl_utils import _error, scan, _toUNICODE -from cl_overriding import exit -import cl_lang - -tr = cl_lang.lang() -tr.setLocalDomain('cl_lib') -tr.setLanguage(sys.modules[__name__]) - -class _terms(_error): - """Вычисление условий применяемых в шаблонах - - """ - def _convertVers(self, verA, verB): - """Конвертирование номеров версий для корректного сравнения - """ - elemA = verA.split(".") - elemB = verB.split(".") - if len(elemA) > len(elemB): - maxElemB = len(elemB)-1 - for i in range(len(elemA)): - if i > maxElemB: - elemB.append("0") - else: - maxElemA = len(elemA)-1 - for i in range(len(elemB)): - if i > maxElemA: - elemA.append("0") - for i in range(len(elemB)): - lenA = len(elemA[i]) - lenB = len(elemB[i]) - if lenA == lenB: - pass - elif lenA > lenB: - res = lenA - lenB - for z in range(res): - elemB[i] = "0" + elemB[i] - elif lenB > lenA: - res = lenB - lenA - for z in range(res): - elemA[i] = "0" + elemA[i] - return (".".join(elemA), ".".join(elemB)) - - def executeListEqual(self, listEqual): - """Вычисляет список выражений - - пример списка: - listEqual = [False, True, ' or ', True , True] - (если нет or между логическими выражениями то между ними and) - результат True - """ - lenOr = listEqual.count(" or ") - for i in xrange(lenOr): - ind = listEqual.index(' or ') - if False in listEqual[:ind]: - listEqual = listEqual[ind+1:] - continue - else: - return True - if False in listEqual: - return False - else: - return True - - - def _equalTerm(self, term, textError, function=False): - """Вычисление логических выражений для условий - - Для корректной работы в классе который наследует этот класс - должен быть объявлен аттрибут self.objVar - (объект для работы с переменными) - function - функция для для обработки функций в заголовке блока - """ - trm = {"&&":" and ","||":" or "} - rule = ["==", "!=", ">=", "<=", ">", "<"] - listEqual = [] - for k in trm.keys(): - if k in term: - term = term.replace(k,trm[k]) - trs = term.split(" ") - for t in trs: - flagRule = False - for sepF in rule: - if sepF in t: - flagRule = True - vals = t.split(sepF) - break - - if not flagRule: - flagLog = False - for k in trm.values(): - if k.strip() == t: - flagLog = True - break - if not flagLog: - self.setError("'%s'"%term + " " + _("incorrect")) - self.setError (textError) - return False - elif k == " or ": - listEqual.append(k) - else: - #проверка на допустимость названия переменной - reDenyName = re.compile("[^a-zA-Z0-9\_\-]") - flagFunction = False - if reDenyName.search(vals[0]): - #проверка на допустимость функции - flagError = True - if function: - reFunction = re.compile(\ - "([a-zA-Z0-9\_\-]+)\([a-zA-Z0-9_\-\+\,\*\/\.]+\)") - searchFunct = reFunction.search(vals[0]) - if searchFunct: - flagError = False - flagFunction = True - if flagError: - self.setError("'%s'"%term + " " + _("incorrect")) - self.setError(textError) - return False - #проверка на допустимость значения - reDenyValue = re.compile("[^0-9a-zA-Z_\.-]") - if reDenyValue.search(vals[1]): - self.setError("'%s'"%term + " " + _("incorrect")) - self.setError(textError) - return False - flagIntTypeVar = None - if flagFunction: - valVars = function("#-%s-#"%vals[0]) - if valVars == "": - flagFunction = False - if valVars == False: - self.setError("'%s'"%term + " " + _("incorrect")) - self.setError(textError) - return False - if "load" == searchFunct.group(1): - if re.search("\(\s*num\s*,",vals[0]): - if valVars: - try: - valVars = int(valVars) - except: - self.setError("'%s'"%term + " " + \ - _("incorrect")) - self.setError (textError) - return False - flagIntTypeVar = True - else: - flagIntTypeVar = False - else: - try: - valVars = self.objVar.Get(vals[0]) - except self.objVar.DataVarsError, e: - print textError - print e - exit(1) - # Cравниваем номера версий - if "_ver" in vals[0] or \ - (flagFunction and "pkg" == searchFunct.group(1)) or\ - (flagFunction and "load" == searchFunct.group(1) and\ - re.search("\(\s*ver\s*,",vals[0])): - verFile, verVar = self._convertVers(vals[1],valVars) - exec("res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")") - if res: - listEqual.append(True) - else: - listEqual.append(False) - else: - if flagIntTypeVar == None: - flagIntTypeVar = True - try: - valVars = int(valVars) - except: - flagIntTypeVar = False - if flagIntTypeVar: - if not vals[1].strip(): - vals[1] = 0 - try: - valFile = int(vals[1]) - except: - self.setError("'%s'"%term + " " + _("incorrect")) - self.setError (textError) - return False - valVar = valVars - exec("res=(%d%s%d)"%(valVar,sepF,valFile)) - if res: - listEqual.append(True) - else: - listEqual.append(False) - else: - if sepF == "!=" or sepF == "==": - if not vals[1].strip(): - vals[1] = "" - valFile = vals[1] - valVar = valVars - exec("res=("+'"""'+valVar+'"""'+sepF+"'"+valFile+\ - "'"+")") - if res: - listEqual.append(True) - else: - listEqual.append(False) - else: - if valVars == "": - listEqual.append(False) - else: - self.setError("'%s'"%term + " "\ - + _("incorrect")) - self.setError (textError) - return False - #exec("res=(%s)"%("".join(listEqual))) - res = self.executeListEqual(listEqual) - return res - - -class shareHeader: - """Общие методы для обработки заголовков""" - reSplParHeader = re.compile("\s+",re.I) - reHeader=re.compile(r"\A\s*#\s*calculate(\s+)?\\?([^\\\n]*\\\n)+[^\\\n]*\n?\ -|\s*#\s*calculate\s+([^\\\n]*\n?)",re.I|re.M) - - def getHeader(self, text): - """Получаем результат поиска и заголовок файла""" - sHeader = self.reHeader.search(text) - if sHeader: - return (sHeader, sHeader.group()) - else: - return (False, "") - - def getParamsHeader(self, textHeader): - """Получаем параметры заголовка в виде списка""" - listParams = self.reSplParHeader.split(textHeader.replace("\\"," ")) - if listParams[0] == "#": - return filter(lambda x: x, listParams[2:]) - else: - return filter(lambda x: x, listParams[1:]) - -class fileHeader(shareHeader, _terms): - """Обработка заголовков шаблонов и конфигурационных файлов - - """ - # Допустимые параметры заголовка - allowParam = ("format", "comment", "append", "force", "link", "mirror", - "symbolic", "chmod", "chown", "path", "name") - - # параметры без значения - listParNotVal = ("symbolic", "force", "mirror") - - # Возможные типы вставки шаблонов - _fileAppend = ("join", "before", "after", "replace", "remove", "skip") - - - # условные операторы - terms = ('>', '<', '==', '!=', '>=', '<=') - - # параметры без значения - #listParNotVal = ("symbolic", "force", "mirror") - # Форматы файлов для которых метод объединения replace если он не задан - #replaceFormats = ("raw","bin") - - def delHeaderConfFile(self, text, comment): - """Удаляет заголовок в тексте конфигурационного файла""" - if comment and text: - # Удаление Заголовка Calculate в конфигурационном файле - # В случае текста XML - if type(comment) == types.TupleType and len(comment) == 2: - _titleList = (_("Modified"), _("File of a template")) - reCalcHeader =\ - re.compile(u"\s*%s\s+%s.+Calculate.+\s+%s.+\s+%s\s?"%(\ - comment[0], - _titleList[0].decode("UTF-8"), - _titleList[1].decode("UTF-8"), - comment[1], - ), - re.M|re.I|re.U) - textUnicode = text.decode("UTF-8") - reS = reCalcHeader.search(textUnicode) - if reS: - textBody = textUnicode[:reS.start()]+textUnicode[reS.end():] - if textBody: - return textBody.encode("UTF-8") - else: - # В остальных случаях - reCalcHeader =\ - re.compile("\s*%s\-+\s+%s.+Calculate.+\s+%s.+\s+%s\-+\s?"%(\ - comment, - comment, - comment, - comment, - ), - re.M|re.I) - reS = reCalcHeader.search(text) - if reS: - return text[reS.end():] - return text - - def getPropertyTemplate(self, textHeader, foundHeader, fileType, objVar, - function, fileName): - """Получаем свойства шаблона из текста заголовка шаблона""" - # Объект с переменными - self.objVar=objVar - # Параметры файла шаблона - params = {} - # Будет ли шаблон применен - headerTerm = True - # Бинарный шаблон - if fileType=="bin": - params["format"] = fileType - params["_position"] = 0 - params["append"] = "replace" - params["_apply"] = headerTerm - # текстовый шаблон с заголовком - elif foundHeader: - # некорректные параметры - incorrectParams = set([]) - # Получаем список параметров шаблона - paramList = self.getParamsHeader(textHeader) - if paramList: - errTerm = _("header template '%s' not valid")%fileName - for i in paramList: - foundTerm = False - for term in self.terms: - if term in i: - foundTerm = True - rezTerm = self._equalTerm(i, "%s: %s"%(errTerm,i), - function) - if not rezTerm: - headerTerm = False - break - if not foundTerm: - par = i.split("=") - if len(par) == 1: - ret = self.checkParams(i, None, params) - if not ret: - incorrectParams = set([i]) - break - elif len(par) == 2: - ret = self.checkParams(par[0], par[1], params) - if not ret: - incorrectParams = set([i]) - break - if not "format" in params: - # format - raw - params["format"] = "raw" - if not "append" in params: - params["append"] = "replace" - else: - if not "append" in params: - # в зависимости от формата - join или replace - formatTemplate = params["format"] - if formatTemplate in ("raw", "bin", ""): - params["append"] = "replace" - else: - params["append"] = "join" - if incorrectParams: - headerTerm = False - self.setError(_("incorrect header parameters - '%s'")\ - %" ".join(list(incorrectParams))) - params["_position"] = foundHeader.end() - params["_apply"] = headerTerm - # текстовый шаблон без заголовка - else: - params["format"] = "raw" - params["_position"] = 0 - params["append"] = "replace" - params["_apply"] = headerTerm - return params - - def checkParams(self, name, value, dictPar): - """Проверка параметра заголовка, при успехе запись в словарь dictPar""" - # Проверка на допустимые параметры заголовка - if not name in self.allowParam: - return False - if name in self.listParNotVal and not value is None: - return False - if name == "append": - if not value in self._fileAppend: - return False - dictPar[name] = value - return True - - - -class dirHeader(shareHeader, _terms): - """Обработка заголовков шаблонов директорий - - """ - # Допустимые параметры заголовка - allowParam = ("append", "chmod", "chown", "path", "name") - # Возможные типы вставки шаблонов - _fileAppend = ("join", "remove", "skip") - # условные операторы - terms = ('>', '<', '==', '!=', '>=', '<=') - - - def getPropertyTemplate(self, text, objVar, function, fileName): - """Получаем свойства шаблона из текста шаблона""" - # Объект с переменными - self.objVar=objVar - # Параметры описанные в заголовке файла шаблона - params = {} - # Некорректные параметры - incorrectParams = set([]) - # Будет ли шаблон применен - headerTerm = True - foundHeader, textHeader = self.getHeader(text) - if foundHeader: - paramList = self.getParamsHeader(textHeader) - if paramList: - errTerm = _("header template '%s' not valid")%fileName - for i in paramList: - foundTerm = False - for term in self.terms: - if term in i: - foundTerm = True - rezTerm = self._equalTerm(i, "%s: %s"%(errTerm,i), - function) - if not rezTerm: - headerTerm = False - break - if not foundTerm: - par = i.split("=") - if len(par) == 1: - ret = self.checkParams(i, None, params) - if not ret: - incorrectParams = set([i]) - break - elif len(par) == 2: - ret = self.checkParams(par[0], par[1], params) - if not ret: - incorrectParams = set([i]) - break - if not "append" in params: - # По умолчанию join - params["append"] = "join" - if incorrectParams: - headerTerm = False - self.setError(_("incorrect header parameters - '%s'")\ - %" ".join(list(incorrectParams))) - params["_apply"] = headerTerm - # текстовый шаблон без заголовка - else: - headerTerm = False - self.setError(_("Can not found header in template")) - params["_apply"] = headerTerm - return params - - def checkParams(self, name, value, dictPar): - """Проверка параметра заголовка, при успехе запись в словарь dictPar""" - # Проверка на допустимые параметры заголовка - if not name in self.allowParam: - return False - if name == "append": - if not value in self._fileAppend: - return False - if value is None: - return False - dictPar[name] = value - return True - - -class objShare: - """Общий клас для объектов, наследуем - - """ - - def createFieldTerm(self, name, value, quote, docObj): - """Создание поля переменная - значение - - при создании поля проверяется первый символ названия переменной - и добавляется тег action - "!" - 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(_toUNICODE(text)) - element.appendChild(txtNode) - for attr in attributes.keys(): - attribute = doc.createAttribute(attr) - attribute.nodeValue = attributes[attr] - element.setAttributeNode(attribute) - return element - - -class xmlNode(xmlShare): - """Класс для создания нод без аттрибутов - - """ - def __init__(self): - self.node = False - - - def createNode(self, doc, tagName, text=""): - """Создает XML элемент без аттрибутов""" - self.node=self._createElement(doc, tagName, text) - return self.node - - def getNode(self): - return self.node - - -class xmlCaption: - """Класс XML заголовок - - """ - def __init__(self): - #Заголовок области XML нода - self.caption = False - - def createCaption(self, doc, name, quotes, action=False): - """Создание заголовка области""" - tmpNode = xmlNode() - self.caption = tmpNode.createNode(doc, "caption") - nameNode = tmpNode.createNode(doc, "name",name) - self.caption.appendChild(nameNode) - if action: - actNode = tmpNode.createNode(doc, "action", action) - self.caption.appendChild(actNode) - for q in quotes: - quoteNode = tmpNode.createNode(doc, "quote", q) - self.caption.appendChild(quoteNode) - return self.caption - - def getCaption(self): - """Выдает XML ноду заголовка области""" - return self.caption - -class xmlField(xmlShare): - """Класс для работы с XML полем - - """ - def __init__(self): - # XML нода поле - self.field = False - - - def createField(self, doc, typeField, quotes, name="", - values=[],action=False): - """Cоздание XML ноды поле""" - self.field = self._createElement(doc, "field", "", {"type":typeField}) - if name: - nameNode = self._createElement(doc, "name", name) - self.field.appendChild(nameNode) - for v in values: - valueNode = self._createElement(doc, "value", v) - self.field.appendChild(valueNode) - if action: - actNode = self._createElement(doc, "action", action) - self.field.appendChild(actNode) - for q in quotes: - quoteNode = self._createElement(doc, "quote", q) - self.field.appendChild(quoteNode) - return self.field - - - -class xmlFields: - """Класс, в котором находится список ХМL нод field - - """ - def __init__(self): - self.fields = [] - - def appendField(self, field): - """Добавить XML ноду field""" - self.fields.append(field) - return self.fields - - def getFields(self): - """Выдать список XML нод""" - return self.fields - - -class xmlArea: - """Класс для работы с XML областью - - """ - def __init__(self): - # Область - self.area = False - - def createArea(self, doc, xmlCaption, xmlFields): - """Создание XML области""" - tmpNode = xmlNode() - self.area = tmpNode.createNode(doc, "area") - if xmlCaption and xmlCaption.getCaption(): - self.area.appendChild(xmlCaption.getCaption()) - if xmlFields: - fields = xmlFields.getFields() - for field in fields: - self.area.appendChild(field) - return self.area - -class xmlDoc: - """Класс для работы с XML документом - - """ - def __init__(self): - # документ - self.doc = False - # главная нода - self.root = False - # тело документа - self.body = False - # Заголовок области - временный (в реальности один объект заголовок) - self.tmpCaption = False - # Поля - временные (в реальности один объект поля) - self.tmpFields = False - # Разделитель областей - по умолчанию перевод строки "\n" - self.sepAreas = False - # Разделитель разделенных списков - по умолчанию перевод строки "\n" - #self.sepSplitFields = False - - - def createDoc(self, typeDoc, version): - """Создание нового документа новый документ""" - docTxt = '' - 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 - i += 1 - if lenTail>1 and lenTail != i: - return (False,1) - if i > 0: - result = True - return (result, i) - - def encode(self, text): - """Кодирует смешанный формат в UTF-8""" - ind = 0 - l = 0 - utf = [] - lenUtf = [] - indErr = [] - i = 0 - for ch in text: - r, l = self._retUTF(ch) - utf.append(r) - lenUtf.append(l) - i+=1 - while 1: - if utf[ind] == '_fb_': - res, l = self._sumbUtf(utf[ind:(ind+lenUtf[ind])],lenUtf[ind]) - if res == False: - indErr.append(ind) - if l>0: - ind +=l - if ind >= len(utf): - break - else: - if utf[ind] != '_ch_': - indErr.append(ind) - ind +=1 - if ind >= len(utf): - break - if indErr: - lenIndErr = len(indErr) - block = [] - blocks = [] - if lenIndErr > 1: - i = 1 - while 1: - if i == 1: - block.append(indErr[i-1]) - if indErr[i] - indErr[i-1] == 1: - block.append(indErr[i]) - else: - if block: - blocks.append(block) - block = [] - block.append(indErr[i]) - i +=1 - if i >= lenIndErr: - break - else: - block.append(indErr[0]) - if block: - blocks.append(block) - listErr = [] - for block in blocks: - string = "" - for elem in block: - string += hex(ord(text[elem]))[-2:] - listErr.append((block[0],"__hex__?%s?__hex__" %string,elem)) - textOut = text - deltaInd = 0 - for erEl in listErr: - startInd = erEl[0] + deltaInd - endInd = erEl[2] + 1 + deltaInd - textOut = textOut[:startInd] + erEl[1] + textOut[endInd:] - deltaInd += len(erEl[1])-(erEl[2]-erEl[0]+1) - return textOut - - def decode(self, text): - """Декодирует UTF-8 в смешанный формат""" - varStart = "__hex__\?" - varEnd = "\?__hex__" - # -1 Это экранирование '?' которое тоже считается - deltVarStart = len(varStart)-1 - deltVarEnd = len(varEnd)-1 - reVar = re.compile(("%s[a-f0-9]+%s")%(varStart,varEnd),re.M) - resS = reVar.search(text) - textTemplateTmp = text - while resS: - mark = textTemplateTmp[resS.start():resS.end()] - hexString = mark[deltVarStart:-deltVarEnd] - i = 0 - stringInsert = "" - hexCode = "" - for ch in hexString: - if i>=1: - hexCode += ch - stringInsert += chr(int(hexCode, 16)) - hexCode = "" - i = 0 - else: - hexCode += ch - i += 1 - textTemplateTmp = textTemplateTmp.replace(mark, stringInsert) - resS = reVar.search(textTemplateTmp) - return textTemplateTmp - -class template(_file, _terms, xmlShare): - """Класс для работы с шаблонами - - На вход 2 параметра: объект хранения переменных, имя сервиса - не - обязательный параметр - - """ - # Импортированные классы поддерживаемых форматов шаблонов - importFormats = {} - # Имена установленных программ - installProg = [] - # Версии установленных программ - installProgVersions = [] - # кеш вызванных значений программа, номер версии - cacheInstallProg = {} - # Название файла шаблона директории - templDirNameFile = ".calculate_directory" - - def __init__(self, objVar, dirsFilter=[], filesFilter=[]): - # Необрабатываемые директории - self.dirsFilter = dirsFilter - # Необрабатываемые файлы - self.filesFilter = filesFilter - _file.__init__(self) - # Словарь для создания объектов новых классов по образцу - # (proftpd создается на основе apache) - self.newObjProt = {'proftpd':'apache'} - # Заголовок title - self.__titleHead = "--------------------------------------\ -----------------------------------------" - self._titleBody = "" - self._titleList = (_("Modified"), _("File of a template")) - - # Метки - varStart = "#-" - varEnd = "-#" - self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")%(varStart,varEnd),re.M) - self._reFunc = re.compile(("%s[a-zA-Z0-9_\-\+\(\)\, \*\/\.]+%s")\ - %(varStart,varEnd),re.M) - self._deltVarStart = len(varStart) - self._deltVarEnd = len(varEnd) - # Условия - self._reTermBloc = re.compile("#\?(?P[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 = "" - - def __octToInt(self, strOct): - """Преобразование восьмеричного в целое (ввод строка, вывод число)""" - if strOct: - z = 0 - i = 0 - lst = list(strOct) - lst.reverse() - for ch in lst: - try: - v = int(ch) - except: - self.setError(_("Not valid oct value: ") + str(strOct)) - return False - if v > 7: - self.setError (_("Not valid oct value: ") + str(strOct)) - return False - z = z + v*8**i - i = i +1 - return z - else: - self.setError (_("Empty oct value")) - return False - - def getFormatObj(self, formatTemplate, textTemplate): - """Создание объекта формата шаблона. - - Объект создается на основании формата шаблона и текста шаблона""" - if formatTemplate in self.importFormats: - classFormat = self.importFormats[formatTemplate] - else: - try: - classFormat = getattr(__import__("format.%s"%formatTemplate, - globals(), locals(), - [formatTemplate]), - formatTemplate) - except (ImportError, AttributeError): - #Создаем объект из self.newObjProt с помощью - # метаклассов - if formatTemplate in self.newObjProt: - # Прототип класса - nameProt = self.newObjProt[formatTemplate] - try: - classProt = getattr(__import__("format.%s"%nameProt, - globals(), locals(), - [nameProt]), - nameProt) - except (ImportError, AttributeError): - return False - newCl = self.createNewClass(formatTemplate, (classProt,)) - self.importFormats[formatTemplate] = newCl - return newCl(textTemplate) - else: - return False - self.importFormats[formatTemplate] = classFormat - return classFormat(textTemplate) - - def removeDir(self, rmDir): - """Рекурсивное удаление директории - - входной параметр директория - """ - if not os.path.exists(rmDir): - self.printERROR(_("Not found remove dir %s") %rmDir) - return False - fileObj = _file() - # Сканируем директорию - scanObjs = fileObj.scanDirs([rmDir]) - for socketRm in scanObjs[0].sockets: - # Удаляем сокеты - if os.path.exists(socketRm): - os.remove(socketRm) - for linkRm in scanObjs[0].links: - # Удаляем ссылки - os.unlink(linkRm[1]) - for fileRm in scanObjs[0].files: - # Удаляем файлы - os.remove(fileRm) - scanObjs[0].dirs.sort(lambda x, y: cmp(len(y), len(x))) - for dirRm in scanObjs[0].dirs: - # Удаляем директории - os.rmdir(dirRm) - if rmDir: - os.rmdir(rmDir) - return True - - - def createConfFile(self, pathTemplate, path=False): - """Создает конфигурационный файл если его нет""" - # Создаем директорию если ее нет - if not path: - path = os.path.split(pathTemplate)[0] - if not os.path.exists(path): - createDirs = self.createDir(path) - if not createDirs: - self.setError (_("Can not create file:" ) + pathTemplate) - return False - # Создаем файл если его нет - if not os.path.exists(pathTemplate): - try: - dMode, uid, gid = self.getModeFile(path) - #mode = dMode & ~0111 - # Создаем файл - open(pathTemplate,"w").close() - #os.chmod(pathTemplate, mode) - os.chown(pathTemplate, uid, gid) - except: - self.setError (_("Can not create file:" ) + pathTemplate) - return False - return True - - def createDir(self, dirName, mode=False, uid=False, gid=False): - """Создает директорию""" - if os.access(dirName, os.F_OK): - return [dirName] - else: - dMode = False - prevDir, tmpSubdir = os.path.split(dirName) - createDirs = [] - while not os.access(prevDir, os.F_OK): - createDirs.append(prevDir) - prevDir = os.path.split(prevDir)[0] - try: - tmpMode,dUid,dGid = self.getModeFile(prevDir) - except OSError: - self.setError (_("Not access dir: " ) + prevDir) - return False - if not mode is False: - dMode = mode - if not uid is False: - dUid = uid - if not gid is False: - dGid = gid - createDirs.reverse() - for nameDir in createDirs: - try: - if dMode: - os.mkdir(nameDir, dMode) - else: - os.mkdir(nameDir) - os.chown(nameDir, dUid, dGid) - except: - self.setError (_("Can not create dir: " ) + nameDir) - return False - try: - if dMode: - os.mkdir(dirName, dMode) - else: - os.mkdir(dirName) - os.chown(dirName, dUid, dGid) - createDirs.append(dirName) - except: - self.setError (_("Can not create dir: " ) + dirName) - return False - return createDirs - - - def applyVarsTemplate(self, textTemplate, nameTemplate): - """ Заменяет переменные на их значения - """ - resS = self._reVar.search(textTemplate) - textTemplateTmp = textTemplate - while resS: - mark = textTemplateTmp[resS.start():resS.end()] - varName = mark[self._deltVarStart:-self._deltVarEnd] - varValue = "" - try: - varValue = str(self.objVar.Get(varName)) - except self.objVar.DataVarsError, e: - print _("error in template %s")%nameTemplate - print e - exit(1) - textTemplateTmp = textTemplateTmp.replace(mark, varValue) - resS = self._reVar.search(textTemplateTmp) - return textTemplateTmp - - - def applyFuncTemplate(self, textTemplate, nameTemplate): - """ Применяет функции к тексту шаблона - """ - def equalTerm(term, sNum, sMD, localVars): - """Локальная функция для вычисления выражения""" - terms = sNum.findall(term) - if terms: - strNumers = [] - for n in terms: - strNum = n.strip() - if "*" in strNum or "/" in strNum: - strNum = multAndDiv(strNum,sNum,sMD,localVars) - try: - num = int(strNum) - except: - minus = False - if strNum[:1] == "-": - minus = True - strNum = strNum[1:] - if localVars.has_key(strNum): - num = localVars[strNum] - elif self.objVar.exists(strNum): - try: - num = int(self.objVar.Get(strNum)) - except: - print _("error in template %s")%nameTemplate - print _("error var %s not int")%str(strNum) - exit(1) - else: - print _("error in template %s")%nameTemplate - print _("error local var %s not defined")\ - %str(strNum) - exit(1) - if minus: - num =-num - strNumers.append(num) - return sum(strNumers) - print _("error in template %s")%nameTemplate - print _("error template term %s, incorrect data")%str(term) - exit(1) - - def multAndDiv(term,sNum,sMD,localVars): - """локальная функция для умножения и деления""" - termTmp = term - varsLocal = sMD.findall(term) - for var in varsLocal: - flagVarTxt = True - try: - int(var) - except: - flagVarTxt = False - if flagVarTxt: - continue - varReplace = str(equalTerm(var,sNum,sMD,localVars)) - termTmp = termTmp.replace(var,varReplace) - ret = eval(termTmp) - return ret - - def funcSum(funTxt,resS,localVars,textTemplateTmp): - """локальная функция вычисляет первую функцию sum() в шаблоне""" - terms = funTxt[4:-1].replace(" ","").split(",") - # Название локальной переменной - nameLocVar = terms[0] - if not localVars.has_key(nameLocVar): - localVars[nameLocVar] = 0 - if len(terms) == 2: - if terms[1].strip(): - localVars[nameLocVar] = equalTerm(terms[1],sNum,sMD, - localVars) - replace = str(localVars[nameLocVar]) - else: - replace = "" - textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ - textTemplateTmp[resS.end():] - elif len(terms) == 3: - if terms[1].strip(): - replaceInt = equalTerm(terms[1],sNum,sMD,localVars) - replace = str(replaceInt) - else: - replace = "" - localVars[nameLocVar] = equalTerm(terms[2], - sNum,sMD,localVars) - textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ - textTemplateTmp[resS.end():] - else: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - exit(1) - return textTemplateTmp - - def funcLoad(funTxt,resS,textTemplateTmp): - """если файл существует читает из файла локальную переменную - - если один параметр - выводит значение локальной переменной - """ - terms = funTxt[5:-1].replace(" ","").split(",") - if not terms[0].strip() or\ - (len(terms)==2 and not terms[1].strip()) or\ - len(terms)>2: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - exit(1) - if len(terms) == 2: - if not terms[0] in ["ver","num","char","key"]: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - print _("first argument function is not 'ver' or 'num' or\ - 'char'") - exit(1) - if len(terms) == 1: - fileName = terms[0].strip() - if fileName[0] != "/": - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - print _("incorrect path %s")%fileName - exit(1) - else: - fileName = terms[1].strip() - if fileName[0] != "/": - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - print _("incorrect path %s")%fileName - exit(1) - replace = "" - if os.path.exists(fileName): - FD = open(fileName) - replace = FD.read().strip() - FD.close - if not replace and len(terms) == 2 and terms[0] in ["ver","num"]: - replace = "0" - textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ - textTemplateTmp[resS.end():] - return textTemplateTmp - - def getInstallPkgGentoo(names = [], versions = []): - """Выдает два списка, инсталлированные программы и номера версий""" - baseDir = "/var/db/pkg" - pkgs = [] - reVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*") - def getFilesDir(pkgs, dirname, names): - for nameFile in names: - absNameFile = os.path.join(dirname,nameFile) - if os.path.isdir(absNameFile): - tail = absNameFile.split(baseDir) - if len(tail)==2: - tail = tail[1].split('/') - if len(tail)==3 and tail[1]!='virtual': - pkgs.append(tail[2]) - return True - os.path.walk(baseDir,getFilesDir, pkgs) - pkgs.sort() - for pkg in pkgs: - findVer = reVer.search(pkg) - if findVer: - ver = findVer.group() - versions.append(ver) - names.append(pkg.split(ver)[0][:-1]) - #return pkgs - return names, versions - - def pkg(nameProg, names, versions): - """Выдает установленные версии по имени программы""" - # Значение версии из кеша - if nameProg in self.cacheInstallProg: - return self.cacheInstallProg[nameProg] - i = 0 - vers = [] - for name in names: - if nameProg == name: - while nameProg == names[i]: - vers.append(versions[i]) - i += 1 - break - i += 1 - if vers: - version = vers[-1] - # Запись значения версии в кеш - self.cacheInstallProg[nameProg] = version - return version - else: - return "" - - def funcPkg(funTxt,resS,textTemplateTmp): - """локальная функция выдает номер версии программы""" - terms = funTxt[4:-1].replace(" ","") - # Название программы - nameProg = terms - if not self.installProg: - # Получение всех названий и версий установленных программ - self.installProg,self.installProgVersions =\ - getInstallPkgGentoo(names=self.installProg, - versions=self.installProgVersions) - replace = pkg(nameProg,self.installProg,self.installProgVersions) - textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ - textTemplateTmp[resS.end():] - return textTemplateTmp - - def funcRnd(funTxt,resS,textTemplateTmp): - """локальная функция выдает строку случайных символов - - первый аргумент: - 'num' - числа, - 'pas' - цифры и буквы - второй аргумент: - количество символов - """ - terms = funTxt[4:-1].replace(" ","").split(",") - if not terms[0].strip() or\ - (len(terms)==2 and not terms[1].strip()) or\ - len(terms)!=2: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - exit(1) - fArgvNames = ['num','pas'] - if not terms[0] in fArgvNames: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - print _("first argument function is not 'num' or 'pas'") - exit(1) - try: - lenStr = int(terms[1]) - except: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - print _("two argument function is not number") - exit(1) - if terms[0] == fArgvNames[0]: - replace=''.join([random.choice(string.digits)\ - for i in xrange(lenStr)]) - elif terms[0] == fArgvNames[1]: - replace=''.join([random.choice(string.ascii_letters + \ - string.digits) for i in xrange(lenStr)]) - else: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - exit(1) - textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ - textTemplateTmp[resS.end():] - return textTemplateTmp - - def funcCase(funTxt,resS,textTemplateTmp): - """локальная функция выдает переменную в определенном регистре - - первый аргумент: - 'upper' - верхний регистр, - 'lower' - нижний регистр, - 'capitalize' - первая буква в верхнем регистре - второй аргумент: - название переменной - """ - terms = funTxt[5:-1].replace(" ","").split(",") - if not terms[0].strip() or\ - (len(terms)==2 and not terms[1].strip()) or len(terms)!=2: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - exit(1) - fArgvNames = ['upper','lower','capitalize'] - if not terms[0] in fArgvNames: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - print _("first argument function is not 'upper' or 'lower' or\ - 'capitalize'") - exit(1) - try: - strValue = str(self.objVar.Get(terms[1])) - except: - print _("error in template %s")%nameTemplate - print _("error var %s not found")%str(terms[1]) - exit(1) - replace = "" - strValue = _toUNICODE(strValue) - if terms[0] == 'upper': - replace = strValue.upper() - elif terms[0] == 'lower': - replace = strValue.lower() - elif terms[0] == 'capitalize': - replace = strValue.capitalize() - if replace: - replace = replace.encode("UTF-8") - textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ - textTemplateTmp[resS.end():] - return textTemplateTmp - - # Локальные переменные - localVars = {} - # Регулярное выражние для сложения - sNum = re.compile("\-[^\-\+]+|[^\-\+]+") - # Регулярное выражение для умножениея и деления - sMD = re.compile("[^\-\+\*\/]+") - resS = self._reFunc.search(textTemplate) - textTemplateTmp = textTemplate - while resS: - mark = textTemplateTmp[resS.start():resS.end()] - funTxt = mark[self._deltVarStart:-self._deltVarEnd] - # Функция sum - if funTxt[:4] == "sum(": - textTemplateTmp = funcSum(funTxt,resS,localVars,textTemplateTmp) - resS = self._reFunc.search(textTemplateTmp) - # Функция load - elif funTxt[:5] == "load(": - textTemplateTmp = funcLoad(funTxt,resS,textTemplateTmp) - resS = self._reFunc.search(textTemplateTmp) - elif funTxt[:4] == "pkg(": - textTemplateTmp = funcPkg(funTxt,resS,textTemplateTmp) - resS = self._reFunc.search(textTemplateTmp) - elif funTxt[:4] == "rnd(": - textTemplateTmp = funcRnd(funTxt,resS,textTemplateTmp) - resS = self._reFunc.search(textTemplateTmp) - elif funTxt[:5] == "case(": - textTemplateTmp = funcCase(funTxt,resS,textTemplateTmp) - resS = self._reFunc.search(textTemplateTmp) - else: - resS = False - return textTemplateTmp - - def applyTermsTemplate(self,textTemplate,nameTemplate,nameSystemFile=False): - """ Применяет условия, к условным блокам текста - """ - textTerm = "" - resS = self._reTermBloc.search(textTemplate) - textTemplateTmp = textTemplate - def function(text): - """Функция обработки функций в заголовке""" - return self.applyFuncTemplate(text, nameTemplate) - if nameSystemFile: - while resS: - mark = resS.group(0) - body = resS.group("body") - end = resS.group("end") - parent = resS.group("func") - if not parent: - parent = "" - term = resS.group("rTerm") + parent +\ - resS.group("lTerm") - if self._equalTerm(term, _("content template not valid: ")+\ - nameTemplate, function): - textTemplateTmp = textTemplateTmp.replace(mark, body+end) - else: - textTemplateTmp = textTemplateTmp.replace(mark, "") - resS = self._reTermBloc.search(textTemplateTmp) - else: - while resS: - mark = resS.group(0) - body = resS.group("body") - end = resS.group("end") - term = resS.group("rTerm") + resS.group("lTerm") - if self._equalTerm(term, _("content template not valid: ")+\ - nameTemplate): - textTemplateTmp = textTemplateTmp.replace(mark, body+end) - else: - textTemplateTmp = textTemplateTmp.replace(mark, "") - resS = self._reTermBloc.search(textTemplateTmp) - return textTemplateTmp - - def getTitle(self, comment, commentList): - """Выдает заголовок шаблона ( версия и.т.д)""" - if comment: - commentFirst = comment - commentInsert = comment - commentLast = comment - flagList = False - # В случае открывающего и закрывающего комментария - if type(comment) == types.TupleType and len(comment) == 2: - commentFirst = comment[0] - commentInsert = "" - commentLast = comment[1] - flagList = True - if flagList: - self._titleBody = commentFirst + "\n" - else: - self._titleBody = commentFirst + self.__titleHead + "\n" - z = 0 - lenCommentList = len(commentList) - 1 - for com in self._titleList: - if lenCommentList < z: - self._titleBody += commentInsert + " " + com + "\n" - else: - self._titleBody += commentInsert + " " + com +\ - " " + commentList[z] + "\n" - z += 1 - if flagList: - self._titleBody += commentLast +"\n" - else: - self._titleBody += commentLast + self.__titleHead + "\n" - return self._titleBody - else: - return "" - - def numberAllTemplates(self, number): - """Количество шаблонов - - Вызов происходит перед наложением шаблонов - в момент вызова в number находится количество обрабатываемых файлов - Наследуемая функция - Используется для отображения прогресса при наложениии шаблонов - """ - return True - - def numberProcessTemplates(self, number): - """Номер текущего обрабатываемого шаблона - - Вызов происходит при наложении шаблона - в момент вызова в number находится номер обрабатываемого шаблона - Наследуемая функция - Используется для отображения прогресса при наложениии шаблонов - """ - return True - - def __clearInErrorDirObj(self, dirObj): - """Очищает объект директории при ошибке""" - # директории [(путь к директории, свойства директории)...] - dirObj.dirs = [] - # файлы [(путь к файлу, свойства файла)...] - dirObj.files = [] - # Ошибка - dirObj.flagError = True - return dirObj - - def __scanDir(self, templatesDir, dirObj, dirProperties=()): - """Измененное cканирование одной директории""" - # сканирование файлов и директорий (следующие сканирования) - if dirProperties: - # Выход при ошибке - if dirObj.flagError: - return dirObj - dirName, prop = dirProperties - # В случае удаления не смотрим внутренние директории - if "append" in prop and prop["append"] == "remove": - return dirObj - filesOrDirs = os.listdir(dirName) - # Сортируем файлы и директории - filesOrDirs.sort() - # Добавляем директорию и ее свойства - dirObj.dirs.append((dirName, prop)) - if self.templDirNameFile in filesOrDirs: - # Удаляем файл описания директории из списка файлов - filesOrDirs.remove(self.templDirNameFile) - for fileOrDir in filesOrDirs: - # Выход при ошибке - if dirObj.flagError: - return dirObj - absPath = os.path.join(dirName,fileOrDir) - statInfo = os.stat(absPath)[stat.ST_MODE] - if stat.S_ISREG(statInfo): - # Свойства файла - propF, applyFile=self.__isApplyHeadTemplate(dirObj.fHeadObj, - absPath) - if self.getError(): - self.setError(_("Incorrect template: " ) + absPath) - return self.__clearInErrorDirObj(dirObj) - if not applyFile: - continue - # Обработка skip - if "append" in propF and propF["append"] == "skip": - continue - if not "path" in propF: - propF["path"] = prop["_real_path"] - if not "name" in propF: - propF["name"] = os.path.split(absPath)[1] - propF["_real_path"] = os.path.join(propF["path"], - propF["name"]) - dirObj.files.append((absPath, propF)) - elif stat.S_ISDIR(statInfo): - # Информация о директории - pDir = {} - # Файл информации о директории - dirInfoFile = os.path.join(absPath, - self.templDirNameFile) - if os.path.exists(dirInfoFile) and\ - stat.S_ISREG(os.stat(dirInfoFile)[stat.ST_MODE]): - # Настройки директории и применение - pDir, applyDir = self.__isApplyHeadDir(dirObj.dHeadObj, - dirInfoFile) - if self.getError(): - self.setError(_("Incorrect template: " ) +\ - dirInfoFile) - return self.__clearInErrorDirObj(dirObj) - if not applyDir: - continue - if not "path" in pDir: - pDir["path"] = prop["_real_path"] - if not "name" in pDir: - pDir["name"] = os.path.split(absPath)[1] - # Обработка skip - if "append" in pDir and pDir["append"] == "skip": - pDir["_real_path"] = pDir["path"] - else: - pDir["_real_path"] = os.path.join(pDir["path"], - pDir["name"]) - self.__scanDir(False, dirObj, (absPath, pDir)) - return dirObj - # Сканирование для получения настроек директории (первое) - else: - if templatesDir and stat.S_ISDIR(os.stat(templatesDir)[stat.ST_MODE]): - # настройки директории - pDir = {} - # Файл информации о директории - dirInfoFile = os.path.join(templatesDir, self.templDirNameFile) - if os.path.exists(dirInfoFile) and\ - stat.S_ISREG(os.stat(dirInfoFile)[stat.ST_MODE]): - # Настройки директории и применение - pDir,applyDir = self.__isApplyHeadDir(dirObj.dHeadObj, - dirInfoFile) - if self.getError(): - self.setError(_("Incorrect template: " ) +\ - dirInfoFile) - return self.__clearInErrorDirObj(dirObj) - if not applyDir: - return dirObj - if not "path" in pDir: - pDir["path"] = "/" - if not "name" in pDir: - pDir["name"] = os.path.split(templatesDir)[1] - # Обработка skip - if "append" in pDir and pDir["append"] == "skip": - pDir["_real_path"] = pDir["path"] - else: - pDir["_real_path"] = os.path.join(pDir["path"], - pDir["name"]) - self.__scanDir(False, dirObj, (templatesDir, pDir)) - return dirObj - - - def scanDirs(self, templatesDirs, objVar): - """Измененное cканирование директорий на вход список - - Выход список объктов _dir - """ - dirs = [] - # Объект заголовка файла - fHeadObj = fileHeader() - # Объект заголовка директории - dHeadObj = dirHeader() - # Объект переменных - for templateDir in templatesDirs: - dirP = scan._dir() - dirP.baseDir = templateDir - # Ошибка при сканировании - dirP.flagError = False - # Объект заголовка файла - dirP.fHeadObj = fHeadObj - # Объект заголовка директории - dirP.dHeadObj = dHeadObj - # Объект переменных - dirP.objVar = objVar - try: - self.__scanDir(templateDir, dirP) - except OSError, e: - print e.strerror, e.filename - self.__clearInErrorDirObj(dirP) - return [dirP] - if dirP.flagError: - return [dirP] - dirs.append(dirP) - return dirs - - def applyTemplates(self): - """Применяет шаблоны к конфигурационным файлам""" - if not self.objVar.defined("cl_template_path"): - self.setError (_("not defined Var: ") + "cl_template_path") - return False - dirsTemplates = self.objVar.Get("cl_template_path") - dirsTemplates.sort() - dirObjs = self.scanDirs(dirsTemplates,self.objVar) - #файлы к которым были применены шаблоны - filesApply = [] - #созданные директории - createdDirs = [] - # Получаем общее количество шаблонов (нужно для прогресбара) - allApplyFiles = self.scanTemplates(dirObjs) - if allApplyFiles == False: - return False - numberAllTemplates = len(allApplyFiles) - # Вызываем пустой метод с параметром общее количество шаблонов - self.numberAllTemplates(numberAllTemplates) - # номер обрабатываемого файла - numberProcessTemplates = 0 - # имя текущей программы - _nameProgram = self.objVar.Get("cl_name").capitalize() - # версия текущей программы - _versionProgram = self.objVar.Get("cl_ver") - # имя и версия текущей программы - programVersion = "%s %s"%(_nameProgram, _versionProgram) - # Объект обработки заголовков файлов шаблонов - fileHeadObj = fileHeader() - # Проверка на ошибки - for dirObj in dirObjs: - if dirObj.flagError: - return False - for dirObj in dirObjs: - # сортируем файлы по названию - if dirObj.files: - dirObj.files.sort() - # сортируем директории по названию - if dirObj.dirs: - dirObj.dirs.sort() - blockDirs = [] - propDir = {} - for dirTemplate, pDirs in dirObj.dirs: - # Получаем реальный путь директории - pathDir = pDirs["_real_path"] - # Фильтрация шаблонов по названию директории - if pathDir in self.dirsFilter: - blockDirs.append(dirTemplate) - continue - dirInfoFile = os.path.join(dirTemplate, self.templDirNameFile) - pathDir, propDir, crDirs = self.__getApplyHeadDir(pDirs) - if not propDir and self.getError(): - self.setError(_("Error in apply template: " ) +\ - dirInfoFile) - return False - if crDirs: - createdDirs += crDirs - for fileTemplate, propFile in dirObj.files: - findBlock = False - pathFile = propFile["_real_path"] - for blDir in blockDirs: - st,mid,end = pathFile.partition(blDir) - if (not st) and mid and end: - findBlock = True - break - if findBlock: - continue - numberProcessTemplates += 1 - self.numberProcessTemplates(numberProcessTemplates) - # Фильтрация шаблонов по названию файла - if pathFile in self.filesFilter: - continue - titleBaseDir = os.path.split(dirObj.baseDir)[0] - titlePath = fileTemplate.partition(titleBaseDir)[2] - templTitle = '"' + titlePath[1:] + '"' - # Записываем в переменную обрабатываемый файл - self.objVar.Set("cl_pass_file",pathFile) - filesApl = self.join(fileTemplate, propFile, - (programVersion,templTitle), fileHeadObj) - if filesApl: - filesApply += filesApl - else: - if self.getError(): - #print self.getError() - return False - self.closeFiles() - return (createdDirs, filesApply) - - def scanTemplates(self, dirObjs=False): - """Сканирует директории шаблонов - выводит список файлов""" - if not self.objVar.defined("cl_template_path"): - self.setError (_("not defined Var: ") + "cl_template_path") - return False - if not dirObjs: - dirsTemplates = self.objVar.Get("cl_template_path") - dirObjs = self.scanDirs(dirsTemplates, self.objVar) - #файлы к которым были применены шаблоны - filesApply = [] - # Проверка на ошибки - for dirObj in dirObjs: - if dirObj.flagError: - return False - for dirObj in dirObjs: - # сортируем файлы по названию - if dirObj.files: - dirObj.files.sort() - # сортируем директории по названию - if dirObj.dirs: - dirObj.dirs.sort() - blockDirs = [] - for dirTemplate, pDirs in dirObj.dirs: - pathDir = pDirs["_real_path"] - # Фильтрация шаблонов по названию директории - if pathDir in self.dirsFilter: - blockDirs.append(dirTemplate) - continue - for fileTemplate, propFile in dirObj.files: - findBlock = False - pathFile = propFile["_real_path"] - # Фильтрация файлов по названию директории - for blDir in blockDirs: - st,mid,end = pathFile.partition(blDir) - if (not st) and mid and end: - findBlock = True - break - if findBlock: - continue - # Фильтрация шаблонов по названию файла - if pathFile in self.filesFilter: - continue - filesApply.append(pathFile) - return filesApply - - - def __isApplyHeadDir(self, headerObj, templateDirFile): - """Будет ли применен шаблон корневой директории - - Возвращает: - (Настройки директории, и будет ли она применена (True, False)) - """ - # Настройки для директории - dPrefs = {} - - def function(text): - """Функция обработки функций в заголовке""" - return self.applyFuncTemplate(text, templateDirFile) - - if not os.path.exists(templateDirFile): - return (dPrefs, True) - try: - FD = open(templateDirFile) - textTemplate = FD.read() - FD.close() - except: - self.setError(_("Error open template: " ) + templateDirFile) - return (dPrefs, False) - # Заменяем переменные на их значения - textTemplate = self.applyVarsTemplate(textTemplate, templateDirFile) - # Обработка заголовка - propDir = headerObj.getPropertyTemplate(textTemplate,self.objVar, - function, templateDirFile) - if not propDir["_apply"]: - if headerObj.getError(): - self.setError(_("Incorrect template: " ) + templateDirFile) - return (dPrefs, False) - # Записываем настройки - dPrefs.update(propDir) - # Тип добавления - if dPrefs['append'] == "remove": - # Удаление конфигурационного файла - return (dPrefs, False) - # chmod - изменяем права - if "chmod" in dPrefs: - mode = self.__octToInt(dPrefs["chmod"]) - if mode: - dPrefs["chmod"] = mode - else: - self.setError (_("False value 'chmod' in template: " ) +\ - templateDirFile) - return (dPrefs, False) - # chown - изменяем владельца и группу - if "chown" in dPrefs: - owner = dPrefs["chown"] - uid = False - gid = False - if ":" in owner: - strUid, strGid = owner.split(":") - import pwd - try: - uid = pwd.getpwnam(strUid)[2] - except: - self.setError (_("Not user in this system: ") + strUid) - self.setError (_("False value 'chown' in template: " )+\ - templateDirFile) - return (dPrefs, False) - try: - import grp - gid = grp.getgrnam(strGid)[2] - except: - self.setError (_("Not group in this system: ")+strGid) - self.setError (_("False value 'chown' in template: " )+\ - templateDirFile) - return (dPrefs, False) - dPrefs["chown"] = [uid, gid] - else: - self.setError (_("False value 'chown' in template: " ) +\ - templateDirFile) - return (dPrefs, False) - # Проверяем path - if "path" in dPrefs and\ - (not dPrefs["path"] or not dPrefs["path"][0] == "/"): - self.setError (_("False value 'path' in template: " )+\ - templateDirFile) - return (dPrefs, False) - # Проверяем name - if "name" in dPrefs and\ - (dPrefs["name"] and dPrefs["name"][0] == "/"): - self.setError (_("False value 'name' in template: " )+\ - templateDirFile) - return (dPrefs, False) - return (dPrefs, True) - - def __getApplyHeadDir(self, dictPropDir): - """Применяет шаблон к директории (права, владелец, и.т. д)""" - newDirMv = dictPropDir["_real_path"] - applyDir = newDirMv - # Созданные директории - createDirs = [] - - if "append" in dictPropDir: - if dictPropDir["append"]=="skip": - return (applyDir, dictPropDir, createDirs) - # Удаляем директорию - elif dictPropDir["append"]=="remove": - if os.path.isdir(newDirMv): - # удаляем директорию - try: - self.removeDir(newDirMv) - except: - self.setError(_("Can not delete dir: " ) +\ - newDirMv) - return (applyDir, False, createDirs) - - # Флаг проверки существования директории - flagFoundDir = os.path.exists(newDirMv) - mode = False - uid = False - gid = False - # chmod - изменяем права - if "chmod" in dictPropDir: - mode = dictPropDir['chmod'] - if flagFoundDir: - os.chmod(newDirMv, mode) - # chown - изменяем владельца и группу - if "chown" in dictPropDir: - uid, gid = dictPropDir['chown'] - if flagFoundDir: - os.chown(newDirMv, uid, gid) - if not flagFoundDir: - createDirs = self.createDir(newDirMv, mode, uid, gid) - if not createDirs: - return (applyDir, False, createDirs) - return (applyDir, dictPropDir, createDirs) - - - def __isApplyHeadTemplate(self, headerObj, templateName): - """Будет ли применен файл шаблона - - Возвращает: - (Настройки файла, и будет ли он применен (True, False)) - """ - # Настройки для файла - fPrefs = {} - def function(text): - """Функция обработки функций в заголовке""" - return self.applyFuncTemplate(text, templateName) - - if not os.path.exists(templateName): - return (fPrefs, True) - try: - FD = open(templateName) - textTemplate = FD.read() - FD.close() - except: - self.setError(_("Error open template: " ) + templateName) - return (fPrefs, False) - # Бинарный или текстовый файл шаблона - templateType = self.getFileType(templateName) - foundHeader = False - textHeader = "" - if templateType != "bin": - # Получаем заголовок файла шаблона - foundHeader, textHeader = headerObj.getHeader(textTemplate) - # Заменяем переменные на их значения - textHeader = self.applyVarsTemplate(textHeader, templateName) - propFile = headerObj.getPropertyTemplate(textHeader, foundHeader, - templateType, self.objVar, - function,templateName) - if not propFile["_apply"]: - if headerObj.getError(): - self.setError(_("Incorrect template: " ) + templateName) - return (fPrefs, False) - if propFile["append"] == "remove": - # Удаление конфигурационного файла - return (propFile, False) - # Записываем настройки - fPrefs.update(propFile) - # chmod - изменяем права - if "chmod" in fPrefs: - mode = self.__octToInt(fPrefs["chmod"]) - if mode: - fPrefs["chmod"] = mode - else: - self.setError (_("False value 'chmod' in template: " ) +\ - templateName) - return (fPrefs, False) - # chown - изменяем владельца и группу - if "chown" in fPrefs: - owner = fPrefs["chown"] - uid = False - gid = False - if ":" in owner: - strUid, strGid = owner.split(":") - import pwd - try: - uid = pwd.getpwnam(strUid)[2] - except: - self.setError (_("Not user in this system: ") + strUid) - self.setError (_("False value 'chown' in template: " )+\ - templateName) - return (fPrefs, False) - try: - import grp - gid = grp.getgrnam(strGid)[2] - except: - self.setError (_("Not group in this system: ")+strGid) - self.setError (_("False value 'chown' in template: " )+\ - templateName) - return (fPrefs, False) - fPrefs["chown"] = [uid, gid] - else: - self.setError (_("False value 'chown' in template: " ) +\ - templateName) - return (fPrefs, False) - # Проверяем path - if "path" in fPrefs and\ - (not fPrefs["path"] or not fPrefs["path"][0] == "/"): - self.setError (_("False value 'path' in template: " )+\ - templateDirFile) - return (fPrefs, False) - # Проверяем name - if "name" in fPrefs and\ - (not fPrefs["name"] or fPrefs["name"][0] == "/"): - self.setError (_("False value 'name' in template: " )+\ - templateDirFile) - return (fPrefs, False) - return (fPrefs, True) - - def __getApplyHeadTemplate(self, newFile, dictPropFile): - """Применяет заголовок к шаблону (права, владелец, и.т. д)""" - # Конфигурационный файл в системе - pathOldFile = dictPropFile["_real_path"] - # Директория в которой находится шаблон - newDir = dictPropFile["path"] - # Файлы в системе к которым были применены шаблоны - applyFiles = [pathOldFile] - pathProg = "" - # В случае force - if "force" in dictPropFile: - if os.path.islink(pathOldFile): - # удаляем ссылку - try: - os.unlink(pathOldFile) - except: - self.setError(_("Can not delete link: " ) +\ - pathOldFile) - return (applyFiles, False) - if os.path.isfile(pathOldFile): - # удаляем файл - try: - os.remove(pathOldFile) - except: - self.setError(_("Can not delete file: " ) +\ - pathOldFile) - return (applyFiles, False) - - # Удаляем оригинальный файл - if dictPropFile["append"] == "remove": - if os.path.islink(pathOldFile): - # удаляем ссылку - try: - os.unlink(pathOldFile) - except: - self.setError(_("Can not delete link: " ) +\ - pathOldFile) - if os.path.isfile(pathOldFile): - # удаляем файл - try: - os.remove(pathOldFile) - except: - self.setError(_("Can not delete file: " ) +\ - pathOldFile) - return (applyFiles, False) - - flagSymlink = False - flagForce = False - # Если есть параметр mirror - if "mirror" in dictPropFile: - if "link" in dictPropFile: - templateFile = dictPropFile['link'] - if not os.path.exists(templateFile): - if os.path.exists(pathOldFile): - os.remove(pathOldFile) - return (applyFiles, False) - elif not os.path.exists(pathOldFile): - return (applyFiles, False) - - # Если есть указатель на файл шаблона (link) - if "link" in dictPropFile and\ - not "symbolic" in dictPropFile: - templateFile = dictPropFile['link'] - foundTemplateFile = os.path.exists(templateFile) - if foundTemplateFile: - FO = self.openNewFile(templateFile) - buff = FO.read() - FO.close() - if os.path.exists(pathOldFile): - os.remove(pathOldFile) - if foundTemplateFile: - if not self.createConfFile(pathOldFile, newDir): - return (applyFiles, False) - FON = open (pathOldFile, "r+") - FON.write(buff) - FON.close() - - # Если символическая ссылка - if "symbolic" in dictPropFile: - prevOldFile = pathOldFile - if "link" in dictPropFile: - pathOldFile = dictPropFile['link'] - flagSymlink = True - if not "/" == pathOldFile[0]: - pathLink = os.path.split(os.path.abspath(prevOldFile))[0] - pathProg = os.getcwd() - os.chdir(pathLink) - - # Флаг - создан конфигурационный файл - flagCreateFile = False - # chmod - изменяем права - if "chmod" in dictPropFile: - mode = dictPropFile['chmod'] - if not os.path.exists(pathOldFile): - if not self.createConfFile(pathOldFile, newDir): - return (applyFiles, False) - flagCreateFile = True - os.chmod(pathOldFile, mode) - - # chown - изменяем владельца и группу - if "chown" in dictPropFile: - uid, gid = dictPropFile['chown'] - if not flagCreateFile and not os.path.exists(pathOldFile): - if not self.createConfFile(pathOldFile, newDir): - return (applyFiles, False) - os.chown(pathOldFile, uid, gid) - - if flagSymlink: - if os.path.exists(prevOldFile) or os.path.islink(prevOldFile): - if os.path.islink(prevOldFile): - # если ссылка то удаляем её - os.unlink(prevOldFile) - else: - # иначе удаляем файл - os.remove(prevOldFile) - if not "/" == pathOldFile[0]: - os.symlink(pathOldFile, prevOldFile) - applyFiles = [prevOldFile,os.path.join(pathLink,pathOldFile)] - else: - os.symlink(pathOldFile, prevOldFile) - applyFiles = [prevOldFile,pathOldFile] - removeLink = not flagSymlink - # Создаем конфигурационный файл если он отсутствует - # открываем файл шаблона и конфигурационный файл - # указатель начала файла шаблона указыввает на текст после заголовка - # файла - if not self.openFiles(newFile, pathOldFile, self.createConfFile, - dictPropFile["_position"], removeLink): - return (applyFiles, False) - if pathProg: - os.chdir(pathProg) - # Если файлы заменяются не нужно их обрабатывать дальше - if "replace" in dictPropFile and\ - not "symbolic" in dictPropFile and\ - "link" in dictPropFile: - return (applyFiles, False) - return (applyFiles, dictPropFile) - - def createNewClass(self, name, bases, attrs={}): - """Создает объект нового класса - - createNewClass(self, name, bases, attrs) - name - имя класса - str, - bases - cписок наследуемых классов - (tuple), - attrs - аттрибуты класса - {dict} - """ - class newMethod: - #Объединяем конфигурации - def join(self, newObj): - if newObj.__class__.__name__ == self.__class__.__name__: - self.docObj.joinDoc(newObj.doc) - # Пост обработка - if 'postXML' in dir(self): - self.postXML() - attrsNew = {} - attrsNew["configName"] = name - if attrs: - for key in attrs.keys(): - attrsNew[key] = attrs[key] - newCl = type(name, bases + (newMethod, object), attrsNew) - return newCl - - def textIsUtf8(self, text): - """Проверяет текст на кодировку UTF-8""" - try: - text.decode("UTF-8") - except: - return False - return True - - def setTemplateRules(self, templateProp, textTemplate, templFile, confFile): - """Устанавливаем значения переменных, условий, функций для текста""" - # Вычисляем условные блоки - textTemplate = self.applyTermsTemplate(textTemplate, - templFile, confFile) - # Заменяем переменные на их значения - textTemplate = self.applyVarsTemplate(textTemplate, - templFile) - # Вычисляем функции - textTemplate = self.applyFuncTemplate(textTemplate, templFile) - return textTemplate - - def join(self, newFile, propFile, ListOptTitle, fileHeadObj): - """Объединения шаблона и конф. файла - - join(newFile, oldFile, ListOptTitle) - Объединение шаблона newFile и конф. файла oldFile, - propFile - словарь свойств конфигурационного файла - ListOptTitle - список строк которые добавятся в заголовок - """ - # Применяем свойства к конфигурационному файлу - # Открываем файл шаблона и конфигурационный файл - - # В случае type=print (печатаем содержимое шаблона) - flagPrintTemplate = False - filesApply, templateProp = self.__getApplyHeadTemplate(newFile,propFile) - if not templateProp: - if self.getError(): - return [] - return filesApply - # Путь к конфигурационному файлу - oldFile = templateProp["_real_path"] - # Формат шаблона - formatTemplate = templateProp["format"] - # Тип объединение шаблона - appendTemplate = templateProp["append"] - if formatTemplate != "bin": - # Применение условий, переменных, функций и переменных заголовка - self.newTemplate = self.setTemplateRules(templateProp, - self.newTemplate, newFile, - oldFile) - else: - # Копируем содержимое шаблона в содержимое конфигурационного файла - self.oldTemplate = self.newTemplate - # Если файл шаблона имеет поддерживаемый формат - if not formatTemplate in ["raw", "bin"]: - # Флаг- кодировка с бинарными примесями у файла шаблона включаем при - # условии текстового файла и кодировки отличной от UTF-8 - flagNotUtf8New = False - # Флаг - кодировка с бинарными примесями у оригинального файла - flagNotUtf8Old = False - # проверяем кодировку шаблона - if not self.textIsUtf8(self.newTemplate): - flagNotUtf8New = True - if not ("link" in templateProp and "symbolic" in templateProp): - # проверяем кодировку оригинального файла - if not self.textIsUtf8(self.oldTemplate): - flagNotUtf8Old = True - # Титл конфигурационного файла - title = "" - if ListOptTitle and "comment" in templateProp: - title = self.getTitle(templateProp["comment"], - ListOptTitle) - title = title.encode("UTF-8") - # Удаляем заголовок Calculate из конфигурационного файла - if "comment" in templateProp: - self.oldTemplate = fileHeadObj.delHeaderConfFile(self.oldTemplate, - templateProp["comment"]) - # Создаем объект в случае параметра format в заголовке - if not formatTemplate in ["raw", "bin"] and\ - appendTemplate in ["replace", "before", "after"]: - # Преобразовываем бинарные файлы - if flagNotUtf8New: - objTxtCoder = utfBin() - self.newTemplate = objTxtCoder.encode(self.newTemplate) - # создаем объект формата шаблона - objTemplNew = self.getFormatObj(formatTemplate, self.newTemplate) - if not objTemplNew: - self.setError (\ - _("Incorrect header parmeter format=%s in template")\ - %formatTemplate + " " + newFile) - return False - - if "xml_" in formatTemplate: - if objTemplNew.getError(): - self.setError (_("False template: " ) + newFile) - return False - nameRootNode = oldFile.rpartition("/")[2].split(".")[0] - objTemplNew.setNameBodyNode(nameRootNode) - # Объект Документ - docObj = objTemplNew.docObj - # Удаление комментариев из документа - docObj.removeComment(docObj.getNodeBody()) - # Добавление необходимых переводов строк - docObj.insertBRtoBody(docObj.getNodeBody()) - # Добавление необходимых разделителей между областями - docObj.insertBeforeSepAreas(docObj.getNodeBody()) - # Пост обработка - if 'postXML' in dir(objTemplNew): - objTemplNew.postXML() - # Получение текстового файла из XML документа - self.newTemplate = objTemplNew.getConfig().encode("UTF-8") - # Если не UTF-8 производим преобразование - if flagNotUtf8New: - self.newTemplate = objTxtCoder.decode(self.newTemplate) - # Титл для объединения - if ListOptTitle: - title = self.getTitle(objTemplNew._comment, - ListOptTitle) - title = title.encode("UTF-8") - # Замена - if appendTemplate == "replace": - if "xml_" in formatTemplate: - data = self.newTemplate.split("\n") - data.insert(1,title) - self.oldTemplate = "\n".join(data) - else: - self.oldTemplate = title + self.newTemplate - self.saveOldFile() - return filesApply - # Впереди - elif appendTemplate == "before": - if "xml_" in formatTemplate: - self.setError (\ - _("False option append=before in template %s") %newFile) - return False - if self.newTemplate: - if self.newTemplate[-1] == "\n": - tmpTemplate = self.newTemplate + self.oldTemplate - else: - tmpTemplate = self.newTemplate + "\n" + self.oldTemplate - else: - tmpTemplate = self.oldTemplate - self.oldTemplate = title + tmpTemplate - self.saveOldFile() - return filesApply - # Cзади - elif appendTemplate == "after": - if "xml_" in formatTemplate: - self.setError (\ - _("False option append=after in template %s") %newFile) - return False - if self.newTemplate: - if self.newTemplate[-1] == "\n": - tmpTemplate = self.oldTemplate + self.newTemplate - else: - tmpTemplate = self.oldTemplate + "\n" + self.newTemplate - else: - tmpTemplate = self.oldTemplate - self.oldTemplate = title + tmpTemplate - self.saveOldFile() - return filesApply - # Объединение - elif appendTemplate == "join": - if flagNotUtf8New: - objTxtCoder = utfBin() - self.newTemplate = objTxtCoder.encode(self.newTemplate) - # создаем объект формата шаблона - objTemplNew = self.getFormatObj(formatTemplate, self.newTemplate) - if not objTemplNew: - self.setError (\ - _("Incorrect header parmeter format=%s in template")\ - %formatTemplate + " " + newFile) - return False - if "xml_" in formatTemplate: - if objTemplNew.getError(): - self.setError (_("False template: " ) + newFile) - return False - nameRootNode = oldFile.rpartition("/")[2].split(".")[0] - objTemplNew.setNameBodyNode(nameRootNode) - # Титл для объединения - if ListOptTitle: - title = self.getTitle(objTemplNew._comment, - ListOptTitle) - title = title.encode("UTF-8") - # В случае пустого конфигурационного файла - reNoClean = re.compile("[^\s]",re.M) - if not self.oldTemplate or\ - not reNoClean.search(self.oldTemplate): - self.oldTemplate = "" - # Удаляем заголовок Calculate из конфигурационного файла - self.oldTemplate = fileHeadObj.delHeaderConfFile(self.oldTemplate, - objTemplNew._comment) - if flagNotUtf8Old: - objTxtCoder = utfBin() - self.oldTemplate = objTxtCoder.encode(self.oldTemplate) - # создаем объект формата шаблона для конфигурационного файла - objTemplOld = self.getFormatObj(formatTemplate, self.oldTemplate) - if not objTemplOld: - self.setError (_("Error in template %s") %oldFile) - return False - if "xml_" in formatTemplate: - if objTemplOld.getError(): - self.setError (_("False template: " ) + oldFile) - return False - nameRootNode = oldFile.rpartition("/")[2].split(".")[0] - objTemplOld.setNameBodyNode(nameRootNode) - - #print "#%s#" %(objTemplOld.docObj.body.toprettyxml()) - #print "#%s#" %(objTemplNew.docObj.body.toprettyxml()) - objTemplOld.join(objTemplNew) - if "xml_" in formatTemplate: - if objTemplOld.getError(): - self.setError (_("False template: " ) + newFile) - return False - data = \ - objTemplOld.getConfig().encode("UTF-8").split("\n") - data.insert(1,title) - self.oldTemplate = "\n".join(data) - else: - self.oldTemplate = title +\ - objTemplOld.getConfig().encode("UTF-8") - # Декодируем если кодировка не UTF-8 - if flagNotUtf8New or flagNotUtf8Old: - self.newTemplate = objTxtCoder.decode(self.newTemplate) - self.oldTemplate = objTxtCoder.decode(self.oldTemplate) - self.saveOldFile() - return filesApply - else: - self.setError (_("False (type append) template: " )+appendTemplate) - return False - -class iniParser(_error): - """Класс для работы с ini файлами - - """ - def __init__(self, iniFile): - # Класс samba - self.samba = getattr(__import__("format.samba", - globals(), locals(), - ["samba"]), "samba") - # название ini файла - self.iniFile = iniFile - # права создаваемого ini-файла - self.mode = 0640 - # Cоответствует ли формат файла нужному - self.checkIni = None - - def setMode(self, mode): - """установка прав создаваемого ini-файла""" - self.mode = mode - - def openIniFile(self): - if not os.access(self.iniFile, os.R_OK): - return "" - FD = open(self.iniFile, "r") - textIni = FD.read() - FD.close() - return textIni - - def writeIniFile(self, txtConfig): - if not os.path.exists(self.iniFile): - fd = os.open(self.iniFile, os.O_CREAT) - os.close(fd) - os.chmod(self.iniFile, self.mode) - if not os.path.exists(self.iniFile): - self.setError(_("Unable to create file") + ": " + self.iniFile) - return False - FD = open(self.iniFile, "r+") - FD.truncate(0) - FD.seek(0) - FD.write(txtConfig) - FD.close() - - def setVar(self, strHeader, dictVar): - """Заменяет или добавляет область и переменные - - Добавляет область в ini-файл или объединяет с существующей - strHeader - имя области - dictVar - словарь переменных - """ - textIni = self.openIniFile() - if not self.checkIniFile(textIni): - return False - # создаем объект типа samba и записываем в него содержимое ini-файла - objIni = self.samba(textIni) - # создаем текст в формате samba из строки заголовка и - # словаря переменных области - txtConfig = objIni.createTxtConfig(strHeader, dictVar) - # создаем объект типа samba и записываем в него текст - objIniAdd = self.samba(txtConfig) - # объединяем объекты для получения результирующего текста - objIni.join(objIniAdd) - # получаем текст - txtConfig = objIni.getConfig().encode("UTF-8") - # записываем его в ini файл - self.writeIniFile(txtConfig) - return True - - def isEmptyFile(self, textIni): - """Является ли файл пустым""" - if not textIni.strip(): - return True - else: - return False - - def checkIniFile(self, textIni): - """Проверка на правильность формата файла""" - if self.checkIni == None: - # Ошибка - if textIni == False: - self.checkIni = False - return False - self.checkIni = True - # В файле есть данные - if not self.isEmptyFile(textIni): - objIni = self.samba(textIni) - xmlBody = objIni.docObj.getNodeBody() - if not xmlBody.firstChild: - self.checkIni = False - return self.checkIni - - def delVar(self, strHeader, nameVar): - """Удаляем переменную из ini файла""" - delNameVar = "!%s" %(nameVar) - dictVar = {delNameVar:"del"} - res = self.setVar(strHeader, dictVar) - return res - - def delArea(self, strHeader): - """Удаляем область из ini файла""" - delStrHeader = "!%s" %(strHeader) - dictVar = {"del":"del"} - res = self.setVar(delStrHeader, dictVar) - return res - - def getVar(self, strHeader, nameVar): - """Получаем значение переменной из ini-файла""" - textIni = self.openIniFile() - if not self.checkIniFile(textIni): - return False - # создаем объект типа samba и записываем в него содержимое ini-файла - objIni = self.samba(textIni) - # получаем ноду body - xmlBody = objIni.docObj.getNodeBody() - # находим в области переменную - res = objIni.docObj.getAreaFieldValues(strHeader, nameVar, xmlBody) - if res == False: - return "" - else: - return res - - def getAreaVars(self,strHeader): - """Получаем все переменнные области из ini-файла""" - textIni = self.openIniFile() - if not self.checkIniFile(textIni): - return False - # создаем объект типа samba и записываем в него содержимое ini-файла - objIni = self.samba(textIni) - # получаем ноду body - xmlBody = objIni.docObj.getNodeBody() - # если находим область то выдаем словарем все переменные иначе False - res = objIni.docObj.getAreaFields(strHeader, xmlBody) - if res == False: - return {} - else: - return res - - def getAllSectionNames(self): - """Получаем все имена секций определенных в ini файле""" - textIni = self.openIniFile() - if not self.checkIniFile(textIni): - return False - # создаем объект типа samba и записываем в него содержимое ini-файла - objIni = self.samba(textIni) - # получаем ноду body - xmlBody = objIni.docObj.getNodeBody() - xmlNodes = objIni.docObj.getFieldsArea(xmlBody) - # Имена секций ini файла - namesSection = [] - for xmlNode in xmlNodes: - if xmlNode.tagName == "area": - nSect = objIni.docObj.getNameArea(xmlNode) - if nSect: - namesSection.append(nSect) - return namesSection diff --git a/build/lib/calculate-lib/pym/cl_utils.py b/build/lib/calculate-lib/pym/cl_utils.py deleted file mode 100644 index 5a29f48..0000000 --- a/build/lib/calculate-lib/pym/cl_utils.py +++ /dev/null @@ -1,214 +0,0 @@ -#-*- 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 subprocess -import string -from random import choice -import os -import types -import stat - - -def _toUNICODE(val): - """перевод текста в юникод""" - if type(val) == types.UnicodeType: - return val - else: - return str(val).decode('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 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) - -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 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 getdirlist(s_path): - """Получить список директорий по указаному пути""" - return filter(lambda x: os.path.isdir(x), os.listdir(s_path)) - -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): - """Установка ошибки""" - if not error in self.error: - self.error.append(error) - return True - -class scan: - """Класс для сканирования директорий""" - class _dir: - """Класс для хранения директорий""" - def __init__(self): - # Базовая директория - self.baseDir = False - # Все директории в базовой включая вложенные - self.dirs = [] - # Все файлы внутри базовой директории - self.files = [] - # Все ссылки внутри базовой директории - self.links = [] - # Все сокеты внутри базовой директории - self.sockets = [] - - - def __scanDir(self, scanDir, dirObj, flagDir=False): - """Сканирование одной директории""" - if flagDir or stat.S_ISDIR(os.stat(scanDir)[stat.ST_MODE]): - for fileOrDir in os.listdir(scanDir): - absPath = os.path.join(scanDir,fileOrDir) - statInfo = os.stat(absPath)[stat.ST_MODE] - if stat.S_ISDIR(statInfo): - dirObj.dirs.append(absPath) - self.__scanDir(absPath, dirObj, True) - elif stat.S_ISLNK(statInfo): - dest = absPath - src = os.readlink(absPath) - dirObj.links.append((src,dest)) - elif stat.S_ISREG(statInfo): - dirObj.files.append(absPath) - elif stat.S_ISSOCK(statInfo): - dirObj.sockets.append(absPath) - return dirObj - - def scanDirs(self, scanDirs): - """Сканирование директорий на вход список - - Выход список объктов _dirProf - """ - dirs = [] - for scanDir in scanDirs: - dirP = scan._dir() - try: - self.__scanDir(scanDir, dirP) - except OSError, e: - print e.strerror, e.filename - return [] - dirP.baseDir = scanDir - dirs.append(dirP) - return dirs \ No newline at end of file diff --git a/build/lib/calculate-lib/pym/cl_vars.py b/build/lib/calculate-lib/pym/cl_vars.py deleted file mode 100644 index 4097326..0000000 --- a/build/lib/calculate-lib/pym/cl_vars.py +++ /dev/null @@ -1,89 +0,0 @@ -#-*- 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"} diff --git a/build/lib/calculate-lib/pym/format/__init__.py b/build/lib/calculate-lib/pym/format/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/build/lib/calculate-lib/pym/format/apache.py b/build/lib/calculate-lib/pym/format/apache.py deleted file mode 100644 index 0b1ffc2..0000000 --- a/build/lib/calculate-lib/pym/format/apache.py +++ /dev/null @@ -1,218 +0,0 @@ -#-*- 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 -from xml import xpath -from cl_template import blocText, xmlDoc -from format.bind import bind - -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 \ No newline at end of file diff --git a/build/lib/calculate-lib/pym/format/bind.py b/build/lib/calculate-lib/pym/format/bind.py deleted file mode 100644 index 7028196..0000000 --- a/build/lib/calculate-lib/pym/format/bind.py +++ /dev/null @@ -1,315 +0,0 @@ -#-*- 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 -from cl_template import objShare, blocText, xmlDoc - -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) diff --git a/build/lib/calculate-lib/pym/format/compiz.py b/build/lib/calculate-lib/pym/format/compiz.py deleted file mode 100644 index 40ae487..0000000 --- a/build/lib/calculate-lib/pym/format/compiz.py +++ /dev/null @@ -1,41 +0,0 @@ -#-*- 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 -from format.samba import samba - -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() diff --git a/build/lib/calculate-lib/pym/format/dhcp.py b/build/lib/calculate-lib/pym/format/dhcp.py deleted file mode 100644 index 4f47666..0000000 --- a/build/lib/calculate-lib/pym/format/dhcp.py +++ /dev/null @@ -1,100 +0,0 @@ -#-*- 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 -from format.bind import bind - -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) diff --git a/build/lib/calculate-lib/pym/format/dovecot.py b/build/lib/calculate-lib/pym/format/dovecot.py deleted file mode 100644 index 5130771..0000000 --- a/build/lib/calculate-lib/pym/format/dovecot.py +++ /dev/null @@ -1,65 +0,0 @@ -#-*- 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 -from xml import xpath -from format.bind import bind - -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() \ No newline at end of file diff --git a/build/lib/calculate-lib/pym/format/kde.py b/build/lib/calculate-lib/pym/format/kde.py deleted file mode 100644 index 5c9b3fd..0000000 --- a/build/lib/calculate-lib/pym/format/kde.py +++ /dev/null @@ -1,160 +0,0 @@ -#-*- 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 -from xml import xpath -from cl_template import xmlDoc -from format.samba import samba - -class kde(samba): - """Класс для обработки конфигурационного файла типа kde - - """ - _comment = "#" - configName = "kde" - configVersion = "0.1" - reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n?",re.M) - reBody = re.compile(".+",re.M|re.S) - reComment = re.compile("^\s*%s.*"%(_comment)) - reSeparator = re.compile("=") - sepFields = "\n" - reSepFields = re.compile(sepFields) - - def __init__(self,text): - samba.__init__(self,text) - - - def _textToXML(self): - """Преобразует текст в XML""" - blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody) - blocs = self.getFullAreas(blTmp) - headers = [] - startHeaders = [] - finHeaders = [] - docObj = xmlDoc() - docObj.createDoc(self.configName, self.configVersion) - rootNode = docObj.getNodeBody() - # Если пустой текст то создаем пустой документ - if not blocs: - return docObj - - for h in blocs[0]: - reH = re.compile("]\s*$") - #listfinH = h.split("]") - listfinH = reH.split(h) - finH = listfinH[0] - if "[" in finH: - startHeaders.append(finH + "]") - else: - startHeaders.append(finH) - if len(listfinH) == 2: - finHeaders.append(listfinH[1]) - else: - finHeaders.append("") - head=finH.replace("][",".").replace("[","").replace("]","").strip() - headers.append(head) - bodys = blocs[1] - - z = 0 - for h in headers: - if not bodys[z]: - z += 1 - continue - areaAction = False - if h: - if h[0] == "!": - docObj.createCaption(h[1:], [startHeaders[z],""]) - areaAction = "drop" - elif h[0] == "-": - docObj.createCaption(h[1:], [startHeaders[z],""]) - areaAction = "replace" - else: - docObj.createCaption(h, [startHeaders[z],""]) - else: - docObj.createCaption(h, [startHeaders[z],""]) - - if "\n" in blocs[0][z]: - if self.reComment.search(finHeaders[z]): - docObj.createField('comment', [finHeaders[z]]) - elif not finHeaders[z].strip() and\ - finHeaders[z].replace("\n",""): - docObj.createField('br', - [finHeaders[z].replace("\n","")]) - else: - docObj.createField('br') - fields = self._splitToFields(bodys[z]) - for f in fields: - if f.name != False and f.value!=False and f.br!=False: - # Обработка условий для samba - if f.name[0] == "!" or f.name[0] == "-" or\ - f.name[0] == "+": - qns = self.removeSymbolTerm(f.br) - xmlField = docObj.createField("var", - [qns], - f.name[1:], [f.value]) - if f.name[0] == "!": - # Удаляемое в дальнейшем поле - docObj.setActionField(xmlField, "drop") - else: - docObj.createField("var",[f.br.replace("\n","")], - f.name, [f.value]) - docObj.createField('br') - elif f.comment != False: - docObj.createField('comment', [f.comment]) - elif f.br != False: - docObj.createField('br', [f.br.replace("\n","")]) - if h.strip(): - area = docObj.createArea() - if areaAction: - docObj.setActionArea(area, areaAction) - rootNode.appendChild(area) - else: - fieldsNodes = docObj.tmpFields.getFields() - for fieldNode in fieldsNodes: - rootNode.appendChild(fieldNode) - docObj.clearTmpFields() - z += 1 - #print docObj.doc.toprettyxml() - return docObj - - def postXML(self): - """Последующая постобработка XML""" - # Для добавления перевода строки между областями если его нет - #print self.docObj.body.toprettyxml() - xmlAreas = xpath.Evaluate("child::area", self.docObj.body) - for xmlArea in xmlAreas: - if xmlArea.previousSibling and\ - self.docObj.getTypeField(xmlArea.previousSibling) == "br": - continue - firstArea = False - xmlFields = xpath.Evaluate("child::field", xmlArea) - if not (xmlFields and\ - (self.docObj.getTypeField(xmlFields[-1]) == "br" or\ - self.docObj.getTypeField(xmlFields[-1]) == "comment")): - if xmlArea.nextSibling: - parentNode = xmlArea.parentNode - nextNode = xmlArea.nextSibling - parentNode.insertBefore(self.docObj.createField("br", - [],"",[], - False,False), - nextNode) - - def join(self, kdeObj): - """Объединяем конфигурации""" - if isinstance(kdeObj, kde): - self.docObj.joinDoc(kdeObj.doc) - self.postXML() - diff --git a/build/lib/calculate-lib/pym/format/ldap.py b/build/lib/calculate-lib/pym/format/ldap.py deleted file mode 100644 index 5df868c..0000000 --- a/build/lib/calculate-lib/pym/format/ldap.py +++ /dev/null @@ -1,183 +0,0 @@ -#-*- 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 -from cl_template import blocText, xmlDoc -from format.samba import samba - -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 diff --git a/build/lib/calculate-lib/pym/format/plasma.py b/build/lib/calculate-lib/pym/format/plasma.py deleted file mode 100644 index d5e9500..0000000 --- a/build/lib/calculate-lib/pym/format/plasma.py +++ /dev/null @@ -1,597 +0,0 @@ -#-*- 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 types -import copy -from xml import xpath -from cl_template import xmlDoc -from format.samba import samba - -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 _textToXML(self): - """Преобразуем текст в XML""" - areas = [] - if self.text.strip(): - self.splitToAllArea(self.text, areas) - #docObj = xmlDoc() - # Создаем новый класс xmlDoc с измененным методом joinArea - newClass = type("newXmlDocPlalma",(xmlDocPlasma,xmlDoc,object),{}) - # Создаем экземпляр нового класса - docObj = newClass() - # Создание объекта документ c пустым разделителем между полями - docObj.createDoc(self.configName, self.configVersion) - if not areas: - return docObj - self.createXML(areas, docObj.getNodeBody(), docObj) - return docObj - - - def postXML(self): - """Последующая постобработка XML""" - # Для добавления перевода строки между областями если его нет - #print self.docObj.body.toprettyxml() - def getQuotesArea(xmlArea): - quotes = [] - xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea) - for node in xmlQuotes: - if node.firstChild: - quotes.append(node.firstChild.nodeValue) - if len(quotes) == 0: - quotes.append("") - quotes.append("") - elif len(quotes) == 1: - quotes.append("") - return quotes - - xmlAreas = xpath.Evaluate("descendant::area", self.docObj.body) - #print "-------------------------------------------------------" - #print xmlAreas - #if xmlAreas: - #prXmlArea = xmlAreas[0] - for xmlArea in xmlAreas: - # Перед пустой областью и после нее удаляем переводы строк - if getQuotesArea(xmlArea) == ["",""]: - #areaTXT = xpath.Evaluate("child::caption/name", xmlArea)[0] - #print "CL_AREA", areaTXT.firstChild - if xmlArea.previousSibling and\ - self.docObj.getTypeField(xmlArea.previousSibling) == "br": - parentNode = xmlArea.previousSibling.parentNode - if xmlArea.previousSibling.previousSibling and\ - self.docObj.getTypeField(xmlArea.previousSibling.previousSibling) == "br": - parentNode.removeChild(\ - xmlArea.previousSibling.previousSibling) - parentNode.removeChild(xmlArea.previousSibling) - if xmlArea.nextSibling and\ - self.docObj.getTypeField(xmlArea.nextSibling) == "br": - parentNode = xmlArea.nextSibling.parentNode - if xmlArea.nextSibling.nextSibling and\ - self.docObj.getTypeField(xmlArea.nextSibling.nextSibling) == "br": - parentNode.removeChild(xmlArea.nextSibling.nextSibling) - parentNode.removeChild(xmlArea.nextSibling) - continue - - # Собираем поля в кучку - xmlChildAreas = xpath.Evaluate("child::area", xmlArea) - if xmlChildAreas: - childNodes = self.docObj.getFieldsArea(xmlArea) - firstChildArea = xmlChildAreas[0] - if firstChildArea.previousSibling and\ - self.docObj.getTypeField(firstChildArea.previousSibling)=="br": - if firstChildArea.previousSibling.previousSibling: - if self.docObj.getTypeField(\ - firstChildArea.previousSibling.previousSibling)=="br": - firstChildArea = firstChildArea.previousSibling - flagFoundArea = False - it = 0 - lenChild = len(childNodes) - for node in childNodes: - it += 1 - if node.tagName == "area": - flagFoundArea = True - continue - if flagFoundArea and node.tagName == "field": - if self.docObj.getTypeField(node) == "var": - xmlArea.insertBefore(node, firstChildArea) - if it < lenChild: - if self.docObj.getTypeField(childNodes[it])==\ - "br": - xmlArea.insertBefore(childNodes[it], - firstChildArea) - - # Добавляем BR если его нет первым полем - xmlFields = xpath.Evaluate("child::field", xmlArea) - if not (xmlFields and\ - (self.docObj.getTypeField(xmlFields[0]) == "br" or\ - self.docObj.getTypeField(xmlFields[0]) == "comment")): - if xmlFields: - xmlArea.insertBefore(self.docObj.createField("br", - [],"",[], - False,False), - xmlFields[0]) - # Если последним полем BR, удаляем его - if xmlFields and self.docObj.getTypeField(xmlFields[-1]) == "br": - #print "DEL_BR", xmlFields[-1].nextSibling - #and\ - if not xmlFields[-1].nextSibling: - xmlArea.removeChild(xmlFields[-1]) - - # Если предыдущим полем не (BR или комментарий) - добавляем BR - if xmlArea.previousSibling and\ - not (self.docObj.getTypeField(xmlArea.previousSibling) == "br" or\ - self.docObj.getTypeField(xmlArea.previousSibling) == "comment"): - parentNode = xmlArea.parentNode - parentNode.insertBefore(self.docObj.createField("br", - [],"",[], - False,False), - xmlArea) - # Если есть предыдущее поле, и поле предыдущеее предыдущему - # не равно BR или комментарий то добавляем BR - if xmlArea.previousSibling: - prPrSibling = xmlArea.previousSibling.previousSibling - if prPrSibling and\ - not (self.docObj.getTypeField(prPrSibling) == "br" or\ - self.docObj.getTypeField(prPrSibling) == "comment"): - parentNode = xmlArea.parentNode - parentNode.insertBefore(self.docObj.createField("br", - [],"",[], - False,False), - xmlArea) - # Если после есть BR а за ним ничего нет, удаляем BR - if xmlArea.nextSibling and\ - self.docObj.getTypeField(xmlArea.nextSibling) == "br": - if not xmlArea.nextSibling.nextSibling: - parentNode = xmlArea.nextSibling.parentNode - parentNode.removeChild(xmlArea.nextSibling) - - #xmlName = xpath.Evaluate("child::caption/name", xmlArea)[0] - #print "------------------------------------" - #print "Name =", xmlName.firstChild - #if xmlArea.previousSibling: - #print "PR_TYPE =", self.docObj.getTypeField(xmlArea.previousSibling) - - - def join(self, kdeObj): - """Объединяем конфигурации""" - if isinstance(kdeObj, plasma): - self.docObj.joinDoc(kdeObj.doc) - self.postXML() - - diff --git a/build/lib/calculate-lib/pym/format/postfix.py b/build/lib/calculate-lib/pym/format/postfix.py deleted file mode 100644 index 4dc2a34..0000000 --- a/build/lib/calculate-lib/pym/format/postfix.py +++ /dev/null @@ -1,117 +0,0 @@ -#-*- 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 -from cl_template import xmlDoc -from format.apache import apache - -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 diff --git a/build/lib/calculate-lib/pym/format/procmail.py b/build/lib/calculate-lib/pym/format/procmail.py deleted file mode 100644 index 50fa05f..0000000 --- a/build/lib/calculate-lib/pym/format/procmail.py +++ /dev/null @@ -1,115 +0,0 @@ -#-*- 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 -from cl_template import objShare, xmlDoc - -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) diff --git a/build/lib/calculate-lib/pym/format/samba.py b/build/lib/calculate-lib/pym/format/samba.py deleted file mode 100644 index 981cc52..0000000 --- a/build/lib/calculate-lib/pym/format/samba.py +++ /dev/null @@ -1,261 +0,0 @@ -#-*- 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 -from xml import xpath -from cl_template import objShare, blocText, xmlDoc - -class samba(objShare): - """Класс для обработки конфигурационного файла типа samba - - """ - _comment = "#" - configName = "samba" - configVersion = "0.1" - reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n",re.M) - reBody = re.compile(".+",re.M|re.S) - reComment = re.compile("\s*%s.*|\s*;.*"%(_comment)) - reSeparator = re.compile("\s*=\s*") - sepFields = "\n" - reSepFields = re.compile(sepFields) - - def __init__(self,text): - self.text = text - self.blocTextObj = blocText() - self._splitToFields = self.splitToFields - # Объект документ - self.docObj = self._textToXML() - # XML документ - self.doc = self.docObj.doc - - def postXML(self): - """Последующая постобработка XML""" - # Для добавления перевода строки между областями если его нет - #print self.docObj.body.toprettyxml() - xmlAreas = xpath.Evaluate("child::area", self.docObj.body) - for xmlArea in xmlAreas: - if xmlArea.previousSibling and\ - self.docObj.getTypeField(xmlArea.previousSibling) == "br": - continue - firstArea = False - xmlFields = xpath.Evaluate("child::field", xmlArea) - if not (xmlFields and\ - (self.docObj.getTypeField(xmlFields[-1]) == "br" or\ - self.docObj.getTypeField(xmlFields[-1]) == "comment")): - if xmlArea.nextSibling: - parentNode = xmlArea.parentNode - nextNode = xmlArea.nextSibling - parentNode.insertBefore(self.docObj.createField("br", - [],"",[], - False,False), - nextNode) - - - def join(self, sambaObj): - """Объединяем конфигурации""" - if isinstance(sambaObj, samba): - self.docObj.joinDoc(sambaObj.doc) - self.postXML() - - def setDataField(self, txtLines, endtxtLines): - """Создаем список объектов с переменными""" - class fieldData: - def __init__(self): - self.name = False - self.value = False - self.comment = False - self.br = False - fields = [] - field = fieldData() - z = 0 - for k in txtLines: - textLine = k + endtxtLines[z] - z += 1 - findComment = self.reComment.search(textLine) - if not textLine.strip(): - field.br = textLine - fields.append(field) - field = fieldData() - elif findComment: - field.comment = textLine - fields.append(field) - field = fieldData() - else: - pars = textLine.strip() - nameValue = self.reSeparator.split(pars) - if len(nameValue) > 2: - valueList = nameValue[1:] - nameValue =[nameValue[0],"=".join(valueList)] - if len(nameValue) == 2: - name = nameValue[0] - value = nameValue[1].replace(self.sepFields,"") - field.name = name.replace(" ","").replace("\t","") - field.value = value - field.br = textLine - fields.append(field) - field = fieldData() - return fields - - - def splitCleanBloc(self, txtBloc): - """Делим блок на две части (переменные, пустые строки в конце)""" - txtLines = txtBloc.split("\n") - firstBloc = [] - nextBloc = [] - txtLines.reverse() - z = 0 - for txtLine in txtLines: - if not txtLine.strip(): - nextBloc.append(txtLine) - else: - break - z += 1 - txtLines.reverse() - firstBloc = txtLines[:-z] - nextBloc.reverse() - if nextBloc: - firstBloc.append("") - if nextBloc and "\n".join(nextBloc): - return ("\n".join(firstBloc), "\n".join(nextBloc)) - else: - return False - - def getFullAreas(self, blocs): - """Делит текст на области, (Заголовок, тело) - - Возвращает два списка: заголовки, тела - """ - headsAreas = [] - bodyAreas = [] - if not blocs: - return [] - lenBlocs = len(blocs[0]) - for i in range(lenBlocs): - txtBloc = blocs[1][i] - clean = self.splitCleanBloc(txtBloc) - if clean: - headsAreas.append(blocs[0][i]) - bodyAreas.append(clean[0]) - headsAreas.append("") - bodyAreas.append(clean[1]) - else: - headsAreas.append(blocs[0][i]) - bodyAreas.append(blocs[1][i]) - return (headsAreas, bodyAreas) - - def createTxtConfig(self, strHeader, dictVar): - """Cоздает область с заголовком - - создает текст конфигурационного файла в формате samba из - заголовка (строка) и словаря переменных - """ - if not strHeader: - return "" - outTxt = "[" + strHeader + "]\n" - for key in dictVar.keys(): - outTxt += "%s = %s\n" %(key,dictVar[key]) - return outTxt - - def _textToXML(self): - """Преобразует текст в XML""" - blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody) - blocs = self.getFullAreas(blTmp) - headers = [] - startHeaders = [] - finHeaders = [] - docObj = xmlDoc() - docObj.createDoc(self.configName, self.configVersion) - rootNode = docObj.getNodeBody() - # Если пустой текст то создаем пустой документ - if not blocs: - return docObj - - for h in blocs[0]: - listfinH = h.split("]") - finH = listfinH[0] - if "[" in finH: - startHeaders.append(finH + "]") - else: - startHeaders.append(finH) - if len(listfinH) == 2: - finHeaders.append(listfinH[1]) - else: - finHeaders.append("") - headers.append(finH.replace("[","").replace("]","").strip()) - bodys = blocs[1] - - z = 0 - for h in headers: - if not bodys[z]: - z += 1 - continue - areaAction = False - if h: - if h[0] == "!": - docObj.createCaption(h[1:], [startHeaders[z],""]) - areaAction = "drop" - elif h[0] == "-": - docObj.createCaption(h[1:], [startHeaders[z],""]) - areaAction = "replace" - else: - docObj.createCaption(h, [startHeaders[z],""]) - else: - docObj.createCaption(h, [startHeaders[z],""]) - - if "\n" in blocs[0][z]: - if self.reComment.search(finHeaders[z]): - docObj.createField('comment', [finHeaders[z]]) - elif not finHeaders[z].strip() and\ - finHeaders[z].replace("\n",""): - docObj.createField('br', - [finHeaders[z].replace("\n","")]) - else: - docObj.createField('br') - fields = self._splitToFields(bodys[z]) - for f in fields: - if f.name != False and f.value!=False and f.br!=False: - # Обработка условий для samba - if f.name[0] == "!" or f.name[0] == "-" or\ - f.name[0] == "+": - qns = self.removeSymbolTerm(f.br) - xmlField = docObj.createField("var", - [qns], - f.name[1:], [f.value]) - if f.name[0] == "!": - # Удаляемое в дальнейшем поле - docObj.setActionField(xmlField, "drop") - else: - docObj.createField("var",[f.br.replace("\n","")], - f.name, [f.value]) - docObj.createField('br') - elif f.comment != False: - docObj.createField('comment', [f.comment]) - elif f.br != False: - docObj.createField('br', [f.br.replace("\n","")]) - if h.strip(): - area = docObj.createArea() - if areaAction: - docObj.setActionArea(area, areaAction) - rootNode.appendChild(area) - else: - fieldsNodes = docObj.tmpFields.getFields() - for fieldNode in fieldsNodes: - rootNode.appendChild(fieldNode) - docObj.clearTmpFields() - z += 1 - #print docObj.doc.toprettyxml() - return docObj - diff --git a/build/lib/calculate-lib/pym/format/squid.py b/build/lib/calculate-lib/pym/format/squid.py deleted file mode 100644 index fba8153..0000000 --- a/build/lib/calculate-lib/pym/format/squid.py +++ /dev/null @@ -1,86 +0,0 @@ -#-*- 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 -from format.procmail import procmail - -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) diff --git a/build/lib/calculate-lib/pym/format/xml_gconf.py b/build/lib/calculate-lib/pym/format/xml_gconf.py deleted file mode 100644 index 84894bd..0000000 --- a/build/lib/calculate-lib/pym/format/xml_gconf.py +++ /dev/null @@ -1,262 +0,0 @@ -#-*- 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 time -from xml import xpath -import xml.dom.minidom -from format.xml_xfce import xml_xfce -# Перевод cообщений модуля -from cl_lang import lang -tr = lang() -tr.setLocalDomain('cl_lib') -tr.setLanguage(sys.modules[__name__]) - - -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 template is XML")) - return False - self.rootNode = self.doc.documentElement - self.bodyNode = self.rootNode - return self.doc - - def cmpListsNodesEntry(self, listXmlA, listXmlB): - """Сравнение содержимого двух списков XML нод""" - getTextsNodes = lambda y: map(lambda x:\ - x.toxml().replace(" ","").replace("\t","").replace("\n",""), - map(lambda x: x.removeAttribute("mtime") or x, - map(lambda x: x.cloneNode(True), - filter(lambda x: x.nodeType==x.ELEMENT_NODE, y)))) - if set(getTextsNodes(listXmlA))==set(getTextsNodes(listXmlB)): - return True - return False - - def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True, levelNumber=0): - """Объединение корневой ноды шаблона и корневой ноды файла""" - if levelNumber>1: - return True - xmlNode = xmlNewNode - childNodes = xmlNode.childNodes - nextOldNode = xmlOldNode - flagError = False - if xmlNode.nodeType == xmlNode.ELEMENT_NODE: - n = xmlNode - tagName = n.tagName - nAction = u'' - nName = u'' - nType = u'' - nValue = u'' - attrName = '' - attrType = '' - if flagRootNode: - if not tagName == "gconf": - self.setError(_("The text is not a valid gconf-XML format \ -(not found '...')")) - return False - else: - if not tagName == "entry": - self.setError(_("The text is not a valid gconf-XML format \ -(found '<%s>..'")%(tagName,tagName)) - return False - if not n.hasAttribute("name"): - self.setError(_('Not found arrtibute "name" in tag entry')) - return False - if not n.hasAttribute("type"): - self.setError(_('Not found arrtibute "type" in tag entry')) - return False - nName = n.getAttribute("name") - attrName = u"attribute::name='%s'"%nName - nType = n.getAttribute("type") - # Проверка правильности аттрибута type - if not nType in self.supportEntryTypes: - self.setError(\ - _('Incorrect arrtibute "type" - ')%nType) - return False - attrType = u"attribute::type='%s'"%nType - if n.hasAttribute("value"): - nValue = n.getAttribute("value") - if n.hasAttribute("action"): - nAction = n.getAttribute("action") - if not nAction in ("join","replace","drop"): - textError = _('''In the text, XML template, look \ -for a reserved attribute 'action' with the incorrect value.\n\ -Valid values attribute 'action': \ -(action="join", action="replace", action="drop")''') - self.setError(textError) - return False - if xmlOldNode.parentNode: - findStr = u"child::%s"%tagName - strAttr = [attrName, attrType] - findAttr = filter(lambda x: x, strAttr) - findAttrStr = '' - if findAttr: - strAttr = u' and '.join(findAttr) - findAttrStr = "[%s]"%strAttr - findPath = u"child::%s%s"%(tagName,findAttrStr) - # Рабочая нода - if flagRootNode: - workNode = xmlOldNode.parentNode - else: - workNode = xmlOldNode - oldNodes = xpath.Evaluate(findPath, workNode) - # Новая нода список - flagArray = False - if nType == "list" or nType == "pair": - flagArray = True - flagDrop = False - flagJoin = True - flagReplace = False - if nType=="string" or nAction=="replace": - flagJoin = False - flagReplace = True - elif nAction == "drop": - flagJoin = False - flagDrop = True - if flagRootNode: - textError = _('Incorrect action="drop" in root node') - self.setError(textError) - return False - if oldNodes: - if len(oldNodes)>1: - textError = _("The uncertainty in this template are \ -the same nodes at one level") - self.setError(textError) - return False - nextOldNode = oldNodes[0] - # Замещаем ноду в случае массива - if flagArray and not flagDrop: - replaceXmlNode = xmlNode.cloneNode(True) - # Сравнение содержимого нод - if not self.cmpListsNodesEntry([replaceXmlNode], - [nextOldNode]): - replaceXmlNode.setAttribute("mtime", - self.currentTime) - if nAction: - replaceXmlNode.removeAttribute("action") - workNode.replaceChild(replaceXmlNode, - nextOldNode) - flagJoin = False - flagReplace = False - childNodes = False - # Объединение нод - if flagJoin: - if nextOldNode.hasAttribute("value"): - oValue = nextOldNode.getAttribute("value") - if nValue != oValue: - nextOldNode.setAttribute("mtime", - self.currentTime) - nextOldNode.setAttribute("value",nValue) - # Замещение ноды - elif flagReplace: - replaceXmlNode = xmlNode.cloneNode(True) - # Сравнение содержимого нод - if not self.cmpListsNodesEntry([replaceXmlNode], - [nextOldNode]): - replaceXmlNode.setAttribute("mtime", - self.currentTime) - if not\ - self._removeDropNodesAndAttrAction(\ - replaceXmlNode): - return False - workNode.replaceChild(replaceXmlNode, - nextOldNode) - childNodes = False - # Удаление ноды - elif flagDrop: - workNode.removeChild(nextOldNode) - childNodes = False - else: - # Добавление ноды - childNodes = False - if not flagDrop: - appendXmlNode = xmlNode.cloneNode(True) - appendXmlNode.setAttribute("mtime", self.currentTime) - if not\ - self._removeDropNodesAndAttrAction(appendXmlNode): - return False - workNode.appendChild(appendXmlNode) - if childNodes: - for node in childNodes: - levelNumber +=1 - if not self._join(node, nextOldNode, False, levelNumber): - flagError = True - break - levelNumber -= 1 - if flagError: - return False - return True - - def join(self, xml_gconfObj): - """Объединяем конфигурации""" - # Получаем текущее время - self.currentTime = self.getCurrentTime() - if isinstance(xml_gconfObj, xml_gconf): - try: - self.joinDoc(xml_gconfObj.doc) - except: - self.setError(_("Can not join template")) - return False - return True - - def getConfig(self): - """Получение текстового файла из XML документа""" - data = self.doc.toprettyxml().split("\n") - data = filter(lambda x: x.strip(), data) - return "\n".join(data).replace("\t"," ") diff --git a/build/lib/calculate-lib/pym/format/xml_xfce.py b/build/lib/calculate-lib/pym/format/xml_xfce.py deleted file mode 100644 index 9acc947..0000000 --- a/build/lib/calculate-lib/pym/format/xml_xfce.py +++ /dev/null @@ -1,268 +0,0 @@ -#-*- 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 -from xml import xpath -import xml.dom.minidom -from cl_utils import _error -# Перевод cообщений модуля -from cl_lang import lang -tr = lang() -tr.setLocalDomain('cl_lib') -tr.setLanguage(sys.modules[__name__]) - -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 template 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 template")) - 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 template, 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 template, look \ -for a reserved attribute 'action' with the incorrect value.\n\ -Valid values attribute 'action': \ -(action="join", action="replace", action="drop")''') - self.setError(textError) - return False - if xmlOldNode.parentNode: - findStr = u"child::%s"%path - strAttr = [attrName, attrType] - findAttr = filter(lambda x: x, strAttr) - findAttrStr = '' - if findAttr: - strAttr = u' and '.join(findAttr) - findAttrStr = "[%s]"%strAttr - findPath = u"child::%s%s"%(path,findAttrStr) - # Рабочая нода - if flagRootNode: - workNode = xmlOldNode.parentNode - else: - workNode = xmlOldNode - oldNodes = xpath.Evaluate(findPath, workNode) - #print findPath - #print workNode - #print "----------------------------" - # Новая нода список - flagArray = False - if nType == "array": - flagArray = True - flagDrop = False - flagJoin = True - flagReplace = False - if nAction == "replace": - flagJoin = False - flagReplace = True - elif nAction == "drop": - flagJoin = False - flagDrop = True - if flagRootNode: - textError = _('Incorrect action="drop" in root node') - self.setError(textError) - return False - if oldNodes: - if len(oldNodes)>1: - textError = _("The uncertainty in this template 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 template 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") diff --git a/build/lib/calculate-lib/pym/format/xml_xfcepanel.py b/build/lib/calculate-lib/pym/format/xml_xfcepanel.py deleted file mode 100644 index 4e9eb06..0000000 --- a/build/lib/calculate-lib/pym/format/xml_xfcepanel.py +++ /dev/null @@ -1,199 +0,0 @@ -#-*- 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 -from xml import xpath -import xml.dom.minidom -from format.xml_xfce import xml_xfce - -# Перевод cообщений модуля -from cl_lang import lang -tr = lang() -tr.setLocalDomain('cl_lib') -tr.setLanguage(sys.modules[__name__]) - -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: - findStr = u"child::%s"%path - findAttrStr = "" - if attrName: - findAttrStr = "[%s]"%attrName - findPath = u"child::%s%s"%(path,findAttrStr) - # Рабочая нода - if flagRootNode: - workNode = xmlOldNode.parentNode - else: - workNode = xmlOldNode - oldNodes = xpath.Evaluate(findPath, workNode) - flagDrop = False - flagJoin = True - flagReplace = False - flagAppend = False - if nAction == "replace": - flagJoin = False - flagReplace = True - elif nAction == "drop": - flagJoin = False - flagDrop = True - if flagRootNode: - textError = _('Incorrect action="drop" in root node') - self.setError(textError) - return False - if path == "panel": - flagJoin = False - if levelNumber in self.panelNumbers.keys(): - self.panelNumbers[levelNumber] += 1 - else: - self.panelNumbers[levelNumber] = 0 - if oldNodes: - if len(oldNodes)>1 and path != "panel": - textError = _("The uncertainty in this profile are \ -the same nodes at one level") - self.setError(textError) - return False - if path == "panel": - if len(oldNodes)<=self.panelNumbers[levelNumber]: - nextOldNode = oldNodes[-1] - # Добавляем ноду - if not flagDrop: - flagAppend = True - flagReplace = False - childNodes = False - else: - nextOldNode=oldNodes[self.panelNumbers[levelNumber]] - else: - nextOldNode = oldNodes[0] - # Замещаем ноду в случае массива - if flagArray and not flagDrop: - replaceXmlNode = xmlNode.cloneNode(True) - if nAction: - replaceXmlNode.removeAttribute("action") - workNode.replaceChild(replaceXmlNode, - nextOldNode) - flagJoin = False - flagReplace = False - childNodes = False - # Объединение нод - if flagJoin: - if nextOldNode.hasAttribute("value"): - oValue = nextOldNode.getAttribute("value") - if nValue != oValue: - nextOldNode.setAttribute("value",nValue) - # Замещение ноды - elif flagReplace: - replaceXmlNode = xmlNode.cloneNode(True) - if not\ - self._removeDropNodesAndAttrAction(replaceXmlNode): - return False - workNode.replaceChild(replaceXmlNode, - nextOldNode) - childNodes = False - # Удаление ноды - elif flagDrop: - workNode.removeChild(nextOldNode) - childNodes = False - else: - flagAppend = True - flagDrop = False - if flagAppend and not flagDrop: - # Добавление ноды - childNodes = False - if not flagDrop: - appendXmlNode = xmlNode.cloneNode(True) - if not\ - self._removeDropNodesAndAttrAction(appendXmlNode): - return False - workNode.appendChild(appendXmlNode) - if childNodes: - for node in childNodes: - levelNumber +=1 - if not self._join(node, nextOldNode, False, levelNumber): - flagError = True - break - levelNumber -= 1 - if flagError: - return False - return True - - def join(self, xml_xfceObj): - """Объединяем конфигурации""" - if isinstance(xml_xfceObj, xml_xfcepanel): - try: - self.joinDoc(xml_xfceObj.doc) - except: - self.setError(_("Can not join profile")) - return False - return True From 308a281c7d289cc5b49d32613f74167b2ba3de42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B0=D0=BC=D0=BE=D1=83=D0=BA=D0=B8=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9?= Date: Mon, 1 Feb 2010 16:46:15 +0300 Subject: [PATCH 4/7] Created class templateFunction for storing template functions --- pym/cl_template.py | 718 ++++++++++++++++++++++++--------------------- 1 file changed, 384 insertions(+), 334 deletions(-) diff --git a/pym/cl_template.py b/pym/cl_template.py index 68f0c0f..46ee7a8 100644 --- a/pym/cl_template.py +++ b/pym/cl_template.py @@ -2080,7 +2080,367 @@ class utfBin: resS = reVar.search(textTemplateTmp) return textTemplateTmp -class template(_file, _terms, xmlShare): +class _shareTemplate: + """Общие аттрибуты для классов шаблонов""" + # Метка начала переменной + varStart = "#-" + # Метка конца переменной + varEnd = "-#" + _deltVarStart = len(varStart) + _deltVarEnd = len(varEnd) + +class templateFunction(_shareTemplate): + """Класс для функций шаблонов""" + # Список названий функций шаблона + namesTemplateFunction = [] + # Словарь {название функции шаблона: функция шаблона, ...} + templateFunction = {} + # Имена установленных программ + installProg = [] + # Версии установленных программ + installProgVersions = [] + # кеш вызванных значений программа, номер версии + cacheInstallProg = {} + # Регулярное выражение для сложения + sNum = re.compile("\-[^\-\+]+|[^\-\+]+") + # Регулярное выражение для умножениея и деления + sMD = re.compile("[^\-\+\*\/]+") + # Имя обрабатываемого шаблона + nameTemplate = "" + + def __init__(self, objVar): + # Если не определен словарь функций шаблона + #print "dict", templateFunction.__dict__.items() + if not self.templateFunction: + # префикс функций шаблона + pref = "func" + # cписок [(название функции, функция), ...] + dictFunc = filter(lambda x: x[0].startswith(pref) and\ + hasattr(x[1],"__call__"), + self.__class__.__dict__.items()) + # удаляем у названия функции префикс и переводим остаток названия + # в нижний регистр + dictFunc = map(lambda x: (x[0][len(pref):].lower(), x[1]), dictFunc) + # Формируем словарь функций шаблона + self.templateFunction.update(dictFunc) + # Формируем список функций шаблона + for nameFunction in self.templateFunction.keys(): + self.namesTemplateFunction.append(nameFunction) + # Объект хранения переменных + self.objVar = objVar + self._reFunc = re.compile(("%s[a-zA-Z0-9_\-\+\(\)\, \*\/\.]+%s")\ + %(self.varStart,self.varEnd),re.M) + + def equalTerm(self, term, localVars): + """Метод для вычисления выражения""" + terms = self.sNum.findall(term) + if terms: + strNumers = [] + for n in terms: + strNum = n.strip() + if "*" in strNum or "/" in strNum: + strNum = self.multAndDiv(strNum,localVars) + try: + num = int(strNum) + except: + minus = False + if strNum[:1] == "-": + minus = True + strNum = strNum[1:] + if localVars.has_key(strNum): + num = localVars[strNum] + elif self.objVar.exists(strNum): + try: + num = int(self.objVar.Get(strNum)) + except: + print _("error in template %s")%self.nameTemplate + print _("error var %s not int")%str(strNum) + exit(1) + else: + print _("error in template %s")%self.nameTemplate + print _("error local var %s not defined")\ + %str(strNum) + exit(1) + if minus: + num =-num + strNumers.append(num) + return sum(strNumers) + print _("error in template %s")%self.nameTemplate + print _("error template term %s, incorrect data")%str(term) + exit(1) + + def multAndDiv(self, term, localVars): + """Метод для умножения и деления""" + termTmp = term + varsLocal = self.sMD.findall(term) + for var in varsLocal: + flagVarTxt = True + try: + int(var) + except: + flagVarTxt = False + if flagVarTxt: + continue + varReplace = str(self.equalTerm(var, localVars)) + termTmp = termTmp.replace(var,varReplace) + ret = eval(termTmp) + return ret + + def funcSum(self, funTxt, resS, localVars, textTemplateTmp): + """Функция шаблона, вычисляет функцию sum()""" + terms = funTxt.replace(" ","").split(",") + # Название локальной переменной + nameLocVar = terms[0] + if not localVars.has_key(nameLocVar): + localVars[nameLocVar] = 0 + if len(terms) == 2: + if terms[1].strip(): + localVars[nameLocVar] = self.equalTerm(terms[1], localVars) + replace = str(localVars[nameLocVar]) + else: + replace = "" + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + elif len(terms) == 3: + if terms[1].strip(): + replaceInt = self.equalTerm(terms[1], localVars) + replace = str(replaceInt) + else: + replace = "" + localVars[nameLocVar] = self.equalTerm(terms[2], localVars) + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + else: + print _("error in template %s")%self.nameTemplate + print _("error template term %s")%str(funTxt) + exit(1) + return textTemplateTmp + + def funcLoad(self, funTxt, resS, localVars, textTemplateTmp): + """Функция шаблона load(), + + если файл существует читает из файла локальную переменную + если один параметр - выводит значение локальной переменной + """ + terms = funTxt.replace(" ","").split(",") + if not terms[0].strip() or\ + (len(terms)==2 and not terms[1].strip()) or\ + len(terms)>2: + print _("error in template %s")%self.nameTemplate + print _("error template term %s")%str(funTxt) + exit(1) + if len(terms) == 2: + if not terms[0] in ["ver","num","char","key"]: + print _("error in template %s")%self.nameTemplate + print _("error template term %s")%str(funTxt) + print _("first argument function is not 'ver' or 'num' or\ +'char'") + exit(1) + if len(terms) == 1: + fileName = terms[0].strip() + if fileName[0] != "/": + print _("error in template %s")%self.nameTemplate + print _("error template term %s")%str(funTxt) + print _("incorrect path %s")%fileName + exit(1) + else: + fileName = terms[1].strip() + if fileName[0] != "/": + print _("error in template %s")%self.nameTemplate + print _("error template term %s")%str(funTxt) + print _("incorrect path %s")%fileName + exit(1) + replace = "" + if os.path.exists(fileName): + FD = open(fileName) + replace = FD.read().strip() + FD.close + if not replace and len(terms) == 2 and terms[0] in ["ver","num"]: + replace = "0" + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + return textTemplateTmp + + def getInstallPkgGentoo(self, names = [], versions = []): + """Выдает два списка, инсталлированные программы и номера версий""" + baseDir = "/var/db/pkg" + pkgs = [] + reVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*") + def getFilesDir(pkgs, dirname, names): + for nameFile in names: + absNameFile = os.path.join(dirname,nameFile) + if os.path.isdir(absNameFile): + tail = absNameFile.split(baseDir) + if len(tail)==2: + tail = tail[1].split('/') + if len(tail)==3 and tail[1]!='virtual': + pkgs.append(tail[2]) + return True + os.path.walk(baseDir,getFilesDir, pkgs) + pkgs.sort() + for pkg in pkgs: + findVer = reVer.search(pkg) + if findVer: + ver = findVer.group() + versions.append(ver) + names.append(pkg.split(ver)[0][:-1]) + #return pkgs + return names, versions + + def pkg(self, nameProg, names, versions): + """Выдает установленные версии по имени программы""" + # Значение версии из кеша + if nameProg in self.cacheInstallProg: + return self.cacheInstallProg[nameProg] + i = 0 + vers = [] + for name in names: + if nameProg == name: + while nameProg == names[i]: + vers.append(versions[i]) + i += 1 + break + i += 1 + if vers: + version = vers[-1] + # Запись значения версии в кеш + self.cacheInstallProg[nameProg] = version + return version + else: + return "" + + def funcPkg(self, funTxt, resS, localVars, textTemplateTmp): + """Функция шаблона pkg(), выдает номер версии программы""" + terms = funTxt.replace(" ","") + # Название программы + nameProg = terms + if not self.installProg: + # Получение всех названий и версий установленных программ + self.installProg,self.installProgVersions =\ + self.getInstallPkgGentoo(names=self.installProg, + versions=self.installProgVersions) + replace = self.pkg(nameProg,self.installProg,self.installProgVersions) + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + return textTemplateTmp + + def funcRnd(self, funTxt, resS, localVars, textTemplateTmp): + """Функция шаблона rnd(), выдает строку случайных символов + + первый аргумент: + 'num' - числа, + 'pas' - цифры и буквы + второй аргумент: + количество символов + """ + terms = funTxt.replace(" ","").split(",") + if not terms[0].strip() or\ + (len(terms)==2 and not terms[1].strip()) or\ + len(terms)!=2: + print _("error in template %s")%self.nameTemplate + print _("error template term %s")%str(funTxt) + exit(1) + fArgvNames = ['num','pas'] + if not terms[0] in fArgvNames: + print _("error in template %s")%self.nameTemplate + print _("error template term %s")%str(funTxt) + print _("first argument function is not 'num' or 'pas'") + exit(1) + try: + lenStr = int(terms[1]) + except: + print _("error in template %s")%self.nameTemplate + print _("error template term %s")%str(funTxt) + print _("two argument function is not number") + exit(1) + if terms[0] == fArgvNames[0]: + replace=''.join([random.choice(string.digits)\ + for i in xrange(lenStr)]) + elif terms[0] == fArgvNames[1]: + replace=''.join([random.choice(string.ascii_letters + \ + string.digits) for i in xrange(lenStr)]) + else: + print _("error in template %s")%self.nameTemplate + print _("error template term %s")%str(funTxt) + exit(1) + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + return textTemplateTmp + + def funcCase(self, funTxt, resS, localVars, textTemplateTmp): + """Функция шаблона case(), выдает переменную в определенном регистре + + первый аргумент: + 'upper' - верхний регистр, + 'lower' - нижний регистр, + 'capitalize' - первая буква в верхнем регистре + второй аргумент: + название переменной + """ + terms = funTxt.replace(" ","").split(",") + if not terms[0].strip() or\ + (len(terms)==2 and not terms[1].strip()) or len(terms)!=2: + print _("error in template %s")%self.nameTemplate + print _("error template term %s")%str(funTxt) + exit(1) + fArgvNames = ['upper','lower','capitalize'] + if not terms[0] in fArgvNames: + print _("error in template %s")%self.nameTemplate + print _("error template term %s")%str(funTxt) + print _("first argument function is not 'upper' or 'lower' or\ +'capitalize'") + exit(1) + try: + strValue = str(self.objVar.Get(terms[1])) + except: + print _("error in template %s")%self.nameTemplate + print _("error var %s not found")%str(terms[1]) + exit(1) + replace = "" + strValue = _toUNICODE(strValue) + if terms[0] == 'upper': + replace = strValue.upper() + elif terms[0] == 'lower': + replace = strValue.lower() + elif terms[0] == 'capitalize': + replace = strValue.capitalize() + if replace: + replace = replace.encode("UTF-8") + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + return textTemplateTmp + + def applyFuncTemplate(self, textTemplate, nameTemplate): + """Применяет функции к тексту шаблона""" + # Локальные переменные + localVars = {} + # Имя обрабатываемого шаблона + self.nameTemplate = nameTemplate + # Регулярное выражение для поиска функции в шаблоне + reFunc = self._reFunc + resS = reFunc.search(textTemplate) + textTemplateTmp = textTemplate + while resS: + mark = textTemplateTmp[resS.start():resS.end()] + funTxt = mark[self._deltVarStart:-self._deltVarEnd] + funcName, spl, funcEnd = funTxt.partition("(") + if funcName in self.namesTemplateFunction: + # аргументы функции - '(' аргументы ')' + funArgv = funcEnd.rpartition(")")[0] + # вызов функции шаблона + textTemplateTmp = self.templateFunction[funcName](self, funArgv, + resS, localVars, + textTemplateTmp) + resS = reFunc.search(textTemplateTmp) + else: + print _("error in template %s")%self.nameTemplate + print _("error template term %s")%str(funTxt) + print _("can not found template function '%s'")%funTxt + exit(1) + return textTemplateTmp + + +class template(_file, _terms, xmlShare, _shareTemplate): """Класс для работы с шаблонами На вход 2 параметра: объект хранения переменных, имя сервиса - не @@ -2089,12 +2449,7 @@ class template(_file, _terms, xmlShare): """ # Импортированные классы поддерживаемых форматов шаблонов importFormats = {} - # Имена установленных программ - installProg = [] - # Версии установленных программ - installProgVersions = [] - # кеш вызванных значений программа, номер версии - cacheInstallProg = {} + # Название файла шаблона директории templDirNameFile = ".calculate_directory" @@ -2112,15 +2467,8 @@ class template(_file, _terms, xmlShare): ----------------------------------------" self._titleBody = "" self._titleList = (_("Modified"), _("File of a template")) - - # Метки - varStart = "#-" - varEnd = "-#" - self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")%(varStart,varEnd),re.M) - self._reFunc = re.compile(("%s[a-zA-Z0-9_\-\+\(\)\, \*\/\.]+%s")\ - %(varStart,varEnd),re.M) - self._deltVarStart = len(varStart) - self._deltVarEnd = len(varEnd) + self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")\ + %(self.varStart,self.varEnd),re.M) # Условия self._reTermBloc = re.compile("#\?(?P[a-zA-Z0-9\-_]+)\ (?P\([a-zA-Z0-9_\-\+\,\*\/\.]+\))?\ @@ -2130,11 +2478,15 @@ class template(_file, _terms, xmlShare): # Объект с переменными self.objVar = objVar # Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д - baseDir = self.objVar.Get("cl_root_path") - #self._baseDir = os.path.split(baseDir)[0] - self._baseDir = baseDir + # По умолчанию / + self._baseDir = self.objVar.Get("cl_root_path") if self._baseDir == "/": self._baseDir = "" + # Объект функций шаблона + self.functObj = templateFunction(self.objVar) + # Метод применения функций к шаблонам + self.applyFuncTemplate = self.functObj.applyFuncTemplate + def __octToInt(self, strOct): """Преобразование восьмеричного в целое (ввод строка, вывод число)""" @@ -2312,321 +2664,6 @@ class template(_file, _terms, xmlShare): return textTemplateTmp - def applyFuncTemplate(self, textTemplate, nameTemplate): - """ Применяет функции к тексту шаблона - """ - def equalTerm(term, sNum, sMD, localVars): - """Локальная функция для вычисления выражения""" - terms = sNum.findall(term) - if terms: - strNumers = [] - for n in terms: - strNum = n.strip() - if "*" in strNum or "/" in strNum: - strNum = multAndDiv(strNum,sNum,sMD,localVars) - try: - num = int(strNum) - except: - minus = False - if strNum[:1] == "-": - minus = True - strNum = strNum[1:] - if localVars.has_key(strNum): - num = localVars[strNum] - elif self.objVar.exists(strNum): - try: - num = int(self.objVar.Get(strNum)) - except: - print _("error in template %s")%nameTemplate - print _("error var %s not int")%str(strNum) - exit(1) - else: - print _("error in template %s")%nameTemplate - print _("error local var %s not defined")\ - %str(strNum) - exit(1) - if minus: - num =-num - strNumers.append(num) - return sum(strNumers) - print _("error in template %s")%nameTemplate - print _("error template term %s, incorrect data")%str(term) - exit(1) - - def multAndDiv(term,sNum,sMD,localVars): - """локальная функция для умножения и деления""" - termTmp = term - varsLocal = sMD.findall(term) - for var in varsLocal: - flagVarTxt = True - try: - int(var) - except: - flagVarTxt = False - if flagVarTxt: - continue - varReplace = str(equalTerm(var,sNum,sMD,localVars)) - termTmp = termTmp.replace(var,varReplace) - ret = eval(termTmp) - return ret - - def funcSum(funTxt,resS,localVars,textTemplateTmp): - """локальная функция вычисляет первую функцию sum() в шаблоне""" - terms = funTxt[4:-1].replace(" ","").split(",") - # Название локальной переменной - nameLocVar = terms[0] - if not localVars.has_key(nameLocVar): - localVars[nameLocVar] = 0 - if len(terms) == 2: - if terms[1].strip(): - localVars[nameLocVar] = equalTerm(terms[1],sNum,sMD, - localVars) - replace = str(localVars[nameLocVar]) - else: - replace = "" - textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ - textTemplateTmp[resS.end():] - elif len(terms) == 3: - if terms[1].strip(): - replaceInt = equalTerm(terms[1],sNum,sMD,localVars) - replace = str(replaceInt) - else: - replace = "" - localVars[nameLocVar] = equalTerm(terms[2], - sNum,sMD,localVars) - textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ - textTemplateTmp[resS.end():] - else: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - exit(1) - return textTemplateTmp - - def funcLoad(funTxt,resS,textTemplateTmp): - """если файл существует читает из файла локальную переменную - - если один параметр - выводит значение локальной переменной - """ - terms = funTxt[5:-1].replace(" ","").split(",") - if not terms[0].strip() or\ - (len(terms)==2 and not terms[1].strip()) or\ - len(terms)>2: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - exit(1) - if len(terms) == 2: - if not terms[0] in ["ver","num","char","key"]: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - print _("first argument function is not 'ver' or 'num' or\ - 'char'") - exit(1) - if len(terms) == 1: - fileName = terms[0].strip() - if fileName[0] != "/": - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - print _("incorrect path %s")%fileName - exit(1) - else: - fileName = terms[1].strip() - if fileName[0] != "/": - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - print _("incorrect path %s")%fileName - exit(1) - replace = "" - if os.path.exists(fileName): - FD = open(fileName) - replace = FD.read().strip() - FD.close - if not replace and len(terms) == 2 and terms[0] in ["ver","num"]: - replace = "0" - textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ - textTemplateTmp[resS.end():] - return textTemplateTmp - - def getInstallPkgGentoo(names = [], versions = []): - """Выдает два списка, инсталлированные программы и номера версий""" - baseDir = "/var/db/pkg" - pkgs = [] - reVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*") - def getFilesDir(pkgs, dirname, names): - for nameFile in names: - absNameFile = os.path.join(dirname,nameFile) - if os.path.isdir(absNameFile): - tail = absNameFile.split(baseDir) - if len(tail)==2: - tail = tail[1].split('/') - if len(tail)==3 and tail[1]!='virtual': - pkgs.append(tail[2]) - return True - os.path.walk(baseDir,getFilesDir, pkgs) - pkgs.sort() - for pkg in pkgs: - findVer = reVer.search(pkg) - if findVer: - ver = findVer.group() - versions.append(ver) - names.append(pkg.split(ver)[0][:-1]) - #return pkgs - return names, versions - - def pkg(nameProg, names, versions): - """Выдает установленные версии по имени программы""" - # Значение версии из кеша - if nameProg in self.cacheInstallProg: - return self.cacheInstallProg[nameProg] - i = 0 - vers = [] - for name in names: - if nameProg == name: - while nameProg == names[i]: - vers.append(versions[i]) - i += 1 - break - i += 1 - if vers: - version = vers[-1] - # Запись значения версии в кеш - self.cacheInstallProg[nameProg] = version - return version - else: - return "" - - def funcPkg(funTxt,resS,textTemplateTmp): - """локальная функция выдает номер версии программы""" - terms = funTxt[4:-1].replace(" ","") - # Название программы - nameProg = terms - if not self.installProg: - # Получение всех названий и версий установленных программ - self.installProg,self.installProgVersions =\ - getInstallPkgGentoo(names=self.installProg, - versions=self.installProgVersions) - replace = pkg(nameProg,self.installProg,self.installProgVersions) - textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ - textTemplateTmp[resS.end():] - return textTemplateTmp - - def funcRnd(funTxt,resS,textTemplateTmp): - """локальная функция выдает строку случайных символов - - первый аргумент: - 'num' - числа, - 'pas' - цифры и буквы - второй аргумент: - количество символов - """ - terms = funTxt[4:-1].replace(" ","").split(",") - if not terms[0].strip() or\ - (len(terms)==2 and not terms[1].strip()) or\ - len(terms)!=2: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - exit(1) - fArgvNames = ['num','pas'] - if not terms[0] in fArgvNames: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - print _("first argument function is not 'num' or 'pas'") - exit(1) - try: - lenStr = int(terms[1]) - except: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - print _("two argument function is not number") - exit(1) - if terms[0] == fArgvNames[0]: - replace=''.join([random.choice(string.digits)\ - for i in xrange(lenStr)]) - elif terms[0] == fArgvNames[1]: - replace=''.join([random.choice(string.ascii_letters + \ - string.digits) for i in xrange(lenStr)]) - else: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - exit(1) - textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ - textTemplateTmp[resS.end():] - return textTemplateTmp - - def funcCase(funTxt,resS,textTemplateTmp): - """локальная функция выдает переменную в определенном регистре - - первый аргумент: - 'upper' - верхний регистр, - 'lower' - нижний регистр, - 'capitalize' - первая буква в верхнем регистре - второй аргумент: - название переменной - """ - terms = funTxt[5:-1].replace(" ","").split(",") - if not terms[0].strip() or\ - (len(terms)==2 and not terms[1].strip()) or len(terms)!=2: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - exit(1) - fArgvNames = ['upper','lower','capitalize'] - if not terms[0] in fArgvNames: - print _("error in template %s")%nameTemplate - print _("error template term %s")%str(funTxt) - print _("first argument function is not 'upper' or 'lower' or\ - 'capitalize'") - exit(1) - try: - strValue = str(self.objVar.Get(terms[1])) - except: - print _("error in template %s")%nameTemplate - print _("error var %s not found")%str(terms[1]) - exit(1) - replace = "" - strValue = _toUNICODE(strValue) - if terms[0] == 'upper': - replace = strValue.upper() - elif terms[0] == 'lower': - replace = strValue.lower() - elif terms[0] == 'capitalize': - replace = strValue.capitalize() - if replace: - replace = replace.encode("UTF-8") - textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ - textTemplateTmp[resS.end():] - return textTemplateTmp - - # Локальные переменные - localVars = {} - # Регулярное выражние для сложения - sNum = re.compile("\-[^\-\+]+|[^\-\+]+") - # Регулярное выражение для умножениея и деления - sMD = re.compile("[^\-\+\*\/]+") - resS = self._reFunc.search(textTemplate) - textTemplateTmp = textTemplate - while resS: - mark = textTemplateTmp[resS.start():resS.end()] - funTxt = mark[self._deltVarStart:-self._deltVarEnd] - # Функция sum - if funTxt[:4] == "sum(": - textTemplateTmp = funcSum(funTxt,resS,localVars,textTemplateTmp) - resS = self._reFunc.search(textTemplateTmp) - # Функция load - elif funTxt[:5] == "load(": - textTemplateTmp = funcLoad(funTxt,resS,textTemplateTmp) - resS = self._reFunc.search(textTemplateTmp) - elif funTxt[:4] == "pkg(": - textTemplateTmp = funcPkg(funTxt,resS,textTemplateTmp) - resS = self._reFunc.search(textTemplateTmp) - elif funTxt[:4] == "rnd(": - textTemplateTmp = funcRnd(funTxt,resS,textTemplateTmp) - resS = self._reFunc.search(textTemplateTmp) - elif funTxt[:5] == "case(": - textTemplateTmp = funcCase(funTxt,resS,textTemplateTmp) - resS = self._reFunc.search(textTemplateTmp) - else: - resS = False - return textTemplateTmp - def applyTermsTemplate(self,textTemplate,nameTemplate,nameSystemFile=False): """ Применяет условия, к условным блокам текста """ @@ -2918,6 +2955,11 @@ class template(_file, _terms, xmlShare): blockDirs.append(dirTemplate) continue dirInfoFile = os.path.join(dirTemplate, self.templDirNameFile) + # Если есть базовая директория наложения шаблонов + # то изменяем путь к директории в системе + if self._baseDir: + pDirs["_real_path"] = os.path.join(self._baseDir, + pathDir[1:]) pathDir, propDir, crDirs = self.__getApplyHeadDir(pDirs) if not propDir and self.getError(): self.setError(_("Error in apply template: " ) +\ @@ -2943,6 +2985,14 @@ class template(_file, _terms, xmlShare): titleBaseDir = os.path.split(dirObj.baseDir)[0] titlePath = fileTemplate.partition(titleBaseDir)[2] templTitle = '"' + titlePath[1:] + '"' + # Если есть базовая директория наложения шаблонов + # то изменяем путь к файлу в системе + # и директорию где этот файл находится + if self._baseDir: + pathFile = os.path.join(self._baseDir, pathFile[1:]) + propFile["_real_path"] = pathFile + propFile["path"] = os.path.join(self._baseDir, + propFile["path"][1:]) # Записываем в переменную обрабатываемый файл self.objVar.Set("cl_pass_file",pathFile) filesApl = self.join(fileTemplate, propFile, From 5f563167177be3f50a2bbe3172898e7db7cdcf08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B0=D0=BC=D0=BE=D1=83=D0=BA=D0=B8=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9?= Date: Wed, 3 Feb 2010 11:59:35 +0300 Subject: [PATCH 5/7] Added cl_lib and cl_libserver modules --- pym/cl_lib.py | 39 +++++++++++++++++++++ pym/cl_libserver.py | 85 +++++++++++++++++++++++++++++++++++++++++++++ pym/cl_template.py | 36 +++---------------- pym/cl_utils.py | 32 ++++++++++++++++- 4 files changed, 159 insertions(+), 33 deletions(-) create mode 100644 pym/cl_lib.py create mode 100644 pym/cl_libserver.py diff --git a/pym/cl_lib.py b/pym/cl_lib.py new file mode 100644 index 0000000..0d0c1e8 --- /dev/null +++ b/pym/cl_lib.py @@ -0,0 +1,39 @@ +#-*- 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. + +from cl_utils import removeDir +from cl_print import color_print + +import cl_lang +tr = cl_lang.lang() +tr.setLocalDomain('cl_lib') +tr.setLanguage(sys.modules[__name__]) + +class shareFile(color_print): + """Общие методы для работы с файлами""" + + def removeDir(self, rmDir): + """Рекурсивное удаление директории + + входной параметр директория или результат сканирования файлов (объект) + """ + try: + removeDir(rmDir) + except (OSError, Exception), e: + print e + self.printERROR(_("Can not delete dir: " ) + rmDir) + return False + return True \ No newline at end of file diff --git a/pym/cl_libserver.py b/pym/cl_libserver.py new file mode 100644 index 0000000..60c2a3d --- /dev/null +++ b/pym/cl_libserver.py @@ -0,0 +1,85 @@ +#-*- 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 hashlib +import crypt +import string +from random import choice +from base64 import urlsafe_b64encode as b64encode + +from cl_print import color_print +import cl_lang + +tr = cl_lang.lang() +tr.setLocalDomain('cl_lib') +tr.setLanguage(sys.modules[__name__]) + +class shareServer(color_print): + """Класс хранения общих методов используемых для настройки сервисов""" + + def __GenCryptSalt__(self): + """Генерация соли для хеширования пароля (CRYPT)""" + chars = string.letters + string.digits+ "./" + salt = "" + for i in range(2): + salt = salt + choice(chars) + return salt + + def getHashPasswd(self, password, crypt): + """Генерация хеша пароля, + + Поддерживаемые алгоритмы шифрования пароля: + plain, md5, smd5, crypt, sha, ssha + """ + if not password: + self.printERROR(_("ERROR") + " getHashPasswd: " +\ + _("password empty")) + return False + + hashPwd = "" + if crypt == "plain": + hashPwd = password + + elif crypt == "md5": + h = hashlib.md5(password) + hashPwd = "{MD5}" + b64encode(h.digest()) + + elif crypt == "smd5": + salt = os.urandom(4) + h = hashlib.md5(password) + h.update(salt) + hashPwd = "{SMD5}" + b64encode(h.digest() + salt) + + elif crypt == "crypt": + salt = self.__GenCryptSalt__() + hashPwd = "{CRYPT}" + crypt.crypt(password, salt) + + elif crypt == "sha": + h = hashlib.sha1(password) + hashPwd = "{SHA}" + b64encode(h.digest()) + + elif crypt == "ssha": + salt = os.urandom(4) + h = hashlib.sha1(password) + h.update(salt) + hashPwd = "{SSHA}" + b64encode(h.digest() + salt) + + else: + self.printERROR(_("ERROR") + " getHashPasswd: " +\ + _("Can not support '%s' crypto algoritm")%crypt) + return False + return hashPwd diff --git a/pym/cl_template.py b/pym/cl_template.py index 46ee7a8..e1d9ac6 100644 --- a/pym/cl_template.py +++ b/pym/cl_template.py @@ -24,7 +24,7 @@ import subprocess import types import random import string -from cl_utils import _error, scan, _toUNICODE +from cl_utils import _error, scan, _toUNICODE, removeDir from cl_overriding import exit import cl_lang @@ -2544,35 +2544,6 @@ class template(_file, _terms, xmlShare, _shareTemplate): self.importFormats[formatTemplate] = classFormat return classFormat(textTemplate) - def removeDir(self, rmDir): - """Рекурсивное удаление директории - - входной параметр директория - """ - if not os.path.exists(rmDir): - self.printERROR(_("Not found remove dir %s") %rmDir) - return False - fileObj = _file() - # Сканируем директорию - scanObjs = fileObj.scanDirs([rmDir]) - for socketRm in scanObjs[0].sockets: - # Удаляем сокеты - if os.path.exists(socketRm): - os.remove(socketRm) - for linkRm in scanObjs[0].links: - # Удаляем ссылки - os.unlink(linkRm[1]) - for fileRm in scanObjs[0].files: - # Удаляем файлы - os.remove(fileRm) - scanObjs[0].dirs.sort(lambda x, y: cmp(len(y), len(x))) - for dirRm in scanObjs[0].dirs: - # Удаляем директории - os.rmdir(dirRm) - if rmDir: - os.rmdir(rmDir) - return True - def createConfFile(self, pathTemplate, path=False): """Создает конфигурационный файл если его нет""" @@ -3155,8 +3126,9 @@ class template(_file, _terms, xmlShare, _shareTemplate): if os.path.isdir(newDirMv): # удаляем директорию try: - self.removeDir(newDirMv) - except: + removeDir(newDirMv) + except (OSError, Exception), e: + print e self.setError(_("Can not delete dir: " ) +\ newDirMv) return (applyDir, False, createDirs) diff --git a/pym/cl_utils.py b/pym/cl_utils.py index 5a29f48..4e69b58 100644 --- a/pym/cl_utils.py +++ b/pym/cl_utils.py @@ -211,4 +211,34 @@ class scan: return [] dirP.baseDir = scanDir dirs.append(dirP) - return dirs \ No newline at end of file + return dirs + +def removeDir(rmDir): + """Рекурсивное удаление директории + + входной параметр директория для удаления + + Ошибки по except + """ + if not os.path.exists(rmDir): + raise Exception(_("Not found remove dir %s") %rmDir) + fileObj = scan() + # Сканируем директорию + 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 os.path.exists(rmDir): + os.rmdir(rmDir) + return True From 36ac222082dd97f8300abced76e1640b5f5c83ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B0=D0=BC=D0=BE=D1=83=D0=BA=D0=B8=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9?= Date: Wed, 3 Feb 2010 12:18:58 +0300 Subject: [PATCH 6/7] Add 'import sys' in cl_lib --- pym/cl_lib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pym/cl_lib.py b/pym/cl_lib.py index 0d0c1e8..605203b 100644 --- a/pym/cl_lib.py +++ b/pym/cl_lib.py @@ -14,6 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import sys from cl_utils import removeDir from cl_print import color_print From 76492a3bd27d1004c97cb18a84f439976cb54619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B0=D0=BC=D0=BE=D1=83=D0=BA=D0=B8=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9?= Date: Wed, 3 Feb 2010 13:23:35 +0300 Subject: [PATCH 7/7] Add 'import sys' in cl_libserver --- pym/cl_libserver.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pym/cl_libserver.py b/pym/cl_libserver.py index 60c2a3d..fc99ebb 100644 --- a/pym/cl_libserver.py +++ b/pym/cl_libserver.py @@ -14,6 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import sys import os import hashlib import crypt