#-*- coding: utf-8 -*- # Copyright 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. __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 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()) packagePath = "/usr/lib/calculate-2.2" for path in os.listdir(packagePath): realPath = os.path.join(packagePath,path) if os.path.isdir(realPath): pymPath = os.path.join(realPath,"pym") if 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: sys.path.insert(0, os.path.abspath(pymPath)) 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): """Класс переменных для десктопа""" def __init__(self, section): cl_datavars.DataVars.__init__(self) self.section=section def importDataObject(self, **args): '''Заполнить конфигурацию переменных, для десктопа''' # Имя секции в calculate.env #envSection = "calculate-desktop" # заполнить переменные окружения алгоритмом по умолнанию self.importData(self.section, ('cl_vars_%s' %self.section, 'cl_fill_%s' %self.section)) self.flIniFile() class shareUpdateConfigs(color_print, writeLog): """Общие методы для обновления конфигурационных файлов""" patternBelongDir = re.compile("belong\(\)") patternBelongName = re.compile("belong\(([^\(\)]+)\)") patternSect = re.compile("^\s*\[([^\[\]]+)\]\s*") templatePaths = ['/usr/share/calculate/templates', '/var/calculate/templates', '/var/calculate/remote/templates'] firstEnvFile = "/etc/calculate/calculate2.env" reCleanVer = re.compile("\d+\.?\d*\.?\d*") def _isApplyTemplateDir(self, scanDir, nameProgram, flagSkipDesktop=True, flagDir=False): """Есть ли шаблоны в директории scanDir для пакета nameProgram выдает True, False """ ret = False if flagDir or stat.S_ISDIR(os.stat(scanDir)[stat.ST_MODE]): for fileOrDir in sorted(os.listdir(scanDir)): absPath = os.path.join(scanDir,fileOrDir) statInfo = os.stat(absPath)[stat.ST_MODE] if stat.S_ISREG(statInfo): textFile = open(absPath).read() if flagSkipDesktop and\ "cl_pass_action==desktop" in textFile: break if self.patternBelongDir.search(textFile): ret = os.path.basename(os.path.dirname(absPath)) if ret == nameProgram: ret = True break else: ret = False else: searchObj = self.patternBelongName.search(textFile) if searchObj: ret = searchObj.group(1) if ret == nameProgram: ret = True break else: ret = False elif stat.S_ISDIR(statInfo): ret = self._isApplyTemplateDir(absPath, nameProgram, True, flagSkipDesktop) if ret: break return ret 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 _getUserTemplateDirs(self, scanDir, userTemplDirs=[], flagDir=False): """Находит в директории scanDir директории шаблонов для пользователя выдает найденные директории. """ if flagDir or stat.S_ISDIR(os.stat(scanDir)[stat.ST_MODE]): for fileOrDir in sorted(os.listdir(scanDir)): absPath = os.path.join(scanDir,fileOrDir) statInfo = os.stat(absPath)[stat.ST_MODE] if stat.S_ISREG(statInfo): textFile = open(absPath).read() if "cl_pass_action==desktop" in textFile: userTemplDirs.append(scanDir) break elif stat.S_ISDIR(statInfo): self._getUserTemplateDirs(absPath, userTemplDirs, True) return userTemplDirs 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")) if not os.path.exists(self.firstEnvFile): self.printWARNING(_("File '%s' does not exist")%self.firstEnvFile) return True if not os.access(self.firstEnvFile, os.R_OK): self.printWARNING(_("Permission denied: '%s'")%self.firstEnvFile) return True sectionsWork = [] for line in open(self.firstEnvFile).readlines(): sRet = self.patternSect.search(line) if sRet: sectionsWork.append(sRet.group(1)) sectName = "desktop" dictPakkages = {} # Если установлен calculate-desktop if sectName in sectionsWork: section = "" for templatePath in self.templatePaths: fullPath = os.path.join(templatePath,sectName) if os.path.isdir(fullPath): for foundUserPath in self._getUserTemplateDirs(fullPath): if self._isApplyTemplateDir(foundUserPath, nameProgram, flagSkipDesktop=False): section = sectName break if section: # Добавление условия, что программа category/nameProgram # установлена cl_template.templateFunction.installProg.update(\ {"%s/%s"%(category,nameProgram):[version], "%s"%(nameProgram):[version]}) for userName in xUsers: clVars = DataVarsObject(section) clVars.importDataObject() clVars.Set("ur_login", userName, True) clVars.Set("cl_pass_action", section, 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"] + map(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 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 if not os.path.exists(self.firstEnvFile): self.printWARNING(_("File '%s' does not exist")%self.firstEnvFile) return True if not os.access(self.firstEnvFile, os.R_OK): self.printWARNING(_("Permission denied: '%s'")%self.firstEnvFile) return True sections = [] sectionsWork = [] for line in open(self.firstEnvFile).readlines(): sRet = self.patternSect.search(line) if sRet: sectionsWork.append(sRet.group(1)) #sectionsWork = os.listdir(self.templatePaths[0]) for sectName in sectionsWork: for templatePath in self.templatePaths: fullPath = os.path.join(templatePath,sectName) if not sectName in sections and os.path.isdir(fullPath): if self._isApplyTemplateDir(fullPath, nameProgram): sections.append(sectName) dictPakkages = {} if sections: # Добавление условия, что программа category/nameProgram установлена cl_template.templateFunction.installProg.update(\ {"%s/%s"%(category,nameProgram):[version], "%s"%(nameProgram):[version]}) for sectName in sections: clVars = DataVarsObject(sectName) clVars.importDataObject() clVars.Set("cl_root_path",configPath, True) clVars.Set("cl_belong_pkg",nameProgram, True) clTempl = cl_template.template(clVars) dirsFiles = clTempl.applyTemplates() nameAndVerPkg = clVars.Get("cl_name")+"-"+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