135 lines
5.4 KiB
Python
135 lines
5.4 KiB
Python
|
#
|
||
|
# Copyright (C) 2020 Red Hat, Inc.
|
||
|
#
|
||
|
# This copyrighted material is made available to anyone wishing to use,
|
||
|
# modify, copy, or redistribute it subject to the terms and conditions of
|
||
|
# the GNU General Public License v.2, or (at your option) any later version.
|
||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||
|
# ANY WARRANTY expressed or implied, including the implied warranties of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||
|
# Public License for more details. You should have received a copy of the
|
||
|
# GNU General Public License along with this program; if not, write to the
|
||
|
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||
|
# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
|
||
|
# source code or documentation are not subject to the GNU General Public
|
||
|
# License and may only be used or replicated with the express permission of
|
||
|
# Red Hat, Inc.
|
||
|
#
|
||
|
import dnf.transaction
|
||
|
import dnf.callback
|
||
|
|
||
|
from pyanaconda.anaconda_loggers import get_module_logger
|
||
|
from pyanaconda.core.i18n import _
|
||
|
from pyanaconda.modules.common.errors.installation import PayloadInstallationError
|
||
|
|
||
|
log = get_module_logger(__name__)
|
||
|
|
||
|
__all__ = ["process_transaction_progress", "TransactionProgress"]
|
||
|
|
||
|
|
||
|
def process_transaction_progress(queue, callback):
|
||
|
"""Process the transaction progress.
|
||
|
|
||
|
When the installation works correctly it will end by 'quit' token.
|
||
|
|
||
|
:param queue: a process shared queue
|
||
|
:param callback: a callback for progress reporting
|
||
|
:raise PayloadInstallationError: if the transaction fails
|
||
|
"""
|
||
|
(token, msg) = queue.get()
|
||
|
|
||
|
while token:
|
||
|
if token == 'install':
|
||
|
callback(_("Installing {}").format(msg))
|
||
|
elif token == 'configure':
|
||
|
callback(_("Configuring {}").format(msg))
|
||
|
elif token == 'log':
|
||
|
log.info(msg)
|
||
|
elif token == 'post':
|
||
|
callback(_("Performing post-installation setup tasks"))
|
||
|
elif token == 'quit':
|
||
|
log.info(msg)
|
||
|
break # Installation finished successfully
|
||
|
elif token == 'error':
|
||
|
log.error(msg)
|
||
|
raise PayloadInstallationError("An error occurred during the transaction: " + msg)
|
||
|
|
||
|
(token, msg) = queue.get()
|
||
|
|
||
|
|
||
|
class TransactionProgress(dnf.callback.TransactionProgress):
|
||
|
"""The class for receiving information about an ongoing transaction."""
|
||
|
|
||
|
def __init__(self, queue):
|
||
|
"""Create a new instance.
|
||
|
|
||
|
:param queue: a process shared queue
|
||
|
"""
|
||
|
super().__init__()
|
||
|
self._queue = queue
|
||
|
self._last_ts = None
|
||
|
self._postinst_phase = False
|
||
|
self.cnt = 0
|
||
|
|
||
|
def progress(self, package, action, ti_done, ti_total, ts_done, ts_total):
|
||
|
"""Report ongoing progress on the given transaction item.
|
||
|
|
||
|
:param package: the DNF package object
|
||
|
:param action: the ID of the current action
|
||
|
:param ti_done: the number of processed bytes of the transaction item
|
||
|
:param ti_total: the total number of bytes of the transaction item
|
||
|
:param ts_done: the number of actions processed in the whole transaction
|
||
|
:param ts_total: the total number of actions in the whole transaction
|
||
|
"""
|
||
|
# Process DNF actions, communicating with anaconda via the queue
|
||
|
# A normal installation consists of 'install' messages followed by
|
||
|
# the 'post' message.
|
||
|
if action == dnf.transaction.PKG_INSTALL and ti_done == 0:
|
||
|
# do not report same package twice
|
||
|
if self._last_ts == ts_done:
|
||
|
return
|
||
|
self._last_ts = ts_done
|
||
|
|
||
|
msg = '%s.%s (%d/%d)' % \
|
||
|
(package.name, package.arch, ts_done, ts_total)
|
||
|
self.cnt += 1
|
||
|
self._queue.put(('install', msg))
|
||
|
|
||
|
# Log the exact package nevra, build time and checksum
|
||
|
nevra = "%s-%s.%s" % (package.name, package.evr, package.arch)
|
||
|
log_msg = "Installed: %s %s %s" % (nevra, package.buildtime, package.returnIdSum()[1])
|
||
|
self._queue.put(('log', log_msg))
|
||
|
|
||
|
elif action == dnf.transaction.TRANS_POST:
|
||
|
self._queue.put(('post', None))
|
||
|
log_msg = "Post installation setup phase started."
|
||
|
self._queue.put(('log', log_msg))
|
||
|
self._postinst_phase = True
|
||
|
|
||
|
elif action == dnf.transaction.PKG_SCRIPTLET:
|
||
|
# Log the exact package nevra, build time and checksum
|
||
|
nevra = "%s-%s.%s" % (package.name, package.evr, package.arch)
|
||
|
log_msg = "Configuring (running scriptlet for): %s %s %s" % (nevra, package.buildtime,
|
||
|
package.returnIdSum()[1])
|
||
|
self._queue.put(('log', log_msg))
|
||
|
|
||
|
# only show progress in UI for post-installation scriptlets
|
||
|
if self._postinst_phase:
|
||
|
msg = '%s.%s' % (package.name, package.arch)
|
||
|
self._queue.put(('configure', msg))
|
||
|
|
||
|
def error(self, message):
|
||
|
"""Report an error that occurred during the transaction.
|
||
|
|
||
|
:param message: a string that describes the error
|
||
|
"""
|
||
|
self._queue.put(('error', message))
|
||
|
|
||
|
def quit(self, message):
|
||
|
"""Report the end of the transaction and close the queue.
|
||
|
|
||
|
:param message: the reason why the transaction ended
|
||
|
"""
|
||
|
self._queue.put(('quit', message))
|
||
|
self._queue.close()
|