Blame dnf/util.py

Packit Service 21c75c
# util.py
Packit Service 21c75c
# Basic dnf utils.
Packit Service 21c75c
#
Packit Service 21c75c
# Copyright (C) 2012-2016 Red Hat, Inc.
Packit Service 21c75c
#
Packit Service 21c75c
# This copyrighted material is made available to anyone wishing to use,
Packit Service 21c75c
# modify, copy, or redistribute it subject to the terms and conditions of
Packit Service 21c75c
# the GNU General Public License v.2, or (at your option) any later version.
Packit Service 21c75c
# This program is distributed in the hope that it will be useful, but WITHOUT
Packit Service 21c75c
# ANY WARRANTY expressed or implied, including the implied warranties of
Packit Service 21c75c
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
Packit Service 21c75c
# Public License for more details.  You should have received a copy of the
Packit Service 21c75c
# GNU General Public License along with this program; if not, write to the
Packit Service 21c75c
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit Service 21c75c
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
Packit Service 21c75c
# source code or documentation are not subject to the GNU General Public
Packit Service 21c75c
# License and may only be used or replicated with the express permission of
Packit Service 21c75c
# Red Hat, Inc.
Packit Service 21c75c
#
Packit Service 21c75c
Packit Service 21c75c
from __future__ import print_function
Packit Service 21c75c
from __future__ import absolute_import
Packit Service 21c75c
from __future__ import unicode_literals
Packit Service 21c75c
Packit Service 21c75c
from .pycomp import PY3, basestring
Packit Service 21c75c
from dnf.i18n import _, ucd
Packit Service 21c75c
import argparse
Packit Service 21c75c
import dnf
Packit Service 21c75c
import dnf.callback
Packit Service 21c75c
import dnf.const
Packit Service 21c75c
import dnf.pycomp
Packit Service 21c75c
import errno
Packit Service 350571
import functools
Packit Service 350571
import hawkey
Packit Service 21c75c
import itertools
Packit Service 21c75c
import locale
Packit Service 21c75c
import logging
Packit Service 21c75c
import os
Packit Service 21c75c
import pwd
Packit Service 21c75c
import shutil
Packit Service 21c75c
import sys
Packit Service 21c75c
import tempfile
Packit Service 21c75c
import time
Packit Service 21c75c
import libdnf.repo
Packit Service 350571
import libdnf.transaction
Packit Service 21c75c
Packit Service 21c75c
logger = logging.getLogger('dnf')
Packit Service 21c75c
Packit Service 21c75c
MAIN_PROG = argparse.ArgumentParser().prog if argparse.ArgumentParser().prog == "yum" else "dnf"
Packit Service 21c75c
MAIN_PROG_UPPER = MAIN_PROG.upper()
Packit Service 21c75c
Packit Service 21c75c
"""DNF Utilities."""
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def _parse_specs(namespace, values):
Packit Service 21c75c
    """
Packit Service 21c75c
    Categorize :param values list into packages, groups and filenames
Packit Service 21c75c
Packit Service 21c75c
    :param namespace: argparse.Namespace, where specs will be stored
Packit Service 21c75c
    :param values: list of specs, whether packages ('foo') or groups/modules ('@bar')
Packit Service 21c75c
                   or filenames ('*.rmp', 'http://*', ...)
Packit Service 21c75c
Packit Service 21c75c
    To access packages use: specs.pkg_specs,
Packit Service 21c75c
    to access groups use: specs.grp_specs,
Packit Service 21c75c
    to access filenames use: specs.filenames
Packit Service 21c75c
    """
Packit Service 21c75c
Packit Service 21c75c
    setattr(namespace, "filenames", [])
Packit Service 21c75c
    setattr(namespace, "grp_specs", [])
Packit Service 21c75c
    setattr(namespace, "pkg_specs", [])
Packit Service 21c75c
    tmp_set = set()
Packit Service 21c75c
    for value in values:
Packit Service 21c75c
        if value in tmp_set:
Packit Service 21c75c
            continue
Packit Service 21c75c
        tmp_set.add(value)
Packit Service 21c75c
        schemes = dnf.pycomp.urlparse.urlparse(value)[0]
Packit Service 21c75c
        if value.endswith('.rpm'):
