fixed colortext, fixed cl-update-checker

Py3
idziubenko 3 years ago
parent fe04a136c9
commit 7f6eb54c6e

@ -15,15 +15,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#TODO: this is untested, and probably broken
import logging
# logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
logger = logging.getLogger(__name__)
import os
from os import path
from PyQt5 import QtCore, QtGui, QtWidgets
import time
from calculate.core.client.cert_info import user_can_run_update
from calculate.consolegui.application.user_update import user_can_run_update
from calculate.lib.datavars import DataVars
import dbus
import dbus.service
@ -131,6 +132,7 @@ class DBusChecker(dbus.service.Object):
self.parent = parent
# export this object to dbus
dbus.service.Object.__init__(self, name, session)
self.parent.systray.setVisible(True)
@dbus.service.method(DBUS_NAME_UPDATER, in_signature='', out_signature='')
def hide_systray(self):
@ -159,7 +161,7 @@ class CheckThread(QtWidgets.QMainWindow, UpdateInfo):
def __init__(self, bus):
super(CheckThread, self).__init__()
UpdateInfo.__init__(self)
self.bus = bus
self.wm = pyinotify.WatchManager()
@ -170,11 +172,11 @@ class CheckThread(QtWidgets.QMainWindow, UpdateInfo):
self.already_timer = QtCore.QTimer(self)
self.already_timer.timeout.connect(self.notify_step)
self.already_timer.start(1000)
self.already_timer.start(1)
self.check_timer = QtCore.QTimer(self)
self.check_timer.timeout.connect(self.step)
self.check_timer.start(self.interval * 1000)
self.check_timer.start(self.interval * 1)
self.systray = SysTray(self)
self.gui_runned = False
@ -222,10 +224,8 @@ class CheckThread(QtWidgets.QMainWindow, UpdateInfo):
if __name__ == '__main__':
import sys
if os.fork():
sys.exit(1)
if not user_can_run_update(True):
sys.stderr.write(_("User can not to perform the system update") + "\n")
sys.exit(1)
@ -236,23 +236,25 @@ if __name__ == '__main__':
sys.exit(1)
app = QtWidgets.QApplication(sys.argv)
for i in [0.5, 1, 2, 5]:
if QtWidgets.QSystemTrayIcon.isSystemTrayAvailable():
break
time.sleep(i)
# Enable glib main loop support
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
# Get the session bus
try:
bus = dbus.SessionBus()
except dbus.exceptions.DBusException, e:
except dbus.exceptions.DBusException as e:
print(e)
sys.exit(1)
try:
remote_object = bus.get_object(DBUS_NAME_UPDATER, DBUS_APP_UPDATER)
g = dbus.Interface(remote_object, DBUS_NAME_UPDATER)
props = g.getProperties()
print(props)
sys.exit(1)
except Exception as e:
pass

@ -0,0 +1,724 @@
# -*- coding: utf-8 -*-
# Copyright 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.
from __future__ import absolute_import
import sys
import os
import stat
import re
from os import path
from calculate.core.server.core_interfaces import MethodsInterface
from calculate.lib.utils.files import (makeDirectory, removeDir, tar_directory,
FilePermission, find, listDirectory,
FilesError, process, readFileEx,
readFile, pathJoin, FindFileType)
from calculate.lib.utils.content import FileOwnersRestricted, ContentsStorage
from calculate.lib.utils.portage import getInstalledAtom, makeCfgName
from calculate.lib.configparser import ConfigParserCaseSens
from calculate.lib.cl_template import Template
from calculate.lib.utils.accounts import Passwd, Group, Shadow
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from .variables.action import Actions
import tarfile
import shutil
import glob
from itertools import chain
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class BackupError(Exception):
"""
Исключение вызванное во время резервного копирования настроек
"""
class Backup(MethodsInterface):
"""
Выполнение резервного копирования настроек
"""
def init(self):
self.apply_files = set()
self.unlink_autorun = set()
self.uid_map = {}
self.gid_map = {}
def prepare_backup(self, dn, rootname):
makeDirectory(path.join(dn, rootname))
return True
def remove_directory(self, dn):
removeDir(dn)
return True
def backup_user_changed(self, owner, dn_root):
"""
Сохранить конфигурационные файлы изменённые пользователем
:param owner:
:param dn_root:
:return:
"""
for fn in owner.get_md5_failed(lambda x: x.startswith('/etc')):
self.backup_file(fn, dn_root)
return True
def prepare_contents(self, dn, contents_file, rootname):
dn_root = path.join(dn, rootname)
fo = FileOwnersRestricted(
"/", ["/%s" % x for x in find(path.join(dn, rootname),
fullpath=False)] + ["/etc"])
self.backup_user_changed(fo, dn_root)
cs = ContentsStorage(contents_file, fo)
cs.keep(dn_root, dn_root)
return True
def create_archive(self, dn, archfile):
arch_dn = path.dirname(archfile)
if not path.exists(arch_dn):
makeDirectory(arch_dn)
os.chmod(arch_dn, FilePermission.UserAll)
tar_directory(dn, archfile)
return True
def open_archive(self, dn, archfile):
makeDirectory(dn)
with tarfile.open(archfile, 'r:bz2') as f:
f.extractall(dn)
return True
def restore_configs(self, archfile, dn, contents_name, root_name):
"""
Восстановить все файлы настроек
:param archfile:
:param dn:
:return:
"""
dirs_data = {}
used_dirs = set()
_gid = lambda x: self.gid_map.get(x, x)
_uid = lambda x: self.uid_map.get(x, x)
with tarfile.open(archfile, 'r:bz2') as f:
try:
# исключить из переноса файлы, которые принадлежат пакетам,
# которые не установлены в системе
contents = f.extractfile(f.getmember(contents_name))
pkg_file = [x.split()[:3:2] for x in contents]
not_installed_files = [
x for x in pkg_file
if not any(getInstalledAtom(x[0].partition(":")[0]))]
skip_packages = sorted(list(
set([x[0] for x in not_installed_files])))
if skip_packages:
self.printWARNING(
_("Settings ignored for following packages: %s") %
", ".join(x.partition(":")[0] for x in skip_packages))
not_installed_files = [x[1] for x in not_installed_files]
except KeyError:
raise BackupError(_("CONTENTS file not found"))
for ti in (x for x in f if x.name.startswith("%s/" % root_name)):
if ti.name[4:] in not_installed_files:
continue
if ti.issym() and not path.exists(ti.linkpath):
continue
if ti.name[5:]:
fn_system = path.join(dn, ti.path[5:])
if ti.isdir():
dirs_data[fn_system] = (ti.mode, _uid(ti.uid),
_gid(ti.gid))
continue
dirs_list = fn_system.split('/')
for i in range(2, len(dirs_list)):
used_dirs.add("/".join(dirs_list[:i]))
if path.lexists(fn_system):
stat_system = os.lstat(fn_system)
if ti.issym():
if stat.S_ISLNK(stat_system.st_mode):
system_link = os.readlink(fn_system)
if system_link == ti.linkpath:
continue
else:
if (stat.S_IMODE(stat_system.st_mode) == ti.mode and
stat_system.st_uid == _uid(ti.uid) and
stat_system.st_gid == _gid(ti.gid)):
data_system = readFile(fn_system)
extr_file = f.extractfile(ti)
if extr_file:
data_ti = extr_file.read()
if self.is_equal_files(data_system,
data_ti):
continue
ti.name = ti.name[5:]
f.extract(ti, dn)
os.chown(fn_system, _uid(ti.uid), _gid(ti.gid))
if ti.isfile() or ti.issym():
# если симлинк в списке предварительного удаления
# то исключаем его из списка изменённых файлов
if fn_system in self.unlink_autorun:
self.unlink_autorun.remove(fn_system)
else:
self.apply_files.add(fn_system)
# восстановление прав у каталогов, конфиги в которых должны были
# восстанавливаться
for dn_name in sorted(used_dirs):
if dn_name in dirs_data:
dn_mode, dn_uid, dn_gid = dirs_data[dn_name]
if path.lexists(dn_name):
stat_system = os.lstat(dn_name)
if (stat.S_IMODE(stat_system.st_mode) != dn_mode or
stat_system.st_uid != dn_uid or
stat_system.st_gid != dn_gid):
os.chmod(dn_name, dn_mode)
os.chown(dn_name, dn_uid, dn_gid)
return True
def sava_ini(self, section, key, val):
ini = ConfigParserCaseSens(strict=False)
ini.read(self.clVars.Get('cl_backup_ini_env'), encoding="utf-8")
if not ini.has_section(section):
ini.add_section(section)
ini[section][key] = str(val)
ini["backup"]["version"] = self.clVars.Get('cl_ver')
with open(self.clVars.Get('cl_backup_ini_env'), 'w') as f:
ini.write(f)
return True
def load_ini(self, section, key):
ini = ConfigParserCaseSens(strict=False)
ini.read(self.clVars.Get('cl_backup_ini_env'), encoding="utf-8")
return ini.get(section, key, fallback="")
def save_initd(self, dn, root_name):
"""
Сохранить список init.d
:param dn:
:param root_name:
:return:
"""
self.sava_ini("backup", "init",
','.join(listDirectory('/etc/init.d', fullPath=False)))
dn_root = path.join(dn, root_name)
for dn in ('/etc/runlevels/sysinit',
'/etc/runlevels/default',
'/etc/runlevels/boot'):
try:
dn_backup = pathJoin(dn_root, dn)
if not path.exists(dn_backup):
makeDirectory(dn_backup)
for fn in listDirectory(dn, fullPath=True):
if path.islink(fn):
link = os.readlink(fn)
symname = pathJoin(dn_root, fn)
if not path.lexists(symname):
os.symlink(link, symname)
except (OSError, IOError) as e:
raise BackupError(_("Failed to enable service at startup") +
(_(": %s") % (str(e))))
return True
def make_directory_sync(self, base_dn, dn, prefix="/"):
"""
Создать директорию и сохранить права из prefix
:param dn:
:param prefix:
:return:
"""
if not path.exists(dn):
self.make_directory_sync(base_dn, path.dirname(dn), prefix)
rel_dn = path.relpath(dn, base_dn)
system_dn = path.join(prefix, rel_dn)
system_dn_stat = os.lstat(system_dn)
if not makeDirectory(dn):
raise BackupError(_("Failed to create directory %s") % dn)
os.chown(dn, system_dn_stat.st_uid, system_dn_stat.st_gid)
os.chmod(dn, stat.S_IMODE(system_dn_stat.st_mode))
def backup_file(self, source_fn, target_dn, prefix="/"):
"""
Сделать резервную копию указанного файла
:param source_fn:
:param target_dn:
:return:
"""
target_fn = path.join(target_dn, path.relpath(source_fn, prefix))
source_stat = os.lstat(source_fn)
target_base_dn = path.dirname(target_fn)
self.make_directory_sync(target_dn, target_base_dn, prefix=prefix)
if stat.S_ISLNK(source_stat.st_mode):
source_link = os.readlink(source_fn)
os.symlink(source_link, target_fn)
elif stat.S_ISREG(source_stat.st_mode):
shutil.copy2(source_fn, target_fn)
os.chown(target_fn, source_stat.st_uid, source_stat.st_gid)
return True
def backup_marked(self, source_dn, target_dn, subdn, root_name):
"""
Сохранить файлы из указанного каталога, отмеченного комментариями
выполнения шаблонов
:return:
"""
source_etc_dn = path.join(source_dn, subdn)
root_dn = path.join(target_dn, root_name)
reCfg = re.compile('._cfg\d{4}_')
try:
for fn in find(source_etc_dn, filetype=FindFileType.RegularFile):
if (not reCfg.search(fn) and
" Modified Calculate" in readFileEx(fn,
headbyte=300)):
self.backup_file(fn, root_dn, prefix=source_dn)
except (OSError, IOError) as e:
raise BackupError(_("Failed to backup configuration files that "
"were modified by templates") +
(_(": %s") % (str(e))))
return True
def clear_autorun(self):
"""
Удалить все файлы из автозапуска, которые ссылаются на файлы из списка
init.d
:return:
"""
files = ["/etc/init.d/%s" % x.strip()
for x in self.load_ini("backup", "init").split(',')]
for dn in ('/etc/runlevels/sysinit',
'/etc/runlevels/default',
'/etc/runlevels/boot'):
for fn in listDirectory(dn, fullPath=True):
if path.islink(fn) and os.readlink(fn) in files:
os.unlink(fn)
self.unlink_autorun.add(fn)
return True
def restore_contents(self, contentsfile, dn):
cs = ContentsStorage(contentsfile)
cs.restore(dn, files=self.apply_files)
return True
def set_service_action(self):
self.clVars.Set('core.cl_backup_action', Actions.Service, force=True)
return True
nm_name = "NetworkManager"
nm_config = "/etc/NetworkManager"
nm_connections = path.join(nm_config, "system-connections")
def _do_service(self, service, action):
"""
Выполнить действие с сервисом (restart, start, stop, zap)
:param service:
:param action:
:return:
"""
actions = {
'restart': _("Failed to restart {name} service"),
'start': _("Failed to start {name} service"),
'stop': _("Failed to stop {name} service"),
'zap': _("Failed to zap {name} service"),
'status': _("Failed to get status of {name} service")
}
try:
p = process(service, action)
if p.failed():
data = p.readerr().strip()
if ("has started, but is inactive" not in data and
"will start when" not in data):
for line in data.split('\n'):
self.printERROR(line)
raise BackupError(actions.get(action, action).format(
name=path.basename(service)))
except FilesError:
self.printERROR(actions.get(action, action).format(
name=path.basename(service)))
raise
return True
def stop_net_services(self):
"""
Остановить все сетевые службы (и NM и openrc)
:return:
"""
self._do_service("/etc/init.d/netmount", "zap")
for fn in chain(["/etc/init.d/%s" % self.nm_name],
glob.glob('/etc/init.d/net.*')):
if fn.endswith('.lo') or not path.exists(fn):
continue
self._do_service(fn, "stop")
return True
def unlink_openrc_net_services(self, files):
"""
Удалить сетевые сервисы openrc сервисы openrc
:return:
"""
for fn in glob.glob('/etc/init.d/net.*'):
if fn.endswith('.lo') or not path.exists(fn) or fn in files:
continue
try:
os.unlink(fn)
self.apply_files.add(fn)
except OSError as e:
self.printERROR(_("Failed to remove %s service"),
path.basename(fn))
self.printERROR(str(e))
return True
def is_networkmanager_backup(self, backup_path):
"""
Проверить сетевой менеджер в резервной копии
:param backup_path:
:return:
"""
return path.lexists(path.join(
backup_path, "root/etc/runlevels/default/%s" % self.nm_name))
def is_networkmanager_system(self):
"""
Проверить сетевой менеджер в текущей системе
:return:
"""
return path.lexists("/etc/runlevels/default/%s" % self.nm_name)
def restore_openrc_net_initd(self, files):
"""
Восстановить сервисы net.* и запустить их
:return:
"""
for fn in files:
if not path.exists(fn):
os.symlink("/etc/init.d/net.lo", fn)
self.apply_files.add(fn)
self._do_service(fn, "start")
return True
def restore_files(self, backup_path, files, notapply=False):
"""
Восстановить указанные файлы из backup/root
:param backup_path:
:param files: список файлов (поддерживаются глобальные символы)
:return:
"""
len_source_prefix = len(path.join(backup_path, "root"))
_gid = lambda x: self.gid_map.get(x, x)
_uid = lambda x: self.uid_map.get(x, x)
for source in chain(*[glob.glob(pathJoin(backup_path, "root", x))
for x in files]):
dest = source[len_source_prefix:]
if path.lexists(source):
dn = path.dirname(dest)
if not path.exists(dn):
makeDirectory(dn)
if path.lexists(dest):
if self.is_equal_system_backup(dest, source):
continue
shutil.copy2(source, dest)
fn_stat = os.lstat(source)
os.chown(dest, _uid(fn_stat.st_uid), _gid(fn_stat.st_gid))
if not notapply:
self.apply_files.add(dest)
return True
def clear_nm_connections(self, backup_path):
"""
Удалить доступные соединения для NetworkManager
:return:
"""
base_dir = pathJoin(backup_path, "root")
for fn in listDirectory(self.nm_connections, fullPath=True):
try:
if not path.exists(pathJoin(base_dir, fn)):
os.unlink(fn)
self.apply_files.add(fn)
except OSError as e:
raise BackupError(str(e))
def is_equal_files(self, text1, text2):
"""
Сравнить два файла отбросив комментарии и пробельные символы в начале и
в конце
:param text1:
:param text2:
:return:
"""
text1 = Template.removeComment(text1).strip()
text2 = Template.removeComment(text2).strip()
return text1 == text2
def is_equal_system_backup(self, system_fn, backup_fn):
"""
Проверить одинаковый ли файл в резервной копии и системе
:param system_fn:
:param backup_fn:
:return:
"""
_gid = lambda x: self.gid_map.get(x, x)
_uid = lambda x: self.uid_map.get(x, x)
if path.islink(system_fn) != path.islink(backup_fn):
return False
if path.islink(system_fn):
return os.readlink(system_fn) == os.readlink(backup_fn)
if path.isfile(system_fn) != path.isfile(backup_fn):
return False
data_system = readFile(system_fn)
data_backup = readFile(backup_fn)
if not self.is_equal_files(data_system, data_backup):
return False
stat_system = os.lstat(system_fn)
stat_backup = os.lstat(backup_fn)
if (stat.S_IMODE(stat_system.st_mode) !=
stat.S_IMODE(stat_backup.st_mode) or
stat_system.st_uid != _uid(stat_backup.st_uid) or
stat_system.st_gid != _gid(stat_backup.st_gid)):
return False
return True
def check_backup_for_network(self, backup_path, files):
"""
Проверить конфигурационные файлы настройки сети на соответствие текущим
:param backup_path:
:return:
"""
backup_nm = self.is_networkmanager_backup(backup_path)
system_nm = self.is_networkmanager_system()
# проверить совпадает ли сетевой менеджер
if backup_nm != system_nm:
if backup_nm and not any(
getInstalledAtom("net-misc/networkmanager")):
return True
return False
# если nm проверить совпадение system-connections
if backup_nm:
connection_files = set(path.basename(x) for x in chain(
glob.glob("%s/*" % self.nm_connections),
glob.glob("%s/*" % (pathJoin(backup_path, "root",
self.nm_connections)))
))
for fn in connection_files:
system_fn = pathJoin(self.nm_connections, fn)
backup_fn = pathJoin(backup_path, "root",
self.nm_connections, fn)
if not self.is_equal_system_backup(system_fn, backup_fn):
return False
# если openrc проверить conf.d/net и соответствие net.*
else:
system_fn = "/etc/conf.d/net"
backup_fn = pathJoin(backup_path, "root", system_fn)
if not self.is_equal_system_backup(system_fn, backup_fn):
return False
system_net_set = (set(path.basename(x)
for x in glob.glob('/etc/init.d/net.*')) -
{"net.lo"})
backup_net_set = set(path.basename(x) for x in files)
if system_net_set != backup_net_set:
return False
return True
def restore_network(self, backup_path):
"""
Восстановить сеть из backup
:param backup_path:
:return:
"""
files = ["/etc/init.d/%s" % x.strip()
for x in self.load_ini("backup", "init").split(',')
if x.startswith("net.") and x != "net.lo"]
if self.check_backup_for_network(backup_path, files):
self.endTask("skip")
return True
self.stop_net_services()
self.unlink_openrc_net_services(files)
self.clear_nm_connections(backup_path)
self.restore_files(backup_path, ["/etc/conf.d/hostname",
"/etc/resolv.conf",
"/etc/hosts"])
self._do_service("/etc/init.d/hostname", "restart")
if self.is_networkmanager_backup(backup_path):
self.unlink_openrc_net_services([])
self.restore_files(backup_path, [
"/etc/NetworkManager/system-connections/*",
"/etc/NetworkManager/dispatcher.d/*",
])
self._do_service("/etc/init.d/NetworkManager", "start")
else:
self.restore_files(backup_path, ["/etc/conf.d/net"])
self.restore_openrc_net_initd(files)
self._do_service("/etc/init.d/netmount", "start")
return True
def special_backup(self, backup_path):
"""
Выполнить специализирование резервное копирование модулей
:param backup_path:
:return:
"""
for backup_obj in self.iterate_modules():
backup_obj.backup(backup_path)
return True
def special_restore(self, backup_path):
"""
Выполнить специализирование восстановление из резервной копии
:param backup_path:
:return:
"""
for backup_obj in self.iterate_modules():
backup_obj.restore(backup_path)
return True
def iterate_modules(self):
"""
Перебрать все модули backup
:return:
"""
site_packages = [path.join(x, "calculate")
for x in sys.path
if (x.endswith('site-packages') and
x.startswith('/usr/lib'))]
ret_list = []
for module, modDir in chain(
*map(lambda x: map(lambda y: (path.basename(y), y),
listDirectory(x, True, True)),
site_packages)):
if path.exists(path.join(modDir, "backup_%s.py" % module)):
if not "calculate-%s" % module in ret_list:
ret_list.append("calculate-%s" % module)
cl_backup = ret_list
for pack in cl_backup:
if pack:
module_name = '%s.backup_%s' % (pack.replace("-", "."),
pack.rpartition("-")[2])
import importlib
try:
backup_module = importlib.import_module(module_name)
backup_obj = backup_module.Backup(self, self.clVars)
yield backup_obj
except ImportError:
sys.stderr.write(_("Unable to import %s") % module_name)
def display_changed_configs(self):
"""
Отобразить список восстановленных файлов
:return:
"""
t = Template(self.clVars, printWARNING=self.printWARNING,
printERROR=self.printERROR, printSUCCESS=self.printSUCCESS)
t.verboseOutput(sorted(list(self.apply_files | self.unlink_autorun)))
return True
def display_backup_configs(self, archfile):
"""
Отобразить список помещённых в резервную копию файлов
:return:
"""
with tarfile.open(archfile, 'r:bz2') as f:
self.printWARNING(_("Calculate Utilities have backuped files")
+ _(":"))
for fn in sorted("/%s" % x.path.partition('/')[2] for x in
f.getmembers() if (not x.isdir() and (
x.path.startswith("root") or
x.path.startswith("ldap")))):
self.printSUCCESS(" " * 5 + fn)
return True
def run_openrc(self, command):
p = process("/sbin/openrc", "default")
p.success()
return True
passwd_fn = '/etc/passwd'
group_fn = '/etc/group'
shadow_fn = '/etc/shadow'
def save_accounts(self, backup_path):
accounts_path = path.join(backup_path, "accounts")
for source_fn in (self.passwd_fn, self.group_fn, self.shadow_fn):
self.backup_file(source_fn, accounts_path, prefix="/etc")
return True
def restore_accounts(self, backup_path):
accounts_path = path.join(backup_path, "accounts")
backup_passwd_fn = pathJoin(accounts_path,
path.basename(self.passwd_fn))
backup_group_fn = pathJoin(accounts_path, path.basename(self.group_fn))
backup_shadow_fn = pathJoin(accounts_path,
path.basename(self.shadow_fn))
if any(not path.exists(x) for x in (backup_passwd_fn,
backup_group_fn,
backup_shadow_fn)):
return "skip"
# пользователи
passwd = Passwd(readFile(self.passwd_fn))
backup_passwd = Passwd(readFile(backup_passwd_fn))
added_users = [x.name for x in passwd.new_users(backup_passwd)]
keep_users = [x.name for x in backup_passwd.new_users(passwd)]
if self.clVars.GetBool('cl_backup_verbose_set') and added_users:
self.printSUCCESS(
_("Restored users:") + " " + ", ".join(added_users))
self.uid_map = backup_passwd.get_uid_map(passwd)
passwd.join(backup_passwd)
with open(makeCfgName(self.passwd_fn), 'w') as f:
passwd.write(f)
os.chown(self.passwd_fn, 0, 0)
os.chmod(self.passwd_fn,
FilePermission.OtherRead |
FilePermission.GroupRead |
FilePermission.UserRead |
FilePermission.UserWrite)
# группы
groups = Group(readFile(self.group_fn))
backup_groups = Group(readFile(backup_group_fn))
added_groups = [x.name for x in groups.new_groups(backup_groups)]
if self.clVars.GetBool('cl_backup_verbose_set') and added_groups:
self.printSUCCESS(_("Restored groups:") + " "
+ ", ".join(added_groups))
self.gid_map = backup_groups.get_gid_map(groups)
groups.join(backup_groups, keep_users=keep_users)
with open(makeCfgName(self.group_fn), 'w') as f:
groups.write(f)
os.chown(self.group_fn, 0, 0)
os.chmod(self.group_fn,
FilePermission.OtherRead |
FilePermission.GroupRead |
FilePermission.UserRead |
FilePermission.UserWrite)
# пароли
shadow = Shadow(readFile(self.shadow_fn))
backup_shadow = Shadow(readFile(backup_shadow_fn))
changed_shadow = [x.name
for x in shadow.changed_passwords(backup_shadow)]
if self.clVars.GetBool('cl_backup_verbose_set') and changed_shadow:
self.printSUCCESS(_("Restored user passwords:") + " "
+ ", ".join(changed_shadow))
shadow.join(backup_shadow)
with open(makeCfgName(self.shadow_fn), 'w') as f:
shadow.write(f)
os.chown(self.shadow_fn, 0, 0)
os.chmod(self.shadow_fn,
FilePermission.UserRead |
FilePermission.UserWrite)
return True

