From: Fabian Groffen Date: Thu, 8 May 2008 19:14:22 +0000 (-0000) Subject: Merged from trunk 10182:10208 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=81ac1fafbdefb4dc3564139413c6483a294a5f5b;p=portage.git Merged from trunk 10182:10208 | 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 --- diff --git a/bin/isolated-functions.sh b/bin/isolated-functions.sh index 343d62657..ddb8e040e 100755 --- a/bin/isolated-functions.sh +++ b/bin/isolated-functions.sh @@ -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 ) diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index 0392af366..993de914e 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -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"], diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index 22c026cbb..765a2dbc0 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -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" ] diff --git a/pym/portage/const.py b/pym/portage/const.py index 8e9ccbc01..c96037d97 100644 --- a/pym/portage/const.py +++ b/pym/portage/const.py @@ -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 diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py index a0f80282b..b6158c054 100644 --- a/pym/portage/dbapi/vartree.py +++ b/pym/portage/dbapi/vartree.py @@ -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,