Packit Service 21c75c
            namespace.filenames.append(value)
Packit Service 21c75c
        elif schemes and schemes in ('http', 'ftp', 'file', 'https'):
Packit Service 21c75c
            namespace.filenames.append(value)
Packit Service 21c75c
        elif value.startswith('@'):
Packit Service 21c75c
            namespace.grp_specs.append(value[1:])
Packit Service 21c75c
        else:
Packit Service 21c75c
            namespace.pkg_specs.append(value)
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def _urlopen_progress(url, conf, progress=None):
Packit Service 21c75c
    if progress is None:
Packit Service 21c75c
        progress = dnf.callback.NullDownloadProgress()
Packit Service 21c75c
    pload = dnf.repo.RemoteRPMPayload(url, conf, progress)
Packit Service 21c75c
    if os.path.exists(pload.local_path):
Packit Service 21c75c
        return pload.local_path
Packit Service 21c75c
    est_remote_size = sum([pload.download_size])
Packit Service 21c75c
    progress.start(1, est_remote_size)
Packit Service 21c75c
    targets = [pload._librepo_target()]
Packit Service 21c75c
    try:
Packit Service 21c75c
        libdnf.repo.PackageTarget.downloadPackages(libdnf.repo.VectorPPackageTarget(targets), True)
Packit Service 21c75c
    except RuntimeError as e:
Packit Service 21c75c
        if conf.strict:
Packit Service 21c75c
            raise IOError(str(e))
Packit Service 21c75c
        logger.error(str(e))
Packit Service 21c75c
    return pload.local_path
Packit Service 21c75c
Packit Service 21c75c
def _urlopen(url, conf=None, repo=None, mode='w+b', **kwargs):
Packit Service 21c75c
    """
Packit Service 21c75c
    Open the specified absolute url, return a file object
Packit Service 21c75c
    which respects proxy setting even for non-repo downloads
Packit Service 21c75c
    """
Packit Service 21c75c
    if PY3 and 'b' not in mode:
Packit Service 21c75c
        kwargs.setdefault('encoding', 'utf-8')
Packit Service 21c75c
    fo = tempfile.NamedTemporaryFile(mode, **kwargs)
Packit Service 21c75c
Packit Service 21c75c
    try:
Packit Service 21c75c
        if repo:
Packit Service 21c75c
            repo._repo.downloadUrl(url, fo.fileno())
Packit Service 21c75c
        else:
Packit Service 21c75c
            libdnf.repo.Downloader.downloadURL(conf._config if conf else None, url, fo.fileno())
Packit Service 21c75c
    except RuntimeError as e:
Packit Service 21c75c
        raise IOError(str(e))
Packit Service 21c75c
Packit Service 21c75c
    fo.seek(0)
Packit Service 21c75c
    return fo
Packit Service 21c75c
Packit Service 21c75c
def rtrim(s, r):
Packit Service 21c75c
    if s.endswith(r):
Packit Service 21c75c
        s = s[:-len(r)]
Packit Service 21c75c
    return s
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def am_i_root():
Packit Service 21c75c
    # used by ansible (lib/ansible/modules/packaging/os/dnf.py)
Packit Service 21c75c
    return os.geteuid() == 0
