blob: aefc3f4599bf52ed630f97aa607f1b9149193458 [file] [log] [blame]
# Copyright 2010-2014 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
"""Resolver output display operation.
"""
from __future__ import unicode_literals
__all__ = (
"Display", "format_unmatched_atom",
)
import sys
import portage
from portage import os
from portage.dbapi.dep_expand import dep_expand
from portage.dep import cpvequal, _repo_separator, _slot_separator
from portage.eapi import _get_eapi_attrs
from portage.exception import InvalidDependString, SignatureException
from portage.localization import localized_size
from portage.package.ebuild.config import _get_feature_flags
from portage.package.ebuild._spawn_nofetch import spawn_nofetch
from portage.output import ( blue, colorize, create_color_func,
darkblue, darkgreen, green, nc_len, teal)
bad = create_color_func("BAD")
from portage._sets.base import InternalPackageSet
from portage.util import writemsg_stdout
from portage.versions import best, cpv_getversion
from _emerge.Blocker import Blocker
from _emerge.create_world_atom import create_world_atom
from _emerge.resolver.output_helpers import ( _DisplayConfig, _tree_display,
_PackageCounters, _create_use_string, _calc_changelog, PkgInfo)
from _emerge.show_invalid_depstring_notice import show_invalid_depstring_notice
if sys.hexversion >= 0x3000000:
basestring = str
_unicode = str
else:
_unicode = unicode
class Display(object):
"""Formats and outputs the depgrah supplied it for merge/re-merge, etc.
__call__()
@param depgraph: list
@param favorites: defaults to []
@param verbosity: integer, defaults to None
"""
def __init__(self):
self.changelogs = []
self.print_msg = []
self.blockers = []
self.counters = _PackageCounters()
self.resolver = None
self.resolved = None
self.vardb = None
self.portdb = None
self.verboseadd = ''
self.oldlp = None
self.myfetchlist = None
self.indent = ''
self.use_expand = None
self.use_expand_hidden = None
self.pkgsettings = None
self.forced_flags = None
self.newlp = None
self.conf = None
self.blocker_style = None
def _blockers(self, blocker):
"""Adds colorized strings to
self.print_msg and self.blockers
@param blocker: _emerge.Blocker.Blocker instance
@rtype: bool
Modifies class globals: self.blocker_style, self.resolved,
self.print_msg
"""
if blocker.satisfied:
self.blocker_style = "PKG_BLOCKER_SATISFIED"
addl = "%s " % (colorize(self.blocker_style, "b"),)
else:
self.blocker_style = "PKG_BLOCKER"
addl = "%s " % (colorize(self.blocker_style, "B"),)
addl += self.empty_space_in_brackets()
self.resolved = dep_expand(
_unicode(blocker.atom).lstrip("!"), mydb=self.vardb,
settings=self.pkgsettings
)
if self.conf.columns and self.conf.quiet:
addl += " " + colorize(self.blocker_style, _unicode(self.resolved))
else:
addl = "[%s %s] %s%s" % \
(colorize(self.blocker_style, "blocks"),
addl, self.indent,
colorize(self.blocker_style, _unicode(self.resolved))
)
block_parents = self.conf.blocker_parents.parent_nodes(blocker)
block_parents = set(_unicode(pnode.cpv) for pnode in block_parents)
block_parents = ", ".join(block_parents)
if blocker.atom.blocker.overlap.forbid:
blocking_desc = "hard blocking"
else:
blocking_desc = "blocking"
if self.resolved != blocker.atom:
addl += colorize(self.blocker_style,
" (\"%s\" is %s %s)" %
(_unicode(blocker.atom).lstrip("!"),
blocking_desc, block_parents))
else:
addl += colorize(self.blocker_style,
" (is %s %s)" % (blocking_desc, block_parents))
if blocker.satisfied:
if not self.conf.columns:
self.print_msg.append(addl)
else:
self.blockers.append(addl)
def include_mask_str(self):
return self.conf.verbosity > 1
def gen_mask_str(self, pkg):
"""
@param pkg: _emerge.Package.Package instance
"""
hardmasked = pkg.isHardMasked()
mask_str = " "
if hardmasked:
mask_str = colorize("BAD", "#")
else:
keyword_mask = pkg.get_keyword_mask()
if keyword_mask is None:
pass
elif keyword_mask == "missing":
mask_str = colorize("BAD", "*")
else:
mask_str = colorize("WARN", "~")
return mask_str
def empty_space_in_brackets(self):
space = ""
if self.include_mask_str():
# add column for mask status
space += " "
return space
def map_to_use_expand(self, myvals, forced_flags=False,
remove_hidden=True):
"""Map use expand variables
@param myvals: list
@param forced_flags: bool
@param remove_hidden: bool
@rtype ret dictionary
or ret dict, forced dict.
"""
ret = {}
forced = {}
for exp in self.use_expand:
ret[exp] = []
forced[exp] = set()
for val in myvals[:]:
if val.startswith(exp.lower()+"_"):
if val in self.forced_flags:
forced[exp].add(val[len(exp)+1:])
ret[exp].append(val[len(exp)+1:])
myvals.remove(val)
ret["USE"] = myvals
forced["USE"] = [val for val in myvals \
if val in self.forced_flags]
if remove_hidden:
for exp in self.use_expand_hidden:
ret.pop(exp, None)
if forced_flags:
return ret, forced
return ret
def _display_use(self, pkg, pkg_info):
""" USE flag display
@param pkg: _emerge.Package.Package instance
@param pkg_info: PkgInfo instance
Modifies self.use_expand_hidden, self.use_expand, self.verboseadd,
self.forced_flags
"""
self.forced_flags = set()
self.forced_flags.update(pkg.use.force)
self.forced_flags.update(pkg.use.mask)
cur_use = [flag for flag in self.conf.pkg_use_enabled(pkg) \
if flag in pkg.iuse.all]
cur_iuse = sorted(pkg.iuse.all)
if pkg_info.previous_pkg is not None:
previous_pkg = pkg_info.previous_pkg
old_iuse = sorted(previous_pkg.iuse.all)
old_use = previous_pkg.use.enabled
is_new = False
else:
old_iuse = []
old_use = []
is_new = True
old_use = [flag for flag in old_use if flag in old_iuse]
self.use_expand = pkg.use.expand
self.use_expand_hidden = pkg.use.expand_hidden
# Prevent USE_EXPAND_HIDDEN flags from being hidden if they
# are the only thing that triggered reinstallation.
reinst_flags_map = {}
reinstall_for_flags = self.conf.reinstall_nodes.get(pkg)
reinst_expand_map = None
if reinstall_for_flags:
reinst_flags_map = self.map_to_use_expand(
list(reinstall_for_flags), remove_hidden=False)
for k in list(reinst_flags_map):
if not reinst_flags_map[k]:
del reinst_flags_map[k]
if not reinst_flags_map.get("USE"):
reinst_expand_map = reinst_flags_map.copy()
reinst_expand_map.pop("USE", None)
if reinst_expand_map and \
not set(reinst_expand_map).difference(
self.use_expand_hidden):
self.use_expand_hidden = \
set(self.use_expand_hidden).difference(
reinst_expand_map)
cur_iuse_map, iuse_forced = \
self.map_to_use_expand(cur_iuse, forced_flags=True)
cur_use_map = self.map_to_use_expand(cur_use)
old_iuse_map = self.map_to_use_expand(old_iuse)
old_use_map = self.map_to_use_expand(old_use)
use_expand = sorted(self.use_expand)
use_expand.insert(0, "USE")
feature_flags = _get_feature_flags(_get_eapi_attrs(pkg.eapi))
for key in use_expand:
if key in self.use_expand_hidden:
continue
self.verboseadd += _create_use_string(self.conf, key.upper(),
cur_iuse_map[key], iuse_forced[key],
cur_use_map[key], old_iuse_map[key],
old_use_map[key], is_new, feature_flags,
reinst_flags_map.get(key))
return
@staticmethod
def pkgprint(pkg_str, pkg_info):
"""Colorizes a string acording to pkg_info settings
@param pkg_str: string
@param pkg_info: dictionary
@rtype colorized string
"""
if pkg_info.merge:
if pkg_info.built:
if pkg_info.system:
return colorize("PKG_BINARY_MERGE_SYSTEM", pkg_str)
elif pkg_info.world:
return colorize("PKG_BINARY_MERGE_WORLD", pkg_str)
else:
return colorize("PKG_BINARY_MERGE", pkg_str)
else:
if pkg_info.system:
return colorize("PKG_MERGE_SYSTEM", pkg_str)
elif pkg_info.world:
return colorize("PKG_MERGE_WORLD", pkg_str)
else:
return colorize("PKG_MERGE", pkg_str)
elif pkg_info.operation == "uninstall":
return colorize("PKG_UNINSTALL", pkg_str)
else:
if pkg_info.system:
return colorize("PKG_NOMERGE_SYSTEM", pkg_str)
elif pkg_info.world:
return colorize("PKG_NOMERGE_WORLD", pkg_str)
else:
return colorize("PKG_NOMERGE", pkg_str)
def verbose_size(self, pkg, repoadd_set, pkg_info):
"""Determines the size of the downloads required
@param pkg: _emerge.Package.Package instance
@param repoadd_set: set of repos to add
@param pkg_info: dictionary
Modifies class globals: self.myfetchlist, self.counters.totalsize,
self.verboseadd, repoadd_set.
"""
mysize = 0
if pkg.type_name in ("binary", "ebuild") and pkg_info.merge:
db = pkg.root_config.trees[
pkg.root_config.pkg_tree_map[pkg.type_name]].dbapi
kwargs = {}
if pkg.type_name == "ebuild":
kwargs["useflags"] = pkg_info.use
kwargs["myrepo"] = pkg.repo
myfilesdict = None
try:
myfilesdict = db.getfetchsizes(pkg.cpv,
**portage._native_kwargs(kwargs))
except InvalidDependString as e:
# FIXME: validate SRC_URI earlier
depstr, = db.aux_get(pkg.cpv,
["SRC_URI"], myrepo=pkg.repo)
show_invalid_depstring_notice(
pkg, depstr, _unicode(e))
raise
except SignatureException:
# missing/invalid binary package SIZE signature
pass
if myfilesdict is None:
myfilesdict = "[empty/missing/bad digest]"
else:
for myfetchfile in myfilesdict:
if myfetchfile not in self.myfetchlist:
mysize += myfilesdict[myfetchfile]
self.myfetchlist.add(myfetchfile)
if pkg_info.ordered:
self.counters.totalsize += mysize
self.verboseadd += localized_size(mysize)
if self.quiet_repo_display:
# overlay verbose
# assign index for a previous version in the same slot
if pkg_info.previous_pkg is not None:
repo_name_prev = pkg_info.previous_pkg.repo
else:
repo_name_prev = None
# now use the data to generate output
if pkg.installed or pkg_info.previous_pkg is None:
self.repoadd = self.conf.repo_display.repoStr(
pkg_info.repo_path_real)
else:
repo_path_prev = None
if repo_name_prev:
repo_path_prev = self.portdb.getRepositoryPath(
repo_name_prev)
if repo_path_prev == pkg_info.repo_path_real:
self.repoadd = self.conf.repo_display.repoStr(
pkg_info.repo_path_real)
else:
self.repoadd = "%s=>%s" % (
self.conf.repo_display.repoStr(repo_path_prev),
self.conf.repo_display.repoStr(pkg_info.repo_path_real))
if self.repoadd:
repoadd_set.add(self.repoadd)
def convert_myoldbest(self, pkg, pkg_info):
"""converts and colorizes a version list to a string
@param pkg: _emerge.Package.Package instance
@param pkg_info: dictionary
@rtype string.
"""
myoldbest = pkg_info.oldbest_list
# Convert myoldbest from a list to a string.
myoldbest_str = ""
if myoldbest:
versions = []
for pos, old_pkg in enumerate(myoldbest):
key = old_pkg.version
if key[-3:] == "-r0":
key = key[:-3]
if self.conf.verbosity == 3:
if pkg_info.attr_display.new_slot:
key += _slot_separator + old_pkg.slot
if old_pkg.slot != old_pkg.sub_slot:
key += "/" + old_pkg.sub_slot
elif any(x.slot + "/" + x.sub_slot != "0/0" for x in myoldbest + [pkg]):
key += _slot_separator + old_pkg.slot
if old_pkg.slot != old_pkg.sub_slot or \
old_pkg.slot == pkg.slot and old_pkg.sub_slot != pkg.sub_slot:
key += "/" + old_pkg.sub_slot
if not self.quiet_repo_display and (self.verbose_main_repo_display or
self.portdb.repositories.mainRepo() is None or
any(x.repo != self.portdb.repositories.mainRepo().name for x in myoldbest + [pkg])):
key += _repo_separator + old_pkg.repo
versions.append(key)
myoldbest_str = blue("["+", ".join(versions)+"]")
return myoldbest_str
def _append_slot(self, pkg_str, pkg, pkg_info):
"""Potentially appends slot and subslot to package string.
@param pkg_str: string
@param pkg: _emerge.Package.Package instance
@param pkg_info: dictionary
@rtype string
"""
if pkg_info.attr_display.new_slot:
pkg_str += _slot_separator + pkg_info.slot
if pkg_info.slot != pkg_info.sub_slot:
pkg_str += "/" + pkg_info.sub_slot
elif any(x.slot + "/" + x.sub_slot != "0/0" for x in pkg_info.oldbest_list + [pkg]):
pkg_str += _slot_separator + pkg_info.slot
if pkg_info.slot != pkg_info.sub_slot or \
any(x.slot == pkg_info.slot and x.sub_slot != pkg_info.sub_slot for x in pkg_info.oldbest_list):
pkg_str += "/" + pkg_info.sub_slot
return pkg_str
def _append_repository(self, pkg_str, pkg, pkg_info):
"""Potentially appends repository to package string.
@param pkg_str: string
@param pkg: _emerge.Package.Package instance
@param pkg_info: dictionary
@rtype string
"""
if not self.quiet_repo_display and (self.verbose_main_repo_display or
self.portdb.repositories.mainRepo() is None or
any(x.repo != self.portdb.repositories.mainRepo().name for x in pkg_info.oldbest_list + [pkg])):
pkg_str += _repo_separator + pkg.repo
return pkg_str
def _set_non_root_columns(self, pkg, pkg_info):
"""sets the indent level and formats the output
@param pkg: _emerge.Package.Package instance
@param pkg_info: dictionary
@rtype string
"""
ver_str = pkg_info.ver
if self.conf.verbosity == 3:
ver_str = self._append_slot(ver_str, pkg, pkg_info)
ver_str = self._append_repository(ver_str, pkg, pkg_info)
if self.conf.quiet:
myprint = _unicode(pkg_info.attr_display) + " " + self.indent + \
self.pkgprint(pkg_info.cp, pkg_info)
myprint = myprint+darkblue(" "+ver_str)+" "
myprint = myprint+pkg_info.oldbest
myprint = myprint+darkgreen("to "+pkg.root)
self.verboseadd = None
else:
if not pkg_info.merge:
myprint = "[%s] %s%s" % \
(self.pkgprint(pkg_info.operation.ljust(13), pkg_info),
self.indent, self.pkgprint(pkg.cp, pkg_info))
else:
myprint = "[%s %s] %s%s" % \
(self.pkgprint(pkg.type_name, pkg_info),
pkg_info.attr_display,
self.indent, self.pkgprint(pkg.cp, pkg_info))
if (self.newlp-nc_len(myprint)) > 0:
myprint = myprint+(" "*(self.newlp-nc_len(myprint)))
myprint = myprint+" "+darkblue("["+ver_str+"]")+" "
if (self.oldlp-nc_len(myprint)) > 0:
myprint = myprint+" "*(self.oldlp-nc_len(myprint))
myprint = myprint+pkg_info.oldbest
myprint += darkgreen("to " + pkg.root)
return myprint
def _set_root_columns(self, pkg, pkg_info):
"""sets the indent level and formats the output
@param pkg: _emerge.Package.Package instance
@param pkg_info: dictionary
@rtype string
Modifies self.verboseadd
"""
ver_str = pkg_info.ver
if self.conf.verbosity == 3:
ver_str = self._append_slot(ver_str, pkg, pkg_info)
ver_str = self._append_repository(ver_str, pkg, pkg_info)
if self.conf.quiet:
myprint = _unicode(pkg_info.attr_display) + " " + self.indent + \
self.pkgprint(pkg_info.cp, pkg_info)
myprint = myprint+" "+green(ver_str)+" "
myprint = myprint+pkg_info.oldbest
self.verboseadd = None
else:
if not pkg_info.merge:
addl = self.empty_space_in_brackets()
myprint = "[%s%s] %s%s" % \
(self.pkgprint(pkg_info.operation.ljust(13), pkg_info),
addl, self.indent, self.pkgprint(pkg.cp, pkg_info))
else:
myprint = "[%s %s] %s%s" % \
(self.pkgprint(pkg.type_name, pkg_info),
pkg_info.attr_display,
self.indent, self.pkgprint(pkg.cp, pkg_info))
if (self.newlp-nc_len(myprint)) > 0:
myprint = myprint+(" "*(self.newlp-nc_len(myprint)))
myprint = myprint+" "+green("["+ver_str+"]")+" "
if (self.oldlp-nc_len(myprint)) > 0:
myprint = myprint+(" "*(self.oldlp-nc_len(myprint)))
myprint += pkg_info.oldbest
return myprint
def _set_no_columns(self, pkg, pkg_info):
"""prints pkg info without column indentation.
@param pkg: _emerge.Package.Package instance
@param pkg_info: dictionary
@rtype the updated addl
"""
pkg_str = pkg.cpv
if self.conf.verbosity == 3:
pkg_str = self._append_slot(pkg_str, pkg, pkg_info)
pkg_str = self._append_repository(pkg_str, pkg, pkg_info)
if not pkg_info.merge:
addl = self.empty_space_in_brackets()
myprint = "[%s%s] %s%s %s" % \
(self.pkgprint(pkg_info.operation.ljust(13),
pkg_info), addl,
self.indent, self.pkgprint(pkg_str, pkg_info),
pkg_info.oldbest)
else:
myprint = "[%s %s] %s%s %s" % \
(self.pkgprint(pkg.type_name, pkg_info),
pkg_info.attr_display, self.indent,
self.pkgprint(pkg_str, pkg_info), pkg_info.oldbest)
return myprint
def print_messages(self, show_repos):
"""Performs the actual output printing of the pre-formatted
messages
@param show_repos: bool.
"""
for msg in self.print_msg:
if isinstance(msg, basestring):
writemsg_stdout("%s\n" % (msg,), noiselevel=-1)
continue
myprint, self.verboseadd, repoadd = msg
if self.verboseadd:
myprint += " " + self.verboseadd
if show_repos and repoadd:
myprint += " " + teal("[%s]" % repoadd)
writemsg_stdout("%s\n" % (myprint,), noiselevel=-1)
return
def print_blockers(self):
"""Performs the actual output printing of the pre-formatted
blocker messages
"""
for pkg in self.blockers:
writemsg_stdout("%s\n" % (pkg,), noiselevel=-1)
return
def print_verbose(self, show_repos):
"""Prints the verbose output to std_out
@param show_repos: bool.
"""
writemsg_stdout('\n%s\n' % (self.counters,), noiselevel=-1)
if show_repos:
# Use unicode_literals to force unicode format string so
# that RepoDisplay.__unicode__() is called in python2.
writemsg_stdout("%s" % (self.conf.repo_display,),
noiselevel=-1)
return
def print_changelog(self):
"""Prints the changelog text to std_out
"""
for chunk in self.changelogs:
writemsg_stdout(chunk,
noiselevel=-1)
def get_display_list(self, mylist):
"""Determines the display list to process
@param mylist
@rtype list
Modifies self.counters.blocks, self.counters.blocks_satisfied,
"""
unsatisfied_blockers = []
ordered_nodes = []
for pkg in mylist:
if isinstance(pkg, Blocker):
self.counters.blocks += 1
if pkg.satisfied:
ordered_nodes.append(pkg)
self.counters.blocks_satisfied += 1
else:
unsatisfied_blockers.append(pkg)
else:
ordered_nodes.append(pkg)
if self.conf.tree_display:
display_list = _tree_display(self.conf, ordered_nodes)
else:
display_list = [(pkg, 0, True) for pkg in ordered_nodes]
for pkg in unsatisfied_blockers:
display_list.append((pkg, 0, True))
return display_list
def set_pkg_info(self, pkg, ordered):
"""Sets various pkg_info dictionary variables
@param pkg: _emerge.Package.Package instance
@param ordered: bool
@rtype pkg_info dictionary
Modifies self.counters.restrict_fetch,
self.counters.restrict_fetch_satisfied
"""
pkg_info = PkgInfo()
pkg_info.cp = pkg.cp
pkg_info.ver = self.get_ver_str(pkg)
pkg_info.slot = pkg.slot
pkg_info.sub_slot = pkg.sub_slot
pkg_info.repo_name = pkg.repo
pkg_info.ordered = ordered
pkg_info.operation = pkg.operation
pkg_info.merge = ordered and pkg_info.operation == "merge"
if not pkg_info.merge and pkg_info.operation == "merge":
pkg_info.operation = "nomerge"
pkg_info.built = pkg.type_name != "ebuild"
pkg_info.ebuild_path = None
if ordered:
if pkg_info.merge:
if pkg.type_name == "binary":
self.counters.binary += 1
elif pkg_info.operation == "uninstall":
self.counters.uninst += 1
if pkg.type_name == "ebuild":
pkg_info.ebuild_path = self.portdb.findname(
pkg.cpv, myrepo=pkg_info.repo_name)
if pkg_info.ebuild_path is None:
raise AssertionError(
"ebuild not found for '%s'" % pkg.cpv)
pkg_info.repo_path_real = os.path.dirname(os.path.dirname(
os.path.dirname(pkg_info.ebuild_path)))
else:
pkg_info.repo_path_real = self.portdb.getRepositoryPath(pkg.repo)
pkg_info.use = list(self.conf.pkg_use_enabled(pkg))
if not pkg.built and pkg.operation == 'merge' and \
'fetch' in pkg.restrict:
if pkg_info.ordered:
self.counters.restrict_fetch += 1
pkg_info.attr_display.fetch_restrict = True
if not self.portdb.getfetchsizes(pkg.cpv,
useflags=pkg_info.use, myrepo=pkg.repo):
pkg_info.attr_display.fetch_restrict_satisfied = True
if pkg_info.ordered:
self.counters.restrict_fetch_satisfied += 1
else:
if pkg_info.ebuild_path is not None:
self.restrict_fetch_list[pkg] = pkg_info
if self.vardb.cpv_exists(pkg.cpv):
# Do a cpv match first, in case the SLOT has changed.
pkg_info.previous_pkg = self.vardb.match_pkgs('=' + pkg.cpv)[0]
else:
slot_matches = self.vardb.match_pkgs(pkg.slot_atom)
if slot_matches:
pkg_info.previous_pkg = slot_matches[0]
return pkg_info
def do_changelog(self, pkg, pkg_info):
"""Processes and adds the changelog text to the master text for output
@param pkg: _emerge.Package.Package instance
@param pkg_info: dictionay
Modifies self.changelogs
"""
if pkg_info.previous_pkg is not None:
ebuild_path_cl = pkg_info.ebuild_path
if ebuild_path_cl is None:
# binary package
ebuild_path_cl = self.portdb.findname(pkg.cpv, myrepo=pkg.repo)
if ebuild_path_cl is not None:
self.changelogs.extend(_calc_changelog(
ebuild_path_cl, pkg_info.previous_pkg, pkg.cpv))
return
def check_system_world(self, pkg):
"""Checks for any occurances of the package in the system or world sets
@param pkg: _emerge.Package.Package instance
@rtype system and world booleans
"""
root_config = self.conf.roots[pkg.root]
system_set = root_config.sets["system"]
world_set = root_config.sets["selected"]
system = False
world = False
try:
system = system_set.findAtomForPackage(
pkg, modified_use=self.conf.pkg_use_enabled(pkg))
world = world_set.findAtomForPackage(
pkg, modified_use=self.conf.pkg_use_enabled(pkg))
if not (self.conf.oneshot or world) and \
pkg.root == self.conf.target_root and \
self.conf.favorites.findAtomForPackage(
pkg, modified_use=self.conf.pkg_use_enabled(pkg)
):
# Maybe it will be added to world now.
if create_world_atom(pkg, self.conf.favorites, root_config):
world = True
except InvalidDependString:
# This is reported elsewhere if relevant.
pass
return system, world
@staticmethod
def get_ver_str(pkg):
"""Obtains the version string
@param pkg: _emerge.Package.Package instance
@rtype string
"""
ver_str = pkg.cpv.version
if ver_str.endswith("-r0"):
ver_str = ver_str[:-3]
return ver_str
def _get_installed_best(self, pkg, pkg_info):
""" we need to use "--emptrytree" testing here rather than
"empty" param testing because "empty"
param is used for -u, where you still *do* want to see when
something is being upgraded.
@param pkg: _emerge.Package.Package instance
@param pkg_info: dictionay
@rtype addl, myoldbest: list, myinslotlist: list
Modifies self.counters.reinst, self.counters.new
"""
myoldbest = []
myinslotlist = None
installed_versions = self.vardb.match_pkgs(pkg.cp)
if self.vardb.cpv_exists(pkg.cpv):
pkg_info.attr_display.replace = True
installed_version = pkg_info.previous_pkg
if installed_version.slot != pkg.slot or installed_version.sub_slot != pkg.sub_slot or \
not self.quiet_repo_display and installed_version.repo != pkg.repo:
myoldbest = [installed_version]
if pkg_info.ordered:
if pkg_info.merge:
self.counters.reinst += 1
# filter out old-style virtual matches
elif installed_versions and \
installed_versions[0].cp == pkg.cp:
myinslotlist = self.vardb.match_pkgs(pkg.slot_atom)
# If this is the first install of a new-style virtual, we
# need to filter out old-style virtual matches.
if myinslotlist and \
myinslotlist[0].cp != pkg.cp:
myinslotlist = None
if myinslotlist:
myoldbest = myinslotlist[:]
if not cpvequal(pkg.cpv,
best([pkg.cpv] + [x.cpv for x in myinslotlist])):
# Downgrade in slot
pkg_info.attr_display.new_version = True
pkg_info.attr_display.downgrade = True
if pkg_info.ordered:
self.counters.downgrades += 1
else:
# Update in slot
pkg_info.attr_display.new_version = True
if pkg_info.ordered:
self.counters.upgrades += 1
else:
myoldbest = installed_versions
pkg_info.attr_display.new = True
pkg_info.attr_display.new_slot = True
if pkg_info.ordered:
self.counters.newslot += 1
if self.conf.changelog:
self.do_changelog(pkg, pkg_info)
else:
pkg_info.attr_display.new = True
if pkg_info.ordered:
self.counters.new += 1
return myoldbest, myinslotlist
def __call__(self, depgraph, mylist, favorites=None, verbosity=None):
"""The main operation to format and display the resolver output.
@param depgraph: dependency grah
@param mylist: list of packages being processed
@param favorites: list, defaults to []
@param verbosity: verbose level, defaults to None
Modifies self.conf, self.myfetchlist, self.portdb, self.vardb,
self.pkgsettings, self.verboseadd, self.oldlp, self.newlp,
self.print_msg,
"""
if favorites is None:
favorites = []
self.conf = _DisplayConfig(depgraph, mylist, favorites, verbosity)
mylist = self.get_display_list(self.conf.mylist)
# files to fetch list - avoids counting a same file twice
# in size display (verbose mode)
self.myfetchlist = set()
self.quiet_repo_display = "--quiet-repo-display" in depgraph._frozen_config.myopts
if self.quiet_repo_display:
# Use this set to detect when all the "repoadd" strings are "[0]"
# and disable the entire repo display in this case.
repoadd_set = set()
self.verbose_main_repo_display = "--verbose-main-repo-display" in depgraph._frozen_config.myopts
self.restrict_fetch_list = {}
for mylist_index in range(len(mylist)):
pkg, depth, ordered = mylist[mylist_index]
self.portdb = self.conf.trees[pkg.root]["porttree"].dbapi
self.vardb = self.conf.trees[pkg.root]["vartree"].dbapi
self.pkgsettings = self.conf.pkgsettings[pkg.root]
self.indent = " " * depth
if isinstance(pkg, Blocker):
self._blockers(pkg)
else:
pkg_info = self.set_pkg_info(pkg, ordered)
pkg_info.oldbest_list, myinslotlist = \
self._get_installed_best(pkg, pkg_info)
if ordered and pkg_info.merge and \
not pkg_info.attr_display.new:
for arg, atom in depgraph._iter_atoms_for_pkg(pkg):
if arg.force_reinstall:
pkg_info.attr_display.force_reinstall = True
break
self.verboseadd = ""
if self.quiet_repo_display:
self.repoadd = None
self._display_use(pkg, pkg_info)
if self.conf.verbosity == 3:
if self.quiet_repo_display:
self.verbose_size(pkg, repoadd_set, pkg_info)
else:
self.verbose_size(pkg, None, pkg_info)
self.oldlp = self.conf.columnwidth - 30
self.newlp = self.oldlp - 30
pkg_info.oldbest = self.convert_myoldbest(pkg, pkg_info)
pkg_info.system, pkg_info.world = \
self.check_system_world(pkg)
if 'interactive' in pkg.properties and \
pkg.operation == 'merge':
pkg_info.attr_display.interactive = True
if ordered:
self.counters.interactive += 1
if self.include_mask_str():
pkg_info.attr_display.mask = self.gen_mask_str(pkg)
if pkg.root_config.settings["ROOT"] != "/":
if pkg_info.oldbest:
pkg_info.oldbest += " "
if self.conf.columns:
myprint = self._set_non_root_columns(pkg, pkg_info)
else:
pkg_str = pkg.cpv
if self.conf.verbosity == 3:
pkg_str = self._append_slot(pkg_str, pkg, pkg_info)
pkg_str = self._append_repository(pkg_str, pkg, pkg_info)
if not pkg_info.merge:
addl = self.empty_space_in_brackets()
myprint = "[%s%s] " % (
self.pkgprint(pkg_info.operation.ljust(13),
pkg_info), addl,
)
else:
myprint = "[%s %s] " % (
self.pkgprint(pkg.type_name, pkg_info),
pkg_info.attr_display)
myprint += self.indent + \
self.pkgprint(pkg_str, pkg_info) + " " + \
pkg_info.oldbest + darkgreen("to " + pkg.root)
else:
if self.conf.columns:
myprint = self._set_root_columns(pkg, pkg_info)
else:
myprint = self._set_no_columns(pkg, pkg_info)
if self.conf.columns and pkg.operation == "uninstall":
continue
if self.quiet_repo_display:
self.print_msg.append((myprint, self.verboseadd, self.repoadd))
else:
self.print_msg.append((myprint, self.verboseadd, None))
show_repos = self.quiet_repo_display and repoadd_set and repoadd_set != set(["0"])
# now finally print out the messages
self.print_messages(show_repos)
self.print_blockers()
if self.conf.verbosity == 3:
self.print_verbose(show_repos)
for pkg, pkg_info in self.restrict_fetch_list.items():
writemsg_stdout("\nFetch instructions for %s:\n" % (pkg.cpv,),
noiselevel=-1)
spawn_nofetch(self.conf.trees[pkg.root]["porttree"].dbapi,
pkg_info.ebuild_path)
if self.conf.changelog:
self.print_changelog()
return os.EX_OK
def format_unmatched_atom(pkg, atom, pkg_use_enabled):
"""
Returns two strings. The first string contains the
'atom' with parts of the atom colored, which 'pkg'
doesn't match. The second string has the same number
of characters as the first one, but consists of only
white space or ^. The ^ characters have the same position
as the colored parts of the first string.
"""
# Things to check:
# 1. Version
# 2. cp
# 3. slot/sub_slot
# 4. repository
# 5. USE
highlight = set()
def perform_coloring():
atom_str = ""
marker_str = ""
for ii, x in enumerate(atom):
if ii in highlight:
atom_str += colorize("BAD", x)
marker_str += "^"
else:
atom_str += x
marker_str += " "
return atom_str, marker_str
if atom.cp != pkg.cp:
# Highlight the cp part only.
ii = atom.find(atom.cp)
highlight.update(range(ii, ii + len(atom.cp)))
return perform_coloring()
version_atom = atom.without_repo.without_slot.without_use
version_atom_set = InternalPackageSet(initial_atoms=(version_atom,))
highlight_version = not bool(version_atom_set.findAtomForPackage(pkg,
modified_use=pkg_use_enabled(pkg)))
highlight_slot = False
if (atom.slot and atom.slot != pkg.slot) or \
(atom.sub_slot and atom.sub_slot != pkg.sub_slot):
highlight_slot = True
if highlight_version:
op = atom.operator
ver = None
if atom.cp != atom.cpv:
ver = cpv_getversion(atom.cpv)
if op == "=*":
op = "="
ver += "*"
if op is not None:
highlight.update(range(len(op)))
if ver is not None:
start = atom.rfind(ver)
end = start + len(ver)
highlight.update(range(start, end))
if highlight_slot:
slot_str = ":" + atom.slot
if atom.sub_slot:
slot_str += "/" + atom.sub_slot
if atom.slot_operator:
slot_str += atom.slot_operator
start = atom.find(slot_str)
end = start + len(slot_str)
highlight.update(range(start, end))
highlight_use = set()
if atom.use:
use_atom = "%s[%s]" % (atom.cp, str(atom.use))
use_atom_set = InternalPackageSet(initial_atoms=(use_atom,))
if not use_atom_set.findAtomForPackage(pkg, \
modified_use=pkg_use_enabled(pkg)):
missing_iuse = pkg.iuse.get_missing_iuse(
atom.unevaluated_atom.use.required)
if missing_iuse:
highlight_use = set(missing_iuse)
else:
#Use conditionals not met.
violated_atom = atom.violated_conditionals(
pkg_use_enabled(pkg), pkg.iuse.is_valid_flag)
if violated_atom.use is not None:
highlight_use = set(violated_atom.use.enabled.union(
violated_atom.use.disabled))
if highlight_use:
ii = atom.find("[") + 1
for token in atom.use.tokens:
if token.lstrip("-!").rstrip("=?") in highlight_use:
highlight.update(range(ii, ii + len(token)))
ii += len(token) + 1
return perform_coloring()