Mini Shell

Direktori : /usr/lib64/python3.6/site-packages/pyanaconda/payload/dnf/
Upload File :
Current File : //usr/lib64/python3.6/site-packages/pyanaconda/payload/dnf/utils.py

#
# 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 os
import operator
import time

from blivet.size import Size

from pyanaconda.anaconda_loggers import get_packaging_logger
from pyanaconda.payload.dnf.transaction_progress import TransactionProgress
from pyanaconda.progress import progressQ
from pyanaconda.core import util
from pyanaconda.core.configuration.anaconda import conf
from pyanaconda.product import productName, productVersion

log = get_packaging_logger()


DNF_CACHE_DIR = '/tmp/dnf.cache'
DNF_PLUGINCONF_DIR = '/tmp/dnf.pluginconf'
DNF_PACKAGE_CACHE_DIR_SUFFIX = 'dnf.package.cache'
DNF_LIBREPO_LOG = '/tmp/dnf.librepo.log'
REPO_DIRS = ['/etc/yum.repos.d',
             '/etc/anaconda.repos.d',
             '/tmp/updates/anaconda.repos.d',
             '/tmp/product/anaconda.repos.d']
YUM_REPOS_DIR = "/etc/yum.repos.d/"

USER_AGENT = "%s (anaconda)/%s" % (productName, productVersion)

# Bonus to required free space which depends on block size and rpm database size estimation.
# Every file could be aligned to fragment size so 4KiB * number_of_files should be a worst
# case scenario. 2KiB for RPM DB was acquired by testing.
# 6KiB = 4K(max default fragment size) + 2K(rpm db could be taken for a header file)
BONUS_SIZE_ON_FILE = Size("6 KiB")


def go_to_failure_limbo():
    progressQ.send_quit(1)
    while True:
        time.sleep(10000)


def get_df_map():
    """Return (mountpoint -> size available) mapping."""
    output = util.execWithCapture('df', ['--output=target,avail'])
    output = output.rstrip()
    lines = output.splitlines()
    structured = {}
    for line in lines:
        key, val = line.rsplit(maxsplit=1)
        if not key.startswith('/'):
            continue
        structured[key] = Size(int(val) * 1024)

    # Add /var/tmp/ if this is a directory or image installation
    if not conf.target.is_hardware:
        var_tmp = os.statvfs("/var/tmp")
        structured["/var/tmp"] = Size(var_tmp.f_frsize * var_tmp.f_bfree)
    return structured


def pick_mount_point(df, download_size, install_size, download_only):
    reasonable_mpoints = {
        '/var/tmp',
        conf.target.system_root,
        os.path.join(conf.target.system_root, 'home'),
        os.path.join(conf.target.system_root, 'tmp'),
        os.path.join(conf.target.system_root, 'var'),
    }

    requested = download_size
    requested_root = requested + install_size
    root_mpoint = conf.target.system_root
    log.debug('Input mount points: %s', df)
    log.info('Estimated size: download %s & install %s', requested,
             (requested_root - requested))

    # Find sufficient mountpoint to download and install packages.
    sufficients = {key: val for (key, val) in df.items()
                   if ((key != root_mpoint and val > requested) or val > requested_root) and
                   key in reasonable_mpoints}

    # If no sufficient mountpoints for download and install were found and we are looking
    # for download mountpoint only, ignore install size and try to find mountpoint just
    # to download packages. This fallback is required when user skipped space check.
    if not sufficients and download_only:
        sufficients = {key: val for (key, val) in df.items() if val > requested and
                       key in reasonable_mpoints}
        if sufficients:
            log.info('Sufficient mountpoint for download only found: %s', sufficients)
    elif sufficients:
        log.info('Sufficient mountpoints found: %s', sufficients)

    if not sufficients:
        log.debug("No sufficient mountpoints found")
        return None

    sorted_mpoints = sorted(sufficients.items(), key=operator.itemgetter(1), reverse=True)

    # try to pick something else than root mountpoint for downloading
    if download_only and len(sorted_mpoints) >= 2 and sorted_mpoints[0][0] == root_mpoint:
        return sorted_mpoints[1][0]
    else:
        # default to the biggest one:
        return sorted_mpoints[0][0]


def do_transaction(base, queue_instance):
    # Execute the DNF transaction and catch any errors. An error doesn't
    # always raise a BaseException, so presence of 'quit' without a preceeding
    # 'post' message also indicates a problem.
    try:
        display = TransactionProgress(queue_instance)
        base.do_transaction(display=display)
        exit_reason = "DNF quit"
    except BaseException as e:  # pylint: disable=broad-except
        log.error('The transaction process has ended abruptly')
        log.info(e)
        import traceback
        exit_reason = str(e) + traceback.format_exc()
    finally:
        base.close()  # Always close this base.
        queue_instance.put(('quit', str(exit_reason)))