diff options
author | 2020-11-27 17:57:14 -0800 | |
---|---|---|
committer | 2020-11-28 12:50:13 -0800 | |
commit | b991f23ad915d1fc37088f11ca855c8c8374f5ae (patch) | |
tree | 80ac54946ea4f3a63efac8877645d76bdaf7a121 /lib/_emerge/depgraph.py | |
parent | backtracking: fix virtual choices for circular deps (bug 757306) (diff) | |
download | portage-b991f23ad915d1fc37088f11ca855c8c8374f5ae.tar.gz portage-b991f23ad915d1fc37088f11ca855c8c8374f5ae.tar.bz2 portage-b991f23ad915d1fc37088f11ca855c8c8374f5ae.zip |
Allow a package to replace its own buildtime dependency
If a package has a buildtime dependency on a previous version that
it will replace, then do not treat it as a slot conflict. This
solves inappropriate behavior for dev-lang/rust[system-bootstrap].
This requires adjustments to package selection logic in several
locations, in order to ensure that an installed package instance
will be selected to satisfy a buildtime dependency when
appropriate. Dependencies of the installed package will be
entirely ignored, but that has already been the case when using
installed package to break cycles, as discussed in bug 199856.
Bug: https://bugs.gentoo.org/756793
Bug: https://bugs.gentoo.org/756961
Signed-off-by: Zac Medico <zmedico@gentoo.org>
Diffstat (limited to 'lib/_emerge/depgraph.py')
-rw-r--r-- | lib/_emerge/depgraph.py | 68 |
1 files changed, 55 insertions, 13 deletions
diff --git a/lib/_emerge/depgraph.py b/lib/_emerge/depgraph.py index d10474ab3..1271bda3e 100644 --- a/lib/_emerge/depgraph.py +++ b/lib/_emerge/depgraph.py @@ -85,6 +85,8 @@ from _emerge.resolver.output import Display, format_unmatched_atom # Exposes a depgraph interface to dep_check. _dep_check_graph_interface = collections.namedtuple('_dep_check_graph_interface',( + # Checks if parent package will replace child. + 'will_replace_child', # Indicates a removal action, like depclean or prune. 'removal_action', # Checks if update is desirable for a given package. @@ -507,6 +509,7 @@ class _dynamic_depgraph_config: # Track missed updates caused by solved conflicts. self._conflict_missed_update = collections.defaultdict(dict) dep_check_iface = _dep_check_graph_interface( + will_replace_child=depgraph._will_replace_child, removal_action="remove" in myparams, want_update_pkg=depgraph._want_update_pkg, ) @@ -3104,6 +3107,22 @@ class depgraph: self._frozen_config.myopts, modified_use=self._pkg_use_enabled(pkg))), level=logging.DEBUG, noiselevel=-1) + elif (pkg.installed and myparent and + pkg.root == myparent.root and + pkg.slot_atom == myparent.slot_atom): + # If the parent package is replacing the child package then + # there's no slot conflict. Since the child will be replaced, + # do not add it to the graph. No attempt will be made to + # satisfy its dependencies, which is unsafe if it has any + # missing dependencies, as discussed in bug 199856. + if debug: + writemsg_level( + "%s%s %s\n" % ("Replace Child:".ljust(15), + pkg, pkg_use_display(pkg, + self._frozen_config.myopts, + modified_use=self._pkg_use_enabled(pkg))), + level=logging.DEBUG, noiselevel=-1) + return 1 else: if debug: @@ -5877,6 +5896,27 @@ class depgraph: (arg_atoms or update) and not self._too_deep(depth)) + def _will_replace_child(self, parent, root, atom): + """ + Check if a given parent package will replace a child package + for the given root and atom. + + @param parent: parent package + @type parent: Package + @param root: child root + @type root: str + @param atom: child atom + @type atom: Atom + @rtype: Package + @return: child package to replace, or None + """ + if parent.root != root or parent.cp != atom.cp: + return None + for child in self._iter_match_pkgs(self._frozen_config.roots[root], "installed", atom): + if parent.slot_atom == child.slot_atom: + return child + return None + def _too_deep(self, depth): """ Check if a package depth is deeper than the max allowed depth. @@ -6440,19 +6480,21 @@ class depgraph: # Calculation of USE for unbuilt ebuilds is relatively # expensive, so it is only performed lazily, after the # above visibility checks are complete. - - myarg = None - try: - for myarg, myarg_atom in self._iter_atoms_for_pkg(pkg): - if myarg.force_reinstall: - reinstall = True - break - except InvalidDependString: - if not installed: - # masked by corruption - continue - if not installed and myarg: - found_available_arg = True + effective_parent = parent or self._select_atoms_parent + if not (effective_parent and self._will_replace_child( + effective_parent, root, atom)): + myarg = None + try: + for myarg, myarg_atom in self._iter_atoms_for_pkg(pkg): + if myarg.force_reinstall: + reinstall = True + break + except InvalidDependString: + if not installed: + # masked by corruption + continue + if not installed and myarg: + found_available_arg = True if atom.package and atom.unevaluated_atom.use: #Make sure we don't miss a 'missing IUSE'. |