Blame dnf/cli/output.py

Packit 6f3914
# Copyright 2005 Duke University
Packit 6f3914
# Copyright (C) 2012-2016 Red Hat, Inc.
Packit 6f3914
#
Packit 6f3914
# This program is free software; you can redistribute it and/or modify
Packit 6f3914
# it under the terms of the GNU General Public License as published by
Packit 6f3914
# the Free Software Foundation; either version 2 of the License, or
Packit 6f3914
# (at your option) any later version.
Packit 6f3914
#
Packit 6f3914
# This program is distributed in the hope that it will be useful,
Packit 6f3914
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6f3914
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 6f3914
# GNU Library General Public License for more details.
Packit 6f3914
#
Packit 6f3914
# You should have received a copy of the GNU General Public License
Packit 6f3914
# along with this program; if not, write to the Free Software
Packit 6f3914
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 6f3914
Packit 6f3914
"""Handle actual output from the cli."""
Packit 6f3914
Packit 6f3914
from __future__ import absolute_import
Packit 6f3914
from __future__ import print_function
Packit 6f3914
from __future__ import unicode_literals
Packit 6f3914
Packit 6f3914
from copy import deepcopy
Packit 6f3914
import fnmatch
Packit 6f3914
import hawkey
Packit 6f3914
import itertools
Packit 6f3914
import libdnf.transaction
Packit 6f3914
import logging
Packit 6f3914
import operator
Packit 6f3914
import pwd
Packit 6f3914
import re
Packit 6f3914
import sys
Packit 6f3914
import time
Packit 6f3914
Packit 6f3914
from dnf.cli.format import format_number, format_time
Packit 6f3914
from dnf.i18n import _, C_, P_, ucd, fill_exact_width, textwrap_fill, exact_width, select_short_long
Packit 6f3914
from dnf.pycomp import xrange, basestring, long, unicode, sys_maxsize
Packit 6f3914
from dnf.yum.rpmtrans import LoggingTransactionDisplay
Packit 6f3914
from dnf.db.history import MergedTransactionWrapper
Packit 6f3914
import dnf.base
Packit 6f3914
import dnf.callback
Packit 6f3914
import dnf.cli.progress
Packit 6f3914
import dnf.cli.term
Packit 6f3914
import dnf.conf
Packit 6f3914
import dnf.crypto
Packit 6f3914
import dnf.i18n
Packit 6f3914
import dnf.transaction
Packit 6f3914
import dnf.util
Packit 6f3914
import dnf.yum.misc
Packit 6f3914
Packit 6f3914
logger = logging.getLogger('dnf')
Packit 6f3914
Packit 6f3914
def _make_lists(transaction, goal):
Packit 6f3914
    b = dnf.util.Bunch({
Packit 6f3914
        'downgraded': [],
Packit 6f3914
        'erased': [],
Packit 6f3914
        'erased_clean': [],
Packit 6f3914
        'erased_dep': [],
Packit 6f3914
        'installed': [],
Packit 6f3914
        'installed_group': [],
Packit 6f3914
        'installed_dep': [],
Packit 6f3914
        'installed_weak': [],
Packit 6f3914
        'reinstalled': [],
Packit 6f3914
        'upgraded': [],
Packit 6f3914
        'failed': [],
Packit 6f3914
    })
Packit 6f3914
Packit 6f3914
    for tsi in transaction:
Packit 6f3914
        if tsi.state == libdnf.transaction.TransactionItemState_ERROR:
Packit 6f3914
            b.failed.append(tsi)
Packit 6f3914
        elif tsi.action == libdnf.transaction.TransactionItemAction_DOWNGRADE:
Packit 6f3914
            b.downgraded.append(tsi)
Packit 6f3914
        elif tsi.action == libdnf.transaction.TransactionItemAction_INSTALL:
Packit 6f3914
            if tsi.reason == libdnf.transaction.TransactionItemReason_GROUP:
Packit 6f3914
                b.installed_group.append(tsi)
Packit 6f3914
            elif tsi.reason == libdnf.transaction.TransactionItemReason_DEPENDENCY:
Packit 6f3914
                b.installed_dep.append(tsi)
Packit 6f3914
            elif tsi.reason == libdnf.transaction.TransactionItemReason_WEAK_DEPENDENCY:
Packit 6f3914
                b.installed_weak.append(tsi)
Packit 6f3914
            else:
Packit 6f3914
                # TransactionItemReason_USER
Packit 6f3914
                b.installed.append(tsi)
Packit 6f3914
        elif tsi.action == libdnf.transaction.TransactionItemAction_REINSTALL:
Packit 6f3914
            b.reinstalled.append(tsi)
Packit 6f3914
        elif tsi.action == libdnf.transaction.TransactionItemAction_REMOVE:
Packit 6f3914
            if tsi.reason == libdnf.transaction.TransactionItemReason_CLEAN:
Packit 6f3914
                b.erased_clean.append(tsi)
Packit 6f3914
            elif tsi.reason == libdnf.transaction.TransactionItemReason_DEPENDENCY:
Packit 6f3914
                b.erased_dep.append(tsi)
Packit 6f3914
            else:
Packit 6f3914
                b.erased.append(tsi)
Packit 6f3914
        elif tsi.action == libdnf.transaction.TransactionItemAction_UPGRADE:
Packit 6f3914
            b.upgraded.append(tsi)
Packit 6f3914
Packit 6f3914
    return b
Packit 6f3914
Packit 6f3914
Packit 6f3914
def _spread_in_columns(cols_count, label, lst):
Packit 6f3914
    left = itertools.chain((label,), itertools.repeat(''))
Packit 6f3914
    lst_length = len(lst)
Packit 6f3914
    right_count = cols_count - 1
Packit 6f3914
    missing_items = -lst_length % right_count
Packit 6f3914
    if not lst_length:
Packit 6f3914
        lst = itertools.repeat('', right_count)
Packit 6f3914
    elif missing_items:
Packit 6f3914
        lst.extend(('',) * missing_items)
Packit 6f3914
    lst_iter = iter(lst)
Packit 6f3914
    return list(zip(left, *[lst_iter] * right_count))
Packit 6f3914
Packit 6f3914
Packit 6f3914
class Output(object):
Packit 6f3914
    """Main output class for the yum command line."""
Packit 6f3914
Packit 6f3914
    GRP_PACKAGE_INDENT = ' ' * 3
Packit 6f3914
    FILE_PROVIDE_RE = re.compile(r'^\*{0,2}/')
Packit 6f3914
Packit 6f3914
    def __init__(self, base, conf):
Packit 6f3914
        self.conf = conf
Packit 6f3914
        self.base = base
Packit 6f3914
        self.term = dnf.cli.term.Term()
Packit 6f3914
        self.progress = None
Packit 6f3914
Packit 6f3914
    def _banner(self, col_data, row):
Packit 6f3914
        term_width = self.term.columns
Packit 6f3914
        rule = '%s' % '=' * term_width
Packit 6f3914
        header = self.fmtColumns(zip(row, col_data), ' ')
Packit 6f3914
        return rule, header, rule
Packit 6f3914
Packit 6f3914
    def _col_widths(self, rows):
Packit 6f3914
        col_data = [dict() for _ in rows[0]]
Packit 6f3914
        for row in rows:
Packit 6f3914
            for (i, val) in enumerate(row):
Packit 6f3914
                col_dct = col_data[i]
Packit 6f3914
                length = len(val)
Packit 6f3914
                col_dct[length] = col_dct.get(length, 0) + 1
Packit 6f3914
        cols = self.calcColumns(col_data, None, indent='  ')
Packit 6f3914
        # align to the left
Packit 6f3914
        return list(map(operator.neg, cols))
Packit 6f3914
Packit 6f3914
    def _highlight(self, highlight):
Packit 6f3914
        hibeg = ''
Packit 6f3914
        hiend = ''
Packit 6f3914
        if not highlight:
Packit 6f3914
            pass
Packit 6f3914
        elif not isinstance(highlight, basestring) or highlight == 'bold':
Packit 6f3914
            hibeg = self.term.MODE['bold']
Packit 6f3914
        elif highlight == 'normal':
Packit 6f3914
            pass # Minor opt.
Packit 6f3914
        else:
Packit 6f3914
            # Turn a string into a specific output: colour, bold, etc.
Packit 6f3914
            for high in highlight.replace(',', ' ').split():
Packit 6f3914
                if high == 'normal':
Packit 6f3914
                    hibeg = ''
Packit 6f3914
                elif high in self.term.MODE:
Packit 6f3914
                    hibeg += self.term.MODE[high]
Packit 6f3914
                elif high in self.term.FG_COLOR:
Packit 6f3914
                    hibeg += self.term.FG_COLOR[high]
Packit 6f3914
                elif (high.startswith('fg:') and
Packit 6f3914
                      high[3:] in self.term.FG_COLOR):
Packit 6f3914
                    hibeg += self.term.FG_COLOR[high[3:]]
Packit 6f3914
                elif (high.startswith('bg:') and
Packit 6f3914
                      high[3:] in self.term.BG_COLOR):
Packit 6f3914
                    hibeg += self.term.BG_COLOR[high[3:]]
Packit 6f3914
Packit 6f3914
        if hibeg:
Packit 6f3914
            hiend = self.term.MODE['normal']
Packit 6f3914
        return (hibeg, hiend)
Packit 6f3914
Packit 6f3914
    def _sub_highlight(self, haystack, highlight, needles, **kwds):
Packit 6f3914
        hibeg, hiend = self._highlight(highlight)
Packit 6f3914
        return self.term.sub(haystack, hibeg, hiend, needles, **kwds)
Packit 6f3914
Packit 6f3914
    @staticmethod
Packit 6f3914
    def _calc_columns_spaces_helps(current, data_tups, left):
Packit 6f3914
        """ Spaces left on the current field will help how many pkgs? """
Packit 6f3914
        ret = 0
Packit 6f3914
        for tup in data_tups:
Packit 6f3914
            if left < (tup[0] - current):
Packit 6f3914
                break
Packit 6f3914
            ret += tup[1]
Packit 6f3914
        return ret
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def history(self):
Packit 6f3914
        return self.base.history
Packit 6f3914
Packit 6f3914
    @property
Packit 6f3914
    def sack(self):
Packit 6f3914
        return self.base.sack
Packit 6f3914
Packit 6f3914
    def calcColumns(self, data, columns=None, remainder_column=0,
Packit 6f3914
                    total_width=None, indent=''):
Packit 6f3914
        """Dynamically calculate the widths of the columns that the
Packit 6f3914
        fields in data should be placed into for output.
Packit 6f3914
Packit 6f3914
        :param data: a list of dictionaries that represent the data to
Packit 6f3914
           be output.  Each dictionary in the list corresponds to a
Packit 6f3914
           column of output. The keys of the dictionary are the
Packit 6f3914
           lengths of the items to be output, and the value associated
Packit 6f3914
           with a key is the number of items of that length.
Packit 6f3914
        :param columns: a list containing the minimum amount of space
Packit 6f3914
           that must be allocated for each row. This can be used to
Packit 6f3914
           ensure that there is space available in a column if, for
Packit 6f3914
           example, the actual lengths of the items being output
Packit 6f3914
           cannot be given in *data*
Packit 6f3914
        :param remainder_column: number of the column to receive a few
Packit 6f3914
           extra spaces that may remain after other allocation has
Packit 6f3914
           taken place
Packit 6f3914
        :param total_width: the total width of the output.
Packit 6f3914
           self.term.real_columns is used by default
Packit 6f3914
        :param indent: string that will be prefixed to a line of
Packit 6f3914
           output to create e.g. an indent
Packit 6f3914
        :return: a list of the widths of the columns that the fields
Packit 6f3914
           in data should be placed into for output
Packit 6f3914
        """
Packit 6f3914
        cols = len(data)
Packit 6f3914
        # Convert the data to ascending list of tuples, (field_length, pkgs)
Packit 6f3914
        pdata = data
Packit 6f3914
        data = [None] * cols # Don't modify the passed in data
Packit 6f3914
        for d in range(0, cols):
Packit 6f3914
            data[d] = sorted(pdata[d].items())
Packit 6f3914
Packit 6f3914
        if total_width is None:
Packit 6f3914
            total_width = self.term.real_columns
Packit 6f3914
Packit 6f3914
        # i'm not able to get real terminal width so i'm probably
Packit 6f3914
        # running in non interactive terminal (pipe to grep, redirect to file...)
Packit 6f3914
        # avoid splitting lines to enable filtering output
Packit 6f3914
        if not total_width:
Packit 6f3914
            full_columns = []
Packit 6f3914
            for col in data:
Packit 6f3914
                if col:
Packit 6f3914
                    full_columns.append(col[-1][0])
Packit 6f3914
                else:
Packit 6f3914
                    full_columns.append(0)
Packit 6f3914
            full_columns[0] += len(indent)
Packit 6f3914
            # if possible, try to keep default width (usually 80 columns)
Packit 6f3914
            default_width = self.term.columns
Packit 6f3914
            if sum(full_columns) > default_width:
Packit 6f3914
                return full_columns
Packit 6f3914
            total_width = default_width
Packit 6f3914
Packit 6f3914
        #  We start allocating 1 char to everything but the last column, and a
Packit 6f3914
        # space between each (again, except for the last column). Because
Packit 6f3914
        # at worst we are better with:
Packit 6f3914
        # |one two three|
Packit 6f3914
        # | four        |
Packit 6f3914
        # ...than:
Packit 6f3914
        # |one two three|
Packit 6f3914
        # |            f|
Packit 6f3914
        # |our          |
Packit 6f3914
        # ...the later being what we get if we pre-allocate the last column, and
Packit 6f3914
        # thus. the space, due to "three" overflowing it's column by 2 chars.
Packit 6f3914
        if columns is None:
Packit 6f3914
            columns = [1] * (cols - 1)
Packit 6f3914
            columns.append(0)
Packit 6f3914
Packit 6f3914
        total_width -= (sum(columns) + (cols - 1) + exact_width(indent))
Packit 6f3914
        if not columns[-1]:
Packit 6f3914
            total_width += 1
Packit 6f3914
        while total_width > 0:
Packit 6f3914
            # Find which field all the spaces left will help best
Packit 6f3914
            helps = 0
Packit 6f3914
            val = 0
Packit 6f3914
            for d in xrange(0, cols):
Packit 6f3914
                thelps = self._calc_columns_spaces_helps(columns[d], data[d],
Packit 6f3914
                                                         total_width)
Packit 6f3914
                if not thelps:
Packit 6f3914
                    continue
Packit 6f3914
                #  We prefer to overflow: the last column, and then earlier
Packit 6f3914
                # columns. This is so that in the best case (just overflow the
Packit 6f3914
                # last) ... grep still "works", and then we make it prettier.
Packit 6f3914
                if helps and (d == (cols - 1)) and (thelps / 2) < helps:
Packit 6f3914
                    continue
Packit 6f3914
                if thelps < helps:
Packit 6f3914
                    continue
Packit 6f3914
                helps = thelps
Packit 6f3914
                val = d
Packit 6f3914
Packit 6f3914
            #  If we found a column to expand, move up to the next level with
Packit 6f3914
            # that column and start again with any remaining space.
Packit 6f3914
            if helps:
Packit 6f3914
                diff = data[val].pop(0)[0] - columns[val]
Packit 6f3914
                if not columns[val] and (val == (cols - 1)):
Packit 6f3914
                    #  If we are going from 0 => N on the last column, take 1
Packit 6f3914
                    # for the space before the column.
Packit 6f3914
                    total_width -= 1
Packit 6f3914
                columns[val] += diff
Packit 6f3914
                total_width -= diff
Packit 6f3914
                continue
Packit 6f3914
Packit 6f3914
            overflowed_columns = 0
Packit 6f3914
            for d in xrange(0, cols):
Packit 6f3914
                if not data[d]:
Packit 6f3914
                    continue
Packit 6f3914
                overflowed_columns += 1
Packit 6f3914
            if overflowed_columns:
Packit 6f3914
                #  Split the remaining spaces among each overflowed column
Packit 6f3914
                # equally
Packit 6f3914
                norm = total_width // overflowed_columns
Packit 6f3914
                for d in xrange(0, cols):
Packit 6f3914
                    if not data[d]:
Packit 6f3914
                        continue
Packit 6f3914
                    columns[d] += norm
