Source code for univention.appcenter.actions.update_check

#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Univention App Center
#  univention-app module checking UCS update regarding installed apps
#
# Copyright 2021-2022 Univention GmbH
#
# https://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <https://www.gnu.org/licenses/>.

from argparse import Action

import six

from univention.lib.ucs import UCS_Version
from univention.appcenter.log import get_logfile_logger
from univention.appcenter.app_cache import Apps, AppCenterCache, default_server
from univention.appcenter.actions import UniventionAppAction, get_action
from univention.appcenter.ucr import ucr_get

if six.PY2:
	from backports.tempfile import TemporaryDirectory
else:
	from tempfile import TemporaryDirectory


[docs]class CheckUcsVersion(Action): def __call__(self, parser, namespace, value, option_string=None): try: UCS_Version(value + '-0') except ValueError as exc: parser.error('--ucs-version ' + str(exc)) setattr(namespace, self.dest, value)
[docs]class UpdateCheck(UniventionAppAction): ''' Check if update to next ucs minor version is possible with the locally installed apps For docker apps check if is available in next UCS version. For package based apps check if there is an app version with the same component in the next UCS version ''' help = 'Check for all locally installed Apps if they are available in the next UCS version'
[docs] def setup_parser(self, parser): parser.add_argument( '--ucs-version', action=CheckUcsVersion, required=True, help="the next ucs version (MAJOR.MINOR), check if update with locally installed apps is possible", )
[docs] @classmethod def app_can_update(cls, app, next_version, next_apps): ''' checks if update is possible for this app docker apps have to support the next version components must be available in the next version component id of package based app must be available in the next version ''' if app.docker: # current docker must support next version if next_version in app.supported_ucs_versions: return True else: if app.without_repository: # current component must be available in next version for a in next_apps: if a.id == app.id: return True else: # current component id must be available in next version for a in next_apps: if a.component_id == app.component_id: return True return False
[docs] @classmethod def get_blocking_apps(cls, ucs_version): ''' checks if update is possible for this app ''' ucs_version = UCS_Version(ucs_version + '-0') next_minor = '%(major)d.%(minor)d' % ucs_version next_version = '%(major)d.%(minor)d-%(patchlevel)d' % ucs_version current_version = UCS_Version(ucr_get('version/version') + '-0') current_minor = '%(major)d.%(minor)d' % current_version # if this is just a patchlevel update, everything is fine if current_minor >= next_minor: return {} # first, update the local cache and get current apps update = get_action('update') update.logger = get_logfile_logger('update-check') update.call() current_cache = Apps(locale='en') # get apps in next version with TemporaryDirectory() as tempdir: update.call(ucs_version=next_minor, cache_dir=tempdir, just_get_cache=True) next_cache = AppCenterCache.build(ucs_versions=next_minor, server=default_server(), locale='en', cache_dir=tempdir) next_apps = next_cache.get_every_single_app() # check apps blocking_apps = dict() for app in current_cache.get_all_locally_installed_apps(): if not cls.app_can_update(app, next_version, next_apps): cls.debug('app %s is not available for %s' % (app.id, next_version)) blocking_apps[app.component_id] = app.name else: cls.debug('app %s is available for %s' % (app.id, next_version)) return blocking_apps
[docs] def main(self, args): blocking_apps = self.get_blocking_apps(args.ucs_version) if blocking_apps: self.log('The update to %s is currently not possible,' % args.ucs_version) self.log('because the following Apps are not available for UCS %s:' % args.ucs_version) for app in blocking_apps.values(): self.log(' * %s' % app) return 1