@ -0,0 +1,68 @@
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# Copyright 2012-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.
# from server.cl_server import main
# print(main)
from __future__ import print_function
from __future__ import absolute_import
def core_main():
import sys
if hasattr(sys, "setdefaultencoding"):
sys.setdefaultencoding("utf-8")
from calculate.lib.cl_lang import setLocalTranslate
_ = lambda x: x
setLocalTranslate('cl_core', sys.modules[__name__])
from traceback import print_exc
from os import path
if not path.exists('/dev/urandom'):
sys.stderr.write("/dev/urandom not found\n")
sys.exit(1)
try:
from .server.cl_server import main
reload(sys)
from calculate.lib.datavars import CriticalError, DataVarsError
try:
sys.exit(main())
except (CriticalError, DataVarsError) as e:
sys.stderr.write("%s\n" % str(e))
sys.exit(1)
except ImportError as e:
print_exc()
cannot_import = 'cannot import name '
no_module = 'No module named '
if e.message.startswith(cannot_import):
print (_('Failed to import %s')
% e.message.rpartition(cannot_import)[2])
elif e.message.startswith(no_module):
print (_('No module named %s') %
e.message.rpartition(no_module)[2])
else:
print(e.message)
sys.exit(1)
except KeyboardInterrupt:
print()
print(_("Task interrupted"))
if (__name__ == "__main__"):
core_main()

@ -0,0 +1,692 @@
# -*- 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.
from __future__ import print_function
from itertools import cycle
from calculate.lib.utils.colortext import get_terminal_print, Terminal, \
TextState, convert_xml_to_terminal, Print
from calculate.lib.cl_progressbar import get_progress_bar
import sys
from calculate.lib.utils.files import getch, set_active_tty, get_active_tty
from calculate.lib.utils.text import tableReport
import threading
from calculate.lib.utils.tools import classificate
Colors = TextState.Colors
from calculate.lib.cl_lang import setLocalTranslate
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
class Spinner(threading.Thread):
def __init__(self, *args, **kwargs):
self.__halt = threading.Event()
self.__main_thread = threading.currentThread()
threading.Thread.__init__(self, *args, **kwargs)
self.start()
def run(self):
Terminal().cursor = False
try:
sys.stdout.write(" |")
for c in cycle('/-\|'):
sys.stdout.write('\b' + c)
sys.stdout.flush()
self.__halt.wait(0.2)
sys.stdout.flush()
if self.__halt.is_set():
sys.stdout.write('\b\b \b\b')
return
if not self.__main_thread.is_alive():
return
finally:
Terminal().cursor = True
def stop(self):
self.__halt.set()
self.join()
class Table(tableReport):
def __init__(self, *args, **kwargs):
self.res = []
tableReport.__init__(self, *args, **kwargs)
def printFunc(self, s):
self.res.append(s)
def printTable(self):
self.setAutosize()
self.printReport(printRows=False)
return "".join(self.res)
def printTable(data, header=None):
try:
if any(data):
return Table(None, header, data, colSpan=0).printTable()
else:
return ""
except Exception:
# print str(e)
raise
def echo_on(f):
def wrapper(self, *args, **kw):
oldecho = self.parent.terminal_info.echo
self.parent.terminal_info.echo = True
try:
return f(self, *args, **kw)
finally:
self.parent.terminal_info.echo = oldecho
return wrapper
class TaskState(object):
"""
Текущее состояние вывода сообщений
"""
def __init__(self, parent):
self.parent = parent
@property
def state(self):
return self.parent.task_state
def process_tags(self, s):
"""
Выполнить текстовое преобразование
"""
s = s or ""
return convert_xml_to_terminal(s).replace(" ", " ")
def display_asterisk(self, color):
"""
Отобразить маркер
"""
self.parent.printer(" ")
self.parent.printer.foreground(color).bold("*")
self.parent.printer(" ")
def _right_indent(self, indent, width=-1):
"""
Выполнить выравнивание от правого края
"""
if width > 0:
self.parent.printer('\r')
self.parent.printer.right(width - indent)
else:
self.parent.printer(" ")
def _change_asterisk(self, color, width=-1):
if width > 0:
self.parent.printer('\r')
self.display_asterisk(color)
def dotting(self):
if self.parent.spinner:
self.parent.spinner.stop()
self.parent.printer(" ...")
self.parent.printer.flush()
def _print_result(self, text, color):
width = self.parent.terminal_info.width
self._change_asterisk(color, width)
self._right_indent(len(text) + 4, width)
self.parent.printer.bold.foreground(TextState.Colors.BLUE)("[ ")
self.parent.printer.bold.foreground(color)(text)
self.parent.printer.bold.foreground(TextState.Colors.BLUE)(" ]")
self.parent.printer("\n")
def _print_ok(self):
self._print_result("ok", TextState.Colors.GREEN)
def _print_failed(self):
self._print_result("!!", TextState.Colors.RED)
def _print_skip(self):
self._print_result("skip", TextState.Colors.YELLOW)
def display_result(self, result):
func_map = {"skip": self._print_skip,
False: self._print_failed}
func_map.get(result, self._print_ok)()
self.parent.printer.flush()
def startTask(self, message, progress, num):
pass
def endTask(self, result, progress_message=None):
pass
def breakTask(self):
pass
def printMessage(self, color, message):
for i, line in classificate(self.process_tags(message).split('\n')):
self.display_asterisk(color)
self.parent.printer(line)
if not i.last:
self.parent.printer('\n')
try:
self.parent.printer.flush()
except IOError:
pass
def printERROR(self, message):
self.printMessage(Colors.RED, message)
def printSUCCESS(self, message):
self.printMessage(Colors.GREEN, message)
def printWARNING(self, message):
self.printMessage(Colors.YELLOW, message)
def startGroup(self, message):
self.parent.printer.foreground(Colors.WHITE)(self.process_tags(message))
self.parent.printer('\n')
def endGroup(self):
pass
def beginFrame(self, message):
self.parent.terminal_info.echo = False
def endFrame(self):
self.parent.terminal_info.echo = True
def addProgress(self, message):
pass
def setProgress(self, percent, short_message, long_message):
pass
@echo_on
def askConfirm(self, message, default):
self.parent.printer("\n")
while True:
try:
_print = Print(output=self.parent.printer.output)
if default in "yes":
yes_color, no_color = Colors.GREEN, Colors.LIGHT_RED
else:
yes_color, no_color = Colors.LIGHT_RED, Colors.GREEN
yes = _print.foreground(yes_color)("Yes")
no = _print.foreground(no_color)("No")
white_message = _print.foreground(Colors.WHITE)(message)
ask = raw_input(white_message + ' (%s/%s): ' % (yes, no))
except (EOFError, KeyboardInterrupt):
ask = 'no'
print()
if ask.lower() in ['n', 'no']:
return "no"
if ask.lower() in ['y', 'yes']:
return "yes"
if ask == '':
return default
def printPre(self, message):
self.parent.printer(self.process_tags(message))
self.parent.printer('\n')
def printDefault(self, message):
self.parent.printer(self.process_tags(message))
self.parent.printer('\n')
@echo_on
def askChoice(self, message, answers):
self.parent.printer("\n")
Colors = TextState.Colors
printer = self.parent.printer
_print = Print(output=printer.output)
# ability answer by first letter
firstletter = 0
i_value, i_comment = 0, 1
answerByChar = map(lambda x: x[i_value][firstletter], answers)
if filter(lambda x: answerByChar.count(x) > 1, answerByChar):
use_getch = False
sa = slice(0, None)
else:
use_getch = True
sa = slice(1)
message = _print.foreground(Colors.WHITE)(message)
full_message = (message +
' (%s): ' % ("/".join(map(
lambda x: "%s[%s]" % (x[i_comment], x[i_value][sa]),
answers))))
while True:
CTRC_C = chr(3)
if use_getch:
printer(full_message)
ask = getch()
printer("\n")
if ask in (CTRC_C, ""):
raise KeyboardInterrupt
else:
try:
ask = raw_input(full_message)
except (EOFError, KeyboardInterrupt):
printer("\n")
raise KeyboardInterrupt
ask = ask.lower()
like_answers = filter(lambda x: x[i_value].startswith(ask),
answers)
if not like_answers:
self.state.printERROR(_('The answer is uncertain'))
continue
if len(like_answers) == 1:
return like_answers[i_value][firstletter]
else:
self.state.printERROR(_('Ambiguous answer:') +
",".join(map(lambda x: x[i_comment],
like_answers)))
@echo_on
def askQuestion(self, message):
self.parent.printer("\n")
return raw_input(message + _(":"))
def askPassword(self, message, twice):
from calculate.lib.utils.common import getpass
old_tty = None
try:
if self.parent.terminal_info.is_boot_console():
old_tty = get_active_tty()
set_active_tty(1)
text1 = _("%s: ") % message
if not twice:
return getpass.getpass(text1)
text2 = _('Repeat: ')
pass1 = 'password'
pass2 = 'repeat'
try:
while pass1 != pass2:
pass1 = getpass.getpass(text1)
pass2 = getpass.getpass(text2)
if pass1 != pass2:
self.state.printERROR(_('Passwords do not match'))
except KeyboardInterrupt:
return None
passwd = pass1 if (pass1 and pass1 == pass2) else None
return passwd
finally:
if old_tty and old_tty.isdigit():
set_active_tty(int(old_tty))
def printTable(self, table_name, head, body):
self.state.printSUCCESS(message=table_name)
self.parent.printer(printTable(body, head))
class CleanState(TaskState):
"""
Ожидается вывод
"""
def startTask(self, message, progress, num):
self.printMessage(Colors.GREEN, message)
self.parent.spinner = Spinner()
self.parent.set_state('start')
if progress:
self.parent.addProgress()
def printERROR(self, message):
super(CleanState, self).printERROR(message)
self.parent.printer('\n')
def printSUCCESS(self, message):
super(CleanState, self).printSUCCESS(message)
self.parent.printer('\n')
def printWARNING(self, message):
super(CleanState, self).printWARNING(message)
self.parent.printer('\n')
class CleanStateNoProgress(CleanState):
"""
... без отображения прогрессов
"""
def startTask(self, message, progress, num):
self.display_asterisk(Colors.GREEN)
self.parent.printer(message)
self.dotting()
self.parent.set_state('start')
class StartState(TaskState):
"""
Выполняется задача (отображается spinner)
"""
def startTask(self, message, progress, num):
self.parent.endTask(True)
self.parent.startTask(message, progress, num)
def endTask(self, result, progress_message=None):
self.dotting()
self.parent.set_state('clean')
self.display_result(result)
def breakTask(self):
self.dotting()
self.parent.set_state('clean')
self.parent.printer('\n')
def printERROR(self, message):
self.dotting()
self.parent.printer('\n')
self.parent.set_state('clean')
self.state.printERROR(message)
def printSUCCESS(self, message):
self.dotting()
self.parent.set_state('breaked')
self.state.printSUCCESS(message)
def printWARNING(self, message):
self.dotting()
self.parent.set_state('breaked')
self.state.printWARNING(message)
def startGroup(self, message):
self.state.endTask(True)
self.state.startGroup(message)
def endGroup(self):
self.state.endTask(True)
self.state.endGroup()
def beginFrame(self, message):
self.state.endTask(True)
self.state.beginFrame(message)
def endFrame(self):
self.state.endTask(True)
self.state.endFrame()
def addProgress(self, message):
self.parent.set_state("pre-progress")
self.state.addProgress(message)
def printPre(self, message):
self.parent.endTask(True)
self.state.printPre(message)
def printDefault(self, message):
self.state.endTask(True)
self.state.printDefault(message)
def askChoice(self, message, answers):
self.breakTask()
return self.state.askChoice(message, answers)
def askQuestion(self, message):
self.breakTask()
return self.state.askQuestion(message)
def askPassword(self, message, twice):
self.breakTask()
return self.state.askPassword(message, twice)
def askConfirm(self, message, default):
self.breakTask()
return self.state.askConfirm(message, default)
def printTable(self, table_name, head, body):
self.breakTask()
self.state.printTable(table_name, head, body)
class StartStateNoProgress(StartState):
"""
... без прогресса
"""
def startTask(self, message, progress, num):
self.parent.endTask(True)
self.parent.startTask(message, progress, num)
def endTask(self, result, progress_message=None):
self.parent.set_state('clean')
self.display_result(result)
def breakTask(self):
self.parent.printer('\n')
def printERROR(self, message):
self.breakTask()
self.parent.set_state('clean')
self.state.printERROR(message)
def printSUCCESS(self, message):
self.breakTask()
self.parent.set_state('clean')
self.state.printSUCCESS(message)
def printWARNING(self, message):
self.breakTask()
self.parent.set_state('clean')
self.state.printWARNING(message)
def addProgress(self, message):
pass
class BreakedState(StartState):
"""
Во время выполнения задачи выведено сообщение
"""
def stop_spinner_newline(self):
self.parent.spinner.stop()
self.parent.printer('\n')
def startTask(self, message, progress, num):
self.state.endTask(True)
self.state.startTask(message, progress, num)
def breakTask(self):
self.stop_spinner_newline()
self.parent.set_state('clean')
def endTask(self, result, progress_message=None):
self.breakTask()
def printERROR(self, message):
self.parent.endTask(True)
self.state.printERROR(message)
def printSUCCESS(self, message):
self.stop_spinner_newline()
TaskState.printSUCCESS(self, message)
self.parent.spinner = Spinner()
def printWARNING(self, message):
self.stop_spinner_newline()
TaskState.printWARNING(self, message)
self.parent.spinner = Spinner()
class PreProgressState(StartState):
"""
Задача запрошена как с прогрессом но проценты еще не обрабатывались
"""
def addProgress(self, message):
pass
def setProgress(self, percent, short_message, long_message):
self.parent.set_state("progress")
self.dotting()
self.parent.printer("\n")
self.parent.add_progressbar()
self.parent.terminal_info.cursor = False
self.state.setProgress(percent, short_message, long_message)
class ProgressState(StartState):
"""
Отображается progressbar
"""
def finish_and_clean(self):
self.parent.printer('\r')
self.parent.printer.flush()
self.parent.progress.finish()
self.parent.terminal_info.cursor = True
self.parent.set_progressbar(None)
self.parent.printer.up(1).clear_line("")
self.parent.printer.up(1)("")
def setProgress(self, percent, short_message, long_message):
if not 0 <= percent <= 100:
self.breakTask()
else:
self.parent.progress.update(percent)
def breakTask(self):
self.finish_and_clean()
self.parent.set_state('clean')
self.parent.printer('\n')
def endTask(self, result, progress_message=None):
self.finish_and_clean()
self.parent.set_state('clean')
self.display_result(result)
def printERROR(self, message):
self.finish_and_clean()
self.parent.printer.down(1)("")
self.parent.set_state('clean')
self.state.printERROR(message)
def printSUCCESS(self, message):
self.finish_and_clean()
self.parent.set_state('breaked')
self.state.printSUCCESS(message)
def printWARNING(self, message):
self.finish_and_clean()
self.parent.set_state('breaked')
self.state.printWARNING(message)
class ResultViewer(object):
"""
Просмотрщик результатов
"""
def __init__(self):
self.printer = \
get_terminal_print(sys.stdout)
self.terminal_info = Terminal()
self.states = {'clean': CleanState(self),
'breaked': BreakedState(self),
'pre-progress': PreProgressState(self),
'progress': ProgressState(self),
'start': StartState(self)}
self.task_state = self.states['clean']
self.spinner = None
self.progress = None
self.no_questions = False
def set_no_progress(self):
self.states = {'clean': CleanStateNoProgress(self),
'start': StartStateNoProgress(self)}
self.set_state('clean')
def set_no_questions(self):
self.no_questions = True
def set_state(self, state):
self.task_state = self.states[state]
def add_progressbar(self):
self.set_progressbar(get_progress_bar())
def set_progressbar(self, pb):
self.progress = pb
def endTask(self, result=None, progress_message=None):
self.task_state.endTask(result, progress_message)
def startTask(self, message, progress=False, num=1):
self.task_state.startTask(message, progress, num)
def printERROR(self, message, onlyShow=None):
if onlyShow != 'gui':
self.task_state.printERROR(message)
def printSUCCESS(self, message, onlyShow=None):
if onlyShow != 'gui':
self.task_state.printSUCCESS(message)
def printWARNING(self, message, onlyShow=None):
if onlyShow != 'gui':
self.task_state.printWARNING(message)
def startGroup(self, message):
self.task_state.startGroup(message)
def endGroup(self):
self.task_state.endGroup()
def beginFrame(self, message=None):
self.task_state.beginFrame(message)
def endFrame(self):
self.task_state.endFrame()
def addProgress(self, message=None):
self.task_state.addProgress(message)
def setProgress(self, percent, short_message=None, long_message=None):
self.task_state.setProgress(percent, short_message, long_message)
def printPre(self, message, onlyShow=None):
if onlyShow != 'gui':
self.task_state.printPre(message)
def printDefault(self, message='', onlyShow=None):
if onlyShow != 'gui':
self.task_state.printDefault(message)
def askConfirm(self, message, default="yes"):
if self.no_questions:
return default
return self.task_state.askConfirm(message, default)
def askChoice(self, message, answers=(("yes", "Yes"), ("no", "No"))):
return self.task_state.askChoice(message, answers)
def askPassword(self, message, twice=False):
return self.task_state.askPassword(message, twice)
def askQuestion(self, message):
return self.task_state.askQuestion(message)
def printTable(self, table_name, head, body, fields=None,
onClick=None, addAction=None, step=None, records=None):
self.task_state.printTable(table_name, head, body)

