You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
calculate-utils-3-console-gui/libs_crutch/core/setup_package.py

415 lines
17 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# -*- 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 calculate.core.datavars import DataVars
from calculate.core.server.core_interfaces import MethodsInterface
from calculate.core.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 map(lambda x: x[user],
filter(lambda x: path.exists(path.join(x[dn], iniEnv)),
map(lambda x: (x, pwd.getpwnam(x).pw_dir),
getPasswdUsers())))
def _setClMergePkg(self, clVars, category, nameProgram, slot=None):
"""
Установить переменную cl_merge_pkg в зависимости от category и
nameProgram
"""
# выбрана перенастройка всех пакетов, установленных в системе
if nameProgram == "all":
clVars.Set("cl_merge_pkg",
map(lambda x: "{CATEGORY}/{PN}".format(**x),
filter(None,
map(reVerSplitToPV,
glob.glob('/var/db/pkg/*/*')))),
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 = filter(lambda x: not "(unknown)" in x,
self.getXUsers())
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 calculate.core.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