From 2999e12b76754b6921022a702f849f7265717c32 Mon Sep 17 00:00:00 2001 From: Fabian Groffen Date: Fri, 5 Dec 2008 21:26:21 +0000 Subject: [PATCH] Merged from trunk -r12146:12161 | 12148 | Bug #249185 - For common cases in which USE deps trigger | | zmedico | SLOT conflicts, give a short explanation and suggest a | | | course of action to solve the problem. | | 12150 | Make sure depgraph._slot_conflict_explanation() doesn't | | zmedico | display the same atom more than once. | | 12152 | Bug #249805 - Add some more | | zmedico | PreservedLibsRegistry.pruneNonExisting() calls, to avoid a | | | KeyError from LinkageMap.findConsumers() triggered inside | | | display_preserved_libs(). | | 12153 | Enable FEATURES=fixpackages by default since the performance | | zmedico | is pretty reasonable now. Thanks to Jeremy Olexa | | | for the suggestion. | | 12154 | Sync with 2.1.6 branch. | | zmedico | | | 12155 | FEATURES=fixpackages is now enabled by default | | zmedico | | | 12157 | Make fixpackages less noisy by only generting '*' characters | | zmedico | for packages that are modified by updates. | | 12159 | Make fixpackages use a new "#" symbol for /var/db updates | | zmedico | (previously '*' which means 'binary update' was used). | svn path=/main/branches/prefix/; revision=12164 --- NEWS | 13 ++-- RELEASE-NOTES | 26 +++++--- cnf/make.globals | 2 +- man/make.conf.5 | 4 +- pym/_emerge/__init__.py | 119 +++++++++++++++++++++++++++++----- pym/portage/__init__.py | 20 ++++-- pym/portage/dbapi/__init__.py | 10 ++- pym/portage/dbapi/vartree.py | 4 ++ 8 files changed, 157 insertions(+), 41 deletions(-) diff --git a/NEWS b/NEWS index 11d601c1e..2affc7f49 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,15 @@ News (mainly features/major bug fixes) portage-2.2 ------------- +* Add link level dependency awareness to emerge --depclean and --prune actions + in order to protect against uninstallation of required libraries. + packages in the same way, and also drops any masked packages. +* Add license visibility filtering (GLEP 23) +* Add support for generic package sets (also see RELEASE-NOTES) + +portage-2.1.6 +------------- + * Add support for a new EAPI="2" value. For more information about new EAPI features, refer to the "Ebuild" chapter of the html documentation that is installed with portage. @@ -25,11 +34,7 @@ portage-2.2 as a decent substitute for module-rebuild. * Namespace sanitizing: move all portage related code into portage.* namespace, rename portage_foo modules to portage.foo (but keep symlinks for compability) -* Add license visibility filtering (GLEP 23) -* Experimental support for preserving old library files on package upgrades - based on FEATURES=preserve-libs * Add support for news items (GLEP 42) -* Add support for generic package sets (also see RELEASE-NOTES) portage-2.1.5 ------------- diff --git a/RELEASE-NOTES b/RELEASE-NOTES index a7ff16ad8..47627acd6 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -4,16 +4,6 @@ Features/major bugfixes are listed in NEWS portage-2.2 ================================== -* The python namespace for portage has been sanitized, all portage related code - is now contained within the portage namespace. External script should be updated - accordingly, though links exist for backward compability. -* -* support in package.keywords was changed as it was inconsistent with - ACCEPT_KEYWORDS behavior (also see http://dev.gentoo.org/~genone/docs/KEYWORDS.stupid). - Previously having -* in package.keywords matched packages with KEYWORDS="-*", - now it resets the ACCEPT_KEYWORDS list for the given atom like it does when - used in ACCEPT_KEYWORDS. - For packages that don't specify any other KEYWORDS you can use the new ** token - as documented in portage(5) to disable KEYWORDS filtering completely. * Portage now warns if an ebuild repository does not have a name, as several new features in 2.2 make use of or require named repositories. The repository name is stored in profiles/repo_name in each repository. @@ -30,6 +20,22 @@ portage-2.2 * "world" does no longer include "system" unconditionally, but you can add "@system" to the world_sets file to restore the old state. +portage-2.1.6 +================================== + +* FEATURES=fixpackages is now enabled by default via make.globals. Set + FEATURES="-fixpackages" in make.conf if you'd like to disable it. +* The python namespace for portage has been sanitized, all portage related code + is now contained within the portage namespace. External script should be updated + accordingly, though links exist for backward compability. +* -* support in package.keywords was changed as it was inconsistent with + ACCEPT_KEYWORDS behavior (also see http://dev.gentoo.org/~genone/docs/KEYWORDS.stupid). + Previously having -* in package.keywords matched packages with KEYWORDS="-*", + now it resets the ACCEPT_KEYWORDS list for the given atom like it does when + used in ACCEPT_KEYWORDS. + For packages that don't specify any other KEYWORDS you can use the new ** token + as documented in portage(5) to disable KEYWORDS filtering completely. + portage-2.1.5 ================================== diff --git a/cnf/make.globals b/cnf/make.globals index d251f4e6c..c41c23a6b 100644 --- a/cnf/make.globals +++ b/cnf/make.globals @@ -38,7 +38,7 @@ FETCHCOMMAND="wget -t 5 -T 60 --passive-ftp -O \"\${DISTDIR}/\${FILE}\" \"\${URI RESUMECOMMAND="wget -c -t 5 -T 60 --passive-ftp -O \"\${DISTDIR}/\${FILE}\" \"\${URI}\"" # Default user options -FEATURES="distlocks parallel-fetch protect-owned sandbox +FEATURES="distlocks fixpackages parallel-fetch protect-owned sandbox sfperms strict unmerge-orphans userfetch" # Ignore file collisions in /lib/modules since files inside this directory diff --git a/man/make.conf.5 b/man/make.conf.5 index 530ef6aef..576278996 100644 --- a/man/make.conf.5 +++ b/man/make.conf.5 @@ -426,9 +426,9 @@ This is the host from which portage will grab prebuilt\-binary packages. The list is a single entry specifying the full address of the directory serving the tbz2's for your system. This is only used when running with the get binary pkg options are given to \fBemerge\fR. Review \fBemerge\fR(1) -for more information. For versions of portage less that 2.2, this variable +for more information. For versions of portage less that 2.1.6, this variable should point to the 'All' directory on the host that creates the binary -packages and not to the root of the \fBPKGDIR\fR. Starting with portage 2.2, +packages and not to the root of the \fBPKGDIR\fR. Starting with portage 2.1.6, it should point to a directory containing a 'Packages' index file. If ${PORTAGE_BINHOST}/Packages does not exist then portage will attempt to use the older protocol. diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index a09262eb1..f098d98ad 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -4376,23 +4376,6 @@ class depgraph(object): automatically, but support for backtracking (removal nodes that have already been selected) will be required in order to handle all possible cases. - - When a slot conflict occurs due to USE deps, there are a few - different cases to consider: - - 1) New USE are correctly set but --newuse wasn't requested so an - installed package with incorrect USE happened to get pulled - into graph before the new one. - - 2) New USE are incorrectly set but an installed package has correct - USE so it got pulled into the graph, and a new instance also got - pulled in due to --newuse or an upgrade. - - 3) Multiple USE deps exist that can't be satisfied simultaneously, - and multiple package instances got pulled into the same slot to - satisfy the conflicting deps. - - TODO: Distinguish the above cases and tailor messages to suit them. """ if not self._slot_collision_info: @@ -4408,6 +4391,8 @@ class depgraph(object): indent = " " # Max number of parents shown, to avoid flooding the display. max_parents = 3 + explanation_columns = 70 + explanations = 0 for (slot_atom, root), slot_nodes \ in self._slot_collision_info.iteritems(): msg.append(str(slot_atom)) @@ -4473,11 +4458,20 @@ class depgraph(object): else: msg.append(" (no parents)\n") msg.append("\n") + explanation = self._slot_conflict_explanation(slot_nodes) + if explanation: + explanations += 1 + msg.append(indent + "Explanation:\n\n") + for line in textwrap.wrap(explanation, explanation_columns): + msg.append(2*indent + line + "\n") + msg.append("\n") msg.append("\n") sys.stderr.write("".join(msg)) sys.stderr.flush() - if "--quiet" in self.myopts: + explanations_for_all = explanations == len(self._slot_collision_info) + + if explanations_for_all or "--quiet" in self.myopts: return msg = [] @@ -4505,6 +4499,92 @@ class depgraph(object): f.end_paragraph(1) f.writer.flush() + def _slot_conflict_explanation(self, slot_nodes): + """ + When a slot conflict occurs due to USE deps, there are a few + different cases to consider: + + 1) New USE are correctly set but --newuse wasn't requested so an + installed package with incorrect USE happened to get pulled + into graph before the new one. + + 2) New USE are incorrectly set but an installed package has correct + USE so it got pulled into the graph, and a new instance also got + pulled in due to --newuse or an upgrade. + + 3) Multiple USE deps exist that can't be satisfied simultaneously, + and multiple package instances got pulled into the same slot to + satisfy the conflicting deps. + + Currently, explanations and suggested courses of action are generated + for cases 1 and 2. Case 3 is too complex to give a useful suggestion. + """ + + if len(slot_nodes) != 2: + # Suggestions are only implemented for + # conflicts between two packages. + return None + + all_conflict_atoms = self._slot_conflict_parent_atoms + matched_node = None + matched_atoms = None + unmatched_node = None + for node in slot_nodes: + parent_atoms = self._parent_atoms.get(node) + if not parent_atoms: + # Normally, there are always parent atoms. If there are + # none then something unexpected is happening and there's + # currently no suggestion for this case. + return None + conflict_atoms = all_conflict_atoms.intersection(parent_atoms) + for parent_atom in conflict_atoms: + parent, atom = parent_atom + if not atom.use: + # Suggestions are currently only implemented for cases + # in which all conflict atoms have USE deps. + return None + if conflict_atoms: + if matched_node is not None: + # If conflict atoms match multiple nodes + # then there's no suggestion. + return None + matched_node = node + matched_atoms = conflict_atoms + else: + if unmatched_node is not None: + # Neither node is matched by conflict atoms, and + # there is no suggestion for this case. + return None + unmatched_node = node + + if matched_node is None or unmatched_node is None: + # This shouldn't happen. + return None + + if unmatched_node.installed and not matched_node.installed: + return "New USE are correctly set, but --newuse wasn't" + \ + " requested, so an installed package with incorrect USE " + \ + "happened to get pulled into the dependency graph. " + \ + "In order to solve " + \ + "this, either specify the --newuse option or explicitly " + \ + " reinstall '%s'." % matched_node.slot_atom + + if matched_node.installed and not unmatched_node.installed: + atoms = sorted(set(atom for parent, atom in matched_atoms)) + explanation = ("New USE for '%s' are incorrectly set. " + \ + "In order to solve this, adjust USE to satisfy '%s'") % \ + (matched_node.slot_atom, atoms[0]) + if len(atoms) > 1: + for atom in atoms[1:-1]: + explanation += ", '%s'" % (atom,) + if len(atoms) > 2: + explanation += "," + explanation += " and '%s'" % (atoms[-1],) + explanation += "." + return explanation + + return None + def _process_slot_conflicts(self): """ Process slot conflict data to identify specific atoms which @@ -11336,6 +11416,9 @@ def display_news_notification(root_config, myopts): def display_preserved_libs(vardbapi): MAX_DISPLAY = 3 + # Ensure the registry is consistent with existing files. + vardbapi.plib_registry.pruneNonExisting() + if vardbapi.plib_registry.hasEntries(): print print colorize("WARN", "!!!") + " existing preserved libs:" diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index 3c9239165..8541b7cae 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -7393,7 +7393,13 @@ def _global_updates(trees, prev_mtimes): writemsg_stdout("\n\n") writemsg_stdout(green("Performing Global Updates: ")+bold(mykey)+"\n") writemsg_stdout("(Could take a couple of minutes if you have a lot of binary packages.)\n") - writemsg_stdout(" "+bold(".")+"='update pass' "+bold("*")+"='binary update' "+bold("@")+"='/var/db move'\n"+" "+bold("s")+"='/var/db SLOT move' "+bold("%")+"='binary move' "+bold("S")+"='binary SLOT move'\n "+bold("p")+"='update /etc/portage/package.*'\n") + writemsg_stdout(" " + bold(".") + "='update pass' " + \ + bold("*") + "='binary update' " + bold("#") + \ + "='/var/db update' " + bold("@") + "='/var/db move'\n" + \ + " " + bold("s") + "='/var/db SLOT move' " + \ + bold("%") + "='binary move' " + bold("S") + \ + "='binary SLOT move'\n " + \ + bold("p") + "='update /etc/portage/package.*'\n") valid_updates, errors = parse_updates(mycontent) myupd.extend(valid_updates) writemsg_stdout(len(valid_updates) * "." + "\n") @@ -7461,11 +7467,15 @@ def _global_updates(trees, prev_mtimes): # We gotta do the brute force updates for these now. if mysettings["PORTAGE_CALLER"] == "fixpackages" or \ "fixpackages" in mysettings.features: - def onProgress(maxval, curval): - writemsg_stdout("*") - vardb.update_ents(myupd, onProgress=onProgress) + def onUpdate(maxval, curval): + if curval > 0: + writemsg_stdout("#") + vardb.update_ents(myupd, onUpdate=onUpdate) if bindb: - bindb.update_ents(myupd, onProgress=onProgress) + def onUpdate(maxval, curval): + if curval > 0: + writemsg_stdout("*") + bindb.update_ents(myupd, onUpdate=onUpdate) else: do_upgrade_packagesmessage = 1 diff --git a/pym/portage/dbapi/__init__.py b/pym/portage/dbapi/__init__.py index 2bdb3e7cd..435ffebbb 100644 --- a/pym/portage/dbapi/__init__.py +++ b/pym/portage/dbapi/__init__.py @@ -200,13 +200,17 @@ class dbapi(object): else: writemsg("!!! Invalid db entry: %s\n" % mypath, noiselevel=-1) - def update_ents(self, updates, onProgress=None): + def update_ents(self, updates, onProgress=None, onUpdate=None): """ Update metadata of all packages for package moves. @param updates: A list of move commands @type updates: List @param onProgress: A progress callback function @type onProgress: a callable that takes 2 integer arguments: maxval and curval + @param onUpdate: A progress callback function called only + for packages that are modified by updates. + @type onUpdate: a callable that takes 2 integer arguments: + maxval and curval """ cpv_all = self.cpv_all() cpv_all.sort() @@ -216,6 +220,8 @@ class dbapi(object): update_keys = ["DEPEND", "RDEPEND", "PDEPEND", "PROVIDE"] from itertools import izip from portage.update import update_dbentries + if onUpdate: + onUpdate(maxval, 0) if onProgress: onProgress(maxval, 0) for i, cpv in enumerate(cpv_all): @@ -223,6 +229,8 @@ class dbapi(object): metadata_updates = update_dbentries(updates, metadata) if metadata_updates: aux_update(cpv, metadata_updates) + if onUpdate: + onUpdate(maxval, i+1) if onProgress: onProgress(maxval, i+1) diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py index 5e695ed07..d67ad5c93 100644 --- a/pym/portage/dbapi/vartree.py +++ b/pym/portage/dbapi/vartree.py @@ -2588,6 +2588,10 @@ class dblink(object): break continue self.vartree.dbapi.removeFromContents(cpv, removed) + else: + # Prune any preserved libs that may have + # been unmerged with this package. + self.vartree.dbapi.plib_registry.pruneNonExisting() finally: if builddir_lock: -- 2.26.2