@ -0,0 +1,129 @@
# -*- 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.
from __future__ import absolute_import
from calculate.lib.cl_progressbar import get_progress_bar, get_message_box
from calculate.lib.utils.colortext import TextState
import sys
from .result_viewer import PreProgressState, ProgressState
Colors = TextState.Colors
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_core3', sys.modules[__name__])
class PreProgressStateGui(PreProgressState):
"""
Задача запрошена как с прогрессом но проценты еще не обрабатывались
"""
def addProgress(self, message):
self.dotting()
self.parent.printer("\n")
self.parent.add_progressbar()
self.parent.set_state("progress")
class ProgressStateGui(ProgressState):
"""
Отображение для gui прогресса
"""
def finish_and_clean(self):
self.parent.progress.finish()
self.parent.printer.up(1)("")
self.parent.set_progressbar(None)
class ResultViewerDecorator(object):
def __init__(self, rv):
self.rv = rv
for v in self.rv.states.values():
v.parent = self
def __getattr__(self, item):
return getattr(self.rv, item)
class ProgressGui(ResultViewerDecorator):
"""
Отображение прогресса в Qt диалогах
"""
def __init__(self, rv):
super(ProgressGui, self).__init__(rv)
self.rv.states['pre-progress'] = PreProgressStateGui(self)
self.rv.states['progress'] = ProgressStateGui(self)
self.progress_title = ""
def add_progressbar(self):
self.set_progressbar(get_progress_bar("gui", self.progress_title))
def startTask(self, message, progress=False, num=1):
self.rv.startTask(message, progress, num)
self.progress_title = message
class ErrorGui(ResultViewerDecorator):
"""
Отображение ошибок через gui
"""
def __init__(self, rv):
super(ErrorGui, self).__init__(rv)
self.messages = []
def show_messages(self):
get_message_box().critical("\n".join(self.messages).decode('utf-8'))
def printERROR(self, message, onlyShow=None):
self.rv.printERROR(message, onlyShow)
if onlyShow != 'gui':
if message:
self.messages.append(message)
def endFrame(self):
self.rv.task_state.endFrame()
if self.messages:
self.show_messages()
class WarningGui(ResultViewerDecorator):
"""
Отображение предупреждений через gui
"""
def __init__(self, rv):
super(WarningGui, self).__init__(rv)
self.warnings = []
def show_messages(self):
get_message_box().warning("\n".join(self.warnings).decode('utf-8'))
def printWARNING(self, message, onlyShow=None):
self.rv.printWARNING(message, onlyShow)
if onlyShow != 'gui':
if message:
self.warnings.append(message)
def endFrame(self):
self.rv.task_state.endFrame()
if not self.messages and self.warnings:
self.show_messages()
elif self.messages:
self.messages.extend(self.warnings)
self.rv.show_messages()

@ -0,0 +1,113 @@
# -*- 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 re
from calculate.core.server.core_interfaces import MethodsInterface
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
VARIABLE, MODE, LOCATION, VALUE = 0, 1, 2, 3
class Variables(MethodsInterface):
def writeVariables(self, vardata):
"""
Write variable to env files, or delete from env files
"""
dv = self.clVars
data = filter(lambda x: x[LOCATION] or
not x[LOCATION] and
dv.isFromIni(x[VARIABLE]),
vardata)
if data:
head = [_("Variable"), _("Mode"), _("Location"), _("Value")]
self.printTable(_("List of variables"), head, data)
for varname, mode, location, value in data:
if location:
value = dv.unserialize(dv.getInfo(varname).type, str(value))
section, op, varname = varname.rpartition('.')
if not location:
for env_location in dv.Get('main.cl_env_location'):
if not dv.Delete(varname, env_location, header=section):
self.printWARNING(
_("Failed to delete variable {var} from "
"{location}").format(
var=varname, location=env_location))
else:
if varname in dv.iniCache:
oldValue = dv.unserialize(
dv.getInfo(varname).type,
str(dv.iniCache[varname]['value']))
else:
oldValue = None
if value != oldValue:
dv.Write(varname, value, location=location,
header=section)
else:
self.printSUCCESS("Nothing to set")
return True
def showVariables(self, showVal, filterVal, vardata):
"""
Show variables by cl_variable_filter
"""
dv = self.clVars
removeQuotes = lambda x: x if x != "''" else ""
reIndex = re.compile("((?:\w+\.)?(\w+))(?:\[(\d+)\])")
if showVal:
index = reIndex.search(showVal)
if index:
varname = index.group(1)
index = int(index.group(3))
else:
varname = showVal
prevVal = str(dv.Select('cl_variable_value',
where='cl_variable_fullname',
eq=varname, limit=1))
if index is not None:
typeVar = dv.getInfo(varname).type
val = dv.unserialize(typeVar, prevVal)
if index < len(val):
self.printDefault(removeQuotes(val[index]))
else:
self.printDefault("")
else:
self.printDefault(removeQuotes(prevVal))
return True
filter_names = {'all': None,
'userset': lambda x: x[LOCATION],
'writable': lambda x: x[MODE].startswith("w"),
'system': lambda x: x[LOCATION] == "system",
'local': lambda x: x[LOCATION] == "local",
'remote': lambda x: x[LOCATION] == "remote"}
filterFunc = filter_names.get(filterVal,
lambda x: filterVal in x[VARIABLE])
body = filter(filterFunc, vardata)
dv.close()
if body:
head = [_("Variable"), _("Mode"),
_("Location"), _("Value")]
self.printTable(_("List of variables"), head, body)
return True
else:
self.printWARNING(_("No such variables"))
return True

@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
# Copyright 2015-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 re
import os
from os import path
from itertools import chain, groupby
import time
from calculate.lib.datavars import DataVars
from calculate.lib.cl_template import templateFunction
from calculate.lib.utils.files import readFile, writeFile
get_pkgname_by_filename = templateFunction.get_pkgname_by_filename
class Cache(object):
reMerge = re.compile("(merge|mergepkg)\(([-\w/]*)(?:\[[^\]]\])?\)[-!=<>]")
rePatch = re.compile("^#\s*Calculate.*ac_install_patch==on")
PATCH_TYPE = "patch"
MERGE_TYPE = "merge"
DIRECTORY_TEMPLATE = ".calculate_directory"
CLT_SUFFIX = ".clt"
def __init__(self, dv=None):
if dv is None:
dv = DataVars()
dv.importData()
dv.flIniFile()
self.dv = dv
self.base_dn = "/var/lib/calculate/calculate-core/cache"
self.fn_mtime = path.join(self.base_dn, "merge.mtime")
self.fn_patch = path.join(self.base_dn, "merge-patch.list")
self.fn_setup = path.join(self.base_dn, "merge-setup.list")
def search_merge(self, dn):
"""
Сканировать директорию с шаблонами
"""
patch_dirs = []
for root, dirs, files in os.walk(dn):
for fn in (path.join(root, x) for x in files):
data = readFile(fn)
if self.rePatch.search(data):
if path.basename(fn) == self.DIRECTORY_TEMPLATE:
patch_dirs.append(path.dirname(fn))
patch_template = True
else:
if any(fn.startswith(x) for x in patch_dirs):
patch_template = True
else:
patch_template = False
for fname, pkg in self.reMerge.findall(data):
pkg = pkg or get_pkgname_by_filename(fn)
yield (self.PATCH_TYPE if patch_template
else self.MERGE_TYPE, pkg)
def search_merge_clt(self, dn):
"""
Сканировать clt шаблоны
"""
for root, dirs, files in os.walk(dn):
for fn in (path.join(root, x) for x in files
if x.endswith(self.CLT_SUFFIX)):
data = readFile(fn)
for fname, pkg in self.reMerge.findall(data):
pkg = pkg or get_pkgname_by_filename(fn)
yield (self.MERGE_TYPE, pkg)
@staticmethod
def check_new_that(mtime_fn, dirs, fn_filter=None):
"""
Проверить появились ли новые файлы после последней проверки
"""
if not path.exists(mtime_fn):
return True
check_mtime = os.stat(mtime_fn).st_mtime
for dn in dirs:
for root, dirs, files in os.walk(dn):
for fn in (path.join(root, x) for x in files
if fn_filter is None or fn_filter(x)):
if os.stat(fn).st_mtime > check_mtime:
return True
return False
def update(self, force=False):
template_path = self.dv.Get('main.cl_template_path')
if (force or
self.check_new_that(
self.fn_mtime, ['/etc'],
fn_filter=lambda x: x.endswith(self.CLT_SUFFIX)) or
self.check_new_that(self.fn_mtime, template_path)):
all_packages = chain(self.search_merge_clt('/etc'),
*[self.search_merge(x) for x in template_path])
for _type, pkgs in groupby(sorted(all_packages), lambda x: x[0]):
list_packages = sorted(set(y for x, y in pkgs))
if _type == self.MERGE_TYPE:
with writeFile(self.fn_setup) as f:
f.write("\n".join(list_packages))
if _type == self.PATCH_TYPE:
with writeFile(self.fn_patch) as f:
f.write("\n".join(list_packages))
with writeFile(self.fn_mtime) as f:
f.write(str(time.time()))

@ -0,0 +1,414 @@
# -*- 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(
"&nbsp;{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

@ -0,0 +1,90 @@
# -*- coding: utf-8 -*-
# Copyright 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
from calculate.core.server.func import Action, Tasks
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.utils.files import FilesError
from calculate.lib.datavars import VariableError, DataVarsError
from calculate.core.backup import BackupError
from calculate.lib.cl_template import TemplatesError
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClBackupAction(Action):
"""
Создание резервной копии настроек
"""
# ошибки, которые отображаются без подробностей
native_error = (BackupError, FilesError, DataVarsError, VariableError,
TemplatesError)
successMessage = __("Backup successfully completed!")
failedMessage = __("Failed to perform backup!")
interruptMessage = __("Backup manually interrupted")
tasks = [
{'name': 'prepare_dir',
'method': 'Backup.prepare_backup(core.cl_backup_path,'
'core.cl_backup_root_name)'
},
{'name': 'backup_marked',
'message': __("Backing up files configured by templates"),
'method': 'Backup.backup_marked("/",core.cl_backup_path,'
'"etc",core.cl_backup_root_name)'
},
{'name': 'templates',
'message': __("Templates preparing for backup"),
'method': 'Backup.applyTemplates(install.cl_source,'
'False,True,None,True,True)',
},
{'name': 'special_backup',
'method': 'Backup.special_backup(core.cl_backup_path)'
},
{'name': 'accounts_backup',
'message': __("Backing up accounts info"),
'method': 'Backup.save_accounts(core.cl_backup_path)'
},
{'name': 'prepare_content',
'message': __("Calculating checksums"),
'method': 'Backup.prepare_contents(core.cl_backup_path,'
'core.cl_backup_file_contents,core.cl_backup_root_name)',
},
{'name': 'save_initd',
'method': 'Backup.save_initd(core.cl_backup_path,'
'core.cl_backup_root_name)',
},
{'name': 'pack_backup',
'message': __("Packing backup"),
'method': 'Backup.create_archive(core.cl_backup_path,'
'core.cl_backup_file)'
},
{'name': 'remove_dir',
'message': __("Clearing temporary files"),
'method': 'Backup.remove_directory(core.cl_backup_path)',
'depend': Tasks.success_one_of("prepare_dir")
},
{'name': 'display_verbose',
'method': 'Backup.display_backup_configs(core.cl_backup_file)',
'condition': lambda Get: Get('core.cl_backup_verbose_set') == 'on'
},
{'name': 'display_arch',
'message': __("Archive created: {core.cl_backup_file}")
}
]

