From b07681e60b04e6b3673ff071a7aa5cd557c91716 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: Wed, 16 Jun 2010 16:36:56 +0400 Subject: [PATCH] Added script cl-update-config --- pym/update_config/__init__.py | 1 + pym/update_config/cl_update_config.py | 209 ++++++++++++++++++++++ pym/update_config/cl_update_config_cmd.py | 103 +++++++++++ scripts/cl-update-config | 43 +++++ setup.py | 48 ++++- 5 files changed, 399 insertions(+), 5 deletions(-) create mode 100644 pym/update_config/__init__.py create mode 100644 pym/update_config/cl_update_config.py create mode 100644 pym/update_config/cl_update_config_cmd.py create mode 100644 scripts/cl-update-config diff --git a/pym/update_config/__init__.py b/pym/update_config/__init__.py new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/pym/update_config/__init__.py @@ -0,0 +1 @@ + diff --git a/pym/update_config/cl_update_config.py b/pym/update_config/cl_update_config.py new file mode 100644 index 0000000..b2b1bca --- /dev/null +++ b/pym/update_config/cl_update_config.py @@ -0,0 +1,209 @@ +#-*- 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 + +import cl_lang +# Перевод модуля +tr = cl_lang.lang() +tr.setLocalDomain('cl_lib') +tr.setLanguage(sys.modules[__name__]) + + +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 updateSystemConfigs(color_print, writeLog): + """Апдейт системных конфигурационных файлов""" + patternBelongDir = re.compile("belong\(\)") + patternBelongName = re.compile("belong\(([^\(\)]+)\)") + patternSect = re.compile("^\s*\[([^\[\]]+)\]\s*") + templatePaths = ['/usr/share/calculate-2.2/templates', + '/var/calculate/templates', + '/var/calculate/remote/templates'] + firstEnvFile = "/etc/calculate/calculate2.env" + + def _isApplyTemplateDir(self, scanDir, nameProgram, 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) + #print absPath + statInfo = os.stat(absPath)[stat.ST_MODE] + if stat.S_ISREG(statInfo): + textFile = open(absPath).read() + if "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.grpoup(1) + if ret == nameProgram: + ret = True + break + else: + ret = False + elif stat.S_ISDIR(statInfo): + ret = self._isApplyTemplateDir(absPath, nameProgram, True) + if ret: + break + return ret + + 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, configPath): + 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 = {} + 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() + if dirsFiles and dirsFiles[1]: + dictPakkages[clVars.Get("cl_name")+"-"+clVars.Get("cl_ver")] =\ + sorted(list(set(dirsFiles[1]))) + if dictPakkages: + self.logger.info(_("Package %s") %nameProgram) + 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) + return True diff --git a/pym/update_config/cl_update_config_cmd.py b/pym/update_config/cl_update_config_cmd.py new file mode 100644 index 0000000..da53d43 --- /dev/null +++ b/pym/update_config/cl_update_config_cmd.py @@ -0,0 +1,103 @@ +#-*- 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. + +from update_config.cl_update_config import updateSystemConfigs, color_print,\ + __app__, __version__ +from cl_print import color_print as old_color_print +from cl_opt import opt +import sys + +import cl_lang +# Перевод модуля +tr = cl_lang.lang() +tr.setLocalDomain('cl_lib') +tr.setLanguage(sys.modules[__name__]) + +# Использование программы +USAGE = _("%prog [options] package_name") + +# Коментарии к использованию программы +COMMENT_EXAMPLES = _("Update configuration files of package nss_ldap") + +# Пример использования программы +EXAMPLES = _("%prog --system --path / nss_ldap") + +# Описание программы (что делает программа) +DESCRIPTION = _("Update configuration files package installed") + +# Опции командной строки +CMD_OPTIONS = [{'longOption':"system", + 'help':_("update system configuration files")}, + {'longOption':"desktop", + 'help':_("update desktop (user) configuration files")}, + {'longOption':"path", + 'optVal':"PATH", + 'help':_("root path for saving the updated configuration files")}] + +class update_cmd: + def __init__(self): + # Объект опций командной строки + self.optobj = opt(\ + package=__app__, + version=__version__, + usage=USAGE, + examples=EXAMPLES, + comment_examples=COMMENT_EXAMPLES, + description=DESCRIPTION, + option_list=CMD_OPTIONS + opt.color_control, + check_values=self.checkOpts) + # Создаем объект логики + self.logicObj = updateSystemConfigs() + + def setPrintNoColor(self, optObj): + """Установка печати сообщений без цвета""" + if optObj.color and optObj.color=="never": + old_color_print.colorPrint = lambda *arg: \ + sys.stdout.write(arg[-1]) or\ + sys.stdout.flush() + + def checkOpts(self, optObj, args): + """Проверка опций командной строки""" + if not args: + errMsg = _("no such argument") + ":" + " %s" %USAGE.split(" ")[-1] + self.optobj.error(errMsg) + return False + if len(args)>1: + errMsg = _("incorrect argument") + ":" + " %s" %" ".join(args) + self.optobj.error(errMsg) + return False + if not optObj.path: + errMsg = _("no such option") + ":" + " --path" + self.optobj.error(errMsg) + return False + if not filter(lambda x: x, [optObj.system, optObj.desktop]): + errMsg = _("no such options") + ":" + " --system " + _("or") +\ + " --desktop" + self.optobj.error(errMsg) + return False + return optObj, args + + def updateSystemConfig(self, nameProgram, configPath): + """Обновление системных конфигурационных файлов""" + # Проверка есть ли в пакете защищенные конфигурационные файлы + if not self.logicObj.isExistsProtectFiles(configPath): + self.logicObj.logger.info(_("Package %s") %nameProgram) + self.logicObj.logger.warn(_("Not found protected files")) + return True + # Обновление конфигурационных файлов + if not self.logicObj.updateConfig(nameProgram, configPath): + return False + return True diff --git a/scripts/cl-update-config b/scripts/cl-update-config new file mode 100644 index 0000000..a377c3b --- /dev/null +++ b/scripts/cl-update-config @@ -0,0 +1,43 @@ +#!/usr/bin/python +#-*- 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. + +import sys +import os +sys.path.insert(0,os.path.abspath('/usr/lib/calculate-2.2/calculate-lib/pym')) +from update_config.cl_update_config_cmd import update_cmd +import cl_lang +# Перевод модуля +tr = cl_lang.lang() +tr.setLocalDomain('cl_lib') +tr.setLanguage(sys.modules[__name__]) + +if __name__ == "__main__": + obj = update_cmd() + ret = obj.optobj.parse_args() + if ret is False: + sys.exit(1) + opts, args = ret + programName = args[0] + # Установка цвета печати сообщений + obj.setPrintNoColor(opts) + # Выполняем логику программы + if opts.system: + if not obj.updateSystemConfig(programName, opts.path): + sys.exit(1) + if opts.desktop: + pass + sys.exit(0) diff --git a/setup.py b/setup.py index 817f654..e9cfd51 100755 --- a/setup.py +++ b/setup.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# -*- coding: utf-8 -*- # setup.py --- Setup script for calculate-lib @@ -16,14 +17,47 @@ # See the License for the specific language governing permissions and # limitations under the License. - -import sys +import sys, os from distutils.core import setup +from distutils.command.build_scripts import build_scripts +from distutils.command.install_scripts import install_scripts + +__version__ = "2.2.0.0" +__app__ = "calculate-lib" + +class cl_build_scripts(build_scripts): + """Class for build scripts""" + def run (self): + scripts = ['./scripts/cl-update-config'] + backup_build_dir = self.build_dir + backup_scripts = filter(lambda x: not x in scripts, self.scripts) + self.scripts = scripts + self.build_dir = self.build_dir + "-bin" + build_scripts.run(self) + if backup_scripts: + self.scripts = backup_scripts + self.build_dir = backup_build_dir + build_scripts.run(self) + +class cl_install_scripts(install_scripts): + """Class for install scripts""" + def run (self): + backup_install_dir = self.install_dir + backup_build_dir = self.build_dir + cl_cmd_obj = self.distribution.get_command_obj("install") + self.build_dir = self.build_dir + "-bin" + self.install_dir = os.path.join(cl_cmd_obj.install_platlib, __app__, + "bin") + install_scripts.run(self) + if os.path.exists(backup_build_dir): + self.build_dir = backup_build_dir + self.install_dir = backup_install_dir + install_scripts.run(self) setup( - name = 'calculate-lib', - version = "2.2.0.0", + name = __app__, + version = __version__, description = "The library for Calculate 2", author = "Mir Calculate Ltd.", author_email = "support@calculate.ru", @@ -33,7 +67,11 @@ setup( packages = ['calculate-lib.pym', 'calculate-lib.pym.format', 'calculate-lib.pym.server', - 'calculate-lib.pym.client'], + 'calculate-lib.pym.client', + 'calculate-lib.pym.update_config'], data_files = [("/usr/share/calculate-2.2/i18n",['i18n/cl_lib_ru.mo']), ("/var/calculate/remote",[])], + scripts=["./scripts/cl-update-config"], + cmdclass={'build_scripts':cl_build_scripts, + 'install_scripts':cl_install_scripts}, )