|
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 |
cfdb81 |
import functools
|
|
Packit Service |
cfdb81 |
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 |
cfdb81 |
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 |
cfdb81 |
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 |
cfdb81 |
|
|
Packit Service |
cfdb81 |
|
|
Packit Service |
cfdb81 |
def _make_lists(transaction):
|
|
Packit Service |
cfdb81 |
b = Bunch({
|
|
Packit Service |
cfdb81 |
'downgraded': [],
|
|
Packit Service |
cfdb81 |
'erased': [],
|
|
Packit Service |
cfdb81 |
'erased_clean': [],
|
|
Packit Service |
cfdb81 |
'erased_dep': [],
|
|
Packit Service |
cfdb81 |
'installed': [],
|
|
Packit Service |
cfdb81 |
'installed_group': [],
|
|
Packit Service |
cfdb81 |
'installed_dep': [],
|
|
Packit Service |
cfdb81 |
'installed_weak': [],
|
|
Packit Service |
cfdb81 |
'reinstalled': [],
|
|
Packit Service |
cfdb81 |
'upgraded': [],
|
|
Packit Service |
cfdb81 |
'failed': [],
|
|
Packit Service |
cfdb81 |
})
|
|
Packit Service |
cfdb81 |
|
|
Packit Service |
cfdb81 |
for tsi in transaction:
|
|
Packit Service |
cfdb81 |
if tsi.state == libdnf.transaction.TransactionItemState_ERROR:
|
|
Packit Service |
cfdb81 |
b.failed.append(tsi)
|
|
Packit Service |
cfdb81 |
elif tsi.action == libdnf.transaction.TransactionItemAction_DOWNGRADE:
|
|
Packit Service |
cfdb81 |
b.downgraded.append(tsi)
|
|
Packit Service |
cfdb81 |
elif tsi.action == libdnf.transaction.TransactionItemAction_INSTALL:
|
|
Packit Service |
cfdb81 |
if tsi.reason == libdnf.transaction.TransactionItemReason_GROUP:
|
|
Packit Service |
cfdb81 |
b.installed_group.append(tsi)
|
|
Packit Service |
cfdb81 |
elif tsi.reason == libdnf.transaction.TransactionItemReason_DEPENDENCY:
|
|
Packit Service |
cfdb81 |
b.installed_dep.append(tsi)
|
|
Packit Service |
cfdb81 |
elif tsi.reason == libdnf.transaction.TransactionItemReason_WEAK_DEPENDENCY:
|
|
Packit Service |
cfdb81 |
b.installed_weak.append(tsi)
|
|
Packit Service |
cfdb81 |
else:
|
|
Packit Service |
cfdb81 |
# TransactionItemReason_USER
|
|
Packit Service |
cfdb81 |
b.installed.append(tsi)
|
|
Packit Service |
cfdb81 |
elif tsi.action == libdnf.transaction.TransactionItemAction_REINSTALL:
|
|
Packit Service |
cfdb81 |
b.reinstalled.append(tsi)
|
|
Packit Service |
cfdb81 |
elif tsi.action == libdnf.transaction.TransactionItemAction_REMOVE:
|
|
Packit Service |
cfdb81 |
if tsi.reason == libdnf.transaction.TransactionItemReason_CLEAN:
|
|
Packit Service |
cfdb81 |
b.erased_clean.append(tsi)
|
|
Packit Service |
cfdb81 |
elif tsi.reason == libdnf.transaction.TransactionItemReason_DEPENDENCY:
|
|
Packit Service |
cfdb81 |
b.erased_dep.append(tsi)
|
|
Packit Service |
cfdb81 |
else:
|
|
Packit Service |
cfdb81 |
b.erased.append(tsi)
|
|
Packit Service |
cfdb81 |
elif tsi.action == libdnf.transaction.TransactionItemAction_UPGRADE:
|
|
Packit Service |
cfdb81 |
b.upgraded.append(tsi)
|
|
Packit Service |
cfdb81 |
|
|
Packit Service |
cfdb81 |
return b
|
|
Packit Service |
cfdb81 |
|
|
Packit Service |
cfdb81 |
|
|
Packit Service |
cfdb81 |
def _post_transaction_output(base, transaction, action_callback):
|
|
Packit Service |
cfdb81 |
"""Returns a human-readable summary of the results of the
|
|
Packit Service |
cfdb81 |
transaction.
|
|
Packit Service |
cfdb81 |
|
|
Packit Service |
cfdb81 |
:param action_callback: function generating output for specific action. It
|
|
Packit Service |
cfdb81 |
takes two parameters - action as a string and list of affected packages for
|
|
Packit Service |
cfdb81 |
this action
|
|
Packit Service |
cfdb81 |
:return: a list of lines containing a human-readable summary of the
|
|
Packit Service |
cfdb81 |
results of the transaction
|
|
Packit Service |
cfdb81 |
"""
|
|
Packit Service |
cfdb81 |
def _tsi_or_pkg_nevra_cmp(item1, item2):
|
|
Packit Service |
cfdb81 |
"""Compares two transaction items or packages by nevra.
|
|
Packit Service |
cfdb81 |
Used as a fallback when tsi does not contain package object.
|
|
Packit Service |
cfdb81 |
"""
|
|
Packit Service |
cfdb81 |
ret = (item1.name > item2.name) - (item1.name < item2.name)
|
|
Packit Service |
cfdb81 |
if ret != 0:
|
|
Packit Service |
cfdb81 |
return ret
|
|
Packit Service |
cfdb81 |
nevra1 = hawkey.NEVRA(name=item1.name, epoch=item1.epoch, version=item1.version,
|
|
Packit Service |
cfdb81 |
release=item1.release, arch=item1.arch)
|
|
Packit Service |
cfdb81 |
nevra2 = hawkey.NEVRA(name=item2.name, epoch=item2.epoch, version=item2.version,
|
|
Packit Service |
cfdb81 |
release=item2.release, arch=item2.arch)
|
|
Packit Service |
cfdb81 |
ret = nevra1.evr_cmp(nevra2, base.sack)
|
|
Packit Service |
cfdb81 |
if ret != 0:
|
|
Packit Service |
cfdb81 |
return ret
|
|
Packit Service |
cfdb81 |
return (item1.arch > item2.arch) - (item1.arch < item2.arch)
|
|
Packit Service |
cfdb81 |
|
|
Packit Service |
cfdb81 |
list_bunch = dnf.util._make_lists(transaction)
|
|
Packit Service |
cfdb81 |
|
|
Packit Service |
cfdb81 |
skipped_conflicts, skipped_broken = base._skipped_packages(
|
|
Packit Service |
cfdb81 |
report_problems=False, transaction=transaction)
|
|
Packit Service |
cfdb81 |
skipped = skipped_conflicts.union(skipped_broken)
|
|
Packit Service |
cfdb81 |
|
|
Packit Service |
cfdb81 |
out = []
|
|
Packit Service |
cfdb81 |
for (action, tsis) in [(_('Upgraded'), list_bunch.upgraded),
|
|
Packit Service |
cfdb81 |
(_('Downgraded'), list_bunch.downgraded),
|
|
Packit Service |
cfdb81 |
(_('Installed'), list_bunch.installed +
|
|
Packit Service |
cfdb81 |
list_bunch.installed_group +
|
|
Packit Service |
cfdb81 |
list_bunch.installed_weak +
|
|
Packit Service |
cfdb81 |
list_bunch.installed_dep),
|
|
Packit Service |
cfdb81 |
(_('Reinstalled'), list_bunch.reinstalled),
|
|
Packit Service |
cfdb81 |
(_('Skipped'), skipped),
|
|
Packit Service |
cfdb81 |
(_('Removed'), list_bunch.erased +
|
|
Packit Service |
cfdb81 |
list_bunch.erased_dep +
|
|
Packit Service |
cfdb81 |
list_bunch.erased_clean),
|
|
Packit Service |
cfdb81 |
(_('Failed'), list_bunch.failed)]:
|
|
Packit Service |
cfdb81 |
out.extend(action_callback(
|
|
Packit Service |
cfdb81 |
action, sorted(tsis, key=functools.cmp_to_key(_tsi_or_pkg_nevra_cmp))))
|
|
Packit Service |
cfdb81 |
|
|
Packit Service |
cfdb81 |
return out
|