From b2a0679a602e38ee178bab5348bf4ba316078b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=B0=D0=BC=D0=BE=D1=83=D0=BA=D0=B8=D0=BD=20=D0=90?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9?= Date: Mon, 26 Apr 2010 17:05:52 +0400 Subject: [PATCH] reorganization of the library --- README | 3 +- pym/cl_data.py | 624 ------- pym/cl_fill.py | 432 ++++- pym/cl_help.py | 375 ---- pym/cl_lib.py | 40 - pym/cl_log.py | 1 - pym/cl_overriding.py | 2 +- pym/cl_template.py | 3394 +++++++++++++++++++++-------------- pym/cl_utils.py | 176 +- pym/cl_vars.py | 31 +- pym/format/__init__.py | 1 + pym/format/apache.py | 3 +- pym/format/bind.py | 2 + pym/format/dhcp.py | 2 + pym/format/dovecot.py | 4 +- pym/format/kde.py | 23 +- pym/format/ldap.py | 1 + pym/format/plasma.py | 42 +- pym/format/postfix.py | 1 + pym/format/samba.py | 17 +- pym/format/squid.py | 1 + pym/format/xml_gconf.py | 128 +- pym/format/xml_xfce.py | 2 +- pym/format/xml_xfcepanel.py | 12 +- pym/server/encrypt.py | 178 -- pym/server/ldap.py | 2 +- setup.py | 4 +- 27 files changed, 2652 insertions(+), 2849 deletions(-) delete mode 100644 pym/cl_data.py delete mode 100644 pym/cl_help.py delete mode 100644 pym/cl_lib.py delete mode 100644 pym/server/encrypt.py diff --git a/README b/README index c1df372..c65a3de 100644 --- a/README +++ b/README @@ -4,9 +4,10 @@ INSTALL ------- calculate-lib needs the following library version installed, in order to run: - Python >= 2.6 + python >= 2.5 python-ldap >= 2.0.0 pyxml >= 0.8 + py-smbpasswd >= 1.0 To install calculate-lib , just execute the install script 'setup.py'. Example: diff --git a/pym/cl_data.py b/pym/cl_data.py deleted file mode 100644 index 926c224..0000000 --- a/pym/cl_data.py +++ /dev/null @@ -1,624 +0,0 @@ -#-*- coding: utf-8 -*- - -# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import os -import sys -import cl_utils -from cl_lang import lang -from cl_template import iniParser -from cl_string import columnWrite - -# Перевод модуля на другой язык -tr = lang() -tr.setLocalDomain('cl_lib') -tr.setLanguage(sys.modules[__name__]) - -class var: - '''Объект "Переменная окружения"''' - # название сервиса которому принадлежит переменная - #(Global, Builder, Client, Server итд) - service = None - # значение переменной - value = "" - # режим записи (атрибут mode) - mode = "r" - # переменная для внутреннего использования (official) - official = False - # количество вызовов метода заполнения - countFill = 0 - # объект в котором создан этот объект - parentObj = None - # запускать или нет метод заполнения - fillStart = True - # dynamic = True то переменная динамическая при повтороном запуске - # запускается метод заполнения - # метод заполнения не запускается только если fillStart = False - # (осторожно возможно зацикливание программы если методы заполнения - # переменных используют методы друг друга) - dynamic = False - - def __init__(self, parentObj): - # словарь зависимых переменных {имя:значение} - self.dependValues = {} - # тип переменной (атрибут type) - self.type = ('default') - # список допустимых значений переменных (select) - self.select = () - # объект который создал этот объект - self.parentObj = parentObj - - def is_update(self): - #Нужно ли перезапускать метод заполнения (если зависимые переменные - #обновились то нужно) - upd = False - for depVarName in self.dependValues.keys(): - value = self.parentObj.__getattribute__(depVarName).Get() - if self.dependValues[depVarName] != value: - self.dependValues[depVarName] =\ - self.parentObj.__getattribute__(depVarName).value - upd = True - break - return upd - - def Get(self): - """Получение значения переменной""" - if not self.fillStart: - return self.value - if self.dynamic: - self.value = self.Fill() - return self.value - if not self.value: - if self.countFill>0: - return self.value - self.countFill += 1 - self.value = self.Fill() - if self.dependValues and self.is_update(): - self.countFill += 1 - self.value = self.Fill() - return self.value - - def Set(self, value): - """Запись значения переменной""" - self.value = value - return self.value - - def Fill(self): - """Заполнение переменной в далнейшем заменяем методом заполнения""" - return self.value - - -class DataVars(object): - class DataVarsError(Exception): - """Класс ошибок""" - pass - # добавляем пути к модулям если они не добавлены - if not os.path.abspath(\ - '/usr/lib/calculate/calculate-server/pym') in sys.path: - sys.path.insert(0,os.path.abspath(\ - '/usr/lib/calculate/calculate-server/pym')) - if not os.path.abspath(\ - '/usr/lib/calculate/calculate-lib/pym') in sys.path: - sys.path.insert(0,os.path.abspath(\ - '/usr/lib/calculate/calculate-lib/pym')) - if not os.path.abspath(\ - '/usr/lib/calculate/calculate-builder/pym') in sys.path: - sys.path.insert(0,os.path.abspath(\ - '/usr/lib/calculate/calculate-builder/pym')) - # Импортируемые модули - (раздел: модуль переменных, модуль заполнения - #переменных) - __modlist={'Global':('cl_vars','cl_fill'), - 'Server':('cl_vars_server','cl_fill_server'), - 'Builder':('cl_vars_builder','cl_fill_builder'), - 'Client':('cl_vars_client','cl_fill_client'), - } - def __init__(self): - #self.t1 = fillVars() - #self.t1.Get = self.Get - #self.t1.Set = self.Set - # Для нахождения зависимостей переменных - self.__levelNumber = 0 - self.__LevelsVar = [] - # Для хранения импортированных модулей и объектов - #[(cекция,импортированный модуль переменных, объект заполнения),] - self._importList = [] - self._importData("Global") - - def _importData(self, section): - """Импортирует модули с переменными и модули с функциями заполнения - - section секция раздела (Global, Server, Client итд) - создает необходимые структуры данных - """ - if not section in self.__modlist.keys(): - raise self.DataVarsError(_("Unsupported section %s")%section) - modVar = self.__modlist[section][0] - modFill = self.__modlist[section][1] - # Импортируем класс описания переменных и класс заполнения - try: - exec ("import %s" % (modVar)) - except ImportError, e: - err1 = _("Error in import module %s")%modVar - err2 = _("error") + ": " +str(e) - raise self.DataVarsError("%s\n%s"%(err1,err2)) - flagFindFillModule = True - try: - exec ("import %s" % (modFill)) - except ImportError, e: - if "No module named" in str(e): - flagFindFillModule = False - else: - err1 = _("Error in import module %s")%modFill - err2 = _("error") + ": " +str(e) - raise self.DataVarsError("%s\n%s"%(err1,err2)) - if flagFindFillModule: - # Создаем объект с методами заполнения переменных - exec("fillObj = %s.fillVars()" %modFill) - # Подключаем методы получения и записи переменных - fillObj.Get = self.Get - fillObj.Set = self.Set - else: - fillObj = False - # Заполняем self._importList - exec("self._importList.insert(0,(section,%s,fillObj))"%(modVar)) - - def __findVarData(self, nameVar): - """Находит данные для создания объекта переменная в модулях и - - объектах - """ - # Ищем переменную в модуле - dataVar = False - e = False - for section, moduleVar, fillobj in self._importList: - try: - exec("dataVar=moduleVar.Data.%s"%nameVar) - except AttributeError, e: - pass - if dataVar: - break - if dataVar == False: - err1 = _("Not found variable %s")%nameVar - err2 = "" - if e: - err2 = _("error") + ": " +str(e) - raise self.DataVarsError("%s\n%s"%(err1,err2)) - dataVar['service'] = section - # Ищем метод в объекте методов заполнения - nameMethod = "get_" + nameVar - flagFindMetod = False - for section, moduleVar, fillobj in self._importList: - if fillobj: - if nameMethod in dir(fillobj): - flagFindMetod = True - method = fillobj.__getattribute__(nameMethod) - break - if flagFindMetod: - return (dataVar,method) - else: - return (dataVar,False) - - def __setAttributesVar(self, var ,nameVar, dict): - """Установка аттрибутов для созданного объекта var - - название аттрибута и его значение берется из словаря dict - """ - dict['type'] = nameVar.split('_') - if not set(dict.keys()) <= set(dir(var)): - raise self.DataVarsError(\ - _("error initalize variable %s, incorrect data")%nameVar) - for nameAttr in dict.keys(): - setattr(var,nameAttr, dict[nameAttr]) - return True - - def __Get(self, nameVar): - ret = "" - self.__LevelsVar.append((self.__levelNumber, nameVar)) - self.__levelNumber += 1 - #nameMethod = "get_" + nameVar - if self.__dict__.has_key(nameVar): - ret = self.__getattribute__(nameVar).Get() - elif self.__findVarData(nameVar): - dictVar, methodFill =self.__findVarData(nameVar) - varobj = var(self) - # Устанавливаем аттрибуты - self.__setAttributesVar(varobj, nameVar, dictVar) - if methodFill: - varobj.Fill = methodFill - self.__setattr__(nameVar, varobj) - ret = self.__getattribute__(nameVar).Get() - self.__levelNumber -= 1 - if self.__levelNumber == 0 and\ - self.__getattribute__(nameVar).fillStart and\ - len(self.__LevelsVar)>1: - links = self.__getLinks(self.__LevelsVar) - for name in links.keys(): - for nameLink in links[name].keys(): - val = self.__getattribute__(nameLink).Get() - self.__getattribute__(name).dependValues[nameLink] = val - if self.__levelNumber == 0: - self.__LevelsVar = [] - return ret - - def Get(self, nameVar): - return self.__Get(nameVar) - - - def __Set(self, nameVar, value, force=False): - nameMethod = "get_" +nameVar - if not self.__dict__.has_key(nameVar) and self.__findVarData(nameVar): - dictVar, methodFill =self.__findVarData(nameVar) - varobj = var(self) - # Устанавливаем аттрибуты - self.__setAttributesVar(varobj, nameVar, dictVar) - if methodFill: - varobj.Fill = methodFill - self.__setattr__(nameVar, varobj) - if self.__dict__.has_key(nameVar): - if not force and "r" in getattr(self, nameVar).mode: - print _("Attempt to rewrite a variable for reading:%s")\ - %nameVar - return False - self.__getattribute__(nameVar).fillStart = False - return self.__getattribute__(nameVar).Set(value) - - def Set(self, nameVar, value, force=False): - return self.__Set(nameVar, value, force) - - def __frame(self, lVar): - """получить список областей зависимости переменных""" - data = [] - if not lVar: - return data - firstLevel = lVar[0][0] - for level, name in lVar[1:]: - if level> firstLevel: - data.append((level, name)) - else: - break - return data - - def __getLinks(self, lVar): - """Получить список переменных и от каких переменных они зависят - - на вход список [(уровень рекурсии, название переменной),] - """ - links = {} - frames = {} - levelLinks = {} - lVarFr = lVar - for level, name in lVar: - fr = self.__frame(lVarFr) - if not frames.has_key(name): - frames[name] = fr - levelLinks[name] = level+1 - lVarFr = lVarFr[1:] - for name in frames.keys(): - level = levelLinks[name] - fr = frames[name] - links[name] = {} - for lv, nm in fr: - if level == lv: - links[name][nm] = "" - return links - - def __getPathCalculateIni(self): - """Получить пути до ini файлов""" - return self.Get('cl_env_path') - - def __getSection(self, vname): - """секция для записи в ini файл переменной - - vname - имя переменной - """ - if self.__dict__.has_key(vname): - if self.__dict__[vname].service == 'Global': - return 'calculate' - else: - return self.__dict__[vname].service.lower() - - def __writeVarValue(self, vname, val, location, header): - '''Записать значение в calculate.ini - - Параметры: - vname имя переменной - val значение переменной - location расположение ini файла ('default', 'local', 'remote') - header раздел ini файла ('client', 'server', 'calculate') - - Возвращаемые значение: - True запись успешна - False запись не удалсь - ''' - # получаем все пути до ini файлов - calculate_ini = self.__getPathCalculateIni() - # получаем полный путь до файла ini - if location == 'default': - name_calculate_ini = calculate_ini[2] - elif location == 'local': - name_calculate_ini = calculate_ini[1] - elif location == 'remote': - name_calculate_ini = calculate_ini[0] - else: - return False - # извлекаем из полного имени файла путь - onlydir = os.path.split(name_calculate_ini)[0] - try: - # проверяем чтобы путь до ини файла существовал - if not os.path.exists(onlydir): - # создаем его если отсутствует - os.makedirs(onlydir) - except OSError (nerr,msg): - print nerr, msg - return False - config = iniParser(name_calculate_ini) - # Получаем секцию конфигурационного файла - if not header: - header = self.__getSection(vname) - return config.setVar(header,{vname: cl_utils.convertStrListDict(val)}) - - def __deleteVarValue(self, vname, location, header): - '''Удалить переменную в calculate.ini - - Параметры: - vname имя переменной - location расположение ini файла ('default', 'local', 'remote') - - Возвращаемые значение: - True удалено успешна - False удаление не удалсь - ''' - # получаем все пути до ini файлов - calculate_ini = self.__getPathCalculateIni() - # получаем полный путь до файла ini - if location == 'default': - name_calculate_ini = calculate_ini[2] - elif location == 'local': - name_calculate_ini = calculate_ini[1] - elif location == 'remote': - name_calculate_ini = calculate_ini[0] - else: - return False - # извлекаем из полного имени файла путь - onlydir = os.path.split(name_calculate_ini)[0] - # проверяем чтобы путь до ини файла существовал - if not os.path.exists(onlydir): - return False - config = iniParser(name_calculate_ini) - # Получаем секцию конфигурационного файла - if not header: - header = self.__getSection(vname) - # Удаляем переменную - retDelVar = config.delVar(header, vname) - retDelArea = True - if not config.getAreaVars(header): - retDelArea = config.delArea(header) - if retDelArea and retDelVar: - return True - else: - return False - - def Write(self, vname, val, force=False, location='default',header=False): - '''Установить и записать значение переменной в ini файл - - Параметры: - vname имя переменной - val значение переменной - force "принудительный режим" - location расположение ini файла ('default', 'local', 'remote') - header раздел ini файла ('client', 'server', 'calculate') - ''' - if self.__Set(vname, val, force)!= False: - if not val.strip(): - self.__deleteVarValue(vname, location, header) - self.__writeVarValue(vname, val, location, header) - return True - return False - - def Delete(self, vname, location='default', header=False): - '''Удалить переменную в calculate.ini - - Параметры: - vname имя переменной - location расположение ini файла ('default', 'local', 'remote') - - Возвращаемые значение: - True удалено успешна - False удаление не удалсь - ''' - return self.__deleteVarValue(vname, location, header) - - def __getActiveSections(self): - """активные секции в ini файле""" - act_section = [] - for service,t,t in self._importList: - if service == "Global": - act_section.append('calculate') - else: - act_section.append(service.lower()) - return act_section - - def flIniFile(self): - '''Заместить значение переменных значениями из ини файлов - - Возвращаемые значения: - cловарь импортированных переменных - переменные считаны - False - файл не был обнаружен - ''' - #Cловарь переменных из ini файлов - importVars = {} - calculate_ini = self.__getPathCalculateIni() - # активные секции (секции из которых будут использованы переменные) - act_section = self.__getActiveSections() - set_act_section = set(act_section) - i = 0 - locations = ['remote','local','default'] - for name_calculate_ini in calculate_ini: - # проверить сущестование ini файла - if os.path.exists(name_calculate_ini): - # получить объект настроенный на ini - config = iniParser(name_calculate_ini) - # получаем все секции из конфигурационного файла - allsect = config.getAllSectionNames() - if not allsect: - continue - # находим встречающиеся у обоих секции - act_sect = tuple(set(allsect)& set_act_section) - # словарь переменных для ini - файла - importFileVars = {} - # получаем все переменные из всех секций - for section in act_sect: - allvars = config.getAreaVars(section) - if allvars == False: - return False - # словарь переменных для ini - файла - importFileVars = {} - # принудительно переписать все переменные окружения - # полученные из ini - for (k,v) in allvars.items(): - k = k.encode("UTF-8") - value = cl_utils.convertStrListDict(v.encode("UTF-8")) - self.Set(k, value, True) - importFileVars[k] = value - if i < 3: - importVars[locations[i]] = importFileVars - i += 1 - return importVars - - def flServer(self, **args): - '''Заполнить конфигурацию переменных, для ldap''' - # заполнить переменные окружения алгоритмом по умолнанию - self._importData("Server") - - def flClient(self, **args): - '''Заполнить конфигурацию переменных, для клиента''' - # заполнить переменные окружения алгоритмом по умолнанию - self._importData("Client") - - def flBuilder(self, **args): - '''Заполнить конфигурацию переменных, для билдера''' - self.Set('setup_pass','builder',True) - # заполнить переменные окружения алгоритмом по умолнанию - self._importData("Builder") - - def flInstall(self, **args): - '''Заполнить конфигурацию переменных для инсталятора''' - self.Set('setup_pass','install',True) - - #def defined(self, vname): - #if vname: - #if self.__dict__.has_key(vname): - #return True - #return False - def defined(self, vname): - return True - - - - def exists(self, nameVar): - """ Определяет существует ли переменная с таким имененм - """ - if self.__dict__.has_key(nameVar): - return True - foundVar = False - # Ищем переменную в импортируемых модулях - for section, moduleVar, fillobj in self._importList: - if moduleVar.Data.__dict__.has_key(nameVar): - foundVar = True - break - return foundVar - - def getVars(self, type_names=None): - ret = {} - for section, moduleVar, fillobj in self._importList: - dataVar=moduleVar.Data - dictVars = dir(dataVar) - for nameVar in dictVars: - if not "__" in nameVar: - if not (getattr(dataVar,nameVar).has_key("official") and\ - getattr(dataVar,nameVar)['official']): - self.Get(nameVar) - if type_names: - #type_names.sort() - varType =list(getattr(dataVar,nameVar)['type']) - #varType.sort() - #print type_names - #print varType - #print - if not set(type_names)<=set(varType): - continue - ret[nameVar] = getattr(self,nameVar) - return ret - - #распечатать список переменных с значениями - def printVars(self,type_names=None): - var=None - var=self.getVars(type_names) - mlen_name=0; - mlen_type=0; - mlen_mode=0; - for i,j in var.items(): - if len(i)>mlen_name: - mlen_name=len(i) - #if len(str(j.type))>mlen_type: - #mlen_type=len(str(j.type)) - vtype=str(type(var[i].value)).split(" ")[1][1] - if not '[' in var[i].mode: - if vtype in ['d','l']: - mode="[%s%s]"%(var[i].mode.lower(),vtype) - else: - mode="[%s]"%(var[i].mode.lower()) - var[i].mode=mode - if len(mode)>mlen_mode: - mlen_mode=len(mode) - plist=var.keys() - plist.sort() - br = cl_utils.fillstr("-",mlen_name) + " " +\ - cl_utils.fillstr("-",mlen_mode) + " " + cl_utils.fillstr("-",10) - #cl_utils.fillstr("-",mlen_type) + " " +\ - - print "The list of variables:" - print "var name".center(mlen_name),\ - "Mode","Value" - #"Type".center(mlen_type),\ - - - print br - for i in plist: - #if var[i].value is None: - #continue - p_val=var[i].value - if var[i].official: - continue - columnWrite( i, mlen_name, var[i].mode.lower(), - mlen_mode, - #str(var[i].type), - #mlen_type, - p_val) - print br - -class glob_attr: - """Глобальные аттрибуты для методов заполнения переменных""" - - def _runos(self,cmd, ret_first=None, env={}): - """Вернуть результат выполнения команды ОС""" - if not env: - envDict = {} - env.update(os.environ.items() + [("PATH",cl_utils.getpathenv())] +\ - env.items()) - retCode, programOut = cl_utils.runOsCommand(cmd, None, ret_first, env) - if not retCode: - return programOut - return False diff --git a/pym/cl_fill.py b/pym/cl_fill.py index 4d3b598..76fdb4b 100644 --- a/pym/cl_fill.py +++ b/pym/cl_fill.py @@ -17,11 +17,197 @@ import re import os import types -from cl_overriding import exit -import cl_utils -import cl_data +import filecmp +import cl_datavars -class fillVars(object, cl_data.glob_attr): +class clLocale: + lang = { + #Belarussian + 'be_BY' : { + 'locale':'be_BY.UTF-8', + 'keymap':'by', + 'dumpkeys_charset': 'koi8-u', + 'consolefont':'Cyr_a8x16', + 'xkblayout':'us,by', + 'language':'ru', + }, + #Belgian + 'fr_BE' : { + 'locale':'fr_BE.UTF-8', + 'keymap':'be-latin1', + 'dumpkeys_charset':'', + 'consolefont':'lat9w-16', + 'xkblayout':'us,be', + 'language':'en_US', + }, + #Brazilian Portuguese + 'pt_BR' : { + 'locale':'pt_BR.UTF-8', + 'keymap':'br-abnt2', + 'dumpkeys_charset':'', + 'consolefont':'lat9w-16', + 'xkblayout':'pt,us', + 'language':'pt_BR', + }, + #Canadian French + 'fr_CA' : { + 'locale':'fr_CA.UTF-8', + 'keymap':'cf', + 'dumpkeys_charset':'', + 'consolefont':'default8x16', + 'xkblayout':'us,ca_enhanced', + 'language':'en_US', + }, + #Danish + 'da_DK' : { + 'locale':'da_DK.UTF-8', + 'keymap':'dk-latin1', + 'dumpkeys_charset':'', + 'consolefont':'lat0-16', + 'xkblayout':'us,dk', + 'language':'da', + }, + #French + 'fr_FR' : { + 'locale':'fr_FR.UTF-8', + 'keymap':'fr-latin9', + 'dumpkeys_charset':'', + 'consolefont':'lat0-16', + 'xkblayout':'fr,us', + 'language':'en_US', + }, + #German + 'de_DE' : { + 'locale':'de_DE.UTF-8', + 'keymap':'de-latin1', + 'dumpkeys_charset':'', + 'consolefont':'lat9w-16', + 'xkblayout':'de,us', + 'language':'de', + }, + #Icelandic + 'is_IS' : { + 'locale':'is_IS.UTF-8', + 'keymap':'is-latin1', + 'dumpkeys_charset':'', + 'consolefont':'cp850-8x16', + 'xkblayout':'us,is', + 'language':'en_US', + }, + #Italian + 'it_IT' : { + 'locale':'it_IT.UTF-8', + 'keymap':'it', + 'dumpkeys_charset':'', + 'consolefont':'default8x16', + 'xkblayout':'us,it', + 'language':'it', + }, + #Norwegian + 'nn_NO' : { + 'locale':'nn_NO.UTF-8', + 'keymap':'no-latin1', + 'dumpkeys_charset':'', + 'consolefont':'lat9w-16', + 'xkblayout':'us,no', + 'language':'nn', + }, + #Polish + 'pl_PL' : { + 'locale':'pl_PL.UTF-8', + 'keymap':'pl', + 'dumpkeys_charset':'', + 'consolefont':'lat2-16', + 'xkblayout':'us,pl', + 'language':'pl', + }, + #Russian + 'ru_RU' : { + 'locale':'ru_RU.UTF-8', + 'keymap':'-u ruwin_cplk-UTF-8', + 'dumpkeys_charset':'', + 'consolefont':'ter-k14n', + 'xkblayout':'us,ru(winkeys)', + 'language':'ru', + }, + #Spanish + 'es_ES' : { + 'locale':'es_ES.UTF-8', + 'keymap':'es euro2', + 'dumpkeys_charset':'', + 'consolefont':'lat0-16', + 'xkblayout':'es,us', + 'language':'es', + }, + #Swedish + 'sv_SE' : { + 'locale':'sv_SE.UTF-8', + 'keymap':'sv-latin1', + 'dumpkeys_charset':'', + 'consolefont':'lat0-16', + 'xkblayout':'us,se', + 'language':'sv', + }, + #Ukrainian + 'uk_UA' : { + 'locale':'uk_UA.UTF-8', + 'keymap':'ua-utf', + 'dumpkeys_charset':'koi8-u', + 'consolefont':'ter-v14n', + 'xkblayout':'us,ua(winkeys)', + 'language':'uk', + }, + #United Kingdom/British + 'en_GB' : { + 'locale':'en_GB.UTF-8', + 'keymap':'uk', + 'dumpkeys_charset':'', + 'consolefont':'LatArCyrHeb-16', + 'xkblayout':'us,gb', + 'language':'en_US', + }, + #United State/English + 'en_US' : { + 'locale':'en_US.UTF-8', + 'keymap':'us', + 'dumpkeys_charset':'', + 'consolefont':'LatArCyrHeb-16', + 'xkblayout':'us', + 'language':'en_US', + } + } + + def getLangs(self): + return self.lang.keys() + + def isLangExists(self,lang): + return lang in self.lang.keys() + + def getFields(self,field): + return [ l[1][field] for l in self.lang.items() ] + + def getFieldByLang(self,field,lang): + return self.lang.get(lang, self.lang['en_US'])[field] + + def getFieldByKeymap(self,field,keymap): + return self.lang.get(self.getLangByField('keymap',keymap), + self.lang['en_US'])[field] + + def getLangByField(self,field,value): + langs = [lang[0] for lang in self.lang.items() + if lang[1][field] == value ] + if not langs: + return 'en_US' + else: + return langs[0] + +def getdirlist(s_path): + #Получить список директорий по указаному пути + fdir=filecmp.dircmp(s_path, s_path) + dir_list=fdir.common_dirs + return dir_list + +class fillVars(object, cl_datavars.glob_attr): def get_os_net_domain(self): ''' Определим домен''' @@ -29,7 +215,7 @@ class fillVars(object, cl_data.glob_attr): if not domain: print _("Error:") + " " +_("Not found domain name") print _("Command 'hostname -d' returns an empty value") - exit(1) + cl_base.exit(1) elif re.search("^hostname: ",domain): return "local" else: @@ -61,6 +247,7 @@ class fillVars(object, cl_data.glob_attr): if linuxShortName: dictLinuxName = {"CLD":"Calculate Linux Desktop", "CLDX":"Calculate Linux Desktop", + "CLDG":"Calculate Linux Desktop", "CDS":"Calculate Directory Server", "Gentoo":"Gentoo"} if linuxShortName in dictLinuxName.keys(): @@ -74,7 +261,7 @@ class fillVars(object, cl_data.glob_attr): """постфикс к названию системы""" linuxShortName = self.Get("os_linux_shortname") if linuxShortName: - dictLinuxSubName = {"CLD":"KDE", "CLDX":"XFCE"} + dictLinuxSubName = {"CLD":"KDE", "CLDX":"XFCE", "CLDG":"GNOME"} if linuxShortName in dictLinuxSubName.keys(): return dictLinuxSubName[linuxShortName] else: @@ -100,7 +287,7 @@ class fillVars(object, cl_data.glob_attr): systemVersion = "" flagGentoo = False if os.path.exists(gentooFile): - gentooLink = "/etc/make.template" + gentooLink = "/etc/make.profile" if os.path.islink(gentooLink): systemVersion = os.readlink(gentooLink).rpartition("/")[2] flagGentoo = True @@ -130,7 +317,7 @@ class fillVars(object, cl_data.glob_attr): def get_os_net_ip(self): """все ip компьютера, разделитель запятая""" IPs = [] - netInterfaces=cl_utils.getdirlist("/sys/class/net/") + netInterfaces=getdirlist("/sys/class/net/") for i in netInterfaces: res = self._runos("/sbin/ifconfig %s"%i) if not res: @@ -165,7 +352,7 @@ class fillVars(object, cl_data.glob_attr): %(x>>24, x>>16&255, x>>8&255, x&255, nMask(maskNumb)) networks=[] - netInterfaces=cl_utils.getdirlist("/sys/class/net/") + netInterfaces=getdirlist("/sys/class/net/") flagError = False for i in netInterfaces: res = self._runos("/sbin/ifconfig %s"%i) @@ -181,85 +368,6 @@ class fillVars(object, cl_data.glob_attr): 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") @@ -344,3 +452,151 @@ class fillVars(object, cl_data.glob_attr): virtName = virtSysDict[vName] break return virtName + + def getValueFromConfig(self,config,name): + """Get value of parameter from bash type file + + Parameters: + config config file name + name param name + """ + reMatch = re.compile("^%s\s*=\s*\"?(.*)\"?$"%name, re.I) + try: + if os.path.exists(config): + for line in open(config,"r").readlines(): + match = reMatch.match(line) + if match: + return group().strip() + except: + pass + return False + + def getValueFromCmdLine(self,option,num): + """Get value of parameter from boot params + + Parameters: + option param name + num number part of value parameter (, split) + """ + cmdLine = "/proc/cmdline" + calculateParam = "calculate" + # try get timezone from kernel calculate param + try: + for param in open(cmdLine,"r").read().split(" "): + parname,op,value = param.partition("=") + if parname == calculateParam and op == "=": + values = value.split(",") + if len(values) > num and values[num].strip(): + return values[num].strip() + except IOError,e: + return "" + + def get_hr_board_model(self): + """motherboard model""" + modelFile = "/sys/class/dmi/id/board_name" + try: + return open(modelFile,"r").read().strip() + except: + return "" + + def get_hr_board_vendor(self): + """motherboard vendor""" + vendorFile = "/sys/class/dmi/id/board_vendor" + try: + return open(vendorFile,"r").read().strip() + except: + return "" + + def get_hr_cpus(self): + """processors count""" + cpuinfoFile = "/proc/cpuinfo" + try: + return len(["" for line in open(cpuinfoFile,"r").readlines() + if "processor" in line]) + except: + return 1 + + def get_os_locale_locale(self): + """locale (example: ru_RU.UTF-8)""" + locale = clLocale() + # get locale from boot calculate param + localeVal = self.getValueFromCmdLine("calculate",0) + if locale.isLangExists(localeVal): + return locale.getFieldByLang('locale',localeVal) + elif os.environ.has_key("LANG"): + return os.environ["LANG"] + else: + return locale.getFieldByLang("locale","default") + + def get_os_locale_lang(self): + """lang (example: ru_RU)""" + locale = clLocale() + return locale.getLangByField("locale",self.Get('os_locale_locale')) + + def get_os_locale_language(self): + """language (example: ru)""" + locale = clLocale() + return locale.getFieldByLang("language",self.Get('os_locale_lang')) + + def get_os_locale_xkb(self): + """xkb layouts (example: en,ru)""" + locale = clLocale() + # is specified keymap support by locale hash + if self.Get('os_locale_keymap') in locale.getFields('keymap'): + return locale.getFieldByKeymap("xkblayout", + self.Get('os_locale_keymap')) + else: + return locale.getFieldByLang("xkblayout", + self.Get('os_locale_lang')) + + def get_os_locale_keymap(self): + """keymap of locale (used for /etc/conf.d/keymaps)""" + locale = clLocale() + # get keymap from boot calculate param (keymap specified + # by lang) + keymapConfd = '/etc/conf.d/keymaps' + keymap = self.getValueFromCmdLine("calculate",1) + if locale.isLangExists(keymap): + return locale.getFieldByLang('keymap',keymap) + # get keymap by os_locale_lang + keymap = self.getValueFromConfig(keymapConfd,'KEYMAP') + if keymap: + return keymap + return locale.getFieldByLang("keymap",self.Get("os_locale_lang")) + + def get_os_locale_dumpkeys(self): + """dumpkeys charset for keymap""" + locale = clLocale() + # is specified keymap support by locale hash + if self.Get('os_locale_keymap') in locale.getFields('keymap'): + return locale.getFieldByKeymap("dumpkeys_charset", + self.Get('os_locale_keymap')) + else: + return locale.getFieldByLang("dumpkeys_charset", + self.Get('os_locale_lang')) + + def get_os_clock_timezone(self): + """timezone for clock""" + zoneinfodir = "/usr/share/zoneinfo/" + localtimefile = "/etc/localtime" + # try get timezone from kernel calculate param + timezone = self.getValueFromCmdLine("calculate",2) + if timezone and \ + os.path.exists(os.path.join(zoneinfodir,timezone)): + return timezone + # get timezone from localtime symlink + if os.path.lexists(localtimefile): + return os.readlink(localtimefile).replace(zoneinfodir,"") + return "UTC" + + def get_os_clock_type(self): + """type of clock (UTC or local)""" + clockTypeFile = ['/etc/conf.d/clock','/etc/conf.d/hwclock'] + for f in clockTypeFile: + clock = self.getValueFromConfig(f,"clock") + if clock: + if clock.upper() == 'UTC': + return clock.upper() + elif clock.lower() == 'local': + return clock.lower() + return "local" diff --git a/pym/cl_help.py b/pym/cl_help.py deleted file mode 100644 index 20ca654..0000000 --- a/pym/cl_help.py +++ /dev/null @@ -1,375 +0,0 @@ -#-*- coding: utf-8 -*- - -# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import getopt -import sys -from cl_string import prettyColumnStr - -pcs = prettyColumnStr - -class opt: - def __init__(self,shortOpt,longOpt = []): - """ Длинные и короткие опции командной строки допустимые в программе - a - короткая опция - >program -a - - a: - короткая опциия со значением - >program -a 10 - - a:: - короткая опциия у которой может быть или не быть значение - >program -a - >program -a 15 - - "ha:" - значение параметра shortOpt - две опции h - без значения, a - со значением - - help - длинная опция без значения - test= - длинная опция со значением - - ["help","test="] - значение парамера longOpt - >program -a - две опции help - без значения, test - со значением - """ - self.shortOpt = shortOpt - self.longOpt = longOpt - self.sysArgv = sys.argv[1:] - - def getopt(self): - try: - opts, args = getopt.getopt(self.sysArgv,self.shortOpt,self.longOpt) - except getopt.GetoptError: - self.handlerErrOpt() - sys.exit(1) - for option, value in opts: - if len(option) == 2: - option = option[1:] - else: - option = option[2:] - self.handlerOpt(option,value) - for param in args: - self.handlerParam(param) - - def handlerErrOpt(self): - # Обработчик в случае неправильных параметров - pass - - def handlerOpt(self,option,value): - # Обработчик (параметр значение) - pass - - def handlerParam(self,param): - # Обработчик хвостов (значение) - pass - -class cl_help: - """Объект для работы со справкой, и обработкой параметров. - - Конструктор __init__ должен определить следующие переменные: - - self.chapter список разделов справки, каждый элементы состоит из - имени раздела, флаг видимый/скрытый, кол-во переводов строк - после названия раздела, количество строк после раздела, - тип раздела - Пример: [("Copyright",False,0,2),"options"] - self.relService словарь связей сервисов и действующих опций - ключ - название сервиса, значение - список отображаемых - разделов отмеченных как "options" - Пример: {"samba":[_("Common options"), - _("Service Samba options")]} - self.relOptions словарь связей длинных опций помощи и выводимых разделов - помощи с опциями - ключ - параметр справки, значение список отображаемых - разделов справки - Пример: {"help-ldap":[_("Common options"), - _("Service LDAP options)]} - self.progName словарь имена используемых программ и их номера для - доступа к переменным - Пример: {'cl-groupadd':0, 'cl-groupdel':1} - self.data список данных для справки, каждый элемент словарь: - progAccess: список номеров программ отображающих - Пример: {'progAccess':(0,), - 'shortOption':"g", - 'longOption':"gid", - 'optVal':"GID", - 'helpChapter':_("Options"), - 'help':_("use GID for the new group") - }, - после заполнения параметров необходимо выполнить - self._cl_help__setParamHelp() для заполнения справки - - """ - def __init__(self, cmdName): - # ширина консоли взята за 80 - # -1 чтобы компенсировать расстрояние между колонками - self.consolewidth = 79 - self.column_width = 32 - self.cmdName = cmdName - #короткие опции командной строки - self.shortOpt = [] - #длинные опции командной строки - self.longOpt = [] - # массив разделов (заполняется в __setParamHelp) - self.chapterBloc = [] - #optEnd = "" - #if "user" in self.cmdName and not "mod" in self.cmdName: - #optEnd = _("user") - #elif "group" in self.cmdName and not "mod" in self.cmdName: - #optEnd = _("group") - #self.__setParamHelp() - - def getChapterNumber(self,NameChapter): - """Получить номер раздела по имени""" - num = 0 - for i in self.chapter: - if i[0] == NameChapter: - return num - num += 1 - return False - - def __setParamHelp(self): - """Внутренняя функция формирования справки по данным - - Перебирает все элементы списка data, проверяет их на доступность - данной программы, разбирает опции на среди data и формирует - для по ним справку. - """ - # сформировать нужное количество блоков раздела - self.chapterBloc = [""]*len(self.chapter) - # - sp = {} - i = 0 - # перебираем все элементы справки собираем элементы опции - # так же формируем разделы не опции - for par in self.data: - # перебираем только те опции, которые принадлежат команде - if self.access(par): - # есть короткая (возможно есть и длинная) - if par.has_key("shortOption"): - sp[par["shortOption"]+":"+par["helpChapter"]] = i - # есть только длинная опция - elif par.has_key("longOption"): - sp[par["longOption"]+":"+par["helpChapter"]] = i - # формирование разделов не опций - else: - helpTxt = par['help'] - numChapter = self.getChapterNumber(par['helpChapter']) - self.addChapterHelp(numChapter,helpTxt) - i += 1 - # перебираем все "собранные" опции - # опции перебираются по порядку в списке date - # для сортировки по ключам следует применить код: - # for index in sorted(sp.keys()): - # par = self.data[sp[index]] - for index in sorted(sp.values()): - par = self.data[index] - numChapter = self.getChapterNumber(par['helpChapter']) - # если есть и короткая и длинная - if "shortOption" in par and "longOption" in par: - paraminfo = "-%s, --%s "%(par["shortOption"],par["longOption"]) - # если есть только короткая - elif "shortOption" in par: - paraminfo = "-%s "%par["shortOption"] - # если только длинная - else: - paraminfo = "--%s "%par["longOption"] - # если указан параметр для опции - if "optVal" in par: - optVal = par["optVal"] - else: - optVal = "" - - # вывод вида: " [-o, ][--option] [PARAM]" "helpstring" - helpTxt = pcs(" "+paraminfo+optVal, self.column_width, \ - par['help'], self.consolewidth-self.column_width) - # добавить строку в нужный раздел - self.addChapterHelp(numChapter,helpTxt) - - def getHelp(self, optionsChapters=False): - """Выдать справку. - - Выдает справку в случае если указан optionsChapters, то фильтрует по - типу разделов. - - Параметры: - optionsChapters Flase или список опциональных разделов для - отображения - - Возвращаемые параметры: - Строка со справкой. - """ - # Выдать справку - help = "" - # перебираем все элементы справочных блоков - iterChapterBloc = iter(self.chapterBloc) - # перебираем все разделы по параметрам - for (nameChapter, visibleChapter, beforeStrChapter, \ - afterStrChapter, typeChapter) in self.chapter: - # получаем следующий блок (т.о. textChapterBloc соответ, chapter) - textChapterBloc = iterChapterBloc.next() - # если тип раздела опциональный - if optionsChapters and typeChapter=="options": - # проверяем нужно ли его отображать - if not (nameChapter in optionsChapters): - continue - bef = "\n"*beforeStrChapter - aft = "\n"*afterStrChapter - # если блок не пустой и раздел отображаемый - if len(textChapterBloc) > 0: - if visibleChapter: - help += nameChapter + ": " + bef - help += textChapterBloc + aft - help = help.rstrip()+"\n" - return help - - def addChapterHelp(self, numChapter, helpTxt): - """Добавить в раздел помощи numChapteк тектстовую строку helpTxt - - Параметры: - numChapter номер раздела в который нужно добавить данные справки - helpTxt строка, содержащая данные - """ - self.chapterBloc[numChapter] += helpTxt - return True - - def addData(self,dataHash): - # На будущее (добавляет опции) - self.data.append(dataHash) - return True - - def handleCheckAccess(self,dataHash): - """Замещаемый дополнительный обработчик проверки - доступности опции. - - Входные параметры: - dataHash элементы списка данных справки (self.data) - """ - return True - - def access(self,dataHash): - """Доступна ли опция вызывающей программе - - Параметры: - dataHash словарь элемент типа self.data - - Возвращаемые параметры: - True/False доступна/недоступна - """ - # доступна ли опция вызывающей программе - # опция без progAccess доступна - numProg = self.progName[self.cmdName] - if 'progAccess' in dataHash: - if numProg in dataHash['progAccess']: - # вызов дополнительной проверки доступа к опции - return self.handleCheckAccess(dataHash) - else: - return False - else: - # вызов дополнительной проверки доступа к опции - return self.handleCheckAccess(dataHash) - - def getTypeChapter(self, nameChapter): - """Получить тип раздела по его имени - - Параметры: - nameChapter название раздела - - Возвращаемые параметры: - строка тип раздела - Flase(Boolean) такой раздел отсутствует - """ - # фильтруем список по имени раздела, помещаем в список тип раздела - filtered = [typeChapter for name, na, na, na, typeChapter \ - in self.chapter if name == nameChapter] - # если среди фильтрованных есть хоть один элемент - if len(filtered) > 0: - # возвращаем - он запрашиваемый - return filtered[0] - else: - # такой раздел отсутствует - return False - - def clearAllOpt(self): - """Очистить все опции, полученные посредством getAllOpt""" - if len(self.shortOpt) > 0: - self.shortOpt = [] - if len(self.longOpt) > 0: - self.longOpt = [] - return True - - def getAllOpt(self,typeOpt="all", optionsChapters=False): - """Получить все доступные опции - - Параметры: - typeOpt 'short'/'long'/'all', вернуть короткие или длинные - опции или все (возвращаются кортежем) - optionsChapters фильтр для опций по типам разделов (список,кортеж) - - Возвращаемые параметры: - строка коротки или список строк длинных опций ('hb:c:wg:G:k:ms:u:') - """ - # Выдать все действующие опции - if typeOpt=="short" or typeOpt=="all": - if len(self.shortOpt) == 0: - for par in self.data: - if optionsChapters and\ - self.getTypeChapter(par['helpChapter'])=="options": - if not (par['helpChapter'] in optionsChapters): - continue - if par.has_key("shortOption") and self.access(par): - if par.has_key("optVal"): - self.shortOpt.append(par["shortOption"]+':') - else: - self.shortOpt.append(par["shortOption"]) - if typeOpt=="long" or typeOpt=="all": - if len(self.longOpt) == 0: - for par in self.data: - if optionsChapters and\ - self.getTypeChapter(par['helpChapter'])=="options": - #print par["longOption"] - if not (par['helpChapter'] in optionsChapters): - continue - if par.has_key("longOption") and self.access(par): - if par.has_key("optVal"): - self.longOpt.append(par["longOption"]+'=') - else: - self.longOpt.append(par["longOption"]) - if typeOpt=="short": - return "".join(self.shortOpt) - elif typeOpt=="long": - return self.longOpt - elif typeOpt=="all": - return ("".join(self.shortOpt),self.longOpt) - - def getShortOpt(self,option): - """Из любой опции получить короткую опцию. - - Фильтрация также происходит и по названию команды. - - Параметры: - option запрашиваемая опция - - Возвращаемые параметры: - короткая опция, если же для длинной опции нет короткой, возвращается - пустая строка. - """ - # Из любой опции получаем короткую опцию - for par in self.data: - if par.has_key("shortOption") and self.access(par): - if (par.has_key("longOption") and\ - par["longOption"] == option) or \ - par["shortOption"] == option: - return par["shortOption"] - return "" diff --git a/pym/cl_lib.py b/pym/cl_lib.py deleted file mode 100644 index 605203b..0000000 --- a/pym/cl_lib.py +++ /dev/null @@ -1,40 +0,0 @@ -#-*- coding: utf-8 -*- - -# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys -from cl_utils import removeDir -from cl_print import color_print - -import cl_lang -tr = cl_lang.lang() -tr.setLocalDomain('cl_lib') -tr.setLanguage(sys.modules[__name__]) - -class shareFile(color_print): - """Общие методы для работы с файлами""" - - def removeDir(self, rmDir): - """Рекурсивное удаление директории - - входной параметр директория или результат сканирования файлов (объект) - """ - try: - removeDir(rmDir) - except (OSError, Exception), e: - print e - self.printERROR(_("Can not delete dir: " ) + rmDir) - return False - return True \ No newline at end of file diff --git a/pym/cl_log.py b/pym/cl_log.py index ab65d0e..46acdf7 100644 --- a/pym/cl_log.py +++ b/pym/cl_log.py @@ -13,7 +13,6 @@ # 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 index 0c6ca8e..3400dbe 100644 --- a/pym/cl_overriding.py +++ b/pym/cl_overriding.py @@ -21,7 +21,7 @@ def __findFileMO(domain, localedir=None, languages=None, all=0): замена gettext.find""" if localedir is None: - localedir = _default_localedir + localedir = gettext._default_localedir if languages is None: languages = [] for envar in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'): diff --git a/pym/cl_template.py b/pym/cl_template.py index 83fc1af..ac24b1c 100644 --- a/pym/cl_template.py +++ b/pym/cl_template.py @@ -24,18 +24,35 @@ import subprocess import types import random import string -from cl_utils import _error, scan, _toUNICODE, removeDir, getModeFile -from cl_overriding import exit -import cl_lang +import time + + +from cl_ldap import ldapFun +# Переопределение exit +import cl_overriding + +from cl_utils import _error, _toUNICODE +import cl_lang tr = cl_lang.lang() tr.setLocalDomain('cl_lib') tr.setLanguage(sys.modules[__name__]) + class _terms(_error): """Вычисление условий применяемых в шаблонах """ + # регулярное выражение для не версии + _re_not_Version = re.compile("[^0-9\.]|^$") + # регулярное выражение для функции + _reFunction = re.compile(\ + "([a-zA-Z0-9\_\-]+)\([a-zA-Z0-9_\-\+\,\*\/\.\'\"~]+\)") + # Регулярное выражение для названия переменной + _reDenyName = re.compile("[^a-zA-Z0-9\_\-]") + # Регулярное выражение для сравниваемого значения + _reDenyValue = re.compile("[^0-9a-zA-Z_\.-]") + def _convertVers(self, verA, verB): """Конвертирование номеров версий для корректного сравнения """ @@ -66,27 +83,6 @@ class _terms(_error): 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): """Вычисление логических выражений для условий @@ -103,6 +99,7 @@ class _terms(_error): if k in term: term = term.replace(k,trm[k]) trs = term.split(" ") + flagOR = False for t in trs: flagRule = False for sepF in rule: @@ -110,7 +107,6 @@ class _terms(_error): flagRule = True vals = t.split(sepF) break - if not flagRule: flagLog = False for k in trm.values(): @@ -121,19 +117,34 @@ class _terms(_error): self.setError("'%s'"%term + " " + _("incorrect")) self.setError (textError) return False - elif k == " or ": - listEqual.append(k) + else: + # если and + if k == " and ": + flagOR = False + if listEqual == [] or False in listEqual: + listEqual = [] + break + else: + listEqual = [True] + # если or + else: + if flagOR: + continue + if False in listEqual: + listEqual = [] + else: + listEqual = [True] + flagOR = True else: + if flagOR: + continue #проверка на допустимость названия переменной - reDenyName = re.compile("[^a-zA-Z0-9\_\-]") flagFunction = False - if reDenyName.search(vals[0]): + if self._reDenyName.search(vals[0]): #проверка на допустимость функции flagError = True if function: - reFunction = re.compile(\ - "([a-zA-Z0-9\_\-]+)\([a-zA-Z0-9_\-\+\,\*\/\.]+\)") - searchFunct = reFunction.search(vals[0]) + searchFunct = self._reFunction.search(vals[0]) if searchFunct: flagError = False flagFunction = True @@ -142,17 +153,14 @@ class _terms(_error): self.setError(textError) return False #проверка на допустимость значения - reDenyValue = re.compile("[^0-9a-zA-Z_\.-]") - if reDenyValue.search(vals[1]): + if self._reDenyValue.search(vals[1]): self.setError("'%s'"%term + " " + _("incorrect")) self.setError(textError) return False flagIntTypeVar = None if flagFunction: valVars = function("#-%s-#"%vals[0]) - if valVars == "": - flagFunction = False - if valVars == False: + if valVars is False: self.setError("'%s'"%term + " " + _("incorrect")) self.setError(textError) return False @@ -169,120 +177,153 @@ class _terms(_error): flagIntTypeVar = True else: flagIntTypeVar = False + else: + if valVars == "" and\ + not self._re_not_Version.search(vals[1]): + valVars = "0" + elif vals[1] == "" and\ + not self._re_not_Version.search(valVars): + vals[1] = "0" else: try: valVars = self.objVar.Get(vals[0]) except self.objVar.DataVarsError, e: print textError print e - exit(1) + cl_overriding.exit(1) + # Номера версий для ini + flagNotIniFunct = True + # Два значения не пусты + flagNotEmptyVals = not (valVars == "" and vals[1] == "") + if flagFunction and flagNotEmptyVals and\ + searchFunct.group(1) == "ini": + # Проверка значения на версию + if not self._re_not_Version.search(valVars) and\ + not self._re_not_Version.search(vals[1]): + verFile, verVar = self._convertVers(vals[1],valVars) + exec(\ + "res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")") + if res: + listEqual.append(True) + else: + listEqual.append(False) + flagNotIniFunct = False # Cравниваем номера версий - if "_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: + if flagNotIniFunct: + if flagNotEmptyVals and\ + ("_ver" in vals[0] or\ + (flagFunction and searchFunct.group(1) == "pkg") or\ + (flagFunction and searchFunct.group(1) == "load" and\ + re.search("\(\s*ver\s*,",vals[0]))): + # Проверка значения на версию + if self._re_not_Version.search(vals[1]): self.setError("'%s'"%term + " " + _("incorrect")) - self.setError (textError) + self.setError (_("Value is not version")) return False - valVar = valVars - exec("res=(%d%s%d)"%(valVar,sepF,valFile)) + # Проверка значения функции на версию + if self._re_not_Version.search(valVars): + self.setError("'%s'"%term + " " + _("incorrect")) + self.setError (_("Value function is not version")) + return False + verFile, verVar = self._convertVers(vals[1],valVars) + exec("res=("+"'"+verVar+"'"+sepF+"'"+verFile+"'"+")") if res: listEqual.append(True) else: listEqual.append(False) + flagNotIniFunct = False else: - if sepF == "!=" or sepF == "==": + if flagIntTypeVar == None: + flagIntTypeVar = True + try: + valVars = int(valVars) + except: + flagIntTypeVar = False + if flagIntTypeVar: if not vals[1].strip(): - vals[1] = "" - valFile = vals[1] + vals[1] = 0 + try: + valFile = int(vals[1]) + except: + self.setError("'%s'"%term +" " +_("incorrect")) + self.setError (textError) + return False valVar = valVars - exec("res=("+'"""'+valVar+'"""'+sepF+"'"+valFile+\ - "'"+")") + exec("res=(%d%s%d)"%(valVar,sepF,valFile)) if res: listEqual.append(True) else: listEqual.append(False) else: - if valVars == "": - listEqual.append(False) + 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: - self.setError("'%s'"%term + " "\ - + _("incorrect")) - self.setError (textError) - return False + if not flagNotEmptyVals: + listEqual.append(False) + else: + self.setError("'%s'"%term + " "\ + + _("incorrect")) + self.setError (textError) + return False + if listEqual == [] or False in listEqual: + return False + return True #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:]) + #return res -class fileHeader(shareHeader, _terms): +class fileHeader(_terms): """Обработка заголовков шаблонов и конфигурационных файлов """ # Допустимые параметры заголовка - allowParam = ("format", "comment", "append", "force", "link", "mirror", - "symbolic", "chmod", "chown", "path", "name") - - # параметры без значения - listParNotVal = ("symbolic", "force", "mirror") - + allowParam = ["format", "format_conf", "comment", "append", "force", + "link", "mirror", "symbolic", "chmod", "chown", "name", + "path"] + # Корректность заголовка + headerCorrect = True + + # Тип шаблона + fileType = "" + # Тип вставки шаблона + typeAppend = "" # Возможные типы вставки шаблонов - _fileAppend = ("join", "before", "after", "replace", "remove", "skip") - - + _fileAppend = "join", "before", "after", "replace", "remove", "skip" + # Интерпретатор (#!/bin/bash) (#!/usr/bin/python) + execStr = "" + # Символ комментария + comment = False + # Выражение для поиска строки интерпретатора + reExecStr = re.compile("^#!.+\s*",re.I) # условные операторы terms = ('>', '<', '==', '!=', '>=', '<=') - # параметры без значения - #listParNotVal = ("symbolic", "force", "mirror") - # Форматы файлов для которых метод объединения replace если он не задан - #replaceFormats = ("raw","bin") - - def delHeaderConfFile(self, text, comment): - """Удаляет заголовок в тексте конфигурационного файла""" - if comment and text: - # Удаление Заголовка Calculate в конфигурационном файле + listParNotVal = ("symbolic", "force", "mirror") + # Результат вычисления условия в заголовке + headerTerm = True + # Сообщение о ошибке + errorMessage = "" + + def __init__(self, text, comment=False, fileType=False, objVar=False, + function=False): + self.body = text + # Объект с переменными + self.objVar=objVar + # Параметры описанные в заголовке файла шаблона + self.params = {} + # некорректные параметры + incorrectParams = set([]) + # Удаление Заголовка Calculate + if comment: # В случае текста XML if type(comment) == types.TupleType and len(comment) == 2: _titleList = (_("Modified"), _("File of a template")) @@ -299,9 +340,8 @@ class fileHeader(shareHeader, _terms): if reS: textBody = textUnicode[:reS.start()]+textUnicode[reS.end():] if textBody: - return textBody.encode("UTF-8") + self.body = textBody.encode("UTF-8") else: - # В остальных случаях reCalcHeader =\ re.compile("\s*%s\-+\s+%s.+Calculate.+\s+%s.+\s+%s\-+\s?"%(\ comment, @@ -312,173 +352,212 @@ class fileHeader(shareHeader, _terms): re.M|re.I) reS = reCalcHeader.search(text) if reS: - return text[reS.end():] - return text + self.body = text[reS.end():] - 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" + if fileType != False: + if fileType=="bin": + self.params["format"] = fileType + self.fileType = self._getType() + self.typeAppend = self._getAppend() 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 - # текстовый шаблон без заголовка + textLines = text.splitlines() + if textLines: + textLine = textLines[0] + rePar = re.compile("\s*#\s*calculate\s+",re.I) + reP = rePar.search(textLine) + if reP: + reL = False + reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M) + reLs = reLns.search(text) + if reLs: + reL = reLs + paramLine = text[reP.end():reLs.end()] + paramLine = paramLine.replace("\\"," ") + else: + reLn = re.compile("\n") + reL = reLn.search(text) + paramLine = textLine[reP.end():] + if reL: + self.body = text[reL.end():] + else: + self.body = "" + paramList = re.split("\s+",paramLine) + if paramList: + for i in paramList: + foundTerm = False + for term in self.terms: + if term in i: + foundTerm = True + if function: + rezTerm = self._equalTerm(i,\ + _("header template not valid: ") + \ + i,function) + else: + rezTerm = self._equalTerm(i,\ + _("header template not valid: ") + \ + i) + if not rezTerm: + self.headerTerm = False + break + if not foundTerm: + par = i.split("=") + if len(par) == 1: + if i in self.listParNotVal: + self.params[i] = "True" + else: + if i.strip(): + incorrectParams = set([i]) + elif len(par) == 2: + self.params[par[0]] = par[1] + + self.comment = self._getComment() + self.fileType = self._getType() + self.typeAppend = self._getAppend() + reExecRes = self.reExecStr.search(self.body) + if reExecRes: + self.execStr = self.body[reExecRes.start():reExecRes.end()] + self.body = self.body[reExecRes.end():] + if not incorrectParams: + incorrectParams = set(self.params.keys()) - set(self.allowParam) + if incorrectParams: + self.headerTerm = False + self.headerCorrect = False + self.errorMessage = _("incorrect header parameters - '%s'")\ + % " ".join(list(incorrectParams)) + + def _getType(self): + """Выдать тип файла""" + if self.params.has_key("format"): + return self.params["format"] else: - 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 + return "raw" + def _getAppend(self): + """Выдать тип добавления файла""" + if self.params.has_key("append") and self.params["append"] in\ + self._fileAppend: + return self.params["append"] + else: + if self.fileType != "raw" and self.fileType != "bin" and\ + self.fileType != "": + self.params["append"] = "join" + return "join" + self.params["append"] = "replace" + return "replace" + + def _getComment(self): + """Выдать символ комментария файла""" + if self.params.has_key("comment"): + return self.params["comment"] + else: + return False -class dirHeader(shareHeader, _terms): +class dirHeader(_terms): """Обработка заголовков шаблонов директорий """ # Допустимые параметры заголовка - allowParam = ("append", "chmod", "chown", "path", "name") + allowParam = ["append", "chmod", "chown", "name", "path"] + # Корректность заголовка + headerCorrect = True + + # Тип вставки шаблона + typeAppend = "" # Возможные типы вставки шаблонов - _fileAppend = ("join", "remove", "skip") + _fileAppend = "join", "remove", "skip" # условные операторы terms = ('>', '<', '==', '!=', '>=', '<=') - - - def getPropertyTemplate(self, text, objVar, function, fileName): - """Получаем свойства шаблона из текста шаблона""" + # параметры без значения + listParNotVal = ("symbolic", "force") + # Результат вычисления условия в заголовке + headerTerm = True + # Сообщение о ошибке + errorMessage = "" + + def __init__(self, text, objVar=False, function=False): + self.body = text # Объект с переменными self.objVar=objVar # Параметры описанные в заголовке файла шаблона - params = {} - # Некорректные параметры + self.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" + + textLines = text.splitlines() + flagErrorBody = False + if textLines: + textLine = textLines[0] + rePar = re.compile("\s*#\s*calculate\s+",re.I) + reP = rePar.search(textLine) + if reP: + reL = False + reLns = re.compile(r"\A([^\\\n]*\\\n)+[^\n]*\n*",re.M) + reLs = reLns.search(text) + if reLs: + reL = reLs + paramLine = text[reP.end():reLs.end()] + paramLine = paramLine.replace("\\"," ") + else: + reLn = re.compile("\n") + reL = reLn.search(text) + paramLine = textLine[reP.end():] + if reL: + self.body = text[reL.end():] + else: + self.body = "" + if self.body.strip(): + self.headerTerm = False + self.headerCorrect = False + self.errorMessage = _("incorrect text in template: '%s'")\ + %self.body + flagErrorBody = True + if not flagErrorBody: + paramList = re.split("\s+",paramLine) + if paramList: + for i in paramList: + foundTerm = False + for term in self.terms: + if term in i: + foundTerm = True + if function: + rezTerm = self._equalTerm(i,\ + _("header template not valid: ") + \ + i,function) + else: + rezTerm = self._equalTerm(i,\ + _("header template not valid: ") + \ + i) + if not rezTerm: + self.headerTerm = False + break + if not foundTerm: + par = i.split("=") + if len(par) == 1: + if i in self.listParNotVal: + self.params[i] = "True" + else: + if i.strip(): + incorrectParams = set([i]) + elif len(par) == 2: + self.params[par[0]] = par[1] + self.typeAppend = self._getAppend() + if not flagErrorBody: + if not incorrectParams: + incorrectParams = set(self.params.keys()) - set(self.allowParam) if incorrectParams: - headerTerm = False - self.setError(_("incorrect header parameters - '%s'")\ - %" ".join(list(incorrectParams))) - params["_apply"] = headerTerm - # текстовый шаблон без заголовка + self.headerTerm = False + self.headerCorrect = False + self.errorMessage = _("incorrect header parameters - '%s'")\ + % " ".join(list(incorrectParams)) + + def _getAppend(self): + """Выдать тип добавления директории""" + if self.params.has_key("append") and self.params["append"] in\ + self._fileAppend: + return self.params["append"] else: - 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 - + return "join" class objShare: """Общий клас для объектов, наследуем @@ -657,6 +736,7 @@ class xmlCaption: #Заголовок области XML нода self.caption = False + def createCaption(self, doc, name, quotes, action=False): """Создание заголовка области""" tmpNode = xmlNode() @@ -1194,6 +1274,17 @@ class xmlDoc: fieldsVal[0]) return fieldValue[0].firstChild.nodeValue + def getAllAreas(self): + """Выдает все области""" + return xpath.Evaluate('descendant::area', self.body) + + def getArea(self, nameArea, xmlArea): + """По имени области находит области (первый потомок xmlArea)""" + namesAreaComare = xpath.Evaluate(\ + "child::area/child::caption[child::name='%s']" %(nameArea), + xmlArea) + return map(lambda x: x.parentNode, namesAreaComare) + def joinArea(self, baseNode, xmlNewArea): """Объединяет область c областью Body (xmlNewArea c baseNode)""" @@ -1787,11 +1878,10 @@ class blocText: return False -class _file(_error, scan): +class _file(_error): """Класс для работы с файлами """ - def __init__(self): # Имя файла старого шаблона self.nameFileOld = "" @@ -1806,15 +1896,22 @@ class _file(_error, scan): # Дескриптор файла старого шаблона self.FO = False - def getFileType(self, fileName=""): + # Владелец и режим доступа файла шаблона + self._mode = False + self._uid = False + self._gid = False + + self.openNewFile = self.__openNewFile + self.absFileName = self.__absFileName + self.closeNewFile = self.__closeNewFile + + def getFileType(self, template="New"): """выдать тип файла (text, bin) """ - if fileName: - nameFile = fileName - elif self.nameFileNew: + if self.nameFileNew: nameFile = self.nameFileNew - else: - return "" + if template=="Old" and self.nameFileOld: + nameFile = self.nameFileOld sp = subprocess.Popen("file '%s'"%nameFile, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, shell=True) @@ -1837,7 +1934,38 @@ class _file(_error, scan): ferr.close() return retText - def absFileName(self, nameFile): + def scanDirs(self, templatesDirs): + """Сканирует дерево каталогов выдает два списка: директории, файлы""" + dirs = [] + class dirTempl: + def __init__(self): + self.baseDir = False + self.dirs = [] + self.files = [] + self.links = [] + self.sockets = [] + def getFilesDir(dirP, dirname,names): + for nameFile in names: + absNameFile = dirname + "/" + nameFile + if os.path.islink(absNameFile): + dest = absNameFile + src = os.readlink(absNameFile) + dirP.links.append((src,dest)) + elif os.path.isfile(absNameFile): + dirP.files.append(absNameFile) + elif os.path.isdir(absNameFile): + dirP.dirs.append(absNameFile) + elif stat.S_ISSOCK(os.stat(absNameFile)[stat.ST_MODE]): + dirP.sockets.append(absNameFile) + for templateDir in templatesDirs: + if templateDir: + dirP = dirTempl() + dirP.baseDir = templateDir + dirs.append(dirP) + os.path.walk(templateDir,getFilesDir, dirP) + return dirs + + def __absFileName(self, nameFile): """Вычисление пути к файлу""" pathList = nameFile.split("/") chortNameFile = pathList.pop() @@ -1857,19 +1985,34 @@ class _file(_error, scan): except: self.setError (_("not open file:" ) + self.nameFileOld) return False + self.FO.flush() return True + def getModeFile(self, nameFile): + """Выдает информацию о файле - def openNewFile(self, nameFileNew): + права файла, владелец, группа файла (777,test, group) + """ + fd = os.open(nameFile, os.O_RDONLY) + fst = os.fstat(fd) + uid = fst.st_uid + gid = fst.st_gid + mode = stat.S_IMODE(fst.st_mode) + os.close(fd) + return (mode,uid,gid) + + def __openNewFile(self, nameFileNew): """Открыть файл шаблона""" + FN = False try: FN = open (nameFileNew, "r") + self._mode,self._uid,self._gid = self.getModeFile(nameFileNew) except: self.setError (_("not open file:" ) + nameFileNew) return False return FN - def closeNewFile(self): + def __closeNewFile(self): if self.FN: self.FN.close() self.FN = False @@ -1879,50 +2022,52 @@ class _file(_error, scan): self.FO.close() self.FO = False - def __openOldFile(self, nameFileOld, funcCreateFile, removeLink): - """Открыть конфигурационный файл""" + def __openOldFile(self, nameFileOld, mode, uid, gid): + """Октрыть конфигурационный файл""" FO = False try: - if os.path.islink(nameFileOld) and removeLink: + if os.path.islink(nameFileOld): # если ссылка то удаляем её os.unlink(nameFileOld) FO = open (nameFileOld, "r+") except: - #try: - # Создаем новый файл - funcCreateFile.__call__(nameFileOld) - FO = open(nameFileOld, "r+") - #except: - #self.setError (_("not open file:" ) + nameFileOld) - #return False + try: + fd = os.open(nameFileOld, os.O_CREAT) + os.close(fd) + os.chmod(nameFileOld, mode) + os.chown(nameFileOld,uid,gid) + FO = open(nameFileOld, "r+") + except: + self.setError (_("not open file:" ) + nameFileOld) + return False return FO - def openFiles(self, nameFileNew, nameFileOld, funcCreateFile, seekFileNew, - removeLink): + def openFiles(self, nameFileNew, nameFileOld): """Открывает шаблон и конфигурационный файл""" self.oldTemplate = "" self.newTemplate = "" self.closeFiles() - self.nameFileOld = self.absFileName(nameFileOld) - self.nameFileNew = self.absFileName(nameFileNew) - self.FN = self.openNewFile(self.nameFileNew) - self.FO = self.__openOldFile(self.nameFileOld,funcCreateFile,removeLink) - if not (self.FN and self.FO): - return False - self.FN.seek(seekFileNew) - self.newTemplate = self.FN.read() - self.oldTemplate = self.FO.read() - return True + self.FN = False + self.FO = False + self.nameFileOld = self.__absFileName(nameFileOld) + self.nameFileNew = self.__absFileName(nameFileNew) + self.FN = self.__openNewFile(self.nameFileNew) + self.FO = self.__openOldFile(self.nameFileOld, + self._mode, self._uid, self._gid) + if self.FN and self.FO: + self.newTemplate = self.FN.read() + self.oldTemplate = self.FO.read() def __del__(self): self.closeFiles() def closeFiles(self): """Закрытие файлов""" - self.closeNewFile() + self.__closeNewFile() self.__closeOldFile() + class utfBin: """Класс для преобразования в utf-8 @@ -1965,14 +2110,23 @@ class utfBin: if i == 0 and symbols[i] != '_fb_': break elif i > 0 and symbols[i] != '_nb_': - break - i += 1 + break if lenTail>1 and lenTail != i: return (False,1) if i > 0: result = True return (result, i) + + def _intToChar(self, x): + he = hex(x)[2:] + exec("ret = '\\x%s'" %he) + return ret + + def _hexToChar(self, he): + exec("ret = '\\x%s'" %he) + return ret + def encode(self, text): """Кодирует смешанный формат в UTF-8""" ind = 0 @@ -1988,8 +2142,8 @@ class utfBin: i+=1 while 1: if utf[ind] == '_fb_': - res, l = self._sumbUtf(utf[ind:(ind+lenUtf[ind])],lenUtf[ind]) - if res == False: + res, l = self._sumbUtf(utf[ind:],lenUtf[ind]) + if res is False: indErr.append(ind) if l>0: ind +=l @@ -2037,6 +2191,9 @@ class utfBin: endInd = erEl[2] + 1 + deltaInd textOut = textOut[:startInd] + erEl[1] + textOut[endInd:] deltaInd += len(erEl[1])-(erEl[2]-erEl[0]+1) + #if i == 1: + #break + #i += 1 return textOut def decode(self, text): @@ -2058,7 +2215,7 @@ class utfBin: for ch in hexString: if i>=1: hexCode += ch - stringInsert += chr(int(hexCode, 16)) + stringInsert += self._hexToChar(hexCode) hexCode = "" i = 0 else: @@ -2068,6 +2225,134 @@ class utfBin: resS = reVar.search(textTemplateTmp) return textTemplateTmp + def getUserDataInLDAP(self, userName): + """Получаем домашнюю директорию пользователя из LDAP""" + if not self.conLdap: + data = self.getLDAPDataInConfig() + if not data: + return "" + serverName, usersDN, bindDN, bindPW = data + # Подключаемся к LDAP + ldapObj = ldapFun(bindDN, bindPW, serverName) + if self.getError(): + return "" + self.conLdap = ldapObj.conLdap + searchScope = ldap.SCOPE_ONELEVEL + searchFilter = "uid=%s" %(userName) + retrieveAttributes = ["uidNumber", + "gidNumber" + "homeDirectory"] + resSearch = ldapObj.ldapSearch(usersDN, searchScope, + searchFilter, retrieveAttributes) + if resSearch: + if resSearch[0][0][1].has_key('uidNumber') and\ + resSearch[0][0][1].has_key('gidNumber') and\ + resSearch[0][0][1].has_key('homeDirectory'): + uid = searchUser[0][0][1]['uidNumber'][0] + gid = searchUser[0][0][1]['gidNumber'][0] + homeDir = resSearch[0][0][1]['homeDirectory'][0] + return uid, gid, homeDir + return "" + + +class processingTemplates: + """Класс для обработки шаблонов""" + + def processingFile(self, path, prefix): + """Обработка в случае шаблона файла""" + return True + + def processingDirectory(self, path, prefix): + """Обработка в случае директории если возвращаем None то пропуск дир.""" + return True + + def scanningTemplates(self, scanDir, skipFile=[], skipDir=[], + prefix=None, flagDir=False): + """Сканирование и обработка шаблонов в директории scanDir""" + ret = True + if not prefix: + prefix = os.path.join(scanDir,"")[:-1] + if not flagDir: + # проверка корневой директории + retDir = self.processingDirectory(scanDir, scanDir) + if retDir is None: + return None + elif retDir is False: + return False + if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]): + for fileOrDir in sorted(os.listdir(scanDir)): + absPath = os.path.join(scanDir,fileOrDir) + relPath = absPath.split(prefix)[1] + stInfo = os.lstat(absPath) + statInfo = stInfo[stat.ST_MODE] + if stat.S_ISREG(statInfo): + # Обработка файла + if relPath in skipFile: + continue + if not self.processingFile(absPath, prefix): + ret = False + break + elif stat.S_ISDIR(statInfo): + # Обработка директории + if relPath in skipDir: + continue + retDir = self.processingDirectory(absPath, prefix) + if retDir is None: + continue + elif retDir is False: + ret = False + break + ret = self.scanningTemplates(absPath, skipFile, + skipDir, prefix, True) + if ret is False: + break + return ret + +class templateFormat: + """Методы получения классов и объектов форматов шаблонов""" + # Импортированные классы поддерживаемых форматов шаблонов + importFormats = {} + + def getClassObj(self, nameClassTemplate): + """Создает класс шаблона по имени""" + if nameClassTemplate in self.importFormats: + classFormat = self.importFormats[nameClassTemplate] + else: + try: + classFormat = getattr(__import__("format.%s"%nameClassTemplate, + globals(), locals(), + [nameClassTemplate]), + nameClassTemplate) + except (ImportError, AttributeError): + #Создаем объект из self.newObjProt с помощью + # метаклассов + if nameClassTemplate in self.newObjProt: + # Прототип класса + nameProt = self.newObjProt[nameClassTemplate] + try: + classProt = getattr(__import__("format.%s"%nameProt, + globals(), locals(), + [nameProt]), + nameProt) + except (ImportError, AttributeError): + return False + classFormat = self.createNewClass(nameClassTemplate, + (classProt,)) + else: + return False + self.importFormats[nameClassTemplate] = classFormat + return classFormat + + def getFormatObj(self, formatTemplate, textTemplate): + """Создание объекта формата шаблона. + + Объект создается на основании формата шаблона и текста шаблона""" + classFormat = self.getClassObj(formatTemplate) + if classFormat: + return classFormat(textTemplate) + else: + return False + class _shareTemplate: """Общие аттрибуты для классов шаблонов""" # Метка начала переменной @@ -2077,25 +2362,44 @@ class _shareTemplate: _deltVarStart = len(varStart) _deltVarEnd = len(varEnd) -class templateFunction(_shareTemplate): +class templateFunction(_error, _shareTemplate): """Класс для функций шаблонов""" + # Словарь установленных программ {"имя программы":[версии]} + installProg = {} + + # Cписок просканированных категорий установленных программ + installCategory = [] + + # Флаг сканирования всех установленных программ + flagAllPkgScan = False + # Список названий функций шаблона namesTemplateFunction = [] + # Словарь {название функции шаблона: функция шаблона, ...} templateFunction = {} - # Имена установленных программ - installProg = [] - # Версии установленных программ - installProgVersions = [] - # кеш вызванных значений программа, номер версии - cacheInstallProg = {} + # Регулярное выражение для сложения sNum = re.compile("\-[^\-\+]+|[^\-\+]+") + # Регулярное выражение для умножениея и деления sMD = re.compile("[^\-\+\*\/]+") + + # стек глобальных переменных + stackGlobalVars = [] + + # директория установленных программ + basePkgDir = "/var/db/pkg" + + # регулярное выражение для поиска версии + reFindVer = re.compile("(?<=\-)\d+\.?\d*\.?\d*") + # Имя обрабатываемого шаблона nameTemplate = "" + # Текст функции шаблона + functText = "" + def __init__(self, objVar): # Если не определен словарь функций шаблона #print "dict", templateFunction.__dict__.items() @@ -2116,8 +2420,37 @@ class templateFunction(_shareTemplate): self.namesTemplateFunction.append(nameFunction) # Объект хранения переменных self.objVar = objVar - self._reFunc = re.compile(("%s[a-zA-Z0-9_\-\+\(\)\, \*\/\.]+%s")\ - %(self.varStart,self.varEnd),re.M) + self._reFunc = re.compile(("%s[a-zA-Z0-9_\-\+\(\)\, \*\/\.\'\"~]+%s")\ + %(self.varStart,self.varEnd),re.M) + # Аттрибуты для функции шаблона ini() + # Первоначальный словарь переменных для ini() + self.prevDictIni = {} + # Текущий словарь переменных для ini() + self.currDictIni = {} + # Время модификации конфигурационного файла для ini() + self.timeIni = -1 + self.uid, self.gid, self.homeDir = self.getDataUser() + # Путь к конфигурационному файлу для ini() + self.pathConfigIni = os.path.join(self.homeDir, ".calculate") + self.fileConfigIni = os.path.join(self.pathConfigIni,"ini.env") + # Словарь времен модификации env файлов + self.timeConfigsIni = {} + + def getDataUser(self): + """Получить информацию о пользователе""" + userName = self.objVar.Get("ur_login") + if not userName: + userName = "root" + import pwd + try: + pwdObj = pwd.getpwnam(userName) + uid = pwdObj.pw_uid + gid = pwdObj.pw_gid + homeDir = pwdObj.pw_dir + except: + print _("Can not found user %s")%str(userName) + cl_overriding.exit(1) + return uid, gid, homeDir def equalTerm(self, term, localVars): """Метод для вычисления выражения""" @@ -2136,26 +2469,31 @@ class templateFunction(_shareTemplate): minus = True strNum = strNum[1:] if localVars.has_key(strNum): - num = localVars[strNum] + try: + num = int(localVars[strNum]) + except: + self.printErrTemplate() + print _("error var %s not int")%str(strNum) + cl_overriding.exit(1) elif self.objVar.exists(strNum): try: num = int(self.objVar.Get(strNum)) except: - print _("error in template %s")%self.nameTemplate + self.printErrTemplate() print _("error var %s not int")%str(strNum) - exit(1) + cl_overriding.exit(1) else: - print _("error in template %s")%self.nameTemplate + self.printErrTemplate() print _("error local var %s not defined")\ %str(strNum) - exit(1) + cl_overriding.exit(1) if minus: - num =-num + num = -num strNumers.append(num) return sum(strNumers) - print _("error in template %s")%self.nameTemplate + self.printErrTemplate() print _("error template term %s, incorrect data")%str(term) - exit(1) + cl_overriding.exit(1) def multAndDiv(self, term, localVars): """Метод для умножения и деления""" @@ -2174,9 +2512,9 @@ class templateFunction(_shareTemplate): ret = eval(termTmp) return ret - def funcSum(self, funTxt, resS, localVars, textTemplateTmp): + def funcSum(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона, вычисляет функцию sum()""" - terms = funTxt.replace(" ","").split(",") + terms = funArgv.replace(" ","").split(",") # Название локальной переменной nameLocVar = terms[0] if not localVars.has_key(nameLocVar): @@ -2199,45 +2537,71 @@ class templateFunction(_shareTemplate): textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] else: - print _("error in template %s")%self.nameTemplate - print _("error template term %s")%str(funTxt) - exit(1) + self.printErrTemplate() + cl_overriding.exit(1) + return textTemplateTmp + + def funcExists(self, funArgv, resS, localVars, textTemplateTmp): + """Функция шаблона exists(), + проверяет существование файла, если существует выдает '1' + """ + terms = funArgv.replace(" ","").split(",") + if len(terms) !=1: + self.printErrTemplate() + cl_overriding.exit(1) + fileName = terms[0].strip() + if fileName[0] == "~": + # Получаем директорию пользователя + fileName = os.path.join(self.homeDir, + fileName.partition("/")[2],"")[:-1] + elif fileName[0] != "/": + path = os.path.split(nameSystemFile)[0] + fileName=os.path.join(path,fileName) + replace = "" + if os.path.exists(fileName): + replace = "1" + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] return textTemplateTmp - def funcLoad(self, funTxt, resS, localVars, textTemplateTmp): + def funcLoad(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона load(), если файл существует читает из файла локальную переменную если один параметр - выводит значение локальной переменной """ - terms = funTxt.replace(" ","").split(",") + terms = funArgv.replace(" ","").split(",") if not terms[0].strip() or\ (len(terms)==2 and not terms[1].strip()) or\ len(terms)>2: - print _("error in template %s")%self.nameTemplate - print _("error template term %s")%str(funTxt) - exit(1) + self.printErrTemplate() + cl_overriding.exit(1) if len(terms) == 2: if not terms[0] in ["ver","num","char","key"]: - print _("error in template %s")%self.nameTemplate - print _("error template term %s")%str(funTxt) - print _("first argument function is not 'ver' or 'num' or\ + self.printErrTemplate() + print _("first argument function is not 'ver' or 'num' or \ 'char'") - exit(1) + cl_overriding.exit(1) if len(terms) == 1: fileName = terms[0].strip() - if fileName[0] != "/": - print _("error in template %s")%self.nameTemplate - print _("error template term %s")%str(funTxt) - print _("incorrect path %s")%fileName - exit(1) + # Если домашняя директория + if fileName[0] == "~": + # Получаем директорию пользователя + fileName = os.path.join(self.homeDir, + fileName.partition("/")[2],"")[:-1] + elif fileName[0] != "/": + path = os.path.split(nameSystemFile)[0] + fileName=os.path.join(path,fileName) else: fileName = terms[1].strip() - if fileName[0] != "/": - print _("error in template %s")%self.nameTemplate - print _("error template term %s")%str(funTxt) - print _("incorrect path %s")%fileName - exit(1) + # Если домашняя директория + if fileName[0] == "~": + # Получаем директорию пользователя + fileName = os.path.join(self.homeDir, + fileName.partition("/")[2],"")[:-1] + elif fileName[1] != "/": + path = os.path.split(nameSystemFile)[0] + fileName=os.path.join(path,fileName) replace = "" if os.path.exists(fileName): FD = open(fileName) @@ -2249,70 +2613,77 @@ class templateFunction(_shareTemplate): textTemplateTmp[resS.end():] return textTemplateTmp - def getInstallPkgGentoo(self, names = [], versions = []): - """Выдает два списка, инсталлированные программы и номера версий""" - baseDir = "/var/db/pkg" + def sharePkg(self, pkgs): + """Получение имен и номеров версий программ""" + pkgs.sort() + installProg = {} + for pkg in pkgs: + findVer = self.reFindVer.search(pkg) + if findVer: + version = findVer.group() + name = pkg.split(version)[0][:-1] + if name in installProg: + installProg[name].append(version) + else: + installProg[name] = [version] + return installProg + + def getInstallPkgGentoo(self): + """Выдает словарь инсталлированных программ и номеров версий""" pkgs = [] - 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) + tail = absNameFile.split(self.basePkgDir) if len(tail)==2: tail = tail[1].split('/') if len(tail)==3 and tail[1]!='virtual': pkgs.append(tail[2]) return True - os.path.walk(baseDir,getFilesDir, pkgs) - pkgs.sort() - for pkg in pkgs: - findVer = reVer.search(pkg) - if findVer: - ver = findVer.group() - versions.append(ver) - names.append(pkg.split(ver)[0][:-1]) - #return pkgs - return names, versions - def pkg(self, nameProg, names, versions): + os.path.walk(self.basePkgDir,getFilesDir, pkgs) + return self.sharePkg(pkgs) + + def pkg(self, nameProg, installProg): """Выдает установленные версии по имени программы""" - # Значение версии из кеша - 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 + if nameProg in installProg: + return installProg[nameProg][-1] else: return "" - def funcPkg(self, funTxt, resS, localVars, textTemplateTmp): + def funcPkg(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона pkg(), выдает номер версии программы""" - terms = funTxt.replace(" ","") # Название программы - nameProg = terms - if not self.installProg: - # Получение всех названий и версий установленных программ - self.installProg,self.installProgVersions =\ - self.getInstallPkgGentoo(names=self.installProg, - versions=self.installProgVersions) - replace = self.pkg(nameProg,self.installProg,self.installProgVersions) + nameProg = funArgv.replace(" ","") + # Замена функции в тексте шаблона + replace = "" + if "/" in nameProg: + if nameProg in self.installProg: + replace = self.pkg(nameProg, self.installProg) + else: + category, spl, nProg = nameProg.partition("/") + if not category in self.installCategory: + self.installCategory.append(category) + pathCategory = os.path.join(self.basePkgDir, category) + if os.path.exists(pathCategory): + pkgs = os.listdir(pathCategory) + pkgs = map(lambda x: os.path.join(category,x), + pkgs) + installProg = self.sharePkg(pkgs) + replace = self.pkg(nameProg, installProg) + self.installProg.update(installProg) + else: + if not self.flagAllPkgScan: + installProg = self.getInstallPkgGentoo() + self.installProg.update(installProg) + templateFunction.flagAllPkgScan = True + replace = self.pkg(nameProg, self.installProg) textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return textTemplateTmp - def funcRnd(self, funTxt, resS, localVars, textTemplateTmp): + def funcRnd(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона rnd(), выдает строку случайных символов первый аргумент: @@ -2321,26 +2692,23 @@ class templateFunction(_shareTemplate): второй аргумент: количество символов """ - terms = funTxt.replace(" ","").split(",") + terms = funArgv.replace(" ","").split(",") if not terms[0].strip() or\ (len(terms)==2 and not terms[1].strip()) or\ len(terms)!=2: - print _("error in template %s")%self.nameTemplate - print _("error template term %s")%str(funTxt) - exit(1) + self.printErrTemplate() + cl_overriding.exit(1) fArgvNames = ['num','pas'] if not terms[0] in fArgvNames: - print _("error in template %s")%self.nameTemplate - print _("error template term %s")%str(funTxt) + self.printErrTemplate() print _("first argument function is not 'num' or 'pas'") - exit(1) + cl_overriding.exit(1) try: lenStr = int(terms[1]) except: - print _("error in template %s")%self.nameTemplate - print _("error template term %s")%str(funTxt) + self.printErrTemplate() print _("two argument function is not number") - exit(1) + cl_overriding.exit(1) if terms[0] == fArgvNames[0]: replace=''.join([random.choice(string.digits)\ for i in xrange(lenStr)]) @@ -2348,14 +2716,13 @@ class templateFunction(_shareTemplate): replace=''.join([random.choice(string.ascii_letters + \ string.digits) for i in xrange(lenStr)]) else: - print _("error in template %s")%self.nameTemplate - print _("error template term %s")%str(funTxt) - exit(1) + self.printErrTemplate() + cl_overriding.exit(1) textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ textTemplateTmp[resS.end():] return textTemplateTmp - def funcCase(self, funTxt, resS, localVars, textTemplateTmp): + def funcCase(self, funArgv, resS, localVars, textTemplateTmp): """Функция шаблона case(), выдает переменную в определенном регистре первый аргумент: @@ -2365,25 +2732,23 @@ class templateFunction(_shareTemplate): второй аргумент: название переменной """ - terms = funTxt.replace(" ","").split(",") + terms = funArgv.replace(" ","").split(",") if not terms[0].strip() or\ (len(terms)==2 and not terms[1].strip()) or len(terms)!=2: - print _("error in template %s")%self.nameTemplate - print _("error template term %s")%str(funTxt) - exit(1) + self.printErrTemplate() + cl_overriding.exit(1) fArgvNames = ['upper','lower','capitalize'] if not terms[0] in fArgvNames: - print _("error in template %s")%self.nameTemplate - print _("error template term %s")%str(funTxt) + self.printErrTemplate() print _("first argument function is not 'upper' or 'lower' or\ 'capitalize'") - exit(1) + cl_overriding.exit(1) try: strValue = str(self.objVar.Get(terms[1])) except: print _("error in template %s")%self.nameTemplate print _("error var %s not found")%str(terms[1]) - exit(1) + cl_overriding.exit(1) replace = "" strValue = _toUNICODE(strValue) if terms[0] == 'upper': @@ -2398,163 +2763,364 @@ class templateFunction(_shareTemplate): textTemplateTmp[resS.end():] return textTemplateTmp - def applyFuncTemplate(self, textTemplate, nameTemplate): - """Применяет функции к тексту шаблона""" - # Локальные переменные - localVars = {} - # Имя обрабатываемого шаблона - self.nameTemplate = nameTemplate - # Регулярное выражение для поиска функции в шаблоне - reFunc = self._reFunc - resS = reFunc.search(textTemplate) - textTemplateTmp = textTemplate - while resS: - mark = textTemplateTmp[resS.start():resS.end()] - funTxt = mark[self._deltVarStart:-self._deltVarEnd] - funcName, spl, funcEnd = funTxt.partition("(") - if funcName in self.namesTemplateFunction: - # аргументы функции - '(' аргументы ')' - funArgv = funcEnd.rpartition(")")[0] - # вызов функции шаблона - textTemplateTmp = self.templateFunction[funcName](self, funArgv, - resS, localVars, - textTemplateTmp) - resS = reFunc.search(textTemplateTmp) + def funcPush(self, funArgv, resS, localVars, textTemplateTmp): + """локальная функция записывает значение переменной + + в стек глобальных переменных + """ + terms = funArgv.replace(" ","").split(",") + # Название локальной переменной + nameLocVar = terms[0] + flagFoundVar = False + if nameLocVar in localVars.keys(): + flagFoundVar = True + value = localVars[nameLocVar] + else: + try: + value = self.objVar.Get(nameLocVar) + flagFoundVar = True + except: + pass + if flagFoundVar: + # Если переменная существует + if len(terms) == 1: + self.stackGlobalVars.append(str(value)) + else: + self.printErrTemplate() + print _("error var %s exists")%str(nameLocVar) + cl_overriding.exit(1) + else: + # Если переменная не существует + if len(terms) == 1: + self.printErrTemplate() + print _("error var %s not exists")%str(nameLocVar) + cl_overriding.exit(1) + elif len(terms) == 2: + value = terms[1].strip() + self.stackGlobalVars.append(str(value)) + localVars[nameLocVar] = value else: - print _("error in template %s")%self.nameTemplate - print _("error template term %s")%str(funTxt) - print _("can not found template function '%s'")%funTxt - exit(1) + self.printErrTemplate() + cl_overriding.exit(1) + replace = "" + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] return textTemplateTmp + def funcPop(self, funArgv, resS, localVars, textTemplateTmp): + """локальная функция получает значение -class template(_file, _terms, xmlShare, _shareTemplate): - """Класс для работы с шаблонами + из стека глобальных переменных и присваивает локальной переменной - На вход 2 параметра: объект хранения переменных, имя сервиса - не + """ + terms = funArgv.replace(" ","").split(",") + # Название локальной переменной + nameLocVar = terms[0] + if len(terms) == 1: + if self.stackGlobalVars: + localVars[nameLocVar] = self.stackGlobalVars.pop() + else: + self.printErrTemplate() + print _("error, gloval variables stack is empty") + cl_overriding.exit(1) + else: + self.printErrTemplate() + cl_overriding.exit(1) + replace = "" + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + return textTemplateTmp + + def loadVarsIni(self, iniFileName): + """ Читает файл fileName + создает и заполняет переменные на основе этого файла + Используеться совместно c funcIni + """ + localVarsIni = {} + # Выходим если есть предыдущие ошибки + if self.getError(): + return False + # получить объект ini файла + config = iniParser(iniFileName) + # получаем все секции из конфигурационного файла + allsect = config.getAllSectionNames() + if not allsect: + if self.getError(): + # Очистка ошибки + _error.error = [] + return localVarsIni + # Заполняем переменные для funcIni + for sect in allsect: + sectVars = config.getAreaVars(sect) + for name in sectVars.keys(): + nameVar = "%s.%s"%(sect,name) + valueVar = sectVars[name] + localVarsIni[nameVar] = valueVar + return localVarsIni + + def getTimeFile(self, fileName): + # Получаем время модификации файла + if fileName in self.timeConfigsIni: + return self.timeConfigsIni[fileName] + return 0 + + def funcIni(self, funArgv, resS, localVars, textTemplateTmp): + """локальная функция записывает и считывает значение переменной + + из ini файла ~./calculate/ini.env + """ + # Создаем директорию + if not os.path.exists(self.pathConfigIni): + os.makedirs(self.pathConfigIni) + os.chown(self.pathConfigIni, int(self.uid), int(self.gid)) + termsRaw = funArgv.split(",") + flagFirst = True + terms = [] + for term in termsRaw: + if flagFirst: + terms.append(term.replace(" ","")) + flagFirst = False + else: + val = term.strip() + # Флаг (не найдены кавычки) + flagNotFoundQuote = True + for el in ('"',"'"): + if val.startswith(el) and val.endswith(el): + terms.append(val[1:-1]) + flagNotFoundQuote = False + break + if flagNotFoundQuote: + terms.append(val) + # Название локальной переменной + nameLocVar = terms[0] + namesVar = nameLocVar.split(".") + if len(namesVar) == 1: + nameLocVar = "main.%s"%nameLocVar + elif len(namesVar)>2: + self.printErrTemplate() + cl_overriding.exit(1) + replace = "" + # Получаем время модификации конфигурационного файла + curTime = self.getTimeFile(self.fileConfigIni) + if len(terms) == 1: + if self.timeIni != curTime: + # читаем переменные из файла + self.prevDictIni = self.loadVarsIni(self.fileConfigIni) + self.currDictIni.update(self.prevDictIni) + self.timeIni = self.getTimeFile(self.fileConfigIni) + if nameLocVar in self.currDictIni.keys(): + replace = self.currDictIni[nameLocVar] + elif len(terms) == 2: + if self.timeIni != curTime: + # читаем переменные из файла + self.prevDictIni = self.loadVarsIni(self.fileConfigIni) + self.currDictIni.update(self.prevDictIni) + self.timeIni = self.getTimeFile(self.fileConfigIni) + # Значение локальной переменной + valueLocVar = terms[1] + self.currDictIni[nameLocVar] = valueLocVar + else: + self.printErrTemplate() + cl_overriding.exit(1) + textTemplateTmp = textTemplateTmp[:resS.start()] + replace +\ + textTemplateTmp[resS.end():] + return (textTemplateTmp) + + def printErrTemplate(self): + """Печать ошибки при обработке функций шаблона""" + print _("error in template %s")%self.nameTemplate + print _("error template term '%s'")%str(self.functText) + + def applyFuncTemplate(self, textTemplate, nameTemplate, nameSystemFile): + """Применяет функции к тексту шаблона""" + # Локальные переменные + localVars = {} + # Имя обрабатываемого шаблона + self.nameTemplate = nameTemplate + # Регулярное выражение для поиска функции в шаблоне + reFunc = self._reFunc + resS = reFunc.search(textTemplate) + textTemplateTmp = textTemplate + flagIniFunc = False + while resS: + mark = textTemplateTmp[resS.start():resS.end()] + self.functText = mark[self._deltVarStart:-self._deltVarEnd] + funcName, spl, funcEnd = self.functText.partition("(") + if funcName in self.namesTemplateFunction: + # аргументы функции - '(' аргументы ')' + funArgv = funcEnd.rpartition(")")[0] + # вызов функции шаблона + textTemplateTmp = self.templateFunction[funcName](self, funArgv, + resS, localVars, + textTemplateTmp) + resS = reFunc.search(textTemplateTmp) + if funcName == "ini": + flagIniFunc = True + else: + self.printErrTemplate() + print _("can not found template function '%s'")\ + %str(self.functText) + cl_overriding.exit(1) + + if flagIniFunc: + # Очистка файла в случае его ошибочного чтения + if not self.prevDictIni and os.path.exists(self.fileConfigIni): + FD = open(self.fileConfigIni, "r+") + FD.truncate(0) + FD.seek(0) + FD.close() + # Если конф. файл модифицирован шаблоном + curTime = self.getTimeFile(self.fileConfigIni) + if curTime != self.timeIni: + # Считаем переменные из конф. файла + self.prevDictIni = self.loadVarsIni(self.fileConfigIni) + self.currDictIni.update(self.prevDictIni) + self.timeIni = curTime + # Если словари переменных не совпадают + if self.prevDictIni != self.currDictIni: + # Запишем переменные в конфигурационный файл + # Создание объекта парсера + config = iniParser(self.fileConfigIni) + # секции будущего конфигурационного файла + sects = list(set(map(lambda x: x.split(".")[0],\ + self.currDictIni.keys()))) + # запись переменных в файл + for sect in sects: + dictVar = {} + for varName in self.currDictIni.keys(): + if varName.startswith("%s."%sect): + nameVar = varName.rpartition(".")[2] + valueVar = self.currDictIni[varName] + if valueVar: + dictVar[nameVar] = valueVar + if dictVar: + # Запись переменных в секцию + config.setVar(sect, dictVar) + # читаем переменные из файла + self.prevDictIni = self.loadVarsIni(self.fileConfigIni) + self.currDictIni.update(self.prevDictIni) + self.timeConfigsIni[self.fileConfigIni] = float(time.time()) + self.timeIni = self.getTimeFile(self.fileConfigIni) + # Меняем владельца в случае необходимости + if os.path.exists(self.fileConfigIni): + fd = os.open(self.fileConfigIni, os.O_RDONLY) + fst = os.fstat(fd) + uid = fst.st_uid + gid = fst.st_gid + os.close(fd) + if self.uid!=uid or self.gid!=gid: + os.chown(self.fileConfigIni, int(self.uid), int(self.gid)) + return textTemplateTmp + +class template(_file, _terms, xmlShare, templateFormat, _shareTemplate): + """Класс для работы с шаблонами + + На вход 2 параметра: объект хранения переменных, имя сервиса - не обязательный параметр """ - # Импортированные классы поддерживаемых форматов шаблонов - importFormats = {} - # Название файла шаблона директории templDirNameFile = ".calculate_directory" - def __init__(self, objVar, dirsFilter=[], filesFilter=[]): + def __init__(self, objVar, servDir=False, 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")) - self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")\ - %(self.varStart,self.varEnd),re.M) + self._reVar = re.compile(("%s[a-zA-Z0-9_-]+%s")%(self.varStart, + self.varEnd),re.M) # Условия self._reTermBloc = re.compile("#\?(?P[a-zA-Z0-9\-_]+)\ -(?P\([a-zA-Z0-9_\-\+\,\*\/\.]+\))?\ +(?P\([a-zA-Z0-9_\-\+\,\*\/\.\'\"~]+\))?\ (?P[\>\<\=\!\&\|]+\ -[a-zA-Z0-9\>\<\=\!\|\&\-\+\*\/_\.\,\(\)]*)#\ +[a-zA-Z0-9\>\<\=\!\|\&\-\+\*\/_\.\,\(\)\'\"~]*)#\ \n*(?P.+?)\n*#(?P=rTerm)#(?P[ ,\t]*\n?)",re.M|re.S) # Объект с переменными self.objVar = objVar # Базовая директория переноса шаблонов "/mnt/calculate" или "/" и.т.д - # По умолчанию / + #self._baseDir = os.path.split(baseDir)[0] self._baseDir = self.objVar.Get("cl_root_path") - if self._baseDir == "/": - self._baseDir = "" + #if self._baseDir == "/": + #self._baseDir = "" + # Последняя часть директории шаблона (имя сервиса: samba, mail) + self._servDir = servDir + if self._servDir: + if self._servDir[0] != "/": + self._servDir = "/" + self._servDir + if self._servDir[-1] != "/": + self._servDir += "/" + self._servDir = os.path.split(self._servDir)[0] + # Созданные директории + self.createdDirs = [] + # Примененные файлы + self.filesApply = [] + # номер обрабатываемого файла + self.numberProcessTempl = 0 + # имя текущей программы + _nameProgram = self.objVar.Get("cl_name").capitalize() + # версия текущей программы + _versionProgram = self.objVar.Get("cl_ver") + # имя и версия текущей программы + self.programVersion = "%s %s"%(_nameProgram, _versionProgram) + # Словарь директорий с количеством файлов шаблонов + self.dictTemplates = {} + # Общее количество шаблонов + self.allTemplates = 0 # Объект функций шаблона self.functObj = templateFunction(self.objVar) # Метод применения функций к шаблонам self.applyFuncTemplate = self.functObj.applyFuncTemplate + # Преобразование восьмеричного в целое (ввод строка, вывод число) 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 + try: + exec("res =" + "0" + strOct) + except: + self.setError (_("Not valid oct value: ") + str(strOct)) + return False + return res else: self.setError (_("Empty oct value")) return False - def 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): + """Рекурсивное удаление директории - 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 = 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 + входной параметр директория + Обязательно должен быть определен метод self.printERROR + """ + if not os.path.exists(rmDir): + self.printERROR(_("Not found remove dir %s") %rmDir) + return False + fileObj = _file() + # Сканируем директорию + scanObjs = fileObj.scanDirs([rmDir]) + for socketRm in scanObjs[0].sockets: + # Удаляем сокеты + if os.path.exists(socketRm): + os.remove(socketRm) + for linkRm in scanObjs[0].links: + # Удаляем ссылки + os.unlink(linkRm[1]) + for fileRm in scanObjs[0].files: + # Удаляем файлы + os.remove(fileRm) + scanObjs[0].dirs.sort(lambda x, y: cmp(len(y), len(x))) + for dirRm in scanObjs[0].dirs: + # Удаляем директории + os.rmdir(dirRm) + if rmDir: + os.rmdir(rmDir) return True def createDir(self, dirName, mode=False, uid=False, gid=False): @@ -2565,11 +3131,11 @@ class template(_file, _terms, xmlShare, _shareTemplate): dMode = False prevDir, tmpSubdir = os.path.split(dirName) createDirs = [] - while not os.access(prevDir, os.F_OK): + while not os.access(prevDir, os.F_OK) and prevDir: createDirs.append(prevDir) prevDir = os.path.split(prevDir)[0] try: - tmpMode,dUid,dGid = getModeFile(prevDir) + tmpMode,dUid,dGid = self.getModeFile(prevDir) except OSError: self.setError (_("Not access dir: " ) + prevDir) return False @@ -2602,7 +3168,6 @@ class template(_file, _terms, xmlShare, _shareTemplate): return False return createDirs - def applyVarsTemplate(self, textTemplate, nameTemplate): """ Заменяет переменные на их значения """ @@ -2617,12 +3182,11 @@ class template(_file, _terms, xmlShare, _shareTemplate): except self.objVar.DataVarsError, e: print _("error in template %s")%nameTemplate print e - exit(1) + cl_overriding.exit(1) textTemplateTmp = textTemplateTmp.replace(mark, varValue) resS = self._reVar.search(textTemplateTmp) return textTemplateTmp - def applyTermsTemplate(self,textTemplate,nameTemplate,nameSystemFile=False): """ Применяет условия, к условным блокам текста """ @@ -2631,7 +3195,7 @@ class template(_file, _terms, xmlShare, _shareTemplate): textTemplateTmp = textTemplate def function(text): """Функция обработки функций в заголовке""" - return self.applyFuncTemplate(text, nameTemplate) + return self.applyFuncTemplate(text, nameTemplate, nameSystemFile) if nameSystemFile: while resS: mark = resS.group(0) @@ -2662,6 +3226,29 @@ class template(_file, _terms, xmlShare, _shareTemplate): resS = self._reTermBloc.search(textTemplateTmp) return textTemplateTmp + def getNeedTemplate(self, fileTemplate): + """Применяем правила к названию файла""" + dirP,fileP = os.path.split(fileTemplate) + if fileP: + spFile = fileP.split("?") + realFileName = spFile[0] + if len(spFile)>1: + flagTrue = False + for term in spFile[1:]: + if self._equalTerm(term, _("name template not valid: ")+\ + fileTemplate): + flagTrue = True + break + if flagTrue: + return True + else: + return False + else: + return True + else: + self.setError (_("name template not valid: ")+ str(fileTemplate)) + return False + def getTitle(self, comment, commentList): """Выдает заголовок шаблона ( версия и.т.д)""" if comment: @@ -2716,537 +3303,535 @@ class template(_file, _terms, xmlShare, _shareTemplate): """ 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.lstat(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.lstat(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.lstat(templatesDir)[stat.ST_MODE]): - # настройки директории - pDir = {} - # Файл информации о директории - dirInfoFile = os.path.join(templatesDir, self.templDirNameFile) - if os.path.exists(dirInfoFile) and\ - stat.S_ISREG(os.lstat(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 - """ + def scanDirs(self, templatesDirs, objVar=False): + """Измененный метод сканирования директорий""" 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) - # Если есть базовая директория наложения шаблонов - # то изменяем путь к директории в системе - if self._baseDir: - pDirs["_real_path"] = os.path.join(self._baseDir, - pathDir[1:]) - pathDir, propDir, crDirs = self.__getApplyHeadDir(pDirs) - if not propDir and self.getError(): - self.setError(_("Error in apply template: " ) +\ - dirInfoFile) - return False - if crDirs: - createdDirs += crDirs - for fileTemplate, propFile in dirObj.files: + class dirTempl: + def __init__(self): + self.baseDir = False + self.dirs = [] + self.files = [] + self.links = [] + self.sockets = [] + flagError = False + blockDirs = [] + def getFilesDir(dirP, dirname, names): + for nameFile in names: + absNameFile = dirname + "/" + nameFile findBlock = False - pathFile = propFile["_real_path"] for blDir in blockDirs: - st,mid,end = pathFile.partition(blDir) + st,mid,end = absNameFile.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:] + '"' - # Если есть базовая директория наложения шаблонов - # то изменяем путь к файлу в системе - # и директорию где этот файл находится - if self._baseDir: - pathFile = os.path.join(self._baseDir, pathFile[1:]) - propFile["_real_path"] = pathFile - propFile["path"] = os.path.join(self._baseDir, - propFile["path"][1:]) - # Записываем в переменную обрабатываемый файл - self.objVar.Set("cl_pass_file",pathFile) - filesApl = self.join(fileTemplate, propFile, - (programVersion,templTitle), fileHeadObj) - if filesApl: - filesApply += filesApl + if not findBlock: + if os.path.islink(absNameFile): + dest = absNameFile + src = os.readlink(absNameFile) + dirP.links.append((src,dest)) + elif os.path.isfile(absNameFile): + # Добавляем файлы кроме описаний директорий + if self.templDirNameFile != nameFile: + dirP.files.append(absNameFile) + elif os.path.isdir(absNameFile): + # Обработка условий в названии директории + if self.getNeedTemplate(absNameFile): + if self.getError(): + blockDirs.append(absNameFile) + flagError = True + break + dirP.dirs.append(absNameFile) + else: + if self.getError(): + blockDirs.append(absNameFile) + flagError = True + break + blockDirs.append(absNameFile) + elif stat.S_ISSOCK(os.stat(absNameFile)[stat.ST_MODE]): + dirP.sockets.append(absNameFile) + for templateDir in templatesDirs: + if templateDir: + # Обработка условий в названии директории + if self.getNeedTemplate(templateDir): + if self.getError(): + flagError = True + break + dirP = dirTempl() + dirP.baseDir = templateDir + dirs.append(dirP) + os.path.walk(templateDir, getFilesDir, dirP) else: if self.getError(): - #print self.getError() - return False - self.closeFiles() - return (createdDirs, filesApply) + flagError = True + break + if flagError: + return [] + return dirs + + + def applyTemplates(self): + """Применяет шаблоны к конфигурационным файлам""" + + def createDictTemplates(path, prefix, dictTemplates): + """Создает словарь {"директория":"кол-во шаблонов" ...} + + и считает общее количество шаблонов + """ + # Количество шаблонов + self.allTemplates += 1 + dirTemplate = os.path.split(path)[0] + while(True): + if dirTemplate in dictTemplates.keys(): + dictTemplates[dirTemplate] += 1 + else: + dictTemplates[dirTemplate] = 1 + if dirTemplate == prefix: + break + dirTemplate = os.path.split(dirTemplate)[0] + return dictTemplates - 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: + dirsTemplates = self.objVar.Get("cl_template_path") + dirsTemplates.sort() + # Созданные директории + self.createdDirs = [] + # Примененные файлы + self.filesApply = [] + # Номер применяемого шаблона + self.numberProcessTempl = 0 + # Словарь директорий с количеством файлов шаблонов + self.dictTemplates = {} + # Количество шаблонов + self.allTemplates = 0 + # Время доступа к конфигурационному файлу функции шаблона ini() + self.timeIni = -1 + # Первоначальный словарь переменных для ini() + self.prevDictIni = {} + # Текущий словарь переменных для ini() + self.currDictIni = {} + # Словарь времен модификации env файлов + self.timeConfigsIni = {} + if self._servDir: + tmpDirsTemplates = [] + for dirP in dirsTemplates: + dirTempl = dirP + self._servDir + if os.access(dirTempl, os.F_OK): + # Если директория существует + tmpDirsTemplates.append(dirTempl) + dirsTemplates = tmpDirsTemplates + scanObj = processingTemplates() + scanObj.processingFile = lambda x,y: createDictTemplates(x, y,\ + self.dictTemplates) + # Считаем количество шаблонов + for dirTemplate in dirsTemplates: + if not os.path.exists(dirTemplate): + self.setError(_("No such template directory") +\ + ": %s" %dirTemplate) + return (self.createdDirs, self.filesApply) + scanObj.scanningTemplates(dirTemplate) + self.numberAllTemplates(self.allTemplates) + # Обрабатываем шаблоны + for dirTemplate in dirsTemplates: + if self.scanningTemplates(dirTemplate) is False: 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 + return (self.createdDirs, self.filesApply) + + + def scanningTemplates(self, scanDir, prefix=None, flagDir=False, optDir={}): + """Сканирование и обработка шаблонов в директории scanDir""" + ret = True + if not prefix: + prefix = os.path.join(scanDir,"")[:-1] + # Флаг - не пропускать шаблоны + flagNoSkipTemplates = True + if not flagDir: + # проверка корневой директории + retDir = self.processingDirectory(scanDir, scanDir, optDir) + if retDir is None: + return None + elif retDir is False: + return False + pathDir, objHead = retDir + optDir["path"] = pathDir + if not objHead is True and objHead.typeAppend == "skip": + # Установка опции пропуска директории + optDir["skip"] = True + if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]): + if optDir.get("skip"): + flagNoSkipTemplates = False + for fileOrDir in sorted(os.listdir(scanDir)): + absPath = os.path.join(scanDir,fileOrDir) + stInfo = os.lstat(absPath) + statInfo = stInfo[stat.ST_MODE] + if stat.S_ISREG(statInfo): + if flagNoSkipTemplates: + # Обработка файла + if not self.processingFile(absPath, prefix, optDir): + ret = False + break + elif stat.S_ISDIR(statInfo): + # Обработка директории + retDir = self.processingDirectory(absPath, prefix, + optDir) + if retDir is None: + continue + elif retDir is False: + ret = False break - if findBlock: - continue - # Фильтрация шаблонов по названию файла - if pathFile in self.filesFilter: - continue - filesApply.append(pathFile) - return filesApply + # Опции следующей директории + optNextDir = {} + pathDir, objHead = retDir + optNextDir["path"] = pathDir + if not objHead is True and objHead.typeAppend == "skip": + # Установка опции пропуска директории + optNextDir["skip"] = True + ret = self.scanningTemplates(absPath, prefix, True, + optNextDir) + if ret is False: + break + return ret - def __isApplyHeadDir(self, headerObj, templateDirFile): - """Будет ли применен шаблон корневой директории + def processingFile(self, path, prefix, optFile): + """Обработка в случае шаблона файла""" + self.numberProcessTempl += 1 + self.numberProcessTemplates(self.numberProcessTempl) + # Пропуск шаблонов директорий + if self.templDirNameFile == os.path.split(path)[1]: + return True + if self.getNeedTemplate(path): + if self.getError(): + return False + oldFile = path.partition(prefix)[2] + # файл в системе без условий + oldFile = "/".join(map(lambda x:x.split("?")[0],\ + oldFile.split("/"))) + listTemplTitle = prefix.split("/")[-2:] + templTitle = '"' + "/".join(listTemplTitle) + '"' + # Записываем в переменную обрабатываемый файл + self.objVar.Set("cl_pass_file",oldFile) + # Пишем время модификации *.env файлов + if oldFile.endswith(".env"): + self.timeConfigsIni[oldFile] = float(time.time()) + filesApl = self.join(path, oldFile,(self.programVersion,templTitle), + optFile) + if filesApl: + self.filesApply += filesApl + else: + if self.getError(): + #print self.getError() + return False + pathTemplate, nameTemplate = os.path.split(oldFile) + return {"path":pathTemplate, "name":nameTemplate} + + def processingDirectory(self, path, prefix, opt): + """Обработка в случае директории если возвращаем None то пропуск дир.""" + # Файл шаблона директории + dirInfoFile = os.path.join(path, self.templDirNameFile) + newDir = os.path.join(self._baseDir, path.partition(prefix)[2][1:]) + newDir = "/".join(map(lambda x:x.split("?")[0], newDir.split("/"))) + # Применяем шаблон + pathDir, objHeadDir = self.__getApplyHeadDir(newDir, dirInfoFile, opt) + if objHeadDir: + if isinstance(objHeadDir, dirHeader): + if not objHeadDir.headerCorrect: + self.setError(_("Incorrect template: " ) +\ + dirInfoFile) + self.setError(objHeadDir.errorMessage) + return False + if not objHeadDir.headerTerm: + if objHeadDir.getError(): + self.setError(_("Incorrect template: " ) +\ + dirInfoFile) + return False + crDirs = self.createDir(pathDir) + if crDirs is False: + return False + self.createdDirs += crDirs + else: + if self.getError(): + self.setError(_("Incorrect template: " ) +\ + dirInfoFile) + return False + # Добавление количества файлов в пропущенной директории + if path in self.dictTemplates.keys(): + self.numberProcessTempl += self.dictTemplates[path] + return None + return pathDir, objHeadDir - Возвращает: - (Настройки директории, и будет ли она применена (True, False)) - """ - # Настройки для директории - dPrefs = {} + def __getGenHeadDir(self, newDir, templateDirFile, changeDirs): + """Определяет название создаваемой директории""" def function(text): """Функция обработки функций в заголовке""" - return self.applyFuncTemplate(text, templateDirFile) - + return self.applyFuncTemplate(text, newDir, templateDirFile) + + newDirMv = newDir + findChangeDir = False + #Меняем путь к директории + listD = changeDirs.items() + listD.reverse() + for dirChangeIn, dirChangeOut in listD: + st,mid,end = templateDirFile.partition(dirChangeIn) + if (not st) and mid: + findChangeDir = True + break + if findChangeDir: + pathRel = dirChangeOut + lenPathRel = len(pathRel.split("/")) + lenNewDir = len(newDir.split("/")) + lenEndDir = lenNewDir - lenPathRel + tmpDir = newDir + namesDirs = [] + for i in range(lenEndDir): + namesDirs.append(os.path.split(tmpDir)[1]) + tmpDir = os.path.split(tmpDir)[0] + namesDirs.reverse() + nameDir = "/".join(namesDirs) + newDirMv = os.path.join(pathRel, nameDir) + applyDir = newDirMv if not os.path.exists(templateDirFile): - return (dPrefs, True) + return (applyDir, 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: " ) +\ + self.setError(_("Error open 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): + return (applyDir, False) + objHead = dirHeader(textTemplate, self.objVar,function) + if not objHead.headerCorrect: + self.setError(_("Incorrect template: " ) +\ + templateDirFile) + self.setError(objHead.errorMessage) + return (applyDir, False) + if not objHead.headerTerm: + if objHead.getError(): + self.setError(_("Incorrect template: " ) +\ + templateDirFile) + return (applyDir, False) + # Изменяем название директории + if objHead.params.has_key("name"): + nameDir = objHead.params['name'] + if "/" in nameDir or nameDir == ".." or nameDir == ".": + self.setError (_("False value 'name' in template: " ) +\ + templateDirFile) + return (applyDir, False) + if not findChangeDir: + pathRel = os.path.split(os.path.abspath(newDirMv))[0] + # Новый путь к оригинальному файлу + newDirMv = os.path.join(pathRel, nameDir) + applyDir = newDirMv + # При удаленнии директории + if objHead.typeAppend == "remove": + return (applyDir, False) + return (applyDir, objHead) + + + def __getApplyHeadDir(self, newDir, templateDirFile, optDir): """Применяет шаблон к директории (права, владелец, и.т. д)""" - 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: - removeDir(newDirMv) - except (OSError, Exception), e: - print e - 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) + return self.applyFuncTemplate(text, newDir, templateDirFile) - if not os.path.exists(templateName): - return (fPrefs, True) + applyDir = newDir + # Родительская директория + if optDir.get("path"): + path = optDir["path"] + else: + path = os.path.split(applyDir)[1] + path = os.path.join(self._baseDir, path[1:]) + if not os.path.exists(templateDirFile): + applyDir = os.path.join(path, os.path.split(applyDir)[1]) + # Фильтрация шаблонов по названию директории + realPath = os.path.join("/",applyDir.partition(self._baseDir)[2]) + if realPath in self.dirsFilter: + return (applyDir, False) + return (applyDir, True) try: - FD = open(templateName) + FD = open(templateDirFile) 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) + self.setError(_("Error open template: " ) +\ + templateDirFile) + return (applyDir, False) + + # Заменяем переменные на их значения + textTemplate = self.applyVarsTemplate(textTemplate, templateDirFile) + # Обработка заголовка + objHead = dirHeader(textTemplate, self.objVar,function) + if not objHead.headerCorrect: + self.setError(_("Incorrect template: " ) +\ + templateDirFile) + self.setError(objHead.errorMessage) + return (applyDir, False) + if not objHead.headerTerm: + if objHead.getError(): + self.setError(_("Incorrect template: " ) +\ + templateDirFile) + return (applyDir, False) + + flagNoSkipDir = True + if objHead.typeAppend == "skip": + flagNoSkipDir = False + if flagNoSkipDir: + # Изменяем название родительской директории + if "path" in objHead.params: + path = objHead.params['path'] + if not path or path and path[0] != "/": + self.setError (_("False value 'path' in template: " ) +\ + templateDirFile) + return (applyDir, False) + path = os.path.join(self._baseDir, path[1:]) + + # Изменяем название директории + if "name" in objHead.params: + nameDir = objHead.params['name'] + if "/" in nameDir or nameDir == ".." or nameDir == ".": + self.setError (_("False value 'name' in template: " ) +\ + templateDirFile) + return (applyDir, False) + # Новый путь к директории + applyDir = os.path.join(path, nameDir) + else: + applyDir = os.path.join(path, os.path.split(applyDir)[1]) + else: + applyDir = path + # Фильтрация шаблонов по названию директории + realPath = os.path.join("/",applyDir.partition(self._baseDir)[2]) + if realPath in self.dirsFilter: + return (applyDir, False) + # Удаляем директорию + if objHead.typeAppend == "remove": + if os.path.isdir(applyDir): + # удаляем директорию + try: + self.removeDir(applyDir) + except: + self.setError(_("Can not delete dir: " ) +\ + applyDir) + return (applyDir, False) + # chmod - изменяем права - if "chmod" in fPrefs: - mode = self.__octToInt(fPrefs["chmod"]) + if "chmod" in objHead.params: + mode = self.__octToInt(objHead.params['chmod']) if mode: - fPrefs["chmod"] = mode + if not os.path.exists(applyDir): + if not self.createDir(applyDir, mode): + return False + else: + os.chmod(applyDir, mode) else: self.setError (_("False value 'chmod' in template: " ) +\ - templateName) - return (fPrefs, False) + templateDirFile) + return (applyDir, 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] + if "chown" in objHead.params: + owner = objHead.params['chown'] + if owner: + if ":" in owner: + strUid, strGid = owner.split(":") + import pwd + try: + uid = pwd.getpwnam(strUid)[2] + except: + self.setError (_("Not user in this system: ") + strUid) + self.setError (_("False value 'chown' in template: " )+\ + templateDirFile) + return (applyDir, False) + try: + import grp + gid = grp.getgrnam(strGid)[2] + except: + self.setError (_("Not group in this system: ")+strGid) + self.setError (_("False value 'chown' in template: " )+\ + templateDirFile) + return (applyDir, False) + + if not os.path.exists(applyDir): + if not self.createDir(applyDir, False, uid, gid): + return False + else: + os.chown(applyDir, uid, gid) + else: + self.setError (_("False value 'chown' in template: " ) +\ + templateDirFile) + return (applyDir, False) 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): + templateDirFile) + return (applyDir, False) + return (applyDir, objHead) + + def __getApplyHeadTemplate(self, newFile, oldFile, copyFile, optFile): """Применяет заголовок к шаблону (права, владелец, и.т. д)""" - # Конфигурационный файл в системе - pathOldFile = dictPropFile["_real_path"] - # Директория в которой находится шаблон - newDir = dictPropFile["path"] + + def function(text): + """Функция обработки функций в заголовке""" + return self.applyFuncTemplate(text, newFile, oldFile) + + self.closeFiles() # Файлы в системе к которым были применены шаблоны - applyFiles = [pathOldFile] + applyFiles = [oldFile] + if copyFile: + self.nameFileNew = self.absFileName(newFile) + self.FN = self.openNewFile(self.nameFileNew) + self.newTemplate = self.FN.read() + self.closeNewFile() + objHeadNew = fileHeader(self.newTemplate, False, + self.getFileType(),objVar=self.objVar, + function=function) + if not objHeadNew.headerCorrect: + self.setError(_("Incorrect template: " ) +\ + newFile) + self.setError(objHeadNew.errorMessage) + return (applyFiles, False) + if not objHeadNew.headerTerm: + if objHeadNew.getError(): + self.setError(_("Incorrect template: " ) +\ + newFile) + return (applyFiles, False) + pathProg = "" - # В случае force - if "force" in dictPropFile: + # Родительская директория + path = optFile["path"] + + # Изменяем название родительской директории + if "path" in objHeadNew.params: + path = objHeadNew.params['path'] + if not path or path and path[0] != "/": + self.setError (_("False value 'path' in template: " ) +\ + templateDirFile) + return (applyDir, False) + path = os.path.join(self._baseDir, path[1:]) + + # Путь к оригинальному файлу - pathOldFile + # Изменяем путь к оригинальному файлу + if objHeadNew.params.has_key("name"): + nameFile = objHeadNew.params['name'] + if "/" in nameFile or nameFile == ".." or nameFile == ".": + self.setError (_("False value 'name' in template: " ) + newFile) + return (applyFiles, False) + # Новый путь к оригинальному файлу + pathOldFile = os.path.join(path,nameFile) + else: + pathOldFile = os.path.join(path,os.path.split(oldFile)[1]) + applyFiles = [pathOldFile] + + # Фильтрация шаблонов по названию файла + realPath = os.path.join("/",pathOldFile.partition(self._baseDir)[2]) + if realPath in self.filesFilter: + return (applyFiles, False) + + # Удаляем оригинальный файл + if objHeadNew.typeAppend == "remove": if os.path.islink(pathOldFile): # удаляем ссылку try: @@ -3254,7 +3839,6 @@ class template(_file, _terms, xmlShare, _shareTemplate): except: self.setError(_("Can not delete link: " ) +\ pathOldFile) - return (applyFiles, False) if os.path.isfile(pathOldFile): # удаляем файл try: @@ -3262,10 +3846,17 @@ class template(_file, _terms, xmlShare, _shareTemplate): except: self.setError(_("Can not delete file: " ) +\ pathOldFile) - return (applyFiles, False) + return (applyFiles, False) + # Пропускаем обработку шаблона + elif objHeadNew.typeAppend == "skip": + return (applyFiles, False) - # Удаляем оригинальный файл - if dictPropFile["append"] == "remove": + # Создаем директорию для файла если ее нет + if not os.path.exists(path): + if not self.createDir(path): + return (applyFiles, False) + # В случае force + if objHeadNew.params.has_key("force"): if os.path.islink(pathOldFile): # удаляем ссылку try: @@ -3273,6 +3864,7 @@ class template(_file, _terms, xmlShare, _shareTemplate): except: self.setError(_("Can not delete link: " ) +\ pathOldFile) + return (applyFiles, False) if os.path.isfile(pathOldFile): # удаляем файл try: @@ -3280,25 +3872,24 @@ class template(_file, _terms, xmlShare, _shareTemplate): except: self.setError(_("Can not delete file: " ) +\ pathOldFile) - return (applyFiles, False) + return (applyFiles, False) flagSymlink = False flagForce = False # Если есть параметр mirror - if "mirror" in dictPropFile: - if "link" in dictPropFile: - templateFile = dictPropFile['link'] + if objHeadNew.params.has_key("mirror"): + if objHeadNew.params.has_key("link"): + templateFile = objHeadNew.params['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'] + if objHeadNew.params.has_key("link") and\ + not objHeadNew.params.has_key("symbolic"): + templateFile = objHeadNew.params['link'] foundTemplateFile = os.path.exists(templateFile) if foundTemplateFile: FO = self.openNewFile(templateFile) @@ -3307,42 +3898,76 @@ class template(_file, _terms, xmlShare, _shareTemplate): if os.path.exists(pathOldFile): os.remove(pathOldFile) if foundTemplateFile: - if not self.createConfFile(pathOldFile, newDir): - return (applyFiles, False) + fd = os.open(pathOldFile, os.O_CREAT) + os.close(fd) + os.chmod(pathOldFile, self._mode) + os.chown(pathOldFile, self._uid, self._gid) FON = open (pathOldFile, "r+") FON.write(buff) FON.close() # Если символическая ссылка - if "symbolic" in dictPropFile: + if objHeadNew.params.has_key("symbolic"): 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) + pathOldFile = objHeadNew.params['link'] + flagSymlink = True + if not "/" == pathOldFile[0]: + pathLink = os.path.split(os.path.abspath(prevOldFile))[0] + pathProg = os.getcwd() + os.chdir(pathLink) + # chmod - изменяем права + if objHeadNew.params.has_key("chmod"): + mode = self.__octToInt(objHeadNew.params['chmod']) + if mode: + if not os.path.exists(pathOldFile): + fd = os.open(pathOldFile, os.O_CREAT) + os.close(fd) + os.chmod(pathOldFile, mode) + else: + self.setError (_("False value 'chmod' in template: " ) +\ + newFile) + return (applyFiles, False) # chown - изменяем владельца и группу - if "chown" in dictPropFile: - uid, gid = dictPropFile['chown'] - if not flagCreateFile and not os.path.exists(pathOldFile): - if not self.createConfFile(pathOldFile, newDir): + if objHeadNew.params.has_key("chown"): + owner = objHeadNew.params['chown'] + if owner: + if ":" in owner: + strUid, strGid = owner.split(":") + import pwd + try: + uid = pwd.getpwnam(strUid)[2] + except: + self.setError (_("Not user in this system: ") + strUid) + self.setError (_("False value 'chown' in template: " )+\ + newFile) + return (applyFiles, False) + try: + import grp + gid = grp.getgrnam(strGid)[2] + except: + self.setError (_("Not group in this system: ")+strGid) + self.setError (_("False value 'chown' in template: " )+\ + newFile) + return (applyFiles, False) + + if not os.path.exists(pathOldFile): + FO = self.openNewFile(newFile) + FO.close() + fd = os.open(pathOldFile, os.O_CREAT) + os.close(fd) + os.chmod(pathOldFile, self._mode) + os.chown(pathOldFile, uid, gid) + else: + self.setError (_("False value 'chown' in template: " ) +\ + newFile) return (applyFiles, False) - os.chown(pathOldFile, uid, gid) + else: + self.setError (_("False value 'chown' in template: " ) +\ + newFile) + return (applyFiles, False) + self.openFiles(newFile, pathOldFile) if flagSymlink: if os.path.exists(prevOldFile) or os.path.islink(prevOldFile): if os.path.islink(prevOldFile): @@ -3357,22 +3982,18 @@ class template(_file, _terms, xmlShare, _shareTemplate): 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 not objHeadNew.body.strip(): + return (applyFiles, False) + else: + applyFiles = [pathOldFile] if pathProg: os.chdir(pathProg) # Если файлы заменяются не нужно их обрабатывать дальше - if "replace" in dictPropFile and\ - not "symbolic" in dictPropFile and\ - "link" in dictPropFile: + if objHeadNew.typeAppend == "replace" and\ + not objHeadNew.params.has_key("symbolic") and\ + objHeadNew.params.has_key("link"): return (applyFiles, False) - return (applyFiles, dictPropFile) + return (applyFiles, objHeadNew) def createNewClass(self, name, bases, attrs={}): """Создает объект нового класса @@ -3395,248 +4016,289 @@ class template(_file, _terms, xmlShare, _shareTemplate): if attrs: for key in attrs.keys(): attrsNew[key] = attrs[key] - newCl = type(name, bases + (newMethod, object), attrsNew) + newCl = type(name, bases + (newMethod, object,), attrsNew) return newCl - def textIsUtf8(self, text): - """Проверяет текст на кодировку UTF-8""" - try: - text.decode("UTF-8") - except: - return False + def fileIsUtf(self, fileName): + """Проверяет файл на кодировку UTF-8""" + if os.path.exists(fileName): + FD = open(self.absFileName(fileName)) + newTemplate = FD.read() + FD.close() + try: + newTemplate.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): + def join(self, newFile, oldFile, ListOptTitle, optFile): """Объединения шаблона и конф. файла join(newFile, oldFile, ListOptTitle) Объединение шаблона newFile и конф. файла oldFile, - propFile - словарь свойств конфигурационного файла ListOptTitle - список строк которые добавятся в заголовок + optFile = опции для шаблона """ - # Применяем свойства к конфигурационному файлу - # Открываем файл шаблона и конфигурационный файл - - # В случае type=print (печатаем содержимое шаблона) - flagPrintTemplate = False - filesApply, templateProp = self.__getApplyHeadTemplate(newFile,propFile) - if not templateProp: - if self.getError(): - return [] + # Выполняем условия для блока текста а так-же заменяем переменные + self.nameFileNew = self.absFileName(newFile) + self.FN = self.openNewFile(self.nameFileNew) + self.newTemplate = self.FN.read() + self.closeNewFile() + copyFile = True + if self.getFileType() != "bin": + # Вычисляем условные блоки + self.newTemplate = self.applyTermsTemplate(self.newTemplate, + newFile, oldFile) + #print "|%s|" %(self.newTemplate) + # Заменяем переменные на их значения + self.newTemplate = self.applyVarsTemplate(self.newTemplate, + newFile) + # Вычисляем функции + self.newTemplate = self.applyFuncTemplate(self.newTemplate, + newFile, oldFile) + copyFile = False + filesApply, objHeadNew = self.__getApplyHeadTemplate(newFile, oldFile, + copyFile, optFile) + if not objHeadNew: 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 + # Флаг - кодировка с бинарными примесями у файла шаблона включаем при + # условии текстового файла и кодировки отличной от UTF-8 + flagNotUtf8New = False + # Флаг - кодировка с бинарными примесями у оригинального файла + flagNotUtf8Old = False + if not copyFile: # проверяем кодировку шаблона - if not self.textIsUtf8(self.newTemplate): + if not self.fileIsUtf(newFile): flagNotUtf8New = True - if not ("link" in templateProp and "symbolic" in templateProp): - # проверяем кодировку оригинального файла - if not self.textIsUtf8(self.oldTemplate): - flagNotUtf8Old = True + if not (objHeadNew.params.has_key("link") and\ + objHeadNew.params.has_key("symbolic")): + # проверяем кодировку оригинального файла + if not self.fileIsUtf(oldFile): + flagNotUtf8Old = True + self.newTemplate = objHeadNew.body + #if objHeadNew.fileType != "bin": + #self.newTemplate = self.applyTermsTemplate(self.newTemplate, + #newFile) + #self.newTemplate = self.applyVarsTemplate(self.newTemplate) + # Титл конфигурационного файла title = "" - if ListOptTitle and "comment" in templateProp: - title = self.getTitle(templateProp["comment"], - ListOptTitle) + if ListOptTitle: + title = self.getTitle(objHeadNew.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) + objHeadOld = False + if objHeadNew.comment: + objHeadOld = fileHeader(self.oldTemplate, objHeadNew.comment) + # Тестирование + #print self.nameFileOld + #print objHeadNew.typeAppend + if objHeadNew.fileType: + # Создаем объект в случае параметра format в заголовке + if (objHeadNew.typeAppend == "replace" or\ + objHeadNew.typeAppend == "before" or\ + objHeadNew.typeAppend == "after") and\ + not (objHeadNew.fileType == "bin" or\ + objHeadNew.fileType == "raw"): + # Преобразовываем бинарные файлы + if flagNotUtf8New: + objTxtCoder = utfBin() + self.newTemplate = objTxtCoder.encode(self.newTemplate) + # создаем объект формата шаблона + objTemplNew = self.getFormatObj(objHeadNew.fileType, + self.newTemplate) + if not objTemplNew: + self.setError (\ + _("Incorrect header parmeter format=%s in template")\ + %formatTemplate + " " + 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 "xml_" in objHeadNew.fileType: + 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 objHeadNew.typeAppend == "replace": + if "xml_" in objHeadNew.fileType: + data = self.newTemplate.split("\n") + data.insert(1,title) + self.oldTemplate = "\n".join(data) + else: + if objHeadNew.execStr: + self.oldTemplate = objHeadNew.execStr+title+\ + self.newTemplate + else: + self.oldTemplate = title + self.newTemplate + self.saveOldFile() + return filesApply + # Впереди + elif objHeadNew.typeAppend == "before": + if "xml_" in objHeadNew.fileType: + self.setError (\ + _("False option append=before in template %s") %newFile) + return False + if objHeadOld and objHeadOld.body: + self.oldTemplate = objHeadOld.body 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 objHeadNew.execStr: + self.oldTemplate = objHeadNew.execStr + title + tmpTemplate + elif objHeadOld.execStr: + self.oldTemplate = objHeadOld.execStr + title + tmpTemplate + else: + self.oldTemplate = title + tmpTemplate + + #print self.oldTemplate + self.saveOldFile() + return filesApply + # Cзади + elif objHeadNew.typeAppend == "after": + if "xml_" in objHeadNew.fileType: + self.setError (\ + _("False option append=after in template %s") %newFile) + return False + if objHeadOld and objHeadOld.body: + self.oldTemplate = objHeadOld.body 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) + if objHeadNew.execStr: + self.oldTemplate = objHeadNew.execStr + title + tmpTemplate + elif objHeadOld.execStr: + self.oldTemplate = objHeadOld.execStr + title + tmpTemplate + else: + self.oldTemplate = title + tmpTemplate + self.saveOldFile() + return filesApply + # Объединение + elif objHeadNew.typeAppend == "join": + if flagNotUtf8New: + objTxtCoder = utfBin() + self.newTemplate = objTxtCoder.encode(self.newTemplate) + # создаем объект формата шаблона + objTemplNew = self.getFormatObj(objHeadNew.fileType, + self.newTemplate) + if not objTemplNew: + self.setError (\ + _("Incorrect header parmeter format=%s in template")\ + %formatTemplate + " " + newFile) 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) + if "xml_" in objHeadNew.fileType: + 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 = "" + #if objHeadNew.execStr: + #self.oldTemplate = objHeadNew.execStr + \ + #title + objTemplNew.getConfig().encode("UTF-8") + #else: + #self.oldTemplate = title +\ + #objTemplNew.getConfig().encode("UTF-8") + #self.saveOldFile() + #return True + + objHeadOld = fileHeader(self.oldTemplate, objTemplNew._comment) + if objHeadOld.body: + self.oldTemplate = objHeadOld.body + else: + self.oldTemplate = "" + if flagNotUtf8Old: + objTxtCoder = utfBin() + self.oldTemplate = objTxtCoder.encode(self.oldTemplate) + # создаем объект формата шаблона для конфигурационного файла + objTemplOld = self.getFormatObj(objHeadNew.fileType, + self.oldTemplate) + if not objTemplOld: + self.setError (_("Error in template %s") %oldFile) return False - data = \ - objTemplOld.getConfig().encode("UTF-8").split("\n") - data.insert(1,title) - self.oldTemplate = "\n".join(data) + if "xml_" in objHeadNew.fileType: + 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) + #print objTemplOld.doc.toprettyxml() + #print objTemplNew.doc.toprettyxml() + if "xml_" in objHeadNew.fileType: + 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: + if objHeadNew.execStr: + self.oldTemplate = objHeadNew.execStr + title +\ + objTemplOld.getConfig().encode("UTF-8") + elif objHeadOld.execStr: + self.oldTemplate = objHeadOld.execStr + title +\ + objTemplOld.getConfig().encode("UTF-8") + 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.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 + self.setError (_("False (type append) template: " ) +\ + objHeadNew.typeAppend) + return False else: - self.setError (_("False (type append) template: " )+appendTemplate) + self.setError (_("Type template not found: ") + newFile) return False + return filesApply -class iniParser(_error): +class iniParser(_error, templateFormat): """Класс для работы с ini файлами """ def __init__(self, iniFile): - # Класс samba - self.samba = getattr(__import__("format.samba", - globals(), locals(), - ["samba"]), "samba") # название ini файла self.iniFile = iniFile # права создаваемого ini-файла @@ -3678,15 +4340,28 @@ class iniParser(_error): dictVar - словарь переменных """ textIni = self.openIniFile() - if not self.checkIniFile(textIni): + nameFomat = self.checkIniFile(textIni) + if not nameFomat: return False - # создаем объект типа samba и записываем в него содержимое ini-файла - objIni = self.samba(textIni) - # создаем текст в формате samba из строки заголовка и + if type(strHeader) in (tuple, list): + # формат plasma + classObj = self.getClassObj("plasma") + else: + if nameFomat == "plasma": + self.setError(_("In the file %s (format - 'plasma'), \ + write the variable in the format 'samba'")\ + %self.iniFile) + return False + # формат samba + classObj = self.getClassObj("samba") + # создаем объект + # и записываем в него содержимое ini-файла + objIni = classObj(textIni) + # создаем текст из строки заголовка и # словаря переменных области txtConfig = objIni.createTxtConfig(strHeader, dictVar) - # создаем объект типа samba и записываем в него текст - objIniAdd = self.samba(txtConfig) + # создаем объект и записываем в него текст + objIniAdd = classObj(txtConfig) # объединяем объекты для получения результирующего текста objIni.join(objIniAdd) # получаем текст @@ -3709,13 +4384,27 @@ class iniParser(_error): if textIni == False: self.checkIni = False return False - self.checkIni = True + self.checkIni = "samba" # В файле есть данные if not self.isEmptyFile(textIni): - objIni = self.samba(textIni) - xmlBody = objIni.docObj.getNodeBody() - if not xmlBody.firstChild: + try: + objIni = self.getClassObj("plasma")(textIni) + except: + self.setError(_("Incorrect format file") + ": " + \ + self.iniFile) self.checkIni = False + return self.checkIni + allAreas = objIni.docObj.getAllAreas() + for xmlArea in allAreas: + parentNode = xmlArea.parentNode + if parentNode and parentNode.tagName == "area": + self.checkIni = "plasma" + break + if self.checkIni == "samba": + objIni = self.getClassObj("samba")(textIni) + xmlBody = objIni.docObj.getNodeBody() + if not xmlBody.firstChild: + self.checkIni = False return self.checkIni def delVar(self, strHeader, nameVar): @@ -3727,7 +4416,13 @@ class iniParser(_error): def delArea(self, strHeader): """Удаляем область из ini файла""" - delStrHeader = "!%s" %(strHeader) + if type(strHeader) in (tuple, list): + # Формат plasma + delStrHeader = strHeader[:] + delStrHeader[-1] = "!%s"%delStrHeader[-1] + else: + # Формат samba + delStrHeader = "!%s" %(strHeader) dictVar = {"del":"del"} res = self.setVar(delStrHeader, dictVar) return res @@ -3735,50 +4430,135 @@ class iniParser(_error): def getVar(self, strHeader, nameVar): """Получаем значение переменной из ini-файла""" textIni = self.openIniFile() - if not self.checkIniFile(textIni): + nameFomat = self.checkIniFile(textIni) + if not nameFomat: return False - # создаем объект типа samba и записываем в него содержимое ini-файла - objIni = self.samba(textIni) + formatPlasma = False + if type(strHeader) in (tuple, list): + # формат plasma + classObj = self.getClassObj("plasma") + formatPlasma = True + else: + if nameFomat == "plasma": + self.setError(_("In the file %s (format - 'plasma'), \ + get the variable in the format 'samba'")\ + %self.iniFile) + return False + # формат samba + classObj = self.getClassObj("samba") + # создаем объект и записываем в него содержимое ini-файла + objIni = classObj(textIni) # получаем ноду body xmlBody = objIni.docObj.getNodeBody() - # находим в области переменную - res = objIni.docObj.getAreaFieldValues(strHeader, nameVar, xmlBody) - if res == False: + flagFound, xmlBody = self.getLastNode(objIni, xmlBody, strHeader, + formatPlasma) + if flagFound and xmlBody: + if formatPlasma: + strHeader = strHeader[-1] + # находим в области переменную + res = objIni.docObj.getAreaFieldValues(strHeader, nameVar, xmlBody) + else: + res = False + if res is False: return "" else: return res - def getAreaVars(self,strHeader): + + def getLastNode(self, objIni, xmlBody, strHeader, formatPlasma): + """Ищет область в XML в которой область с переменными""" + flagFound = True + lenStrHeader = len(strHeader) + if formatPlasma and lenStrHeader>0: + xmlAreas = [xmlBody] + for i in xrange(lenStrHeader-1): + flagFound = False + for xmlArea in xmlAreas: + xmlAreas = objIni.docObj.getArea(strHeader[i], xmlArea) + if xmlAreas: + flagFound = True + break + if xmlAreas: + xmlBody = xmlAreas[0] + return flagFound,xmlBody + + def getAreaVars(self, strHeader): """Получаем все переменнные области из ini-файла""" textIni = self.openIniFile() - if not self.checkIniFile(textIni): + nameFomat = self.checkIniFile(textIni) + if not nameFomat: return False + formatPlasma = False + if type(strHeader) in (tuple, list): + # формат plasma + classObj = self.getClassObj("plasma") + formatPlasma = True + else: + if nameFomat == "plasma": + self.setError(_("In the file %s (format - 'plasma'), \ + get all variables in the format 'samba'")\ + %self.iniFile) + return False + # формат samba + classObj = self.getClassObj("samba") # создаем объект типа samba и записываем в него содержимое ini-файла - objIni = self.samba(textIni) + objIni = classObj(textIni) # получаем ноду body xmlBody = objIni.docObj.getNodeBody() - # если находим область то выдаем словарем все переменные иначе False - res = objIni.docObj.getAreaFields(strHeader, xmlBody) - if res == False: + flagFound, xmlBody = self.getLastNode(objIni, xmlBody, strHeader, + formatPlasma) + if flagFound and xmlBody: + if formatPlasma: + strHeader = strHeader[-1] + # если находим область то выдаем словарем все переменные иначе False + res = objIni.docObj.getAreaFields(strHeader, xmlBody) + else: + res = False + if res is False: return {} else: return res def getAllSectionNames(self): - """Получаем все имена секций определенных в ini файле""" + """Получаем все имена секций определенных в ini файле + + Если формат ini файла plasma то имя секции - + имена нескольких секций через запятую + """ textIni = self.openIniFile() - if not self.checkIniFile(textIni): + nameFomat = self.checkIniFile(textIni) + if not nameFomat: return False - # создаем объект типа samba и записываем в него содержимое ini-файла - objIni = self.samba(textIni) - # получаем ноду body - xmlBody = objIni.docObj.getNodeBody() - xmlNodes = objIni.docObj.getFieldsArea(xmlBody) + if nameFomat == "samba": + # создаем объект типа samba и записываем в него содержимое ini-файла + objIni = self.getClassObj("samba")(textIni) + elif nameFomat == "plasma": + # создаем объект типа plasma и записываем в него содержимое + # ini-файла + objIni = self.getClassObj("plasma")(textIni) + else: + return [] + xmlNodes = objIni.docObj.getAllAreas() # Имена секций ini файла namesSection = [] - for xmlNode in xmlNodes: - if xmlNode.tagName == "area": + if nameFomat == "plasma": + for xmlNode in xmlNodes: + nSect = objIni.docObj.getNameArea(xmlNode) + if nSect: + namesSect = [nSect] + parentNode = xmlNode.parentNode + while parentNode != objIni.docObj.body: + nameSect = objIni.docObj.getNameArea(parentNode) + if nameSect: + namesSect.append(nameSect) + parentNode = parentNode.parentNode + else: + return [] + namesSection.append(",".join(reversed(namesSect))) + elif nameFomat == "samba": + # получаем ноду body + for xmlNode in xmlNodes: nSect = objIni.docObj.getNameArea(xmlNode) if nSect: namesSection.append(nSect) - return namesSection + return namesSection \ No newline at end of file diff --git a/pym/cl_utils.py b/pym/cl_utils.py index d2fd486..fa54d7f 100644 --- a/pym/cl_utils.py +++ b/pym/cl_utils.py @@ -14,20 +14,30 @@ # 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 +import subprocess -def _toUNICODE(val): - """перевод текста в юникод""" - if type(val) == types.UnicodeType: - return val - else: - return str(val).decode('UTF-8') +class _error: + # Здесь ошибки, если они есть + error = [] + def getError(self): + """Выдать ошибки""" + if not self.error: + return False + error = "" + for e in self.error: + error += e + "\n" + return error + + def setError(self, error): + """Установка ошибки""" + self.error.append(error) + return True def runOsCommand(cmd, inStr=None, ret_first=None, env_dict=None): """Выполняет внешнюю программу @@ -65,21 +75,8 @@ def runOsCommand(cmd, inStr=None, ret_first=None, env_dict=None): 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 длина пароля который нужно сгенерировать @@ -95,6 +92,18 @@ def fillstr(char, width): '''Заполнить строку указанным числом символов. Псеводоним символ*кол-во''' return str(char) * width +def getpathenv(): + """Вернуть пути для запуска утилит""" + bindir=['/sbin','/bin','/usr/sbin','/usr/bin'] + env=os.environ + if env and env.has_key('PATH'): + lpath=env['PATH'].split(":") + npath=[] + for dirname in bindir: + if os.path.exists(dirname) and dirname not in lpath: + npath.append(dirname) + lpath=npath+lpath + return ":".join(lpath) def list2str(list): '''Функция переводит список в строку''' @@ -138,120 +147,9 @@ def convertStrListDict(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.lstat(scanDir)[stat.ST_MODE]): - for fileOrDir in os.listdir(scanDir): - absPath = os.path.join(scanDir,fileOrDir) - statInfo = os.lstat(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 - -def removeDir(rmDir): - """Рекурсивное удаление директории - - входной параметр директория для удаления - - Ошибки по except - """ - if not os.path.exists(rmDir): - raise Exception(_("Not found remove dir %s") %rmDir) - fileObj = scan() - # Сканируем директорию - scanObjs = fileObj.scanDirs([rmDir]) - for socketRm in scanObjs[0].sockets: - # Удаляем сокеты - if os.path.exists(socketRm): - os.remove(socketRm) - for linkRm in scanObjs[0].links: - # Удаляем ссылки - os.unlink(linkRm[1]) - for fileRm in scanObjs[0].files: - # Удаляем файлы - os.remove(fileRm) - scanObjs[0].dirs.sort(lambda x, y: cmp(len(y), len(x))) - for dirRm in scanObjs[0].dirs: - # Удаляем директории - os.rmdir(dirRm) - if os.path.exists(rmDir): - os.rmdir(rmDir) - return True - -def getModeFile(nameFile): - """Выдает информацию о файле - - права файла, владелец, группа файла (777,test, group) - """ - fd = os.open(nameFile, os.O_RDONLY) - fst = os.fstat(fd) - uid = fst.st_uid - gid = fst.st_gid - mode = stat.S_IMODE(fst.st_mode) - os.close(fd) - return (mode,uid,gid) \ No newline at end of file +def _toUNICODE(val): + """перевод текста в юникод""" + if type(val) == types.UnicodeType: + return val + else: + return str(val).decode('UTF-8') diff --git a/pym/cl_vars.py b/pym/cl_vars.py index 4097326..722619b 100644 --- a/pym/cl_vars.py +++ b/pym/cl_vars.py @@ -14,7 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - #Допустимые ключи значений # mode - режим переменной r-не переназначается из командной строки, # w-переназначается из командной строки @@ -55,13 +54,25 @@ class Data: # названия используемых раскладок клавиатуры для X os_locale_xkbname = {} + # keymap of locale (used for /etc/conf.d/keymaps) + os_locale_keymap = {} + + # dumpkeys_charset for keymap + os_locale_dumpkeys = {} + + # timezone for clock + os_clock_timezone = {} + + # type of clock (UTC or local) + os_clock_type = {} + # архитектура компьютера (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"} # корневой раздел файловой системы @@ -76,14 +87,26 @@ class Data: # постфикс к названию системы os_linux_subname = {} + # motherboard model + hr_board_model = {} + + # motherboard vendor + hr_board_vendor = {} + + # processors count + hr_cpus = {} + # название виртуальной машины (virtualbox, vmware, qemu) hr_virtual = {} # версия системы os_linux_ver = {} - # Тип шаблона + # Тип профиля cl_pass_type = {'mode':"w"} # Действие программы cl_pass_run = {'mode':"w"} + + #Логин пользователя + ur_login = {'mode':"w"} diff --git a/pym/format/__init__.py b/pym/format/__init__.py index e69de29..8d1c8b6 100644 --- a/pym/format/__init__.py +++ b/pym/format/__init__.py @@ -0,0 +1 @@ + diff --git a/pym/format/apache.py b/pym/format/apache.py index 0b1ffc2..5d96fef 100644 --- a/pym/format/apache.py +++ b/pym/format/apache.py @@ -215,4 +215,5 @@ class apache(bind): if not areas: return docObj self.createXML(areas, docObj.getNodeBody(), docObj) - return docObj \ No newline at end of file + return docObj + \ No newline at end of file diff --git a/pym/format/bind.py b/pym/format/bind.py index 7028196..6db28fa 100644 --- a/pym/format/bind.py +++ b/pym/format/bind.py @@ -313,3 +313,5 @@ class bind(objShare): """Объединяем конфигурации""" if isinstance(bindObj, bind): self.docObj.joinDoc(bindObj.doc) + + diff --git a/pym/format/dhcp.py b/pym/format/dhcp.py index 4f47666..698c7cd 100644 --- a/pym/format/dhcp.py +++ b/pym/format/dhcp.py @@ -98,3 +98,5 @@ class dhcp(bind): """Объединяем конфигурации""" if isinstance(dhcpObj, dhcp): self.docObj.joinDoc(dhcpObj.doc) + + diff --git a/pym/format/dovecot.py b/pym/format/dovecot.py index 5130771..c6832cb 100644 --- a/pym/format/dovecot.py +++ b/pym/format/dovecot.py @@ -62,4 +62,6 @@ class dovecot(bind): self.docObj.joinDoc(dovecotObj.doc) # Для добавления перевода строки перед закрывающим тегом # конфигурационного файла - self.postXML() \ No newline at end of file + self.postXML() + + diff --git a/pym/format/kde.py b/pym/format/kde.py index 5c9b3fd..3e3b0c6 100644 --- a/pym/format/kde.py +++ b/pym/format/kde.py @@ -130,31 +130,10 @@ class kde(samba): #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 index 5df868c..1f9efc6 100644 --- a/pym/format/ldap.py +++ b/pym/format/ldap.py @@ -181,3 +181,4 @@ class ldap(samba): z += 1 #print docObj.doc.toprettyxml() return docObj + diff --git a/pym/format/plasma.py b/pym/format/plasma.py index d5e9500..2522f42 100644 --- a/pym/format/plasma.py +++ b/pym/format/plasma.py @@ -446,6 +446,26 @@ class plasma(samba): rootNode.appendChild(fieldXML) #rootNode.appendChild(areaXML) + + def createTxtConfig(self, strHeader, dictVar): + """Cоздает область с заголовком + + создает текст конфигурационного файла в формате samba из + заголовка (строка) и словаря переменных + """ + if not strHeader: + return "" + if type(strHeader) in (tuple, list): + outTxt = "".join(map(lambda x: "["+x+"]",strHeader)) + if not outTxt: + return "" + outTxt += "\n" + else: + outTxt = "[" + strHeader + "]\n" + for key in dictVar.keys(): + outTxt += "%s=%s\n" %(key,dictVar[key]) + return outTxt + def _textToXML(self): """Преобразуем текст в XML""" areas = [] @@ -480,7 +500,7 @@ class plasma(samba): elif len(quotes) == 1: quotes.append("") return quotes - + xmlAreas = xpath.Evaluate("descendant::area", self.docObj.body) #print "-------------------------------------------------------" #print xmlAreas @@ -507,7 +527,7 @@ class plasma(samba): parentNode.removeChild(xmlArea.nextSibling.nextSibling) parentNode.removeChild(xmlArea.nextSibling) continue - + # Собираем поля в кучку xmlChildAreas = xpath.Evaluate("child::area", xmlArea) if xmlChildAreas: @@ -535,6 +555,15 @@ class plasma(samba): "br": xmlArea.insertBefore(childNodes[it], firstChildArea) + # Добавление перевода строк в если его нет между полями + if self.docObj.getTypeField(node) == "var" and\ + node.previousSibling and\ + not (self.docObj.getTypeField(node.previousSibling) in\ + ("br","comment")): + xmlArea.insertBefore(self.docObj.createField("br", + [],"",[], + False,False), + node) # Добавляем BR если его нет первым полем xmlFields = xpath.Evaluate("child::field", xmlArea) @@ -581,17 +610,10 @@ class plasma(samba): 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 index 4dc2a34..c4a9c75 100644 --- a/pym/format/postfix.py +++ b/pym/format/postfix.py @@ -115,3 +115,4 @@ class postfix(apache): fields.append(field) field = fieldData() return fields + diff --git a/pym/format/samba.py b/pym/format/samba.py index 981cc52..f2d963a 100644 --- a/pym/format/samba.py +++ b/pym/format/samba.py @@ -62,6 +62,21 @@ class samba(objShare): [],"",[], False,False), nextNode) + # Удаление лишних переводов строк + childNodes = self.docObj.getFieldsArea(self.docObj.body) + lenBr = 0 + removeBrNodes = [] + for node in childNodes: + if node.tagName == "field" and\ + self.docObj.getTypeField(node) == "br": + lenBr += 1 + if lenBr > 2: + removeBrNodes.append(node) + else: + lenBr = 0 + # Удаление + for rmNode in removeBrNodes: + self.docObj.body.removeChild(rmNode) def join(self, sambaObj): @@ -258,4 +273,4 @@ class samba(objShare): z += 1 #print docObj.doc.toprettyxml() return docObj - + diff --git a/pym/format/squid.py b/pym/format/squid.py index fba8153..06d91f9 100644 --- a/pym/format/squid.py +++ b/pym/format/squid.py @@ -84,3 +84,4 @@ class squid(procmail): 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 index 84894bd..59f5994 100644 --- a/pym/format/xml_gconf.py +++ b/pym/format/xml_gconf.py @@ -25,7 +25,6 @@ tr = lang() tr.setLocalDomain('cl_lib') tr.setLanguage(sys.modules[__name__]) - class xml_gconf(xml_xfce): """Класс для объединения gconf-xml файлов""" # root нода @@ -42,6 +41,8 @@ class xml_gconf(xml_xfce): _comment = ("") # поддерживаемые аттрибуты тега entry. Пример supportEntryTypes = ("int", "bool", "float", "string", "list", "pair") + # регулярное выражения для поиска \t в начале строки (преобразование xml) + reStartTabs = re.compile("^(\t+)(.*)$") def __init__(self, text): self.text = text @@ -81,7 +82,8 @@ class xml_gconf(xml_xfce): """Сравнение содержимого двух списков 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.hasAttribute("mtime") and\ + x.removeAttribute("mtime") or x, map(lambda x: x.cloneNode(True), filter(lambda x: x.nodeType==x.ELEMENT_NODE, y)))) if set(getTextsNodes(listXmlA))==set(getTextsNodes(listXmlB)): @@ -103,13 +105,16 @@ class xml_gconf(xml_xfce): nName = u'' nType = u'' nValue = u'' + nSchema = u'' attrName = '' - attrType = '' if flagRootNode: if not tagName == "gconf": self.setError(_("The text is not a valid gconf-XML format \ (not found '...')")) return False + flagType = False + flagValue = False + flagSchema = False else: if not tagName == "entry": self.setError(_("The text is not a valid gconf-XML format \ @@ -118,20 +123,27 @@ class xml_gconf(xml_xfce): if not n.hasAttribute("name"): self.setError(_('Not found arrtibute "name" in tag entry')) return False - if not n.hasAttribute("type"): + flagType = n.hasAttribute("type") + flagValue = False + flagSchema = n.hasAttribute("schema") + if flagSchema: + nSchema = n.getAttribute("schema") + if not flagType and not flagSchema: self.setError(_('Not found arrtibute "type" in tag entry')) return False nName = n.getAttribute("name") attrName = u"attribute::name='%s'"%nName - 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 flagType: + flagValue = n.hasAttribute("value") + nType = n.getAttribute("type") + # Проверка правильности аттрибута type + if not nType in self.supportEntryTypes: + self.setError(\ + _('Incorrect arrtibute "type" - ')\ + %nType) + return False + if flagValue: + nValue = n.getAttribute("value") if n.hasAttribute("action"): nAction = n.getAttribute("action") if not nAction in ("join","replace","drop"): @@ -142,13 +154,9 @@ Valid values attribute 'action': \ 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 + findAttrStr = "" + if attrName: + findAttrStr = "[%s]"%attrName findPath = u"child::%s%s"%(tagName,findAttrStr) # Рабочая нода if flagRootNode: @@ -156,16 +164,19 @@ Valid values attribute 'action': \ else: workNode = xmlOldNode oldNodes = xpath.Evaluate(findPath, workNode) - # Новая нода список - flagArray = False - if nType == "list" or nType == "pair": - flagArray = True - flagDrop = False + # По умолчанию - объединение flagJoin = True flagReplace = False + flagDrop = False + # Замещаем ноду if nType=="string" or nAction=="replace": flagJoin = False flagReplace = True + # Замещаем ноду в случае массива + elif nType == "list" or nType == "pair": + flagJoin = False + flagReplace = True + # Удаляем ноду elif nAction == "drop": flagJoin = False flagDrop = True @@ -180,29 +191,34 @@ 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: + if flagType and flagValue: + flagChange = False + foundValue = nextOldNode.hasAttribute("value") + if foundValue: + oValue = nextOldNode.getAttribute("value") + if nValue != oValue: + flagChange = True + else: + flagChange = True + if flagChange: nextOldNode.setAttribute("mtime", self.currentTime) nextOldNode.setAttribute("value",nValue) + elif flagSchema: + flagChange = False + foundValue = nextOldNode.hasAttribute("schema") + if foundValue: + oSchema = nextOldNode.getAttribute("schema") + if nSchema != oSchema: + flagChange = True + else: + flagChange = True + if flagChange: + nextOldNode.setAttribute("mtime", + self.currentTime) + nextOldNode.setAttribute("schema",nSchema) # Замещение ноды elif flagReplace: replaceXmlNode = xmlNode.cloneNode(True) @@ -252,11 +268,31 @@ the same nodes at one level") self.joinDoc(xml_gconfObj.doc) except: self.setError(_("Can not join template")) - return False + return False return True def getConfig(self): """Получение текстового файла из XML документа""" + def expandStartTabs(s): + if s.startswith("\t"): + res = self.reStartTabs.search(s) + return res.group(1).replace("\t"," ") + res.group(2) + else: + return s data = self.doc.toprettyxml().split("\n") - data = filter(lambda x: x.strip(), data) - return "\n".join(data).replace("\t"," ") + data = map(lambda x: expandStartTabs(x), + filter(lambda x: x.strip(), data)) + dataOut = [] + z = 0 + lenData = len(data) + lenM2 = lenData - 2 + for i in xrange(lenData): + if z>0: + z -= 1 + continue + if i < lenM2 and data[i].endswith(">") and not "<" in data[i+1]: + dataOut.append(data[i] + data[i+1].strip() + data[i+2].strip()) + z = 2 + continue + dataOut.append(data[i]) + return "\n".join(dataOut) diff --git a/pym/format/xml_xfce.py b/pym/format/xml_xfce.py index 9acc947..5e39d59 100644 --- a/pym/format/xml_xfce.py +++ b/pym/format/xml_xfce.py @@ -158,7 +158,6 @@ Valid values attribute 'action': \ self.setError(textError) return False if xmlOldNode.parentNode: - findStr = u"child::%s"%path strAttr = [attrName, attrType] findAttr = filter(lambda x: x, strAttr) findAttrStr = '' @@ -266,3 +265,4 @@ the same nodes at one level") 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 index 4e9eb06..5b0bd98 100644 --- a/pym/format/xml_xfcepanel.py +++ b/pym/format/xml_xfcepanel.py @@ -43,7 +43,7 @@ class xml_xfcepanel(xml_xfce): try: self.doc = xml.dom.minidom.parseString(self.text) except: - self.setError(_("Can not text profile is XML")) + self.setError(_("Can not text template is XML")) return False self.rootNode = self.doc.documentElement self.bodyNode = self.rootNode @@ -54,7 +54,7 @@ class xml_xfcepanel(xml_xfce): return True def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True, levelNumber=0): - """Объединение корневой ноды профиля и корневой ноды файла""" + """Объединение корневой ноды шаблона и корневой ноды файла""" xmlNode = xmlNewNode childNodes = xmlNode.childNodes nextOldNode = xmlOldNode @@ -80,14 +80,13 @@ class xml_xfcepanel(xml_xfce): if n.hasAttribute("action"): nAction = n.getAttribute("action") if not nAction in ("join","replace","drop"): - textError = _('''In the text, XML profile, look \ + 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 findAttrStr = "" if attrName: findAttrStr = "[%s]"%attrName @@ -120,7 +119,7 @@ Valid values attribute 'action': \ self.panelNumbers[levelNumber] = 0 if oldNodes: if len(oldNodes)>1 and path != "panel": - textError = _("The uncertainty in this profile are \ + textError = _("The uncertainty in this template are \ the same nodes at one level") self.setError(textError) return False @@ -194,6 +193,7 @@ the same nodes at one level") try: self.joinDoc(xml_xfceObj.doc) except: - self.setError(_("Can not join profile")) + self.setError(_("Can not join template")) return False return True + diff --git a/pym/server/encrypt.py b/pym/server/encrypt.py deleted file mode 100644 index 4dfbcfe..0000000 --- a/pym/server/encrypt.py +++ /dev/null @@ -1,178 +0,0 @@ -#-*- coding: utf-8 -*- - -# Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys -import os -import hashlib -import crypt -import string -import time -from random import choice -from base64 import urlsafe_b64encode as b64encode -from cl_print import color_print -from server.users import users -from server.utils import execProg -import cl_lang -# Перевод модуля -tr = cl_lang.lang() -tr.setLocalDomain('cl_lib') -tr.setLanguage(sys.modules[__name__]) - - -class encrypt(color_print): - """Класс хранения общих методов используемых для настройки сервисов - - Методы шифрования, создания сертификатов и.т. д - """ - - def __GenCryptSalt__(self): - """Генерация соли для хеширования пароля (CRYPT)""" - chars = string.letters + string.digits + "./" - salt = "" - for i in range(2): - salt = salt + choice(chars) - return salt - - def getHashPasswd(self, password, crypt): - """Генерация хеша пароля, - - Поддерживаемые алгоритмы шифрования пароля: - plain, md5, smd5, crypt, sha, ssha - """ - if not password: - self.printERROR(_("ERROR") + " getHashPasswd: " +\ - _("password empty")) - return False - - hashPwd = "" - if crypt == "plain": - hashPwd = password - - elif crypt == "md5": - h = hashlib.md5(password) - hashPwd = "{MD5}" + b64encode(h.digest()) - - elif crypt == "smd5": - salt = os.urandom(4) - h = hashlib.md5(password) - h.update(salt) - hashPwd = "{SMD5}" + b64encode(h.digest() + salt) - - elif crypt == "crypt": - salt = self.__GenCryptSalt__() - hashPwd = "{CRYPT}" + crypt.crypt(password, salt) - - elif crypt == "sha": - h = hashlib.sha1(password) - hashPwd = "{SHA}" + b64encode(h.digest()) - - elif crypt == "ssha": - salt = os.urandom(4) - h = hashlib.sha1(password) - h.update(salt) - hashPwd = "{SSHA}" + b64encode(h.digest() + salt) - - else: - self.printERROR(_("ERROR") + " getHashPasswd: " +\ - _("Can not support '%s' crypto algoritm")%crypt) - return False - return hashPwd - - def createCertificate(self, sslCountry="US", - sslState="California", - sslLocality="Santa Barbara", - sslOrganization="SSL Server", - sslUnit="For Testing Purposes Only", - sslCommonName="localhost", - sslEmail="root@localhost", - nsCertType="server", - sslDays=730, - sslBits=1024, - userName="root",groupName="root", - certFile="/tmp/server.pem", - certFileMode=0400, - keyFile="/tmp/server.key", - keyFileMode=0400): - """Создает сертификат""" - certAndKeyFiles = [certFile, keyFile] - foundCertFiles = filter(lambda x: os.path.exists(x), certAndKeyFiles) - if len(foundCertFiles)==2: - return True - # Удаляем файл сертификата - map(lambda x: os.remove(x), foundCertFiles) - # Объект для работы с пользователями - usersObj = users() - # получаем id и gid пользователя - uidAndGid = usersObj.getUserUidAndGid(userName, groupName) - if not uidAndGid: - return False - uid, gid = uidAndGid - textCnf="""[ req ] -prompt = no -default_bits = %s -distinguished_name = req_dn - -[ req_dn ] -C = %s -ST = %s -L = %s -O = %s -OU = %s -CN = %s -emailAddress = %s - -[ cert_type ] -nsCertType = %s -"""%(sslBits, sslCountry, sslState, sslLocality, sslOrganization, sslUnit, - sslCommonName, sslEmail, nsCertType) - # генерируем название файла конфигурации - strData = time.strftime("%Y%m%d%H%M%S",time.localtime(time.time())) - cnfFile = "/tmp/%s.cnf" %strData - sslFile = "/usr/bin/openssl" - if not os.path.exists(sslFile): - self.printERROR(_("Can not found %s")%sslFile) - return False - # Cоздание директорий - for fileName in certAndKeyFiles: - dirName = os.path.split(fileName)[0] - if not os.path.exists(dirName): - self.createUserDir(0, 0, dirName, 0755) - # Создание конфигурационного файла - usersObj.createUserFile(cnfFile, textCnf, 0, 0, 0600) - # Создание сертификата - textLine = execProg(\ - "%s req -new -x509 -nodes -config %s -days %s -out %s -keyout %s"\ - %(sslFile, cnfFile, sslDays, certFile, keyFile)) - # Удаление конфигурационного файла - if os.path.exists(cnfFile): - os.remove(cnfFile) - # Меняем права - if os.path.exists(certFile): - os.chown(certFile, uid,gid) - os.chmod(certFile, certFileMode) - if os.path.exists(keyFile): - os.chown(keyFile, uid,gid) - os.chmod(keyFile, keyFileMode) - if textLine == False: - self.printERROR(_("Can not create certificate %s")%certFile) - return False - # Проверка сертификата - textLine = execProg("%s x509 -subject -fingerprint -noout -in %s"\ - %(sslFile, certFile)) - if textLine == False: - self.printERROR(_("Can not create certificate %s")%certFile) - return False - return True \ No newline at end of file diff --git a/pym/server/ldap.py b/pym/server/ldap.py index 89495e5..6e3cd86 100644 --- a/pym/server/ldap.py +++ b/pym/server/ldap.py @@ -104,7 +104,7 @@ class iniLdapParser(iniParser): if not os.path.exists(pathIniFile): os.makedirs(pathIniFile) -class ldap(_error, color_print, shareVars): +class shareldap(_error, color_print, shareVars): """Общие методы для работы с LDAP для серверных программ""" # DN сервисов относительно базового diff --git a/setup.py b/setup.py index 52e1ddc..301cc1c 100755 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# setup.py --- Setup script for calculate-server +# setup.py --- Setup script for calculate-lib # Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org # @@ -30,7 +30,7 @@ setup( url = "http://calculate-linux.org", license = "http://www.apache.org/licenses/LICENSE-2.0", package_dir = {'calculate-lib': "."}, - packages = ['calculate-lib.pym','calculate-lib.pym.format'], + packages = ['calculate-lib.pym'], data_files = [("/usr/share/calculate/i18n",['i18n/cl_lib_ru.mo']), ("/var/calculate/remote",[])], )