self.edebug = 1
self.spinner = spinner
self.pkgsettings = {}
- # Maps cpv to digraph node for "merge" nodes only.
+ # Maps cpv to digraph node for all nodes added to the graph.
self.pkg_node_map = {}
# Maps slot atom to digraph node for all nodes added to the graph.
self._slot_node_map = {}
self._altlist_cache = {}
self._pprovided_args = []
+ def _show_slot_collision_notice(self, packages):
+ """Show an informational message advising the user to mask one of the
+ the packages. In some cases it may be possible to resolve this
+ automatically, but support for backtracking (removal nodes that have
+ already been selected) will be required in order to handle all possible
+ cases."""
+
+ from formatter import AbstractFormatter, DumbWriter
+ f = AbstractFormatter(DumbWriter(maxcol=72))
+
+ print "\n!!! Multiple versions within a single " + \
+ "package slot have been "
+ print "!!! pulled into the dependency graph:"
+ print
+ for cpv in packages:
+ print " ", cpv
+ print
+
+ msg = []
+ msg.append("It may be possible to solve this problem ")
+ msg.append("by using package.mask to prevent one of ")
+ msg.append("those packages from being selected. ")
+ msg.append("However, it is also possible that conflicting ")
+ msg.append("dependencies exist such that they are impossible to ")
+ msg.append("satisfy simultaneously. If such a conflict exists in ")
+ msg.append("the dependencies of two different packages, then those ")
+ msg.append("packages can not be installed simultaneously.")
+
+ for x in msg:
+ f.add_flowing_data(x)
+ f.end_paragraph(1)
+
+ msg = []
+ msg.append("For more information, see MASKED PACKAGES ")
+ msg.append("section in the emerge man page or refer ")
+ msg.append("to the Gentoo Handbook.")
+ for x in msg:
+ f.add_flowing_data(x)
+ f.end_paragraph(1)
+
def create(self, mybigkey, myparent=None, addme=1, myuse=None,
priority=DepPriority(), rev_dep=False, arg=None):
"""
#IUSE-aware emerge -> USE DEP aware depgraph
#"no downgrade" emerge
"""
- jbigkey = tuple(chain(mybigkey, ["merge"]))
mytype, myroot, mykey = mybigkey
- if self.digraph.hasnode(jbigkey):
- if addme and jbigkey != myparent:
+ existing_node = None
+ if addme:
+ existing_node = self.pkg_node_map[myroot].get(mykey)
+ if existing_node:
+ if existing_node != myparent:
# Refuse to make a node depend on itself so that the we don't
# don't create a bogus circular dependency in self.altlist().
if rev_dep and myparent:
- ptype, proot, pkey, pstatus = myparent
- self.digraph.addnode(myparent, jbigkey, priority=priority)
+ self.digraph.addnode(myparent, existing_node,
+ priority=priority)
else:
- self.digraph.addnode(jbigkey, myparent, priority=priority)
- return 1
- jbigkey = tuple(chain(mybigkey, ["nomerge"]))
- if self.digraph.hasnode(jbigkey):
- if rev_dep and myparent:
- ptype, proot, pkey, pstatus = myparent
- self.digraph.addnode(myparent, jbigkey, priority=priority)
- else:
- self.digraph.addnode(jbigkey, myparent, priority=priority)
+ self.digraph.addnode(existing_node, myparent,
+ priority=priority)
return 1
self.spinner.update()
if myuse is None:
self.pkgsettings[myroot].setcpv(mykey, mydb=portdb)
myuse = self.pkgsettings[myroot]["USE"].split()
- self.useFlags[myroot][mykey] = myuse
merging=1
if mytype == "installed":
else:
mybigkey.append("nomerge")
- if merging == 0 and vardbapi.cpv_exists(mykey):
- myuse = vardbapi.aux_get(mykey, ["USE"])[0].split()
- self.useFlags[myroot][mykey] = myuse
+ if addme:
+ metadata = dict(izip(self._mydbapi_keys,
+ mydbapi.aux_get(mykey, self._mydbapi_keys)))
+ if merging == 0 and vardbapi.cpv_exists(mykey):
+ metadata["USE"] = vardbapi.aux_get(mykey, ["USE"])[0]
+ myuse = metadata["USE"].split()
+ metadata["SLOT"] = vardbapi.aux_get(mykey, ["SLOT"])[0]
+ slot_atom = "%s:%s" % (portage.dep_getkey(mykey), metadata["SLOT"])
+ existing_node = self._slot_node_map[myroot].get(
+ slot_atom, None)
+ if existing_node:
+ e_type, myroot, e_cpv, e_status = existing_node
+ if mykey == e_cpv:
+ # The existing node can be reused.
+ if rev_dep and myparent:
+ ptype, proot, pkey, pstatus = myparent
+ self.digraph.addnode(myparent, existing_node,
+ priority=priority)
+ else:
+ self.digraph.addnode(existing_node, myparent,
+ priority=priority)
+ return 1
+ else:
+ self._show_slot_collision_notice((mykey, e_cpv))
+ return 0
- """ At this point, we have either hit a blocker and returned, found the package in the
- depgraph already and returned, or we are here. Whether we are merging or not; we must
- add the package to the depgraph; so we do that here. """
- jbigkey = tuple(mybigkey)
- if rev_dep and myparent:
- ptype, proot, pkey, pstatus = myparent
- self.digraph.addnode(myparent, jbigkey,
- priority=priority)
- else:
- self.digraph.addnode(jbigkey, myparent,
- priority=priority)
-
- metadata = dict(izip(self._mydbapi_keys,
- mydbapi.aux_get(mykey, self._mydbapi_keys)))
- slot_atom = "%s:%s" % (portage.dep_getkey(mykey), metadata["SLOT"])
- self._slot_node_map[myroot][slot_atom] = jbigkey
- if mybigkey[-1] == "merge":
+ jbigkey = tuple(mybigkey)
+ self._slot_node_map[myroot][slot_atom] = jbigkey
self.pkg_node_map[myroot][mykey] = jbigkey
+ self.useFlags[myroot][mykey] = myuse
self.mydbapi[myroot].cpv_inject(mykey, metadata=metadata)
+ if rev_dep and myparent:
+ self.digraph.addnode(myparent, jbigkey,
+ priority=priority)
+ else:
+ self.digraph.addnode(jbigkey, myparent,
+ priority=priority)
+
""" This section determines whether we go deeper into dependencies or not.
We want to go deeper on a few occasions:
Installing package A, we need to make sure package A's deps are met.
# ordered by type preference ("ebuild" type is the last resort)
selected_pkg = matched_packages[0]
+ pkgtype, myroot, mycpv, myuse = selected_pkg
+ mydbapi = self.trees[myroot][self.pkg_tree_map[pkgtype]].dbapi
+ slot_atom = "%s:%s" % (portage.dep_getkey(mycpv),
+ mydbapi.aux_get(mycpv, ["SLOT"])[0])
+ existing_node = self._slot_node_map[myroot].get(
+ slot_atom, None)
+ if existing_node:
+ e_type, myroot, e_cpv, e_status = existing_node
+ if portage.match_from_list(x, [e_cpv]):
+ # The existing node can be reused.
+ selected_pkg = [e_type, myroot, e_cpv,
+ self.useFlags[myroot][e_cpv]]
+ else:
+ self._show_slot_collision_notice((mycpv, e_cpv))
+ return 0
if myparent:
#we are a dependency, so we want to be unconditionally added
counters.blocks += 1
resolved = portage.key_expand(
pkg_key, mydb=vardb, settings=pkgsettings)
- print "["+x[0]+" "+addl+"]",red(resolved),
+ if "--columns" in self.myopts and "--quiet" in self.myopts:
+ print addl,red(resolved),
+ else:
+ print "["+x[0]+" "+addl+"]",red(resolved),
block_parents = self.blocker_parents[tuple(x)]
block_parents = set([pnode[2] for pnode in block_parents])
block_parents = ", ".join(block_parents)