Packit Service 21c75c
Packit Service 21c75c
def clear_dir(path):
Packit Service 21c75c
    """Remove all files and dirs under `path`
Packit Service 21c75c
Packit Service 21c75c
    Also see rm_rf()
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    for entry in os.listdir(path):
Packit Service 21c75c
        contained_path = os.path.join(path, entry)
Packit Service 21c75c
        rm_rf(contained_path)
Packit Service 21c75c
Packit Service 21c75c
def ensure_dir(dname):
Packit Service 21c75c
    # used by ansible (lib/ansible/modules/packaging/os/dnf.py)
Packit Service 21c75c
    try:
Packit Service 21c75c
        os.makedirs(dname, mode=0o755)
Packit Service 21c75c
    except OSError as e:
Packit Service 21c75c
        if e.errno != errno.EEXIST or not os.path.isdir(dname):
Packit Service 21c75c
            raise e
Packit Service 21c75c
Packit Service 21c75c
def empty(iterable):
Packit Service 21c75c
    try:
Packit Service 21c75c
        l = len(iterable)
Packit Service 21c75c
    except TypeError:
Packit Service 21c75c
        l = len(list(iterable))
Packit Service 21c75c
    return l == 0
Packit Service 21c75c
Packit Service 21c75c
def first(iterable):
Packit Service 21c75c
    """Returns the first item from an iterable or None if it has no elements."""
Packit Service 21c75c
    it = iter(iterable)
Packit Service 21c75c
    try:
Packit Service 21c75c
        return next(it)
Packit Service 21c75c
    except StopIteration:
Packit Service 21c75c
        return None
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def first_not_none(iterable):
Packit Service 21c75c
    it = iter(iterable)
Packit Service 21c75c
    try:
Packit Service 21c75c
        return next(item for item in it if item is not None)
Packit Service 21c75c
    except StopIteration:
Packit Service 21c75c
        return None
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def file_age(fn):
Packit Service 21c75c
    return time.time() - file_timestamp(fn)
Packit Service 21c75c
Packit Service 21c75c
def file_timestamp(fn):
Packit Service 21c75c
    return os.stat(fn).st_mtime
Packit Service 21c75c
Packit Service 21c75c
def get_effective_login():
Packit Service 21c75c
    try:
Packit Service 21c75c
        return pwd.getpwuid(os.geteuid())[0]
Packit Service 21c75c
    except KeyError:
Packit Service 21c75c
        return "UID: %s" % os.geteuid()
Packit Service 21c75c
Packit Service 21c75c
def get_in(dct, keys, not_found):
Packit Service 21c75c
    """Like dict.get() for nested dicts."""
Packit Service 21c75c
    for k in keys:
Packit Service 21c75c
        dct = dct.get(k)
Packit Service 21c75c
        if dct is None:
Packit Service 21c75c
            return not_found
Packit Service 21c75c
    return dct
Packit Service 21c75c
Packit Service 21c75c
def group_by_filter(fn, iterable):
Packit Service 21c75c
    def splitter(acc, item):
Packit Service 21c75c
        acc[not bool(fn(item))].append(item)
Packit Service 21c75c
        return acc
Packit Service 350571
    return functools.reduce(splitter, iterable, ([], []))
Packit Service 21c75c
Packit Service 21c75c
def insert_if(item, iterable, condition):
Packit Service 21c75c
    """Insert an item into an iterable by a condition."""
Packit Service 21c75c
    for original_item in iterable:
Packit Service 21c75c
        if condition(original_item):
Packit Service 21c75c
            yield item
Packit Service 21c75c
        yield original_item
Packit Service 21c75c
Packit Service 21c75c
def is_exhausted(iterator):
Packit Service 21c75c
    """Test whether an iterator is exhausted."""
Packit Service 21c75c
    try:
Packit Service 21c75c
        next(iterator)
Packit Service 21c75c
    except StopIteration:
Packit Service 21c75c
        return True
Packit Service 21c75c
    else:
Packit Service 21c75c
        return False
Packit Service 21c75c
Packit Service 21c75c
def is_glob_pattern(pattern):
Packit Service 21c75c
    if is_string_type(pattern):
Packit Service 21c75c
        pattern = [pattern]
Packit Service 21c75c
    return (isinstance(pattern, list) and any(set(p) & set("*[?") for p in pattern))
Packit Service 21c75c
Packit Service 21c75c
def is_string_type(obj):
Packit Service 21c75c
    if PY3:
Packit Service 21c75c
        return isinstance(obj, str)
Packit Service 21c75c
    else:
Packit Service 21c75c
        return isinstance(obj, basestring)
Packit Service 21c75c
Packit Service 21c75c
def lazyattr(attrname):
Packit Service 21c75c
    """Decorator to get lazy attribute initialization.
Packit Service 21c75c
Packit Service 21c75c
    Composes with @property. Force reinitialization by deleting the <attrname>.
