Merged from trunk 10182:10208
authorFabian Groffen <grobian@gentoo.org>
Thu, 8 May 2008 19:14:22 +0000 (19:14 -0000)
committerFabian Groffen <grobian@gentoo.org>
Thu, 8 May 2008 19:14:22 +0000 (19:14 -0000)
   | 10184   | In the package uninstall sanity check, use RDEPEND from the  |
   | zmedico | currently running 'sys-apps/portage' instance to create a    |
   |         | set of protected atoms.                                      |

   | 10186   | Fix misplaced variable.                                      |
   | zmedico |                                                              |

   | 10188   | Use a separate digraph to preserve irrelevant blocker        |
   | zmedico | relationships that are removed from                          |
   |         | depgraph._blocker_parents since the irrelevant blockers are  |
   |         | still needed for the blocker cache.                          |

   | 10190   | Use writemsg() to warn about InvalidDependString exceptions  |
   | zmedico | that may occur for installed packages.                       |

   | 10192   | Bug #220171 - Filter out 'lost+found' directories in         |
   | zmedico | vardbapi.cpv_all() in order to avoid fatal 'Permission       |
   |         | denied' errors. Currently, CVS and names beginning with '.'  |
   |         | are also filtered.                                           |

   | 10194   | * Fix --buildpkgonly logic to avoid an unwanted code path. * |
   | zmedico | Remove unnecessary mtimedb.pop("resume", None) call.         |

   | 10195   | Bug #219286 - Whitelist INSTALL_MASK so that it works        |
   | zmedico | properly for binary packages. Also, filter INSTALL_MASK when |
   |         | saving or loading environment.bz2. This also applies to      |
   |         | PKG_INSTALL_MASK and DOC_SYMLINKS_DIR, so add them too.      |

   | 10198   | Add "package" to EBUILD_PHASES since it's possible for einfo |
   | zmedico | to be called by install_mask() during that phase.            |

   | 10200   | fix preserve_libs logic to properly account for the current  |
   | genone  | package instance                                             |

   | 10202   | Handle a potential InvalidData exception in                  |
   | zmedico | vardbapi.cp_all().                                           |

   | 10204   | * In vardbapi.cpv_all() use catpkgsplit() for validation     |
   | zmedico | since that's what with cp_all() uses. * Use the listdir()    |
   |         | dirsonly=1 parameter to avoid unnecessary stat calls via     |
   |         | os.path.isdir().                                             |

   | 10206   | Add -MERGING-.* to vardbapi._excluded_dirs.                  |
   | zmedico |                                                              |

   | 10208   | Use vardbapi._excluded_dirs to filter results inside         |
   | zmedico | cp_list().                                                   |

svn path=/main/branches/prefix/; revision=10243

bin/isolated-functions.sh
pym/_emerge/__init__.py
pym/portage/__init__.py
pym/portage/const.py
pym/portage/dbapi/vartree.py

index 343d6265700e9a9f222e9af8d5277e3178d751c3..ddb8e040ecb1ebc0e9abead00fa3b55ad8957783 100755 (executable)
@@ -503,6 +503,9 @@ save_ebuild_env() {
                # Prefix additions
                unset BPREFIX DEFAULT_PATH EPREFIX EROOT PORTAGE_GROUP PORTAGE_USER
 
+               # user config variables
+               unset DOC_SYMLINKS_DIR INSTALL_MASK PKG_INSTALL_MASK
+
                set
                export
        )
index 0392af366fe2925bcdb6b77bedb476bbd6065c90..993de914ed9eca0090dd03ebcc95c2fd4d388b89 100644 (file)
@@ -1814,6 +1814,8 @@ class depgraph(object):
                self._blocker_uninstalls = digraph()
                # Contains only Package -> Blocker edges
                self._blocker_parents = digraph()
+               # Contains only irrelevant Package -> Blocker edges
+               self._irrelevant_blockers = digraph()
                # Contains only unsolvable Package -> Blocker edges
                self._unsolvable_blockers = digraph()
                self._slot_collision_info = set()
@@ -3199,10 +3201,17 @@ class depgraph(object):
                                        blocker_atoms = None
                                        blockers = None
                                        if self.digraph.contains(pkg):
+                                               blockers = []
                                                try:
-                                                       blockers = self._blocker_parents.child_nodes(pkg)
+                                                       blockers.extend(
+                                                               self._blocker_parents.child_nodes(pkg))
                                                except KeyError:
