from portage.output import create_color_func
good = create_color_func("GOOD")
bad = create_color_func("BAD")
+# white looks bad on terminals with white background
+from portage.output import bold as white
import portage.dep
portage.dep._dep_check_strict = True
from portage.data import secpass
from portage.util import normalize_path as normpath
from portage.util import writemsg
+from portage.sets import InternalPackageSet
+from portage.sets.profiles import PackagesSystemSet as SystemSet
+from portage.sets.files import WorldSet
-if not hasattr(__builtins__, "set"):
- from sets import Set as set
from itertools import chain, izip
from UserDict import DictMixin
KeyboardInterrupt is converted to SystemExit to avoid tracebacks being
printed."""
if responses is None:
- responses, colours = ["Yes", "No"], [green, red]
+ responses = ["Yes", "No"]
+ colours = [
+ create_color_func("PROMPT_CHOICE_DEFAULT"),
+ create_color_func("PROMPT_CHOICE_OTHER")
+ ]
elif colours is None:
colours=[bold]
colours=(colours*len(responses))[:len(responses)]
# recurse: go into the dependencies
# deep: go into the dependencies of already merged packages
# empty: pretend nothing is merged
- myparams = ["recurse"]
- add=[]
- sub=[]
+ myparams = set(["recurse"])
if "--update" in myopts or \
"--newuse" in myopts or \
+ "--reinstall" in myopts or \
"--noreplace" in myopts or \
myaction in ("system", "world"):
- add.extend(["selective"])
+ myparams.add("selective")
if "--emptytree" in myopts:
- add.extend(["empty"])
- sub.extend(["selective"])
+ myparams.add("empty")
+ myparams.discard("selective")
if "--nodeps" in myopts:
- sub.extend(["recurse"])
+ myparams.discard("recurse")
if "--deep" in myopts:
- add.extend(["deep"])
- for x in add:
- if (x not in myparams) and (x not in sub):
- myparams.append(x)
- for x in sub:
- if x in myparams:
- myparams.remove(x)
+ myparams.add("deep")
return myparams
# search functionality
def clean_world(vardb, cpv):
"""Remove a package from the world file when unmerged."""
- world_filename = os.path.join(vardb.root, portage.WORLD_FILE)
- worldlist = portage.util.grabfile(world_filename)
+ world_set = WorldSet("world", vardb.settings["ROOT"])
+ world_set.lock()
+ worldlist = list(world_set) # loads latest from disk
mykey = portage.cpv_getkey(cpv)
newworldlist = []
for x in worldlist:
#this doesn't match the package we're unmerging; keep it.
newworldlist.append(x)
- portage.util.ensure_dirs(os.path.join(vardb.root, portage.PRIVATE_PATH),
- gid=portage.portage_gid, mode=02770)
- portage.util.write_atomic(world_filename, "\n".join(newworldlist))
+ world_set.replace(newworldlist)
+ world_set.unlock()
-def genericdict(mylist):
- mynewdict={}
- for x in mylist:
- mynewdict[portage.dep_getkey(x)]=x
- return mynewdict
+
+class RootConfig(object):
+ """This is used internally by depgraph to track information about a
+ particular $ROOT."""
+ def __init__(self, trees):
+ self.trees = trees
+ self.settings = trees["vartree"].settings
+ self.root = self.settings["ROOT"]
+ self.sets = {}
+ world_set = WorldSet("world", self.root)
+ self.sets["world"] = world_set
+ system_set = SystemSet("system", self.settings.profiles)
+ self.sets["system"] = system_set
+
+def create_world_atom(pkg_key, metadata, args_set, root_config):
+ """Create a new atom for the world file if one does not exist. If the
+ argument atom is precise enough to identify a specific slot then a slot
+ atom will be returned. Atoms that are in the system set may also be stored
+ in world since system atoms can only match one slot while world atoms can
+ be greedy with respect to slots. Unslotted system packages will not be
+ stored in world."""
+ arg_atom = args_set.findAtomForPackage(pkg_key, metadata)
+ cp = portage.dep_getkey(arg_atom)
+ new_world_atom = cp
+ sets = root_config.sets
+ portdb = root_config.trees["porttree"].dbapi
+ vardb = root_config.trees["vartree"].dbapi
+ available_slots = set(portdb.aux_get(cpv, ["SLOT"])[0] \
+ for cpv in portdb.match(cp))
+ slotted = len(available_slots) > 1 or \
+ (len(available_slots) == 1 and "0" not in available_slots)
+ if not slotted:
+ # check the vdb in case this is multislot
+ available_slots = set(vardb.aux_get(cpv, ["SLOT"])[0] \
+ for cpv in vardb.match(cp))
+ slotted = len(available_slots) > 1 or \
+ (len(available_slots) == 1 and "0" not in available_slots)
+ if slotted and arg_atom != cp:
+ # If the user gave a specific atom, store it as a
+ # slot atom in the world file.
+ slot_atom = "%s:%s" % (cp, metadata["SLOT"])
+ # First verify the slot is in the portage tree to avoid
+ # adding a bogus slot like that produced by multislot.
+ if portdb.match(slot_atom):
+ # Now verify that the argument is precise enough to identify a
+ # specific slot.
+ matches = portdb.match(arg_atom)
+ matched_slots = set()
+ for cpv in matches:
+ matched_slots.add(portdb.aux_get(cpv, ["SLOT"])[0])
+ if len(matched_slots) == 1:
+ new_world_atom = slot_atom
+ if new_world_atom == sets["world"].findAtomForPackage(pkg_key, metadata):
+ # Both atoms would be identical, so there's nothing to add.
+ return None
+ if not slotted:
+ # Unlike world atoms, system atoms are not greedy for slots, so they
+ # can't be safely excluded from world if they are slotted.
+ system_atom = sets["system"].findAtomForPackage(pkg_key, metadata)
+ if system_atom:
+ if not portage.dep_getkey(system_atom).startswith("virtual/"):
+ return None
+ # System virtuals aren't safe to exclude from world since they can
+ # match multiple old-style virtuals but only one of them will be
+ # pulled in by update or depclean.
+ providers = portdb.mysettings.getvirtuals().get(
+ portage.dep_getkey(system_atom))
+ if providers and len(providers) == 1 and providers[0] == cp:
+ return None
+ return new_world_atom
def filter_iuse_defaults(iuse):
for flag in iuse:
levels:
MEDIUM The upper boundary for medium dependencies.
+ MEDIUM_SOFT The upper boundary for medium-soft dependencies.
SOFT The upper boundary for soft dependencies.
MIN The lower boundary for soft dependencies.
"""
- __slots__ = ("__weakref__", "satisfied", "buildtime", "runtime")
+ __slots__ = ("__weakref__", "satisfied", "buildtime", "runtime", "runtime_post")
MEDIUM = -1
- SOFT = -2
- MIN = -4
+ MEDIUM_SOFT = -2
+ SOFT = -3
+ MIN = -6
def __init__(self, **kwargs):
for myattr in self.__slots__:
if myattr == "__weakref__":
return 0
if self.runtime:
return -1
+ if self.runtime_post:
+ return -2
if self.buildtime:
- return -2
- if self.runtime:
return -3
- return -4
+ if self.runtime:
+ return -4
+ if self.runtime_post:
+ return -5
+ return -6
def __lt__(self, other):
return self.__int__() < other
def __le__(self, other):
myvalue = self.__int__()
if myvalue > self.MEDIUM:
return "hard"
- if myvalue > self.SOFT:
+ if myvalue > self.MEDIUM_SOFT:
return "medium"
+ if myvalue > self.SOFT:
+ return "medium-soft"
return "soft"
class FakeVartree(portage.vartree):
if os.access(vdb_path, os.W_OK):
vdb_lock = portage.locks.lockdir(vdb_path)
mykeys = ["SLOT", "COUNTER", "PROVIDE", "USE", "IUSE",
- "DEPEND", "RDEPEND", "PDEPEND"]
+ "RESTRICT", "DEPEND", "RDEPEND", "PDEPEND", "repository"]
real_dbapi = real_vartree.dbapi
slot_counters = {}
for cpv in real_dbapi.cpv_all():
"""
return self.BlockerData(*self._cache_data["blockers"][cpv])
+ def keys(self):
+ """This needs to be implemented so that self.__repr__() doesn't raise
+ an AttributeError."""
+ if self._cache_data and "blockers" in self._cache_data:
+ return self._cache_data["blockers"].keys()
+ return []
+
def show_invalid_depstring_notice(parent_node, depstring, error_msg):
from formatter import AbstractFormatter, DumbWriter
self.pkg_node_map = {}
# Maps slot atom to digraph node for all nodes added to the graph.
self._slot_node_map = {}
+ # Maps nodes to the reasons they were selected for reinstallation.
+ self._reinstall_nodes = {}
self.mydbapi = {}
- self._mydbapi_keys = ["SLOT", "DEPEND", "RDEPEND", "PDEPEND"]
+ self._mydbapi_keys = ["SLOT", "DEPEND", "RDEPEND", "PDEPEND",
+ "USE", "IUSE", "PROVIDE", "RESTRICT", "repository"]
self.useFlags = {}
self.trees = {}
+ self.roots = {}
for myroot in trees:
self.trees[myroot] = {}
for tree in ("porttree", "bintree"):
self.pkg_node_map[myroot] = {}
self._slot_node_map[myroot] = {}
vardb = self.trees[myroot]["vartree"].dbapi
+ self.roots[myroot] = RootConfig(self.trees[myroot])
# This fakedbapi instance will model the state that the vdb will
# have after new packages have been installed.
fakedb = portage.fakedbapi(settings=self.pkgsettings[myroot])
self._parent_child_digraph = digraph()
self.orderedkeys=[]
self.outdatedpackages=[]
- self.args_keys = []
+ # contains all sets added to the graph
+ self._sets = {}
+ # contains atoms given as arguments
+ self._sets["args"] = InternalPackageSet()
+ # contains all atoms from all sets added to the graph, including
+ # atoms given as arguments
+ self._set_atoms = InternalPackageSet()
+ # contains all nodes pulled in by self._set_atoms
+ self._set_nodes = set()
self.blocker_digraph = digraph()
self.blocker_parents = {}
self._unresolved_blocker_parents = {}
f.end_paragraph(1)
f.writer.flush()
+ def _reinstall_for_flags(self, forced_flags,
+ orig_use, orig_iuse, cur_use, cur_iuse):
+ """Return a set of flags that trigger reinstallation, or None if there
+ are no such flags."""
+ if "--newuse" in self.myopts:
+ flags = orig_iuse.symmetric_difference(
+ cur_iuse).difference(forced_flags)
+ flags.update(orig_iuse.intersection(orig_use).symmetric_difference(
+ cur_iuse.intersection(cur_use)))
+ if flags:
+ return flags
+ elif "changed-use" == self.myopts.get("--reinstall"):
+ flags = orig_iuse.intersection(orig_use).symmetric_difference(
+ cur_iuse.intersection(cur_use))
+ if flags:
+ return flags
+ return None
+
def create(self, mybigkey, myparent=None, addme=1, myuse=None,
priority=DepPriority(), rev_dep=False, arg=None):
"""
# directive, otherwise we add a "merge" directive.
mydbapi = self.trees[myroot][self.pkg_tree_map[mytype]].dbapi
+ metadata = dict(izip(self._mydbapi_keys,
+ mydbapi.aux_get(mykey, self._mydbapi_keys)))
+ if mytype == "ebuild":
+ pkgsettings.setcpv(mykey, mydb=portdb)
+ metadata["USE"] = pkgsettings["USE"]
+ myuse = pkgsettings["USE"].split()
if not arg and myroot == self.target_root:
- cpv_slot = "%s:%s" % (mykey, mydbapi.aux_get(mykey, ["SLOT"])[0])
- arg = portage.best_match_to_list(cpv_slot, self.args_keys)
-
- if myuse is None:
- self.pkgsettings[myroot].setcpv(mykey, mydb=portdb)
- myuse = self.pkgsettings[myroot]["USE"].split()
+ try:
+ arg = self._set_atoms.findAtomForPackage(mykey, metadata)
+ except portage.exception.InvalidDependString, e:
+ if mytype != "installed":
+ show_invalid_depstring_notice(tuple(mybigkey+["merge"]),
+ metadata["PROVIDE"], str(e))
+ return 0
+ del e
+ reinstall_for_flags = None
merging=1
if mytype == "installed":
merging = 0
""" If we aren't merging, perform the --newuse check.
If the package has new iuse flags or different use flags then if
--newuse is specified, we need to merge the package. """
- if merging==0 and "--newuse" in self.myopts and \
+ if merging == 0 and \
+ myroot == self.target_root and \
+ ("--newuse" in self.myopts or
+ "--reinstall" in self.myopts) and \
vardbapi.cpv_exists(mykey):
pkgsettings.setcpv(mykey, mydb=mydbapi)
forced_flags = set()
forced_flags.update(pkgsettings.useforce)
forced_flags.update(pkgsettings.usemask)
old_use = vardbapi.aux_get(mykey, ["USE"])[0].split()
- iuses = set(filter_iuse_defaults(
- mydbapi.aux_get(mykey, ["IUSE"])[0].split()))
+ iuses = set(filter_iuse_defaults(metadata["IUSE"].split()))
old_iuse = set(filter_iuse_defaults(
vardbapi.aux_get(mykey, ["IUSE"])[0].split()))
- if iuses.symmetric_difference(
- old_iuse).difference(forced_flags):
+ reinstall_for_flags = self._reinstall_for_flags(
+ forced_flags, old_use, old_iuse, myuse, iuses)
+ if reinstall_for_flags:
merging = 1
- elif old_iuse.intersection(old_use) != \
- iuses.intersection(myuse):
- merging=1
if addme and merging == 1:
mybigkey.append("merge")
jbigkey = tuple(mybigkey)
if addme:
- metadata = dict(izip(self._mydbapi_keys,
- mydbapi.aux_get(mykey, self._mydbapi_keys)))
if merging == 0 and vardbapi.cpv_exists(mykey) and \
mytype != "installed":
+ mytype = "installed"
mybigkey[0] = "installed"
mydbapi = vardbapi
jbigkey = tuple(mybigkey)
metadata = dict(izip(self._mydbapi_keys,
mydbapi.aux_get(mykey, self._mydbapi_keys)))
- myuse = mydbapi.aux_get(mykey, ["USE"])[0].split()
+ myuse = metadata["USE"].split()
slot_atom = "%s:%s" % (portage.dep_getkey(mykey), metadata["SLOT"])
existing_node = self._slot_node_map[myroot].get(
slot_atom, None)
self._slot_node_map[myroot][slot_atom] = jbigkey
self.pkg_node_map[myroot][mykey] = jbigkey
self.useFlags[myroot][mykey] = myuse
+ if reinstall_for_flags:
+ self._reinstall_nodes[jbigkey] = reinstall_for_flags
if rev_dep and myparent:
self.digraph.addnode(myparent, jbigkey,
self.digraph.addnode(jbigkey, myparent,
priority=priority)
+ if arg:
+ self._set_nodes.add(jbigkey)
+
# Do this even when addme is False (--onlydeps) so that the
# parent/child relationship is always known in case
# self._show_slot_collision_notice() needs to be called later.
edepend={}
depkeys = ["DEPEND","RDEPEND","PDEPEND"]
- depvalues = mydbapi.aux_get(mykey, depkeys)
- for i in xrange(len(depkeys)):
- edepend[depkeys[i]] = depvalues[i]
+ for k in depkeys:
+ edepend[k] = metadata[k]
if mytype == "ebuild":
if "--buildpkgonly" in self.myopts:
# Post Depend -- Add to the list without a parent, as it depends
# on a package being present AND must be built after that package.
if not self.select_dep(myroot, edepend["PDEPEND"], myparent=mp,
- myuse=myuse, priority=DepPriority(), rev_deps=True,
+ myuse=myuse, priority=DepPriority(runtime_post=True),
parent_arg=arg):
return 0
except ValueError, e:
"given a list of .tbz2s, .ebuilds and deps, create the appropriate depgraph and return a favorite list"
myfavorites=[]
myroot = self.target_root
+ vardb = self.trees[myroot]["vartree"].dbapi
portdb = self.trees[myroot]["porttree"].dbapi
bindb = self.trees[myroot]["bintree"].dbapi
pkgsettings = self.pkgsettings[myroot]
else:
print "\n\n!!! Binary package '"+str(x)+"' does not exist."
print "!!! Please ensure the tbz2 exists as specified.\n"
- sys.exit(1)
+ return 0, myfavorites
mytbz2=portage.xpak.tbz2(x)
mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.splitext(os.path.basename(x))[0]
if os.path.realpath(x) != \
os.path.realpath(self.trees[myroot]["bintree"].getname(mykey)):
print colorize("BAD", "\n*** You need to adjust PKGDIR to emerge this package.\n")
- sys.exit(1)
+ return 0, myfavorites
if not self.create(["binary", myroot, mykey],
- None, "--onlydeps" not in self.myopts):
+ None, "--onlydeps" not in self.myopts,
+ myuse=mytbz2.getelements("USE"), arg=x):
return (0,myfavorites)
- elif not "--oneshot" in self.myopts:
- myfavorites.append(mykey)
+ arg_atoms.append((x, "="+mykey))
elif ext==".ebuild":
- x = os.path.realpath(x)
- mykey=os.path.basename(os.path.normpath(x+"/../.."))+"/"+os.path.splitext(os.path.basename(x))[0]
+ ebuild_path = portage.util.normalize_path(os.path.abspath(x))
+ pkgdir = os.path.dirname(ebuild_path)
+ tree_root = os.path.dirname(os.path.dirname(pkgdir))
+ cp = pkgdir[len(tree_root)+1:]
+ e = portage.exception.PackageNotFound(
+ ("%s is not in a valid portage tree " + \
+ "hierarchy or does not exist") % x)
+ if not portage.isvalidatom(cp):
+ raise e
+ cat = portage.catsplit(cp)[0]
+ mykey = cat + "/" + os.path.basename(ebuild_path[:-7])
+ if not portage.isvalidatom("="+mykey):
+ raise e
ebuild_path = portdb.findname(mykey)
if ebuild_path:
- if os.path.realpath(ebuild_path) != x:
+ if ebuild_path != os.path.join(os.path.realpath(tree_root),
+ cp, os.path.basename(ebuild_path)):
print colorize("BAD", "\n*** You need to adjust PORTDIR or PORTDIR_OVERLAY to emerge this package.\n")
- sys.exit(1)
+ return 0, myfavorites
if mykey not in portdb.xmatch(
"match-visible", portage.dep_getkey(mykey)):
print colorize("BAD", "\n*** You are emerging a masked package. It is MUCH better to use")
raise portage.exception.PackageNotFound(
"%s is not in a valid portage tree hierarchy or does not exist" % x)
if not self.create(["ebuild", myroot, mykey],
- None, "--onlydeps" not in self.myopts):
+ None, "--onlydeps" not in self.myopts, arg=x):
return (0,myfavorites)
- elif not "--oneshot" in self.myopts:
- myfavorites.append(mykey)
+ arg_atoms.append((x, "="+mykey))
else:
if not is_valid_package_atom(x):
portage.writemsg("\n\n!!! '%s' is not a valid package atom.\n" % x,
if "--usepkg" in self.myopts:
mykey = portage.dep_expand(x, mydb=bindb,
settings=pkgsettings)
- if (mykey and not mykey.startswith("null/")) or \
- "--usepkgonly" in self.myopts:
+ if "--usepkgonly" in self.myopts or \
+ (mykey and not portage.dep_getkey(mykey).startswith("null/")):
arg_atoms.append((x, mykey))
continue
- mykey = portage.dep_expand(x,
- mydb=portdb, settings=pkgsettings)
+ try:
+ mykey = portage.dep_expand(x,
+ mydb=portdb, settings=pkgsettings)
+ except ValueError, e:
+ mykey = portage.dep_expand(x,
+ mydb=vardb, settings=pkgsettings)
+ cp = portage.dep_getkey(mykey)
+ if cp.startswith("null/") or \
+ cp not in e[0]:
+ raise
+ del e
arg_atoms.append((x, mykey))
except ValueError, errpkgs:
print "\n\n!!! The short ebuild name \"" + x + "\" is ambiguous. Please specify"
greedy_atoms.append((myarg, myslot_atom))
arg_atoms = greedy_atoms
+ oneshot = "--oneshot" in self.myopts or "--onlydeps" in self.myopts
""" These are used inside self.create() in order to ensure packages
that happen to match arguments are not incorrectly marked as nomerge."""
- self.args_keys = [x[1] for x in arg_atoms]
+ args_set = self._sets["args"]
+ for myarg, myatom in arg_atoms:
+ if myatom in args_set:
+ continue
+ args_set.add(myatom)
+ self._set_atoms.add(myatom)
+ if not oneshot:
+ myfavorites.append(myatom)
for myarg, myatom in arg_atoms:
try:
self.mysd = self.select_dep(myroot, myatom, arg=myarg)
if not self.mysd:
return (0,myfavorites)
- elif not "--oneshot" in self.myopts:
- mykey = portage.dep_getkey(myatom)
- if mykey not in myfavorites:
- myfavorites.append(mykey)
missing=0
if "--usepkgonly" in self.myopts:
return 0
mymerge = mycheck[1]
- if not mymerge and arg and \
- portage.best_match_to_list(depstring, self.args_keys):
+ if not mymerge and arg:
# A provided package has been specified on the command line. The
# package will not be merged and a warning will be displayed.
- self._pprovided_args.append(arg)
+ if depstring in self._set_atoms:
+ self._pprovided_args.append((arg, depstring))
if myparent:
# The parent is added after it's own dep_check call so that it
if p_status == "merge":
# Update old-style virtuals if this package provides any.
# These are needed for dep_virtual calls inside dep_check.
- p_db = self.trees[p_root][self.pkg_tree_map[p_type]].dbapi
+ p_db = self.mydbapi[p_root] # contains cached metadata
+ if myparent in self._slot_collision_nodes:
+ # The metadata isn't cached due to the slot collision.
+ p_db = self.trees[p_root][self.pkg_tree_map[p_type]].dbapi
try:
self.pkgsettings[p_root].setinst(p_key, p_db)
+ # For consistency, also update the global virtuals.
+ settings = self.roots[p_root].settings
+ settings.unlock()
+ settings.setinst(p_key, p_db)
+ settings.lock()
except portage.exception.InvalidDependString, e:
provide = p_db.aux_get(p_key, ["PROVIDE"])[0]
show_invalid_depstring_notice(myparent, provide, str(e))
if myeb_pkg_matches:
myeb_pkg = portage.best(myeb_pkg_matches)
- if myeb_pkg and "--newuse" in self.myopts:
+ if myeb_pkg and \
+ ("--newuse" in self.myopts or \
+ "--reinstall" in self.myopts):
iuses = set(filter_iuse_defaults(
bindb.aux_get(myeb_pkg, ["IUSE"])[0].split()))
old_use = bindb.aux_get(myeb_pkg, ["USE"])[0].split()
if "--usepkgonly" not in self.myopts and myeb:
cur_iuse = set(filter_iuse_defaults(
portdb.aux_get(myeb, ["IUSE"])[0].split()))
- if iuses.symmetric_difference(
- cur_iuse).difference(forced_flags):
- myeb_pkg = None
- elif iuses.intersection(old_use) != \
- cur_iuse.intersection(now_use):
+ if self._reinstall_for_flags(
+ forced_flags, old_use, iuses, now_use, cur_iuse):
myeb_pkg = None
if myeb_pkg:
binpkguseflags = \
self._altlist_cache[reversed] = retlist[:]
return retlist
mygraph=self.digraph.copy()
+ for node in mygraph.order[:]:
+ if node[-1] == "nomerge":
+ mygraph.remove(node)
self._merge_order_bias(mygraph)
myblockers = self.blocker_digraph.copy()
retlist=[]
if "portage" == portage.catsplit(portage.dep_getkey(cpv))[-1]:
asap_nodes.append(node)
break
- ignore_priority_range = [None]
- ignore_priority_range.extend(
- xrange(DepPriority.MIN, DepPriority.MEDIUM + 1))
+ ignore_priority_soft_range = [None]
+ ignore_priority_soft_range.extend(
+ xrange(DepPriority.MIN, DepPriority.SOFT + 1))
tree_mode = "--tree" in self.myopts
+ # Tracks whether or not the current iteration should prefer asap_nodes
+ # if available. This is set to False when the previous iteration
+ # failed to select any nodes. It is reset whenever nodes are
+ # successfully selected.
+ prefer_asap = True
while not mygraph.empty():
- ignore_priority = None
- nodes = None
- if asap_nodes:
+ selected_nodes = None
+ if prefer_asap and asap_nodes:
"""ASAP nodes are merged before their soft deps."""
+ asap_nodes = [node for node in asap_nodes \
+ if mygraph.contains(node)]
for node in asap_nodes:
- if not mygraph.contains(node):
- asap_nodes.remove(node)
- continue
if not mygraph.child_nodes(node,
ignore_priority=DepPriority.SOFT):
- nodes = [node]
+ selected_nodes = [node]
asap_nodes.remove(node)
break
- if not nodes:
- for ignore_priority in ignore_priority_range:
+ if not selected_nodes and \
+ not (prefer_asap and asap_nodes):
+ for ignore_priority in ignore_priority_soft_range:
nodes = get_nodes(ignore_priority=ignore_priority)
if nodes:
break
- selected_nodes = None
- if nodes:
- if ignore_priority <= DepPriority.SOFT:
+ if nodes:
if ignore_priority is None and not tree_mode:
# Greedily pop all of these nodes since no relationship
# has been ignored. This optimization destroys --tree
if not selected_nodes:
# settle for a root node
selected_nodes = [nodes[0]]
- else:
+ if not selected_nodes:
+ nodes = get_nodes(ignore_priority=DepPriority.MEDIUM)
+ if nodes:
"""Recursively gather a group of nodes that RDEPEND on
eachother. This ensures that they are merged as a group
and get their RDEPENDs satisfied as soon as possible."""
- def gather_deps(mergeable_nodes, selected_nodes, node):
+ def gather_deps(ignore_priority,
+ mergeable_nodes, selected_nodes, node):
if node in selected_nodes:
return True
if node not in mergeable_nodes:
return False
selected_nodes.add(node)
for child in mygraph.child_nodes(node,
- ignore_priority=DepPriority.SOFT):
- if not gather_deps(
+ ignore_priority=ignore_priority):
+ if not gather_deps(ignore_priority,
mergeable_nodes, selected_nodes, child):
return False
return True
mergeable_nodes = set(nodes)
- for node in nodes:
- selected_nodes = set()
- if gather_deps(
- mergeable_nodes, selected_nodes, node):
+ if prefer_asap and asap_nodes:
+ nodes = asap_nodes
+ for ignore_priority in xrange(DepPriority.SOFT,
+ DepPriority.MEDIUM_SOFT + 1):
+ for node in nodes:
+ selected_nodes = set()
+ if gather_deps(ignore_priority,
+ mergeable_nodes, selected_nodes, node):
+ break
+ else:
+ selected_nodes = None
+ if selected_nodes:
break
- else:
- selected_nodes = None
+
+ if prefer_asap and asap_nodes and not selected_nodes:
+ # We failed to find any asap nodes to merge, so ignore
+ # them for the next iteration.
+ prefer_asap = False
+ continue
+
+ if selected_nodes and ignore_priority > DepPriority.SOFT:
+ # Try to merge ignored medium deps as soon as possible.
+ for node in selected_nodes:
+ children = set(mygraph.child_nodes(node))
+ soft = children.difference(
+ mygraph.child_nodes(node,
+ ignore_priority=DepPriority.SOFT))
+ medium_soft = children.difference(
+ mygraph.child_nodes(node,
+ ignore_priority=DepPriority.MEDIUM_SOFT))
+ medium_soft.difference_update(soft)
+ for child in medium_soft:
+ if child in selected_nodes:
+ continue
+ if child in asap_nodes:
+ continue
+ # TODO: Try harder to make these nodes get
+ # merged absolutely as soon as possible.
+ asap_nodes.append(child)
if not selected_nodes:
if not myblockers.is_empty():
print "!!! disabling USE flags that trigger optional dependencies."
sys.exit(1)
+ # At this point, we've succeeded in selecting one or more nodes, so
+ # it's now safe to reset the prefer_asap to it's default state.
+ prefer_asap = True
+
for node in selected_nodes:
retlist.append(list(node))
mygraph.remove(node)
return [x for x in mylist \
if x in matches or not portdb.cpv_exists(x)]
world_problems = False
- if mode=="system":
- mylist = getlist(self.settings, "system")
- else:
- #world mode
- worldlist = getlist(self.settings, "world")
- mylist = getlist(self.settings, "system")
- worlddict=genericdict(worldlist)
- for x in worlddict:
+ root_config = self.roots[self.target_root]
+ world_set = root_config.sets["world"]
+ system_set = root_config.sets["system"]
+ mylist = list(system_set)
+ self._sets["system"] = system_set
+ if mode == "world":
+ self._sets["world"] = world_set
+ for x in world_set:
if not portage.isvalidatom(x):
world_problems = True
continue
mykey = portage.dep_getkey(atom)
if True:
newlist.append(atom)
- """Make sure all installed slots are updated when possible.
- Do this with --emptytree also, to ensure that all slots are
- remerged."""
+ if mode == "system" or atom not in world_set:
+ # only world is greedy for slots, not system
+ continue
+ # Make sure all installed slots are updated when possible.
+ # Do this with --emptytree also, to ensure that all slots are
+ # remerged.
myslots = set()
for cpv in vardb.match(mykey):
myslots.add(vardb.aux_get(cpv, ["SLOT"])[0])
if available:
newlist.append(myslot_atom)
mylist = newlist
-
+
+ for myatom in mylist:
+ self._set_atoms.add(myatom)
+
missing_atoms = []
for mydep in mylist:
try:
return 1
- def display(self,mylist,verbosity=None):
+ def display(self, mylist, favorites=[], verbosity=None):
if verbosity is None:
verbosity = ("--quiet" in self.myopts and 1 or \
"--verbose" in self.myopts and 3 or 2)
+ favorites_set = InternalPackageSet(favorites)
changelogs=[]
p=[]
blockers = []
ret = '%s="%s" ' % (name, ret)
return ret
- if verbosity == 3:
- # FIXME: account for the possibility of different overlays in
- # /etc/make.conf vs. ${PORTAGE_CONFIGROOT}/etc/make.conf
- overlays = self.settings["PORTDIR_OVERLAY"].split()
- overlays_real = [os.path.realpath(t) \
- for t in self.settings["PORTDIR_OVERLAY"].split()]
+ repo_display = RepoDisplay(self.roots)
tree_nodes = []
display_list = []
traversed_nodes = set() # prevent endless circles
traversed_nodes.add(graph_key)
def add_parents(current_node, ordered):
- parent_nodes = mygraph.parent_nodes(current_node)
+ 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 self._set_nodes:
+ parent_nodes = mygraph.parent_nodes(current_node)
if parent_nodes:
child_nodes = set(mygraph.child_nodes(current_node))
selected_parent = None
from portage import flatten
from portage.dep import use_reduce, paren_reduce
- display_overlays=False
# files to fetch list - avoids counting a same file twice
# in size display (verbose mode)
myfetchlist=[]
+
for mylist_index in xrange(len(mylist)):
x, depth, ordered = mylist[mylist_index]
+ pkg_node = tuple(x)
pkg_type = x[0]
myroot = x[1]
pkg_key = x[2]
addl += bad(" (is blocking %s)") % block_parents
blockers.append(addl)
else:
- mydbapi = self.trees[myroot][self.pkg_tree_map[pkg_type]].dbapi
pkg_status = x[3]
- binary_package = True
- if "ebuild" == pkg_type:
- if "merge" == x[3] or \
- not vartree.dbapi.cpv_exists(pkg_key):
- """An ebuild "merge" node or a --onlydeps "nomerge"
- node."""
- binary_package = False
- pkgsettings.setcpv(pkg_key, mydb=portdb)
- if pkg_key not in self.useFlags[myroot]:
- self.useFlags[myroot][pkg_key] = \
- pkgsettings["USE"].split()
- else:
- # An ebuild "nomerge" node, so USE come from the vardb.
- mydbapi = vartree.dbapi
+ pkg_merge = ordered and pkg_status != "nomerge"
+ if pkg_node in self._slot_collision_nodes or \
+ (pkg_status == "nomerge" and pkg_type != "installed"):
+ # The metadata isn't cached due to a slot collision or
+ # --onlydeps.
+ mydbapi = self.trees[myroot][self.pkg_tree_map[pkg_type]].dbapi
+ else:
+ mydbapi = self.mydbapi[myroot] # contains cached metadata
+ metadata = dict(izip(self._mydbapi_keys,
+ mydbapi.aux_get(pkg_key, self._mydbapi_keys)))
+ ebuild_path = None
+ repo_name = metadata["repository"]
+ if pkg_type == "ebuild":
+ ebuild_path = portdb.findname(pkg_key)
+ if not ebuild_path: # shouldn't happen
+ raise portage.exception.PackageNotFound(pkg_key)
+ repo_path_real = os.path.dirname(os.path.dirname(
+ os.path.dirname(ebuild_path)))
+ else:
+ repo_path_real = portdb.getRepositoryPath(repo_name)
if pkg_key not in self.useFlags[myroot]:
"""If this is a --resume then the USE flags need to be
fetched from the appropriate locations here."""
restrict = mydbapi.aux_get(pkg_key, ["RESTRICT"])[0]
show_invalid_depstring_notice(x, restrict, str(e))
del e
- sys.exit(1)
+ return 1
restrict = []
if "ebuild" == pkg_type and x[3] != "nomerge" and \
"fetch" in restrict:
mydbapi.aux_get(pkg_key, ["IUSE"])[0].split()))
forced_flags = set()
- if not binary_package:
- forced_flags.update(pkgsettings.useforce)
- forced_flags.update(pkgsettings.usemask)
+ pkgsettings.setcpv(pkg_key) # for package.use.{mask,force}
+ forced_flags.update(pkgsettings.useforce)
+ forced_flags.update(pkgsettings.usemask)
cur_iuse = portage.unique_array(cur_iuse)
cur_iuse.sort()
use_expand_hidden = \
pkgsettings["USE_EXPAND_HIDDEN"].lower().split()
- def map_to_use_expand(myvals, forcedFlags=False):
+ def map_to_use_expand(myvals, forcedFlags=False,
+ removeHidden=True):
ret = {}
forced = {}
for exp in use_expand:
ret["USE"] = myvals
forced["USE"] = [val for val in myvals \
if val in forced_flags]
- for exp in use_expand_hidden:
- if exp in ret:
- del ret[exp]
+ 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 = None
+ reinstall_for_flags = self._reinstall_nodes.get(pkg_node)
+ if reinstall_for_flags:
+ reinst_flags_map = map_to_use_expand(
+ list(reinstall_for_flags), removeHidden=False)
+ if reinst_flags_map["USE"]:
+ reinst_flags_map = None
+ else:
+ for k in reinst_flags_map.keys():
+ if not reinst_flags_map[k]:
+ del reinst_flags_map[k]
+ if reinst_flags_map and \
+ not set(reinst_flags_map).difference(
+ use_expand_hidden):
+ use_expand_hidden = set(use_expand_hidden).difference(
+ reinst_flags_map)
+
cur_iuse_map, iuse_forced = \
map_to_use_expand(cur_iuse, forcedFlags=True)
cur_use_map = map_to_use_expand(cur_use)
if verbosity == 3:
# size verbose
mysize=0
- if x[0] == "ebuild" and ordered and x[-1] != "nomerge":
+ if pkg_type == "ebuild" and pkg_merge:
try:
myfilesdict = portdb.getfetchsizes(pkg_key,
useflags=self.useFlags[myroot][pkg_key],
src_uri = portdb.aux_get(pkg_key, ["SRC_URI"])[0]
show_invalid_depstring_notice(x, src_uri, str(e))
del e
- sys.exit(1)
+ return 1
if myfilesdict is None:
myfilesdict="[empty/missing/bad digest]"
else:
verboseadd+=format_size(mysize)+" "
# overlay verbose
- # XXX: Invalid binaries have caused tracebacks here. 'if file_name'
- # x = ['binary', '/', 'sys-apps/pcmcia-cs-3.2.7.2.6', 'merge']
- file_name = portdb.findname(pkg_key)
- if file_name: # It might not exist in the tree
- dir_name=os.path.abspath(os.path.dirname(file_name)+"/../..")
- if (overlays_real.count(dir_name)>0):
- verboseadd+=teal("["+str(overlays_real.index(
- os.path.normpath(dir_name))+1)+"]")+" "
- display_overlays=True
+ # assign index for a previous version in the same slot
+ has_previous = False
+ repo_name_prev = None
+ slot_atom = "%s:%s" % (portage.dep_getkey(pkg_key),
+ metadata["SLOT"])
+ slot_matches = vardb.match(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
+ repoadd = None
+ if pkg_status == "nomerge" or not has_previous:
+ repoadd = repo_display.repoStr(repo_path_real)
else:
- verboseadd += "[No ebuild?]"
+ repo_path_prev = None
+ if repo_name_prev:
+ repo_path_prev = portdb.getRepositoryPath(
+ repo_name_prev)
+ repoadd = "%s=>%s" % (
+ repo_display.repoStr(repo_path_prev),
+ repo_display.repoStr(repo_path_real))
+ if repoadd:
+ verboseadd += teal("[%s]" % repoadd)
xs = list(portage.pkgsplit(x[2]))
if xs[2]=="r0":
myoldbest=myoldbest[:-3]
myoldbest=blue("["+myoldbest+"]")
+ pkg_cp = xs[0]
+ root_config = self.roots[myroot]
+ system_set = root_config.sets["system"]
+ world_set = root_config.sets["world"]
+
+ pkg_system = False
+ pkg_world = False
+ try:
+ pkg_system = system_set.findAtomForPackage(pkg_key, metadata)
+ pkg_world = world_set.findAtomForPackage(pkg_key, metadata)
+ if not pkg_world and myroot == self.target_root and \
+ favorites_set.findAtomForPackage(pkg_key, metadata):
+ # Maybe it will be added to world now.
+ if create_world_atom(pkg_key, metadata,
+ favorites_set, root_config):
+ pkg_world = True
+ except portage.exception.InvalidDependString:
+ # This is reported elsewhere if relevant.
+ pass
+
+ def pkgprint(pkg):
+ if pkg_merge:
+ if pkg_system:
+ return colorize("PKG_MERGE_SYSTEM", pkg)
+ elif pkg_world:
+ return colorize("PKG_MERGE_WORLD", pkg)
+ else:
+ return colorize("PKG_MERGE", pkg)
+ else:
+ if pkg_system:
+ return colorize("PKG_NOMERGE_SYSTEM", pkg)
+ elif pkg_world:
+ return colorize("PKG_NOMERGE_WORLD", pkg)
+ else:
+ return colorize("PKG_NOMERGE", pkg)
+
if x[1]!="/":
if myoldbest:
myoldbest +=" "
if "--columns" in self.myopts:
if "--quiet" in self.myopts:
- myprint=addl+" "+indent+darkgreen(xs[0])
+ myprint=addl+" "+indent+pkgprint(pkg_cp)
myprint=myprint+darkblue(" "+xs[1]+xs[2])+" "
myprint=myprint+myoldbest
myprint=myprint+darkgreen("to "+x[1])
else:
- myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0])
+ myprint="["+pkgprint(pkg_type)+" "+addl+"] "+indent+pkgprint(pkg_cp)
if (newlp-nc_len(myprint)) > 0:
myprint=myprint+(" "*(newlp-nc_len(myprint)))
myprint=myprint+"["+darkblue(xs[1]+xs[2])+"] "
myprint=myprint+myoldbest
myprint=myprint+darkgreen("to "+x[1])+" "+verboseadd
else:
- if x[-1] == "nomerge" or not ordered:
- myprint = darkblue("[nomerge ] ")
+ if not pkg_merge:
+ myprint = "[%s ] " % pkgprint("nomerge")
else:
myprint = "[" + pkg_type + " " + addl + "] "
- myprint += indent + darkgreen(pkg_key) + " " + \
+ myprint += indent + pkgprint(pkg_key) + " " + \
myoldbest + darkgreen("to " + myroot) + " " + \
verboseadd
else:
if "--columns" in self.myopts:
if "--quiet" in self.myopts:
- myprint=addl+" "+indent+darkgreen(xs[0])
+ myprint=addl+" "+indent+pkgprint(pkg_cp)
myprint=myprint+" "+green(xs[1]+xs[2])+" "
myprint=myprint+myoldbest
else:
- myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0])
+ myprint="["+pkgprint(pkg_type)+" "+addl+"] "+indent+pkgprint(pkg_cp)
if (newlp-nc_len(myprint)) > 0:
myprint=myprint+(" "*(newlp-nc_len(myprint)))
myprint=myprint+green(" ["+xs[1]+xs[2]+"] ")
myprint=myprint+(" "*(oldlp-nc_len(myprint)))
myprint=myprint+myoldbest+" "+verboseadd
else:
- if x[-1] == "nomerge" or not ordered:
- myprint=darkblue("[nomerge ] "+indent+x[2]+" "+myoldbest+" ")+verboseadd
+ if not pkg_merge:
+ myprint="["+pkgprint("nomerge")+" ] "+indent+pkgprint(pkg_key)+" "+myoldbest+" "+verboseadd
else:
- myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(x[2])+" "+myoldbest+" "+verboseadd
+ myprint="["+pkgprint(pkg_type)+" "+addl+"] "+indent+pkgprint(pkg_key)+" "+myoldbest+" "+verboseadd
p.append(myprint)
mysplit = portage.pkgsplit(x[2])
if verbosity == 3:
print
print counters
- if overlays and display_overlays:
- print "Portage overlays:"
- y=0
- for x in overlays:
- y=y+1
- print " "+teal("["+str(y)+"]"),x
+ if p:
+ sys.stdout.write(str(repo_display))
if "--changelog" in self.myopts:
print
sys.stdout.write(text)
if self._pprovided_args:
+ arg_refs = {}
+ for arg_atom in self._pprovided_args:
+ arg, atom = arg_atom
+ arg_refs[arg_atom] = []
+ cp = portage.dep_getkey(atom)
+ for set_name, atom_set in self._sets.iteritems():
+ if atom in atom_set:
+ arg_refs[arg_atom].append(set_name)
msg = []
msg.append(bad("\nWARNING: "))
if len(self._pprovided_args) > 1:
else:
msg.append("A requested package will not be " + \
"merged because it is listed in\n")
- msg.append(" package.provided:\n\n")
- for arg in self._pprovided_args:
- msg.append(" " + arg + "\n")
+ msg.append("package.provided:\n\n")
+ problems_sets = set()
+ for (arg, atom), refs in arg_refs.iteritems():
+ ref_string = ""
+ if refs:
+ problems_sets.update(refs)
+ refs.sort()
+ ref_string = ", ".join(["'%s'" % name for name in refs])
+ ref_string = " pulled in by " + ref_string
+ msg.append(" %s%s\n" % (colorize("INFORM", arg), ref_string))
msg.append("\n")
+ if "world" in problems_sets:
+ msg.append("This problem can be solved in one of the following ways:\n\n")
+ msg.append(" A) Use emaint to clean offending packages from world (if not installed).\n")
+ msg.append(" B) Uninstall offending packages (cleans them from world).\n")
+ msg.append(" C) Remove offending entries from package.provided.\n\n")
+ msg.append("The best course of action depends on the reason that an offending\n")
+ msg.append("package.provided entry exists.\n\n")
sys.stderr.write("".join(msg))
+ return os.EX_OK
def calc_changelog(self,ebuildpath,current,next):
if ebuildpath == None or not os.path.exists(ebuildpath):
if release.endswith('-r0'):
release = release[:-3]
- def outdated(self):
- return self.outdatedpackages
+ def saveNomergeFavorites(self):
+ """Find atoms in favorites that are not in the mergelist and add them
+ to the world file if necessary."""
+ for x in ("--fetchonly", "--fetch-all-uri",
+ "--oneshot", "--onlydeps", "--pretend"):
+ if x in self.myopts:
+ return
+ root_config = self.roots[self.target_root]
+ world_set = root_config.sets["world"]
+ world_set.lock()
+ world_set.load() # maybe it's changed on disk
+ args_set = self._sets["args"]
+ portdb = self.trees[self.target_root]["porttree"].dbapi
+ added_favorites = set()
+ for x in self._set_nodes:
+ pkg_type, root, pkg_key, pkg_status = x
+ if pkg_status != "nomerge":
+ continue
+ metadata = dict(izip(self._mydbapi_keys,
+ self.mydbapi[root].aux_get(pkg_key, self._mydbapi_keys)))
+ try:
+ myfavkey = create_world_atom(pkg_key, metadata,
+ args_set, root_config)
+ if myfavkey:
+ if myfavkey in added_favorites:
+ continue
+ added_favorites.add(myfavkey)
+ world_set.add(myfavkey)
+ print ">>> Recording",myfavkey,"in \"world\" favorites file..."
+ except portage.exception.InvalidDependString, e:
+ writemsg("\n\n!!! '%s' has invalid PROVIDE: %s\n" % \
+ (pkg_key, str(e)), noiselevel=-1)
+ writemsg("!!! see '%s'\n\n" % os.path.join(
+ root, portage.VDB_PATH, pkg_key, "PROVIDE"), noiselevel=-1)
+ del e
+ world_set.unlock()
+
+ def loadResumeCommand(self, resume_data):
+ """
+ Add a resume command to the graph and validate it in the process. This
+ will raise a PackageNotFound exception if a package is not available.
+ """
+ self._sets["args"].update(resume_data.get("favorites", []))
+ mergelist = resume_data.get("mergelist", [])
+ fakedb = self.mydbapi
+ trees = self.trees
+ for x in mergelist:
+ if len(x) != 4:
+ continue
+ pkg_type, myroot, pkg_key, action = x
+ if pkg_type not in self.pkg_tree_map:
+ continue
+ if action != "merge":
+ continue
+ mydb = trees[myroot][self.pkg_tree_map[pkg_type]].dbapi
+ try:
+ metadata = dict(izip(self._mydbapi_keys,
+ mydb.aux_get(pkg_key, self._mydbapi_keys)))
+ except KeyError:
+ # It does no exist or it is corrupt.
+ raise portage.exception.PackageNotFound(pkg_key)
+ fakedb[myroot].cpv_inject(pkg_key, metadata=metadata)
+ if pkg_type == "ebuild":
+ pkgsettings = self.pkgsettings[myroot]
+ pkgsettings.setcpv(pkg_key, mydb=fakedb[myroot])
+ fakedb[myroot].aux_update(pkg_key, {"USE":pkgsettings["USE"]})
+ self.spinner.update()
+
+class RepoDisplay(object):
+ def __init__(self, roots):
+ self._shown_repos = {}
+ self._unknown_repo = False
+ repo_paths = set()
+ for root_config in roots.itervalues():
+ portdir = root_config.settings.get("PORTDIR")
+ if portdir:
+ repo_paths.add(portdir)
+ overlays = root_config.settings.get("PORTDIR_OVERLAY")
+ if overlays:
+ repo_paths.update(overlays.split())
+ 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.itervalues():
+ 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.iteritems():
+ 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)
class PackageCounters(object):
if self.target_root != "/":
self.pkgsettings["/"] = \
portage.config(clone=trees["/"]["vartree"].settings)
+ self.curval = 0
def merge(self, mylist, favorites, mtimedb):
+ from portage.elog import elog_process
+ from portage.elog.filtering import filter_mergephases
failed_fetches = []
fetchonly = "--fetchonly" in self.myopts or \
"--fetch-all-uri" in self.myopts
+ pretend = "--pretend" in self.myopts
mymergelist=[]
ldpath_mtimes = mtimedb["ldpath"]
xterm_titles = "notitles" not in self.settings.features
del mtimedb["resume"]["mergelist"][0]
del mylist[0]
mtimedb.commit()
- validate_merge_list(self.trees, mylist)
mymergelist = mylist
# Verify all the manifests now so that the user is notified of failure
del x, mytype, myroot, mycpv, mystatus, quiet_config
del shown_verifying_msg, quiet_settings
- #buildsyspkg: I need mysysdict also on resume (moved from the else block)
- mysysdict = genericdict(getlist(self.settings, "system"))
+ root_config = RootConfig(self.trees[self.target_root])
+ system_set = root_config.sets["system"]
+ args_set = InternalPackageSet(favorites)
+ world_set = root_config.sets["world"]
if "--resume" not in self.myopts:
- myfavs = portage.grabfile(
- os.path.join(self.target_root, portage.WORLD_FILE))
- myfavdict=genericdict(myfavs)
- for x in range(len(mylist)):
- if mylist[x][3]!="nomerge":
- # Add to the mergelist
- mymergelist.append(mylist[x])
- else:
- myfavkey=portage.cpv_getkey(mylist[x][2])
- if "--onlydeps" in self.myopts:
- continue
- # Add to the world file. Since we won't be able to later.
- if "--fetchonly" not in self.myopts and \
- myfavkey in favorites:
- #don't record if already in system profile or already recorded
- if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)):
- #we don't have a favorites entry for this package yet; add one
- myfavdict[myfavkey]=myfavkey
- print ">>> Recording",myfavkey,"in \"world\" favorites file..."
- if not ("--fetchonly" in self.myopts or \
- "--fetch-all-uri" in self.myopts or \
- "--pretend" in self.myopts):
- portage.write_atomic(
- os.path.join(self.target_root, portage.WORLD_FILE),
- "\n".join(myfavdict.values()))
-
+ mymergelist = mylist
mtimedb["resume"]["mergelist"]=mymergelist[:]
mtimedb.commit()
del fetch_log, logfile, fd_pipes, fetch_env, fetch_args, \
resume_opts
+ metadata_keys = [k for k in portage.auxdbkeys \
+ if not k.startswith("UNUSED_")] + ["USE"]
+
mergecount=0
for x in mymergelist:
mergecount+=1
+ pkg_type = x[0]
myroot=x[1]
pkg_key = x[2]
pkgindex=2
bindb = self.trees[myroot]["bintree"].dbapi
vartree = self.trees[myroot]["vartree"]
pkgsettings = self.pkgsettings[myroot]
+ metadata = {}
+ if pkg_type == "blocks":
+ pass
+ elif pkg_type == "ebuild":
+ mydbapi = portdb
+ metadata.update(izip(metadata_keys,
+ mydbapi.aux_get(pkg_key, metadata_keys)))
+ pkgsettings.setcpv(pkg_key, mydb=mydbapi)
+ metadata["USE"] = pkgsettings["USE"]
+ else:
+ if pkg_type == "binary":
+ mydbapi = bindb
+ else:
+ raise AssertionError("Package type: '%s'" % pkg_type)
+ metadata.update(izip(metadata_keys,
+ mydbapi.aux_get(pkg_key, metadata_keys)))
if x[0]=="blocks":
pkgindex=3
y = portdb.findname(pkg_key)
#buildsyspkg: Check if we need to _force_ binary package creation
issyspkg = ("buildsyspkg" in myfeat) \
and x[0] != "blocks" \
- and mysysdict.has_key(portage.cpv_getkey(x[2])) \
+ and system_set.findAtomForPackage(pkg_key, metadata) \
and "--buildpkg" not in self.myopts
if x[0] in ["ebuild","blocks"]:
if x[0] == "blocks" and "--fetchonly" not in self.myopts:
print "!!! Fetch for",y,"failed, continuing..."
print
failed_fetches.append(pkg_key)
+ self.curval += 1
continue
portage.doebuild_environment(y, "setup", myroot,
pkgsettings, self.edebug, mydbapi=portdb,
tree="porttree")
del pkgsettings["PORTAGE_BINPKG_TMPFILE"]
+ if retval != os.EX_OK or \
+ "--buildpkgonly" in self.myopts:
+ elog_process(pkg_key, pkgsettings, phasefilter=filter_mergephases)
if retval != os.EX_OK:
return retval
bintree = self.trees[myroot]["bintree"]
if "--fetchonly" in self.myopts or \
"--fetch-all-uri" in self.myopts:
+ self.curval += 1
continue
short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge Binary"
#need to check for errors
if "--buildpkgonly" not in self.myopts:
self.trees[x[1]]["vartree"].inject(x[2])
- myfavkey=portage.cpv_getkey(x[2])
- if "--fetchonly" not in self.myopts and \
- "--fetch-all-uri" not in self.myopts and \
- myfavkey in favorites:
- myfavs = portage.grabfile(os.path.join(myroot, portage.WORLD_FILE))
- myfavdict=genericdict(myfavs)
- #don't record if already in system profile or already recorded
- if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)):
- #we don't have a favorites entry for this package yet; add one
- myfavdict[myfavkey]=myfavkey
+ myfavkey = portage.cpv_getkey(x[2])
+ if not fetchonly and not pretend and \
+ args_set.findAtomForPackage(pkg_key, metadata):
+ world_set.lock()
+ world_set.load() # maybe it's changed on disk
+ myfavkey = create_world_atom(pkg_key, metadata,
+ args_set, root_config)
+ if myfavkey:
print ">>> Recording",myfavkey,"in \"world\" favorites file..."
emergelog(xterm_titles, " === ("+\
str(mergecount)+" of "+\
str(len(mymergelist))+\
") Updating world file ("+x[pkgindex]+")")
- portage.write_atomic(
- os.path.join(myroot, portage.WORLD_FILE),
- "\n".join(myfavdict.values()))
+ world_set.add(myfavkey)
+ world_set.unlock()
if "--pretend" not in self.myopts and \
"--fetchonly" not in self.myopts and \
# in the event that portage is not allowed to exit normally
# due to power failure, SIGKILL, etc...
mtimedb.commit()
+ self.curval += 1
if "--pretend" not in self.myopts:
emergelog(xterm_titles, " *** Finished. Cleaning up...")
if "--pretend" not in myopts and "--ask" not in myopts:
countdown(int(settings["EMERGE_WARNING_DELAY"]),
colorize("UNMERGE_WARN", "Press Ctrl-C to Stop"))
- print "\n "+white(x)
+ if "--quiet" not in myopts:
+ print "\n "+white(x)
+ else:
+ print white(x)+": ",
for mytype in ["selected","protected","omitted"]:
- portage.writemsg_stdout((mytype + ": ").rjust(14), noiselevel=-1)
+ if "--quiet" not in myopts:
+ portage.writemsg_stdout((mytype + ": ").rjust(14), noiselevel=-1)
if pkgmap[x][mytype]:
for mypkg in pkgmap[x][mytype]:
mysplit=portage.catpkgsplit(mypkg)
portage.writemsg_stdout(
colorize("GOOD", myversion + " "), noiselevel=-1)
else:
- portage.writemsg_stdout("none", noiselevel=-1)
+ portage.writemsg_stdout("none ", noiselevel=-1)
+ if "--quiet" not in myopts:
+ portage.writemsg_stdout("\n", noiselevel=-1)
+ if "--quiet" in myopts:
portage.writemsg_stdout("\n", noiselevel=-1)
portage.writemsg_stdout("\n>>> " + colorize("UNMERGE_WARN", "'Selected'") + \
testatom = x
return portage.isvalidatom(testatom)
-def validate_merge_list(trees, mergelist):
- """Validate the list to make sure all the packages are still available.
- This is needed for --resume."""
- for (pkg_type, myroot, pkg_key, action) in mergelist:
- if pkg_type == "binary" and \
- not trees[myroot]["bintree"].dbapi.match("="+pkg_key) or \
- pkg_type == "ebuild" and \
- not trees[myroot]["porttree"].dbapi.xmatch(
- "match-all", "="+pkg_key):
- print red("!!! Error: The resume list contains packages that are no longer")
- print red("!!! available to be emerged. Please restart/continue")
- print red("!!! the merge operation manually.")
- sys.exit(1)
-
def show_blocker_docs_link():
print
print "For more information about " + bad("Blocked Packages") + ", please refer to the following"
print
print red(" * ")+bold("An update to portage is available.")+" It is _highly_ recommended"
print red(" * ")+"that you update portage now, before any other packages are updated."
- print red(" * ")+"Please run 'emerge portage' and then update "+bold("ALL")+" of your"
- print red(" * ")+"configuration files."
- print red(" * ")+"To update portage, run 'emerge portage'."
+ print
+ print red(" * ")+"To update portage, run 'emerge portage' now."
print
display_news_notification(trees)
# Loop through each package
# Only print settings if they differ from global settings
- header_printed = False
+ header_title = "Package Settings"
+ print header_width * "="
+ print header_title.rjust(int(header_width/2 + len(header_title)/2))
+ print header_width * "="
+ from portage.output import EOutput
+ out = EOutput()
for pkg in mypkgs:
# Get all package specific variables
auxvalues = vardb.aux_get(pkg, auxkeys)
# If a difference was found, print the info for
# this package.
if diff_values:
-
- # If we have not yet printed the header,
- # print it now
- if not header_printed:
- header_title = "Package Settings"
- print header_width * "="
- print header_title.rjust(int(header_width/2 + len(header_title)/2))
- print header_width * "="
- header_printed = True
-
# Print package info
print "%s was built with the following:" % pkg
for myvar in mydesiredvars + ["USE"]:
mylist.sort()
print "%s=\"%s\"" % (myvar, " ".join(mylist))
print
+ print ">>> Attempting to run pkg_info() for '%s'" % pkg
+ ebuildpath = vardb.findname(pkg)
+ if not ebuildpath or not os.path.exists(ebuildpath):
+ out.ewarn("No ebuild found for '%s'" % pkg)
+ continue
+ portage.doebuild(ebuildpath, "info", pkgsettings["ROOT"],
+ pkgsettings, debug=(settings.get("PORTAGE_DEBUG", "") == 1),
+ mydbapi=trees[settings["ROOT"]]["vartree"].dbapi,
+ tree="vartree")
def action_search(settings, portdb, vartree, myopts, myfiles, spinner):
if not myfiles:
# Kill packages that aren't explicitly merged or are required as a
# dependency of another package. World file is explicit.
- warn_prefix = colorize("BAD", "*** WARNING *** ")
- print
- print warn_prefix + "Depclean may break link level dependencies. Thus, it is"
- print warn_prefix + "recommended to use a tool such as " + good("`revdep-rebuild`") + " (from"
- print warn_prefix + "app-portage/gentoolkit) in order to detect such breakage."
- print warn_prefix
- print warn_prefix + "Also study the list of packages to be cleaned for any obvious"
- print warn_prefix + "mistakes. Packages that are part of the world set will always"
- print warn_prefix + "be kept. They can be manually added to this set with"
- print warn_prefix + good("`emerge --noreplace <atom>`") + ". Packages that are listed in"
- print warn_prefix + "package.provided (see portage(5)) will be removed by"
- print warn_prefix + "depclean, even if they are part of the world set."
- print warn_prefix
- print warn_prefix + "As a safety measure, depclean will not remove any packages"
- print warn_prefix + "unless *all* required dependencies have been resolved. As a"
- print warn_prefix + "consequence, it is often necessary to run "
- print warn_prefix + good("`emerge --update --newuse --deep world`") + " prior to depclean."
+ msg = []
+ msg.append("Depclean may break link level dependencies. Thus, it is\n")
+ msg.append("recommended to use a tool such as " + good("`revdep-rebuild`") + " (from\n")
+ msg.append("app-portage/gentoolkit) in order to detect such breakage.\n")
+ msg.append("\n")
+ msg.append("Also study the list of packages to be cleaned for any obvious\n")
+ msg.append("mistakes. Packages that are part of the world set will always\n")
+ msg.append("be kept. They can be manually added to this set with\n")
+ msg.append(good("`emerge --noreplace <atom>`") + ". Packages that are listed in\n")
+ msg.append("package.provided (see portage(5)) will be removed by\n")
+ msg.append("depclean, even if they are part of the world set.\n")
+ msg.append("\n")
+ msg.append("As a safety measure, depclean will not remove any packages\n")
+ msg.append("unless *all* required dependencies have been resolved. As a\n")
+ msg.append("consequence, it is often necessary to run\n")
+ msg.append(good("`emerge --update --newuse --deep world`") + " prior to depclean.\n")
+
+ portage.writemsg_stdout("\n")
+ for x in msg:
+ portage.writemsg_stdout(colorize("BAD", "*** WARNING *** ") + x)
xterm_titles = "notitles" not in settings.features
myroot = settings["ROOT"]
+ portdb = trees[myroot]["porttree"].dbapi
dep_check_trees = {}
dep_check_trees[myroot] = {}
dep_check_trees[myroot]["vartree"] = \
vardb = dep_check_trees[myroot]["vartree"].dbapi
# Constrain dependency selection to the installed packages.
dep_check_trees[myroot]["porttree"] = dep_check_trees[myroot]["vartree"]
- syslist = getlist(settings, "system")
- worldlist = getlist(settings, "world")
- system_world_dict = genericdict(worldlist)
- system_world_dict.update(genericdict(syslist))
+ system_set = SystemSet("system", settings.profiles)
+ syslist = list(system_set)
+ world_set = WorldSet("world", myroot)
+ worldlist = list(world_set)
fakedb = portage.fakedbapi(settings=settings)
myvarlist = vardb.cpv_all()
remaining_atoms += [(atom, 'system', hard) for atom in syslist if vardb.match(atom)]
unresolveable = {}
aux_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
+ metadata_keys = ["PROVIDE", "SLOT", "USE"]
while remaining_atoms:
atom, parent, priority = remaining_atoms.pop()
if not atom.startswith("!") and priority == hard:
unresolveable.setdefault(atom, []).append(parent)
continue
- if portage.dep_getkey(atom) not in system_world_dict:
+ if len(pkgs) > 1 and parent != "world":
# Prune all but the best matching slot, since that's all that a
- # deep world update would pull in. Don't prune if the cpv is in
- # system or world though, since those sets trigger greedy update
- # of all slots.
+ # deep world update would pull in. Don't prune if this atom comes
+ # directly from world though, since world atoms are greedy when
+ # they don't specify a slot.
+ visible_in_portdb = [cpv for cpv in pkgs if portdb.match("="+cpv)]
+ if visible_in_portdb:
+ # For consistency with the update algorithm, keep the highest
+ # visible version and prune any versions that are either masked
+ # or no longer exist in the portage tree.
+ pkgs = visible_in_portdb
pkgs = [portage.best(pkgs)]
for pkg in pkgs:
if fakedb.cpv_exists(pkg):
myopts, myaction, myfiles, spinner):
ldpath_mtimes = mtimedb["ldpath"]
favorites=[]
+ merge_count = 0
+ pretend = "--pretend" in myopts
+ fetchonly = "--fetchonly" in myopts or "--fetch-all-uri" in myopts
+ if pretend or fetchonly:
+ # make the mtimedb readonly
+ mtimedb.filename = None
if "--quiet" not in myopts and \
("--pretend" in myopts or "--ask" in myopts or \
"--tree" in myopts or "--verbose" in myopts):
mtimedb["resume"] = mtimedb["resume_backup"]
del mtimedb["resume_backup"]
mtimedb.commit()
- # XXX: "myopts" is a list for backward compatibility.
- myresumeopts = dict([(k,True) for k in mtimedb["resume"]["myopts"]])
-
- for opt in ("--skipfirst", "--ask", "--tree"):
- myresumeopts.pop(opt, None)
-
- for myopt, myarg in myopts.iteritems():
- if myopt not in myresumeopts:
- myresumeopts[myopt] = myarg
- myopts=myresumeopts
# Adjust config according to options of the command being resumed.
for myroot in trees:
mysettings.lock()
del myroot, mysettings
- myparams = create_depgraph_params(myopts, myaction)
- if "--quiet" not in myopts and "--nodeps" not in myopts:
+ # "myopts" is a list for backward compatibility.
+ resume_opts = mtimedb["resume"].get("myopts", [])
+ if isinstance(resume_opts, list):
+ resume_opts = dict((k,True) for k in resume_opts)
+ for opt in ("--skipfirst", "--ask", "--tree"):
+ resume_opts.pop(opt, None)
+ myopts.update(resume_opts)
+ show_spinner = "--quiet" not in myopts and "--nodeps" not in myopts
+ if not show_spinner:
+ spinner.update = spinner.update_quiet
+ if show_spinner:
print "Calculating dependencies ",
+ myparams = create_depgraph_params(myopts, myaction)
mydepgraph = depgraph(settings, trees,
myopts, myparams, spinner)
- if "--quiet" not in myopts and "--nodeps" not in myopts:
+ try:
+ mydepgraph.loadResumeCommand(mtimedb["resume"])
+ except portage.exception.PackageNotFound:
+ if show_spinner:
+ print
+ from portage.output import EOutput
+ out = EOutput()
+ out.eerror("Error: The resume list contains packages that are no longer")
+ out.eerror(" available to be emerged. Please restart/continue")
+ out.eerror(" the merge operation manually.")
+ return 1
+ if show_spinner:
print "\b\b... done!"
else:
if ("--resume" in myopts):
print darkgreen("emerge: It seems we have nothing to resume...")
- sys.exit(0)
+ return os.EX_OK
myparams = create_depgraph_params(myopts, myaction)
if myaction in ["system","world"]:
mydepgraph = depgraph(settings, trees, myopts, myparams, spinner)
if not mydepgraph.xcreate(myaction):
print "!!! Depgraph creation failed."
- sys.exit(1)
+ return 1
if "--quiet" not in myopts and "--nodeps" not in myopts:
print "\b\b... done!"
else:
retval, favorites = mydepgraph.select_files(myfiles)
except portage.exception.PackageNotFound, e:
portage.writemsg("\n!!! %s\n" % str(e), noiselevel=-1)
- sys.exit(1)
+ return 1
if not retval:
- sys.exit(1)
+ return 1
if "--quiet" not in myopts and "--nodeps" not in myopts:
print "\b\b... done!"
for x in mydepgraph.missingbins:
sys.stderr.write(" "+str(x)+"\n")
sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n")
- sys.exit(1)
+ return 1
if "--pretend" not in myopts and \
("--ask" in myopts or "--tree" in myopts or \
"--verbose" in myopts) and \
not ("--quiet" in myopts and "--ask" not in myopts):
if "--resume" in myopts:
- validate_merge_list(trees, mtimedb["resume"]["mergelist"])
mymergelist = mtimedb["resume"]["mergelist"]
if "--skipfirst" in myopts:
mymergelist = mymergelist[1:]
if len(mymergelist) == 0:
print colorize("INFORM", "emerge: It seems we have nothing to resume...")
- sys.exit(0)
- mydepgraph.display(mymergelist)
+ return os.EX_OK
+ favorites = mtimedb["resume"]["favorites"]
+ retval = mydepgraph.display(mymergelist, favorites=favorites)
+ if retval != os.EX_OK:
+ return retval
prompt="Would you like to resume merging these packages?"
else:
- mydepgraph.display(
- mydepgraph.altlist(reversed=("--tree" in myopts)))
+ retval = mydepgraph.display(
+ mydepgraph.altlist(reversed=("--tree" in myopts)),
+ favorites=favorites)
+ if retval != os.EX_OK:
+ return retval
mergecount=0
for x in mydepgraph.altlist():
if x[0] != "blocks" and x[3] != "nomerge":
print "!!! at the same time on the same system."
if "--quiet" not in myopts:
show_blocker_docs_link()
- sys.exit(1)
+ return 1
if mergecount==0:
if "--noreplace" in myopts and favorites:
print
print
print "Nothing to merge; quitting."
print
- sys.exit(0)
+ return os.EX_OK
elif "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
prompt="Would you like to fetch the source files for these packages?"
else:
print
print "Quitting."
print
- sys.exit(0)
+ return os.EX_OK
# Don't ask again (e.g. when auto-cleaning packages after merge)
myopts.pop("--ask", None)
if ("--pretend" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts):
if ("--resume" in myopts):
- validate_merge_list(trees, mtimedb["resume"]["mergelist"])
mymergelist = mtimedb["resume"]["mergelist"]
if "--skipfirst" in myopts:
mymergelist = mymergelist[1:]
if len(mymergelist) == 0:
print colorize("INFORM", "emerge: It seems we have nothing to resume...")
- sys.exit(0)
- mydepgraph.display(mymergelist)
+ return os.EX_OK
+ favorites = mtimedb["resume"]["favorites"]
+ retval = mydepgraph.display(mymergelist, favorites=favorites)
+ if retval != os.EX_OK:
+ return retval
else:
- mydepgraph.display(
- mydepgraph.altlist(reversed=("--tree" in myopts)))
+ retval = mydepgraph.display(
+ mydepgraph.altlist(reversed=("--tree" in myopts)),
+ favorites=favorites)
+ if retval != os.EX_OK:
+ return retval
if "--buildpkgonly" in myopts and \
not mydepgraph.digraph.hasallzeros(ignore_priority=DepPriority.MEDIUM):
print "\n!!! --buildpkgonly requires all dependencies to be merged."
print "!!! You have to merge the dependencies before you can build this package.\n"
- sys.exit(1)
+ return 1
else:
if ("--buildpkgonly" in myopts):
if not mydepgraph.digraph.hasallzeros(ignore_priority=DepPriority.MEDIUM):
print "\n!!! --buildpkgonly requires all dependencies to be merged."
print "!!! Cannot merge requested packages. Merge deps and try again.\n"
- sys.exit(1)
+ return 1
if ("--resume" in myopts):
favorites=mtimedb["resume"]["favorites"]
del mydepgraph
retval = mergetask.merge(
mtimedb["resume"]["mergelist"], favorites, mtimedb)
- if retval != os.EX_OK:
- sys.exit(retval)
+ merge_count = mergetask.curval
else:
if "resume" in mtimedb and \
"mergelist" in mtimedb["resume"] and \
pkglist.append(pkg)
else:
pkglist = mydepgraph.altlist()
+ if favorites:
+ mydepgraph.saveNomergeFavorites()
del mydepgraph
mergetask = MergeTask(settings, trees, myopts)
retval = mergetask.merge(pkglist, favorites, mtimedb)
- if retval != os.EX_OK:
- sys.exit(retval)
+ merge_count = mergetask.curval
+
+ if retval == os.EX_OK and not (pretend or fetchonly):
+ mtimedb.pop("resume", None)
+ if "yes" == settings.get("AUTOCLEAN"):
+ portage.writemsg_stdout(">>> Auto-cleaning packages...\n")
+ vartree = trees[settings["ROOT"]]["vartree"]
+ unmerge(settings, myopts, vartree, "clean", ["world"],
+ ldpath_mtimes, autoclean=1)
+ else:
+ portage.writemsg_stdout(colorize("WARN", "WARNING:")
+ + " AUTOCLEAN is disabled. This can cause serious"
+ + " problems due to overlapping packages.\n")
- if mtimedb.has_key("resume"):
- del mtimedb["resume"]
- if settings["AUTOCLEAN"] and "yes"==settings["AUTOCLEAN"]:
- portage.writemsg_stdout(">>> Auto-cleaning packages...\n")
- vartree = trees[settings["ROOT"]]["vartree"]
- unmerge(settings, myopts, vartree, "clean", ["world"],
- ldpath_mtimes, autoclean=1)
- else:
- portage.writemsg_stdout(colorize("WARN", "WARNING:")
- + " AUTOCLEAN is disabled. This can cause serious"
- + " problems due to overlapping packages.\n")
+ if merge_count and not (pretend or fetchonly):
+ post_emerge(trees, mtimedb, retval)
+ return retval
def multiple_actions(action1, action2):
sys.stderr.write("\n!!! Multiple actions requested... Please choose one only.\n")
"help":"include unnecessary build time dependencies",
"type":"choice",
"choices":("y", "n")
+ },
+ "--reinstall": {
+ "help":"specify conditions to trigger package reinstallation",
+ "type":"choice",
+ "choices":["changed-use"]
}
}
for x in myfiles:
ext = os.path.splitext(x)[1]
if (ext == ".ebuild" or ext == ".tbz2") and os.path.exists(os.path.abspath(x)):
- print "emerging by path implies --oneshot... adding --oneshot to options."
print colorize("BAD", "\n*** emerging by path is broken and may not always work!!!\n")
break
emerge.help.help(myaction, myopts, portage.output.havecolor)
sys.exit(0)
- if portage.wheelgid == portage.portage_gid:
- print "emerge: wheel group use is being deprecated. Please update group and passwd to"
- print " include the portage user as noted above, and then use group portage."
-
if "--debug" in myopts:
print "myaction", myaction
print "myopts", myopts
validate_ebuild_environment(trees)
if "--pretend" not in myopts:
display_news_notification(trees)
- action_build(settings, trees, mtimedb,
+ retval = action_build(settings, trees, mtimedb,
myopts, myaction, myfiles, spinner)
- if "--pretend" not in myopts:
- post_emerge(trees, mtimedb, os.EX_OK)
- else:
+ if "--pretend" in myopts:
display_news_notification(trees)
+ return retval
if __name__ == "__main__":
retval = emerge_main()