|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
# Copyright 2011-2016 Mir Calculate. 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
|
|
|
from os import path
|
|
|
|
|
|
from .datavars import DataVars
|
|
|
from .server.core_interfaces import MethodsInterface
|
|
|
from .server.gen_pid import get_pid_info, ProcessMode
|
|
|
from calculate.lib.datavars import Variable
|
|
|
from calculate.lib.cl_log import log
|
|
|
from calculate.lib.utils.common import getPasswdUsers
|
|
|
from calculate.lib.utils.portage import isPkgInstalled, reVerSplitToPV
|
|
|
from calculate.lib.utils.colortext import get_color_print
|
|
|
import pwd
|
|
|
import glob
|
|
|
import calculate.lib.cl_template as cl_template
|
|
|
|
|
|
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
|
|
|
|
|
|
_ = lambda x: x
|
|
|
setLocalTranslate('cl_core3', sys.modules[__name__])
|
|
|
|
|
|
__ = getLazyLocalTranslate(_)
|
|
|
|
|
|
|
|
|
class SetupPackageError(Exception):
|
|
|
"""
|
|
|
Исключение вызванное во время настройки пакета
|
|
|
"""
|
|
|
|
|
|
|
|
|
class UpdateLogger(MethodsInterface):
|
|
|
"""
|
|
|
Логгер для обновления настроек системы
|
|
|
"""
|
|
|
|
|
|
logger = log("apply-templates",
|
|
|
filename="/var/log/calculate/update_config.log",
|
|
|
formatter="%(asctime)s - %(levelname)s - %(message)s")
|
|
|
|
|
|
def ERROR(self, *arg, **argv):
|
|
|
"""
|
|
|
Вывести ошибку в лог и на экран
|
|
|
"""
|
|
|
self.logger.error(arg[0])
|
|
|
self.printERROR(*arg, **argv)
|
|
|
|
|
|
def SUCCESS(self, *arg, **argv):
|
|
|
"""
|
|
|
Вывести сообщение в лог и на экран
|
|
|
"""
|
|
|
self.logger.info(arg[0])
|
|
|
self.printSUCCESS(*arg, **argv)
|
|
|
|
|
|
def WARNING(self, *arg, **argv):
|
|
|
"""
|
|
|
Вывести предупреждение в лог и на экран
|
|
|
"""
|
|
|
self.logger.warn(arg[0])
|
|
|
self.printWARNING(*arg, **argv)
|
|
|
|
|
|
|
|
|
class ChainProgressTemplate(cl_template.ProgressTemplate):
|
|
|
"""
|
|
|
Наложение шаблонов с определением перенастройки зависимых пакетов
|
|
|
"""
|
|
|
|
|
|
def __init__(self, startTask, endTask, *args, **kwargs):
|
|
|
self.startTask = startTask
|
|
|
self.endTask = endTask
|
|
|
cl_template.ProgressTemplate.__init__(self, *args, **kwargs)
|
|
|
|
|
|
def changeMergePackage(self, packages):
|
|
|
"""
|
|
|
Изменился настраиваемый пакет (по зависимостям)
|
|
|
"""
|
|
|
self.endTask()
|
|
|
packages = filter(isPkgInstalled,
|
|
|
packages)
|
|
|
self.startTask(_("Configuring dependencies: %s") %
|
|
|
",".join(packages))
|
|
|
return True
|
|
|
|
|
|
|
|
|
class StubVariable(Variable):
|
|
|
"""
|
|
|
Переменная-заглушка используется при обновлении настроек пакета
|
|
|
в emerge. Если переменная не найдена, то будет возвращена пустая
|
|
|
строка.
|
|
|
"""
|
|
|
value = ""
|
|
|
|
|
|
|
|
|
class UpdateConfigs(UpdateLogger):
|
|
|
"""
|
|
|
Обновить настройки пакета в пользовательских профилях
|
|
|
"""
|
|
|
|
|
|
def init(self):
|
|
|
self.color_print = get_color_print()
|
|
|
|
|
|
def getXUsers(self):
|
|
|
"""
|
|
|
Получить пользователей в X сессии
|
|
|
"""
|
|
|
return list(
|
|
|
self.clVars.Get('desktop.cl_desktop_online_user')) + ["root"]
|
|
|
|
|
|
def getConfiguredPasswdUsers(self):
|
|
|
"""
|
|
|
Получить пользоватлей, которые есть в /etc/passwd (UID>=1000)
|
|
|
и при этом у них есть настройка профиля (.calculate/ini.env)
|
|
|
"""
|
|
|
user, dn = 0, 1
|
|
|
iniEnv = ".calculate/ini.env"
|
|
|
return [x[user] for x in [(y, pwd.getpwnam(y).pw_dir) for y
|
|
|
in getPasswdUsers()] if path.exists(path.join(x[dn], iniEnv))]
|
|
|
|
|
|
|
|
|
def _setClMergePkg(self, clVars, category, nameProgram, slot=None):
|
|
|
"""
|
|
|
Установить переменную cl_merge_pkg в зависимости от category и
|
|
|
nameProgram
|
|
|
"""
|
|
|
# выбрана перенастройка всех пакетов, установленных в системе
|
|
|
if nameProgram == "all":
|
|
|
clVars.Set("cl_merge_pkg",
|
|
|
["{CATEGORY}/{PN}".format(**x) for x
|
|
|
in map(reVerSplitToPV, glob.glob('/var/db/pkg/*/*')) if x],
|
|
|
True)
|
|
|
else:
|
|
|
if slot:
|
|
|
clVars.Set("cl_merge_pkg", ["%s/%s:%s" % (category,
|
|
|
nameProgram, slot)], True)
|
|
|
else:
|
|
|
clVars.Set("cl_merge_pkg", ["%s/%s" % (category, nameProgram)],
|
|
|
True)
|
|
|
clVars.Set("cl_merge_set", "on", True)
|
|
|
|
|
|
def updateDesktopConfig(self, nameProgram, version, slot, category,
|
|
|
configPath,
|
|
|
rootSet, verbose, dispatchConf, templates_locate,
|
|
|
ebuildPhase, useClt, arch_machine):
|
|
|
"""
|
|
|
Настроить пакеты в профилях пользователей
|
|
|
"""
|
|
|
# настраиватся будут пользователи из активных X сессии
|
|
|
# и сконфигурированные
|
|
|
xUsers = [x for x in self.getXUsers() if not "(unknown)" in x]
|
|
|
if not xUsers:
|
|
|
self.logger.info(_("Package %s") % nameProgram)
|
|
|
self.logger.warn(_("X session users not found"))
|
|
|
return True
|
|
|
self.logger.info(_("Package %s") % nameProgram)
|
|
|
self.logger.info(_("Updating user configuration files"))
|
|
|
firstValue = True
|
|
|
|
|
|
clVars = DataVars()
|
|
|
try:
|
|
|
clVars.importData()
|
|
|
clVars.flIniFile()
|
|
|
setupable_users = set(xUsers + self.getConfiguredPasswdUsers())
|
|
|
for userName in list(setupable_users):
|
|
|
clVars.Set("cl_root_path", '/', True)
|
|
|
clVars.Set("ur_login", userName, True)
|
|
|
clVars.Set("cl_action", "desktop", True)
|
|
|
clVars.Set("cl_verbose_set", verbose, True)
|
|
|
clVars.Set("cl_protect_use_set", "off", True)
|
|
|
clVars.Set("cl_template_path_use", templates_locate, True)
|
|
|
clVars.Set("install.os_install_arch_machine", arch_machine,
|
|
|
True)
|
|
|
|
|
|
self._setClMergePkg(clVars, category, nameProgram)
|
|
|
|
|
|
clTempl = ChainProgressTemplate(self.startTask,
|
|
|
self.endTask,
|
|
|
self.setProgress,
|
|
|
clVars, cltObj=False,
|
|
|
printSUCCESS=self.printSUCCESS,
|
|
|
printERROR=self.printERROR,
|
|
|
askConfirm=self.askConfirm,
|
|
|
printWARNING=self.printWARNING,
|
|
|
printWarning=False)
|
|
|
clTempl.onFirstValue = lambda *args: \
|
|
|
self.startTask(
|
|
|
_("User configuring the {nameProgram} package by "
|
|
|
"Calculate Utilities").format(
|
|
|
nameProgram=nameProgram))
|
|
|
clTempl.firstValue = firstValue
|
|
|
clTempl.applyTemplates()
|
|
|
firstValue = clTempl.firstValue
|
|
|
nofastlogin_users = set(getPasswdUsers()) - setupable_users
|
|
|
fastlogin_path = self.clVars.Get(
|
|
|
'desktop.cl_desktop_fastlogin_path')
|
|
|
for user in nofastlogin_users:
|
|
|
fastlogin_user = path.join(fastlogin_path, user)
|
|
|
if path.exists(fastlogin_user):
|
|
|
try:
|
|
|
os.unlink(fastlogin_user)
|
|
|
except OSError:
|
|
|
pass
|
|
|
finally:
|
|
|
clVars.close()
|
|
|
self.endTask()
|
|
|
return True
|
|
|
|
|
|
def updateSystemConfig(self, nameProgram, version, slot, category,
|
|
|
configPath,
|
|
|
rootSet, verbose, dispatchConf, templates_locate,
|
|
|
ebuildPhase, useClt, arch_machine):
|
|
|
"""
|
|
|
Обновить конфигурационные файлы системы
|
|
|
"""
|
|
|
self.logger.info(_("Package %s") % nameProgram)
|
|
|
self.logger.info(_("Updating system cofiguration files"))
|
|
|
if not os.path.exists(configPath):
|
|
|
self.ERROR(_("Path '%s' does not exist") % configPath)
|
|
|
return False
|
|
|
|
|
|
clVars = DataVars()
|
|
|
try:
|
|
|
clVars.importData()
|
|
|
clVars.flIniFile()
|
|
|
clVars.Set("cl_root_path", configPath, True)
|
|
|
|
|
|
# если конфигурирование пакета происходит не в корне
|
|
|
if rootSet:
|
|
|
# остальные пакеты настраиваются в корень
|
|
|
clVars.Set("cl_root_path_next", '/', True)
|
|
|
|
|
|
if self.clVars.Get('core.cl_core_pkg_slot_opt') != "all":
|
|
|
self._setClMergePkg(clVars, category, nameProgram, slot)
|
|
|
else:
|
|
|
self._setClMergePkg(clVars, category, nameProgram)
|
|
|
clVars.Set("cl_action", 'merge', True)
|
|
|
clVars.Set("cl_verbose_set", verbose, True)
|
|
|
clVars.Set("cl_dispatch_conf", dispatchConf, True)
|
|
|
clVars.Set("cl_template_path_use", templates_locate, True)
|
|
|
clVars.Set("core.cl_core_pkg_slot", slot, True)
|
|
|
clVars.Set("install.os_install_arch_machine", arch_machine, True)
|
|
|
useClt = useClt in (True, "on")
|
|
|
|
|
|
dictVer = {slot: version}
|
|
|
cl_template.templateFunction.installProg.update(
|
|
|
{"%s/%s" % (category, nameProgram): dictVer,
|
|
|
"%s" % nameProgram: dictVer})
|
|
|
|
|
|
# используем объект шаблонов
|
|
|
# с clt шаблонами, clt фильтром, без использования postDispatchConf
|
|
|
clTempl = ChainProgressTemplate(
|
|
|
self.startTask,
|
|
|
self.endTask,
|
|
|
self.setProgress,
|
|
|
clVars, cltObj=useClt,
|
|
|
cltFilter=True,
|
|
|
printSUCCESS=self.printSUCCESS,
|
|
|
printERROR=self.printERROR,
|
|
|
printWARNING=self.printWARNING,
|
|
|
askConfirm=self.askConfirm,
|
|
|
dispatchConf=self.dispatchConf
|
|
|
if not ebuildPhase and self.isInteractive() else None,
|
|
|
printWarning=False)
|
|
|
# выводим сообщение о настройке пакета только если действительно
|
|
|
# менялись файлы
|
|
|
clTempl.onFirstValue = lambda *args: \
|
|
|
self.startTask(_("System configuring for {nameProgram} "
|
|
|
"package by Calculate Utilities").format(
|
|
|
nameProgram=nameProgram))
|
|
|
clTempl.applyTemplates()
|
|
|
finally:
|
|
|
clVars.close()
|
|
|
self.endTask()
|
|
|
return True
|
|
|
|
|
|
def patchPackage(self, configPath, nameProgram, arch_machine):
|
|
|
"""
|
|
|
Наложить патчи на пакет
|
|
|
"""
|
|
|
self.clVars.Set("cl_root_path", configPath, True)
|
|
|
self.clVars.Set("install.os_install_arch_machine", arch_machine, True)
|
|
|
clTempl = ChainProgressTemplate(self.startTask,
|
|
|
self.endTask,
|
|
|
self.setProgress,
|
|
|
self.clVars, cltObj=False,
|
|
|
printSUCCESS=self.printSUCCESS,
|
|
|
printERROR=self.printERROR,
|
|
|
askConfirm=self.askConfirm,
|
|
|
printWARNING=self.printWARNING,
|
|
|
printWarning=False)
|
|
|
clTempl.onFirstValue = lambda *args: self.startTask(
|
|
|
_("Using patches for the {nameProgram} package by "
|
|
|
"Calculate Utilities").format(
|
|
|
nameProgram=nameProgram),
|
|
|
progress=True)
|
|
|
clTempl.applyTemplates()
|
|
|
return True
|
|
|
|
|
|
def checkRunning(self):
|
|
|
"""
|
|
|
Проверить наличие запущенных процессов в cl-core
|
|
|
"""
|
|
|
from .server.loaded_methods import LoadedMethods
|
|
|
|
|
|
cur_pid = os.getpid()
|
|
|
pid_list = [pid for pid in get_pid_info(self.clVars)
|
|
|
if (pid.get("mode", '') == ProcessMode.CoreDaemon and
|
|
|
pid.get("os_pid", '') != cur_pid)]
|
|
|
if pid_list:
|
|
|
_print = self.color_print
|
|
|
method_names = {value[0]: value[2] for key, value in
|
|
|
LoadedMethods.conMethods.items()}
|
|
|
self.printSUCCESS(
|
|
|
_("Calculate core is executing the following tasks"))
|
|
|
mult = _print.bold("*")
|
|
|
for pid in pid_list:
|
|
|
name = pid['name']
|
|
|
method_name = method_names.get(name, name)
|
|
|
self.printDefault(
|
|
|
" {mult} {title} ({name})".format(mult=mult,
|
|
|
title=method_name,
|
|
|
name=name))
|
|
|
answer = self.askConfirm(
|
|
|
_("Would you like to terminate these tasks?"), "no")
|
|
|
if answer == "no":
|
|
|
raise KeyboardInterrupt
|
|
|
return True
|
|
|
|
|
|
def restartService(self, service_name):
|
|
|
"""
|
|
|
Перезапустить указанный сервис
|
|
|
"""
|
|
|
import time
|
|
|
|
|
|
time.sleep(1)
|
|
|
os.system('/etc/init.d/%s restart &>/dev/null &' % service_name)
|
|
|
return True
|
|
|
|
|
|
def processConfig(self, nameProgram, version, slot, category,
|
|
|
verbose, dispatchConf, templates_locate,
|
|
|
ebuildPhase, useClt, arch_machine):
|
|
|
"""
|
|
|
Обновить конфигурационные файлы системы
|
|
|
"""
|
|
|
self.logger.info(_("Package %s") % nameProgram)
|
|
|
self.logger.info(_("Updating system cofiguration files"))
|
|
|
|
|
|
clVars = DataVars()
|
|
|
try:
|
|
|
clVars.importData()
|
|
|
clVars.flIniFile()
|
|
|
clVars.Set("cl_root_path", "/", True)
|
|
|
|
|
|
if self.clVars.Get('core.cl_core_pkg_slot_opt') != "all":
|
|
|
self._setClMergePkg(clVars, category, nameProgram, slot)
|
|
|
else:
|
|
|
self._setClMergePkg(clVars, category, nameProgram)
|
|
|
clVars.Set("cl_action", 'config', True)
|
|
|
clVars.Set("cl_verbose_set", verbose, True)
|
|
|
clVars.Set("cl_dispatch_conf", dispatchConf, True)
|
|
|
clVars.Set("cl_template_path_use", templates_locate, True)
|
|
|
clVars.Set("core.cl_core_pkg_slot", slot, True)
|
|
|
useClt = False
|
|
|
|
|
|
#dictVer = {slot: version}
|
|
|
#cl_template.templateFunction.installProg.update(
|
|
|
# {"%s/%s" % (category, nameProgram): dictVer,
|
|
|
# "%s" % nameProgram: dictVer})
|
|
|
|
|
|
# используем объект шаблонов
|
|
|
# с clt шаблонами, clt фильтром, без использования postDispatchConf
|
|
|
clTempl = ChainProgressTemplate(
|
|
|
self.startTask,
|
|
|
self.endTask,
|
|
|
self.setProgress,
|
|
|
clVars, cltObj=useClt,
|
|
|
cltFilter=True,
|
|
|
printSUCCESS=self.printSUCCESS,
|
|
|
printERROR=self.printERROR,
|
|
|
printWARNING=self.printWARNING,
|
|
|
askConfirm=self.askConfirm,
|
|
|
dispatchConf=self.dispatchConf
|
|
|
if not ebuildPhase and self.isInteractive() else None,
|
|
|
printWarning=False)
|
|
|
# выводим сообщение о настройке пакета только если действительно
|
|
|
# менялись файлы
|
|
|
clTempl.onFirstValue = lambda *args: \
|
|
|
self.startTask(_("System configuring for {nameProgram} "
|
|
|
"package by Calculate Utilities").format(
|
|
|
nameProgram=nameProgram))
|
|
|
clTempl.applyTemplates()
|
|
|
finally:
|
|
|
clVars.close()
|
|
|
self.endTask()
|
|
|
return True
|