@ -0,0 +1,104 @@
# -*- coding: utf-8 -*-
# Copyright 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
from calculate.core.server.func import Action, Tasks
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.utils.files import FilesError
from calculate.lib.datavars import VariableError, DataVarsError
from calculate.core.backup import BackupError
from calculate.lib.cl_template import TemplatesError
from tarfile import ReadError
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClBackupRestoreAction(Action):
"""
Восстановление настроек из резервной копии
"""
# ошибки, которые отображаются без подробностей
native_error = (BackupError, FilesError, DataVarsError, VariableError,
TemplatesError, ReadError)
successMessage = __("Files successfully restored from backup!")
failedMessage = __("Failed to restore from backup!")
interruptMessage = __("Restoration from backup manually interrupted")
restore_tasks = []
tasks = [
{'name': 'unpack_backup',
'message': __("Unpacking backup"),
'method': 'Backup.open_archive(core.cl_backup_path,'
'core.cl_backup_file)'
},
{'name': 'restore_accounts',
'message': __("Restoring user accounts"),
'method': 'Backup.restore_accounts(core.cl_backup_path)'
},
{'name': 'restore_network',
'message': __("Restoring network"),
'method': 'Backup.restore_network(core.cl_backup_path)'
},
{'name': 'special_restore',
'method': 'Backup.special_restore(core.cl_backup_path)'
},
{'name': 'templates',
'message': __("Restoring services"),
'method': 'Backup.applyTemplates(install.cl_source,'
'False,True,None,True,True)',
},
{'name': 'clear_autorun',
'method': 'Backup.clear_autorun()',
},
{'name': 'restore_configs',
'message': __("Unpacking configuration files"),
'method': 'Backup.restore_configs(core.cl_backup_file,"/",'
'core.cl_backup_contents_name,core.cl_backup_root_name)'
},
{'name': 'restore_content',
'message': __("Restoring file owners"),
'method': 'Backup.restore_contents(core.cl_backup_file_contents,'
'"/")',
},
{'name': 'display_verbose',
'method': 'Backup.display_changed_configs()',
'condition': lambda Get: Get('core.cl_backup_verbose_set') == 'on'
},
{'name': 'set_service_mode',
'method': 'Backup.set_service_action()',
},
{'name': 'templates_service',
'message': __("Configuration after restoring from backup"),
'method': 'Backup.applyTemplates(install.cl_source,'
'False,True,None,True,True)',
},
{'name': 'remove_dir',
'method': 'Backup.remove_directory(core.cl_backup_path)',
'depend': Tasks.success_one_of("unpack_backup")
},
{'name': 'dispatch_conf',
'message': __("Updating configuration files"),
'method': 'Backup.dispatchConf()',
'condition': lambda Get: Get('cl_dispatch_conf') != 'skip'
},
{'name': 'openrc_default',
'message': __("Running stopped services"),
'method': 'Backup.run_openrc("default")',
}
]

@ -0,0 +1,49 @@
# -*- 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
from calculate.core.server.func import Action
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.utils.files import FilesError
from calculate.lib.datavars import VariableError, DataVarsError
from calculate.lib.cl_template import TemplatesError
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClConfigAction(Action):
"""
Действие настройка пакета для пользователя и системы
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError, TemplatesError, VariableError, DataVarsError)
templateTaskMessage = __("The system is being configured")
successMessage = None
failedMessage = __("Failed to configure the system!")
interruptMessage = __("Configuration manually interrupted")
tasks = [
{'name': 'process_config',
# наложить шаблоны настройки пакета
'method': 'UpdateConfigs.processConfig(cl_core_pkg_name,'
'cl_core_pkg_version,cl_core_pkg_slot,'
'cl_core_pkg_category,cl_verbose_set,cl_dispatch_conf,'
'cl_template_path_use,cl_ebuild_phase,'
'cl_template_clt_set,cl_core_arch_machine)',
},
]

@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
# Copyright 2013-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
from calculate.core.server.func import Action
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.datavars import VariableError
from calculate.lib.cl_template import TemplatesError
from calculate.lib.utils.files import FilesError
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClCoreCustomAction(Action):
"""
Действие для настройки параметров видео
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError, TemplatesError, VariableError)
successMessage = __("Action successfully completed!")
failedMessage = __("Failed to perform action!")
interruptMessage = __("Action manually interrupted")
def __init__(self):
# список задач для действия
self.tasks = [
{'name': 'set_vars',
'method': (
'UpdateConfigs.setVariable("install.os_install_arch_machine",'
'cl_core_arch_machine, True)')
},
{'name': 'apply_templates',
# наложить шаблоны на текущий дистрибутив, включая clt шаблоны
# без использования фильтров по clt шаблонам
'method': 'UpdateConfigs.applyTemplates(None,False,'
'None,None)',
},
{'name': 'failed_action',
'error': __("Action {ac_custom_name} not found"),
'condition': lambda Get: not filter(
lambda x: (x and x[0] == 'ac_custom_name' and
x[1] == Get('ac_custom_name')),
Get('cl_used_action'))
}
]
Action.__init__(self)

@ -0,0 +1,42 @@
# -*- 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
from calculate.core.server.func import Action
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.utils.files import FilesError
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClCoreDispatchAction(Action):
"""
Действие обновление конфигурационных файлов
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,)
successMessage = __("Dispatch complete!")
failedMessage = __("Failed to dispatch configuration files!")
interruptMessage = __("Dispatching manually interrupted")
# список задач для действия
tasks = [
{'name': 'dispatch',
'method': 'UpdateConfigs.dispatchConf()',
}]

@ -0,0 +1,92 @@
# -*- 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
from calculate.core.server.func import Action
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.utils.files import FilesError
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClCoreGroupShow(Action):
"""
Отображение групп
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,)
successMessage = None
failedMessage = None
interruptMessage = __("Viewing manually interrupted")
tasks = [
{'name': 'view_group',
'method': 'Groups.show_groups_meth(cl_page_count,cl_page_offset)'
}]
class ClCoreGroupMod(Action):
"""
Изменение группы
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,)
successMessage = __("Group {cl_core_group} changed")
failedMessage = __("Failed to change {cl_core_group} group")
interruptMessage = __("Modifying manually interrupted")
tasks = [
{'name': 'mod_group',
'method': (
'Groups.change_group_meth(cl_core_group,cl_core_group_rights,'
'cl_core_group_rights_path)')
}]
class ClCoreGroupAdd(Action):
"""
Добавление группы
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,)
successMessage = __("Group {cl_core_group} added")
failedMessage = __("Failed to add {cl_core_group} group")
interruptMessage = __("Adding manually interrupted")
tasks = [
{'name': 'add_group',
'method': 'Groups.add_group_meth(cl_core_group,cl_core_group_rights,'
'cl_core_group_rights_path)'
}]
class ClCoreGroupDel(Action):
"""
Удаление группы
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,)
successMessage = __("Group {cl_core_group} deleted")
failedMessage = __("Failed to delete {cl_core_group} group")
interruptMessage = __("Deleting manually interrupted")
tasks = [
{'name': 'del_group',
'method': 'Groups.del_group_meth(cl_core_group,'
'cl_core_group_rights_path)'
}]

@ -0,0 +1,46 @@
# -*- 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
from calculate.core.server.func import Action
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.utils.files import FilesError
from calculate.lib.datavars import VariableError, DataVarsError
from calculate.lib.cl_template import TemplatesError
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClCorePatchAction(Action):
"""
Действие наложния патчей
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError, TemplatesError, VariableError, DataVarsError)
templateTaskMessage = __("Appling patches to package sources")
successMessage = None
failedMessage = __("Failed to patch package sources!")
interruptMessage = __("Patching manually interrupted")
tasks = [
{'name': 'patch_package',
# наложить патчи для пакета
'method': 'UpdateConfigs.patchPackage(cl_core_pkg_path,'
'cl_core_pkg_name,cl_core_arch_machine)'
}
]

@ -0,0 +1,75 @@
# -*- 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
from calculate.core.server.func import Action
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.utils.files import FilesError
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClCoreRequestShow(Action):
"""
Отображение запросов
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,)
successMessage = None
failedMessage = None
interruptMessage = __("Viewing manually interrupted")
tasks = [
{'name': 'view_req',
'method': 'Request.show_request_meth(cl_page_count,cl_page_offset)'
}]
class ClCoreRequestConfirm(Action):
"""
Подтверждение запроса
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,)
successMessage = __("Certificate {cl_req_crt_path} is signed")
failedMessage = __("Failed to sign {cl_req_csr_path} request")
interruptMessage = __("Signing manually interrupted")
tasks = [
{'name': 'mod_req',
'method': 'Request.confirm_request_meth(cl_core_client_certs_path,'
'cl_core_cert_path,cl_req_csr_path,cl_req_crt_path,'
'cl_req_group)'
}]
class ClCoreRequestDel(Action):
"""
Удаление запроса
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,)
successMessage = None
failedMessage = __("Failed to delete the request with ID={cl_req_id}")
interruptMessage = __("Deleting manually interrupted")
tasks = [
{'name': 'del_req',
'method': 'Request.del_request_meth(cl_core_database,cl_req_csr_path,'
'cl_req_crt_path,cl_req_id)'
}]

@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
# Copyright 2013-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
from calculate.core.server.func import Action
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.datavars import VariableError
from calculate.lib.cl_template import TemplatesError
from calculate.lib.utils.files import FilesError
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClCoreRestartAction(Action):
"""
Действие для настройки параметров видео
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError, TemplatesError, VariableError)
successMessage = __("Action successfully completed!")
failedMessage = __("Failed to perform action!")
interruptMessage = __("Action manually interrupted")
def __init__(self):
# список задач для действия
self.tasks = [
{'name': 'check_running',
# проверить запущенные процессы
'method': 'UpdateConfigs.checkRunning()',
},
{'name': 'restart',
# перезапустить calculate-core
'message': _("Restarting calculate-core"),
'method': 'UpdateConfigs.restartService("calculate-core")',
}]
Action.__init__(self)

@ -0,0 +1,77 @@
# -*- 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
from calculate.core.server.func import Action
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.utils.files import FilesError
from calculate.lib.datavars import VariableError, DataVarsError
from calculate.lib.cl_template import TemplatesError
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClCoreSetupAction(Action):
"""
Действие настройка пакета для пользователя и системы
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError, TemplatesError, VariableError, DataVarsError)
templateTaskMessage = __("The system is being configured")
successMessage = None
failedMessage = __("Failed to configure the system!")
interruptMessage = __("Configuration manually interrupted")
tasks = [
{'name': 'system_rm_package',
# наложить шаблоны удаления пакета
'method': 'UpdateConfigs.updateSystemConfig(cl_core_pkg_name,'
'"",cl_core_pkg_slot,cl_core_pkg_category,cl_core_pkg_path,'
'cl_core_pkg_root_set,cl_verbose_set,cl_dispatch_conf,'
'cl_template_path_use,cl_ebuild_phase,'
'cl_template_clt_set,cl_core_arch_machine)',
'condition': lambda dv: (
dv.Get('cl_core_pkg_system_set') == 'on' and
dv.Get('cl_ebuild_phase') in ('prerm', 'postrm'))
},
{'name': 'system_setup_package',
# наложить шаблоны настройки пакета
'method': 'UpdateConfigs.updateSystemConfig(cl_core_pkg_name,'
'cl_core_pkg_version,cl_core_pkg_slot,'
'cl_core_pkg_category,cl_core_pkg_path,'
'cl_core_pkg_root_set,cl_verbose_set,cl_dispatch_conf,'
'cl_template_path_use,cl_ebuild_phase,'
'cl_template_clt_set,cl_core_arch_machine)',
'condition': lambda dv: (
dv.Get('cl_core_pkg_system_set') == 'on' and
dv.Get('cl_ebuild_phase') not in ('prerm', 'postrm'))
},
{'name': 'user_setup_package',
# наложить шаблоны настройки пакета
'method': 'UpdateConfigs.updateDesktopConfig(cl_core_pkg_name,'
'cl_core_pkg_version,cl_core_pkg_slot,'
'cl_core_pkg_category,cl_core_pkg_path,'
'cl_core_pkg_root_set,cl_verbose_set,cl_dispatch_conf,'
'cl_template_path_use,cl_ebuild_phase,'
'cl_template_clt_set,cl_core_arch_machine)',
'condition': lambda dv: (
dv.Get('cl_core_pkg_desktop_set') == 'on' and
dv.isModuleInstalled('desktop') and
dv.Get('cl_ebuild_phase') not in ("preinst", "prerm"))
}
]

@ -0,0 +1,62 @@
# -*- 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
from calculate.core.server.func import Action
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.utils.files import FilesError
from calculate.lib.datavars import VariableError, DataVarsError
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClCoreVariables(Action):
"""
Отображение сертификатов
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError, DataVarsError, VariableError)
successMessage = None
failedMessage = None
interruptMessage = __("Modification of variables manually interrupted")
tasks = [
{'name': 'write_vars',
# записать переменные
'method': 'Variables.writeVariables(cl_variable_data)'
}
]
class ClCoreVariablesShow(Action):
"""
Отображение сертификатов
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError, DataVarsError, VariableError)
successMessage = None
failedMessage = None
interruptMessage = __("Viewing manually interrupted")
tasks = [
{'name': 'view_vars',
# отобразить переменные
'method': 'Variables.showVariables(cl_variable_show,'
'cl_variable_filter,cl_variable_data)'
}
]

@ -0,0 +1,42 @@
# -*- 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
from calculate.core.server.func import Action
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.utils.files import FilesError
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClCoreViewCert(Action):
"""
Отображение сертификатов
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,)
successMessage = None
failedMessage = None
interruptMessage = __("Viewing manually interrupted")
tasks = [
{'name': 'view_cert',
# наложить патчи для пакета
'method': 'Certificate.show_certs_meth(cl_page_count,cl_page_offset)'
}
]