Packit 6f3914
                    total_width -= norm
Packit 6f3914
Packit 6f3914
            #  Split the remaining spaces among each column equally, except the
Packit 6f3914
            # last one. And put the rest into the remainder column
Packit 6f3914
            cols -= 1
Packit 6f3914
            norm = total_width // cols
Packit 6f3914
            for d in xrange(0, cols):
Packit 6f3914
                columns[d] += norm
Packit 6f3914
            columns[remainder_column] += total_width - (cols * norm)
Packit 6f3914
            total_width = 0
Packit 6f3914
Packit 6f3914
        return columns
Packit 6f3914
Packit 6f3914
    @staticmethod
Packit 6f3914
    def _fmt_column_align_width(width):
Packit 6f3914
        """Returns tuple of (align_left, width)"""
Packit 6f3914
        if width < 0:
Packit 6f3914
            return (True, -width)
Packit 6f3914
        return (False, width)
Packit 6f3914
Packit 6f3914
    def _col_data(self, col_data):
Packit 6f3914
        assert len(col_data) == 2 or len(col_data) == 3
Packit 6f3914
        if len(col_data) == 2:
Packit 6f3914
            (val, width) = col_data
Packit 6f3914
            hibeg = hiend = ''
Packit 6f3914
        if len(col_data) == 3:
Packit 6f3914
            (val, width, highlight) = col_data
Packit 6f3914
            (hibeg, hiend) = self._highlight(highlight)
Packit 6f3914
        return (ucd(val), width, hibeg, hiend)
Packit 6f3914
Packit 6f3914
    def fmtColumns(self, columns, msg=u'', end=u''):
Packit 6f3914
        """Return a row of data formatted into a string for output.
Packit 6f3914
        Items can overflow their columns.
Packit 6f3914
Packit 6f3914
        :param columns: a list of tuples containing the data to
Packit 6f3914
           output.  Each tuple contains first the item to be output,
Packit 6f3914
           then the amount of space allocated for the column, and then
Packit 6f3914
           optionally a type of highlighting for the item
Packit 6f3914
        :param msg: a string to begin the line of output with
Packit 6f3914
        :param end: a string to end the line of output with
Packit 6f3914
        :return: a row of data formatted into a string for output
Packit 6f3914
        """
Packit 6f3914
        columns = list(columns)
Packit 6f3914
        total_width = len(msg)
Packit 6f3914
        data = []
Packit 6f3914
        for col_data in columns[:-1]:
Packit 6f3914
            (val, width, hibeg, hiend) = self._col_data(col_data)
Packit 6f3914
Packit 6f3914
            if not width: # Don't count this column, invisible text
Packit 6f3914
                msg += u"%s"
Packit 6f3914
                data.append(val)
Packit 6f3914
                continue
Packit 6f3914
Packit 6f3914
            (align_left, width) = self._fmt_column_align_width(width)
Packit 6f3914
            val_width = exact_width(val)
Packit 6f3914
            if val_width <= width:
Packit 6f3914
                #  Don't use fill_exact_width() because it sucks performance
Packit 6f3914
                # wise for 1,000s of rows. Also allows us to use len(), when
Packit 6f3914
                # we can.
Packit 6f3914
                msg += u"%s%s%s%s "
Packit 6f3914
                if align_left:
Packit 6f3914
                    data.extend([hibeg, val, " " * (width - val_width), hiend])
Packit 6f3914
                else:
Packit 6f3914
                    data.extend([hibeg, " " * (width - val_width), val, hiend])
Packit 6f3914
            else:
Packit 6f3914
                msg += u"%s%s%s\n" + " " * (total_width + width + 1)
Packit 6f3914
                data.extend([hibeg, val, hiend])
Packit 6f3914
            total_width += width
Packit 6f3914
            total_width += 1
Packit 6f3914
        (val, width, hibeg, hiend) = self._col_data(columns[-1])
Packit 6f3914
        (align_left, width) = self._fmt_column_align_width(width)
Packit 6f3914
        val = fill_exact_width(val, width, left=align_left,
Packit 6f3914
                              prefix=hibeg, suffix=hiend)
Packit 6f3914
        msg += u"%%s%s" % end
Packit 6f3914
        data.append(val)
Packit 6f3914
        return msg % tuple(data)
Packit 6f3914
Packit 6f3914
    def simpleList(self, pkg, ui_overflow=False, indent='', highlight=False,
Packit 6f3914
                   columns=None):
Packit 6f3914
        """Print a package as a line.
Packit 6f3914
Packit 6f3914
        :param pkg: the package to be printed
Packit 6f3914
        :param ui_overflow: unused
Packit 6f3914
        :param indent: string to be prefixed onto the line to provide
Packit 6f3914
           e.g. an indent
Packit 6f3914
        :param highlight: highlighting options for the name of the
Packit 6f3914
           package
Packit 6f3914
        :param columns: tuple containing the space allocated for each
Packit 6f3914
           column of output.  The columns are the package name, version,
Packit 6f3914
           and repository
Packit 6f3914
        """
Packit 6f3914
        if columns is None:
Packit 6f3914
            columns = (-40, -22, -16) # Old default
Packit 6f3914
        na = '%s%s.%s' % (indent, pkg.name, pkg.arch)
Packit 6f3914
        hi_cols = [highlight, 'normal', 'normal']
Packit 6f3914
Packit 6f3914
        columns = zip((na, pkg.evr, pkg._from_repo), columns, hi_cols)
Packit 6f3914
        print(self.fmtColumns(columns))
Packit 6f3914
Packit 6f3914
    def simpleEnvraList(self, pkg, ui_overflow=False,
Packit 6f3914
                        indent='', highlight=False, columns=None):
Packit 6f3914
        """Print a package as a line, with the package itself in envra
Packit 6f3914
        format so it can be passed to list/install/etc.
Packit 6f3914
Packit 6f3914
        :param pkg: the package to be printed
Packit 6f3914
        :param ui_overflow: unused
Packit 6f3914
        :param indent: string to be prefixed onto the line to provide
Packit 6f3914
           e.g. an indent
Packit 6f3914
        :param highlight: highlighting options for the name of the
Packit 6f3914
           package
Packit 6f3914
        :param columns: tuple containing the space allocated for each
Packit 6f3914
           column of output.  The columns the are the package envra and
Packit 6f3914
           repository
Packit 6f3914
        """
Packit 6f3914
        if columns is None:
Packit 6f3914
            columns = (-63, -16) # Old default
Packit 6f3914
        envra = '%s%s' % (indent, ucd(pkg))
Packit 6f3914
        hi_cols = [highlight, 'normal', 'normal']
Packit 6f3914
        rid = pkg.ui_from_repo
Packit 6f3914
        columns = zip((envra, rid), columns, hi_cols)
Packit 6f3914
        print(self.fmtColumns(columns))
Packit 6f3914
Packit 6f3914
    def simple_name_list(self, pkg):
Packit 6f3914
        """Print a package as a line containing its name."""
Packit 6f3914
        print(ucd(pkg.name))
Packit 6f3914
Packit 6f3914
    def simple_nevra_list(self, pkg):
Packit 6f3914
        """Print a package as a line containing its NEVRA."""
Packit 6f3914
        print(ucd(pkg))
Packit 6f3914
Packit 6f3914
    def fmtKeyValFill(self, key, val):
Packit 6f3914
        """Return a key value pair in the common two column output
Packit 6f3914
        format.
Packit 6f3914
Packit 6f3914
        :param key: the key to be formatted
Packit 6f3914
        :param val: the value associated with *key*
Packit 6f3914
        :return: the key value pair formatted in two columns for output
Packit 6f3914
        """
Packit 6f3914
        keylen = exact_width(key)
Packit 6f3914
        cols = self.term.real_columns
Packit 6f3914
        if not cols:
Packit 6f3914
            cols = sys_maxsize
Packit 6f3914
        elif cols < 20:
Packit 6f3914
            cols = 20
Packit 6f3914
        nxt = ' ' * (keylen - 2) + ': '
Packit 6f3914
        if not val:
Packit 6f3914
            # textwrap.fill in case of empty val returns empty string
Packit 6f3914
            return key
Packit 6f3914
        val = ucd(val)
Packit 6f3914
        ret = textwrap_fill(val, width=cols, initial_indent=key,
Packit 6f3914
                            subsequent_indent=nxt)
