#-*- 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, fillstr, getpathenv, runOsCommand,\
pathJoin
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"
# переменная для внутреннего использования (official)
official = 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 import 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 import 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
e = False
for section, moduleVar, fillobj in self._importList:
try:
dataVar = getattr(moduleVar.Data, nameVar)
except AttributeError, e:
pass
if not dataVar is False:
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 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 initalize 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 the alias '%s' of the file path for \
storage of 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(_("Not found template variable %s")\
%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)
# Удаляем переменную
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=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 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 var %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=[]):
"""Словарь переменных для печати"""
# проверка фильтра
reFilter = False
if varsFilter:
try:
reFilter = re.compile("^%s$"%varsFilter)
except:
cl_overriding.printERROR(_("wrong vars filter '%s'")\
%str(varsFilter))
cl_overriding.exit(1)
ret = {}
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("official") and\
getattr(dataVar,nameVar)['official']):
if varsNames and not nameVar in varsNames:
continue
if reFilter and not reFilter.search(nameVar):
continue
self.Get(nameVar)
ret[nameVar] = getattr(self, nameVar)
return ret
def printVars(self, varsFilter=None, varsNames=[], outFormat="default"):
"""распечатать список переменных с значениями"""
var=None
var=self.getVars(varsFilter, varsNames)
if outFormat == "default":
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 not '[' in var[i].mode:
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 = fillstr("-",mlen_name) + " " +\
fillstr("-",mlen_mode) + " " + fillstr("-",10)
cl_overriding.printSUCCESS(_("The list of variables:"))
cl_overriding.printSUCCESS(_("Variable name").center(mlen_name) +\
" " + _("Mode") + " " +_("Value"))
cl_overriding.printSUCCESS(br)
for i in plist:
if i.endswith("_pw"):
p_val = "***"
else:
p_val=var[i].value
columnWrite(i, mlen_name, var[i].mode.lower(), mlen_mode, p_val)
cl_overriding.printSUCCESS(br)
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