# -*- 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_layman', 'message': __("Layman cache update"), 'method': Object('update_layman()'), 'condition': lambda Get: (isPkgInstalled( "app-portage/layman", 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('syncLaymanRepository(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': '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') }], }, {'name': 'update', 'condition': lambda Get:Get('cl_update_pretend_set') == 'off', }, {'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"), '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_skip_rb_set') == 'off' 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': 'update:set_upto_date_cache', 'method': 'Update.setUpToDateCache()' } ] # список задач для действия 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': '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' }, ]