@ -0,0 +1,795 @@
# -*- 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.
from __future__ import absolute_import
import sys
from calculate.lib.datavars import VariableError, DataVarsError
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
from . import setup_package
from . import server.certificate as certificate
from . import server.groups as groups
from . import server.request as request
from . import set_vars
from .backup import Backup, BackupError
from calculate.core.utils.cl_backup import ClBackupAction
from calculate.core.utils.cl_backup_restore import ClBackupRestoreAction
from calculate.core.server.func import WsdlBase
from calculate.core.utils.cl_core_setup import ClCoreSetupAction
from calculate.core.utils.cl_core_patch import ClCorePatchAction
from calculate.core.utils.cl_config import ClConfigAction
from calculate.core.utils.cl_core_dispatch import ClCoreDispatchAction
from calculate.core.utils.cl_core_view_cert import ClCoreViewCert
from calculate.core.utils.cl_core_group import (
ClCoreGroupShow, ClCoreGroupMod, ClCoreGroupAdd, ClCoreGroupDel)
from calculate.core.utils.cl_core_request import (
ClCoreRequestShow, ClCoreRequestConfirm, ClCoreRequestDel)
from calculate.core.utils.cl_core_variables import (ClCoreVariables,
ClCoreVariablesShow)
from calculate.core.utils.cl_core_custom import ClCoreCustomAction
from calculate.core.utils.cl_core_restart import ClCoreRestartAction
from calculate.core.variables.action import Actions
class Wsdl(WsdlBase):
methods = [
#
# Настройка пакета во время установки (cl-core-setup)
#
{
# идентификатор метода
'method_name': "core_setup",
# категория метода
'category': __('Configuration'),
# заголовок метода
'title': __("Configure a Package"),
# иконка для графической консоли
'image': 'calculate-core-setup,'
'preferences-desktop-default-applications',
# метод присутствует в графической консоли
'gui': True,
# консольная команда
'command': 'cl-core-setup',
# права для запуска метода
'rights': ['setup_package'],
# объект содержащий модули для действия
'logic': {'UpdateConfigs': setup_package.UpdateConfigs},
# описание действия
'action': ClCoreSetupAction,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError,
setup_package.SetupPackageError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'merge', 'cl_verbose_set': "on"},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Configure a package"),
normal=('cl_core_pkg_name',),
expert=('cl_core_pkg_category',
'cl_core_pkg_version_opt',
'cl_core_pkg_slot_opt',
'cl_core_pkg_path',
'cl_core_arch_machine',
'cl_templates_locate',
'cl_core_pkg_system_set',
'cl_core_pkg_desktop_set',
'cl_core_pkg_root_set',
'cl_verbose_set',
'cl_dispatch_conf'),
next_label=_("Run"))]},
#
# Патч исходников пакета (cl-core-patch)
#
{
# идентификатор метода
'method_name': "core_patch",
# категория метода
'category': __('Configuration'),
# заголовок метода
'title': __("Patch"),
# иконка для графической консоли
'image': None,
# метода нет в графической консоли
'gui': False,
# консольная команда
'command': 'cl-core-patch',
# права для запуска метода
'rights': ['configure'],
# объект содержащий модули для действия
'logic': {'UpdateConfigs': setup_package.UpdateConfigs},
# описание действия
'action': ClCorePatchAction,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError,
setup_package.SetupPackageError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'patch',
'cl_protect_use_set!': 'off'},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Configure a package"),
normal=('cl_core_pkg_name',),
expert=('cl_core_pkg_category',
'cl_core_pkg_version',
'cl_core_pkg_slot',
'cl_core_pkg_path',
'cl_core_arch_machine',
'cl_templates_locate',
'cl_verbose_set'),
next_label=_("Run"))]},
#
# Обновление конфигурационных файлов (cl-dispatch-conf)
#
{
# идентификатор метода
'method_name': "core_dispatch",
# категория метода
'category': __('Update '),
# заголовок метода
'title': __("Update Settings"),
# иконка для графической консоли
'image': 'calculate-core-dispatch,edit-find-replace,computer',
# метод в графической консоли
'gui': True,
# консольная команда
'command': 'cl-dispatch-conf',
# права для запуска метода
'rights': ['configure'],
# объект содержащий модули для действия
'logic': {'UpdateConfigs': setup_package.UpdateConfigs},
# описание действия
'action': ClCoreDispatchAction,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError,
setup_package.SetupPackageError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'dispatch'},
# описание груп (список лямбда функций)
'groups': []},
#
# Отобразить сертификаты
#
{
# идентификатор метода
'method_name': "core_view_cert",
# категория метода
'category': __('Utilities'),
# заголовок метода
'title': __("Show Certificates"),
# иконка для графической консоли
'image': 'calculate-core-view-cert,certificate-server,'
'application-certificate',
# метод в графической консоли
'gui': True,
# консольная команда
'command': 'cl-core-view-cert',
# права для запуска метода
'rights': ['certificates'],
# объект содержащий модули для действия
'logic': {'Certificate': certificate.Certificate},
# описание действия
'action': ClCoreViewCert,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {
'cl_page_max!': lambda dv: len(dv.Get('cl_list_cert_id'))},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Certificates"),
normal=('cl_page_count', 'cl_page_offset'),
next_label=_("Next"))]},
#
# Отобразить детали сертификата
#
{
# идентификатор метода
'method_name': "core_detail_view_cert",
# категория метода
# 'category':__('Utilities'),
# заголовок метода
'title': __("Certificate Details"),
# иконка для графической консоли
'image': None,
# метод в графической консоли
'gui': True,
# права для запуска метода
'rights': ['certificates'],
# объект содержащий модули для действия
'logic': {},
# описание действия
'action': None,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Certificate details"),
normal=('cl_cert_id', 'cl_cert_groups',
'cl_cert_perms'),
custom_buttons=[('but0', _("Back"),
"core_view_cert",
"button")])]},
#
# Группы
#
{
# идентификатор метода
'method_name': "core_group_show",
# категория метода
'category': __('Utilities'),
# заголовок метода
'title': __("Show Groups"),
# иконка для графической консоли
'image': 'calculate-core-group-show,user-group-properties,'
'view-certificate-import,application-certificate',
# метод в графической консоли
'gui': True,
# консольная команда
'command': 'cl-core-group-show',
# права для запуска метода
'rights': ['core_group'],
# объект содержащий модули для действия
'logic': {'Groups': groups.Groups},
# описание действия
'action': ClCoreGroupShow,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {
'cl_page_max!': lambda dv: len(dv.Choice('cl_core_group'))},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Groups"),
normal=('cl_page_count', 'cl_page_offset'),
next_label=_("Next"))]},
#
# Отобразить детали группы
#
{
# идентификатор метода
'method_name': "core_detail_group",
# категория метода
# 'category':__('Utilities'),
# заголовок метода
'title': __("Group Details"),
# иконка для графической консоли
'image': None,
# метод в графической консоли
'gui': True,
# права для запуска метода
'rights': ['core_group'],
# объект содержащий модули для действия
'logic': {},
# описание действия
'action': None,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Group details"),
normal=(
'cl_core_group',
'cl_core_group_rights'),
custom_buttons=[('but0', _("Back"),
"core_group_show",
"button"),
('but1', _("Change"),
"core_group_mod",
"button"),
('but2', _("Delete"),
"core_group_del",
"button")])]},
#
# Изменить группу
#
{
# идентификатор метода
'method_name': "core_group_mod",
# категория метода
# 'category':__('Utilities'),
# заголовок метода
'title': __("Modify Group"),
# иконка для графической консоли
'image': None,
# метод в графической консоли
'gui': True,
# консольная команда
'command': 'cl-core-groupmod',
# права для запуска метода
'rights': ['core_group'],
# объект содержащий модули для действия
'logic': {'Groups': groups.Groups},
# описание действия
'action': ClCoreGroupMod,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'modify'},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Modify group"),
normal=(
'cl_core_group',
'cl_core_group_rights'),
next_label=_("Done"),
custom_buttons=[('but2', _("Confirm"),
'core_change_group',
"button")])]},
#
# Добавить группу
#
{
# идентификатор метода
'method_name': "core_group_add",
# категория метода
# 'category':__('Utilities'),
# заголовок метода
'title': __("Add a Group"),
# иконка для графической консоли
'image': None,
# метод в графической консоли
'gui': True,
# консольная команда
'command': 'cl-core-groupadd',
# права для запуска метода
'rights': ['core_group'],
# объект содержащий модули для действия
'logic': {'Groups': groups.Groups},
# описание действия
'action': ClCoreGroupAdd,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'add'},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Add a group"),
normal=(
'cl_core_group',
'cl_core_group_rights'),
next_label=_("Add"))]},
#
# Удалить группу
#
{
# идентификатор метода
'method_name': "core_group_del",
# категория метода
# 'category':__('Utilities'),
# заголовок метода
'title': __("Delete the Group"),
# иконка для графической консоли
'image': None,
# метод в графической консоли
'gui': True,
# консольная команда
'command': 'cl-core-groupdel',
# права для запуска метода
'rights': ['core_group'],
# объект содержащий модули для действия
'logic': {'Groups': groups.Groups},
# описание действия
'action': ClCoreGroupDel,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'delete'},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Delete the group"),
normal=('cl_core_group',),
next_label=_("Delete"))]},
#
# Запрос на сертификат
#
{
# идентификатор метода
'method_name': "core_request_show",
# категория метода
'category': __('Utilities'),
# заголовок метода
'title': __("Show Requests"),
# иконка для графической консоли
'image': 'calculate-core-request-show,view-certificate-import,'
'application-certificate',
# метод в графической консоли
'gui': True,
# консольная команда
'command': 'cl-core-request-show',
# права для запуска метода
'rights': ['request'],
# объект содержащий модули для действия
'logic': {'Request': request.Request},
# описание действия
'action': ClCoreRequestShow,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {
'cl_page_max!': lambda dv: len(dv.Get('cl_list_req_id'))},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Show requests"),
normal=('cl_page_count', 'cl_page_offset'),
next_label=_("Next"))]},
#
# Отобразить детали запроса
#
{
# идентификатор метода
'method_name': "core_detail_request",
# категория метода
# 'category':__('Utilities'),
# заголовок метода
'title': __("Request Details"),
# иконка для графической консоли
'image': None,
# метод в графической консоли
'gui': True,
# права для запуска метода
'rights': ['request'],
# объект содержащий модули для действия
'logic': {},
# описание действия
'action': None,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Group details"),
normal=('cl_req_id', 'cl_req_user_name',
'cl_req_ip',
'cl_req_mac', 'cl_req_date',
'cl_req_location',
'cl_req_group'),
custom_buttons=[('but0', _("Back"),
"core_request_show",
"button"),
('but1', _("Confirm"),
"core_request_confirm",
"button"),
('but2', _("Delete"),
"core_request_del",
"button")])]},
#
# Удалить запрос
#
{
# идентификатор метода
'method_name': "core_request_del",
# категория метода
# 'category':__('Utilities'),
# заголовок метода
'title': __("Delete the Request"),
# иконка для графической консоли
'image': None,
# метод в графической консоли
'gui': True,
# консольная команда
'command': 'cl-core-request-del',
# права для запуска метода
'rights': ['request'],
# объект содержащий модули для действия
'logic': {'Request': request.Request},
# описание действия
'action': ClCoreRequestDel,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'delete'},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Delete the request"),
normal=('cl_req_id',),
next_label=_("Delete"))]},
#
# Подтвердить запрос
#
{
# идентификатор метода
'method_name': "core_request_confirm",
# категория метода
# 'category':__('Utilities'),
# заголовок метода
'title': __("Confirm the Request"),
# иконка для графической консоли
'image': None,
# метод в графической консоли
'gui': True,
# консольная команда
'command': 'cl-core-request-confirm',
# права для запуска метода
'rights': ['request'],
# объект содержащий модули для действия
'logic': {'Request': request.Request},
# описание действия
'action': ClCoreRequestConfirm,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'confirm'},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Delete the request"),
normal=('cl_req_id', 'cl_req_group'),
next_label=_("Delete"))]},
#
# установить переменные
#
{
# идентификатор метода
'method_name': "core_variables",
# категория метода
'category': __('Utilities'),
# заголовок метода
'title': __("Setup Variables"),
# иконка для графической консоли
'image': 'calculate-core-variables,applications-versioncontrol,'
'text-x-preview,text-x-makefile',
# метод в графической консоли
'gui': True,
# консольная команда
'command': 'cl-core-variables',
# права для запуска метода
'rights': ['setup_variables'],
# объект содержащий модули для действия
'logic': {'Variables': set_vars.Variables},
# описание действия
'action': ClCoreVariables,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Setup variables"),
normal=('cl_variable_data',),
next_label=_("Save"))]},
#
# отобразить переменные
#
{
# идентификатор метода
'method_name': "core_variables_show",
# категория метода
'category': __('Utilities'),
# заголовок метода
'title': __("View Variables"),
# иконка для графической консоли
'image': None,
# метод в графической консоли
'gui': False,
# консольная команда
'command': 'cl-core-variables-show',
# права для запуска метода
'rights': ['configure'],
# объект содержащий модули для действия
'logic': {'Variables': set_vars.Variables},
# описание действия
'action': ClCoreVariablesShow,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Setup variables"),
normal=(
'cl_variable_filter',
'cl_variable_show'),
next_label=_("Show"))]},
#
# Выполнить настройку пакета (cl-config)
#
{
# идентификатор метода
'method_name': "core_config",
# категория метода
'category': __('Configuration'),
# заголовок метода
'title': __("Config"),
# иконка для графической консоли
'image': None,
# метода нет в графической консоли
'gui': False,
# консольная команда
'command': 'cl-config',
# права для запуска метода
'rights': ['configure'],
# объект содержащий модули для действия
'logic': {'UpdateConfigs': setup_package.UpdateConfigs},
# описание действия
'action': ClConfigAction,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError,
setup_package.SetupPackageError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'config', 'cl_verbose_set': "on"},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Configure a package"),
normal=('cl_core_pkg_name',),
expert=('cl_core_pkg_category',
'cl_core_pkg_version_opt',
'cl_core_pkg_slot_opt',
'cl_templates_locate',
'cl_verbose_set'),
next_label=_("Run"))]},
#
# отобразить переменные
#
{
# идентификатор метода
'method_name': "core_custom",
# категория метода
'category': __('Utilities'),
# заголовок метода
'title': __("Custom Action"),
# иконка для графической консоли
'image': 'calculate-core-custom,gnome-desktop-config,desktop-config',
# метод в графической консоли
'gui': True,
# консольная команда
'command': 'cl-core-custom',
# права для запуска метода
'rights': ['custom_configure'],
# объект содержащий модули для действия
'logic': {'UpdateConfigs': setup_package.UpdateConfigs},
# описание действия
'action': ClCoreCustomAction,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_verbose_set': "on", 'cl_human_edit_set': "on"},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Custom action"),
normal=(
'ac_custom_name', 'cl_human_edit_set',
'cl_verbose_set'),
expert=(
'ur_core_login', 'cl_core_arch_machine',
'cl_templates_locate',
'cl_dispatch_conf'),
next_label=_("Run"))]},
#
# перезапустить сервис calculate core
#
{
# идентификатор метода
'method_name': "core_restart",
# категория метода
'category': __('Utilities'),
# заголовок метода
'title': __("Restart calculate-core"),
# иконка для графической консоли
'image': 'calculate-core-restart,view-refresh',
# метод в графической консоли
'gui': True,
# консольная команда
'command': 'cl-core-restart',
# права для запуска метода
'rights': ['core_restart'],
# объект содержащий модули для действия
'logic': {'UpdateConfigs': setup_package.UpdateConfigs},
# описание действия
'action': ClCoreRestartAction,
# объект переменных
'datavars': "core",
'native_error': (VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'restart'},
# описание груп (список лямбда функций)
'groups': []},
#
# создание резервной копии настроек
#
{
# идентификатор метода
'method_name': "backup",
# категория метода
'category':__('Backup'),
# заголовок метода
'title': __("Backup"),
# иконка для графической консоли
'image': 'calculate-backup',
# метод в графической консоли
'gui': True,
# консольная команда
'command': 'cl-backup',
# права для запуска метода
'rights': ['backup'],
# объект содержащий модули для действия
'logic': {'Backup': Backup},
# описание действия
'action': ClBackupAction,
# объект переменных
'datavars': "core",
'native_error': (BackupError, VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': Actions.Backup},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("System backup"),
normal=('cl_backup_verbose_set',),
next_label=_("Run"))]},
#
# восстановление настроек из резервной копии
#
{
# идентификатор метода
'method_name': "backup_restore",
# категория метода
'category':__('Backup'),
# заголовок метода
'title': __("Restore"),
# иконка для графической консоли
'image': 'calculate-backup-restore',
# метод в графической консоли
'gui': True,
# консольная команда
'command': 'cl-backup-restore',
# права для запуска метода
'rights': ['backup'],
# объект содержащий модули для действия
'logic': {'Backup': Backup},
# описание действия
'action': ClBackupRestoreAction,
# объект переменных
'datavars': "core",
'native_error': (BackupError, VariableError, DataVarsError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': Actions.BackupRestore,
'core.cl_backup_action': Actions.Restore},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("System restore"),
normal=('cl_backup_verbose_set',),
brief=('cl_backup_file', 'cl_backup_time'),
next_label=_("Run"))],
'brief': {'next': __("Run"),
'name': __("System restore")}},
]

@ -1051,6 +1051,7 @@ class SimpleDataVars(object):
return getList()(value)
if "table" in varType:
return map(getList(':'), value.split(','))
value = str(value, "UTF-8")
return fixEmpty(value).strip("'").strip('"')
def ZipVars(self, *argvVarNames, **kw):

@ -15,7 +15,7 @@
# limitations under the License.
import sys
import urllib2
import urllib.request as urllib2
import re
import time
import os