-                                                       blockers = []
+                                                       pass
+                                               try:
+                                                       blockers.extend(
+                                                               self._irrelevant_blockers.child_nodes(pkg))
+                                               except KeyError:
+                                                       pass
                                        if blockers is not None:
                                                blockers = set("!" + blocker.atom \
                                                        for blocker in blockers)
@@ -3334,6 +3343,7 @@ class depgraph(object):
                                self._blocker_parents.remove(blocker)
                                # Discard any parents that don't have any more blockers.
                                for pkg in parent_pkgs:
+                                       self._irrelevant_blockers.add(blocker, pkg)
                                        if not self._blocker_parents.child_nodes(pkg):
                                                self._blocker_parents.remove(pkg)
                                continue
@@ -3408,6 +3418,7 @@ class depgraph(object):
                                                # merged.
                                                self._blocker_uninstalls.addnode(uninst_task, blocker)
                                if not unresolved_blocks and not depends_on_order:
+                                       self._irrelevant_blockers.add(blocker, parent)
                                        self._blocker_parents.remove_edge(blocker, parent)
                                        if not self._blocker_parents.parent_nodes(blocker):
                                                self._blocker_parents.remove(blocker)
@@ -3514,18 +3525,42 @@ class depgraph(object):
                                node.operation != "uninstall"]
 
                # sys-apps/portage needs special treatment if ROOT="/"
-               portage_python_dep = ">=dev-lang/python-2.4"
-               portage_unslotted_deps = frozenset(
-                       ["app-shells/bash", "sys-apps/portage"])
-               portage_node = self.mydbapi["/"].match_pkgs("sys-apps/portage")
-               if portage_node:
-                       portage_node = portage_node[0]
+               running_root = "/"
+               from portage.const import PORTAGE_PACKAGE_ATOM
+               runtime_deps = InternalPackageSet(
+                       initial_atoms=[PORTAGE_PACKAGE_ATOM])
+               running_portage = self.trees[running_root]["vartree"].dbapi.match_pkgs(
+                       PORTAGE_PACKAGE_ATOM)
+               replacement_portage = self.mydbapi[running_root].match_pkgs(
+                       PORTAGE_PACKAGE_ATOM)
+
+               if running_portage:
+                       running_portage = running_portage[0]
                else:
