#-*- coding: utf-8 -*- # Copyright 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. __version__ = "2.2.0.0" __app__ = "calculate-lib" import sys, os, stat, re from cl_log import log import cl_datavars import cl_template from cl_print import color_print as old_color_print from cl_utils import runOsCommand, scanDirectory, pathJoin import cl_overriding import cl_lang # Перевод модуля tr = cl_lang.lang() tr.setLocalDomain('cl_lib') tr.setLanguage(sys.modules[__name__]) cl_overriding.printERROR = lambda x:filter(lambda y:color_print().printERROR(y), str(x).splitlines()) class writeLog: """Класс логгирования""" logger = log("apply-templates", filename="/var/log/calculate/update_config.log", formatter="%(asctime)s - %(levelname)s - %(message)s") class color_print(old_color_print, writeLog): """Класс для переопределения печати сообщений""" _printObj = old_color_print() def printERROR(self, *arg, **argv): """Вывод на печать ошибки""" # Запись в log ошибки self.logger.error(arg[0]) self._printObj.printERROR(*arg, **argv) def printSUCCESS(self, *arg, **argv): """Вывод на печать в случае успеха без [ok] справа""" # Запись в log информации self.logger.info(arg[0]) self._printObj.printSUCCESS(*arg, **argv) def printWARNING(self, *arg, **argv): """Вывод на печать предупреждения""" # Запись в log предупреждения self.logger.warn(arg[0]) self._printObj.printWARNING(*arg, **argv) def printOK(self, *arg, **argv): """Вывод на печать в случае успеха с [ok] справа""" # Запись в log информации self.logger.info(arg[0]) self._printObj.printOK(*arg, **argv) def printNotOK(self, *arg, **argv): """Вывод на печать в случае сбоя""" # Запись в log предупреждения self.logger.error(arg[0]) self._printObj.printNotOK(*arg, **argv) class DataVarsObject(cl_datavars.DataVars): """Класс переменных для десктопа""" packagePath = "/usr/lib/calculate-2.2" def __init__(self, nameProgram): cl_datavars.DataVars.__init__(self) self.nameProgram = nameProgram def findPathVars(self): pymPath = os.path.join(self.packagePath, self.nameProgram, "pym") if os.path.isdir(pymPath) and\ len(filter(lambda x:x.startswith("cl_vars_") and\ x.endswith(".py") or x.startswith("cl_fill_") and\ x.endswith(".py"), os.listdir(pymPath)))==2: importPath = os.path.abspath(pymPath) if not importPath in sys.path: sys.path.insert(0, importPath) return True return False def importDataObject(self, **args): '''Заполнить конфигурацию переменных, для десктопа''' # заполнить переменные окружения алгоритмом по умолнанию sectName = self.nameProgram.rpartition("-")[2] self.importData(sectName, ('cl_vars_%s' %sectName, 'cl_fill_%s' %sectName)) self.flIniFile() class shareUpdateConfigs(color_print, writeLog): """Общие методы для обновления конфигурационных файлов""" reCleanVer = re.compile("\d+\.?\d*\.?\d*") def getPrograms(self): """Получаем установленные программы работающие с шаблонами""" clVars = cl_datavars.DataVars() clVars.flIniFile() return clVars.GetList("cl_merges") class updateUserConfigs(shareUpdateConfigs): """Обновление пользовательских конфигурационных файлов""" def getXUsers(self): """Имена пользователей в X сессии""" xSession = 0 foundTwoSession = False retCode, resWho = runOsCommand("who") xUsers = [] if retCode==0: if resWho and type(resWho) == list: xUsers = map(lambda x: x[0], filter(lambda x: x[1].startswith(":"), map(lambda x: filter(lambda y: y, x.split(" "))[:2] ,resWho))) else: self.printERROR(_("Can not execute 'who'")) return False return xUsers def updateConfig(self, nameProgram, category, version, xUsers): """Обновление конфигурационных файлов у пользователей""" cleanVer = self.reCleanVer.search(version) if cleanVer: version = cleanVer.group() self.logger.info(_("Package %s") %nameProgram) self.logger.info(_("Update desktop configuration files")) # Программы используемые для наложения шаблонов mergePrograms = self.getPrograms() if "calculate-desktop" in mergePrograms: mergePrograms = ["calculate-desktop"] else: mergePrograms = [] dictPakkages = {} # Добавление условия, что программа category/nameProgram # установлена cl_template.templateFunction.installProg.update(\ {"%s/%s"%(category,nameProgram):[version], "%s"%(nameProgram):[version]}) for mergeProgram in mergePrograms: for userName in xUsers: clVars = DataVarsObject(mergeProgram) if not clVars.findPathVars(): continue clVars.importDataObject() clVars.Set("ur_login", userName, True) clVars.Set("cl_action", "desktop", True) clVars.Set("cl_belong_pkg", nameProgram, True) clTempl = cl_template.template(clVars) dirsFiles = clTempl.applyTemplates() if dirsFiles is False: self.printERROR(\ _("Error using templates for the user %s")\ %userName) for errMess in clTempl.getError().splitlines(): self.printERROR(errMess) return False if dirsFiles and dirsFiles[1]: nameAndVerPkg = clVars.Get("cl_name")+"-"+\ clVars.Get("cl_ver") if not nameAndVerPkg in dictPakkages: dictPakkages[nameAndVerPkg] = [] dictPakkages[nameAndVerPkg].append((userName, sorted(list(set(dirsFiles[1]))))) if dictPakkages: for calcPkg in dictPakkages: self.printWARNING(_("Package %s has changed files")\ %calcPkg+":") for userName, configFiles in dictPakkages[calcPkg]: self.printWARNING(" "*2 + _("User %s")%userName + ":") for nameConfigFile in configFiles: self.printWARNING(" "*5 + nameConfigFile) if not dictPakkages: self.logger.warn(_("Not found templates")) return True class updateSystemConfigs(shareUpdateConfigs): """Обновление системных конфигурационных файлов""" def isExistsProtectFiles(self, configPath): """Есть ли в защищенных директориях конфигурационные файлы""" if not "CONFIG_PROTECT" in os.environ: self.printERROR(_("Missing environment variable CONFIG_PROTECT")) exit(1) protectPaths = ["/etc"] + filter(lambda x: x.strip(), os.environ["CONFIG_PROTECT"].split(" ")) flagFoundProtect = False for pPath in protectPaths: fPath = os.path.join(configPath, pPath[1:]) if os.path.exists(fPath) and os.listdir(fPath): flagFoundProtect = True break if not flagFoundProtect: return False return True def scanProtectDirs(self, configPath): configFiles = [] scanObj = scanDirectory() scanObj.processingFile = lambda path,prefix:configFiles.append(path) or\ True protectPaths = ["/etc"] + filter(lambda x: x.strip(), os.environ["CONFIG_PROTECT"].split(" ")) configPath = os.path.realpath(configPath) for pPath in protectPaths: realPath = pathJoin(configPath, pPath) if os.path.exists(realPath): scanObj.scanningDirectory(realPath) configFiles = map(lambda x: x.partition(configPath)[2], configFiles) return configFiles def updateConfig(self, nameProgram, category, version, configPath): """Обновление системных конфигурационных файлов""" cleanVer = self.reCleanVer.search(version) if cleanVer: version = cleanVer.group() self.logger.info(_("Package %s") %nameProgram) self.logger.info(_("Update system cofiguration files")) if not os.path.exists(configPath): self.printERROR(_("Path '%s' does not exist")%configPath) return False # Программы используемые для наложения шаблонов mergePrograms = self.getPrograms() dictPakkages = {} # Добавление условия, что программа category/nameProgram установлена cl_template.templateFunction.installProg.update(\ {"%s/%s"%(category,nameProgram):[version], "%s"%(nameProgram):[version]}) for mergeProgram in mergePrograms: clVars = DataVarsObject(mergeProgram) if not clVars.findPathVars(): continue clVars.importDataObject() clVars.Set("cl_root_path", configPath, True) clVars.Set("cl_belong_pkg", nameProgram, True) clVars.Set("cl_action", 'merge', True) configFiles = [] nameProg = clVars.Get("cl_name") if nameProg == "calculate-install": configFiles = self.scanProtectDirs(configPath) cltObject = cl_template.templateClt(clVars) if configFiles: cltObject.filterApplyTemplates = configFiles else: cltObject.filterApplyTemplates = [] clTempl = cl_template.template(clVars, cltObj=cltObject) dirsFiles = clTempl.applyTemplates() nameAndVerPkg = nameProg + "-"+clVars.Get("cl_ver") if dirsFiles is False: self.printERROR(_("Error template in a package %s")\ %nameAndVerPkg) for errMess in clTempl.getError().splitlines(): self.printERROR(errMess) return False if dirsFiles and dirsFiles[1]: dictPakkages[nameAndVerPkg] =\ sorted(list(set(dirsFiles[1]))) if dictPakkages: for calcPkg in dictPakkages: self.printWARNING(_("Package %s has changed files")%calcPkg+":") for nameF in dictPakkages[calcPkg]: nameFile = nameF.partition(configPath)[2] if nameFile[:1] != "/": nameFile = "/" + nameFile self.printWARNING(" "*5 + nameFile) else: self.logger.warn(_("Not found templates")) return True