Merged from trunk -r12146:12161
authorFabian Groffen <grobian@gentoo.org>
Fri, 5 Dec 2008 21:26:21 +0000 (21:26 -0000)
committerFabian Groffen <grobian@gentoo.org>
Fri, 5 Dec 2008 21:26:21 +0000 (21:26 -0000)
   | 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             |
   |         | <darkside@g.o> 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
RELEASE-NOTES
cnf/make.globals
man/make.conf.5
pym/_emerge/__init__.py
pym/portage/__init__.py
pym/portage/dbapi/__init__.py
pym/portage/dbapi/vartree.py

diff --git a/NEWS b/NEWS
index 11d601c1e8197ddc77bd573e8bfa677b7280695d..2affc7f49052f3bdeaa53cf3256a4cb6188cbc3e 100644 (file)
--- 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
 -------------
index a7ff16ad87de92ab360f60e31d3067943b376ce4..47627acd6d11bb215e0c3b7ffe4652253023bf6d 100644 (file)
@@ -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
 ==================================
 
index d251f4e6cc1b149265da0ae801e88c0f72ab1840..c41c23a6bccc8c99b530c36476a2b427bf08a1ae 100644 (file)
@@ -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
index 530ef6aeffff45fefb8620e4cd5cab411194dd84..576278996b449f39a7064513ef2aa4ff57d8c581 100644 (file)
@@ -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.
index a09262eb12f4e6590d47302df3001a2b2207b4cb..f098d98ad1fc10679f8938aa6e2e49c8457fbb1d 100644 (file)
@@ -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:"
index 3c923916523661fccac6f084a2da9e52f8425de1..8541b7caebb645df6eb9d8eb6434e8153722f6d3 100644 (file)
@@ -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
 
index 2bdb3e7cdefaa5d34eea89ec34a3cc705d823689..435ffebbb941a2dd9f51a6944842ee33ae535505 100644 (file)
@@ -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)
 
index 5e695ed079aed45b21966827057f369603d628e4..d67ad5c931cd7d55e19f4c4e5d035fb3027eb0c8 100644 (file)
@@ -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: