Hello community, here is the log from the commit of package dnf-plugins-extras for openSUSE:Factory checked in at 2020-02-27 16:57:47 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/dnf-plugins-extras (Old) and /work/SRC/openSUSE:Factory/.dnf-plugins-extras.new.26092 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "dnf-plugins-extras" Thu Feb 27 16:57:47 2020 rev:3 rq:779947 version:4.0.9 Changes: -------- --- /work/SRC/openSUSE:Factory/dnf-plugins-extras/dnf-plugins-extras.changes 2019-12-03 15:20:15.894564958 +0100 +++ /work/SRC/openSUSE:Factory/.dnf-plugins-extras.new.26092/dnf-plugins-extras.changes 2020-02-27 16:57:49.122855765 +0100 @@ -1,0 +2,12 @@ +Thu Feb 27 14:21:01 UTC 2020 - Neal Gompa <ngomp...@gmail.com> + +- Update to version 4.0.9 + + [doc] move manpages for plugins to "dnf-PLUGIN" (rh#1706386) + + Add offline-upgrade and offline-distrosync commands + + [doc] Add description for new offline command + + Store reason for system-upgrade plugin + + Do not show Operation aborted as an error (rh#1797427) +- Drop backported patch included in this release + * Patch: 0001-doc-move-manpages-for-plugins-to-dnf-PLUGIN-RhBug-17.patch + +------------------------------------------------------------------- Old: ---- 0001-doc-move-manpages-for-plugins-to-dnf-PLUGIN-RhBug-17.patch dnf-plugins-extras-4.0.8.tar.gz New: ---- dnf-plugins-extras-4.0.9.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ dnf-plugins-extras.spec ++++++ --- /var/tmp/diff_new_pack.Ex7LDu/_old 2020-02-27 16:57:49.670856681 +0100 +++ /var/tmp/diff_new_pack.Ex7LDu/_new 2020-02-27 16:57:49.670856681 +0100 @@ -1,7 +1,7 @@ # # spec file for package dnf-plugins-extras # -# Copyright (c) 2019 Neal Gompa <ngomp...@gmail.com>. +# Copyright (c) 2020 Neal Gompa <ngomp...@gmail.com>. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,7 +16,7 @@ # -%{!?dnf_lowest_compatible: %global dnf_lowest_compatible 4.2.1} +%{!?dnf_lowest_compatible: %global dnf_lowest_compatible 4.2.19} %global dnf_plugins_extra_obsolete 2.0.0 # YUM v3 has been removed from openSUSE Tumbleweed as of 20191119 @@ -37,7 +37,7 @@ %bcond_with tests Name: dnf-plugins-extras -Version: 4.0.8 +Version: 4.0.9 Release: 0 Summary: Extras Plugins for DNF Group: System/Packages @@ -45,9 +45,6 @@ URL: https://github.com/rpm-software-management/%{name} Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz -# Backports from upstream -Patch0001: 0001-doc-move-manpages-for-plugins-to-dnf-PLUGIN-RhBug-17.patch - BuildArch: noarch BuildRequires: cmake BuildRequires: gettext @@ -142,6 +139,8 @@ Requires: python3-%{name}-common = %{version}-%{release} Requires: python3-systemd Requires: systemd +Provides: dnf-command(offline-distrosync) +Provides: dnf-command(offline-upgrade) Provides: dnf-command(system-upgrade) Provides: %{name}-system-upgrade = %{version}-%{release} Provides: system-upgrade = %{version}-%{release} ++++++ dnf-plugins-extras-4.0.8.tar.gz -> dnf-plugins-extras-4.0.9.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-plugins-extras-4.0.8/dnf-plugins-extras.spec new/dnf-plugins-extras-4.0.9/dnf-plugins-extras.spec --- old/dnf-plugins-extras-4.0.8/dnf-plugins-extras.spec 2019-11-07 11:41:51.000000000 +0100 +++ new/dnf-plugins-extras-4.0.9/dnf-plugins-extras.spec 2020-02-24 15:52:08.000000000 +0100 @@ -1,4 +1,4 @@ -%{!?dnf_lowest_compatible: %global dnf_lowest_compatible 4.2.1} +%{!?dnf_lowest_compatible: %global dnf_lowest_compatible 4.2.19} %global dnf_plugins_extra_obsolete 2.0.0 %if 0%{?rhel} > 7 || 0%{?fedora} > 29 @@ -14,7 +14,7 @@ %endif Name: dnf-plugins-extras -Version: 4.0.8 +Version: 4.0.9 Release: 1%{?dist} Summary: Extras Plugins for DNF License: GPLv2+ @@ -364,14 +364,14 @@ %if %{with python2} %files -n python2-dnf-plugin-kickstart %{python2_sitelib}/dnf-plugins/kickstart.* -%{_mandir}/man8/dnf.plugin.kickstart.* +%{_mandir}/man8/dnf-kickstart.* %endif %if %{with python3} %files -n python3-dnf-plugin-kickstart %{python3_sitelib}/dnf-plugins/kickstart.* %{python3_sitelib}/dnf-plugins/__pycache__/kickstart.* -%{_mandir}/man8/dnf.plugin.kickstart.* +%{_mandir}/man8/dnf-kickstart.* %endif %if %{with python3} @@ -379,20 +379,20 @@ %config(noreplace) %{_sysconfdir}/dnf/plugins/rpmconf.conf %{python3_sitelib}/dnf-plugins/rpm_conf.* %{python3_sitelib}/dnf-plugins/__pycache__/rpm_conf.* -%{_mandir}/man8/dnf.plugin.rpmconf.* +%{_mandir}/man8/dnf-rpmconf.* %endif %if %{with python2} %files -n python2-dnf-plugin-snapper %{python2_sitelib}/dnf-plugins/snapper.* -%{_mandir}/man8/dnf.plugin.snapper.* +%{_mandir}/man8/dnf-snapper.* %endif %if %{with python3} %files -n python3-dnf-plugin-snapper %{python3_sitelib}/dnf-plugins/snapper.* %{python3_sitelib}/dnf-plugins/__pycache__/snapper.* -%{_mandir}/man8/dnf.plugin.snapper.* +%{_mandir}/man8/dnf-snapper.* %endif %if %{with python2} @@ -401,7 +401,7 @@ %{_unitdir}/dnf-system-upgrade-cleanup.service %{_unitdir}/system-update.target.wants/dnf-system-upgrade.service %{python2_sitelib}/dnf-plugins/system_upgrade.* -%{_mandir}/man8/dnf.plugin.system-upgrade.* +%{_mandir}/man8/dnf-system-upgrade.* %endif %if %{with python3} @@ -411,20 +411,20 @@ %{_unitdir}/system-update.target.wants/dnf-system-upgrade.service %{python3_sitelib}/dnf-plugins/system_upgrade.py %{python3_sitelib}/dnf-plugins/__pycache__/system_upgrade.* -%{_mandir}/man8/dnf.plugin.system-upgrade.* +%{_mandir}/man8/dnf-system-upgrade.* %endif %if %{with python2} %files -n python2-dnf-plugin-tracer %{python2_sitelib}/dnf-plugins/tracer.* -%{_mandir}/man8/dnf.plugin.tracer.* +%{_mandir}/man8/dnf-tracer.* %endif %if %{with python3} %files -n python3-dnf-plugin-tracer %{python3_sitelib}/dnf-plugins/tracer.* %{python3_sitelib}/dnf-plugins/__pycache__/tracer.* -%{_mandir}/man8/dnf.plugin.tracer.* +%{_mandir}/man8/dnf-tracer.* %endif %if %{with python3} @@ -432,14 +432,14 @@ %config(noreplace) %{_sysconfdir}/dnf/plugins/torproxy.conf %{python3_sitelib}/dnf-plugins/torproxy.* %{python3_sitelib}/dnf-plugins/__pycache__/torproxy.* -%{_mandir}/man8/dnf.plugin.torproxy.* +%{_mandir}/man8/dnf-torproxy.* %endif %if %{with python3} %files -n python3-dnf-plugin-showvars %{python3_sitelib}/dnf-plugins/showvars.* %{python3_sitelib}/dnf-plugins/__pycache__/showvars.* -%{_mandir}/man8/dnf.plugin.showvars.* +%{_mandir}/man8/dnf-showvars.* %endif %changelog diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-plugins-extras-4.0.8/doc/CMakeLists.txt new/dnf-plugins-extras-4.0.9/doc/CMakeLists.txt --- old/dnf-plugins-extras-4.0.8/doc/CMakeLists.txt 2019-11-07 11:41:51.000000000 +0100 +++ new/dnf-plugins-extras-4.0.9/doc/CMakeLists.txt 2020-02-24 15:52:08.000000000 +0100 @@ -18,14 +18,14 @@ ADD_CUSTOM_TARGET (doc) ADD_DEPENDENCIES (doc doc-html doc-man) -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/dnf.plugin.kickstart.8 - ${CMAKE_CURRENT_BINARY_DIR}/dnf.plugin.snapper.8 - ${CMAKE_CURRENT_BINARY_DIR}/dnf.plugin.system-upgrade.8 - ${CMAKE_CURRENT_BINARY_DIR}/dnf.plugin.tracer.8 - ${CMAKE_CURRENT_BINARY_DIR}/dnf.plugin.showvars.8 +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/dnf-kickstart.8 + ${CMAKE_CURRENT_BINARY_DIR}/dnf-snapper.8 + ${CMAKE_CURRENT_BINARY_DIR}/dnf-system-upgrade.8 + ${CMAKE_CURRENT_BINARY_DIR}/dnf-tracer.8 + ${CMAKE_CURRENT_BINARY_DIR}/dnf-showvars.8 DESTINATION share/man/man8) if (${PYTHON_VERSION_MAJOR} STREQUAL "3") - INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/dnf.plugin.rpmconf.8 - ${CMAKE_CURRENT_BINARY_DIR}/dnf.plugin.torproxy.8 + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/dnf-rpmconf.8 + ${CMAKE_CURRENT_BINARY_DIR}/dnf-torproxy.8 DESTINATION share/man/man8) endif() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-plugins-extras-4.0.8/doc/conf.py new/dnf-plugins-extras-4.0.9/doc/conf.py --- old/dnf-plugins-extras-4.0.8/doc/conf.py 2019-11-07 11:41:51.000000000 +0100 +++ new/dnf-plugins-extras-4.0.9/doc/conf.py 2020-02-24 15:52:08.000000000 +0100 @@ -240,17 +240,13 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('kickstart', 'dnf.plugin.kickstart', - u'DNF kickstart Plugin', AUTHORS, 8), - ('rpmconf', 'dnf.plugin.rpmconf', - u'DNF rpmconf Plugin', AUTHORS, 8), - ('snapper', 'dnf.plugin.snapper', - u'DNF snapper Plugin', AUTHORS, 8), - ('system-upgrade', 'dnf.plugin.system-upgrade', u'DNF system-upgrade Plugin', AUTHORS, 8), - ('torproxy', 'dnf.plugin.torproxy', u'DNF torproxy Plugin', AUTHORS, 8), - ('showvars', 'dnf.plugin.showvars', u'DNF showvars Plugin', AUTHORS, 8), - ('tracer', 'dnf.plugin.tracer', - u'DNF tracer Plugin', AUTHORS, 8), + ('kickstart', 'dnf-kickstart', u'DNF kickstart Plugin', AUTHORS, 8), + ('rpmconf', 'dnf-rpmconf', u'DNF rpmconf Plugin', AUTHORS, 8), + ('snapper', 'dnf-snapper', u'DNF snapper Plugin', AUTHORS, 8), + ('system-upgrade', 'dnf-system-upgrade', u'DNF system-upgrade Plugin', AUTHORS, 8), + ('torproxy', 'dnf-torproxy', u'DNF torproxy Plugin', AUTHORS, 8), + ('showvars', 'dnf-showvars', u'DNF showvars Plugin', AUTHORS, 8), + ('tracer', 'dnf-tracer', u'DNF tracer Plugin', AUTHORS, 8), ] # If true, show URL addresses after external links. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-plugins-extras-4.0.8/doc/release_notes.rst new/dnf-plugins-extras-4.0.9/doc/release_notes.rst --- old/dnf-plugins-extras-4.0.8/doc/release_notes.rst 2019-11-07 11:41:51.000000000 +0100 +++ new/dnf-plugins-extras-4.0.9/doc/release_notes.rst 2020-02-24 15:52:08.000000000 +0100 @@ -5,6 +5,21 @@ .. contents:: =================== +4.0.9 Release Notes +=================== + +- [doc] move manpages for plugins to "dnf-PLUGIN" (RhBug:1706386) +- Add offline-upgrade and offline-distrosync commands +- [doc] Add description for new offline command +- Store reason for system-upgrade plugin +- Do not show Operation aborted as an error (RhBug:1797427) + +Bugs fixed in 4.0.9: + +* :rhbug:`1706386` +* :rhbug:`1797427` + +=================== 4.0.8 Release Notes =================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-plugins-extras-4.0.8/doc/summaries_cache new/dnf-plugins-extras-4.0.9/doc/summaries_cache --- old/dnf-plugins-extras-4.0.8/doc/summaries_cache 2019-11-07 11:41:51.000000000 +0100 +++ new/dnf-plugins-extras-4.0.9/doc/summaries_cache 2020-02-24 15:52:08.000000000 +0100 @@ -190,5 +190,13 @@ [ 1764169, "system upgrade fails when packages need to be reinstalled, they are not downloaded" + ], + [ + 1706386, + "[RFE] Discoverable man page names for DNF plugins" + ], + [ + 1797427, + "'dnf system-upgrade download' misleading message" ] ] \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-plugins-extras-4.0.8/doc/system-upgrade.rst new/dnf-plugins-extras-4.0.9/doc/system-upgrade.rst --- old/dnf-plugins-extras-4.0.8/doc/system-upgrade.rst 2019-11-07 11:41:51.000000000 +0100 +++ new/dnf-plugins-extras-4.0.9/doc/system-upgrade.rst 2020-02-24 15:52:08.000000000 +0100 @@ -23,6 +23,10 @@ Description ----------- +DNF system-upgrades plugin provides three commands: ``system-upgrade``, ``offline-upgrade``, and +``offline-distrosync``. Only ``system-upgrade`` command requires increase of distribution major +version (``--releasever``) compared to installed version. + ``dnf system-upgrade`` can be used to upgrade a Fedora system to a new major release. It replaces fedup (the old Fedora Upgrade tool). Before you proceed ensure that your system is fully upgraded (``dnf --refresh upgrade``). @@ -35,7 +39,7 @@ On modular system, also set the ``module_platform_id``. For example, for Fedora 30: - ``dnf system-upgrade download --releasever 30 --setopt='module_platform_id=platform:f30' [OPTIONS]`` +``dnf system-upgrade download --releasever 30 [OPTIONS]`` ``dnf system-upgrade reboot`` @@ -45,6 +49,26 @@ ``dnf system-upgrade log --number=<number>`` +``dnf offline-upgrade download [OPTIONS]`` + +``dnf offline-upgrade reboot`` + +``dnf offline-upgrade clean`` + +``dnf offline-upgrade log`` + +``dnf offline-upgrade log --number=<number>`` + +``dnf offline-distrosync download [OPTIONS]`` + +``dnf offline-distrosync reboot`` + +``dnf offline-distrosync clean`` + +``dnf offline-distrosync log`` + +``dnf offline-distrosync log --number=<number>`` + ----------- Subcommands ----------- @@ -88,7 +112,8 @@ ``--no-downgrade`` Behave like ``dnf update``: do not install packages from the new release if they are older than what is currently installed. This is the opposite of - ``--distro-sync``. If both are specified, the last option will be used. + ``--distro-sync``. If both are specified, the last option will be used. The option cannot be + used with the ``offline-distrosync` command. ``--number`` Applied with ``log`` subcommand will show the log specified by the number. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-plugins-extras-4.0.8/plugins/system_upgrade.py new/dnf-plugins-extras-4.0.9/plugins/system_upgrade.py --- old/dnf-plugins-extras-4.0.8/plugins/system_upgrade.py 2019-11-07 11:41:51.000000000 +0100 +++ new/dnf-plugins-extras-4.0.9/plugins/system_upgrade.py 2020-02-24 15:52:08.000000000 +0100 @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# Copyright (c) 2015 Red Hat, Inc. +# Copyright (c) 2015-2020 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ import os import os.path import re +import sys import uuid from systemd import journal @@ -60,11 +61,13 @@ RELEASEVER_MSG = _( "Need a --releasever greater than the current system version.") DOWNLOAD_FINISHED_MSG = _( # Translators: do not change "reboot" here - "Download complete! Use 'dnf system-upgrade reboot' to start the upgrade.\n" - "To remove cached metadata and transaction use 'dnf system-upgrade clean'") + "Download complete! Use 'dnf {command} reboot' to start the upgrade.\n" + "To remove cached metadata and transaction use 'dnf {command} clean'") CANT_RESET_RELEASEVER = _( "Sorry, you need to use 'download --releasever' instead of '--network'") +STATE_VERSION = 2 + # --- Miscellaneous helper functions ------------------------------------------ @@ -166,6 +169,9 @@ return self._data.get(option) return property(getprop, setprop) + # !!! Increase STATE_VERSION for any changes in data structure like a new property or a new + # data structure !!! + state_version = _prop("state_version") download_status = _prop("download_status") destdir = _prop("destdir") target_releasever = _prop("target_releasever") @@ -176,6 +182,7 @@ # list of repos with repo_gpgcheck=True repo_gpgcheck_repos = _prop("repo_gpgcheck_repos") upgrade_status = _prop("upgrade_status") + upgrade_command = _prop("upgrade_command") distro_sync = _prop("distro_sync") allow_erasing = _prop("allow_erasing") enable_disable_repos = _prop("enable_disable_repos") @@ -323,10 +330,12 @@ super(SystemUpgradePlugin, self).__init__(base, cli) if cli: cli.register_command(SystemUpgradeCommand) + cli.register_command(OfflineUpgradeCommand) + cli.register_command(OfflineDistrosyncCommand) class SystemUpgradeCommand(dnf.cli.Command): - aliases = ('system-upgrade', 'fedup') + aliases = ('system-upgrade', 'fedup',) summary = _("Prepare system for upgrade to a new release") def __init__(self, cli): @@ -353,11 +362,11 @@ DNF_VERSION=dnf.const.VERSION) def pre_configure(self): + self._call_sub("check") self._call_sub("pre_configure") def configure(self): self._call_sub("configure") - self._call_sub("check") def run(self): self._call_sub("run") @@ -365,21 +374,56 @@ def run_transaction(self): self._call_sub("transaction") + def run_resolved(self): + self._call_sub("resolved") + def _call_sub(self, name): subfunc = getattr(self, name + '_' + self.opts.tid[0], None) if callable(subfunc): subfunc() + def _check_state_version(self, command): + if self.state.state_version != STATE_VERSION: + msg = _("Incompatible version of data. Rerun 'dnf {command} download [OPTIONS]'" + "").format(command=command) + raise CliError(msg) + def _set_cachedir(self): # set download directories from json state file self.base.conf.cachedir = DEFAULT_DATADIR self.base.conf.destdir = self.state.destdir if self.state.destdir else None + def _get_forward_reverse_pkg_reason_pairs(self): + """ + forward = {repoid:{pkg_nevra: {tsi.action: tsi.reason}} + reverse = {pkg_nevra: {tsi.action: tsi.reason}} + :return: forward, reverse + """ + backward_action = set(dnf.transaction.BACKWARD_ACTIONS +\ + [libdnf.transaction.TransactionItemAction_REINSTALLED]) + forward_actions = set(dnf.transaction.FORWARD_ACTIONS) + + forward = {} + reverse = {} + for tsi in self.cli.base.transaction: + if tsi.action in forward_actions: + pkg = tsi.pkg + forward.setdefault(pkg.repo.id, {}).setdefault( + str(pkg), {})[tsi.action] = tsi.reason + elif tsi.action in backward_action: + reverse.setdefault(str(tsi.pkg), {})[tsi.action] = tsi.reason + return forward, reverse + # == pre_configure_*: set up action-specific demands ========================== def pre_configure_download(self): # only download subcommand accepts --destdir command line option self.base.conf.cachedir = DEFAULT_DATADIR self.base.conf.destdir = self.opts.destdir if self.opts.destdir else None + if 'offline-distrosync' == self.opts.command and not self.opts.distro_sync: + raise CliError( + _("Command 'offline-distrosync' cannot be used with --no-downgrade option")) + elif 'offline-upgrade' == self.opts.command: + self.opts.distro_sync = False def pre_configure_reboot(self): self._set_cachedir() @@ -396,16 +440,19 @@ # == configure_*: set up action-specific demands ========================== def configure_download(self): - help_url = get_url_from_os_release() - if help_url: - msg = _('Additional information for System Upgrade: {}') - logger.info(msg.format(ucd(help_url))) - if self.base._promptWanted(): - msg = _('Before you continue ensure that your system is fully upgraded by running ' - '"dnf --refresh upgrade". Do you want to continue') - if self.base.conf.assumeno or not self.base.output.userconfirm( - msg='{} [y/N]: '.format(msg), defaultyes_msg='{} [Y/n]: '.format(msg)): - raise CliError(_("Operation aborted.")) + if 'system-upgrade' == self.opts.command or 'fedup' == self.opts.command: + help_url = get_url_from_os_release() + if help_url: + msg = _('Additional information for System Upgrade: {}') + logger.info(msg.format(ucd(help_url))) + if self.base._promptWanted(): + msg = _('Before you continue ensure that your system is fully upgraded by running ' + '"dnf --refresh upgrade". Do you want to continue') + if self.base.conf.assumeno or not self.base.output.userconfirm( + msg='{} [y/N]: '.format(msg), defaultyes_msg='{} [Y/n]: '.format(msg)): + logger.error(_("Operation aborted.")) + sys.exit(1) + check_release_ver(self.base.conf, target=self.opts.releasever) self.cli.demands.root_user = True self.cli.demands.resolving = True self.cli.demands.available_repos = True @@ -464,15 +511,14 @@ # == check_*: do any action-specific checks =============================== - def check_download(self): - check_release_ver(self.base.conf, target=self.opts.releasever) - dnf.util.ensure_dir(self.base.conf.cachedir) - if self.base.conf.destdir: - dnf.util.ensure_dir(self.base.conf.destdir) - def check_reboot(self): if not self.state.download_status == 'complete': raise CliError(_("system is not ready for upgrade")) + self._check_state_version(self.opts.command) + if self.state.upgrade_command != self.opts.command: + msg = _("the transaction was not prepared for '{command}'. " + "Rerun 'dnf {command} download [OPTIONS]'").format(command=self.opts.command) + raise CliError(msg) if os.path.lexists(MAGIC_SYMLINK): raise CliError(_("upgrade is already scheduled")) dnf.util.ensure_dir(DEFAULT_DATADIR) @@ -487,9 +533,13 @@ raise SystemExit(0) # Delete symlink ASAP to avoid reboot loops dnf.yum.misc.unlink_f(MAGIC_SYMLINK) + command = self.state.upgrade_command + if not command: + command = self.opts.command + self._check_state_version(command) if not self.state.upgrade_status == 'ready': - raise CliError( # Translators: do not change "reboot" here - _("use 'dnf system-upgrade reboot' to begin the upgrade")) + msg = _("use 'dnf {command} reboot' to begin the upgrade").format(command=command) + raise CliError(msg) # == run_*: run the action/prep the transaction =========================== @@ -525,16 +575,23 @@ def run_upgrade(self): # change the upgrade status (so we can detect crashed upgrades later) + command = '' with self.state as state: state.upgrade_status = 'incomplete' + command = state.upgrade_command + if command == 'offline-upgrade': + msg = _("Starting offline upgrade. This will take a while.") + elif command == 'offline-distrosync': + msg = _("Starting offline distrosync. This will take a while.") + else: + msg = _("Starting system upgrade. This will take a while.") - self.log_status(_("Starting system upgrade. This will take a while."), - UPGRADE_STARTED_ID) + self.log_status(msg, UPGRADE_STARTED_ID) # reset the splash mode and let the user know we're running Plymouth.set_mode() Plymouth.progress(0) - Plymouth.message(_("Starting system upgrade. This will take a while.")) + Plymouth.message(msg) # disable screen blanking disable_blanking() @@ -555,7 +612,7 @@ errs = [] - for pkgspec in self.state.remove_packages: + for pkgspec in self.state.remove_packages.keys(): try: self.base.remove(pkgspec) except dnf.exceptions.MarkingError: @@ -563,8 +620,8 @@ logger.info(msg, self.base.output.term.bold(pkgspec)) errs.append(pkgspec) - for repo_id, pkg_spec_list in self.state.install_packages.items(): - for pkgspec in pkg_spec_list: + for repo_id, pkg_spec_dict in self.state.install_packages.items(): + for pkgspec in pkg_spec_dict.keys(): try: self.base.install(pkgspec, reponame=repo_id) except dnf.exceptions.MarkingError: @@ -582,7 +639,9 @@ clear_dir(self.base.conf.destdir) with self.state as state: state.download_status = None + state.state_version = None state.upgrade_status = None + state.upgrade_command = None state.destdir = None state.install_packages = {} state.remove_packages = [] @@ -593,19 +652,46 @@ else: list_logs() + # == resolved_*: do staff after succesful resolvement ===================== + + def resolved_upgrade(self): + """Adjust transaction reasons according to stored values""" + if not self.cli.base.transaction: + return + backward_action = set(dnf.transaction.BACKWARD_ACTIONS + \ + [libdnf.transaction.TransactionItemAction_REINSTALLED]) + forward_actions = set(dnf.transaction.FORWARD_ACTIONS) + + install_packages = self.state.install_packages + remove_packages = self.state.remove_packages + for tsi in self.cli.base.transaction: + if tsi.action in forward_actions: + pkg = tsi.pkg + try: + stored_reason = install_packages[pkg.repo.id][str(pkg)][str(tsi.action)] + if stored_reason != tsi.reason: + tsi.reason = stored_reason + except KeyError: + pass + elif tsi.action in backward_action: + pkg = tsi.pkg + try: + stored_reason = remove_packages[str(pkg)][str(tsi.action)] + if stored_reason != tsi.reason: + tsi.reason = stored_reason + except KeyError: + pass + # == transaction_*: do stuff after a successful transaction =============== def transaction_download(self): - downloads = self.cli.base.transaction.install_set - install_packages = {} - for pkg in downloads: - install_packages.setdefault(pkg.repo.id, []).append(str(pkg)) - remove_packages = [str(pkg) for pkg in self.cli.base.transaction.remove_set] + install_packages, remove_packages = self._get_forward_reverse_pkg_reason_pairs() # Okay! Write out the state so the upgrade can use it. system_ver = dnf.rpm.detect_releasever(self.base.conf.installroot) with self.state as state: state.download_status = 'complete' + state.state_version = STATE_VERSION state.distro_sync = self.opts.distro_sync state.allow_erasing = self.cli.demands.allow_erasing state.gpgcheck = self.base.conf.gpgcheck @@ -622,7 +708,9 @@ state.module_platform_id = self.base.conf.module_platform_id state.enable_disable_repos = self.opts.repos_ed state.destdir = self.base.conf.destdir - logger.info(DOWNLOAD_FINISHED_MSG) + state.upgrade_command = self.opts.command + msg = DOWNLOAD_FINISHED_MSG.format(command=self.opts.command) + logger.info(msg) self.log_status(_("Download finished."), DOWNLOAD_FINISHED_ID) @@ -633,3 +721,13 @@ self.run_clean() if self.opts.tid[0] == "upgrade": reboot() + + +class OfflineUpgradeCommand(SystemUpgradeCommand): + aliases = ('offline-upgrade',) + summary = _("Prepare offline upgrade of the system") + + +class OfflineDistrosyncCommand(SystemUpgradeCommand): + aliases = ('offline-distrosync',) + summary = _("Prepare offline distrosync of the system") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dnf-plugins-extras-4.0.8/tests/test_system_upgrade.py new/dnf-plugins-extras-4.0.9/tests/test_system_upgrade.py --- old/dnf-plugins-extras-4.0.8/tests/test_system_upgrade.py 2019-11-07 11:41:51.000000000 +0100 +++ new/dnf-plugins-extras-4.0.9/tests/test_system_upgrade.py 2020-02-24 15:52:08.000000000 +0100 @@ -259,6 +259,7 @@ self.command = system_upgrade.SystemUpgradeCommand(cli=self.cli) self.command.base.conf.cachedir = os.path.join(self.statedir, "cache") self.command.base.conf.destdir = None + system_upgrade.DEFAULT_DATADIR = os.path.join(self.statedir, 'default_datadir') def tearDown(self): shutil.rmtree(self.statedir) @@ -315,16 +316,26 @@ self.command.configure_reboot() self.assertTrue(self.cli.demands.root_user) - def check_reboot(self, status='complete', lexists=False): + def check_reboot(self, status='complete', lexists=False, command='system-upgrade', + state_command='system-upgrade'): with patch('system_upgrade.os.path.lexists') as lexists_func,\ patch('system_upgrade.DEFAULT_DATADIR', self.DEFAULT_DATADIR): + self.command.state.state_version = 2 self.command.state.download_status = status + self.command.opts = mock.MagicMock() + self.command.opts.command = command + self.command.state.upgrade_command = state_command lexists_func.return_value = lexists self.command.check_reboot() def test_check_reboot_ok(self): self.check_reboot(status='complete', lexists=False) + def test_check_reboot_different_command(self): + with self.assertRaises(CliError): + self.check_reboot(status='complete', lexists=False, command='system-upgrade', + state_command='offline-upgrade') + def test_check_reboot_no_download(self): with self.assertRaises(CliError): self.check_reboot(status=None, lexists=False) @@ -336,7 +347,7 @@ def test_run_prepare(self): with patch('system_upgrade.MAGIC_SYMLINK', self.MAGIC_SYMLINK): self.command.run_prepare() - self.assertEqual(os.readlink(self.MAGIC_SYMLINK), DEFAULT_DATADIR) + self.assertEqual(os.readlink(self.MAGIC_SYMLINK), system_upgrade.DEFAULT_DATADIR) self.assertEqual(self.command.state.upgrade_status, 'ready') @patch('system_upgrade.SystemUpgradeCommand.run_prepare') @@ -366,14 +377,16 @@ class DownloadCommandTestCase(CommandTestCase): def test_pre_configure_download_default(self): self.command.opts = mock.MagicMock() + self.command.opts.destdir = None + self.command.base.conf.destdir = None self.command.pre_configure_download() - self.assertEqual(self.command.base.conf.cachedir, DEFAULT_DATADIR) + self.assertEqual(self.command.base.conf.cachedir, system_upgrade.DEFAULT_DATADIR) def test_pre_configure_download_destdir(self): self.command.opts = mock.MagicMock() - self.command.opts.destdir = "/grape/wine" + self.command.opts.destdir = self.statedir self.command.pre_configure_download() - self.assertEqual(self.command.base.conf.destdir, "/grape/wine") + self.assertEqual(self.command.base.conf.destdir, self.statedir) def test_configure_download(self): self.command.opts = mock.MagicMock() @@ -392,23 +405,56 @@ pkg.repo = repo self.cli.base.transaction.install_set = [pkg] self.command.opts = mock.MagicMock() - self.command.opts.distro_sync = "distro_sync" + self.command.opts.distro_sync = True + self.command.opts.command = "system_upgrade" self.command.opts.repos_ed = [] self.cli.demands.allow_erasing = "allow_erasing" - self.command.base.conf.best = "best" + self.command.base.conf.best = True self.command.base.conf.installroot = "/" self.command.base.conf.releasever = "35" self.command.base.conf.gpgcheck = True - self.command.base.conf.destdir = "/grape/wine" + self.command.opts.destdir = self.statedir self.command.base.conf.install_weak_deps = True self.command.base.conf.module_platform_id = '' + self.command.pre_configure_download() + self.command.transaction_download() + with system_upgrade.State() as state: + self.assertEqual(state.state_version, system_upgrade.STATE_VERSION) + self.assertEqual(state.download_status, "complete") + self.assertEqual(state.distro_sync, True) + self.assertEqual(state.allow_erasing, "allow_erasing") + self.assertEqual(state.best, True) + self.assertEqual(state.destdir, self.statedir) + self.assertEqual(state.upgrade_command, "system_upgrade") + + def test_transaction_download_offline_upgrade(self): + pkg = mock.MagicMock() + repo = mock.MagicMock() + repo.id = 'test' + pkg.name = "kernel" + pkg.repo = repo + self.cli.base.transaction.install_set = [pkg] + self.command.opts = mock.MagicMock() + self.command.opts.distro_sync = True + self.command.opts.command = "offline-upgrade" + self.command.opts.repos_ed = [] + self.cli.demands.allow_erasing = "allow_erasing" + self.command.base.conf.best = True + self.command.base.conf.installroot = "/" + self.command.base.conf.releasever = "35" + self.command.base.conf.gpgcheck = True + self.command.opts.destdir = self.statedir + self.command.base.conf.install_weak_deps = True + self.command.base.conf.module_platform_id = '' + self.command.pre_configure_download() self.command.transaction_download() with system_upgrade.State() as state: self.assertEqual(state.download_status, "complete") - self.assertEqual(state.distro_sync, "distro_sync") + self.assertEqual(state.distro_sync, False) self.assertEqual(state.allow_erasing, "allow_erasing") - self.assertEqual(state.best, "best") - self.assertEqual(state.destdir, "/grape/wine") + self.assertEqual(state.best, True) + self.assertEqual(state.destdir, self.statedir) + self.assertEqual(state.upgrade_command, "offline-upgrade") class UpgradeCommandTestCase(CommandTestCase):