Packit 6f3914
        if ret.count("\n") > 1 and keylen > (cols // 3):
Packit 6f3914
            # If it's big, redo it again with a smaller subsequent off
Packit 6f3914
            ret = textwrap_fill(val, width=cols, initial_indent=key,
Packit 6f3914
                                subsequent_indent='     ...: ')
Packit 6f3914
        return ret
Packit 6f3914
Packit 6f3914
    def fmtSection(self, name, fill='='):
Packit 6f3914
        """Format and return a section header.  The format of the
Packit 6f3914
        header is a line with *name* centered, and *fill* repeated on
Packit 6f3914
        either side to fill an entire line on the terminal.
Packit 6f3914
Packit 6f3914
        :param name: the name of the section
Packit 6f3914
        :param fill: the character to repeat on either side of *name*
Packit 6f3914
          to fill an entire line.  *fill* must be a single character.
Packit 6f3914
        :return: a string formatted to be a section header
Packit 6f3914
        """
Packit 6f3914
        name = ucd(name)
Packit 6f3914
        cols = self.term.columns - 2
Packit 6f3914
        name_len = exact_width(name)
Packit 6f3914
        if name_len >= (cols - 4):
Packit 6f3914
            beg = end = fill * 2
Packit 6f3914
        else:
Packit 6f3914
            beg = fill * ((cols - name_len) // 2)
Packit 6f3914
            end = fill * (cols - name_len - len(beg))
Packit 6f3914
Packit 6f3914
        return "%s %s %s" % (beg, name, end)
Packit 6f3914
Packit 6f3914
    def infoOutput(self, pkg, highlight=False):
Packit 6f3914
        """Print information about the given package.
Packit 6f3914
Packit 6f3914
        :param pkg: the package to print information about
Packit 6f3914
        :param highlight: highlighting options for the name of the
Packit 6f3914
           package
Packit 6f3914
        """
Packit 6f3914
        def format_key_val(key, val):
Packit 6f3914
            return " ".join([fill_exact_width(key, 12, 12), ":", str(val)])
Packit 6f3914
Packit 6f3914
        def format_key_val_fill(key, val):
Packit 6f3914
            return self.fmtKeyValFill(fill_exact_width(key, 12, 12) + " : ", val or "")
Packit 6f3914
Packit 6f3914
        output_list = []
Packit 6f3914
        (hibeg, hiend) = self._highlight(highlight)
Packit 6f3914
        # Translators: This is abbreviated 'Name'. Should be no longer
Packit 6f3914
        # than 12 characters. You can use the full version if it is short
Packit 6f3914
        # enough in your language.
Packit 6f3914
        key = select_short_long(12, C_("short", "Name"),
Packit 6f3914
                                    C_("long", "Name"))
Packit 6f3914
        output_list.append(format_key_val(key,
Packit 6f3914
                                          "%s%s%s" % (hibeg, pkg.name, hiend)))
Packit 6f3914
        if pkg.epoch:
Packit 6f3914
            # Translators: This message should be no longer than 12 characters.
Packit 6f3914
            output_list.append(format_key_val(_("Epoch"), pkg.epoch))
Packit 6f3914
        key = select_short_long(12, C_("short", "Version"),
Packit 6f3914
                                    C_("long", "Version"))
Packit 6f3914
        output_list.append(format_key_val(key, pkg.version))
Packit 6f3914
        # Translators: This message should be no longer than 12 characters.
Packit 6f3914
        output_list.append(format_key_val(_("Release"), pkg.release))
Packit 6f3914
        key = select_short_long(12, C_("short", "Arch"),
Packit 6f3914
                                    C_("long", "Architecture"))
Packit 6f3914
        output_list.append(format_key_val(key, pkg.arch))
Packit 6f3914
        key = select_short_long(12, C_("short", "Size"), C_("long", "Size"))
Packit 6f3914
        output_list.append(format_key_val(key,
Packit 6f3914
                                          format_number(float(pkg._size))))
Packit 6f3914
        # Translators: This message should be no longer than 12 characters.
Packit 6f3914
        output_list.append(format_key_val(_("Source"), pkg.sourcerpm))
Packit 6f3914
        key = select_short_long(12, C_("short", "Repo"),
Packit 6f3914
                                    C_("long", "Repository"))
Packit 6f3914
        output_list.append(format_key_val(key, pkg.repoid))
Packit 6f3914
Packit 6f3914
        if pkg._from_system:
Packit 6f3914
            history_repo = self.history.repo(pkg)
Packit 6f3914
            if history_repo:
Packit 6f3914
                # Translators: This message should be no longer than 12 chars.
Packit 6f3914
                output_list.append(format_key_val(_("From repo"), history_repo))
Packit 6f3914
        if self.conf.verbose:
Packit 6f3914
            # :hawkey does not support changelog information
Packit 6f3914
            # print(_("Committer   : %s") % ucd(pkg.committer))
Packit 6f3914
            # print(_("Committime  : %s") % time.ctime(pkg.committime))
Packit 6f3914
            # Translators: This message should be no longer than 12 characters.
Packit 6f3914
            output_list.append(format_key_val(_("Packager"), pkg.packager))
Packit 6f3914
            # Translators: This message should be no longer than 12 characters.
Packit 6f3914
            output_list.append(format_key_val(_("Buildtime"),
Packit 6f3914
                                              dnf.util.normalize_time(pkg.buildtime)))
Packit 6f3914
            if pkg.installtime:
Packit 6f3914
            # Translators: This message should be no longer than 12 characters.
Packit 6f3914
                output_list.append(format_key_val(_("Install time"),
Packit 6f3914
                                                  dnf.util.normalize_time(pkg.installtime)))
Packit 6f3914
            history_pkg = self.history.package_data(pkg)
Packit 6f3914
            if history_pkg:
Packit 6f3914
                try:
Packit 6f3914
                    uid = int(history_pkg._item.getInstalledBy())
Packit 6f3914
                except ValueError: # In case int() fails
Packit 6f3914
                    uid = None
Packit 6f3914
                # Translators: This message should be no longer than 12 chars.
Packit 6f3914
                output_list.append(format_key_val(_("Installed by"), self._pwd_ui_username(uid)))
Packit 6f3914
        # Translators: This is abbreviated 'Summary'. Should be no longer
Packit 6f3914
        # than 12 characters. You can use the full version if it is short
Packit 6f3914
        # enough in your language.
Packit 6f3914
        key = select_short_long(12, C_("short", "Summary"),
Packit 6f3914
                                    C_("long", "Summary"))
Packit 6f3914
        output_list.append(format_key_val_fill(key, pkg.summary))
Packit 6f3914
        if pkg.url:
Packit 6f3914
            output_list.append(format_key_val(_("URL"), ucd(pkg.url)))
Packit 6f3914
        # Translators: This message should be no longer than 12 characters.
Packit 6f3914
        output_list.append(format_key_val_fill(_("License"), pkg.license))
Packit 6f3914
        # Translators: This is abbreviated 'Description'. Should be no longer
Packit 6f3914
        # than 12 characters. You can use the full version if it is short
Packit 6f3914
        # enough in your language.
Packit 6f3914
        key = select_short_long(12, C_("short", "Description"),
Packit 6f3914
                                    C_("long", "Description"))
Packit 6f3914
        output_list.append(format_key_val_fill(key, pkg.description))
Packit 6f3914
        return "\n".join(output_list)
Packit 6f3914
Packit 6f3914
    def updatesObsoletesList(self, uotup, changetype, columns=None):
Packit 6f3914
        """Print a simple string that explains the relationship
Packit 6f3914
        between the members of an update or obsoletes tuple.
Packit 6f3914
Packit 6f3914
        :param uotup: an update or obsoletes tuple.  The first member
Packit 6f3914
           is the new package, and the second member is the old
Packit 6f3914
           package
Packit 6f3914
        :param changetype: a string indicating what the change between
Packit 6f3914
           the packages is, e.g. 'updates' or 'obsoletes'
Packit 6f3914
        :param columns: a tuple containing information about how to
Packit 6f3914
           format the columns of output.  The absolute value of each
Packit 6f3914
           number in the tuple indicates how much space has been
Packit 6f3914
           allocated for the corresponding column.  If the number is
Packit 6f3914
           negative, the text in the column will be left justified,
Packit 6f3914
           and if it is positive, the text will be right justified.
Packit 6f3914
           The columns of output are the package name, version, and repository
Packit 6f3914
        """
Packit 6f3914
        (changePkg, instPkg) = uotup
Packit 6f3914
Packit 6f3914
        if columns is not None:
Packit 6f3914
            # New style, output all info. for both old/new with old indented
Packit 6f3914
            chi = self.conf.color_update_remote
Packit 6f3914
            if changePkg.reponame != hawkey.SYSTEM_REPO_NAME:
Packit 6f3914
                chi = self.conf.color_update_local
Packit 6f3914
            self.simpleList(changePkg, columns=columns, highlight=chi)
Packit 6f3914
            self.simpleList(instPkg, columns=columns, indent=' ' * 4,
Packit 6f3914
                            highlight=self.conf.color_update_installed)
Packit 6f3914
            return
Packit 6f3914
Packit 6f3914
        # Old style
Packit 6f3914
        c_compact = changePkg.compactPrint()
Packit 6f3914
        i_compact = '%s.%s' % (instPkg.name, instPkg.arch)
Packit 6f3914
        c_repo = changePkg.repoid
Packit 6f3914
        print('%-35.35s [%.12s] %.10s %-20.20s' %
Packit 6f3914
              (c_compact, c_repo, changetype, i_compact))
Packit 6f3914
Packit 6f3914
    def listPkgs(self, lst, description, outputType, highlight_na={},
Packit 6f3914
                 columns=None, highlight_modes={}):
Packit 6f3914
        """Prints information about the given list of packages.
Packit 6f3914
Packit 6f3914
        :param lst: a list of packages to print information about
Packit 6f3914
        :param description: string describing what the list of
Packit 6f3914
           packages contains, e.g. 'Available Packages'
Packit 6f3914
        :param outputType: The type of information to be printed.
Packit 6f3914
           Current options::
Packit 6f3914
Packit 6f3914
              'list' - simple pkg list
Packit 6f3914
              'info' - similar to rpm -qi output
Packit 6f3914
              'name' - simple name list
Packit 6f3914
              'nevra' - simple nevra list
Packit 6f3914
        :param highlight_na: a dictionary containing information about
Packit 6f3914
              packages that should be highlighted in the output.  The
Packit 6f3914
              dictionary keys are (name, arch) tuples for the package,
Packit 6f3914
              and the associated values are the package objects
Packit 6f3914
              themselves.
Packit 6f3914
        :param columns: a tuple containing information about how to
Packit 6f3914
           format the columns of output.  The absolute value of each
Packit 6f3914
           number in the tuple indicates how much space has been
Packit 6f3914
           allocated for the corresponding column.  If the number is
Packit 6f3914
           negative, the text in the column will be left justified,
Packit 6f3914
           and if it is positive, the text will be right justified.
Packit 6f3914
           The columns of output are the package name, version, and
Packit 6f3914
           repository
Packit 6f3914
        :param highlight_modes: dictionary containing information
Packit 6f3914
              about to highlight the packages in *highlight_na*.
Packit 6f3914
              *highlight_modes* should contain the following keys::
Packit 6f3914
Packit 6f3914
                 'not_in' - highlighting used for packages not in *highlight_na*
Packit 6f3914
                 '=' - highlighting used when the package versions are equal
Packit 6f3914
                 '<' - highlighting used when the package has a lower version
Packit 6f3914
                       number
Packit 6f3914
                 '>' - highlighting used when the package has a higher version
Packit 6f3914
                       number
Packit 6f3914
        :return: (exit_code, [errors])
Packit 6f3914
Packit 6f3914
        exit_code is::
Packit 6f3914
Packit 6f3914
            0 = we're done, exit
Packit 6f3914
            1 = we've errored, exit with error string
Packit 6f3914
Packit 6f3914
        """
Packit 6f3914
        if outputType in ['list', 'info', 'name', 'nevra']:
Packit 6f3914
            thingslisted = 0
Packit 6f3914
            if len(lst) > 0:
Packit 6f3914
                thingslisted = 1
Packit 6f3914
                print('%s' % description)
Packit 6f3914
                info_set = set()
Packit 6f3914
                if outputType == 'list':
Packit 6f3914
                    unique_item_dict = {}
Packit 6f3914
                    for pkg in lst:
Packit 6f3914
                        unique_item_dict[str(pkg) + str(pkg._from_repo)] = pkg
Packit 6f3914
Packit 6f3914
                    lst = unique_item_dict.values()
Packit 6f3914
Packit 6f3914
                for pkg in sorted(lst):
Packit 6f3914
                    key = (pkg.name, pkg.arch)
Packit 6f3914
                    highlight = False
Packit 6f3914
                    if key not in highlight_na:
Packit 6f3914
                        highlight = highlight_modes.get('not in', 'normal')
Packit 6f3914
                    elif pkg.evr_eq(highlight_na[key]):
Packit 6f3914
                        highlight = highlight_modes.get('=', 'normal')
Packit 6f3914
                    elif pkg.evr_lt(highlight_na[key]):
Packit 6f3914
                        highlight = highlight_modes.get('>', 'bold')
Packit 6f3914
                    else:
Packit 6f3914
                        highlight = highlight_modes.get('<', 'normal')
Packit 6f3914
Packit 6f3914
                    if outputType == 'list':
Packit 6f3914
                        self.simpleList(pkg, ui_overflow=True,
Packit 6f3914
                                        highlight=highlight, columns=columns)
Packit 6f3914
                    elif outputType == 'info':
Packit 6f3914
                        info_set.add(self.infoOutput(pkg, highlight=highlight) + "\n")
Packit 6f3914
                    elif outputType == 'name':
Packit 6f3914
                        self.simple_name_list(pkg)
Packit 6f3914
                    elif outputType == 'nevra':
Packit 6f3914
                        self.simple_nevra_list(pkg)
Packit 6f3914
                    else:
Packit 6f3914
                        pass
Packit 6f3914
Packit 6f3914
                if info_set:
Packit 6f3914
                    print("\n".join(sorted(info_set)))
Packit 6f3914
Packit 6f3914
            if thingslisted == 0:
Packit 6f3914
                return 1, [_('No packages to list')]
Packit 6f3914
            return 0, []
Packit 6f3914
Packit 6f3914
    def userconfirm(self, msg=None, defaultyes_msg=None):
Packit 6f3914
        """Get a yes or no from the user, and default to No
Packit 6f3914
Packit 6f3914
        :msg: String for case with [y/N]
Packit 6f3914
        :defaultyes_msg: String for case with [Y/n]
Packit 6f3914
        :return: True if the user selects yes, and False if the user
Packit 6f3914
           selects no
Packit 6f3914
        """
Packit 6f3914
        yui = (ucd(_('y')), ucd(_('yes')))
Packit 6f3914
        nui = (ucd(_('n')), ucd(_('no')))
Packit 6f3914
        aui = yui + nui
Packit 6f3914
        while True:
Packit 6f3914
            if msg is None:
Packit 6f3914
                msg = _('Is this ok [y/N]: ')
Packit 6f3914
            choice = ''
Packit 6f3914
            if self.conf.defaultyes:
Packit 6f3914
                if defaultyes_msg is None:
Packit 6f3914
                    msg = _('Is this ok [Y/n]: ')
Packit 6f3914
                else:
Packit 6f3914
                    msg = defaultyes_msg
Packit 6f3914
            try:
Packit 6f3914
                choice = dnf.i18n.ucd_input(msg)
Packit 6f3914
            except EOFError:
Packit 6f3914
                pass
Packit 6f3914
            except KeyboardInterrupt:
Packit 6f3914
                choice = nui[0]
Packit 6f3914
            choice = ucd(choice).lower()
Packit 6f3914
            if len(choice) == 0:
Packit 6f3914
                choice = yui[0] if self.conf.defaultyes else nui[0]
Packit 6f3914
            if choice in aui:
Packit 6f3914
                break
Packit 6f3914
Packit 6f3914
            # If the English one letter names don't mix with the translated
Packit 6f3914
            # letters, allow them too:
Packit 6f3914
            if u'y' == choice and u'y' not in aui:
Packit 6f3914
                choice = yui[0]
Packit 6f3914
                break
Packit 6f3914
            if u'n' == choice and u'n' not in aui:
Packit 6f3914
                choice = nui[0]
Packit 6f3914
                break
Packit 6f3914
Packit 6f3914
        if choice in yui:
Packit 6f3914
            return True
Packit 6f3914
        return False
Packit 6f3914
Packit 6f3914
    def _pkgs2name_dict(self, sections):
Packit 6f3914
        installed = self.sack.query().installed()._name_dict()
Packit 6f3914
        available = self.sack.query().available()._name_dict()
Packit 6f3914
Packit 6f3914
        d = {}
Packit 6f3914
        for pkg_name in itertools.chain(*list(zip(*sections))[1]):
Packit 6f3914
            if pkg_name in installed:
Packit 6f3914
                d[pkg_name] = installed[pkg_name][0]
Packit 6f3914
            elif pkg_name in available:
Packit 6f3914
                d[pkg_name] = available[pkg_name][0]
Packit 6f3914
        return d
Packit 6f3914
Packit 6f3914
    def _pkgs2col_lengths(self, sections, name_dict):
Packit 6f3914
        nevra_lengths = {}
Packit 6f3914
        repo_lengths = {}
Packit 6f3914
        for pkg_name in itertools.chain(*list(zip(*sections))[1]):
Packit 6f3914
            pkg = name_dict.get(pkg_name)
Packit 6f3914
            if pkg is None:
Packit 6f3914
                continue
Packit 6f3914
            nevra_l = exact_width(ucd(pkg)) + exact_width(self.GRP_PACKAGE_INDENT)
Packit 6f3914
            repo_l = exact_width(ucd(pkg.reponame))
Packit 6f3914
            nevra_lengths[nevra_l] = nevra_lengths.get(nevra_l, 0) + 1
Packit 6f3914
            repo_lengths[repo_l] = repo_lengths.get(repo_l, 0) + 1
Packit 6f3914
        return (nevra_lengths, repo_lengths)
Packit 6f3914
Packit 6f3914
    def _display_packages(self, pkg_names):
Packit 6f3914
        for name in pkg_names:
Packit 6f3914
            print('%s%s' % (self.GRP_PACKAGE_INDENT, name))
Packit 6f3914
Packit 6f3914
    def _display_packages_verbose(self, pkg_names, name_dict, columns):
Packit 6f3914
        for name in pkg_names:
Packit 6f3914
            try:
Packit 6f3914
                pkg = name_dict[name]
Packit 6f3914
            except KeyError:
Packit 6f3914
                # package not in any repo -> print only package name
Packit 6f3914
                print('%s%s' % (self.GRP_PACKAGE_INDENT, name))
Packit 6f3914
                continue
Packit 6f3914
            highlight = False
Packit 6f3914
            if not pkg._from_system:
Packit 6f3914
                highlight = self.conf.color_list_available_install
Packit 6f3914
            self.simpleEnvraList(pkg, ui_overflow=True,
Packit 6f3914
                                 indent=self.GRP_PACKAGE_INDENT,
Packit 6f3914
                                 highlight=highlight,
Packit 6f3914
                                 columns=columns)
Packit 6f3914
Packit 6f3914
    def display_pkgs_in_groups(self, group):
Packit 6f3914
        """Output information about the packages in a given group
Packit 6f3914
Packit 6f3914
        :param group: a Group object to output information about
Packit 6f3914
        """
Packit 6f3914
        def names(packages):
Packit 6f3914
            return sorted(pkg.name for pkg in packages)
Packit 6f3914
        print('\n' + _('Group: %s') % group.ui_name)
Packit 6f3914
Packit 6f3914
        verbose = self.conf.verbose
Packit 6f3914
        if verbose:
Packit 6f3914
            print(_(' Group-Id: %s') % ucd(group.id))
Packit 6f3914
        if group.ui_description:
Packit 6f3914
            print(_(' Description: %s') % ucd(group.ui_description) or "")
Packit 6f3914
        if group.lang_only:
Packit 6f3914
            print(_(' Language: %s') % group.lang_only)
Packit 6f3914
Packit 6f3914
        sections = (
Packit 6f3914
            (_(' Mandatory Packages:'), names(group.mandatory_packages)),
Packit 6f3914
            (_(' Default Packages:'), names(group.default_packages)),
Packit 6f3914
            (_(' Optional Packages:'), names(group.optional_packages)),
Packit 6f3914
            (_(' Conditional Packages:'), names(group.conditional_packages)))
Packit 6f3914
        if verbose:
Packit 6f3914
            name_dict = self._pkgs2name_dict(sections)
Packit 6f3914
            col_lengths = self._pkgs2col_lengths(sections, name_dict)
Packit 6f3914
            columns = self.calcColumns(col_lengths)
Packit 6f3914
            columns = (-columns[0], -columns[1])
Packit 6f3914
            for (section_name, packages) in sections:
Packit 6f3914
                if len(packages) < 1:
Packit 6f3914
                    continue
Packit 6f3914
                print(section_name)
Packit 6f3914
                self._display_packages_verbose(packages, name_dict, columns)
Packit 6f3914
        else:
Packit 6f3914
            for (section_name, packages) in sections:
Packit 6f3914
                if len(packages) < 1:
Packit 6f3914
                    continue
Packit 6f3914
                print(section_name)
Packit 6f3914
                self._display_packages(packages)
Packit 6f3914
Packit 6f3914
    def display_groups_in_environment(self, environment):
Packit 6f3914
        """Output information about the packages in a given environment
Packit 6f3914
Packit 6f3914
        :param environment: an Environment object to output information about
Packit 6f3914
        """
Packit 6f3914
        def names(groups):
Packit 6f3914
            return sorted(group.name for group in groups)
Packit 6f3914
        print(_('Environment Group: %s') % environment.ui_name)
Packit 6f3914
Packit 6f3914
        if self.conf.verbose:
Packit 6f3914
            print(_(' Environment-Id: %s') % ucd(environment.id))
Packit 6f3914
        if environment.ui_description:
Packit 6f3914
            description = ucd(environment.ui_description) or ""
Packit 6f3914
            print(_(' Description: %s') % description)
Packit 6f3914
Packit 6f3914
        sections = (
Packit 6f3914
            (_(' Mandatory Groups:'), names(environment.mandatory_groups)),
Packit 6f3914
            (_(' Optional Groups:'), names(environment.optional_groups)))
Packit 6f3914
        for (section_name, packages) in sections:
Packit 6f3914
            if len(packages) < 1:
Packit 6f3914
                continue
Packit 6f3914
            print(section_name)
Packit 6f3914
            self._display_packages(packages)
Packit 6f3914
Packit 6f3914
    def matchcallback(self, po, values, matchfor=None, verbose=None,
Packit 6f3914
                      highlight=None):
Packit 6f3914
        """Output search/provides type callback matches.
Packit 6f3914
Packit 6f3914
        :param po: the package object that matched the search
Packit 6f3914
        :param values: the information associated with *po* that
Packit 6f3914
           matched the search
Packit 6f3914
        :param matchfor: a list of strings to be highlighted in the
Packit 6f3914
           output
Packit 6f3914
        :param verbose: whether to output extra verbose information
Packit 6f3914
        :param highlight: highlighting options for the highlighted matches
Packit 6f3914
        """
Packit 6f3914
        def print_highlighted_key_item(key, item, printed_headline, can_overflow=False):
Packit 6f3914
            if not printed_headline:
Packit 6f3914
                print(_('Matched from:'))
Packit 6f3914
            item = ucd(item) or ""
Packit 6f3914
            if item == "":
Packit 6f3914
                return
Packit 6f3914
            if matchfor:
Packit 6f3914
                item = self._sub_highlight(item, highlight, matchfor, ignore_case=True)
Packit 6f3914
            if can_overflow:
Packit 6f3914
                print(self.fmtKeyValFill(key, item))
Packit 6f3914
            else:
Packit 6f3914
                print(key % item)
Packit 6f3914
Packit 6f3914
        def print_file_provides(item, printed_match):
Packit 6f3914
            if not self.FILE_PROVIDE_RE.match(item):
Packit 6f3914
                return False
Packit 6f3914
            key = _("Filename    : %s")
Packit 6f3914
            file_match = False
Packit 6f3914
            for filename in po.files:
Packit 6f3914
                if fnmatch.fnmatch(filename, item):
Packit 6f3914
                    print_highlighted_key_item(
Packit 6f3914
                        key, filename, file_match or printed_match, can_overflow=False)
Packit 6f3914
                    file_match = True
Packit 6f3914
            return file_match
Packit 6f3914
Packit 6f3914
        if self.conf.showdupesfromrepos:
Packit 6f3914
            msg = '%s : ' % po
Packit 6f3914
        else:
Packit 6f3914
            msg = '%s.%s : ' % (po.name, po.arch)
Packit 6f3914
        msg = self.fmtKeyValFill(msg, po.summary or "")
Packit 6f3914
        if matchfor:
Packit 6f3914
            if highlight is None:
Packit 6f3914
                highlight = self.conf.color_search_match
Packit 6f3914
            msg = self._sub_highlight(msg, highlight, matchfor, ignore_case=True)
Packit 6f3914
        print(msg)
Packit 6f3914
Packit 6f3914
        if verbose is None:
Packit 6f3914
            verbose = self.conf.verbose
Packit 6f3914
        if not verbose:
Packit 6f3914
            return
Packit 6f3914
Packit 6f3914
        print(_("Repo        : %s") % po.ui_from_repo)
Packit 6f3914
        printed_match = False
Packit 6f3914
        name_match = False
Packit 6f3914
        for item in set(values):
Packit 6f3914
            if po.summary == item:
Packit 6f3914
                name_match = True
Packit 6f3914
                continue # Skip double name/summary printing
Packit 6f3914
Packit 6f3914
            if po.description == item:
Packit 6f3914
                key = _("Description : ")
Packit 6f3914
                print_highlighted_key_item(key, item, printed_match, can_overflow=True)
Packit 6f3914
                printed_match = True
Packit 6f3914
            elif po.url == item:
Packit 6f3914
                key = _("URL         : %s")
Packit 6f3914
                print_highlighted_key_item(key, item, printed_match, can_overflow=False)
Packit 6f3914
                printed_match = True
Packit 6f3914
            elif po.license == item:
Packit 6f3914
                key = _("License     : %s")
Packit 6f3914
                print_highlighted_key_item(key, item, printed_match, can_overflow=False)
Packit 6f3914
                printed_match = True
Packit 6f3914
            elif print_file_provides(item, printed_match):
Packit 6f3914
                printed_match = True
Packit 6f3914
            else:
Packit 6f3914
                key = _("Provide    : %s")
Packit 6f3914
                for provide in po.provides:
Packit 6f3914
                    provide = str(provide)
Packit 6f3914
                    if fnmatch.fnmatch(provide, item):
Packit 6f3914
                        print_highlighted_key_item(key, provide, printed_match, can_overflow=False)
Packit 6f3914
                        printed_match = True
Packit 6f3914
                    else:
Packit 6f3914
                        first_provide = provide.split()[0]
Packit 6f3914
                        possible = set('=<>')
Packit 6f3914
                        if any((char in possible) for char in item):
Packit 6f3914
                            item_new = item.split()[0]
Packit 6f3914
                        else:
Packit 6f3914
                            item_new = item
Packit 6f3914
                        if fnmatch.fnmatch(first_provide, item_new):
Packit 6f3914
                            print_highlighted_key_item(
Packit 6f3914
                                key, provide, printed_match, can_overflow=False)
Packit 6f3914
                            printed_match = True
Packit 6f3914
Packit 6f3914
        if not any([printed_match, name_match]):
Packit 6f3914
            for item in set(values):
Packit 6f3914
                key = _("Other       : %s")
Packit 6f3914
                print_highlighted_key_item(key, item, printed_match, can_overflow=False)
Packit 6f3914
        print()
Packit 6f3914
Packit 6f3914
    def matchcallback_verbose(self, po, values, matchfor=None):
Packit 6f3914
        """Output search/provides type callback matches.  This will
Packit 6f3914
        output more information than :func:`matchcallback`.
Packit 6f3914
Packit 6f3914
        :param po: the package object that matched the search
Packit 6f3914
        :param values: the information associated with *po* that
Packit 6f3914
           matched the search
Packit 6f3914
        :param matchfor: a list of strings to be highlighted in the
Packit 6f3914
           output
Packit 6f3914
        """
Packit 6f3914
        return self.matchcallback(po, values, matchfor, verbose=True)
Packit 6f3914
Packit 6f3914
    def reportDownloadSize(self, packages, installonly=False):
Packit 6f3914
        """Report the total download size for a set of packages
Packit 6f3914
Packit 6f3914
        :param packages: a list of package objects
Packit 6f3914
        :param installonly: whether the transaction consists only of installations
Packit 6f3914
        """
Packit 6f3914
        totsize = 0
Packit 6f3914
        locsize = 0
Packit 6f3914
        insize = 0
Packit 6f3914
        error = False
Packit 6f3914
        for pkg in packages:
Packit 6f3914
            # Just to be on the safe side, if for some reason getting
Packit 6f3914
            # the package size fails, log the error and don't report download
Packit 6f3914
            # size
Packit 6f3914
            try:
Packit 6f3914
                size = int(pkg._size)
Packit 6f3914
                totsize += size
Packit 6f3914
                try:
Packit 6f3914
                    if pkg.verifyLocalPkg():
Packit 6f3914
                        locsize += size
Packit 6f3914
                except Exception:
Packit 6f3914
                    pass
Packit 6f3914
Packit 6f3914
                if not installonly:
Packit 6f3914
                    continue
Packit 6f3914
Packit 6f3914
                try:
Packit 6f3914
                    size = int(pkg.installsize)
Packit 6f3914
                except Exception:
Packit 6f3914
                    pass
Packit 6f3914
                insize += size
Packit 6f3914
            except Exception:
Packit 6f3914
                error = True
Packit 6f3914
                msg = _('There was an error calculating total download size')
Packit 6f3914
                logger.error(msg)
Packit 6f3914
                break
Packit 6f3914
Packit 6f3914
        if not error:
Packit 6f3914
            if locsize:
Packit 6f3914
                logger.info(_("Total size: %s"),
Packit 6f3914
                                        format_number(totsize))
Packit 6f3914
            if locsize != totsize:
Packit 6f3914
                logger.info(_("Total download size: %s"),
Packit 6f3914
                                        format_number(totsize - locsize))
Packit 6f3914
            if installonly:
Packit 6f3914
                logger.info(_("Installed size: %s"), format_number(insize))
Packit 6f3914
Packit 6f3914
    def reportRemoveSize(self, packages):
Packit 6f3914
        """Report the total size of packages being removed.
Packit 6f3914
Packit 6f3914
        :param packages: a list of package objects
Packit 6f3914
        """
Packit 6f3914
        totsize = 0
Packit 6f3914
        error = False
Packit 6f3914
        for pkg in packages:
Packit 6f3914
            # Just to be on the safe side, if for some reason getting
Packit 6f3914
            # the package size fails, log the error and don't report download
Packit 6f3914
            # size
Packit 6f3914
            try:
Packit 6f3914
                size = pkg._size
Packit 6f3914
                totsize += size
Packit 6f3914
            except Exception:
Packit 6f3914
                error = True
Packit 6f3914
                msg = _('There was an error calculating installed size')
Packit 6f3914
                logger.error(msg)
Packit 6f3914
                break
Packit 6f3914
        if not error:
Packit 6f3914
            logger.info(_("Freed space: %s"), format_number(totsize))
Packit 6f3914
Packit 6f3914
    def list_group_transaction(self, comps, history, diff):
Packit 6f3914
        if not diff:
Packit 6f3914
            return None
Packit 6f3914
Packit 6f3914
        out = []
Packit 6f3914
        rows = []
Packit 6f3914
        if diff.new_groups:
Packit 6f3914
            out.append(_('Marking packages as installed by the group:'))
Packit 6f3914
        for grp_id in diff.new_groups:
Packit 6f3914
            pkgs = list(diff.added_packages(grp_id))
Packit 6f3914
            group_object = comps._group_by_id(grp_id)
Packit 6f3914
            grp_name = group_object.ui_name if group_object else grp_id
Packit 6f3914
            rows.extend(_spread_in_columns(4, "@" + grp_name, pkgs))
Packit 6f3914
        if diff.removed_groups:
Packit 6f3914
            out.append(_('Marking packages as removed by the group:'))
Packit 6f3914
        for grp_id in diff.removed_groups:
Packit 6f3914
            pkgs = list(diff.removed_packages(grp_id))
Packit 6f3914
            grp_name = history.group.get(grp_id).ui_name
Packit 6f3914
            rows.extend(_spread_in_columns(4, "@" + grp_name, pkgs))
Packit 6f3914
Packit 6f3914
        if rows:
Packit 6f3914
            col_data = self._col_widths(rows)
Packit 6f3914
            for row in rows:
Packit 6f3914
                out.append(self.fmtColumns(zip(row, col_data), ' '))
Packit 6f3914
            out[0:0] = self._banner(col_data, (_('Group'), _('Packages'), '', ''))
Packit 6f3914
        return '\n'.join(out)
Packit 6f3914
Packit 6f3914
    def _skipped_packages(self, report_problems):
Packit 6f3914
        """returns set of conflicting packages and set of packages with broken dependency that would
Packit 6f3914
        be additionally installed when --best and --allowerasing"""
Packit 6f3914
        if self.base._goal.actions & (hawkey.INSTALL | hawkey.UPGRADE | hawkey.UPGRADE_ALL):
Packit 6f3914
            best = True
Packit 6f3914
        else:
Packit 6f3914
            best = False
Packit 6f3914
        ng = deepcopy(self.base._goal)
Packit 6f3914
        params = {"allow_uninstall": self.base._allow_erasing,
Packit 6f3914
                  "force_best": best,
Packit 6f3914
                  "ignore_weak": True}
Packit 6f3914
        ret = ng.run(**params)
Packit 6f3914
        if not ret and report_problems:
Packit 6f3914
            msg = dnf.util._format_resolve_problems(ng.problem_rules())
Packit 6f3914
            logger.warning(msg)
Packit 6f3914
        problem_conflicts = set(ng.problem_conflicts(available=True))
Packit 6f3914
        problem_dependency = set(ng.problem_broken_dependency(available=True)) - problem_conflicts
Packit 6f3914
        return problem_conflicts, problem_dependency
Packit 6f3914
Packit 6f3914
    def list_transaction(self, transaction, total_width=None):
Packit 6f3914
        """Return a string representation of the transaction in an
Packit 6f3914
        easy-to-read format.
Packit 6f3914
        """
Packit 6f3914
        forward_actions = hawkey.UPGRADE | hawkey.UPGRADE_ALL | hawkey.DISTUPGRADE | \
Packit 6f3914
            hawkey.DISTUPGRADE_ALL | hawkey.DOWNGRADE | hawkey.INSTALL
Packit 6f3914
        skipped_conflicts = set()
Packit 6f3914
        skipped_broken = set()
Packit 6f3914
Packit 6f3914
        if transaction is None:
Packit 6f3914
            # set empty transaction list instead of returning None
Packit 6f3914
            # in order to display module changes when RPM transaction is empty
Packit 6f3914
            transaction = []
Packit 6f3914
Packit 6f3914
        list_bunch = _make_lists(transaction, self.base._goal)
Packit 6f3914
        pkglist_lines = []
Packit 6f3914
        data = {'n' : {}, 'v' : {}, 'r' : {}}
Packit 6f3914
        a_wid = 0 # Arch can't get "that big" ... so always use the max.
Packit 6f3914
Packit 6f3914
        def _add_line(lines, data, a_wid, po, obsoletes=[]):
Packit 6f3914
            (n, a, e, v, r) = po.pkgtup
Packit 6f3914
            evr = po.evr
Packit 6f3914
            repoid = po._from_repo
Packit 6f3914
            size = format_number(po._size)
Packit 6f3914
Packit 6f3914
            if a is None: # gpgkeys are weird
Packit 6f3914
                a = 'noarch'
Packit 6f3914
Packit 6f3914
            # none, partial, full?
Packit 6f3914
            if po._from_system:
Packit 6f3914
                hi = self.conf.color_update_installed
Packit 6f3914
            elif po._from_cmdline:
Packit 6f3914
                hi = self.conf.color_update_local
Packit 6f3914
            else:
Packit 6f3914
                hi = self.conf.color_update_remote
Packit 6f3914
            lines.append((n, a, evr, repoid, size, obsoletes, hi))
Packit 6f3914
            #  Create a dict of field_length => number of packages, for
Packit 6f3914
            # each field.
Packit 6f3914
            for (d, v) in (("n", len(n)), ("v", len(evr)), ("r", len(repoid))):
Packit 6f3914
                data[d].setdefault(v, 0)
Packit 6f3914
                data[d][v] += 1
Packit 6f3914
            a_wid = max(a_wid, len(a))
Packit 6f3914
            return a_wid
Packit 6f3914
        ins_group_msg = _('Installing group/module packages') if dnf.base.WITH_MODULES \
Packit 6f3914
            else _('Installing group packages')
Packit 6f3914
Packit 6f3914
        for (action, pkglist) in [
Packit 6f3914
                # TRANSLATORS: This is for a list of packages to be installed.
Packit 6f3914
                (C_('summary', 'Installing'), list_bunch.installed),
Packit 6f3914
                # TRANSLATORS: This is for a list of packages to be upgraded.
Packit 6f3914
                (C_('summary', 'Upgrading'), list_bunch.upgraded),
Packit 6f3914
                # TRANSLATORS: This is for a list of packages to be reinstalled.
Packit 6f3914
                (C_('summary', 'Reinstalling'), list_bunch.reinstalled),
Packit 6f3914
                (ins_group_msg, list_bunch.installed_group),
Packit 6f3914
                (_('Installing dependencies'), list_bunch.installed_dep),
Packit 6f3914
                (_('Installing weak dependencies'), list_bunch.installed_weak),
Packit 6f3914
                # TRANSLATORS: This is for a list of packages to be removed.
Packit 6f3914
                (_('Removing'), list_bunch.erased),
Packit 6f3914
                (_('Removing dependent packages'), list_bunch.erased_dep),
Packit 6f3914
                (_('Removing unused dependencies'), list_bunch.erased_clean),
Packit 6f3914
                # TRANSLATORS: This is for a list of packages to be downgraded.
Packit 6f3914
                (C_('summary', 'Downgrading'), list_bunch.downgraded)]:
Packit 6f3914
            lines = []
Packit 6f3914
Packit 6f3914
            # build a reverse mapping to 'replaced_by'
Packit 6f3914
            # this is required to achieve reasonable speed
Packit 6f3914
            replaces = {}
Packit 6f3914
            for tsi in transaction:
Packit 6f3914
                if tsi.action != libdnf.transaction.TransactionItemAction_OBSOLETED:
Packit 6f3914
                    continue
Packit 6f3914
                for i in tsi._item.getReplacedBy():
Packit 6f3914
                    replaces.setdefault(i, set()).add(tsi)
Packit 6f3914
Packit 6f3914
            for tsi in pkglist:
Packit 6f3914
                if tsi.action not in dnf.transaction.FORWARD_ACTIONS + [libdnf.transaction.TransactionItemAction_REMOVE]:
Packit 6f3914
                    continue
Packit 6f3914
Packit 6f3914
                # get TransactionItems obsoleted by tsi
Packit 6f3914
                obsoleted = sorted(replaces.get(tsi._item, []))
Packit 6f3914
Packit 6f3914
                a_wid = _add_line(lines, data, a_wid, tsi.pkg, obsoleted)
Packit 6f3914
Packit 6f3914
            pkglist_lines.append((action, lines))
Packit 6f3914
Packit 6f3914
        installedProfiles = sorted(dict(self.base._moduleContainer.getInstalledProfiles()).items())
Packit 6f3914
        if installedProfiles:
Packit 6f3914
            action = _("Installing module profiles")
Packit 6f3914
            lines = []
Packit 6f3914
            for name, profiles in installedProfiles:
Packit 6f3914
                for profile in list(profiles):
Packit 6f3914
                    lines.append(("%s/%s" % (name, profile), "", "", "", "", "", ""))
Packit 6f3914
            pkglist_lines.append((action, lines))
Packit 6f3914
Packit 6f3914
        removedProfiles = sorted(dict(self.base._moduleContainer.getRemovedProfiles()).items())
Packit 6f3914
        if removedProfiles:
Packit 6f3914
            action = _("Disabling module profiles")
Packit 6f3914
            lines = []
Packit 6f3914
            for name, profiles in removedProfiles:
Packit 6f3914
                for profile in list(profiles):
Packit 6f3914
                    lines.append(("%s/%s" % (name, profile), "", "", "", "", "", ""))
Packit 6f3914
            pkglist_lines.append((action, lines))
Packit 6f3914
Packit 6f3914
        enabledStreams = sorted(dict(self.base._moduleContainer.getEnabledStreams()).items())
Packit 6f3914
        if enabledStreams:
Packit 6f3914
            action = _("Enabling module streams")
Packit 6f3914
            lines = []
Packit 6f3914
            for name, stream in enabledStreams:
Packit 6f3914
                lines.append((name, "", stream, "", "", "", ""))
Packit 6f3914
            pkglist_lines.append((action, lines))
Packit 6f3914
Packit 6f3914
        switchedStreams = sorted(dict(self.base._moduleContainer.getSwitchedStreams()).items())
Packit 6f3914
        if switchedStreams:
Packit 6f3914
            action = _("Switching module streams")
Packit 6f3914
            lines = []
Packit 6f3914
            for name, stream in switchedStreams:
Packit 6f3914
                lines.append((name, "", "%s -> %s" % (stream[0], stream[1]), "", "", "", ""))
Packit 6f3914
            pkglist_lines.append((action, lines))
Packit 6f3914
Packit 6f3914
        disabledModules = sorted(list(self.base._moduleContainer.getDisabledModules()))
Packit 6f3914
        if disabledModules:
Packit 6f3914
            action = _("Disabling modules")
Packit 6f3914
            lines = []
Packit 6f3914
            for name in disabledModules:
Packit 6f3914
                lines.append((name, "", "", "", "", "", ""))
Packit 6f3914
            pkglist_lines.append((action, lines))
Packit 6f3914
Packit 6f3914
        resetModules = sorted(list(self.base._moduleContainer.getResetModules()))
Packit 6f3914
        if resetModules:
Packit 6f3914
            action = _("Resetting modules")
Packit 6f3914
            lines = []
Packit 6f3914
            for name in resetModules:
Packit 6f3914
                lines.append((name, "", "", "", "", "", ""))
Packit 6f3914
            pkglist_lines.append((action, lines))
Packit 6f3914
        if self.base._history:
Packit 6f3914
            install_env_group = self.base._history.env._installed
Packit 6f3914
            if install_env_group:
Packit 6f3914
                action = _("Installing Environment Groups")
Packit 6f3914
                lines = []
Packit 6f3914
                for group in install_env_group.values():
Packit 6f3914
                    lines.append((group.getName(), "", "", "", "", "", ""))
Packit 6f3914
                pkglist_lines.append((action, lines))
Packit 6f3914
            upgrade_env_group = self.base._history.env._upgraded
Packit 6f3914
            if upgrade_env_group:
Packit 6f3914
                action = _("Upgrading Environment Groups")
Packit 6f3914
                lines = []
Packit 6f3914
                for group in upgrade_env_group.values():
Packit 6f3914
                    lines.append((group.getName(), "", "", "", "", "", ""))
Packit 6f3914
                pkglist_lines.append((action, lines))
Packit 6f3914
            remove_env_group = self.base._history.env._removed
Packit 6f3914
            if remove_env_group:
Packit 6f3914
                action = _("Removing Environment Groups")
Packit 6f3914
                lines = []
Packit 6f3914
                for group in remove_env_group.values():
Packit 6f3914
                    lines.append((group.getName(), "", "", "", "", "", ""))
Packit 6f3914
                pkglist_lines.append((action, lines))
Packit 6f3914
            install_group = self.base._history.group._installed
Packit 6f3914
            if install_group:
Packit 6f3914
                action = _("Installing Groups")
Packit 6f3914
                lines = []
Packit 6f3914
                for group in install_group.values():
Packit 6f3914
                    lines.append((group.getName(), "", "", "", "", "", ""))
Packit 6f3914
                pkglist_lines.append((action, lines))
Packit 6f3914
            upgrade_group = self.base._history.group._upgraded
Packit 6f3914
            if upgrade_group:
Packit 6f3914
                action = _("Upgrading Groups")
Packit 6f3914
                lines = []
Packit 6f3914
                for group in upgrade_group.values():
Packit 6f3914
                    lines.append((group.getName(), "", "", "", "", "", ""))
Packit 6f3914
                pkglist_lines.append((action, lines))
Packit 6f3914
            remove_group = self.base._history.group._removed
Packit 6f3914
            if remove_group:
Packit 6f3914
                action = _("Removing Groups")
Packit 6f3914
                lines = []
Packit 6f3914
                for group in remove_group.values():
Packit 6f3914
                    lines.append((group.getName(), "", "", "", "", "", ""))
Packit 6f3914
                pkglist_lines.append((action, lines))
Packit 6f3914
        # show skipped conflicting packages
Packit 6f3914
        if not self.conf.best and self.base._goal.actions & forward_actions:
Packit 6f3914
            lines = []
Packit 6f3914
            skipped_conflicts, skipped_broken = self._skipped_packages(report_problems=True)
Packit 6f3914
            skipped_broken = dict((str(pkg), pkg) for pkg in skipped_broken)
Packit 6f3914
            for pkg in sorted(skipped_conflicts):
Packit 6f3914
                a_wid = _add_line(lines, data, a_wid, pkg, [])
Packit 6f3914
            recommendations = ["--best"]
Packit 6f3914
            if not self.base._allow_erasing:
Packit 6f3914
                recommendations.append("--allowerasing")
Packit 6f3914
            skip_str = _("Skipping packages with conflicts:\n"
Packit 6f3914
                         "(add '%s' to command line "
Packit 6f3914
                         "to force their upgrade)") % " ".join(recommendations)
Packit 6f3914
            pkglist_lines.append((skip_str, lines))
Packit 6f3914
Packit 6f3914
            lines = []
Packit 6f3914
            for nevra, pkg in sorted(skipped_broken.items()):
Packit 6f3914
                a_wid = _add_line(lines, data, a_wid, pkg, [])
Packit 6f3914
            skip_str = _("Skipping packages with broken dependencies%s")
Packit 6f3914
            if self.base.conf.upgrade_group_objects_upgrade:
Packit 6f3914
                skip_str = skip_str % ""
Packit 6f3914
            else:
Packit 6f3914
                skip_str = skip_str % _(" or part of a group")
Packit 6f3914
Packit 6f3914
            pkglist_lines.append((skip_str, lines))
Packit 6f3914
Packit 6f3914
        if not data['n'] and not self.base._moduleContainer.isChanged() and not \
Packit 6f3914
                (self.base._history and (self.base._history.group or self.base._history.env)):
Packit 6f3914
            return u''
Packit 6f3914
        else:
Packit 6f3914
            data = [data['n'], {}, data['v'], data['r'], {}]
Packit 6f3914
            columns = [1, a_wid, 1, 1, 5]
Packit 6f3914
            columns = self.calcColumns(data, indent="  ", columns=columns,
Packit 6f3914
                                       remainder_column=2, total_width=total_width)
Packit 6f3914
            (n_wid, a_wid, v_wid, r_wid, s_wid) = columns
Packit 6f3914
Packit 6f3914
            # Do not use 'Package' without context. Using context resolves
Packit 6f3914
            # RhBug 1302935 as a side effect.
Packit 6f3914
            msg_package = select_short_long(n_wid,
Packit 6f3914
            # Translators: This is the short version of 'Package'. You can
Packit 6f3914
            # use the full (unabbreviated) term 'Package' if you think that
Packit 6f3914
            # the translation to your language is not too long and will
Packit 6f3914
            # always fit to limited space.
Packit 6f3914
                                            C_('short', 'Package'),
Packit 6f3914
            # Translators: This is the full (unabbreviated) term 'Package'.
Packit 6f3914
                                            C_('long', 'Package'))
Packit 6f3914
            msg_arch = select_short_long(a_wid,
Packit 6f3914
            # Translators: This is abbreviated 'Architecture', used when
Packit 6f3914
            # we have not enough space to display the full word.
Packit 6f3914
                                         C_('short', 'Arch'),
Packit 6f3914
            # Translators: This is the full word 'Architecture', used when
Packit 6f3914
            # we have enough space.
Packit 6f3914
                                         C_('long', 'Architecture'))
Packit 6f3914
            msg_version = select_short_long(v_wid,
Packit 6f3914
            # Translators: This is the short version of 'Version'. You can
Packit 6f3914
            # use the full (unabbreviated) term 'Version' if you think that
Packit 6f3914
            # the translation to your language is not too long and will
Packit 6f3914
            # always fit to limited space.
Packit 6f3914
                                            C_('short', 'Version'),
Packit 6f3914
            # Translators: This is the full (unabbreviated) term 'Version'.
Packit 6f3914
                                            C_('long', 'Version'))
Packit 6f3914
            msg_repository = select_short_long(r_wid,
Packit 6f3914
            # Translators: This is abbreviated 'Repository', used when
Packit 6f3914
            # we have not enough space to display the full word.
Packit 6f3914
                                               C_('short', 'Repo'),
Packit 6f3914
            # Translators: This is the full word 'Repository', used when
Packit 6f3914
            # we have enough space.
Packit 6f3914
                                               C_('long', 'Repository'))
Packit 6f3914
            msg_size = select_short_long(s_wid,
Packit 6f3914
            # Translators: This is the short version of 'Size'. It should
Packit 6f3914
            # not be longer than 5 characters. If the term 'Size' in your
Packit 6f3914
            # language is not longer than 5 characters then you can use it
Packit 6f3914
            # unabbreviated.
Packit 6f3914
                                         C_('short', 'Size'),
Packit 6f3914
            # Translators: This is the full (unabbreviated) term 'Size'.
Packit 6f3914
                                         C_('long', 'Size'))
Packit 6f3914
Packit 6f3914
            out = [u"%s\n%s\n%s\n" % ('=' * self.term.columns,
Packit 6f3914
                                      self.fmtColumns(((msg_package, -n_wid),
Packit 6f3914
                                                       (msg_arch, -a_wid),
Packit 6f3914
                                                       (msg_version, -v_wid),
Packit 6f3914
                                                       (msg_repository, -r_wid),
Packit 6f3914
                                                       (msg_size, s_wid)), u" "),
Packit 6f3914
                                      '=' * self.term.columns)]
Packit 6f3914
Packit 6f3914
        for (action, lines) in pkglist_lines:
Packit 6f3914
            if lines:
Packit 6f3914
                totalmsg = u"%s:\n" % action
Packit 6f3914
            for (n, a, evr, repoid, size, obsoletes, hi) in lines:
Packit 6f3914
                columns = ((n, -n_wid, hi), (a, -a_wid),
Packit 6f3914
                           (evr, -v_wid), (repoid, -r_wid), (size, s_wid))
Packit 6f3914
                msg = self.fmtColumns(columns, u" ", u"\n")
Packit 6f3914
                hibeg, hiend = self._highlight(self.conf.color_update_installed)
Packit 6f3914
                for obspo in sorted(obsoletes):
Packit 6f3914
                    appended = '     ' + _('replacing') + '  %s%s%s.%s %s\n'
Packit 6f3914
                    appended %= (hibeg, obspo.name, hiend, obspo.arch, obspo.evr)
Packit 6f3914
                    msg += appended
Packit 6f3914
                totalmsg = totalmsg + msg
Packit 6f3914
Packit 6f3914
            if lines:
Packit 6f3914
                out.append(totalmsg)
Packit 6f3914
Packit 6f3914
        out.append(_("""
Packit 6f3914
Transaction Summary
Packit 6f3914
%s
Packit 6f3914
""") % ('=' * self.term.columns))
Packit 6f3914
        summary_data = (
Packit 6f3914
            (_('Install'), len(list_bunch.installed) +
Packit 6f3914
             len(list_bunch.installed_group) +
Packit 6f3914
             len(list_bunch.installed_weak) +
Packit 6f3914
             len(list_bunch.installed_dep), 0),
Packit 6f3914
            (_('Upgrade'), len(list_bunch.upgraded), 0),
Packit 6f3914
            (_('Remove'), len(list_bunch.erased) + len(list_bunch.erased_dep) +
Packit 6f3914
             len(list_bunch.erased_clean), 0),
Packit 6f3914
            (_('Downgrade'), len(list_bunch.downgraded), 0),
Packit 6f3914
            (_('Skip'), len(skipped_conflicts) + len(skipped_broken), 0))
Packit 6f3914
        max_msg_action = 0
Packit 6f3914
        max_msg_count = 0
Packit 6f3914
        max_msg_pkgs = 0
Packit 6f3914
        max_msg_depcount = 0
Packit 6f3914
        for action, count, depcount in summary_data:
Packit 6f3914
            if not count and not depcount:
Packit 6f3914
                continue
Packit 6f3914
Packit 6f3914
            msg_pkgs = P_('Package', 'Packages', count)
Packit 6f3914
            len_msg_action = exact_width(action)
Packit 6f3914
            len_msg_count = exact_width(unicode(count))
Packit 6f3914
            len_msg_pkgs = exact_width(msg_pkgs)
Packit 6f3914
Packit 6f3914
            if depcount:
Packit 6f3914
                len_msg_depcount = exact_width(unicode(depcount))
Packit 6f3914
            else:
Packit 6f3914
                len_msg_depcount = 0
Packit 6f3914
Packit 6f3914
            max_msg_action = max(len_msg_action, max_msg_action)
Packit 6f3914
            max_msg_count = max(len_msg_count, max_msg_count)
Packit 6f3914
            max_msg_pkgs = max(len_msg_pkgs, max_msg_pkgs)
Packit 6f3914
            max_msg_depcount = max(len_msg_depcount, max_msg_depcount)
Packit 6f3914
Packit 6f3914
        for action, count, depcount in summary_data:
Packit 6f3914
            msg_pkgs = P_('Package', 'Packages', count)
Packit 6f3914
            if depcount:
Packit 6f3914
                msg_deppkgs = P_('Dependent package', 'Dependent packages',
Packit 6f3914
                                 depcount)
Packit 6f3914
                action_msg = fill_exact_width(action, max_msg_action)
Packit 6f3914
                if count:
Packit 6f3914
                    msg = '%s  %*d %s (+%*d %s)\n'
Packit 6f3914
                    out.append(msg % (action_msg,
Packit 6f3914
                                      max_msg_count, count,
Packit 6f3914
                                      "%-*s" % (max_msg_pkgs, msg_pkgs),
Packit 6f3914
                                      max_msg_depcount, depcount, msg_deppkgs))
Packit 6f3914
                else:
Packit 6f3914
                    msg = '%s  %s  ( %*d %s)\n'
Packit 6f3914
                    out.append(msg % (action_msg,
Packit 6f3914
                                      (max_msg_count + max_msg_pkgs) * ' ',
Packit 6f3914
                                      max_msg_depcount, depcount, msg_deppkgs))
Packit 6f3914
            elif count:
Packit 6f3914
                msg = '%s  %*d %s\n'
Packit 6f3914
                out.append(msg % (fill_exact_width(action, max_msg_action),
Packit 6f3914
                                  max_msg_count, count, msg_pkgs))
Packit 6f3914
        return ''.join(out)
Packit 6f3914
Packit 6f3914
    def post_transaction_output(self, transaction):
Packit 6f3914
        """Returns a human-readable summary of the results of the
Packit 6f3914
        transaction.
Packit 6f3914
Packit 6f3914
        :return: a string containing a human-readable summary of the
Packit 6f3914
           results of the transaction
Packit 6f3914
        """
Packit 6f3914
        #  Works a bit like calcColumns, but we never overflow a column we just
Packit 6f3914
        # have a dynamic number of columns.
Packit 6f3914
        def _fits_in_cols(msgs, num):
Packit 6f3914
            """ Work out how many columns we can use to display stuff, in
Packit 6f3914
                the post trans output. """
Packit 6f3914
            if len(msgs) < num:
Packit 6f3914
                return []
Packit 6f3914
Packit 6f3914
            left = self.term.columns - ((num - 1) + 2)
Packit 6f3914
            if left <= 0:
Packit 6f3914
                return []
Packit 6f3914
Packit 6f3914
            col_lens = [0] * num
Packit 6f3914
            col = 0
Packit 6f3914
            for msg in msgs:
Packit 6f3914
                if len(msg) > col_lens[col]:
Packit 6f3914
                    diff = (len(msg) - col_lens[col])
Packit 6f3914
                    if left <= diff:
Packit 6f3914
                        return []
Packit 6f3914
                    left -= diff
Packit 6f3914
                    col_lens[col] = len(msg)
Packit 6f3914
                col += 1
Packit 6f3914
                col %= len(col_lens)
Packit 6f3914
Packit 6f3914
            for col in range(len(col_lens)):
Packit 6f3914
                col_lens[col] += left // num
Packit 6f3914
                col_lens[col] *= -1
Packit 6f3914
            return col_lens
Packit 6f3914
Packit 6f3914
        out = ''
Packit 6f3914
        list_bunch = _make_lists(transaction, self.base._goal)
Packit 6f3914
        skipped_conflicts, skipped_broken = self._skipped_packages(report_problems=False)
Packit 6f3914
        skipped = skipped_conflicts.union(skipped_broken)
Packit 6f3914
        skipped = sorted(set([str(pkg) for pkg in skipped]))
Packit 6f3914
Packit 6f3914
        for (action, tsis) in [(_('Upgraded'), list_bunch.upgraded),
Packit 6f3914
                               (_('Downgraded'), list_bunch.downgraded),
Packit 6f3914
                               (_('Installed'), list_bunch.installed +
Packit 6f3914
                                list_bunch.installed_group +
Packit 6f3914
                                list_bunch.installed_weak +
Packit 6f3914
                                list_bunch.installed_dep),
Packit 6f3914
                               (_('Reinstalled'), list_bunch.reinstalled),
Packit 6f3914
                               (_('Skipped'), skipped),
Packit 6f3914
                               (_('Removed'), list_bunch.erased +
Packit 6f3914
                                   list_bunch.erased_dep +
Packit 6f3914
                                   list_bunch.erased_clean),
Packit 6f3914
                               (_('Failed'), list_bunch.failed)]:
Packit 6f3914
            if not tsis:
Packit 6f3914
                continue
Packit 6f3914
            msgs = []
Packit 6f3914
            out += '\n%s:\n' % action
Packit 6f3914
            for tsi in tsis:
Packit 6f3914
                msgs.append(str(tsi))
Packit 6f3914
            for num in (8, 7, 6, 5, 4, 3, 2):
Packit 6f3914
                cols = _fits_in_cols(msgs, num)
Packit 6f3914
                if cols:
Packit 6f3914
                    break
Packit 6f3914
            if not cols:
Packit 6f3914
                cols = [-(self.term.columns - 2)]
Packit 6f3914
            while msgs:
Packit 6f3914
                current_msgs = msgs[:len(cols)]
Packit 6f3914
                out += '  '
Packit 6f3914
                out += self.fmtColumns(zip(current_msgs, cols), end=u'\n')
Packit 6f3914
                msgs = msgs[len(cols):]
Packit 6f3914
Packit 6f3914
        return out
Packit 6f3914
Packit 6f3914
    def setup_progress_callbacks(self):
Packit 6f3914
        """Set up the progress callbacks and various
Packit 6f3914
           output bars based on debug level.
Packit 6f3914
        """
Packit 6f3914
        progressbar = None
Packit 6f3914
        if self.conf.debuglevel >= 2:
Packit 6f3914
            progressbar = dnf.cli.progress.MultiFileProgressMeter(fo=sys.stdout)
Packit 6f3914
            self.progress = dnf.cli.progress.MultiFileProgressMeter(fo=sys.stdout)
Packit 6f3914
Packit 6f3914
        # setup our depsolve progress callback
Packit 6f3914
        return (progressbar, DepSolveProgressCallBack())
Packit 6f3914
Packit 6f3914
    def download_callback_total_cb(self, remote_size, download_start_timestamp):
Packit 6f3914
        """Outputs summary information about the download process.
Packit 6f3914
Packit 6f3914
        :param remote_size: the total amount of information that was
Packit 6f3914
           downloaded, in bytes
Packit 6f3914
        :param download_start_timestamp: the time when the download
Packit 6f3914
           process started, in seconds since the epoch
Packit 6f3914
        """
Packit 6f3914
        if remote_size <= 0:
Packit 6f3914
            return
Packit 6f3914
Packit 6f3914
        width = self.term.columns
Packit 6f3914
        logger.info("-" * width)
Packit 6f3914
        dl_time = max(0.01, time.time() - download_start_timestamp)
Packit 6f3914
        msg = ' %5sB/s | %5sB %9s     ' % (
Packit 6f3914
            format_number(remote_size // dl_time),
Packit 6f3914
            format_number(remote_size),
Packit 6f3914
            format_time(dl_time))
Packit 6f3914
        msg = fill_exact_width(_("Total"), width - len(msg)) + msg
Packit 6f3914
        logger.info(msg)
Packit 6f3914
Packit 6f3914
    def _history_uiactions(self, hpkgs):
Packit 6f3914
        actions = set()
Packit 6f3914
        actions_short = set()
Packit 6f3914
        count = 0
Packit 6f3914
        for pkg in hpkgs:
Packit 6f3914
            if pkg.action in (libdnf.transaction.TransactionItemAction_UPGRADED, libdnf.transaction.TransactionItemAction_DOWNGRADED):
Packit 6f3914
                # skip states we don't want to display in user input
Packit 6f3914
                continue
Packit 6f3914
            actions.add(pkg.action_name)
Packit 6f3914
            actions_short.add(pkg.action_short)
Packit 6f3914
            count += 1
Packit 6f3914
Packit 6f3914
        if len(actions) > 1:
Packit 6f3914
            return count, ", ".join(sorted(actions_short))
Packit 6f3914
Packit 6f3914
        # So empty transactions work, although that "shouldn't" really happen
Packit 6f3914
        return count, "".join(list(actions))
Packit 6f3914
Packit 6f3914
    def _pwd_ui_username(self, uid, limit=None):
Packit 6f3914
        if isinstance(uid, list):
Packit 6f3914
            return [self._pwd_ui_username(u, limit) for u in uid]
Packit 6f3914
Packit 6f3914
        # loginuid is set to      -1 (0xFFFF_FFFF) on init, in newer kernels.
Packit 6f3914
        # loginuid is set to INT_MAX (0x7FFF_FFFF) on init, in older kernels.
Packit 6f3914
        if uid is None or uid in (0xFFFFFFFF, 0x7FFFFFFF):
Packit 6f3914
            loginid = _("<unset>")
Packit 6f3914
            name = _("System") + " " + loginid
Packit 6f3914
            if limit is not None and len(name) > limit:
Packit 6f3914
                name = loginid
Packit 6f3914
            return ucd(name)
Packit 6f3914
Packit 6f3914
        def _safe_split_0(text, *args):
Packit 6f3914
            """ Split gives us a [0] for everything _but_ '', this function
Packit 6f3914
                returns '' in that case. """
Packit 6f3914
            ret = text.split(*args)
Packit 6f3914
            if not ret:
Packit 6f3914
                return ''
Packit 6f3914
            return ret[0]
Packit 6f3914
Packit 6f3914
        try:
Packit 6f3914
            user = pwd.getpwuid(int(uid))
Packit 6f3914
            fullname = _safe_split_0(ucd(user.pw_gecos), ';', 2)
Packit 6f3914
            user_name = ucd(user.pw_name)
Packit 6f3914
            name = "%s <%s>" % (fullname, user_name)
Packit 6f3914
            if limit is not None and len(name) > limit:
Packit 6f3914
                name = "%s ... <%s>" % (_safe_split_0(fullname), user_name)
Packit 6f3914
                if len(name) > limit:
Packit 6f3914
                    name = "<%s>" % user_name
Packit 6f3914
            return name
Packit 6f3914
        except KeyError:
Packit 6f3914
            return ucd(uid)
Packit 6f3914
Packit 6f3914
    def historyListCmd(self, tids):
Packit 6f3914
        """Output a list of information about the history of yum
Packit 6f3914
        transactions.
Packit 6f3914
Packit 6f3914
        :param tids: transaction Ids; lists all transactions if empty
Packit 6f3914
        """
Packit 6f3914
        transactions = self.history.old(tids)
Packit 6f3914
        if self.conf.history_list_view == 'users':
Packit 6f3914
            uids = [1, 2]
Packit 6f3914
        elif self.conf.history_list_view == 'commands':
Packit 6f3914
            uids = [1]
Packit 6f3914
        else:
Packit 6f3914
            assert self.conf.history_list_view == 'single-user-commands'
Packit 6f3914
            uids = set()
Packit 6f3914
            done = 0
Packit 6f3914
            blanks = 0
Packit 6f3914
            for transaction in transactions:
Packit 6f3914
                done += 1
Packit 6f3914
                if transaction.cmdline is None:
Packit 6f3914
                    blanks += 1
Packit 6f3914
                uids.add(transaction.loginuid)
Packit 6f3914
Packit 6f3914
        fmt = "%s | %s | %s | %s | %s"
Packit 6f3914
        if len(uids) == 1:
Packit 6f3914
            name = _("Command line")
Packit 6f3914
        else:
Packit 6f3914
            # TRANSLATORS: user names who executed transaction in history command output
Packit 6f3914
            name = _("User name")
Packit 6f3914
        print(fmt % (fill_exact_width(_("ID"), 6, 6),
Packit 6f3914
                     fill_exact_width(name, 24, 24),
Packit 6f3914
                     fill_exact_width(_("Date and time"), 16, 16),
Packit 6f3914
                     fill_exact_width(_("Action(s)"), 14, 14),
Packit 6f3914
                     fill_exact_width(_("Altered"), 7, 7)))
Packit 6f3914
        print("-" * 79)
Packit 6f3914
        fmt = "%6u | %s | %-16.16s | %s | %4u"
Packit 6f3914
Packit 6f3914
        for transaction in transactions:
Packit 6f3914
            if len(uids) == 1:
Packit 6f3914
                name = transaction.cmdline or ''
Packit 6f3914
            else:
Packit 6f3914
                name = self._pwd_ui_username(transaction.loginuid, 24)
Packit 6f3914
            name = ucd(name)
Packit 6f3914
            tm = time.strftime("%Y-%m-%d %H:%M",
Packit 6f3914
                               time.localtime(transaction.beg_timestamp))
Packit 6f3914
            num, uiacts = self._history_uiactions(transaction.data())
Packit 6f3914
            name = fill_exact_width(name, 24, 24)
Packit 6f3914
            uiacts = fill_exact_width(uiacts, 14, 14)
Packit 6f3914
            rmark = lmark = ' '
Packit 6f3914
            if transaction.return_code is None:
Packit 6f3914
                rmark = lmark = '*'
Packit 6f3914
            elif transaction.return_code:
Packit 6f3914
                rmark = lmark = '#'
Packit 6f3914
                # We don't check .errors, because return_code will be non-0
Packit 6f3914
            elif transaction.is_output:
Packit 6f3914
                rmark = lmark = 'E'
Packit 6f3914
            if transaction.altered_lt_rpmdb:
Packit 6f3914
                rmark = '<'
Packit 6f3914
            if transaction.altered_gt_rpmdb:
Packit 6f3914
                lmark = '>'
Packit 6f3914
            print(fmt % (transaction.tid, name, tm, uiacts, num), "%s%s" % (lmark, rmark))
Packit 6f3914
Packit 6f3914
    def historyInfoCmd(self, tids, pats=[], mtids=set()):
Packit 6f3914
        """Output information about a transaction in history
Packit 6f3914
Packit 6f3914
        :param tids: transaction Ids; prints info for the last transaction if empty
Packit 6f3914
        :raises dnf.exceptions.Error in case no transactions were found
Packit 6f3914
        """
Packit 6f3914
        tids = set(tids)
Packit 6f3914
        last = self.history.last()
Packit 6f3914
        if last is None:
Packit 6f3914
            logger.critical(_('No transactions'))
Packit 6f3914
            raise dnf.exceptions.Error(_('Failed history info'))
Packit 6f3914
Packit 6f3914
        lasttid = last.tid
Packit 6f3914
        lastdbv = last.end_rpmdb_version
Packit 6f3914
Packit 6f3914
        transactions = []
Packit 6f3914
        if not tids:
Packit 6f3914
            last = self.history.last(complete_transactions_only=False)
Packit 6f3914
            if last is not None:
Packit 6f3914
                tids.add(last.tid)
Packit 6f3914
                transactions.append(last)
Packit 6f3914
        else:
Packit 6f3914
            transactions = self.history.old(tids)
Packit 6f3914
Packit 6f3914
        if not tids:
Packit 6f3914
            logger.critical(_('No transaction ID, or package, given'))
Packit 6f3914
            raise dnf.exceptions.Error(_('Failed history info'))
Packit 6f3914
Packit 6f3914
        bmtid, emtid = -1, -1
Packit 6f3914
        mobj = None
Packit 6f3914
        done = False
Packit 6f3914
Packit 6f3914
        if mtids:
Packit 6f3914
            mtids = sorted(mtids)
Packit 6f3914
            bmtid, emtid = mtids.pop()
Packit 6f3914
Packit 6f3914
        for trans in transactions:
Packit 6f3914
            if lastdbv is not None and trans.tid == lasttid:
Packit 6f3914
                #  If this is the last transaction, is good and it doesn't
Packit 6f3914
                # match the current rpmdb ... then mark it as bad.
Packit 6f3914
                rpmdbv = self.sack._rpmdb_version()
Packit 6f3914
                trans.compare_rpmdbv(str(rpmdbv))
Packit 6f3914
            lastdbv = None
Packit 6f3914
Packit 6f3914
            merged = False
Packit 6f3914
Packit 6f3914
            if trans.tid >= bmtid and trans.tid <= emtid:
Packit 6f3914
                if mobj is None:
Packit 6f3914
                    mobj = MergedTransactionWrapper(trans)
Packit 6f3914
                else:
Packit 6f3914
                    mobj.merge(trans)
Packit 6f3914
                merged = True
Packit 6f3914
            elif mobj is not None:
Packit 6f3914
                if done:
Packit 6f3914
                    print("-" * 79)
Packit 6f3914
                done = True
Packit 6f3914
Packit 6f3914
                self._historyInfoCmd(mobj)
Packit 6f3914
                mobj = None
Packit 6f3914
Packit 6f3914
                if mtids:
Packit 6f3914
                    bmtid, emtid = mtids.pop()
Packit 6f3914
                    if trans.tid >= bmtid and trans.tid <= emtid:
Packit 6f3914
                        mobj = trans
Packit 6f3914
                        merged = True
Packit 6f3914
Packit 6f3914
            if not merged:
Packit 6f3914
                if done:
Packit 6f3914
                    print("-" * 79)
Packit 6f3914
                done = True
Packit 6f3914
                self._historyInfoCmd(trans, pats)
Packit 6f3914
Packit 6f3914
        if mobj is not None:
Packit 6f3914
            if done:
Packit 6f3914
                print("-" * 79)
Packit 6f3914
            self._historyInfoCmd(mobj)
Packit 6f3914
Packit 6f3914
    def _historyInfoCmd(self, old, pats=[]):
Packit 6f3914
        loginuid = old.loginuid
Packit 6f3914
        if isinstance(loginuid, int):
Packit 6f3914
            loginuid = [loginuid]
Packit 6f3914
        name = [self._pwd_ui_username(uid) for uid in loginuid]
Packit 6f3914
Packit 6f3914
        _pkg_states_installed = {'i' : _('Installed'), 'e' : _('Erased'),
Packit 6f3914
                                 'o' : _('Upgraded'), 'n' : _('Downgraded')}
Packit 6f3914
        _pkg_states_available = {'i' : _('Installed'), 'e' : _('Not installed'),
Packit 6f3914
                                 'o' : _('Older'), 'n' : _('Newer')}
Packit 6f3914
        maxlen = max([len(x) for x in (list(_pkg_states_installed.values()) +
Packit 6f3914
                                       list(_pkg_states_available.values()))])
Packit 6f3914
        _pkg_states_installed['maxlen'] = maxlen
Packit 6f3914
        _pkg_states_available['maxlen'] = maxlen
Packit 6f3914
        def _simple_pkg(pkg, prefix_len, was_installed=False, highlight=False,
Packit 6f3914
                        pkg_max_len=0, show_repo=True):
Packit 6f3914
            prefix = " " * prefix_len
Packit 6f3914
            if was_installed:
Packit 6f3914
                _pkg_states = _pkg_states_installed
Packit 6f3914
            else:
Packit 6f3914
                _pkg_states = _pkg_states_available
Packit 6f3914
            state = _pkg_states['i']
Packit 6f3914
Packit 6f3914
            # get installed packages with name = pkg.name
Packit 6f3914
            ipkgs = self.sack.query().installed().filterm(name=pkg.name).run()
Packit 6f3914
Packit 6f3914
            if not ipkgs:
Packit 6f3914
                state = _pkg_states['e']
Packit 6f3914
            else:
Packit 6f3914
                # get latest installed package from software database
Packit 6f3914
                inst_pkg = self.history.package(ipkgs[0])
Packit 6f3914
                if inst_pkg:
Packit 6f3914
                    res = pkg.compare(inst_pkg)
Packit 6f3914
                    # res is:
Packit 6f3914
                    # 0 if inst_pkg == pkg
Packit 6f3914
                    # > 0 when inst_pkg > pkg
Packit 6f3914
                    # < 0 when inst_pkg < pkg
Packit 6f3914
                    if res == 0:
Packit 6f3914
                        pass  # installed
Packit 6f3914
                    elif res > 0:
Packit 6f3914
                        state = _pkg_states['o']  # updated
Packit 6f3914
                    else:
Packit 6f3914
                        state = _pkg_states['n']  # downgraded
Packit 6f3914
Packit 6f3914
            if highlight:
Packit 6f3914
                (hibeg, hiend) = self._highlight('bold')
Packit 6f3914
            else:
Packit 6f3914
                (hibeg, hiend) = self._highlight('normal')
Packit 6f3914
            state = fill_exact_width(state, _pkg_states['maxlen'])
Packit 6f3914
            ui_repo = ''
Packit 6f3914
            if show_repo:
Packit 6f3914
                ui_repo = pkg.ui_from_repo()
Packit 6f3914
            print("%s%s%s%s %-*s %s" % (prefix, hibeg, state, hiend,
Packit 6f3914
                                        pkg_max_len, str(pkg), ui_repo))
Packit 6f3914
Packit 6f3914
        tids = old.tids()
Packit 6f3914
        if len(tids) > 1:
Packit 6f3914
            print(_("Transaction ID :"), "%u..%u" % (tids[0], tids[-1]))
Packit 6f3914
        else:
Packit 6f3914
            print(_("Transaction ID :"), tids[0])
Packit 6f3914
        begt = float(old.beg_timestamp)
Packit 6f3914
        begtm = time.strftime("%c", time.localtime(begt))
Packit 6f3914
        print(_("Begin time     :"), begtm)
Packit 6f3914
        if old.beg_rpmdb_version is not None:
Packit 6f3914
            if old.altered_lt_rpmdb:
Packit 6f3914
                print(_("Begin rpmdb    :"), old.beg_rpmdb_version, "**")
Packit 6f3914
            else:
Packit 6f3914
                print(_("Begin rpmdb    :"), old.beg_rpmdb_version)
Packit 6f3914
        if old.end_timestamp is not None:
Packit 6f3914
            endt = old.end_timestamp
Packit 6f3914
            endtm = time.strftime("%c", time.localtime(endt))
Packit 6f3914
            diff = endt - begt
Packit 6f3914
            if diff < 5 * 60:
Packit 6f3914
                diff = _("(%u seconds)") % diff
Packit 6f3914
            elif diff < 5 * 60 * 60:
Packit 6f3914
                diff = _("(%u minutes)") % (diff // 60)
Packit 6f3914
            elif diff < 5 * 60 * 60 * 24:
Packit 6f3914
                diff = _("(%u hours)") % (diff // (60 * 60))
Packit 6f3914
            else:
Packit 6f3914
                diff = _("(%u days)") % (diff // (60 * 60 * 24))
Packit 6f3914
            print(_("End time       :"), endtm, diff)
Packit 6f3914
        if old.end_rpmdb_version is not None:
Packit 6f3914
            if old.altered_gt_rpmdb:
Packit 6f3914
                print(_("End rpmdb      :"), old.end_rpmdb_version, "**")
Packit 6f3914
            else:
Packit 6f3914
                print(_("End rpmdb      :"), old.end_rpmdb_version)
Packit 6f3914
        if isinstance(name, (list, tuple)):
Packit 6f3914
            seen = set()
Packit 6f3914
            for i in name:
Packit 6f3914
                if i in seen:
Packit 6f3914
                    continue
Packit 6f3914
                seen.add(i)
Packit 6f3914
                print(_("User           :"), i)
Packit 6f3914
        else:
Packit 6f3914
            print(_("User           :"), name)
Packit 6f3914
        if isinstance(old.return_code, (list, tuple)):
Packit 6f3914
            codes = old.return_code
Packit 6f3914
            if codes[0] is None:
Packit 6f3914
                print(_("Return-Code    :"), "**", _("Aborted"), "**")
Packit 6f3914
                codes = codes[1:]
Packit 6f3914
            elif not all(codes):
Packit 6f3914
                print(_("Return-Code    :"), _("Success"))
Packit 6f3914
            elif codes:
Packit 6f3914
                print(_("Return-Code    :"), _("Failures:"), ", ".join([str(i) for i in codes]))
Packit 6f3914
        elif old.return_code is None:
Packit 6f3914
            print(_("Return-Code    :"), "**", _("Aborted"), "**")
Packit 6f3914
        elif old.return_code:
Packit 6f3914
            print(_("Return-Code    :"), _("Failure:"), old.return_code)
Packit 6f3914
        else:
Packit 6f3914
            print(_("Return-Code    :"), _("Success"))
Packit 6f3914
Packit 6f3914
        if isinstance(old.releasever, (list, tuple)):
Packit 6f3914
            seen = set()
Packit 6f3914
            for i in old.releasever:
Packit 6f3914
                if i in seen:
Packit 6f3914
                    continue
Packit 6f3914
                seen.add(i)
Packit 6f3914
            print(_("Releasever     :"), i)
Packit 6f3914
        else:
Packit 6f3914
            print(_("Releasever     :"), old.releasever)
Packit 6f3914
Packit 6f3914
        if old.cmdline is not None:
Packit 6f3914
            if isinstance(old.cmdline, (list, tuple)):
Packit 6f3914
                for cmdline in old.cmdline:
Packit 6f3914
                    print(_("Command Line   :"), cmdline)
Packit 6f3914
            else:
Packit 6f3914
                print(_("Command Line   :"), old.cmdline)
Packit 6f3914
Packit 6f3914
        # TODO:
Packit 6f3914
        # comment = self.history.addon_data.read(old.tid, item='transaction-comment')
Packit 6f3914
        comment = ""
Packit 6f3914
        if comment:
Packit 6f3914
            print(_("Comment        :"), comment)
Packit 6f3914
Packit 6f3914
        perf_with = old.performed_with()
Packit 6f3914
        if perf_with:
Packit 6f3914
            print(_("Transaction performed with:"))
Packit 6f3914
        max_len = 0
Packit 6f3914
        for with_pkg in perf_with:
Packit 6f3914
            str_len = len(str(with_pkg))
Packit 6f3914
            if str_len > max_len:
Packit 6f3914
                max_len = str_len
Packit 6f3914
        for with_pkg in perf_with:
Packit 6f3914
            _simple_pkg(with_pkg, 4, was_installed=True, pkg_max_len=max_len)
Packit 6f3914
Packit 6f3914
        print(_("Packages Altered:"))
Packit 6f3914
Packit 6f3914
        self.historyInfoCmdPkgsAltered(old, pats)
Packit 6f3914
Packit 6f3914
        t_out = old.output()
Packit 6f3914
        if t_out:
Packit 6f3914
            print(_("Scriptlet output:"))
Packit 6f3914
            num = 0
Packit 6f3914
            for line in t_out:
Packit 6f3914
                num += 1
Packit 6f3914
                print("%4d" % num, line)
Packit 6f3914
        t_err = old.error()
Packit 6f3914
        if t_err:
Packit 6f3914
            print(_("Errors:"))
Packit 6f3914
            num = 0
Packit 6f3914
            for line in t_err:
Packit 6f3914
                num += 1
Packit 6f3914
                print("%4d" % num, line)
Packit 6f3914
Packit 6f3914
    # TODO: remove
Packit 6f3914
    _history_state2uistate = {'True-Install' : _('Install'),
Packit 6f3914
                              'Install'      : _('Install'),
Packit 6f3914
                              'Dep-Install'  : _('Dep-Install'),
Packit 6f3914
                              'Obsoleted'    : _('Obsoleted'),
Packit 6f3914
                              'Obsoleting'   : _('Obsoleting'),
Packit 6f3914
                              'Erase'        : _('Erase'),
Packit 6f3914
                              'Reinstall'    : _('Reinstall'),
Packit 6f3914
                              'Downgrade'    : _('Downgrade'),
Packit 6f3914
                              'Downgraded'   : _('Downgraded'),
Packit 6f3914
                              'Update'       : _('Upgrade'),
Packit 6f3914
                              'Updated'      : _('Upgraded'),
Packit 6f3914
                              }
Packit 6f3914
    def historyInfoCmdPkgsAltered(self, old, pats=[]):
Packit 6f3914
        """Print information about how packages are altered in a transaction.
Packit 6f3914
Packit 6f3914
        :param old: the :class:`DnfSwdbTrans` to
Packit 6f3914
           print information about
Packit 6f3914
        :param pats: a list of patterns.  Packages that match a patten
Packit 6f3914
           in *pats* will be highlighted in the output
Packit 6f3914
        """
Packit 6f3914
        last = None
Packit 6f3914
        #  Note that these don't use _simple_pkg() because we are showing what
Packit 6f3914
        # happened to them in the transaction ... not the difference between the
Packit 6f3914
        # version in the transaction and now.
Packit 6f3914
        all_uistates = self._history_state2uistate
Packit 6f3914
        maxlen = 0
Packit 6f3914
        pkg_max_len = 0
Packit 6f3914
Packit 6f3914
        packages = old.packages()
Packit 6f3914
Packit 6f3914
        for pkg in packages:
Packit 6f3914
            uistate = all_uistates.get(pkg.action_name, pkg.action_name)
Packit 6f3914
            if maxlen < len(uistate):
Packit 6f3914
                maxlen = len(uistate)
Packit 6f3914
            pkg_len = len(str(pkg))
Packit 6f3914
            if pkg_max_len < pkg_len:
Packit 6f3914
                pkg_max_len = pkg_len
Packit 6f3914
Packit 6f3914
        for pkg in packages:
Packit 6f3914
            prefix = " " * 4
Packit 6f3914
            if pkg.state != libdnf.transaction.TransactionItemState_DONE:
Packit 6f3914
                prefix = " ** "
Packit 6f3914
Packit 6f3914
            highlight = 'normal'
Packit 6f3914
            if pats:
Packit 6f3914
                if any([pkg.match(pat) for pat in pats]):
Packit 6f3914
                    highlight = 'bold'
Packit 6f3914
            (hibeg, hiend) = self._highlight(highlight)
Packit 6f3914
Packit 6f3914
            cn = str(pkg)
Packit 6f3914
Packit 6f3914
            uistate = all_uistates.get(pkg.action_name, pkg.action_name)
Packit 6f3914
            uistate = fill_exact_width(ucd(uistate), maxlen)
Packit 6f3914
Packit 6f3914
            if (last is not None and last.action == libdnf.transaction.TransactionItemAction_UPGRADED and
Packit 6f3914
                    last.name == pkg.name and pkg.action == libdnf.transaction.TransactionItemAction_UPGRADE):
Packit 6f3914
Packit 6f3914
                ln = len(pkg.name) + 1
Packit 6f3914
                cn = (" " * ln) + cn[ln:]
Packit 6f3914
            elif (last is not None and last.action == libdnf.transaction.TransactionItemAction_DOWNGRADE and
Packit 6f3914
                  last.name == pkg.name and pkg.action == libdnf.transaction.TransactionItemAction_DOWNGRADED):
Packit 6f3914
Packit 6f3914
                ln = len(pkg.name) + 1
Packit 6f3914
                cn = (" " * ln) + cn[ln:]
Packit 6f3914
            else:
Packit 6f3914
                last = None
Packit 6f3914
                if pkg.action in (libdnf.transaction.TransactionItemAction_UPGRADED, libdnf.transaction.TransactionItemAction_DOWNGRADE):
Packit 6f3914
                    last = pkg
Packit 6f3914
            print("%s%s%s%s %-*s %s" % (prefix, hibeg, uistate, hiend,
Packit 6f3914
                                        pkg_max_len, str(pkg),
Packit 6f3914
                                        pkg.ui_from_repo()))
Packit 6f3914
Packit 6f3914
    def historyPackageListCmd(self, extcmds):
Packit 6f3914
        """Print a list of information about transactions from history
Packit 6f3914
        that involve the given package or packages.
Packit 6f3914
Packit 6f3914
        :param extcmds: list of extra command line arguments
Packit 6f3914
        """
Packit 6f3914
        tids = self.history.search(extcmds)
Packit 6f3914
        limit = None
Packit 6f3914
        if extcmds and not tids:
Packit 6f3914
            logger.critical(_('Bad transaction IDs, or package(s), given'))
Packit 6f3914
            return 1, ['Failed history packages-list']
Packit 6f3914
        if not tids:
Packit 6f3914
            limit = 20
Packit 6f3914
Packit 6f3914
        all_uistates = self._history_state2uistate
Packit 6f3914
Packit 6f3914
        fmt = "%s | %s | %s"
Packit 6f3914
        # REALLY Needs to use columns!
Packit 6f3914
        print(fmt % (fill_exact_width(_("ID"), 6, 6),
Packit 6f3914
                     fill_exact_width(_("Action(s)"), 14, 14),
Packit 6f3914
        # This is also a hack to resolve RhBug 1302935 correctly.
Packit 6f3914
                     fill_exact_width(C_("long", "Package"), 53, 53)))
Packit 6f3914
        print("-" * 79)
Packit 6f3914
        fmt = "%6u | %s | %-50s"
Packit 6f3914
        num = 0
Packit 6f3914
        for old in self.history.old(tids, limit=limit):
Packit 6f3914
            packages = old.packages()
Packit 6f3914
            if limit and num and (num + len(packages)) > limit:
Packit 6f3914
                break
Packit 6f3914
            last = None
Packit 6f3914
Packit 6f3914
            # Copy and paste from list ... uh.
Packit 6f3914
            rmark = lmark = ' '
Packit 6f3914
            if old.return_code is None:
Packit 6f3914
                rmark = lmark = '*'
Packit 6f3914
            elif old.return_code:
Packit 6f3914
                rmark = lmark = '#'
Packit 6f3914
                # We don't check .errors, because return_code will be non-0
Packit 6f3914
            elif old.output:
Packit 6f3914
                rmark = lmark = 'E'
Packit 6f3914
            elif old.rpmdb_problems:
Packit 6f3914
                rmark = lmark = 'P'
Packit 6f3914
            elif old.trans_skip:
Packit 6f3914
                rmark = lmark = 's'
Packit 6f3914
            if old.altered_lt_rpmdb:
Packit 6f3914
                rmark = '<'
Packit 6f3914
            if old.altered_gt_rpmdb:
Packit 6f3914
                lmark = '>'
Packit 6f3914
Packit 6f3914
            # Find a pkg to go with each cmd...
Packit 6f3914
            for pkg in packages:
Packit 6f3914
                if limit is None:
Packit 6f3914
                    if not any([pkg.match(pat) for pat in extcmds]):
Packit 6f3914
                        continue
Packit 6f3914
Packit 6f3914
                uistate = all_uistates.get(pkg.action_name, pkg.action_name)
Packit 6f3914
                uistate = fill_exact_width(uistate, 14)
Packit 6f3914
Packit 6f3914
                #  To chop the name off we need nevra strings, str(pkg) gives
Packit 6f3914
                # envra so we have to do it by hand ... *sigh*.
Packit 6f3914
                cn = pkg.ui_nevra
Packit 6f3914
Packit 6f3914
                if (last is not None and last.action == libdnf.transaction.TransactionItemAction_UPGRADED and
Packit 6f3914
                        last.name == pkg.name and pkg.action == libdnf.transaction.TransactionItemAction_UPGRADE):
Packit 6f3914
                    ln = len(pkg.name) + 1
Packit 6f3914
                    cn = (" " * ln) + cn[ln:]
Packit 6f3914
                elif (last is not None and
Packit 6f3914
                      last.action == libdnf.transaction.TransactionItemAction_DOWNGRADE and last.name == pkg.name and
Packit 6f3914
                      pkg.action == libdnf.transaction.TransactionItemAction_DOWNGRADED):
Packit 6f3914
                    ln = len(pkg.name) + 1
Packit 6f3914
                    cn = (" " * ln) + cn[ln:]
Packit 6f3914
                else:
Packit 6f3914
                    last = None
Packit 6f3914
                    if pkg.action in (libdnf.transaction.TransactionItemAction_UPGRADED, libdnf.transaction.TransactionItemAction_DOWNGRADE):
Packit 6f3914
                        last = pkg
Packit 6f3914
Packit 6f3914
                num += 1
Packit 6f3914
                print(fmt % (old.tid, uistate, cn), "%s%s" % (lmark, rmark))
Packit 6f3914
Packit 6f3914
class DepSolveProgressCallBack(dnf.callback.Depsolve):
Packit 6f3914
    """Provides text output callback functions for Dependency Solver callback."""
Packit 6f3914
Packit 6f3914
    def __init__(self):
Packit 6f3914
        """requires yum-cli log and errorlog functions as arguments"""
Packit 6f3914
        self.loops = 0
Packit 6f3914
Packit 6f3914
    def pkg_added(self, pkg, mode):
Packit 6f3914
        """Print information about a package being added to the
Packit 6f3914
        transaction set.
Packit 6f3914
Packit 6f3914
        :param pkgtup: tuple containing the package name, arch,
Packit 6f3914
           version, and repository
Packit 6f3914
        :param mode: a short string indicating why the package is
Packit 6f3914
           being added to the transaction set.
Packit 6f3914
Packit 6f3914
        Valid current values for *mode* are::
Packit 6f3914
Packit 6f3914
           i = the package will be installed
Packit 6f3914
           u = the package will be an update
Packit 6f3914
           e = the package will be erased
Packit 6f3914
           r = the package will be reinstalled
Packit 6f3914
           d = the package will be a downgrade
Packit 6f3914
           o = the package will be obsoleting another package
Packit 6f3914
           ud = the package will be updated
Packit 6f3914
           od = the package will be obsoleted
Packit 6f3914
        """
Packit 6f3914
        output = None
Packit 6f3914
        if mode == 'i':
Packit 6f3914
            output = _('---> Package %s.%s %s will be installed')
Packit 6f3914
        elif mode == 'u':
Packit 6f3914
            output = _('---> Package %s.%s %s will be an upgrade')
Packit 6f3914
        elif mode == 'e':
Packit 6f3914
            output = _('---> Package %s.%s %s will be erased')
Packit 6f3914
        elif mode == 'r':
Packit 6f3914
            output = _('---> Package %s.%s %s will be reinstalled')
Packit 6f3914
        elif mode == 'd':
Packit 6f3914
            output = _('---> Package %s.%s %s will be a downgrade')
Packit 6f3914
        elif mode == 'o':
Packit 6f3914
            output = _('---> Package %s.%s %s will be obsoleting')
Packit 6f3914
        elif mode == 'ud':
Packit 6f3914
            output = _('---> Package %s.%s %s will be upgraded')
Packit 6f3914
        elif mode == 'od':
Packit 6f3914
            output = _('---> Package %s.%s %s will be obsoleted')
Packit 6f3914
Packit 6f3914
        if output:
Packit 6f3914
            logger.debug(output, pkg.name, pkg.arch, pkg.evr)
Packit 6f3914
Packit 6f3914
    def start(self):
Packit 6f3914
        """Perform setup at the beginning of the dependency solving
Packit 6f3914
        process.
Packit 6f3914
        """
Packit 6f3914
        logger.debug(_('--> Starting dependency resolution'))
Packit 6f3914
        self.loops += 1
Packit 6f3914
Packit 6f3914
    def end(self):
Packit 6f3914
        """Output a message stating that dependency resolution has finished."""
Packit 6f3914
        logger.debug(_('--> Finished dependency resolution'))
Packit 6f3914
Packit 6f3914
Packit 6f3914
class CliKeyImport(dnf.callback.KeyImport):
Packit 6f3914
    def __init__(self, base, output):
Packit 6f3914
        self.base = base
Packit 6f3914
        self.output = output
Packit 6f3914
Packit 6f3914
    def _confirm(self, id, userid, fingerprint, url, timestamp):
Packit 6f3914
Packit 6f3914
        def short_id(id):
Packit 6f3914
            rj = '0' if dnf.pycomp.PY3 else b'0'
Packit 6f3914
            return id[-8:].rjust(8, rj)
Packit 6f3914
Packit 6f3914
        msg = (_('Importing GPG key 0x%s:\n'
Packit 6f3914
                 ' Userid     : "%s"\n'
Packit 6f3914
                 ' Fingerprint: %s\n'
Packit 6f3914
                 ' From       : %s') %
Packit 6f3914
               (short_id(id), userid,
Packit 6f3914
                dnf.crypto._printable_fingerprint(fingerprint),
Packit 6f3914
                url.replace("file://", "")))
Packit 6f3914
        logger.critical("%s", msg)
Packit 6f3914
Packit 6f3914
        if self.base.conf.assumeyes:
Packit 6f3914
            return True
Packit 6f3914
        if self.base.conf.assumeno:
Packit 6f3914
            return False
Packit 6f3914
        return self.output.userconfirm()
Packit 6f3914
Packit 6f3914
Packit 6f3914
class CliTransactionDisplay(LoggingTransactionDisplay):
Packit 6f3914
    """A YUM specific callback class for RPM operations."""
Packit 6f3914
Packit 6f3914
    width = property(lambda self: dnf.cli.term._term_width())
Packit 6f3914
Packit 6f3914
    def __init__(self):
Packit 6f3914
        super(CliTransactionDisplay, self).__init__()
Packit 6f3914
        self.lastmsg = ""
Packit 6f3914
        self.lastpackage = None # name of last package we looked at
Packit 6f3914
        self.output = True
Packit 6f3914
Packit 6f3914
        # for a progress bar
Packit 6f3914
        self.mark = "="
Packit 6f3914
        self.marks = 22
Packit 6f3914
Packit 6f3914
    def progress(self, package, action, ti_done, ti_total, ts_done, ts_total):
Packit 6f3914
        """Output information about an rpm operation.  This may
Packit 6f3914
        include a text progress bar.
Packit 6f3914
Packit 6f3914
        :param package: the package involved in the event
Packit 6f3914
        :param action: the type of action that is taking place.  Valid
Packit 6f3914
           values are given by
Packit 6f3914
           :func:`rpmtrans.LoggingTransactionDisplay.action.keys()`
Packit 6f3914
        :param ti_done: a number representing the amount of work
Packit 6f3914
           already done in the current transaction
Packit 6f3914
        :param ti_total: a number representing the total amount of work
Packit 6f3914
           to be done in the current transaction
Packit 6f3914
        :param ts_done: the number of the current transaction in
Packit 6f3914
           transaction set
Packit 6f3914
        :param ts_total: the total number of transactions in the
Packit 6f3914
           transaction set
Packit 6f3914
        """
Packit 6f3914
        action_str = dnf.transaction.ACTIONS.get(action)
Packit 6f3914
        if action_str is None:
Packit 6f3914
            return
Packit 6f3914
Packit 6f3914
        wid1 = self._max_action_width()
Packit 6f3914
Packit 6f3914
        pkgname = ucd(package)
Packit 6f3914
        self.lastpackage = package
Packit 6f3914
        if ti_total == 0:
Packit 6f3914
            percent = 0
Packit 6f3914
        else:
Packit 6f3914
            percent = (ti_done*long(100))//ti_total
Packit 6f3914
        self._out_progress(ti_done, ti_total, ts_done, ts_total,
Packit 6f3914
                           percent, action_str, pkgname, wid1)
Packit 6f3914
Packit 6f3914
    def _max_action_width(self):
Packit 6f3914
        if not hasattr(self, '_max_action_wid_cache'):
Packit 6f3914
            wid1 = 0
Packit 6f3914
            for val in dnf.transaction.ACTIONS.values():
Packit 6f3914
                wid_val = exact_width(val)
Packit 6f3914
                if wid1 < wid_val:
Packit 6f3914
                    wid1 = wid_val
Packit 6f3914
            self._max_action_wid_cache = wid1
Packit 6f3914
        wid1 = self._max_action_wid_cache
Packit 6f3914
        return wid1
Packit 6f3914
Packit 6f3914
    def _out_progress(self, ti_done, ti_total, ts_done, ts_total,
Packit 6f3914
                      percent, process, pkgname, wid1):
Packit 6f3914
        if self.output and (sys.stdout.isatty() or ti_done == ti_total):
Packit 6f3914
            (fmt, wid1, wid2) = self._makefmt(percent, ts_done, ts_total,
Packit 6f3914
                                              progress=sys.stdout.isatty(),
Packit 6f3914
                                              pkgname=pkgname, wid1=wid1)
Packit 6f3914
            pkgname = ucd(pkgname)
Packit 6f3914
            msg = fmt % (fill_exact_width(process, wid1, wid1),
Packit 6f3914
                         fill_exact_width(pkgname, wid2, wid2))
Packit 6f3914
            if msg != self.lastmsg:
Packit 6f3914
                dnf.util._terminal_messenger('write_flush', msg, sys.stdout)
Packit 6f3914
                self.lastmsg = msg
Packit 6f3914
                if ti_done == ti_total:
Packit 6f3914
                    print(" ")
Packit 6f3914
Packit 6f3914
    def filelog(self, package, action):
Packit 6f3914
        pass
Packit 6f3914
Packit 6f3914
    def error(self, message):
Packit 6f3914
        pass
Packit 6f3914
Packit 6f3914
    def scriptout(self, msgs):
Packit 6f3914
        """Print messages originating from a package script.
Packit 6f3914
Packit 6f3914
        :param msgs: the messages coming from the script
Packit 6f3914
        """
Packit 6f3914
        if msgs:
Packit 6f3914
            self.rpm_logger.info(ucd(msgs))
Packit 6f3914
Packit 6f3914
    def _makefmt(self, percent, ts_done, ts_total, progress=True,
Packit 6f3914
                 pkgname=None, wid1=15):
Packit 6f3914
        l = len(str(ts_total))
Packit 6f3914
        size = "%s.%s" % (l, l)
Packit 6f3914
        fmt_done = "%" + size + "s/%" + size + "s"
Packit 6f3914
        done = fmt_done % (ts_done, ts_total)
Packit 6f3914
Packit 6f3914
        #  This should probably use TerminLine, but we don't want to dep. on
Packit 6f3914
        # that. So we kind do an ok job by hand ... at least it's dynamic now.
Packit 6f3914
        if pkgname is None:
Packit 6f3914
            pnl = 22
Packit 6f3914
        else:
Packit 6f3914
            pnl = exact_width(pkgname)
Packit 6f3914
Packit 6f3914
        overhead = (2 * l) + 2 # Length of done, above
Packit 6f3914
        overhead += 2 + wid1 +2 # Length of beginning ("  " action " :")
Packit 6f3914
        overhead += 1          # Space between pn and done
Packit 6f3914
        overhead += 2          # Ends for progress
Packit 6f3914
        overhead += 1          # Space for end
Packit 6f3914
        width = self.width
Packit 6f3914
        if width < overhead:
Packit 6f3914
            width = overhead    # Give up
Packit 6f3914
        width -= overhead
Packit 6f3914
        if pnl > width // 2:
Packit 6f3914
            pnl = width // 2
Packit 6f3914
Packit 6f3914
        marks = self.width - (overhead + pnl)
Packit 6f3914
        width = "%s.%s" % (marks, marks)
Packit 6f3914
        fmt_bar = "[%-" + width + "s]"
Packit 6f3914
        # pnl = str(28 + marks + 1)
Packit 6f3914
        full_pnl = pnl + marks + 1
Packit 6f3914
Packit 6f3914
        if progress and percent == 100: # Don't chop pkg name on 100%
Packit 6f3914
            fmt = "\r  %s: %s   " + done
Packit 6f3914
            wid2 = full_pnl
Packit 6f3914
        elif progress:
Packit 6f3914
            if marks > 5:
Packit 6f3914
                bar = fmt_bar % (self.mark * int(marks * (percent / 100.0)), )
Packit 6f3914
            else:
Packit 6f3914
                bar = ""
Packit 6f3914
            fmt = "\r  %s: %s " + bar + " " + done
Packit 6f3914
            wid2 = pnl
Packit 6f3914
        elif percent == 100:
Packit 6f3914
            fmt = "  %s: %s   " + done
Packit 6f3914
            wid2 = full_pnl
Packit 6f3914
        else:
Packit 6f3914
            if marks > 5:
Packit 6f3914
                bar = fmt_bar % (self.mark * marks, )
Packit 6f3914
            else:
Packit 6f3914
                bar = ""
Packit 6f3914
            fmt = "  %s: %s " + bar + " " + done
Packit 6f3914
            wid2 = pnl
Packit 6f3914
        return fmt, wid1, wid2
Packit 6f3914
Packit 6f3914
def progressbar(current, total, name=None):
Packit 6f3914
    """Output the current status to the terminal using a simple
Packit 6f3914
    text progress bar consisting of 50 # marks.
Packit 6f3914
Packit 6f3914
    :param current: a number representing the amount of work
Packit 6f3914
       already done
Packit 6f3914
    :param total: a number representing the total amount of work
Packit 6f3914
       to be done
Packit 6f3914
    :param name: a name to label the progress bar with
Packit 6f3914
    """
Packit 6f3914
Packit 6f3914
    mark = '#'
Packit 6f3914
    if not sys.stdout.isatty():
Packit 6f3914
        return
Packit 6f3914
Packit 6f3914
    if current == 0:
Packit 6f3914
        percent = 0
Packit 6f3914
    else:
Packit 6f3914
        if total != 0:
Packit 6f3914
            percent = float(current) / total
Packit 6f3914
        else:
Packit 6f3914
            percent = 0
Packit 6f3914
Packit 6f3914
    width = dnf.cli.term._term_width()
Packit 6f3914
Packit 6f3914
    if name is None and current == total:
Packit 6f3914
        name = '-'
Packit 6f3914
Packit 6f3914
    end = ' %d/%d' % (current, total)
Packit 6f3914
    width -= len(end) + 1
Packit 6f3914
    if width < 0:
Packit 6f3914
        width = 0
Packit 6f3914
    if name is None:
Packit 6f3914
        width -= 2
Packit 6f3914
        if width < 0:
Packit 6f3914
            width = 0
Packit 6f3914
        hashbar = mark * int(width * percent)
Packit 6f3914
        output = '\r[%-*s]%s' % (width, hashbar, end)
Packit 6f3914
    elif current == total: # Don't chop name on 100%
Packit 6f3914
        output = '\r%s%s' % (fill_exact_width(name, width, width), end)
Packit 6f3914
    else:
Packit 6f3914
        width -= 4
Packit 6f3914
        if width < 0:
Packit 6f3914
            width = 0
Packit 6f3914
        nwid = width // 2
Packit 6f3914
        if nwid > exact_width(name):
Packit 6f3914
            nwid = exact_width(name)
Packit 6f3914
        width -= nwid
Packit 6f3914
        hashbar = mark * int(width * percent)
Packit 6f3914
        output = '\r%s: [%-*s]%s' % (fill_exact_width(name, nwid, nwid), width,
Packit 6f3914
                                     hashbar, end)
Packit 6f3914
Packit 6f3914
    if current <= total:
Packit 6f3914
        dnf.util._terminal_messenger('write', output, sys.stdout)
Packit 6f3914
Packit 6f3914
    if current == total:
Packit 6f3914
        dnf.util._terminal_messenger('write', '\n', sys.stdout)
Packit 6f3914
Packit 6f3914
    dnf.util._terminal_messenger('flush', out=sys.stdout)