@ -0,0 +1,853 @@
# -*- coding: utf-8 -*-
# Copyright 2015-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 hashlib
import os
from os import path
import re
import sys
from calculate.lib.utils.colortext.palette import TextState
from calculate.lib.utils.tools import ignore
from calculate.lib.utils.git import Git, GitError
from calculate.lib.utils.portage import (EmergePackage, PackageList,
EmergeUpdateInfo,
EmergeRemoveInfo)
Colors = TextState.Colors
import pexpect
from calculate.lib.utils.files import (getProgPath, readLinesFile,
listDirectory,
writeFile, readFile)
from calculate.lib.utils.colortext.output import XmlOutput
from calculate.lib.utils.colortext.converter import (ConsoleCodes256Converter,
XmlConverter)
from calculate.lib.cl_log import log
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate, _
setLocalTranslate('cl_update3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
linux_term_env = {'TERM': 'linux'}
class EmergeError(Exception):
"""
Ошибка при сборке пакетов
"""
class EmergeNeedRootError(EmergeError):
pass
class CommandExecutor(object):
"""
Запуск программы для объекта Emerge
"""
logfile = '/var/log/calculate/lastcommand.log'
def __init__(self, cmd, params, env=None, cwd=None, logfile=None):
self.cwd = cwd
self.env = env or dict(os.environ)
self.env.update({'EINFO_QUIET': 'NO'})
self.env.update(linux_term_env)
self.cmd = cmd
self.params = params
self.child = None
if logfile:
self.logfile = logfile
def get_command(self):
return [self.cmd] + list(self.params)
def execute(self):
if self.child is None:
command_data = self.get_command()
self.child = pexpect.spawn(command_data[0], command_data[1:],
logfile=open(self.logfile, 'w'),
env=self.env, cwd=self.cwd, timeout=None)
return self.child
def close(self):
if self.child is not None:
self.child.close()
self.child = None
def success(self):
if self.child:
self.child.read()
if self.child.isalive():
self.child.wait()
return self.child.exitstatus == 0
return False
def failed(self):
return not self.success()
def send(self, s):
if self.child:
self.child.send(s)
class EmergeCommand(CommandExecutor):
"""
Запуск emerge для последующего анализирования
"""
# параметры по умолчанию
default_params = ["-av", "--color=y", "--nospinner"]
emerge_cmd = getProgPath("/usr/bin/emerge")
def __init__(self, packages, extra_params=None, env=None, cwd=None,
logfile=None, emerge_default_opts=None, env_update=None,
use=""):
extra_params = extra_params or []
if env is None:
if emerge_default_opts is None:
env = {'CLEAN_DELAY': '0'}
else:
env = {
'CLEAN_DELAY': '0',
'EMERGE_DEFAULT_OPTS': re.sub(
r'(?:^|\s)(--columns)(?=\s|$)', '',
emerge_default_opts)
}
if use:
env["USE"] = use
env.update(os.environ)
if env_update is not None:
env.update(env_update)
params = self.default_params + extra_params + packages
super(EmergeCommand, self).__init__(self.emerge_cmd, params=params,
env=env, cwd=cwd, logfile=logfile)
def Chroot(chroot_path, obj):
"""
Преобразовать команду (экземпляр объекта) в chroot
:param obj: экземпляр команды
:param chroot_path: путь для chroot
:return:
"""
old_get_command = obj.get_command
def get_command():
chrootCmd = '/usr/bin/chroot'
bashCmd = '/bin/bash'
bash_command = (
"env-update &>/dev/null;"
"source /etc/profile &>/dev/null;"
"{cmd}".format(cmd=" ".join(old_get_command())))
return [chrootCmd, chroot_path, bashCmd, "-c", bash_command]
obj.get_command = get_command
return obj
def Linux32(obj):
"""
Преобразовать команду (экземпляр объекта) в вызов под linux32
:param obj: экземпляр команды
:return:
"""
old_get_command = obj.get_command
def get_command():
return ["/usr/bin/linux32"] + old_get_command()
obj.get_command = get_command
return obj
class InfoBlockInterface(object):
"""
Интерфейс для информационного блока
"""
action = None
token = None
result = None
text_converter = ConsoleCodes256Converter(XmlOutput())
def get_block(self, child):
pass
def add_element(self, element):
"""
:type element: InfoBlockInterface
"""
pass
class EmergeInformationBlock(InfoBlockInterface):
_color_block = "(?:\033\[[^m]+?m)?"
_new_line = "(?:\r*\n)"
end_token = ["\n"]
re_block = None
re_match_type = type(re.match("", ""))
re_type = type(re.compile(""))
def __init__(self, parent):
"""
:type parent: InfoBlockInterface
"""
self.result = None
self.text_converter = parent.text_converter
self.parent = parent
self.parent.add_element(self)
self.children = []
def add_element(self, element):
"""
:type element: InfoBlockInterface
"""
self.children.append(element)
def __str__(self):
if type(self.result) == self.re_match_type:
return self.result.group()
else:
return self.result or ""
def __nonzero__(self):
return bool(self.result)
def __len__(self):
if self.result is None:
return 0
else:
return len(self.result)
def __contains__(self, item):
if self.result is None:
return False
else:
return item in str(self)
def _get_text(self, result):
"""
Получить результат из регулярки и преобразовать его через self.converter
"""
if result:
return self.text_converter.transform(result.rstrip())
return ""
def get_block(self, child):
try:
token = child.match
if type(self.end_token) == self.re_type:
child.expect(self.end_token)
match = child.match.group()
else:
child.expect_exact(self.end_token)
match = child.match
self.get_data(self.re_block.search(
token + child.before + match))
except pexpect.EOF:
child.buffer = "".join(
[x for x in (child.before, child.after, child.buffer)
if type(x) == str])
def get_data(self, match):
self.result = self._get_text(match.group(1))
class InstallPackagesBlock(EmergeInformationBlock):
"""
Блок emerge содержащий список пакетов для установки
"""
list = PackageList([])
remove_list = PackageList([])
block_packages = False
_new_line = EmergeInformationBlock._new_line
_color_block = EmergeInformationBlock._color_block
token = "\n["
end_token = ["\r\n\r", "\n\n"]
re_block = re.compile(r"((?:^\[.*?{nl})+)".format(nl=_new_line),
re.MULTILINE)
re_blocks = re.compile(r"\[{c}blocks{c} {c}b".format(c=_color_block))
def get_data(self, match):
super(InstallPackagesBlock, self).get_data(match)
list_block = XmlConverter().transform(self.result).split('\n')
self.list = PackageList(map(EmergeUpdateInfo, list_block))
self.remove_list = PackageList(map(EmergeRemoveInfo, list_block))
self.block_packages = any(self.re_blocks.search(x) for x in list_block)
class UninstallPackagesBlock(EmergeInformationBlock):
"""
Блок emerge содержащий список удаляемых пакетов
"""
list = PackageList([])
verbose_result = ""
_new_line = EmergeInformationBlock._new_line
_color_block = EmergeInformationBlock._color_block
token = ["Calculating removal order",
"These are the packages that would be unmerged"]
end_token = re.compile("All selected packages:.*\n")
re_block = re.compile(
r"(?:{token}).*?{nl}(.*){nl}All selected packages: (.*?){nl}".
format(token="|".join(token),
nl=_new_line, c=_color_block), re.DOTALL)
def get_data(self, match):
re_clean = re.compile(
"^.*?({token}).*?{c}{nl}".format(token="|".join(self.token),
nl=self._new_line,
c=self._color_block), re.DOTALL)
verbose_result = re_clean.sub("", match.group(1))
self.verbose_result = self._get_text(verbose_result)
self.result = self._get_text(match.group(2))
list_block = XmlConverter().transform(self.result).split()
self.list = PackageList(map(EmergePackage, list_block))
class GroupEmergeInformationBlock(EmergeInformationBlock):
"""
Группа блоков
"""
def get_block(self, child):
self.children_get_block(child)
self.result = True
def children_get_block(self, child):
for block in self.children:
block.get_block(child)
def children_action(self, child):
for block in (x for x in self.children if x.result and x.action):
if block.action(child) is False:
return False
def action(self, child):
self.children_action(child)
return False
class FinishEmergeGroup(GroupEmergeInformationBlock):
"""
Блок завершения команды
"""
token = pexpect.EOF
# регуляреное выражение, определяющее содержит ли блок
# сообщения об ошибках
re_failed = re.compile(
r"Fetch instructions for \S+:|"
r"The following.*are necessary to proceed|"
r"!!! Multiple package .* slot have been pulled|"
r"no ebuilds to satisfy|"
r"Dependencies could not be completely resolved due to",
re.MULTILINE)
def get_block(self, child):
if child.isalive():
child.wait()
if child.exitstatus != 0 or self.re_failed.search(child.before):
self.children_get_block(child)
else:
self.result = True
class PrepareErrorBlock(EmergeInformationBlock):
"""
Блок информации с ошибками при получении списка устанавливаемых пакетов
"""
token = None
re_drop = re.compile("news items need reading|"
"Use eselect news|"
"Calculating dependencies|"
"to read news items|"
"Local copy of remote index is up-to-date|"
"These are the packages that would be merged|"
"Process finished with exit code")
re_multi_empty_line = re.compile("(?:<br/>){3,}", re.DOTALL)
re_strip_br = re.compile("^(?:<br/>)+|(?:<br/>)+$", re.DOTALL)
def remove_needless_data(self, data):
return "\n".join([x for x in data.split('\n')
if not self.re_drop.search(x)])
def strip_br(self, data):
return self.re_strip_br.sub(
"",
self.re_multi_empty_line.sub("<br/><br/>", data))
def get_block(self, child):
self.result = self.strip_br(
self._get_text(self.remove_needless_data(child.before)))
def action(self, child):
raise EmergeError(_("Emerge failed"))
class DownloadSizeBlock(EmergeInformationBlock):
"""
Размер скачиваемых обновлений
"""
token = "Size of downloads:"
re_block = re.compile(r"Size of downloads:\s(\S+\s\S+)")
def __str__(self):
if self.result:
return self.result
else:
return "0 kB"
class SkippedPackagesBlock(EmergeInformationBlock):
"""
Размер скачиваемых обновлений
"""
token = "The following update has been skipped"
end_token = ["For more information, see the MASKED"]
re_block = re.compile(
r"(The following update has.*?)(?=For more information)", re.S)
def __str__(self):
if self.result:
return self.result
else:
return ""
class QuestionGroup(GroupEmergeInformationBlock):
"""
Группа блоков разбора вопросов от emerge
"""
token = "Would you like"
end_token = ["]", "\n"]
_color_block = EmergeInformationBlock._color_block
re_block = re.compile(
"(Would you.*)\[{c}Yes{c}/{c}No{c}".format(c=_color_block))
def get_block(self, child):
try:
before = child.before
token = child.match
if type(self.end_token) == self.re_type:
child.expect(self.end_token)
match = child.match.group()
else:
child.expect_exact(self.end_token)
match = child.match
data = token + child.before + match
child.before = before
for block in self.children:
child.match = re.search(block.token, data)
block.get_block(child)
if block.result:
break
except pexpect.EOF:
child.buffer = "".join(
[x for x in (child.before, child.after, child.buffer)
if type(x) == str])
class QuestionChangeConfigBlock(GroupEmergeInformationBlock):
"""
Вопрос об изменении конфигурационных файлов
"""
token = "Would you like to add these changes to your config files"
def get_block(self, child):
if child.match:
self.result = self.token
self.children_get_block(child)
def action(self, child):
if self.result:
child.send("no\n")
if child.isalive():
child.wait()
self.children_action(child)
class QuestionBlock(EmergeInformationBlock):
"""
Блок вопроса
"""
default_answer = "yes"
token = "Would you"
def get_block(self, child):
if child.match:
self.result = self.token
def action(self, child):
if self.result:
child.send("%s\n" % self.default_answer)
return False
class NeedRootBlock(EmergeInformationBlock):
"""
Пользователь не явеляется root
"""
token = "This action requires superuser access"
def get_data(self, child):
self.result = True
def action(self, child):
raise EmergeNeedRootError(_("This action requires superuser access"))
class NotifierInformationBlock(EmergeInformationBlock):
"""
Информационный блок поддерживающий observing
"""
def __init__(self, parent):
super(NotifierInformationBlock, self).__init__(parent)
self.observers = []
def get_data(self, match):
self.result = match
def add_observer(self, f):
self.observers.append(f)
def clear_observers(self):
self.observers = []
def remove_observer(self, f):
if f in self.observers:
self.observers.remove(f)
def notify(self, observer, groups):
observer(groups)
def action(self, child):
if self.result and self.observers:
groups = self.result.groups()
for observer in self.observers:
self.notify(observer, groups)
class EmergingPackage(NotifierInformationBlock):
"""
Запуск устанавливаемого пакета
ObserverFunc: (package, num=number, max_num=number, binary=binary)
"""
_color_block = EmergeInformationBlock._color_block
token = ">>> Emerging "
re_block = re.compile(
"Emerging (binary )?\({c}(\d+){c} "
"of {c}(\d+){c}\) {c}([^\s\033]+){c}".format(c=_color_block))
def notify(self, observer, groups):
observer(EmergePackage(groups[3]), num=groups[1], max_num=groups[2],
binary=bool(groups[0]))
class UnemergingPackage(NotifierInformationBlock):
"""
Запуск устанавливаемого пакета
ObserverFunc: (package, num=number, max_num=number)
"""
_color_block = EmergeInformationBlock._color_block
token = ">>> Unmerging"
re_block = re.compile(
r"Unmerging (?:\({c}(\d+){c} "
r"of {c}(\d+){c}\) )?(\S+)\.\.\.".format(c=_color_block))
def notify(self, observer, groups):
observer(EmergePackage(groups[2]), num=groups[0], max_num=groups[1])
class FetchingTarball(NotifierInformationBlock):
"""
Происходит скачивание архивов
"""
token = "Saving to:"
re_block = re.compile("Saving to:\s*['](\S+)?[']")
def notify(self, observer, groups):
observer(groups[0])
class InstallingPackage(NotifierInformationBlock):
"""
Запуск устанавливаемого пакета
ObserverFunc: (package, binary=binary)
"""
_color_block = EmergeInformationBlock._color_block
binary = None
token = ">>> Installing "
re_block = re.compile(
"Installing \({c}(\d+){c} "
"of {c}(\d+){c}\) {c}([^\s\033]+){c}".format(c=_color_block))
def notify(self, observer, groups):
strpkg = str(EmergePackage(groups[2]))
binary = bool(self.binary and strpkg in self.binary)
observer(EmergePackage(groups[2]), binary=binary)
def mark_binary(self, package):
if self.binary is None:
self.binary = []
self.binary.append(str(package))
class EmergeingErrorBlock(EmergeInformationBlock):
"""
Блок содержит информацию об ошибке во время сборки пакета
"""
token = ["* ERROR: ", " * \033[39;49;00mERROR: "]
end_token = "Working directory:"
re_block = re.compile("ERROR: (\S*) failed \([^)]+\).*?"
"The complete build log is located at '([^']+)",
re.DOTALL)
package = ""
def get_data(self, match):
self.result = self._get_text(match.group(2).rstrip())
self.package = match.group(1)
@property
def log(self):
return self.text_converter.transform(readFile(self.result))
def action(self, child):
raise EmergeError(_("Failed to emerge %s") % self.package)
class RevdepPercentBlock(NotifierInformationBlock):
"""
Блок определния статуса revdep-rebuild
"""
token = "Collecting system binaries"
end_token = [re.compile("Assigning files to packages|"
"All prepared. Starting rebuild")]
re_block = re.compile("\[\s(\d+)%\s\]")
action = None
def notify(self, observer, groups):
percent = int(groups[0])
observer(percent)
def get_block(self, child):
expect_result = [self.re_block]+self.end_token
try:
while True:
index = child.expect(expect_result)
if index == 0:
for observer in self.observers:
self.notify(observer, child.match.groups())
else:
self.result = child.match
break
except pexpect.EOF:
self.result = ""
class EmergeParser(InfoBlockInterface):
"""
Парсер вывода emerge
"""
def __init__(self, command, run=False):
self.command = command
self.elements = {}
self.install_packages = InstallPackagesBlock(self)
self.uninstall_packages = UninstallPackagesBlock(self)
self.question_group = QuestionGroup(self)
self.change_config_question = QuestionChangeConfigBlock(
self.question_group)
self.question = QuestionBlock(self.question_group)
self.finish_block = FinishEmergeGroup(self)
self.need_root = NeedRootBlock(self)
self.prepare_error = PrepareErrorBlock(self.finish_block)
self.change_config_question.add_element(self.prepare_error)
self.download_size = DownloadSizeBlock(self)
self.skipped_packages = SkippedPackagesBlock(self)
self.emerging_error = EmergeingErrorBlock(self)
self.installing = InstallingPackage(self)
self.uninstalling = UnemergingPackage(self)
self.emerging = EmergingPackage(self)
self.fetching = FetchingTarball(self)
self.emerging.add_observer(self.mark_binary)
self.emerging.add_observer(self.skip_fetching)
if run:
self.run()
def mark_binary(self, package, binary=False, **kw):
if binary:
self.installing.mark_binary(package)
def skip_fetching(self, *argv, **kw):
self.fetching.action = lambda child: None
def add_element(self, element):
"""
:type element: InfoBlockInterface
"""
if element.token:
if type(element.token) == list:
for token in element.token:
self.elements[token] = element
else:
self.elements[element.token] = element
def run(self):
"""
Запустить команду
"""
child = self.command.execute()
while True:
index = child.expect_exact(self.elements.keys())
element = self.elements.values()[index]
element.get_block(child)
if element.action:
if element.action(child) is False:
break
def close(self):
self.command.close()
def __enter__(self):
return self
def __exit__(self, *exc_info):
self.close()
class MtimeCheckvalue(object):
def __init__(self, *fname):
self.fname = fname
def value_func(self, fn):
return str(int(os.stat(fn).st_mtime))
def get_check_values(self, file_list):
for fn in file_list:
if path.exists(fn) and not path.isdir(fn):
yield fn, self.value_func(fn)
else:
for k, v in self.get_check_values(
listDirectory(fn, fullPath=True)):
yield k, v
def checkvalues(self):
return self.get_check_values(self.fname)
class Md5Checkvalue(MtimeCheckvalue):
def value_func(self, fn):
return hashlib.md5(readFile(fn)).hexdigest()
class GitCheckvalue(object):
def __init__(self, git, rpath):
self.rpath = rpath
self.git = git
def checkvalues(self):
with ignore(GitError):
if self.git.is_git(self.rpath):
yield self.rpath, self.git.getCurrentCommit(self.rpath)
class EmergeCache(object):
"""
Кэш пакетов
"""
cache_file = '/var/lib/calculate/calculate-update/world.cache'
# список файлов проверяемый по mtime на изменения
check_list = [MtimeCheckvalue('/etc/make.conf',
'/etc/portage',
'/etc/make.profile'),
Md5Checkvalue('/var/lib/portage/world',
'/var/lib/portage/world_sets')]
logger = log("emerge-cache",
filename="/var/log/calculate/emerge-cache.log",
formatter="%(asctime)s - %(levelname)s - %(message)s")
def __init__(self):
self.files_control_values = {}
self.pkg_list = PackageList([])
def set_cache(self, package_list):
"""
Установить в кэш список пакетов
"""
with writeFile(self.cache_file) as f:
for fn, val in self.get_control_values().items():
f.write("{fn}={val}\n".format(fn=fn, val=val))
f.write('\n')
for pkg in package_list:
f.write("%s\n" % str(pkg))
self.logger.info("Setting cache (%d packages)" % len(package_list))
def drop_cache(self, reason=None):
if path.exists(self.cache_file):
with ignore(OSError):
os.unlink(self.cache_file)
self.logger.info("Droping cache. Reason: %s" % reason)
else:
self.logger.info("Droping empty cache. Reason: %s" % reason)
def get_cached_package_list(self):
self.read_cache()
if not path.exists(self.cache_file):
self.logger.info("Requesting empty cache")
if self.check_actuality():
return self.pkg_list
return None
def check_actuality(self):
"""
Кэш считается актуальным если ни один из файлов не менялся
"""
if self.get_control_values() == self.files_control_values:
self.logger.info(
"Getting actuality cache (%d packages)" % len(self.pkg_list))
return True
else:
reason = "Unknown"
for k, v in self.get_control_values().items():
if k in self.files_control_values:
if v != self.files_control_values[k]:
reason = "%s was modified" % k
else:
reason = "Checksum of file %s is not exist" % k
self.logger.info("Failed to get cache. Reason: %s" % reason)
return False
def read_cache(self):
self.files_control_values = {}
cache_file_lines = readLinesFile(self.cache_file)
for line in cache_file_lines:
if "=" not in line:
break
k, v = line.split('=')
self.files_control_values[k] = v.strip()
self.pkg_list = PackageList(cache_file_lines)
def get_control_values(self):
def generate():
for obj in self.check_list:
for check_value in obj.checkvalues():
yield check_value
return dict(generate())

@ -0,0 +1,268 @@
# -*- coding: utf-8 -*-
# Copyright 2014-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
import shutil
from calculate.lib.utils.files import (listDirectory, readFile, readLinesFile,
makeDirectory, removeDir)
from calculate.lib.utils.git import Git
from .update import UpdateError
from calculate.lib.cl_lang import setLocalTranslate, _
setLocalTranslate('cl_update3', sys.modules[__name__])
DEFAULT_BRANCH = Git.Reference.Master
class RepositoryStorageInterface(object):
def __iter__(self):
raise StopIteration
def get_profiles(self, url, branch=DEFAULT_BRANCH):
return []
def get_repository(self, url, branch=DEFAULT_BRANCH):
return None
class RepositoryStorage(RepositoryStorageInterface):
directory = '/tmp'
def __init__(self, git, directory):
self.directory = directory
self.git = git
makeDirectory(directory)
def __iter__(self):
for dn in listDirectory(self.directory, onlyDir=True, fullPath=True):
if self.git.is_git(dn):
yield ProfileRepository(self.git, path.basename(dn), self)
def get_profiles(self, url, branch=DEFAULT_BRANCH):
return []
def get_repository(self, url, branch=DEFAULT_BRANCH):
return None
class ProfileStorage(RepositoryStorage):
def get_profiles(self, url, branch=DEFAULT_BRANCH):
rep = self.get_repository(url, branch)
if rep:
return rep.get_profiles()
return None
def get_repository(self, url, branch=DEFAULT_BRANCH):
return None
class LocalStorage(ProfileStorage):
"""
Локальное хранилище репозиториев, при запросе по урлу смотрит, доступные
репозитории если находит подходящий - возвращает его профили
"""
def get_repository(self, url, branch=DEFAULT_BRANCH):
for rep in self:
if rep.is_like(url, branch):
return rep
class CacheStorage(ProfileStorage):
"""
Хранилище репозиториев, при запросе по урлу смотрит, доступные
репозитории если находит подходящий - возвращает его профили,
если не находит - скачивает и возвращает профили
"""
def get_repository(self, url, branch=DEFAULT_BRANCH):
for rep in self:
if rep.is_like(url, branch):
return rep
else:
return ProfileRepository.clone(self.git, url, self,
branch or DEFAULT_BRANCH)
class RepositoryStorageSet(RepositoryStorageInterface):
"""
Набор хранилищ репозиториев
"""
def __init__(self, *storages):
self.storages = storages
def get_profiles(self, url, branch=DEFAULT_BRANCH):
"""
Получить профили из указанного репозитория
"""
for storage in self.storages:
profiles = storage.get_profiles(url, branch)
if profiles is not None:
return profiles
return None
def __iter__(self):
for storage in self.storages:
for rep in storage:
yield rep
def get_repository(self, url, branch=DEFAULT_BRANCH):
"""
Получить репозиторий по параметрам
"""
for rep in self:
if rep.is_like(url, branch):
return rep
for storage in self.storages:
rep = storage.get_repository(url, branch)
if rep:
return rep
return None
def is_local(self, url, branch=DEFAULT_BRANCH):
"""
Проверить является ли репозиторий с указанными параметрами
локальным
"""
rep = self.get_repository(url, branch)
if rep and isinstance(rep.storage, LocalStorage):
return True
return False
def __repr__(self):
return "Repository set"
class Profile(object):
"""
Профиль репозитория
"""
available_arch = ["amd64", "x86"]
def __init__(self, repository, profile, arch):
self.repository = repository
self.profile = profile
self.arch = arch
@property
def path(self):
return path.join(self.repository.directory,"profiles", self.profile)
@classmethod
def from_string(cls, repository, s):
parts = filter(None, s.split())
if len(parts) == 3 and parts[0] in cls.available_arch:
return Profile(repository, parts[1], parts[0])
return None
def __repr__(self):
return "<Profile (%s) %s:%s from %s>" % (self.arch,
self.repository.repo_name,
self.profile,
self.repository.directory)
class ProfileRepository(object):
"""
Репозиторий либо скачивается, либо берется из кэша
"""
def __init__(self, git, name, storage):
self._storage = storage
self.name = name
self.git = git
@property
def storage(self):
return self._storage
@storage.setter
def storage(self, storage):
if storage.directory != self._storage.directory:
newpath = path.join(storage.directory, self.name)
if self.directory == newpath:
return
try:
if path.exists(newpath):
removeDir(newpath)
shutil.move(self.directory, newpath)
self._storage = storage
except OSError as e:
raise UpdateError(_("Failed to move the profile: %s") %
str(e))
@classmethod
def clone(cls, git, url, storage, branch=DEFAULT_BRANCH):
name = path.basename(url)
if name.endswith(".git"):
name = name[:-4]
rpath = path.join(storage.directory, name)
if path.exists(rpath):
removeDir(rpath)
if git.is_private_url(url):
try:
makeDirectory(rpath)
os.chmod(rpath, 0o700)
except OSError:
pass
git.cloneRepository(url, rpath, branch)
pr = cls(git, name, storage)
repo_name = pr.repo_name
if name != repo_name:
rpath_new = path.join(storage.directory, repo_name)
if path.exists(rpath_new):
removeDir(rpath_new)
shutil.move(rpath, rpath_new)
pr = cls(git, repo_name, storage)
return pr
@property
def repo_name(self):
return readFile(path.join(self.directory,
"profiles/repo_name")).strip()
def is_like(self, url, branch=DEFAULT_BRANCH):
if self.url == url and (branch is None or self.branch == branch):
return True
return False
@property
def directory(self):
"""
Получить локальную директорию на данные репозитория
"""
return path.join(self.storage.directory, self.name)
@property
def url(self):
return self.git.get_url(self.directory, "origin")
@property
def branch(self):
return self.git.getBranch(self.directory)
def sync(self):
"""
Синхронизировать репозиторий
"""
if not self.git.pullRepository(self.directory, quiet_error=True):
self.git.resetRepository(self.directory, to_origin=True)
self.git.pullRepository(self.directory, quiet_error=True)
def get_profiles(self):
"""
Получить список профилей репозитория
"""
profiles_desc = path.join(self.directory, "profiles/profiles.desc")
return filter(None, (Profile.from_string(self, line)
for line in readLinesFile(profiles_desc)))
def __repr__(self):
return "<ProfileRepository %s url=%s>" % (self.directory, self.url)

File diff suppressed because it is too large Load Diff

@ -16,50 +16,13 @@
import os
from os import path
# from itertools import ifilter
from calculate.core.datavars import DataVarsCore
# from calculate.core.server.gen_pid import search_worked_process
from calculate.core.server.gen_pid import search_worked_process
from calculate.lib.cl_template import SystemIni
from calculate.lib.utils.content import getCfgFiles
from calculate.lib.utils.files import getRunCommands, readFile, writeFile
# from core:
#######################################
class ProcessStatus(object):
SuccessFinished = 0
Worked = 1
FailedFinished = 2
NotFound = 3
Paused = 4
def search_worked_process(method_name, clVars,
statuses=(ProcessStatus.Worked,)):
"""
Найти все работающие процессы
Возвращает список процессов со статусом Worked и существующем системным
процессом
"""
def generator():
pids = clVars.Get('core.cl_core_pids_path')
for pidfile in listDirectory(pids, fullPath=True):
try:
status = pickle.load(open(pidfile))
if ((method_name is None or status['name'] == method_name) and
status['status'] in statuses):
pid_path = path.join("/proc", str(status['os_pid']))
if path.exists(pid_path):
cmdline = readFile(path.join(pid_path, "cmdline"))
if cmdline and any(x in cmdline
for x in get_symlink_commands()):
yield status['os_pid']
except (socket.error, ValueError, KeyError, EOFError, OSError):
pass
return list(generator())
###################################
class UpdateInfo(object):
"""
Информационный объект о процессе обновления

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Copyright 2015-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.
class EmergeMark:
Schedule = "schedule"
Premerge = "check updates"
PythonUpdater = "update python modules"
PerlCleaner = "update perl modules"
KernelModules = "update kernel modules"
Depclean = "depclean"
XorgModules = "update xorg modules"
PreservedLibs = "update preserved libs"
RevdepRebuild = "revdep rebuild"
Prelink = "prelink"
Automagic = "check for auto depends"

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
# Copyright 2010-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
from calculate.core.server.func import Action
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.utils.files import FilesError
from calculate.update.update import UpdateError
from calculate.lib.utils.git import GitError
_ = lambda x: x
setLocalTranslate('cl_update3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClSetupUpdateAction(Action):
"""
Действие для настройки параметров автопроверки обновлений
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError, UpdateError, GitError)
successMessage = __("Updates autocheck configured!")
failedMessage = __("Failed to configure the updates autocheck procedure!")
interruptMessage = __("Configuration manually interrupted")
# список задач для действия
tasks = [
{'name': 'set_variables',
'method': 'Update.setAutocheckParams(cl_update_autocheck_set,'
'cl_update_autocheck_interval,'
'cl_update_other_set,'
'cl_update_cleanpkg_set)'}
]

