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>..%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>..%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",[])],
)