Packit Service 21c75c
    """
Packit Service 21c75c
    def get_decorated(fn):
Packit Service 21c75c
        def cached_getter(obj):
Packit Service 21c75c
            try:
Packit Service 21c75c
                return getattr(obj, attrname)
Packit Service 21c75c
            except AttributeError:
Packit Service 21c75c
                val = fn(obj)
Packit Service 21c75c
                setattr(obj, attrname, val)
Packit Service 21c75c
                return val
Packit Service 21c75c
        return cached_getter
Packit Service 21c75c
    return get_decorated
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def mapall(fn, *seq):
Packit Service 21c75c
    """Like functools.map(), but return a list instead of an iterator.
Packit Service 21c75c
Packit Service 21c75c
    This means all side effects of fn take place even without iterating the
Packit Service 21c75c
    result.
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    return list(map(fn, *seq))
Packit Service 21c75c
Packit Service 21c75c
def normalize_time(timestamp):
Packit Service 21c75c
    """Convert time into locale aware datetime string object."""
Packit Service 21c75c
    t = time.strftime("%c", time.localtime(timestamp))
Packit Service 21c75c
    if not dnf.pycomp.PY3:
Packit Service 21c75c
        current_locale_setting = locale.getlocale()[1]
Packit Service 21c75c
        if current_locale_setting:
Packit Service 21c75c
            t = t.decode(current_locale_setting)
Packit Service 21c75c
    return t
Packit Service 21c75c
Packit Service 21c75c
def on_ac_power():
Packit Service 21c75c
    """Decide whether we are on line power.
Packit Service 21c75c
Packit Service 21c75c
    Returns True if we are on line power, False if not, None if it can not be
Packit Service 21c75c
    decided.
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    try:
Packit Service 21c75c
        with open("/sys/class/power_supply/AC/online") as ac_status:
Packit Service 21c75c
            data = ac_status.read()
Packit Service 21c75c
            return int(data) == 1
Packit Service 21c75c
    except (IOError, ValueError):
Packit Service 21c75c
        return None
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def on_metered_connection():
Packit Service 21c75c
    """Decide whether we are on metered connection.
Packit Service 21c75c
Packit Service 21c75c
    Returns:
Packit Service 21c75c
      True: if on metered connection
Packit Service 21c75c
      False: if not
Packit Service 21c75c
      None: if it can not be decided
Packit Service 21c75c
    """
Packit Service 21c75c
    try:
Packit Service 21c75c
        import dbus
Packit Service 21c75c
    except ImportError:
Packit Service 21c75c
        return None
Packit Service 21c75c
    try:
Packit Service 21c75c
        bus = dbus.SystemBus()
Packit Service 21c75c
        proxy = bus.get_object("org.freedesktop.NetworkManager",
Packit Service 21c75c
                               "/org/freedesktop/NetworkManager")
Packit Service 21c75c
        iface = dbus.Interface(proxy, "org.freedesktop.DBus.Properties")
Packit Service 21c75c
        metered = iface.Get("org.freedesktop.NetworkManager", "Metered")
Packit Service 21c75c
    except dbus.DBusException:
Packit Service 21c75c
        return None
Packit Service 21c75c
    if metered == 0: # NM_METERED_UNKNOWN
Packit Service 21c75c
        return None
Packit Service 21c75c
    elif metered in (1, 3): # NM_METERED_YES, NM_METERED_GUESS_YES
Packit Service 21c75c
        return True
Packit Service 21c75c
    elif metered in (2, 4): # NM_METERED_NO, NM_METERED_GUESS_NO
Packit Service 21c75c
        return False
Packit Service 21c75c
    else: # Something undocumented (at least at this moment)
Packit Service 21c75c
        raise ValueError("Unknown value for metered property: %r", metered)
Packit Service 21c75c
Packit Service 21c75c
def partition(pred, iterable):
Packit Service 21c75c
    """Use a predicate to partition entries into false entries and true entries.
Packit Service 21c75c
Packit Service 21c75c
    Credit: Python library itertools' documentation.
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    t1, t2 = itertools.tee(iterable)
Packit Service 21c75c
    return dnf.pycomp.filterfalse(pred, t1), filter(pred, t2)
Packit Service 21c75c
Packit Service 21c75c
def rm_rf(path):
Packit Service 21c75c
    try:
Packit Service 21c75c
        shutil.rmtree(path)
Packit Service 21c75c
    except OSError:
Packit Service 21c75c
        pass
