#-*- coding: utf-8 -*- # Copyright 2008-2010 Calculate Ltd. http://www.calculate-linux.org # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os import sys from cl_utils import convertStrListDict, getpathenv, runOsCommand,\ pathJoin, _toUNICODE from cl_vars_share import varsShare as glob_attr import re from cl_lang import lang from cl_template import iniParser from cl_string import columnWrite import cl_overriding # Перевод модуля на другой язык tr = lang() tr.setLocalDomain('cl_lib') tr.setLanguage(sys.modules[__name__]) class var: '''Объект "Переменная окружения"''' # название сервиса которому принадлежит переменная #(Main, Builder, Client итд) # была ли установлена переменная isSet = False # Для какой программы переменная service = None # значение переменной value = "" # режим записи (атрибут mode) mode = "r" # скрытая переменная hide = False # был ли вызван метод заполнения isCallFill = False # объект в котором создан этот объект parentObj = None # запускать или нет метод заполнения fillStart = True # dynamic = True то переменная динамическая при повтороном запуске # запускается метод заполнения # метод заполнения не запускается только если fillStart = False # (осторожно возможно зацикливание программы если методы заполнения # переменных используют методы друг друга) dynamic = False def __init__(self, parentObj): # словарь зависимых переменных {имя:значение} self.dependValues = {} # объект который создал этот объект self.parentObj = parentObj def is_update(self): #Нужно ли перезапускать метод заполнения (если зависимые переменные #обновились то нужно) upd = False for depVarName in self.dependValues.keys(): value = getattr(self.parentObj, depVarName).Get() if self.dependValues[depVarName] != value: self.dependValues[depVarName] =\ getattr(self.parentObj, depVarName).value upd = True break return upd def Get(self): """Получение значения переменной""" if not self.fillStart: self.isSet = True return self.value if self.dynamic: self.value = self.Fill() self.isSet = True return self.value if not self.isSet: if self.isCallFill: self.isSet = True return self.value self.isCallFill = True self.value = self.Fill() if self.dependValues and self.is_update(): self.isCallFill = True self.value = self.Fill() self.isSet = True return self.value def Set(self, value): """Запись значения переменной""" self.value = value self.isSet = True return self.value def Fill(self): """Заполнение переменной в дальнейшем заменяем методом заполнения""" return self.value class DataVars(object): """Класс хранения переменных шаблонов""" class DataVarsError(Exception): """Класс ошибок""" pass # Импортируемые модули - (раздел: модуль переменных, модуль заполнения #переменных) __modlist={'Main':('cl_vars','cl_fill')} def __init__(self): # Для нахождения зависимостей переменных self.__levelNumber = 0 self.__LevelsVar = [] # Для хранения импортированных модулей и объектов #[(cекция,импортированный модуль переменных, объект заполнения),] self._importList = [] self.importData("Main") # Переменные которые нужно записать self.varsNeedWritten = [] def importData(self, section, modlist=[]): """Импортирует модули с переменными и модули с функциями заполнения section секция раздела (Main, Client итд) создает необходимые структуры данных """ if modlist: self.__modlist.update({section:modlist}) 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: globals()[modVar] = __import__(modVar) except (ImportError, AttributeError), e: err1 = _("Error in importing module %s")%modVar err2 = _("error") + ": " +str(e) raise self.DataVarsError("%s\n%s"%(err1,err2)) flagFindFillModule = True try: globals()[modFill] = __import__(modFill) except (ImportError, AttributeError), e: if "No module named" in str(e): flagFindFillModule = False else: err1 = _("Error in importing module %s")%modFill err2 = _("error") + ": " +str(e) raise self.DataVarsError("%s\n%s"%(err1,err2)) if flagFindFillModule: # Создаем объект с методами заполнения переменных fillObj = globals()[modFill].fillVars() # Подключаем методы получения и записи переменных fillObj.Get = self.Get fillObj.Set = self.Set fillObj.GetList = self.GetList fillObj.SetList = self.SetList else: fillObj = False # Заполняем self._importList self._importList.insert(0,(section,globals()[modVar],fillObj)) def __findVarData(self, nameVar): """Находит данные для создания объекта переменная в модулях и объектах """ # Ищем переменную в модуле dataVar = False dataVarWork = False e = False for sectionWork, moduleVar, fillobj in self._importList: if not hasattr(moduleVar.Data, nameVar): continue dataVarWork = getattr(moduleVar.Data, nameVar) section = sectionWork if dataVar is False: dataVar = dataVarWork if dataVar == False: err1 = _("Variable %s not found")%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 and hasattr(fillobj, nameMethod): flagFindMetod = True method = getattr(fillobj, nameMethod) break if flagFindMetod: return (dataVar,method) else: return (dataVar,False) def __setAttributesVar(self, var, nameVar, dictVar): """Установка аттрибутов для созданного объекта var название аттрибута и его значение берется из словаря dictVar """ if not set(dictVar.keys()) <= set(dir(var)): raise self.DataVarsError(\ _("error in initalizing variable %s, incorrect data")%nameVar) for nameAttr in dictVar.keys(): setattr(var, nameAttr, dictVar[nameAttr]) return True def __Get(self, nameVar): ret = "" self.__LevelsVar.append((self.__levelNumber, nameVar)) self.__levelNumber += 1 #nameMethod = "get_" + nameVar if hasattr(self, nameVar): ret = getattr(self, nameVar).Get() elif self.__findVarData(nameVar): dictVar, methodFill =self.__findVarData(nameVar) varobj = var(self) # Устанавливаем аттрибуты self.__setAttributesVar(varobj, nameVar, dictVar) if methodFill: varobj.Fill = methodFill setattr(self, nameVar, varobj) ret = getattr(self, nameVar).Get() self.__levelNumber -= 1 if self.__levelNumber == 0 and\ getattr(self, nameVar).fillStart and\ len(self.__LevelsVar)>1: links = self.__getLinks(self.__LevelsVar) for name in links.keys(): for nameLink in links[name].keys(): val = getattr(self, nameLink).Get() getattr(self, name).dependValues[nameLink] = val if self.__levelNumber == 0: self.__LevelsVar = [] return ret def Get(self, nameVar): return self.__Get(nameVar) def __Set(self, nameVar, value, force=False): nameMethod = "get_" + nameVar if not hasattr(self, nameVar) and self.__findVarData(nameVar): dictVar, methodFill =self.__findVarData(nameVar) varobj = var(self) # Устанавливаем аттрибуты self.__setAttributesVar(varobj, nameVar, dictVar) if methodFill: varobj.Fill = methodFill setattr(self, nameVar, varobj) if hasattr(self, nameVar): if not force and "r" in getattr(self, nameVar).mode: cl_overriding.printERROR(\ _("Attempt to rewrite a variable for reading") +\ ": %s"%nameVar) return False getattr(self, nameVar).fillStart = False return getattr(self, nameVar).Set(value) def Set(self, nameVar, value, force=False): return self.__Set(nameVar, value, force) def SetWriteVar(self, nameVar, value, force=False): """Установка значения переменной, и запись в список сохраняемых переменных""" ret = self.__Set(nameVar, value, force) if ret and not nameVar in self.varsNeedWritten: self.varsNeedWritten.append(nameVar) return ret def WriteVars(self, location='default', header=False): """Запись переменных установленных командой SetWriteVar""" flagSuccess = True for nameVar in self.varsNeedWritten: if not self.Write(nameVar, self.Get(nameVar), force=False, location=location, header=header): flagSuccess = False break return flagSuccess 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, location): """Получить путь к ini файлу по алиасу пути""" retData = self.Get('cl_env_data') ini_dict = {} ini_dict.update(retData) if location in ini_dict.keys(): name_calculate_ini = ini_dict[location] else: cl_overriding.printERROR(\ _("Unable to find alias '%s' of the path to the file " "storing template variables templates")%location) cl_overriding.exit(1) return pathJoin(self.Get('cl_chroot_path'), name_calculate_ini) def __getSection(self, vname): """секция для записи в ini файл переменной vname - имя переменной """ if not hasattr(self, vname): try: self.Get(vname) except self.DataVarsError, e: cl_overriding.printERROR(_("Template variable %s not found")\ %vname) cl_overriding.printERROR(e) cl_overriding.exit(1) return getattr(self, vname).service.lower() def __writeVarValue(self, vname, val, location, header): '''Записать значение в calculate.ini Параметры: vname имя переменной val значение переменной location расположение ini файла ('default', 'local', 'remote') header раздел ini файла ('client', 'server', 'main') Возвращаемые значение: True запись успешна False запись не удалaсь ''' # получаем путь до ini файла name_calculate_ini = self.__getPathCalculateIni(location) # извлекаем из полного имени файла путь onlydir = os.path.split(name_calculate_ini)[0] try: # проверяем чтобы путь до ини файла существовал if not os.path.exists(onlydir): # создаем его если отсутствует os.makedirs(onlydir) except OSError (nerr,msg): cl_overriding.printERROR(str(nerr) + " " + str(msg)) return False config = iniParser(name_calculate_ini) # Получаем секцию конфигурационного файла if not header: header = self.__getSection(vname) return config.setVar(header,{vname: convertStrListDict(val)}) def __deleteVarValue(self, vname, location, header): '''Удалить переменную в calculate.ini Параметры: vname имя переменной location расположение ini файла ('default', 'local', 'remote') Возвращаемые значение: True удалено успешна False удаление не удалось ''' # получаем путь до ini файла name_calculate_ini = self.__getPathCalculateIni(location) # извлекаем из полного имени файла путь 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) # Удаляем переменную allVars = config.getAreaVars(header) if allVars is False: return False if vname in allVars.keys(): 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 return True def Write(self,vname,val=None,force=False,location='default',header=False): '''Установить и записать значение переменной в ini файл Параметры: vname имя переменной val значение переменной force "принудительный режим" location расположение ini файла ('default', 'local', 'remote') header раздел ini файла ('client', 'server', 'main') ''' if val is None: val = self.Get(vname) else: if self.__Set(vname, val, force) is False: return False if 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: act_section.append(service.lower()) return act_section def zipVars(self,*argvVarNames): """Get zip() the value of the variable name""" return zip(*map(self.Get,argvVarNames)) def GetIniVar(self, section_dot_nameVar): """Получить значение переменной из конфигурационного файла section_dot_nameVar - "имя_секции.имя_переменной_профиля" """ calculate_ini_files = self.Get('cl_env_path') section, spl, name_var = section_dot_nameVar.rpartition(".") if section and name_var: pass elif name_var: section = "main" else: cl_overriding.printERROR(\ _("error Datavars.GetIniVar: empty section")) return False # Значение переменной в env файлах valueVar = "" for name_calculate_ini in calculate_ini_files: # проверить сущестование ini файла if os.path.exists(name_calculate_ini): # получить объект настроенный на ini config = iniParser(name_calculate_ini) # получаем значение переменной из секции data = config.getVar(section, name_var, checkExistVar=True) if data is False: return False existsVar, value = data if existsVar: valueVar = value return valueVar.encode("UTF-8") def GetRemoteInfo(self, envFile): """Получение информационных переменных из файла envFile""" optionsInfo = {} # получить объект настроенный на ini config = iniParser(envFile) # получаем все секции из конфигурационного файла allsect = config.getAllSectionNames() if allsect: # Секция (название сервиса) for section in allsect: allvars = config.getAreaVars(section) if allvars == False: return False # Опции сервиса options = {} for varName, value in allvars.items(): varName = varName.encode("UTF-8") value=convertStrListDict(value.encode("UTF-8")) options[varName] = value if options: optionsInfo[section] = options return optionsInfo def flIniFile(self): '''Заместить значение переменных значениями из ини файлов Возвращаемые значения: cловарь импортированных переменных - переменные считаны False - файл не был обнаружен ''' #Cловарь переменных из ini файлов importVars = {} calculate_ini_files = self.Get('cl_env_path') # активные секции (секции из которых будут использованы переменные) act_section = self.__getActiveSections() set_act_section = set(act_section) i = 0 # Алиасы к путям env locations = self.Get('cl_env_location') for name_calculate_ini in calculate_ini_files: # проверить сущестование 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 = 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 defined(self, vname): """Имеет ли значение переменная""" try: value = self.Get(vname) except: cl_overriding.printERROR(_("error, variable %s not found")% str(vname)) cl_overriding.exit(1) if value: return True else: return False #def defined(self, vname): #return True def exists(self, nameVar): """ Определяет существует ли переменная с таким имененм """ if hasattr(self, nameVar): return True foundVar = False # Ищем переменную в импортируемых модулях for section, moduleVar, fillobj in self._importList: if hasattr(moduleVar.Data, nameVar): foundVar = True break return foundVar def getVars(self, varsFilter=None, varsNames=[], verbose=1): """Словарь переменных для печати""" # проверка фильтра reFilter = False if varsFilter: try: reFilter = re.compile("%s"%varsFilter) except: cl_overriding.printERROR(_("wrong variable filter '%s'")\ %str(varsFilter)) cl_overriding.exit(1) ret = {} dictServicesVars = {} for section, moduleVar, fillobj in self._importList: dataVar = moduleVar.Data dictVars = dir(dataVar) for nameVar in dictVars: if not "__" in nameVar and (not\ (getattr(dataVar,nameVar).has_key("hide") and\ getattr(dataVar,nameVar)['hide']) or verbose>1 \ or varsFilter): if varsNames and not nameVar in varsNames: continue if reFilter and not reFilter.search(nameVar): continue self.Get(nameVar) variable = getattr(self, nameVar) service = variable.service.lower() ret[nameVar] = variable if not service in dictServicesVars: dictServicesVars[service] = {} dictServicesVars[service][nameVar] = variable return ret, dictServicesVars def printVars(self, varsFilter=None, varsNames=[], outFormat="default", verbose=1): """распечатать список переменных с значениями""" def getLenElements(varsDict): mlen_name=0; mlen_type=0; mlen_mode=0; for i,j in varsDict.items(): if len(i)>mlen_name: mlen_name=len(i) if not '[' in varsDict[i].mode: mode="[%s]"%(varsDict[i].mode.lower()) varsDict[i].mode=mode if len(mode)>mlen_mode: mlen_mode=len(mode) return mlen_name, mlen_type, mlen_mode def printVarsTable(varsDict, title, lenList=()): """print variables table""" if lenList: mlen_name, mlen_type, mlen_mode = lenList; else: mlen_name, mlen_type, mlen_mode = getLenElements(varsDict) plist=varsDict.keys() plist.sort() br = "-"*mlen_name + " " +\ "-"*mlen_mode + " " + "-"*10 cl_overriding.printSUCCESS(title) cl_overriding.printSUCCESS(br) cl_overriding.printSUCCESS(\ _toUNICODE(_("Variable name")).center(mlen_name).encode('UTF-8') +\ " " + _("Mode") + " " +_("Value")) cl_overriding.printSUCCESS(br) for i in plist: if i.endswith("_pw") and varsDict[i].value: p_val = "***" else: p_val=varsDict[i].value columnWrite(i, mlen_name, varsDict[i].mode.lower(), mlen_mode, p_val) var, dictPkgVars = self.getVars(varsFilter, varsNames, verbose=verbose) if outFormat == "default": lenList = getLenElements(var) libService = 'main' if libService in dictPkgVars: var = dictPkgVars.pop(libService) printVarsTable(var, _("The list of %s variables:")%'library', lenList=lenList) for service in dictPkgVars.keys(): var = dictPkgVars[service] cl_overriding.printSUCCESS("") printVarsTable(var, _("The list of %s variables:")%service, lenList=lenList) elif outFormat == "xml": xmlObj = _varsXML() varNames = sorted(var.keys()) for name in varNames: if name.endswith("_pw"): value = "***" else: value = var[name].value typeVar = type(value) if typeVar in (str, int, float): xmlObj.addVar(name, value) elif typeVar == list: valueList = value xmlObj.addList(name, valueList) elif typeVar == dict: valueDict = value xmlObj.addDict(name, valueDict) cl_overriding.printSUCCESS(xmlObj.toXML(),printBR=False) def GetList(self, nameVar, spl=","): """Получить значение переменной в виде списка если значение переменной: строка - разделяем spl (по умолчанию ',') и выводим список, кроме строки - выводим как есть """ value = self.Get(nameVar) if type(value) in (str, unicode): return map(lambda x: x.strip(), value.split(spl)) return value def SetList(self, nameVar, value, force=False, spl=","): """Записать список в переменную в виде строки, элементы разделены spl если значение переменной: список - объединяем через spl (по умолчанию ',') список в строку, записываем кроме списка - записываем """ if type(value) == list: strValue = ",".join(value) else: strValue = value return self.Set(nameVar, strValue, force) def WriteList(self, vname, val=None, force=False, location='default', header=False, spl=","): """Записать список в переменную в виде строки и записать в ini файл (элементы разделены spl) если значение переменной: список - объединяем через spl (по умолчанию ',') список в строку, записываем кроме списка - записываем """ if val is None: val = self.Get(vname) if type(val) == list: strValue = ",".join(val) else: strValue = val if not strValue and type(strValue) in (str, unicode): if self.__Set(vname, strValue, force) is False: return False if not self.__deleteVarValue(vname, location, header): return False return True return self.Write(vname, strValue, force, location, header) def AppendToList(self, nameVar, value, force=False, spl=",", unique=True): """Добавление в переменную со строковым значением элемента Разделитель элементов spl (по умолчанию ',') """ listValues = self.GetList(nameVar, spl) if type(listValues) == list: listValues = filter(lambda x: x, listValues) if unique: if not value in listValues: listValues.append(value) else: listValues.append(value) return self.SetList(nameVar, listValues, force, spl) def RemoveToList(self, nameVar, value, force=False, spl=","): """Удаление из переменной со строковым значением элементов со значением value Разделитель элементов spl (по умолчанию ',') """ listValues = self.GetList(nameVar, spl) if type(listValues) == list: listValues = filter(lambda x: x, listValues) listValues = filter(lambda x: x!=value, listValues) self.SetList(nameVar, listValues, force, spl) return True class _varsXML: declaration = '\n' rootElementStart = '\n' rootElementEnd = '\n' indent = " " templateVar = """%(indent)s\n\ %(indent)s%(indent)s%(value)s\n\ %(indent)s\n""" templateListStart = """%(indent)s\n""" templateListValue = """%(indent)s%(indent)s%(value)s\n""" templateListEnd = """%(indent)s\n""" templateDictStart = """%(indent)s\n""" templateDictValue = """%(indent)s%(indent)s%(value)s\ \n""" templateDictEnd = """%(indent)s\n""" templateDoc = "%(declaration)s%(rootStart)s%(vars)s%(rootEnd)s" varsXML = "" def addVar(self, name, value): """Add var to XML""" dictVar = {"indent":self.indent, "name":name, "value":self.serialize(value)} self.varsXML += self.templateVar %dictVar def addList(self, name, valueList): """Add var (valie - list) to XML""" dictVar = {"indent":self.indent, "name":name} varXml = self.templateListStart %dictVar for value in valueList: dictValue = {"indent":self.indent, "value":self.serialize(value)} varXml += self.templateListValue %dictValue varXml += self.templateListEnd %dictVar self.varsXML += varXml def addDict(self, name, valueDict): """Add var (valie - list) to XML""" dictVar = {"indent":self.indent, "name":name} varXml = self.templateDictStart %dictVar for nameDict, valueDict in valueDict.items(): dictValue = {"indent":self.indent, "name":nameDict, "value":self.serialize(valueDict)} varXml += self.templateDictValue %dictValue varXml += self.templateDictEnd %dictVar self.varsXML += varXml def serialize(self, value): """Serialization""" return str(value).replace("&","&").replace("<","<").replace(">", ">") def toXML(self): dictXML = {"declaration":self.declaration, "rootStart":self.rootElementStart, "vars":self.varsXML, "rootEnd":self.rootElementEnd} return self.templateDoc %dictXML