-                       portage_node = None
-               if portage_node is not None and \
-                       (not mygraph.contains(portage_node) or \
-                       portage_node.operation == "nomerge"):
-                       portage_node = None
+                       running_portage = None
+
+               if replacement_portage:
+                       replacement_portage = replacement_portage[0]
+               else:
+                       replacement_portage = None
+
+               if replacement_portage == running_portage:
+                       replacement_portage = None
+
+               if running_portage is not None:
+                       try:
+                               portage_rdepend = self._select_atoms_highest_available(
+                                       running_root, running_portage.metadata["RDEPEND"],
+                                       myuse=running_portage.metadata["USE"].split(),
+                                       parent=running_portage, strict=False)
+                       except portage.exception.InvalidDependString, e:
+                               portage.writemsg("!!! Invalid RDEPEND in " + \
+                                       "'%svar/db/pkg/%s/RDEPEND': %s\n" % \
+                                       (running_root, running_portage.cpv, e), noiselevel=-1)
+                               del e
+                               portage_rdepend = []
+                       runtime_deps.update(atom for atom in portage_rdepend \
+                               if not atom.startswith("!"))
 
                ignore_priority_soft_range = [None]
                ignore_priority_soft_range.extend(
@@ -3609,7 +3644,8 @@ class depgraph(object):
                                                        return True
                                                if node not in mergeable_nodes:
                                                        return False
-                                               if node == portage_node and mygraph.child_nodes(node,
+                                               if node == replacement_portage and \
+                                                       mygraph.child_nodes(node,
                                                        ignore_priority=DepPriority.MEDIUM_SOFT):
                                                        # Make sure that portage always has all of it's
                                                        # RDEPENDs installed first.
@@ -3704,20 +3740,26 @@ class depgraph(object):
                                        if self.digraph.contains(inst_pkg):
                                                continue
 
-                                       if "/" == task.root:
+                                       if running_root == task.root:
                                                # Never uninstall sys-apps/portage or it's essential
                                                # dependencies, except through replacement.
-                                               if task.cp in portage_unslotted_deps:
+                                               try:
+                                                       runtime_dep_atoms = \
+                                                               list(runtime_deps.iterAtomsForPackage(task))
+                                               except portage.exception.InvalidDependString, e:
+                                                       portage.writemsg("!!! Invalid PROVIDE in " + \
+                                                               "'%svar/db/pkg/%s/PROVIDE': %s\n" % \
+                                                               (task.root, task.cpv, e), noiselevel=-1)
+                                                       del e
                                                        continue
 
-                                               # Don't uninstall python if it appears to be
-                                               # the only suitable one installed.
-                                               if task.cp == "dev-lang/python" and \
-                                                       portage.match_from_list(
-                                                       portage_python_dep, [task.cpv_slot]):
-                                                       vardb = root_config.trees["vartree"].dbapi
+                                               # Don't uninstall a runtime dep if it appears
+                                               # to be the only suitable one installed.
+                                               skip = False
+                                               vardb = root_config.trees["vartree"].dbapi
+                                               for atom in runtime_dep_atoms:
                                                        other_version = None
-                                                       for pkg in vardb.match_pkgs(portage_python_dep):
+                                                       for pkg in vardb.match_pkgs(atom):
                                                                if pkg.cpv == task.cpv and \
                                                                        pkg.metadata["COUNTER"] == \
                                                                        task.metadata["COUNTER"]:
@@ -3725,7 +3767,10 @@ class depgraph(object):
                                                                other_version = pkg
                                                                break
                                                        if other_version is None:
-                                                               continue
+                                                               skip = True
+                                                               break
+                                               if skip:
+                                                       continue
 
                                                # For packages in the system set, don't take
                                                # any chances. If the conflict can't be resolved
@@ -3736,7 +3781,11 @@ class depgraph(object):
                                                                "system"].iterAtomsForPackage(task):
                                                                skip = True
                                                                break
-                                               except portage.exception.InvalidDependString:
+                                               except portage.exception.InvalidDependString, e:
+                                                       portage.writemsg("!!! Invalid PROVIDE in " + \
+                                                               "'%svar/db/pkg/%s/PROVIDE': %s\n" % \
+                                                               (task.root, task.cpv, e), noiselevel=-1)
+                                                       del e
                                                        skip = True
                                                if skip:
                                                        continue
@@ -3765,7 +3814,11 @@ class depgraph(object):
                                                                if not satisfied:
                                                                        skip = True
                                                                        break
-                                               except portage.exception.InvalidDependString:
+                                               except portage.exception.InvalidDependString, e:
+                                                       portage.writemsg("!!! Invalid PROVIDE in " + \
+                                                               "'%svar/db/pkg/%s/PROVIDE': %s\n" % \
+                                                               (task.root, task.cpv, e), noiselevel=-1)
+                                                       del e
                                                        skip = True
                                                if skip:
                                                        continue
@@ -7862,7 +7915,7 @@ def action_build(settings, trees, mtimedb,
                        del mtimedb[k]
                        continue
                favorites = resume_data.get("favorites")
-               if not isinstance(resume_opts, list):
+               if not isinstance(favorites, list):
                        del mtimedb[k]
                        continue
 
@@ -8179,8 +8232,7 @@ def action_build(settings, trees, mtimedb,
                        retval = mergetask.merge(pkglist, favorites, mtimedb)
                        merge_count = mergetask.curval
 
-               if retval == os.EX_OK and not (pretend or fetchonly):
-                       mtimedb.pop("resume", None)
+               if retval == os.EX_OK and not (buildpkgonly or fetchonly or pretend):
                        if "yes" == settings.get("AUTOCLEAN"):
                                portage.writemsg_stdout(">>> Auto-cleaning packages...\n")
                                unmerge(trees[settings["ROOT"]]["root_config"],
index 22c026cbbe18aa62e5f7112bfaa5145232129c5b..765a2dbc0c6f212edac76f27a63ffe4975196c1d 100644 (file)
@@ -943,6 +943,11 @@ class config(object):
                "PORTAGE_GROUP", "PORTAGE_USER",
        ]
 
+       # user config variables
+       _environ_whitelist += [
+               "DOC_SYMLINKS_DIR", "INSTALL_MASK", "PKG_INSTALL_MASK"
+       ]
+
        _environ_whitelist += [
                "A", "AA", "CATEGORY", "P", "PF", "PN", "PR", "PV", "PVR"
        ]
index 8e9ccbc01c8b9cf41643cdb64133a763dccd2b88..c96037d975c0c05fc3ddf23b4bfc3de2e12b1612 100644 (file)
@@ -35,6 +35,7 @@ GLOBAL_CONFIG_PATH      = DATADIR+"/portage/config"
 PORTAGE_BASE_PATH       = PORTAGE_BASE
 PORTAGE_BIN_PATH        = PORTAGE_BASE_PATH+"/bin"
 PORTAGE_PYM_PATH        = PORTAGE_BASE_PATH+"/pym"
+PORTAGE_PACKAGE_ATOM    = "sys-apps/portage"
 NEWS_LIB_PATH           = EPREFIX+"/var/lib/gentoo"
 PROFILE_PATH            = EPREFIX+"/etc/make.profile"
 LOCALE_DATA_PATH        = PORTAGE_BASE_PATH+"/locale"
@@ -66,7 +67,8 @@ INCREMENTALS = ["USE", "USE_EXPAND", "USE_EXPAND_HIDDEN", "FEATURES",
        "CONFIG_PROTECT_MASK", "CONFIG_PROTECT",
        "PRELINK_PATH", "PRELINK_PATH_MASK", "PROFILE_ONLY_VARIABLES"]
 EBUILD_PHASES           = ["setup", "unpack", "compile", "test", "install",
-                          "preinst", "postinst", "prerm", "postrm", "other"]
+                          "package", "preinst", "postinst","prerm", "postrm",
+                          "other"]
 
 EAPI = 1
 
index a0f80282bda0859f97c41764139bc3fa9f56b641..b6158c054042c89196bff718fe19e63103456839 100644 (file)
@@ -9,7 +9,7 @@ from portage.data import portage_gid, portage_uid, secpass, ostype
 from portage.dbapi import dbapi
 from portage.dep import dep_getslot, use_reduce, paren_reduce, isvalidatom, \
        isjustname, dep_getkey, match_from_list
-from portage.exception import InvalidPackageName, InvalidAtom, \
+from portage.exception import InvalidAtom, InvalidData, InvalidPackageName, \
        FileNotFound, PermissionDenied, UnsupportedAPIException
 from portage.locks import lockdir, unlockdir
 from portage.output import bold, red, green
@@ -132,13 +132,16 @@ class LinkageMap(object):
                self._obj_properties = {}
                self._defpath = getlibpaths()
        
-       def rebuild(self):
+       def rebuild(self, include_file=None):
                libs = {}
                obj_properties = {}
                lines = []
                for cpv in self._dbapi.cpv_all():
                        lines += grabfile(self._dbapi.getpath(cpv, filename="NEEDED.ELF.2"))
-
+               
+               if include_file:
+                       lines += grabfile(include_file)
+               
                # have to call scanelf for preserved libs here as they aren't 
                # registered in NEEDED.ELF.2 files
                if self._dbapi.plib_registry and self._dbapi.plib_registry.getPreservedLibs():
@@ -187,10 +190,11 @@ class LinkageMap(object):
        def findProviders(self, obj):
                if not self._libs:
                        self.rebuild()
-               obj = os.path.realpath(obj)
                rValue = {}
                if obj not in self._obj_properties:
-                       raise KeyError("%s not in object list" % obj)
+                       obj = os.path.realpath(obj)
+                       if obj not in self._obj_properties:
+                               raise KeyError("%s not in object list" % obj)
                arch, needed, path, soname = self._obj_properties[obj]
                path.extend(self._defpath)
                path = [os.path.realpath(x) for x in path]
@@ -208,7 +212,10 @@ class LinkageMap(object):
        def findConsumers(self, obj):
                if not self._libs:
                        self.rebuild()
-               obj = os.path.realpath(obj)
+               if obj not in self._obj_properties:
+                       obj = os.path.realpath(obj)
+                       if obj not in self._obj_properties:
+                               raise KeyError("%s not in object list" % obj)
                rValue = set()
                for soname in self._libs:
                        for arch in self._libs[soname]:
@@ -307,6 +314,12 @@ class LinkageMapMachO(object):
                return rValue
                                        
 class vardbapi(dbapi):
+
+       _excluded_dirs = ["CVS", "lost+found"]
+       _excluded_dirs = [re.escape(x) for x in _excluded_dirs]
+       _excluded_dirs = re.compile(r'^(\..*|-MERGING-.*|' + \
+               "|".join(_excluded_dirs) + r')$')
+
        def __init__(self, root, categories=None, settings=None, vartree=None):
                """
                The categories parameter is unused since the dbapi class
@@ -507,10 +520,7 @@ class vardbapi(dbapi):
 
                returnme = []
                for x in dir_list:
-                       if x.startswith("."):
-                               continue
-                       if x[0] == '-':
-                               #writemsg(red("INCOMPLETE MERGE:")+str(x[len("-MERGING-"):])+"\n")
+                       if self._excluded_dirs.match(x) is not None:
                                continue
                        ps = pkgsplit(x)
                        if not ps:
@@ -530,15 +540,23 @@ class vardbapi(dbapi):
                returnme = []
                basepath = os.path.join(self.root, VDB_PATH) + os.path.sep
                for x in listdir(basepath, EmptyOnError=1, ignorecvs=1, dirsonly=1):
+                       if self._excluded_dirs.match(x) is not None:
+                               continue
                        if not self._category_re.match(x):
                                continue
-                       for y in listdir(basepath + x, EmptyOnError=1):
-                               if y.startswith("."):
+                       for y in listdir(basepath + x, EmptyOnError=1, dirsonly=1):
+                               if self._excluded_dirs.match(y) is not None:
                                        continue
                                subpath = x + "/" + y
                                # -MERGING- should never be a cpv, nor should files.
-                               if os.path.isdir(basepath + subpath) and (pkgsplit(y) is not None):
-                                       returnme += [subpath]
+                               try:
+                                       if catpkgsplit(subpath) is None:
+                                               self.invalidentry(os.path.join(self.root, subpath))
+                                               continue
+                               except portage.exception.InvalidData:
+                                       self.invalidentry(os.path.join(self.root, subpath))
+                                       continue
+                               returnme.append(subpath)
                return returnme
 
        def cp_all(self, use_cache=1):
@@ -547,7 +565,11 @@ class vardbapi(dbapi):
                for y in mylist:
                        if y[0] == '*':
                                y = y[1:]
-                       mysplit = catpkgsplit(y)
+                       try:
+                               mysplit = catpkgsplit(y)
+                       except portage.exception.InvalidData:
+                               self.invalidentry(self.getpath(y))
+                               continue
                        if not mysplit:
                                self.invalidentry(self.getpath(y))
                                continue
@@ -1732,10 +1754,10 @@ class dblink(object):
 
                return False
 
-       def _preserve_libs(self, srcroot, destroot, mycontents, counter):
+       def _preserve_libs(self, srcroot, destroot, mycontents, counter, inforoot):
                # read global reverse NEEDED map
                linkmap = self.vartree.dbapi.linkmap
-               linkmap.rebuild()
+               linkmap.rebuild(include_file=os.path.join(inforoot, "NEEDED.ELF.2"))
                liblist = linkmap.listLibraryObjects()
 
                # get list of libraries from old package instance
@@ -1743,12 +1765,13 @@ class dblink(object):
                old_libs = set(old_contents).intersection(liblist)
 
                # get list of libraries from new package instance
-               mylibs = set(mycontents).intersection(liblist)
-
+               mylibs = set([os.path.join(os.sep, x) for x in mycontents]).intersection(liblist)
+               
                # check which libs are present in the old, but not the new package instance
                candidates = old_libs.difference(mylibs)
+               
                for x in old_contents:
-                       if os.path.islink(x) and os.path.realpath(x) in candidates:
+                       if os.path.islink(x) and os.path.realpath(x) in candidates and x not in mycontents:
                                candidates.add(x)
 
                # ignore any libs that are only internally used by the package
@@ -1779,6 +1802,7 @@ class dblink(object):
                        for c in linkmap.findConsumers(lib):
                                localkeep = True
                                providers = linkmap.findProviders(c)
+                               
                                for soname in providers:
                                        if lib in providers[soname]:
                                                for p in providers[soname]:
@@ -2119,7 +2143,7 @@ class dblink(object):
 
                # Preserve old libs if they are still in use
                if slot_matches and "preserve-libs" in self.settings.features:
-                       self._preserve_libs(srcroot, destroot, myfilelist+mylinklist, counter)
+                       self._preserve_libs(srcroot, destroot, myfilelist+mylinklist, counter, inforoot)
 
                # check for package collisions
                collisions = self._collision_protect(srcroot, destroot, others_in_slot,