Packit Service 21c75c
Packit Service 21c75c
def split_by(iterable, condition):
Packit Service 21c75c
    """Split an iterable into tuples by a condition.
Packit Service 21c75c
Packit Service 21c75c
    Inserts a separator before each item which meets the condition and then
Packit Service 21c75c
    cuts the iterable by these separators.
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    separator = object()  # A unique object.
Packit Service 21c75c
    # Create a function returning tuple of objects before the separator.
Packit Service 21c75c
    def next_subsequence(it):
Packit Service 21c75c
        return tuple(itertools.takewhile(lambda e: e != separator, it))
Packit Service 21c75c
Packit Service 21c75c
    # Mark each place where the condition is met by the separator.
Packit Service 21c75c
    marked = insert_if(separator, iterable, condition)
Packit Service 21c75c
Packit Service 21c75c
    # The 1st subsequence may be empty if the 1st item meets the condition.
Packit Service 21c75c
    yield next_subsequence(marked)
Packit Service 21c75c
Packit Service 21c75c
    while True:
Packit Service 21c75c
        subsequence = next_subsequence(marked)
Packit Service 21c75c
        if not subsequence:
Packit Service 21c75c
            break
Packit Service 21c75c
        yield subsequence
Packit Service 21c75c
Packit Service 21c75c
def strip_prefix(s, prefix):
Packit Service 21c75c
    if s.startswith(prefix):
Packit Service 21c75c
        return s[len(prefix):]
Packit Service 21c75c
    return None
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def touch(path, no_create=False):
Packit Service 21c75c
    """Create an empty file if it doesn't exist or bump it's timestamps.
Packit Service 21c75c
Packit Service 21c75c
    If no_create is True only bumps the timestamps.
Packit Service 21c75c
    """
Packit Service 21c75c
    if no_create or os.access(path, os.F_OK):
Packit Service 21c75c
        return os.utime(path, None)
Packit Service 21c75c
    with open(path, 'a'):
Packit Service 21c75c
        pass
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def _terminal_messenger(tp='write', msg="", out=sys.stdout):
Packit Service 21c75c
    try:
Packit Service 21c75c
        if tp == 'write':
Packit Service 21c75c
            out.write(msg)
Packit Service 21c75c
        elif tp == 'flush':
Packit Service 21c75c
            out.flush()
Packit Service 21c75c
        elif tp == 'write_flush':
Packit Service 21c75c
            out.write(msg)
Packit Service 21c75c
            out.flush()
Packit Service 21c75c
        elif tp == 'print':
Packit Service 21c75c
            print(msg, file=out)
Packit Service 21c75c
        else:
Packit Service 21c75c
            raise ValueError('Unsupported type: ' + tp)
Packit Service 21c75c
    except IOError as e:
Packit Service 21c75c
        logger.critical('{}: {}'.format(type(e).__name__, ucd(e)))
Packit Service 21c75c
        pass
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def _format_resolve_problems(resolve_problems):
Packit Service 21c75c
    """
Packit Service 21c75c
    Format string about problems in resolve
Packit Service 21c75c
Packit Service 21c75c
    :param resolve_problems: list with list of strings (output of goal.problem_rules())
Packit Service 21c75c
    :return: string