@ -0,0 +1,457 @@
# -*- coding: utf-8 -*-
# Copyright 2010-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
from calculate.core.server.func import Action, Tasks, AllTasks
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.cl_template import TemplatesError
from calculate.lib.utils.binhosts import BinhostError
from calculate.lib.utils.files import FilesError, readFile
from calculate.update.update import UpdateError
from calculate.update.emerge_parser import EmergeError
from calculate.lib.utils.git import GitError
from calculate.lib.utils.portage import (EmergeLog, isPkgInstalled,
EmergeLogNamedTask, PackageList)
from calculate.update.update_tasks import EmergeMark
_ = lambda x: x
setLocalTranslate('cl_update3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
def get_synchronization_tasks(object_name):
Object = lambda s: "%s.%s"%(object_name, s)
return [
{'name': 'reps_synchronization',
'group': __("Repositories synchronization"),
'tasks': [
# создать объект проверки PGP
{'name': 'prepare_gpg',
'method': Object("prepare_gpg()"),
},
# создать объект хранилище серверов обновлений
{'name': 'create_binhost_data',
'method': Object('create_binhost_data()')
},
# проверить валиден ли текущий хост
{'name': 'check_current_binhost',
'message': __("Checking current binhost"),
'essential': False,
'method': Object('check_current_binhost(update.cl_update_binhost)'),
'condition': lambda GetBool, Get: (
not GetBool('update.cl_update_binhost_recheck_set') and
Get('update.cl_update_sync_rep') and
Get('update.cl_update_binhost'))
},
{'name': 'not_use_search:failed_base_binhost',
'error': __("Failed to use base binhost"),
'method': Object("delete_binhost()"),
'depend': AllTasks.failed_all("check_current_binhost")
},
{'name': 'group_find_binhost',
'group': '',
'while': (~AllTasks.has_any("detect_best_binhost") &
((AllTasks.failed_all("update_packages_cache")
& ~AllTasks.has_any("not_use_search")) |
~AllTasks.has_any("sync_reps"))) & Tasks.success(),
'condition': lambda GetBool, Get: (GetBool('update.cl_update_usetag_set') and
Get('update.cl_update_sync_rep')),
'tasks': [
# найти лучший сервер обновлений
{'name': 'detect_best_binhost',
'method': Object('detect_best_binhost()'),
'essential': False,
'depend': (Tasks.success() & ~AllTasks.has_any("not_use_search") &
(~AllTasks.success_one_of("check_current_binhost") |
AllTasks.success_all("sync_reps"))),
},
# запасная синхронизация, в ходе которой ветки обновляются до
# master
{'name': 'sync_reps_fallback',
'foreach': 'update.cl_update_sync_rep',
'message':
__("Fallback syncing the {eachvar:capitalize} repository"),
'method': Object('syncRepositories(eachvar,True)'),
'depend': Tasks.success() & AllTasks.failed_one_of("detect_best_binhost"),
},
# обновление переменных информации из binhost
{'name': 'sync_reps_fallback:update_binhost_list',
'method': Object('update_binhost_list()'),
'depend': Tasks.success() & AllTasks.failed_one_of("detect_best_binhost"),
},
# найти лучший сервер обновлений
{'name': 'sync_reps_fallback:detect_best_binhost',
'method': Object('detect_best_binhost()'),
'depend': Tasks.success() & AllTasks.failed_one_of("detect_best_binhost"),
},
{'name': 'sync_reps',
'foreach': 'update.cl_update_sync_rep',
'message': __("Checking {eachvar:capitalize} updates"),
'method': Object('syncRepositories(eachvar)'),
'condition': lambda Get: Get('update.cl_update_sync_rep'),
'depend': Tasks.success() & ~AllTasks.success_all("update_packages_cache")
},
{'name': 'sync_reps:update_local_info_binhost',
'method': Object('update_local_info_binhost()'),
},
{'name': 'sync_reps:update_binhost_list',
'essential': False,
'method': Object('update_binhost_list()'),
'condition': lambda GetBool: GetBool('update.cl_update_outdate_set')
},
{'name': 'sync_reps:update_packages_cache',
'message': __("Update packages index"),
'method': Object('download_packages(update.cl_update_portage_binhost,'
'update.cl_update_package_cache,update.cl_update_package_cache_sign,'
'update.cl_update_gpg)'),
'essential': False,
'condition': lambda Get, GetBool: (
Get('update.cl_update_package_cache') and (
Get('update.cl_update_outdate_set') == 'on' or
Get('update.cl_update_package_cache_set') == 'on'))
},
],
},
{'name': 'no_server',
'error': __("Failed to find the binary updates server"),
'method': Object("delete_binhost()"),
# method: который должен удалить текущую информацию о сервере обновлений
'depend': (~Tasks.has_any("failed_base_binhost") & (Tasks.failed() |
Tasks.success() & AllTasks.failed_one_of("update_packages_cache"))),
'condition': lambda GetBool, Get: (GetBool('update.cl_update_usetag_set') and
Get('update.cl_update_sync_rep')),
},
{'name': 'sync_reps',
'foreach': 'update.cl_update_sync_rep',
'message': __("Checking {eachvar:capitalize} updates"),
'method': Object('syncRepositories(eachvar)'),
'condition': lambda Get, GetBool: (Get('update.cl_update_sync_rep') and
not GetBool('update.cl_update_usetag_set')),
},
{'name': 'update_rep_list',
'message': __("Repository cache update"),
'method': Object('update_rep_list()'),
'condition': lambda Get: (isPkgInstalled(
"app-eselect/eselect-repository", prefix=Get('cl_chroot_path')) and
Get('cl_chroot_path') != "/"),
'essential': False,
},
{'name': 'sync_other_reps',
'foreach': 'update.cl_update_other_rep_name',
'message': __("Syncing the {eachvar:capitalize} repository"),
'method': Object('syncOtherRepository(eachvar)'),
'condition': lambda GetBool: GetBool('update.cl_update_other_set')
},
{'name': 'trim_reps',
'foreach': 'update.cl_update_sync_rep',
'message': __("Cleaning the history of the "
"{eachvar:capitalize} repository"),
'method': Object('trimRepositories(eachvar)'),
'condition': lambda Get: (Get('update.cl_update_sync_rep') and
Get('update.cl_update_onedepth_set') == 'on')
},
{'name': 'sync_reps:regen_cache',
'foreach': 'update.cl_update_sync_overlay_rep',
'essential': False,
'method': Object('regenCache(eachvar)'),
'condition': (
lambda Get: (Get('update.cl_update_outdate_set') == 'on' and
Get('update.cl_update_egencache_force') != 'skip' or
Get('update.cl_update_egencache_force') == 'force'))
},
{'name': 'sync_other_reps:regen_other_cache',
'foreach': 'update.cl_update_other_rep_name',
'method': Object('regenCache(eachvar)'),
'essential': False,
},
{'name': 'eix_update',
'message': __("Updating the eix cache for "
"{update.cl_update_eix_repositories}"),
'method': Object('eixUpdate(cl_repository_name)'),
'condition': (
lambda Get: (Get('update.cl_update_outdate_set') == 'on' and
Get('update.cl_update_eixupdate_force') != 'skip' or
Get('update.cl_update_eixupdate_force') == 'force'))
},
{'name': 'update_setup_cache',
'message': __("Updating the cache of configurable packages"),
'method': Object('updateSetupCache()'),
'essential': False,
'condition': lambda Get: Get('update.cl_update_outdate_set') == 'on'
},
{'name': 'sync_reps:cleanpkg',
'message': __("Removing obsolete distfiles and binary packages"),
'method': Object('cleanpkg()'),
'condition': (
lambda Get: Get('update.cl_update_cleanpkg_set') == 'on' and
Get('update.cl_update_outdate_set') == 'on'),
'essential': False
},
# сообщение удачного завершения при обновлении репозиториев
{'name': 'success_syncrep',
'message': __("Synchronization finished"),
'depend': (Tasks.success() & Tasks.has_any("sync_reps",
"sync_other_reps",
"emerge_metadata",
"eix_update")),
}
]
},
]
class UpdateConditions(object):
@staticmethod
def was_installed(pkg, task_name):
def func():
task = EmergeLog(EmergeLogNamedTask(task_name))
return bool(PackageList(task.list)[pkg])
return func
@staticmethod
def need_depclean(pkg, task_name):
def func(Get):
task = EmergeLog(EmergeLogNamedTask(task_name))
return (bool(PackageList(task.list)[pkg])
or Get('cl_update_force_depclean_set') == 'on'
or Get('cl_update_outdated_kernel_set') == 'on')
return func
@staticmethod
def force_preserved(Get):
pfile = "/var/lib/portage/preserved_libs_registry"
content = readFile(pfile).strip()
if not content or content[1:-1].strip() == '':
return False
else:
return True
class ClUpdateAction(Action):
"""
Действие обновление конфигурационных файлов
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError, UpdateError,
TemplatesError, BinhostError,
GitError, EmergeError)
successMessage = None
failedMessage = None
interruptMessage = __("Update manually interrupted")
emerge_tasks = [
{'name': 'save_bdeps_val',
'method': 'Update.save_with_bdeps()',
'essential': False
},
{'name': 'update_fastlogin_domain',
'method': "Update.update_fastlogin_domain_path()"
},
{'name': 'drop_portage_hash_on_sync',
'method': 'Update.drop_portage_state_hash()',
'condition': lambda Get: Get('cl_update_outdate_set') == 'on'
},
{'name': 'premerge_group',
'group': __("Checking for updates"),
'tasks': [
{'name': 'premerge',
'message': __("Calculating dependencies"),
'method': 'Update.premerge("-uDN","@world")',
'condition': lambda Get: (
Get('cl_update_sync_only_set') == 'off' and
Get('cl_update_pretend_set') == 'on') and \
(Get('cl_update_world') != "update" or
Get('cl_update_outdate_set') == 'on' or
Get('cl_update_settings_changes_set') == 'on' or
Get('cl_update_binhost_recheck_set') == 'on' or
Get('cl_update_force_fix_set') == 'on' or
Get('update.cl_update_package_cache_set') == 'on')
}],
},
{'name': 'update',
'condition': lambda Get:Get('cl_update_pretend_set') == 'off' and \
(Get('cl_update_world') != "update" or
Get('cl_update_outdate_set') == 'on' or
Get('cl_update_settings_changes_set') == 'on' or
Get('cl_update_binhost_recheck_set') == 'on' or
Get('cl_update_force_fix_set') == 'on' or
Get('cl_update_available_set') == 'on' or
Get('update.cl_update_package_cache_set') == 'on')
},
{'name': 'update_other',
'condition': lambda Get: ( Get('cl_update_pretend_set') == 'off' and
Get('cl_update_sync_only_set') == 'off')
},
{'name': 'update:update_world',
'group': __("Updating packages"),
'tasks': [
{'name': 'update_world',
'message': __("Calculating dependencies"),
'method': 'Update.emerge_ask(cl_update_pretend_set,'
'"-uDN","@world")',
}
],
'condition': lambda Get: Get('cl_update_sync_only_set') == 'off'
},
{'name': 'update_other:update_perl',
'group': __("Updating Perl modules"),
'tasks': [
{'name': 'update_other:perl_cleaner',
'message': __('Find & rebuild packages and Perl header files '
'broken due to a perl upgrade'),
'method': 'Update.emergelike("perl-cleaner", "all")',
'condition': UpdateConditions.was_installed(
'dev-lang/perl$', EmergeMark.PerlCleaner),
'decoration': 'Update.update_task("%s")' % EmergeMark.PerlCleaner
},
]
},
{'name': 'update_other:depclean',
'group': __("Cleaning the system from needless packages"),
'tasks': [
{'name': 'update_other:update_depclean',
'message': __("Calculating dependencies"),
'method': 'Update.depclean()',
'condition': UpdateConditions.need_depclean(
'.*', EmergeMark.Depclean),
'decoration': 'Update.update_task("%s")' % EmergeMark.Depclean
},
]
},
{'name': 'update_other:update_modules',
'group': __("Rebuilding dependent modules"),
'tasks': [
{'name': 'update_other:module_rebuild',
'message': __('Updating Kernel modules'),
'method': 'Update.emerge("","@module-rebuild")',
'condition': UpdateConditions.was_installed(
'sys-kernel/.*source', EmergeMark.KernelModules),
'decoration': 'Update.update_task("%s")' %
EmergeMark.KernelModules
},
{'name': 'update_other:x11_module_rebuild',
'message': __('Updating X.Org server modules'),
'method': 'Update.emerge("","@x11-module-rebuild")',
'condition': UpdateConditions.was_installed(
'x11-base/xorg-server', EmergeMark.XorgModules),
'decoration': 'Update.update_task("%s")' %
EmergeMark.XorgModules
},
{'name': 'update_other:preserved_rebuild',
'message': __('Updating preserved libraries'),
'method': 'Update.emerge("","@preserved-rebuild")',
'condition': lambda Get: (UpdateConditions.was_installed(
'.*', EmergeMark.PreservedLibs)() or
UpdateConditions.force_preserved(Get)),
'decoration': 'Update.update_task("%s")' %
EmergeMark.PreservedLibs
},
{'name': 'update_other:revdev_rebuild',
'message': __('Checking reverse dependencies'),
'method': 'Update.revdep_rebuild("revdep-rebuild")',
'condition': lambda Get: (Get(
'cl_update_revdep_rebuild_set') == 'on' and
UpdateConditions.was_installed(
'.*', EmergeMark.RevdepRebuild)()),
'decoration': 'Update.update_task("%s")' %
EmergeMark.RevdepRebuild
},
{'name': 'update_other:dispatch_conf_end',
'message': __("Updating configuration files"),
'method': 'Update.dispatchConf()',
'condition': lambda Get: (Get('cl_dispatch_conf') != 'skip' and
Get('cl_update_pretend_set') == 'off')
},
]
},
{'name': 'set_upto_date_cache',
'method': 'Update.setUpToDateCache()',
'condition': lambda Get: Get('cl_update_sync_only_set') == 'off' and \
Get('cl_update_pretend_set') == 'off'
}
]
# список задач для действия
tasks = [
{'name': 'check_schedule',
'method': 'Update.checkSchedule(cl_update_autocheck_interval,'
'cl_update_autocheck_set)',
'condition': lambda Get: (
Get('cl_update_autocheck_schedule_set') == 'on'),
},
{'name': 'check_run',
'method': 'Update.checkRun(cl_update_wait_another_set)'
},
] + get_synchronization_tasks("Update") + [
{'name': 'system_configuration',
'group': __("System configuration"),
'tasks': [
{'name': 'binhost_changed',
'method': 'Update.message_binhost_changed()'
},
{'name': 'revision',
'message': __("Fixing the settings"),
'method': 'Update.applyTemplates(install.cl_source,'
'cl_template_clt_set,True,None,False)',
'condition': lambda Get, GetBool: (Get('cl_templates_locate') and
(Get('cl_update_world') != "update" or
GetBool('cl_update_outdate_set') or
GetBool('cl_update_binhost_recheck_set') or
GetBool('cl_update_force_fix_set') or
GetBool('update.cl_update_package_cache_set')))
},
{'name': 'dispatch_conf',
'message': __("Updating configuration files"),
'method': 'Update.dispatchConf()',
'condition': lambda Get, GetBool: (Get('cl_dispatch_conf') != 'skip' and
Get('cl_update_pretend_set') == 'off' and
(GetBool('cl_update_outdate_set') or
GetBool('cl_update_binhost_recheck_set') or
GetBool('cl_update_force_fix_set') or
GetBool('update.cl_update_package_cache_set')))
},
]
}
] + emerge_tasks + [
{'name': 'failed',
'error': __("Update failed"),
'depend': (Tasks.failed() & Tasks.hasnot("interrupt") &
(Tasks.hasnot("check_schedule") |
Tasks.success_all("check_schedule")))},
{'name': 'failed',
'depend': Tasks.failed_all("check_schedule")
},
# сообщение удачного завершения при обновлении ревизии
{'name': 'update:save_portage_hash',
'method': 'Update.save_portage_state_hash()',
'condition': lambda Get: Get('cl_update_sync_only_set') == 'off'
},
{'name': 'drop_portage_hash',
'method': 'Update.drop_portage_state_hash()',
'depend': Tasks.failed()
},
# сообщение удачного завершения при обновлении ревизии
{'name': 'success_rev',
'message': __("System update finished!"),
'condition': lambda Get: (Get('cl_update_rev_set') == 'on' and
Get('cl_update_pretend_set') == 'off')
},
# сообщение удачного завершения при пересоздании world
{'name': 'success_world',
'message': __("World rebuild finished!"),
'condition': lambda Get: Get('cl_rebuild_world_set') == 'on'
},
]

@ -0,0 +1,147 @@
# -*- coding: utf-8 -*-
# Copyright 2010-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
from calculate.core.server.func import Action, Tasks
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
from calculate.lib.cl_template import TemplatesError
from calculate.lib.utils.binhosts import BinhostError
from calculate.lib.utils.files import FilesError
from calculate.update.update import UpdateError
from calculate.lib.utils.git import GitError
_ = lambda x: x
setLocalTranslate('cl_update3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClUpdateProfileAction(Action):
"""
Действие обновление конфигурационных файлов
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,
TemplatesError, BinhostError,
UpdateError, GitError)
successMessage = __("The profile was successfully updated")
failedMessage = __("Failed to update the profile")
interruptMessage = __("Profile update manually interrupted")
# список задач для действия
tasks = [
{'name': 'migrate_repository',
'method': 'Update.migrateCacheRepository('
'cl_update_profile_url,cl_update_profile_branch,'
'cl_update_profile_storage)',
'message': __("Repository transfer"),
'condition': lambda Get: not (
Get('cl_update_profile_storage').is_local(
Get('cl_update_profile_url'),
Get('cl_update_profile_branch')))
},
{'name': 'reconfigure_vars1',
'method': 'Update.invalidateVariables("cl_update_profile_storage")',
'depend': Tasks.has('migrate_repository')
},
{'name': 'check_datavars',
'error': _("Profile not found in master"),
'condition': lambda Get: not Get('update.cl_update_profile_datavars')
},
{'name': 'drop_binhosts',
'method': 'Update.drop_binhosts(update.cl_update_profile_datavars)'
},
{'name': 'reconfigure_vars',
'method': 'Update.reconfigureProfileVars(cl_update_profile_datavars,'
'cl_chroot_path)'
},
{'name': 'reps_synchronization',
'group': __("Repositories synchronization"),
'tasks': [
{'name': 'sync_reps',
'foreach': 'cl_update_profile_sync_rep',
'message': __("Syncing the {eachvar:capitalize} repository"),
'method': 'Update.syncRepositories(eachvar)',
},
{'name': 'sync_reps:regen_cache',
'foreach': 'cl_update_sync_overlay_rep',
'message': __("Updating the {eachvar:capitalize} repository cache"),
'essential': False,
'method': 'Update.regenCache(eachvar)',
'condition': (
lambda Get: (Get('cl_update_outdate_set') == 'on' and
Get('cl_update_metadata_force') != 'skip' or
Get('cl_update_metadata_force') == 'force'))
},
{'name': 'emerge_metadata',
'message': __("Metadata transfer"),
'method': 'Update.emergeMetadata()',
'condition': (
lambda Get: (Get('cl_update_outdate_set') == 'on' and
Get('cl_update_metadata_force') != 'skip' or
Get('cl_update_metadata_force') == 'force'))
},
{'name': 'eix_update',
'message': __("Updating the eix cache for "
"{cl_update_eix_repositories}"),
'method': 'Update.eixUpdate(cl_repository_name)',
'condition': (
lambda Get: (Get('cl_update_outdate_set') == 'on' and
Get('cl_update_eixupdate_force') != 'skip' or
Get('cl_update_eixupdate_force') == 'force'))
},
# сообщение удачного завершения при обновлении репозиториев
{'name': 'success_syncrep',
'message': __("Synchronization finished"),
'depend': (Tasks.success() & Tasks.has_any("sync_reps",
"sync_other_reps",
"emerge_metadata",
"eix_update")),
}
]
},
{'name': 'reps_synchronization',
'group': __("Setting up the profile"),
'tasks': [
{'name': 'set_profile',
'message': __("Switching to profile {cl_update_profile_system}"),
'method': 'Update.setProfile(cl_update_profile_system)'
},
{'name': 'rename_custom',
'method': 'Update.rename_custom_files()',
},
{'name': 'revision',
'message': __("Fixing the settings"),
'method': 'Update.applyProfileTemplates(cl_template_clt_set,'
'True,False,"update_profile")',
'condition': lambda Get: Get('cl_templates_locate')
},
{'name': 'reconfigure',
'message': __("The system is being configured"),
'method': 'Update.applyProfileTemplates(cl_template_clt_set,'
'True,False,"merge")',
'condition': lambda Get: (
Get('cl_update_templates_locate') and
Get('cl_update_skip_setup_set') == 'off')
},
{'name': 'dispatch_conf',
'message': __("Updating configuration files"),
'method': 'Update.dispatchConf()',
'condition': lambda Get: Get('cl_dispatch_conf') != 'skip'
},
]
}
]

