blob: d324d7ef77a13e5a73c77bebd4c951f89a0644ce [file] [log] [blame]
# Copyright 2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
__all__ = (
"display", "filter_iuse_defaults",
)
import codecs
import re
import sys
from portage import os
from portage import _encodings, _unicode_decode, _unicode_encode
from portage.dbapi.dep_expand import dep_expand
from portage.const import PORTAGE_PACKAGE_ATOM
from portage.dep import cpvequal, match_from_list
from portage.exception import InvalidDependString
from portage._sets.base import InternalPackageSet
from portage.output import blue, bold, colorize, create_color_func, darkblue, darkgreen, green, nc_len, red, \
teal, turquoise, yellow
bad = create_color_func("BAD")
from portage.util import writemsg, writemsg_stdout
from portage.versions import best, catpkgsplit, cpv_getkey
from _emerge.Blocker import Blocker
from _emerge.create_world_atom import create_world_atom
from _emerge.Package import Package
if sys.hexversion >= 0x3000000:
basestring = str
def filter_iuse_defaults(iuse):
for flag in iuse:
if flag.startswith("+") or flag.startswith("-"):
yield flag[1:]
else:
yield flag
class _RepoDisplay(object):
def __init__(self, roots):
self._shown_repos = {}
self._unknown_repo = False
repo_paths = set()
for root_config in roots.values():
portdir = root_config.settings.get("PORTDIR")
if root_config.settings.repositories:
repo_paths.update(root_config.settings.repositories.repoUserLocationList())
repo_paths = list(repo_paths)
self._repo_paths = repo_paths
self._repo_paths_real = [ os.path.realpath(repo_path) \
for repo_path in repo_paths ]
# pre-allocate index for PORTDIR so that it always has index 0.
for root_config in roots.values():
portdb = root_config.trees["porttree"].dbapi
portdir = portdb.porttree_root
if portdir:
self.repoStr(portdir)
def repoStr(self, repo_path_real):
real_index = -1
if repo_path_real:
real_index = self._repo_paths_real.index(repo_path_real)
if real_index == -1:
s = "?"
self._unknown_repo = True
else:
shown_repos = self._shown_repos
repo_paths = self._repo_paths
repo_path = repo_paths[real_index]
index = shown_repos.get(repo_path)
if index is None:
index = len(shown_repos)
shown_repos[repo_path] = index
s = str(index)
return s
def __str__(self):
output = []
shown_repos = self._shown_repos
unknown_repo = self._unknown_repo
if shown_repos or self._unknown_repo:
output.append("Portage tree and overlays:\n")
show_repo_paths = list(shown_repos)
for repo_path, repo_index in shown_repos.items():
show_repo_paths[repo_index] = repo_path
if show_repo_paths:
for index, repo_path in enumerate(show_repo_paths):
output.append(" "+teal("["+str(index)+"]")+" %s\n" % repo_path)
if unknown_repo:
output.append(" "+teal("[?]") + \
" indicates that the source repository could not be determined\n")
return "".join(output)
if sys.hexversion < 0x3000000:
__unicode__ = __str__
def __str__(self):
return _unicode_encode(self.__unicode__(),
encoding=_encodings['content'])
class _PackageCounters(object):
def __init__(self):
self.upgrades = 0
self.downgrades = 0
self.new = 0
self.newslot = 0
self.reinst = 0
self.uninst = 0
self.blocks = 0
self.blocks_satisfied = 0
self.totalsize = 0
self.restrict_fetch = 0
self.restrict_fetch_satisfied = 0
self.interactive = 0
self.binary = 0
def __str__(self):
total_installs = self.upgrades + self.downgrades + self.newslot + self.new + self.reinst
myoutput = []
details = []
myoutput.append("Total: %s package" % total_installs)
if total_installs != 1:
myoutput.append("s")
if total_installs != 0:
myoutput.append(" (")
if self.upgrades > 0:
details.append("%s upgrade" % self.upgrades)
if self.upgrades > 1:
details[-1] += "s"
if self.downgrades > 0:
details.append("%s downgrade" % self.downgrades)
if self.downgrades > 1:
details[-1] += "s"
if self.new > 0:
details.append("%s new" % self.new)
if self.newslot > 0:
details.append("%s in new slot" % self.newslot)
if self.newslot > 1:
details[-1] += "s"
if self.reinst > 0:
details.append("%s reinstall" % self.reinst)
if self.reinst > 1:
details[-1] += "s"
if self.binary > 0:
details.append("%s binary" % self.binary)
if self.binary > 1:
details[-1] = details[-1][:-1] + "ies"
if self.uninst > 0:
details.append("%s uninstall" % self.uninst)
if self.uninst > 1:
details[-1] += "s"
if self.interactive > 0:
details.append("%s %s" % (self.interactive,
colorize("WARN", "interactive")))
myoutput.append(", ".join(details))
if total_installs != 0:
myoutput.append(")")
myoutput.append(", Size of downloads: %s" % _format_size(self.totalsize))
if self.restrict_fetch:
myoutput.append("\nFetch Restriction: %s package" % \
self.restrict_fetch)
if self.restrict_fetch > 1:
myoutput.append("s")
if self.restrict_fetch_satisfied < self.restrict_fetch:
myoutput.append(bad(" (%s unsatisfied)") % \
(self.restrict_fetch - self.restrict_fetch_satisfied))
if self.blocks > 0:
myoutput.append("\nConflict: %s block" % \
self.blocks)
if self.blocks > 1:
myoutput.append("s")
if self.blocks_satisfied < self.blocks:
myoutput.append(bad(" (%s unsatisfied)") % \
(self.blocks - self.blocks_satisfied))
return "".join(myoutput)
class _DisplayConfig(object):
def __init__(self, depgraph, mylist, favorites, verbosity):
frozen_config = depgraph._frozen_config
dynamic_config = depgraph._dynamic_config
self.mylist = mylist
self.favorites = InternalPackageSet(favorites, allow_repo=True)
self.verbosity = verbosity
if self.verbosity is None:
self.verbosity = ("--quiet" in frozen_config.myopts and 1 or \
"--verbose" in frozen_config.myopts and 3 or 2)
self.oneshot = "--oneshot" in frozen_config.myopts or \
"--onlydeps" in frozen_config.myopts
self.columns = "--columns" in frozen_config.myopts
self.tree_display = "--tree" in frozen_config.myopts
self.alphabetical = "--alphabetical" in frozen_config.myopts
self.quiet = "--quiet" in frozen_config.myopts
self.all_flags = self.verbosity == 3 or self.quiet
self.print_use_string = self.verbosity != 1 or "--verbose" in frozen_config.myopts
self.changelog = "--changelog" in frozen_config.myopts
self.edebug = frozen_config.edebug
self.no_restart = frozen_config._opts_no_restart.intersection(frozen_config.myopts)
self.unordered_display = "--unordered-display" in frozen_config.myopts
mywidth = 130
if "COLUMNWIDTH" in frozen_config.settings:
try:
mywidth = int(frozen_config.settings["COLUMNWIDTH"])
except ValueError as e:
writemsg("!!! %s\n" % str(e), noiselevel=-1)
writemsg("!!! Unable to parse COLUMNWIDTH='%s'\n" % \
frozen_config.settings["COLUMNWIDTH"], noiselevel=-1)
del e
self.columnwidth = mywidth
self.repo_display = _RepoDisplay(frozen_config.roots)
self.trees = frozen_config.trees
self.pkgsettings = frozen_config.pkgsettings
self.target_root = frozen_config.target_root
self.running_root = frozen_config._running_root
self.roots = frozen_config.roots
self.blocker_parents = dynamic_config._blocker_parents
self.reinstall_nodes = dynamic_config._reinstall_nodes
self.digraph = dynamic_config.digraph
self.blocker_uninstalls = dynamic_config._blocker_uninstalls
self.slot_pkg_map = dynamic_config._slot_pkg_map
self.set_nodes = dynamic_config._set_nodes
self.pkg_use_enabled = depgraph._pkg_use_enabled
self.pkg = depgraph._pkg
# formats a size given in bytes nicely
def _format_size(mysize):
if isinstance(mysize, basestring):
return mysize
if 0 != mysize % 1024:
# Always round up to the next kB so that it doesn't show 0 kB when
# some small file still needs to be fetched.
mysize += 1024 - mysize % 1024
mystr=str(mysize//1024)
mycount=len(mystr)
while (mycount > 3):
mycount-=3
mystr=mystr[:mycount]+","+mystr[mycount:]
return mystr+" kB"
def display(depgraph, mylist, favorites=[], verbosity=None):
conf = _DisplayConfig(depgraph, mylist, favorites, verbosity)
changelogs=[]
p=[]
blockers = []
counters = _PackageCounters()
repo_display = conf.repo_display
unsatisfied_blockers = []
ordered_nodes = []
for x in conf.mylist:
if isinstance(x, Blocker):
counters.blocks += 1
if x.satisfied:
ordered_nodes.append(x)
counters.blocks_satisfied += 1
else:
unsatisfied_blockers.append(x)
else:
ordered_nodes.append(x)
if conf.tree_display:
display_list = _tree_display(conf, ordered_nodes)
else:
display_list = [(x, 0, True) for x in ordered_nodes]
mylist = display_list
for x in unsatisfied_blockers:
mylist.append((x, 0, True))
# files to fetch list - avoids counting a same file twice
# in size display (verbose mode)
myfetchlist=[]
# Use this set to detect when all the "repoadd" strings are "[0]"
# and disable the entire repo display in this case.
repoadd_set = set()
for mylist_index in range(len(mylist)):
x, depth, ordered = mylist[mylist_index]
pkg_type = x[0]
myroot = x[1]
pkg_key = x[2]
portdb = conf.trees[myroot]["porttree"].dbapi
vardb = conf.trees[myroot]["vartree"].dbapi
pkgsettings = conf.pkgsettings[myroot]
fetch=" "
indent = " " * depth
if isinstance(x, Blocker):
if x.satisfied:
blocker_style = "PKG_BLOCKER_SATISFIED"
addl = "%s %s " % (colorize(blocker_style, "b"), fetch)
else:
blocker_style = "PKG_BLOCKER"
addl = "%s %s " % (colorize(blocker_style, "B"), fetch)
resolved = dep_expand(
str(x.atom).lstrip("!"), mydb=vardb, settings=pkgsettings)
if conf.columns and conf.quiet:
addl += " " + colorize(blocker_style, str(resolved))
else:
addl = "[%s %s] %s%s" % \
(colorize(blocker_style, "blocks"),
addl, indent, colorize(blocker_style, str(resolved)))
block_parents = conf.blocker_parents.parent_nodes(x)
block_parents = set([pnode[2] for pnode in block_parents])
block_parents = ", ".join(block_parents)
if resolved!=x[2]:
addl += colorize(blocker_style,
" (\"%s\" is blocking %s)") % \
(str(x.atom).lstrip("!"), block_parents)
else:
addl += colorize(blocker_style,
" (is blocking %s)") % block_parents
if isinstance(x, Blocker) and x.satisfied:
if conf.columns:
continue
p.append(addl)
else:
blockers.append(addl)
else:
pkg_status = x[3]
pkg_merge = ordered and pkg_status == "merge"
if not pkg_merge and pkg_status == "merge":
pkg_status = "nomerge"
built = pkg_type != "ebuild"
pkg = x
metadata = pkg.metadata
ebuild_path = None
repo_name = pkg.repo
if pkg.type_name == "ebuild":
ebuild_path = portdb.findname(pkg.cpv, myrepo=repo_name)
if ebuild_path is None:
raise AssertionError(
"ebuild not found for '%s'" % pkg.cpv)
repo_path_real = os.path.dirname(os.path.dirname(
os.path.dirname(ebuild_path)))
else:
repo_path_real = portdb.getRepositoryPath(repo_name)
pkg_use = list(conf.pkg_use_enabled(pkg))
if not pkg.built and pkg.operation == 'merge' and \
'fetch' in pkg.metadata.restrict:
fetch = red("F")
if ordered:
counters.restrict_fetch += 1
if portdb.fetch_check(pkg_key, pkg_use, myrepo=pkg.repo):
fetch = green("f")
if ordered:
counters.restrict_fetch_satisfied += 1
#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.
myoldbest = []
myinslotlist = None
installed_versions = vardb.match(cpv_getkey(pkg_key))
if vardb.cpv_exists(pkg_key):
addl=" "+yellow("R")+fetch+" "
if ordered:
if pkg_merge:
counters.reinst += 1
if pkg_type == "binary":
counters.binary += 1
elif pkg_status == "uninstall":
counters.uninst += 1
# filter out old-style virtual matches
elif installed_versions and \
cpv_getkey(installed_versions[0]) == \
cpv_getkey(pkg_key):
myinslotlist = vardb.match(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 \
cpv_getkey(myinslotlist[0]) != \
cpv_getkey(pkg_key):
myinslotlist = None
if myinslotlist:
myoldbest = myinslotlist[:]
addl = " " + fetch
if not cpvequal(pkg_key,
best([pkg_key] + myoldbest)):
# Downgrade in slot
addl += turquoise("U")+blue("D")
if ordered:
counters.downgrades += 1
if pkg_type == "binary":
counters.binary += 1
else:
# Update in slot
addl += turquoise("U") + " "
if ordered:
counters.upgrades += 1
if pkg_type == "binary":
counters.binary += 1
else:
# New slot, mark it new.
addl = " " + green("NS") + fetch + " "
myoldbest = vardb.match(cpv_getkey(pkg_key))
if ordered:
counters.newslot += 1
if pkg_type == "binary":
counters.binary += 1
if conf.changelog:
inst_matches = vardb.match(pkg.slot_atom)
if inst_matches:
ebuild_path_cl = ebuild_path
if ebuild_path_cl is None:
# binary package
ebuild_path_cl = portdb.findname(pkg.cpv)
if ebuild_path_cl is not None:
changelogs.extend(_calc_changelog(
ebuild_path_cl, inst_matches[0], pkg.cpv))
else:
addl = " " + green("N") + " " + fetch + " "
if ordered:
counters.new += 1
if pkg_type == "binary":
counters.binary += 1
verboseadd = ""
repoadd = None
if True:
# USE flag display
forced_flags = set()
pkgsettings.setcpv(pkg) # for package.use.{mask,force}
forced_flags.update(pkgsettings.useforce)
forced_flags.update(pkgsettings.usemask)
cur_use = [flag for flag in conf.pkg_use_enabled(pkg) \
if flag in pkg.iuse.all]
cur_iuse = sorted(pkg.iuse.all)
if myoldbest and myinslotlist:
previous_cpv = myoldbest[0]
else:
previous_cpv = pkg.cpv
if vardb.cpv_exists(previous_cpv):
old_iuse, old_use = vardb.aux_get(
previous_cpv, ["IUSE", "USE"])
old_iuse = list(set(
filter_iuse_defaults(old_iuse.split())))
old_iuse.sort()
old_use = old_use.split()
is_new = False
else:
old_iuse = []
old_use = []
is_new = True
old_use = [flag for flag in old_use if flag in old_iuse]
use_expand = pkgsettings["USE_EXPAND"].lower().split()
use_expand.sort()
use_expand.reverse()
use_expand_hidden = \
pkgsettings["USE_EXPAND_HIDDEN"].lower().split()
def map_to_use_expand(myvals, forcedFlags=False,
removeHidden=True):
ret = {}
forced = {}
for exp in use_expand:
ret[exp] = []
forced[exp] = set()
for val in myvals[:]:
if val.startswith(exp.lower()+"_"):
if val in 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 forced_flags]
if removeHidden:
for exp in use_expand_hidden:
ret.pop(exp, None)
if forcedFlags:
return ret, forced
return ret
# Prevent USE_EXPAND_HIDDEN flags from being hidden if they
# are the only thing that triggered reinstallation.
reinst_flags_map = {}
reinstall_for_flags = conf.reinstall_nodes.get(pkg)
reinst_expand_map = None
if reinstall_for_flags:
reinst_flags_map = map_to_use_expand(
list(reinstall_for_flags), removeHidden=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(
use_expand_hidden):
use_expand_hidden = \
set(use_expand_hidden).difference(
reinst_expand_map)
cur_iuse_map, iuse_forced = \
map_to_use_expand(cur_iuse, forcedFlags=True)
cur_use_map = map_to_use_expand(cur_use)
old_iuse_map = map_to_use_expand(old_iuse)
old_use_map = map_to_use_expand(old_use)
use_expand.sort()
use_expand.insert(0, "USE")
for key in use_expand:
if key in use_expand_hidden:
continue
verboseadd += _create_use_string(conf, key.upper(),
cur_iuse_map[key], iuse_forced[key],
cur_use_map[key], old_iuse_map[key],
old_use_map[key], is_new,
reinst_flags_map.get(key))
if conf.verbosity == 3:
# size verbose
mysize=0
if pkg_type == "ebuild" and pkg_merge:
try:
myfilesdict = portdb.getfetchsizes(pkg_key,
useflags=pkg_use, debug=conf.edebug)
except InvalidDependString:
# should have been masked before it was selected
raise
if myfilesdict is None:
myfilesdict="[empty/missing/bad digest]"
else:
for myfetchfile in myfilesdict:
if myfetchfile not in myfetchlist:
mysize+=myfilesdict[myfetchfile]
myfetchlist.append(myfetchfile)
if ordered:
counters.totalsize += mysize
verboseadd += _format_size(mysize)
# overlay verbose
# assign index for a previous version in the same slot
has_previous = False
repo_name_prev = None
slot_matches = vardb.match(pkg.slot_atom)
if slot_matches:
has_previous = True
repo_name_prev = vardb.aux_get(slot_matches[0],
["repository"])[0]
# now use the data to generate output
if pkg.installed or not has_previous:
repoadd = repo_display.repoStr(repo_path_real)
else:
repo_path_prev = None
if repo_name_prev:
repo_path_prev = portdb.getRepositoryPath(
repo_name_prev)
if repo_path_prev == repo_path_real:
repoadd = repo_display.repoStr(repo_path_real)
else:
repoadd = "%s=>%s" % (
repo_display.repoStr(repo_path_prev),
repo_display.repoStr(repo_path_real))
if repoadd:
repoadd_set.add(repoadd)
xs = [cpv_getkey(pkg_key)] + \
list(catpkgsplit(pkg_key)[2:])
if xs[2] == "r0":
xs[2] = ""
else:
xs[2] = "-" + xs[2]
oldlp = conf.columnwidth - 30
newlp = oldlp - 30
# Convert myoldbest from a list to a string.
if not myoldbest:
myoldbest = ""
else:
for pos, key in enumerate(myoldbest):
key = catpkgsplit(key)[2] + \
"-" + catpkgsplit(key)[3]
if key[-3:] == "-r0":
key = key[:-3]
myoldbest[pos] = key
myoldbest = blue("["+", ".join(myoldbest)+"]")
pkg_cp = xs[0]
root_config = conf.roots[myroot]
system_set = root_config.sets["system"]
world_set = root_config.sets["selected"]
pkg_system = False
pkg_world = False
try:
pkg_system = system_set.findAtomForPackage(pkg, modified_use=conf.pkg_use_enabled(pkg))
pkg_world = world_set.findAtomForPackage(pkg, modified_use=conf.pkg_use_enabled(pkg))
if not (conf.oneshot or pkg_world) and \
myroot == conf.target_root and \
conf.favorites.findAtomForPackage(pkg, modified_use=conf.pkg_use_enabled(pkg)):
# Maybe it will be added to world now.
if create_world_atom(pkg, conf.favorites, root_config):
pkg_world = True
except InvalidDependString:
# This is reported elsewhere if relevant.
pass
def pkgprint(pkg_str):
if pkg_merge:
if built:
if pkg_system:
return colorize("PKG_BINARY_MERGE_SYSTEM", pkg_str)
elif pkg_world:
return colorize("PKG_BINARY_MERGE_WORLD", pkg_str)
else:
return colorize("PKG_BINARY_MERGE", pkg_str)
else:
if pkg_system:
return colorize("PKG_MERGE_SYSTEM", pkg_str)
elif pkg_world:
return colorize("PKG_MERGE_WORLD", pkg_str)
else:
return colorize("PKG_MERGE", pkg_str)
elif pkg_status == "uninstall":
return colorize("PKG_UNINSTALL", pkg_str)
else:
if pkg_system:
return colorize("PKG_NOMERGE_SYSTEM", pkg_str)
elif pkg_world:
return colorize("PKG_NOMERGE_WORLD", pkg_str)
else:
return colorize("PKG_NOMERGE", pkg_str)
if 'interactive' in pkg.metadata.properties and \
pkg.operation == 'merge':
addl = colorize("WARN", "I") + addl[1:]
if ordered:
counters.interactive += 1
if x[1]!="/":
if myoldbest:
myoldbest +=" "
if conf.columns:
if conf.quiet:
myprint=addl+" "+indent+pkgprint(pkg_cp)
myprint=myprint+darkblue(" "+xs[1]+xs[2])+" "
myprint=myprint+myoldbest
myprint=myprint+darkgreen("to "+x[1])
verboseadd = None
else:
if not pkg_merge:
myprint = "[%s] %s%s" % \
(pkgprint(pkg_status.ljust(13)),
indent, pkgprint(pkg.cp))
else:
myprint = "[%s %s] %s%s" % \
(pkgprint(pkg.type_name), addl,
indent, pkgprint(pkg.cp))
if (newlp-nc_len(myprint)) > 0:
myprint=myprint+(" "*(newlp-nc_len(myprint)))
myprint=myprint+"["+darkblue(xs[1]+xs[2])+"] "
if (oldlp-nc_len(myprint)) > 0:
myprint=myprint+" "*(oldlp-nc_len(myprint))
myprint=myprint+myoldbest
myprint += darkgreen("to " + pkg.root)
else:
if not pkg_merge:
myprint = "[%s] " % pkgprint(pkg_status.ljust(13))
else:
myprint = "[%s %s] " % (pkgprint(pkg_type), addl)
myprint += indent + pkgprint(pkg_key) + " " + \
myoldbest + darkgreen("to " + myroot)
else:
if conf.columns:
if conf.quiet:
myprint=addl+" "+indent+pkgprint(pkg_cp)
myprint=myprint+" "+green(xs[1]+xs[2])+" "
myprint=myprint+myoldbest
verboseadd = None
else:
if not pkg_merge:
myprint = "[%s] %s%s" % \
(pkgprint(pkg_status.ljust(13)),
indent, pkgprint(pkg.cp))
else:
myprint = "[%s %s] %s%s" % \
(pkgprint(pkg.type_name), addl,
indent, pkgprint(pkg.cp))
if (newlp-nc_len(myprint)) > 0:
myprint=myprint+(" "*(newlp-nc_len(myprint)))
myprint=myprint+green(" ["+xs[1]+xs[2]+"] ")
if (oldlp-nc_len(myprint)) > 0:
myprint=myprint+(" "*(oldlp-nc_len(myprint)))
myprint += myoldbest
else:
if not pkg_merge:
myprint = "[%s] %s%s %s" % \
(pkgprint(pkg_status.ljust(13)),
indent, pkgprint(pkg.cpv),
myoldbest)
else:
myprint = "[%s %s] %s%s %s" % \
(pkgprint(pkg_type), addl, indent,
pkgprint(pkg.cpv), myoldbest)
if conf.columns and pkg.operation == "uninstall":
continue
p.append((myprint, verboseadd, repoadd))
if not conf.tree_display and \
conf.quiet and \
not conf.no_restart and \
pkg.root == conf.running_root.root and \
match_from_list(
PORTAGE_PACKAGE_ATOM, [pkg]) and \
not conf.quiet:
if not vardb.cpv_exists(pkg.cpv) or \
'9999' in pkg.cpv or \
'git' in pkg.inherited:
if mylist_index < len(mylist) - 1:
p.append(colorize("WARN", "*** Portage will stop merging at this point and reload itself,"))
p.append(colorize("WARN", " then resume the merge."))
show_repos = repoadd_set and repoadd_set != set(["0"])
for x in p:
if isinstance(x, basestring):
writemsg_stdout("%s\n" % (x,), noiselevel=-1)
continue
myprint, verboseadd, repoadd = x
if verboseadd:
myprint += " " + verboseadd
if show_repos and repoadd:
myprint += " " + teal("[%s]" % repoadd)
writemsg_stdout("%s\n" % (myprint,), noiselevel=-1)
for x in blockers:
writemsg_stdout("%s\n" % (x,), noiselevel=-1)
if conf.verbosity == 3:
writemsg_stdout('\n%s\n' % (counters,), noiselevel=-1)
if show_repos:
# Use _unicode_decode() to force unicode format string so
# that RepoDisplay.__unicode__() is called in python2.
writemsg_stdout(_unicode_decode("%s") % (repo_display,),
noiselevel=-1)
if conf.changelog:
writemsg_stdout('\n', noiselevel=-1)
for revision,text in changelogs:
writemsg_stdout(bold('*'+revision) + '\n' + text,
noiselevel=-1)
return os.EX_OK
def _create_use_string(conf, name, cur_iuse, iuse_forced, cur_use,
old_iuse, old_use,
is_new, reinst_flags):
if not conf.print_use_string:
return ""
enabled = []
if conf.alphabetical:
disabled = enabled
removed = enabled
else:
disabled = []
removed = []
cur_iuse = set(cur_iuse)
enabled_flags = cur_iuse.intersection(cur_use)
removed_iuse = set(old_iuse).difference(cur_iuse)
any_iuse = cur_iuse.union(old_iuse)
any_iuse = list(any_iuse)
any_iuse.sort()
for flag in any_iuse:
flag_str = None
isEnabled = False
reinst_flag = reinst_flags and flag in reinst_flags
if flag in enabled_flags:
isEnabled = True
if is_new or flag in old_use and \
(conf.all_flags or reinst_flag):
flag_str = red(flag)
elif flag not in old_iuse:
flag_str = yellow(flag) + "%*"
elif flag not in old_use:
flag_str = green(flag) + "*"
elif flag in removed_iuse:
if conf.all_flags or reinst_flag:
flag_str = yellow("-" + flag) + "%"
if flag in old_use:
flag_str += "*"
flag_str = "(" + flag_str + ")"
removed.append(flag_str)
continue
else:
if is_new or flag in old_iuse and \
flag not in old_use and \
(conf.all_flags or reinst_flag):
flag_str = blue("-" + flag)
elif flag not in old_iuse:
flag_str = yellow("-" + flag)
if flag not in iuse_forced:
flag_str += "%"
elif flag in old_use:
flag_str = green("-" + flag) + "*"
if flag_str:
if flag in iuse_forced:
flag_str = "(" + flag_str + ")"
if isEnabled:
enabled.append(flag_str)
else:
disabled.append(flag_str)
if conf.alphabetical:
ret = " ".join(enabled)
else:
ret = " ".join(enabled + disabled + removed)
if ret:
ret = '%s="%s" ' % (name, ret)
return ret
def _tree_display(conf, mylist):
# If there are any Uninstall instances, add the
# corresponding blockers to the digraph.
mygraph = conf.digraph.copy()
executed_uninstalls = set(node for node in mylist \
if isinstance(node, Package) and node.operation == "unmerge")
for uninstall in conf.blocker_uninstalls.leaf_nodes():
uninstall_parents = \
conf.blocker_uninstalls.parent_nodes(uninstall)
if not uninstall_parents:
continue
# Remove the corresponding "nomerge" node and substitute
# the Uninstall node.
inst_pkg = conf.pkg(uninstall.cpv, "installed",
uninstall.root_config, installed=True)
try:
mygraph.remove(inst_pkg)
except KeyError:
pass
try:
inst_pkg_blockers = conf.blocker_parents.child_nodes(inst_pkg)
except KeyError:
inst_pkg_blockers = []
# Break the Package -> Uninstall edges.
mygraph.remove(uninstall)
# Resolution of a package's blockers
# depend on it's own uninstallation.
for blocker in inst_pkg_blockers:
mygraph.add(uninstall, blocker)
# Expand Package -> Uninstall edges into
# Package -> Blocker -> Uninstall edges.
for blocker in uninstall_parents:
mygraph.add(uninstall, blocker)
for parent in conf.blocker_parents.parent_nodes(blocker):
if parent != inst_pkg:
mygraph.add(blocker, parent)
# If the uninstall task did not need to be executed because
# of an upgrade, display Blocker -> Upgrade edges since the
# corresponding Blocker -> Uninstall edges will not be shown.
upgrade_node = \
conf.slot_pkg_map[uninstall.root].get(uninstall.slot_atom)
if upgrade_node is not None and \
uninstall not in executed_uninstalls:
for blocker in uninstall_parents:
mygraph.add(upgrade_node, blocker)
if conf.unordered_display:
display_list = _unordered_tree_display(mygraph, mylist)
else:
display_list = _ordered_tree_display(conf, mygraph, mylist)
_prune_tree_display(display_list)
return display_list
def _unordered_tree_display(mygraph, mylist):
display_list = []
seen_nodes = set()
def print_node(node, depth):
if node in seen_nodes:
pass
else:
seen_nodes.add(node)
if isinstance(node, (Blocker, Package)):
display_list.append((node, depth, True))
else:
depth = -1
for child_node in mygraph.child_nodes(node):
print_node(child_node, depth + 1)
for root_node in mygraph.root_nodes():
print_node(root_node, 0)
return display_list
def _ordered_tree_display(conf, mygraph, mylist):
depth = 0
shown_edges = set()
tree_nodes = []
display_list = []
for x in mylist:
depth = len(tree_nodes)
while depth and x not in \
mygraph.child_nodes(tree_nodes[depth-1]):
depth -= 1
if depth:
tree_nodes = tree_nodes[:depth]
tree_nodes.append(x)
display_list.append((x, depth, True))
shown_edges.add((x, tree_nodes[depth-1]))
else:
traversed_nodes = set() # prevent endless circles
traversed_nodes.add(x)
def add_parents(current_node, ordered):
parent_nodes = None
# Do not traverse to parents if this node is an
# an argument or a direct member of a set that has
# been specified as an argument (system or world).
if current_node not in conf.set_nodes:
parent_nodes = mygraph.parent_nodes(current_node)
if parent_nodes:
child_nodes = set(mygraph.child_nodes(current_node))
selected_parent = None
# First, try to avoid a direct cycle.
for node in parent_nodes:
if not isinstance(node, (Blocker, Package)):
continue
if node not in traversed_nodes and \
node not in child_nodes:
edge = (current_node, node)
if edge in shown_edges:
continue
selected_parent = node
break
if not selected_parent:
# A direct cycle is unavoidable.
for node in parent_nodes:
if not isinstance(node, (Blocker, Package)):
continue
if node not in traversed_nodes:
edge = (current_node, node)
if edge in shown_edges:
continue
selected_parent = node
break
if selected_parent:
shown_edges.add((current_node, selected_parent))
traversed_nodes.add(selected_parent)
add_parents(selected_parent, False)
display_list.append((current_node,
len(tree_nodes), ordered))
tree_nodes.append(current_node)
tree_nodes = []
add_parents(x, True)
return display_list
def _prune_tree_display(display_list):
last_merge_depth = 0
for i in range(len(display_list) - 1, -1, -1):
node, depth, ordered = display_list[i]
if not ordered and depth == 0 and i > 0 \
and node == display_list[i-1][0] and \
display_list[i-1][1] == 0:
# An ordered node got a consecutive duplicate
# when the tree was being filled in.
del display_list[i]
continue
if ordered and isinstance(node, Package) \
and node.operation in ('merge', 'uninstall'):
last_merge_depth = depth
continue
if depth >= last_merge_depth or \
i < len(display_list) - 1 and \
depth >= display_list[i+1][1]:
del display_list[i]
def _calc_changelog(ebuildpath,current,next):
if ebuildpath == None or not os.path.exists(ebuildpath):
return []
current = '-'.join(catpkgsplit(current)[1:])
if current.endswith('-r0'):
current = current[:-3]
next = '-'.join(catpkgsplit(next)[1:])
if next.endswith('-r0'):
next = next[:-3]
changelogpath = os.path.join(os.path.split(ebuildpath)[0],'ChangeLog')
try:
changelog = codecs.open(_unicode_encode(changelogpath,
encoding=_encodings['fs'], errors='strict'),
mode='r', encoding=_encodings['repo.content'], errors='replace'
).read()
except SystemExit:
raise # Needed else can't exit
except:
return []
divisions = _find_changelog_tags(changelog)
#print 'XX from',current,'to',next
#for div,text in divisions: print 'XX',div
# skip entries for all revisions above the one we are about to emerge
for i in range(len(divisions)):
if divisions[i][0]==next:
divisions = divisions[i:]
break
# find out how many entries we are going to display
for i in range(len(divisions)):
if divisions[i][0]==current:
divisions = divisions[:i]
break
else:
# couldnt find the current revision in the list. display nothing
return []
return divisions
def _find_changelog_tags(changelog):
divs = []
release = None
while 1:
match = re.search(r'^\*\ ?([-a-zA-Z0-9_.+]*)(?:\ .*)?\n',changelog,re.M)
if match is None:
if release is not None:
divs.append((release,changelog))
return divs
if release is not None:
divs.append((release,changelog[:match.start()]))
changelog = changelog[match.end():]
release = match.group(1)
if release.endswith('.ebuild'):
release = release[:-7]
if release.endswith('-r0'):
release = release[:-3]