Packit Service 21c75c
    """
Packit Service 21c75c
    msg = ""
Packit Service 21c75c
    count_problems = (len(resolve_problems) > 1)
Packit Service 21c75c
    for i, rs in enumerate(resolve_problems, start=1):
Packit Service 21c75c
        if count_problems:
Packit Service 21c75c
            msg += "\n " + _("Problem") + " %d: " % i
Packit Service 21c75c
        else:
Packit Service 21c75c
            msg += "\n " + _("Problem") + ": "
Packit Service 21c75c
        msg += "\n  - ".join(rs)
Packit Service 21c75c
    return msg
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def _te_nevra(te):
Packit Service 21c75c
    nevra = te.N() + '-'
Packit Service 21c75c
    if te.E() is not None and te.E() != '0':
Packit Service 21c75c
        nevra += te.E() + ':'
Packit Service 21c75c
    return nevra + te.V() + '-' + te.R() + '.' + te.A()
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def _log_rpm_trans_with_swdb(rpm_transaction, swdb_transaction):
Packit Service 21c75c
    logger.debug("Logging transaction elements")
Packit Service 21c75c
    for rpm_el in rpm_transaction:
Packit Service 21c75c
        tsi = rpm_el.Key()
Packit Service 21c75c
        tsi_state = None
Packit Service 21c75c
        if tsi is not None:
Packit Service 21c75c
            tsi_state = tsi.state
Packit Service 21c75c
        msg = "RPM element: '{}', Key(): '{}', Key state: '{}', Failed() '{}': ".format(
Packit Service 21c75c
            _te_nevra(rpm_el), tsi, tsi_state, rpm_el.Failed())
Packit Service 21c75c
        logger.debug(msg)
Packit Service 21c75c
    for tsi in swdb_transaction:
Packit Service 21c75c
        msg = "SWDB element: '{}', State: '{}', Action: '{}', From repo: '{}', Reason: '{}', " \
Packit Service 21c75c
              "Get reason: '{}'".format(str(tsi), tsi.state, tsi.action, tsi.from_repo, tsi.reason,
Packit Service 21c75c
                                        tsi.get_reason())
Packit Service 21c75c
        logger.debug(msg)
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
def _sync_rpm_trans_with_swdb(rpm_transaction, swdb_transaction):
Packit Service 21c75c
    revert_actions = {libdnf.transaction.TransactionItemAction_DOWNGRADED,
Packit Service 21c75c
                      libdnf.transaction.TransactionItemAction_OBSOLETED,
Packit Service 21c75c
                      libdnf.transaction.TransactionItemAction_REMOVE,
Packit Service 21c75c
                      libdnf.transaction.TransactionItemAction_UPGRADED,
Packit Service 21c75c
                      libdnf.transaction.TransactionItemAction_REINSTALLED}
Packit Service 21c75c
    cached_tsi = [tsi for tsi in swdb_transaction]
Packit Service 21c75c
    el_not_found = False
Packit Service 21c75c
    error = False
Packit Service 21c75c
    for rpm_el in rpm_transaction:
Packit Service 21c75c
        te_nevra = _te_nevra(rpm_el)
Packit Service 21c75c
        tsi = rpm_el.Key()
Packit Service 21c75c
        if tsi is None or not hasattr(tsi, "pkg"):
Packit Service 21c75c
            for tsi_candidate in cached_tsi:
Packit Service 21c75c
                if tsi_candidate.state != libdnf.transaction.TransactionItemState_UNKNOWN:
Packit Service 21c75c
                    continue
Packit Service 21c75c
                if tsi_candidate.action not in revert_actions:
Packit Service 21c75c
                    continue
Packit Service 21c75c
                if str(tsi_candidate) == te_nevra:
Packit Service 21c75c
                    tsi = tsi_candidate
Packit Service 21c75c
                    break
Packit Service 21c75c
        if tsi is None or not hasattr(tsi, "pkg"):
Packit Service 21c75c
            logger.critical(_("TransactionItem not found for key: {}").format(te_nevra))
Packit Service 21c75c
            el_not_found = True
Packit Service 21c75c
            continue
Packit Service 21c75c
        if rpm_el.Failed():
Packit Service 21c75c
            tsi.state = libdnf.transaction.TransactionItemState_ERROR
Packit Service 21c75c
            error = True
Packit Service 21c75c
        else:
Packit Service 21c75c
            tsi.state = libdnf.transaction.TransactionItemState_DONE
Packit Service 21c75c
    for tsi in cached_tsi:
Packit Service 21c75c
        if tsi.state == libdnf.transaction.TransactionItemState_UNKNOWN:
Packit Service 21c75c
            logger.critical(_("TransactionSWDBItem not found for key: {}").format(str(tsi)))
Packit Service 21c75c
            el_not_found = True
Packit Service 21c75c
    if error:
Packit Service 21c75c
        logger.debug(_('Errors occurred during transaction.'))
Packit Service 21c75c
    if el_not_found:
Packit Service 21c75c
        _log_rpm_trans_with_swdb(rpm_transaction, cached_tsi)
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
class tmpdir(object):
Packit Service 21c75c
    # used by subscription-manager (src/dnf-plugins/product-id.py)
Packit Service 21c75c
    def __init__(self):
Packit Service 21c75c
        prefix = '%s-' % dnf.const.PREFIX
Packit Service 21c75c
        self.path = tempfile.mkdtemp(prefix=prefix)
Packit Service 21c75c
Packit Service 21c75c
    def __enter__(self):
Packit Service 21c75c
        return self.path
Packit Service 21c75c
Packit Service 21c75c
    def __exit__(self, exc_type, exc_value, traceback):
Packit Service 21c75c
        rm_rf(self.path)
Packit Service 21c75c
Packit Service 21c75c
class Bunch(dict):
Packit Service 21c75c
    """Dictionary with attribute accessing syntax.