@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import action
import update
from . import action
from . import update
section = "update"

@ -42,7 +42,7 @@ from calculate.lib.variables import env
from calculate.lib.variables import system as lib_system
from calculate.update.update_info import UpdateInfo
from itertools import chain
from urlparse import urlparse
from urllib.parse import urlparse
import io
import time

@ -0,0 +1,183 @@
# -*- coding: utf-8 -*-
# Copyright 2010-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
from calculate.lib.datavars import VariableError,DataVarsError
from calculate.core.server.func import WsdlBase
from calculate.install.install import InstallError
from .update import Update, UpdateError
from calculate.lib.utils.git import GitError
from utils.cl_update import ClUpdateAction
from utils.cl_update_profile import ClUpdateProfileAction
from utils.cl_setup_update import ClSetupUpdateAction
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate, _
setLocalTranslate('cl_update3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class Wsdl(WsdlBase):
methods = [
#
# Обновить текущую конфигурацию системы (world,ревизия)
#
{
# идентификатор метода
'method_name': "update",
# категория метода
'category': __('Update '),
# заголовок метода
'title': __("Update the System"),
# иконка для графической консоли
'image': 'calculate-update',
# метод присутствует в графической консоли
'gui': True,
# консольная команда
'command': 'cl-update',
# права для запуска метода
'rights': ['update'],
# объект содержащий модули для действия
'logic': {'Update': Update},
# описание действия
'action': ClUpdateAction,
# объект переменных
'datavars': "update",
'native_error': (VariableError, DataVarsError,
InstallError, UpdateError, GitError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'sync'},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Update the system"),
normal=(
'cl_update_binhost_stable_opt_set',
'cl_update_binhost_recheck_set',
'cl_update_with_bdeps_opt_set'
),
expert=(
'cl_update_sync_only_set',
'cl_update_other_set',
'cl_update_pretend_set',
'cl_update_sync_rep',
'cl_update_emergelist_set',
'cl_update_check_rep_set',
'cl_update_force_fix_set',
'cl_update_world',
'cl_update_gpg_force',
'cl_update_egencache_force',
'cl_update_eixupdate_force',
'cl_update_revdep_rebuild_set',
'cl_update_wait_another_set',
'cl_update_autocheck_schedule_set',
'cl_update_onedepth_set',
'cl_update_cleanpkg_set',
'cl_update_branch_data',
'cl_templates_locate',
'cl_verbose_set', 'cl_dispatch_conf'),
next_label=_("Run"))]},
#
# Сменить профиль
#
{
# идентификатор метода
'method_name': "update_profile",
# категория метода
'category': __('Update '),
# заголовок метода
'title': __("Change the Profile"),
# иконка для графической консоли
'image': 'calculate-update-profile,'
'notification-display-brightness-full,gtk-dialog-info,'
'help-hint',
# метод присутствует в графической консоли
'gui': True,
# консольная команда
'command': 'cl-update-profile',
# права для запуска метода
'rights': ['change_profile'],
# объект содержащий модули для действия
'logic': {'Update': Update},
# описание действия
'action': ClUpdateProfileAction,
# объект переменных
'datavars': "update",
'native_error': (VariableError, DataVarsError,
InstallError, UpdateError, GitError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'update_profile'},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Repository"),
brief=('cl_update_profile_repo_name',),
hide=('cl_update_profile_url',
'cl_update_profile_sync_set'),
normal=('cl_update_profile_url',),
expert=('cl_update_profile_sync_set',)),
lambda group: group(_("Profile"),
normal=('cl_update_profile_system',
'cl_update_world'),
expert=('cl_update_skip_setup_set',
'cl_update_templates_locate',
'cl_verbose_set',
'cl_dispatch_conf'),
hide=('cl_update_templates_locate',
'cl_verbose_set',
'cl_dispatch_conf'),
brief=('cl_update_profile_system',
'cl_update_profile_linux_fullname',
'cl_update_profile_depend_data')
)],
'brief': {'next': __("Run"),
'name': __("Set the profile")}},
#
# Настроить автопроверку обновлений
#
{
# идентификатор метода
'method_name': "setup_update",
# категория метода
'category': __('Configuration'),
# заголовок метода
'title': __("Update Check"),
# иконка для графической консоли
'image': 'calculate-setup-update,software-properties,preferences-desktop',
# метод присутствует в графической консоли
'gui': True,
# консольная команда
'command': 'cl-setup-update',
# права для запуска метода
'rights': ['setup_update'],
# объект содержащий модули для действия
'logic': {'Update': Update},
# описание действия
'action': ClSetupUpdateAction,
# объект переменных
'datavars': "update",
'native_error': (VariableError, DataVarsError,
InstallError, UpdateError, GitError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'merge'},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Updates autocheck settings"),
normal=('cl_update_autocheck_set',
'cl_update_autocheck_interval',
'cl_update_cleanpkg_set',
'cl_update_other_set'),
next_label=_("Save"))]},
]

@ -24,7 +24,8 @@ import sys
from calculate.consolegui import qt
# from calculate.core.client.function import create_obj
from .utils import create_obj
# from .utils import create_obj
from . import utils
from calculate.lib.utils.files import readLinesFile, listDirectory, readFile, \
getProgPath, process, STDOUT
from calculate.lib.utils.colortext.palette import (
@ -2500,14 +2501,12 @@ def icon_visible (mainwgt, name, action):
if hasattr (mainwgt.topmenu, name):
getattr (mainwgt.topmenu, name).setVisible(action)
# from calculate.core.client.function import get_ip_mac_type
from .utils import get_ip_mac_type
from calculate.lib.utils import ip as ip_mod
def get_ip_mac():
for Interfaces in ip_mod.getInterfaces():
try:
ip, mac, client_type = get_ip_mac_type('gui')
ip, mac, client_type = utils.get_ip_mac_type('gui')
return (ip, mac)
except:
pass
@ -2733,7 +2732,7 @@ class ImageLabel(qt.QLabel):
self.setFixedHeight(sizes[1])
def get_view_params(client, method, step = None, expert = None, brief = None):
view_params = create_obj(client, method)
view_params = utils.create_obj(client, method)
view_params.step = step
view_params.expert = expert
view_params.brief = brief

@ -0,0 +1,122 @@
# -*- coding: utf-8 -*-
# Copyright 2012-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 logging
import sys
from os import path
import calculate.contrib
from suds.transport import TransportError
from suds import WebFault
from .client_class import Client_suds
import urllib.request as urllib2
from calculate.core.datavars import DataVarsCore
from .client_class import HTTPSClientCertTransport
from calculate.lib.utils.dbus_tools import get_dbus_hostname
from functools import partial
from M2Crypto import X509
from .utils import clear
_ = lambda x: x
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_core3', sys.modules[__name__])
def get_cert_groups(cert_file):
"""
Получить строку с группами сертификата
:param cert_file: файл сертификата
"""
try:
cert = X509.load_cert(cert_file)
val = cert.get_ext('nsComment').get_value()
if val.startswith('group:'):
return val[6:]
return ""
except (IOError, LookupError):
return ""
def get_certifactions_for_host(host, use_dbus=False):
"""
Получить список сертификатов подходящих для host
:param host:
:return: список полных путей файлов сертификатов
"""
log = logging.getLogger("certification")
cl_vars_core = DataVarsCore()
cl_vars_core.importCore()
cl_vars_core.flIniFile()
home_path = cl_vars_core.Get('ur_home_path')
port = cl_vars_core.GetInteger('core.cl_core_port')
path_to_cert = cl_vars_core.Get('core.cl_client_cert_dir')
path_to_cert = path_to_cert.replace("~", home_path)
url = "https://%s:%d/?wsdl" % (host, port)
clear()
if not use_dbus:
try:
client = Client_suds(url, transport=HTTPSClientCertTransport(
None, None, path_to_cert, None))
client.wsdl.services[0].setlocation(url)
server_host_name = client.service.get_server_host_name()
del client
except (urllib2.URLError, TransportError) as e:
log.debug(_('Failed to connect', ) + _(': ') + str(e))
return []
except KeyboardInterrupt:
log.debug(_("Manually interrupted"))
return []
else:
server_host_name = get_dbus_hostname() or "localhost"
try:
import glob
all_cert_list = glob.glob(os.path.join(path_to_cert, '*.crt'))
fit_cert_list = []
for client_cert_path in all_cert_list:
client_cert = client_cert_path.replace(path_to_cert, '')
client_cert_name = client_cert.replace('.crt', '')
if server_host_name.endswith(client_cert_name):
fit_cert_list.append(client_cert_name)
fit_cert_list.sort(key=len)
mkfullpath = partial(path.join, path_to_cert)
return map(mkfullpath, map(lambda x: "%s.crt" % x, fit_cert_list))
# ----------------------------------------------------
except WebFault as f:
log.debug(_("Exception: %s") % f)
log.debug(f.fault)
except TransportError as te:
log.debug(_("Exception: %s") % te)
except KeyboardInterrupt:
log.debug(_("Manually interrupted"))
except Exception as e:
log.debug(str(e))
return []
def user_can_run_update(use_dbus):
"""
Текущий пользователь может запускать обновление системы
"""
for cert in get_certifactions_for_host("localhost", use_dbus=use_dbus):
groups = get_cert_groups(cert)
if any(x in groups for x in ("all", "update")):
return True
return False

@ -14,15 +14,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
import calculate.contrib
from suds import MethodNotFound
from calculate.lib.utils import ip as ip
_ = lambda x: x
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_core3', sys.modules[__name__])
def getIpLocal():
@ -146,3 +148,4 @@ class switch(object):
return True
else:
return False

Loading…
Cancel
Save