Packit Service 21c75c
Packit Service 21c75c
    In DNF, prefer using this over dnf.yum.misc.GenericHolder.
Packit Service 21c75c
Packit Service 21c75c
    Credit: Alex Martelli, Doug Hudgeon
Packit Service 21c75c
Packit Service 21c75c
    """
Packit Service 21c75c
    def __init__(self, *args, **kwds):
Packit Service 21c75c
         super(Bunch, self).__init__(*args, **kwds)
Packit Service 21c75c
         self.__dict__ = self
Packit Service 21c75c
Packit Service 21c75c
    def __hash__(self):
Packit Service 21c75c
        return id(self)
Packit Service 21c75c
Packit Service 21c75c
Packit Service 21c75c
class MultiCallList(list):
Packit Service 21c75c
    def __init__(self, iterable):
Packit Service 21c75c
        super(MultiCallList, self).__init__()
Packit Service 21c75c
        self.extend(iterable)
Packit Service 21c75c
Packit Service 21c75c
    def __getattr__(self, what):
Packit Service 21c75c
        def fn(*args, **kwargs):
Packit Service 21c75c
            def call_what(v):
Packit Service 21c75c
                method = getattr(v, what)
Packit Service 21c75c
                return method(*args, **kwargs)
Packit Service 21c75c
            return list(map(call_what, self))
Packit Service 21c75c
        return fn
Packit Service 21c75c
Packit Service 21c75c
    def __setattr__(self, what, val):
Packit Service 21c75c
        def setter(item):
Packit Service 21c75c
            setattr(item, what, val)
Packit Service 21c75c
        return list(map(setter, self))
Packit Service 350571
Packit Service 350571
Packit Service 350571
def _make_lists(transaction):
Packit Service 350571
    b = Bunch({
Packit Service 350571
        'downgraded': [],
Packit Service 350571
        'erased': [],
Packit Service 350571
        'erased_clean': [],
Packit Service 350571
        'erased_dep': [],
Packit Service 350571
        'installed': [],
Packit Service 350571
        'installed_group': [],
Packit Service 350571
        'installed_dep': [],
Packit Service 350571
        'installed_weak': [],
Packit Service 350571
        'reinstalled': [],
Packit Service 350571
        'upgraded': [],
Packit Service 350571
        'failed': [],
Packit Service 350571
    })
Packit Service 350571
Packit Service 350571
    for tsi in transaction:
Packit Service 350571
        if tsi.state == libdnf.transaction.TransactionItemState_ERROR:
Packit Service 350571
            b.failed.append(tsi)
Packit Service 350571
        elif tsi.action == libdnf.transaction.TransactionItemAction_DOWNGRADE:
Packit Service 350571
            b.downgraded.append(tsi)
Packit Service 350571
        elif tsi.action == libdnf.transaction.TransactionItemAction_INSTALL:
Packit Service 350571
            if tsi.reason == libdnf.transaction.TransactionItemReason_GROUP:
Packit Service 350571
                b.installed_group.append(tsi)
Packit Service 350571
            elif tsi.reason == libdnf.transaction.TransactionItemReason_DEPENDENCY:
Packit Service 350571
                b.installed_dep.append(tsi)
Packit Service 350571
            elif tsi.reason == libdnf.transaction.TransactionItemReason_WEAK_DEPENDENCY:
Packit Service 350571
                b.installed_weak.append(tsi)
Packit Service 350571
            else:
Packit Service 350571
                # TransactionItemReason_USER
Packit Service 350571
                b.installed.append(tsi)
Packit Service 350571
        elif tsi.action == libdnf.transaction.TransactionItemAction_REINSTALL:
Packit Service 350571
            b.reinstalled.append(tsi)
Packit Service 350571
        elif tsi.action == libdnf.transaction.TransactionItemAction_REMOVE:
Packit Service 350571
            if tsi.reason == libdnf.transaction.TransactionItemReason_CLEAN:
Packit Service 350571
                b.erased_clean.append(tsi)
Packit Service 350571
            elif tsi.reason == libdnf.transaction.TransactionItemReason_DEPENDENCY:
Packit Service 350571
                b.erased_dep.append(tsi)
Packit Service 350571
            else:
Packit Service 350571
                b.erased.append(tsi)
Packit Service 350571
        elif tsi.action == libdnf.transaction.TransactionItemAction_UPGRADE:
Packit Service 350571
            b.upgraded.append(tsi)
Packit Service 350571
Packit Service 350571
    return b
Packit Service 350571
Packit Service 350571
Packit Service 350571
def _post_transaction_output(base, transaction, action_callback):
Packit Service 350571
    """Returns a human-readable summary of the results of the
Packit Service 350571
    transaction.
Packit Service 350571
Packit Service 350571
    :param action_callback: function generating output for specific action. It
Packit Service 350571
       takes two parameters - action as a string and list of affected packages for
Packit Service 350571
       this action
Packit Service 350571
    :return: a list of lines containing a human-readable summary of the
Packit Service 350571
       results of the transaction
Packit Service 350571
    """
Packit Service 350571
    def _tsi_or_pkg_nevra_cmp(item1, item2):
Packit Service 350571
        """Compares two transaction items or packages by nevra.
Packit Service 350571
           Used as a fallback when tsi does not contain package object.
Packit Service 350571
        """
Packit Service 350571
        ret = (item1.name > item2.name) - (item1.name < item2.name)
Packit Service 350571
        if ret != 0:
Packit Service 350571
            return ret
Packit Service 350571
        nevra1 = hawkey.NEVRA(name=item1.name, epoch=item1.epoch, version=item1.version,
Packit Service 350571
                              release=item1.release, arch=item1.arch)
Packit Service 350571
        nevra2 = hawkey.NEVRA(name=item2.name, epoch=item2.epoch, version=item2.version,
Packit Service 350571
                              release=item2.release, arch=item2.arch)
Packit Service 350571
        ret = nevra1.evr_cmp(nevra2, base.sack)
Packit Service 350571
        if ret != 0:
Packit Service 350571
            return ret
Packit Service 350571
        return (item1.arch > item2.arch) - (item1.arch < item2.arch)
Packit Service 350571
Packit Service 350571
    list_bunch = dnf.util._make_lists(transaction)
Packit Service 350571
Packit Service 350571
    skipped_conflicts, skipped_broken = base._skipped_packages(
Packit Service 350571
        report_problems=False, transaction=transaction)
Packit Service 350571
    skipped = skipped_conflicts.union(skipped_broken)
Packit Service 350571
Packit Service 350571
    out = []
Packit Service 350571
    for (action, tsis) in [(_('Upgraded'), list_bunch.upgraded),
Packit Service 350571
                           (_('Downgraded'), list_bunch.downgraded),
Packit Service 350571
                           (_('Installed'), list_bunch.installed +
Packit Service 350571
                            list_bunch.installed_group +
Packit Service 350571
                            list_bunch.installed_weak +
Packit Service 350571
                            list_bunch.installed_dep),
Packit Service 350571
                           (_('Reinstalled'), list_bunch.reinstalled),
Packit Service 350571
                           (_('Skipped'), skipped),
Packit Service 350571
                           (_('Removed'), list_bunch.erased +
Packit Service 350571
                               list_bunch.erased_dep +
Packit Service 350571
                               list_bunch.erased_clean),
Packit Service 350571
                           (_('Failed'), list_bunch.failed)]:
Packit Service 350571
        out.extend(action_callback(
Packit Service 350571
            action, sorted(tsis, key=functools.cmp_to_key(_tsi_or_pkg_nevra_cmp))))
Packit Service 350571
Packit Service 350571
    return out