From d793cd26f00ebcde7049ed1cbf34400e8ea234eb Mon Sep 17 00:00:00 2001 From: Fabian Groffen Date: Fri, 2 May 2008 14:40:49 +0000 Subject: [PATCH] Merged from trunk 10069:10086 | 10070 | Skip group/owner tarsync options for tarsync if chown on | | zmedico | /usr/portage fails, since the user might still be able to | | | sync even though the chown call is not permitted. | | 10072 | Fix broken variable references found by pyflakes. | | zmedico | | | 10073 | remove 'sets/' name-prefix for file-based package sets | | genone | | | 10075 | check if a given package set is defined more than once | | genone | | | 10077 | add config option for package sets to not be recorded in | | genone | 'world' | | 10078 | properly remove sets from 'world' when unmerging | | genone | | | 10079 | move cleaning of sets out of package loop | | genone | | | 10080 | do not consider sets to be installed that are about to be | | genone | unmerged | | 10081 | v2 of FEATURES=preserved-libs, using LinkageMap instead of | | genone | the now removed LibraryPackageMap class | | 10082 | use special symlink comparison code (original patch from | | genone | prefix r9499) | | 10083 | fix typo | | genone | | | 10085 | rename NEEDED.2 to NEEDED.ELF.2 to allow other ABI formats | | genone | to use a different syntax | | 10086 | Update documentation for package set configuration. Original | | genone | patch by Arfrever Frehtes Taifersar Arahesis | svn path=/main/branches/prefix/; revision=10089 --- bin/emerge-webrsync | 5 +- bin/misc-functions.sh | 4 +- cnf/sets.conf | 8 +- doc/config/sets.docbook | 50 +++++++--- pym/_emerge/__init__.py | 13 ++- pym/portage/dbapi/vartree.py | 178 ++++++++++++++++++++++------------- pym/portage/sets/__init__.py | 16 +++- pym/portage/sets/base.py | 2 + pym/portage/sets/dbapi.py | 74 +-------------- pym/portage/sets/files.py | 2 +- pym/portage/sets/libs.py | 50 ++++++++++ 11 files changed, 240 insertions(+), 162 deletions(-) create mode 100644 pym/portage/sets/libs.py diff --git a/bin/emerge-webrsync b/bin/emerge-webrsync index 91a1375d6..5cc7fe80c 100755 --- a/bin/emerge-webrsync +++ b/bin/emerge-webrsync @@ -174,7 +174,10 @@ sync_local() { vecho "Syncing local tree ..." if type -P tarsync > /dev/null ; then - if ! tarsync $(vvecho -v) -s 1 -o portage -g portage -e /distfiles -e /packages -e /local "${file}" "${PORTDIR}"; then + local chown_opts="-o portage -g portage" + chown portage:portage portage > /dev/null 2>&1 || chown_opts="" + if ! tarsync $(vvecho -v) -s 1 ${chown_opts} \ + -e /distfiles -e /packages -e /local "${file}" "${PORTDIR}"; then eecho "tarsync failed; tarball is corrupt? (${file})" return 1 fi diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh index 58e773b28..b5988dbda 100644 --- a/bin/misc-functions.sh +++ b/bin/misc-functions.sh @@ -169,7 +169,7 @@ install_qa_check() { if [ -z "${rpath}" -o -n "${rpath//*ORIGIN*}" ]; then # object doesn't contain $ORIGIN in its runpath attribute echo "${obj} ${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED - echo "${arch:3};${obj};${soname};${rpath};${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.2 + echo "${arch:3};${obj};${soname};${rpath};${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2 else dir=$(dirname ${obj}) # replace $ORIGIN with the dirname of the current object for the lookup @@ -186,7 +186,7 @@ install_qa_check() { rneeded=${rneeded:1} if [ -n "${rneeded}" ]; then echo "${obj} ${rneeded}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED - echo "${arch:3};${obj};${soname};${rpath};${rneeded}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.2 + echo "${arch:3};${obj};${soname};${rpath};${rneeded}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2 fi fi done } diff --git a/cnf/sets.conf b/cnf/sets.conf index 46d7c769f..7d852cae5 100644 --- a/cnf/sets.conf +++ b/cnf/sets.conf @@ -7,6 +7,7 @@ # Not much that could be changed for world, so better leave it alone [world] class = portage.sets.files.WorldSet +world-candidate = False # Same as for world, though later portage versions might use a different class [system] @@ -21,13 +22,15 @@ class = portage.sets.profiles.PackagesSystemSet # - SecuritySet: include all GLSAs [security] class = portage.sets.security.NewAffectedSet +world-candidate = False # Again, not much to change here, though people might prefer a different name [everything] class = portage.sets.dbapi.EverythingSet +world-candidate = False # The following treats all files in /etc/portage/sets as a package set called -# 'sets/$filename'. +# '$filename'. [usersets] class = portage.sets.files.StaticFileSet multiset = true @@ -36,4 +39,5 @@ directory = @DOMAIN_PREFIX@/etc/portage/sets # Set to rebuild all packages that need a preserved lib that only remains due # to FEATURES=preserve-libs [preserved-rebuild] -class = portage.sets.dbapi.PreservedLibraryConsumerSet +class = portage.sets.libs.PreservedLibraryConsumerSet +world-candidate = False diff --git a/doc/config/sets.docbook b/doc/config/sets.docbook index c7fc37c21..40274a426 100644 --- a/doc/config/sets.docbook +++ b/doc/config/sets.docbook @@ -49,12 +49,13 @@ isn't stricly required, but it should always be used as the default handler might be changed in future versions.. That option defines which handler class should be used to - create the set. Another universal option available for single sets is - name, however it's usually not needed as the name + create the set. Other universal options available for single sets are + name (which is usually not needed as the name of the set is generated from the section name if name - is missing. Some handler classes might require additional - options for their configuration, these will be covered later in - this chapter. + is missing) and world-candidate, which determines if + given package should be added to the world set. Some + handler classes might require additional options for their configuration, + these will be covered later in this chapter. Here are a few examples for single sets taken from the default @@ -63,6 +64,7 @@ # The classic world set [world] class = portage.sets.files.WorldSet + world-candidate = False # The classic system set [system] @@ -81,7 +83,8 @@ sets each section still requires the class option, but to indicate that the section should generate multiple sets it's also necessary to set the multiset option to - true. + true. The world-candidate + option is also supported like with single sets. As it doesn't make much sense to specify a single name for multiple sets @@ -157,6 +160,11 @@ filename: Required. Specifies the path to the file that should be used for the package set. + greedy: Optional, defaults to false. + Determines if atoms in the package should include all installed slots (when set to + true) or if no slot expansion is wanted (when set to + false). This option only affects packages that have multiple + slots available (e.g. sys-kernel/gentoo-sources). @@ -172,7 +180,7 @@ that location a separate package set is created. name_pattern: Optional, defaults to - sets/$name. This describes the naming pattern + $name. This describes the naming pattern to be used for creating the sets. It must contain either $name or ${name}, which will be replaced by the filename (without any directory components). @@ -218,7 +226,7 @@ No other files in that directory will be used. name_pattern: Optional, defaults to - sets/package_$suffix. This describes the naming + package_$suffix. This describes the naming pattern to be used for creating the sets. It must contain either $suffix or ${suffix}, which will be replaced by the file suffix (e.g. @@ -240,7 +248,7 @@ Single Set Configuraton - This class does not support any options. + This class doesn't support any extra options. @@ -258,7 +266,7 @@ Single Set Configuration - This class does not support any options. + This class doesn't support any extra options. @@ -441,7 +449,26 @@ Single Set Configuration - This class does not support any options. + This class doesn't support any extra options. + + + + + portage.sets.libs.PreservedLibraryConsumerSet + + A special set used to rebuild all packages that need a preserved library that only + remains due to FEATURES="preserve-libs". + + + + Single Set Configuration + + This class supports the following option: + + debug: Generate extra output useful to figure out why + certain packages are included in the set, as it's not always obvious. + + @@ -462,6 +489,7 @@ world: uses WorldSet security: uses NewAffectedSet with default options everything: uses EverythingSet + preserved-rebuild: uses PreservedLibraryConsumerSet Additionally the default configuration includes a multi set section based on the StaticFileSet defaults that creates a set for each diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index 77281f3fc..69df7da4a 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -3207,7 +3207,7 @@ class depgraph(object): blockers is not None: # Re-use the blockers from the graph. blocker_atoms = sorted(blockers) - counter = long(node.metadata["COUNTER"]) + counter = long(pkg.metadata["COUNTER"]) blocker_data = \ blocker_cache.BlockerData(counter, blocker_atoms) blocker_cache[pkg.cpv] = blocker_data @@ -4238,9 +4238,7 @@ class depgraph(object): counters.newslot += 1 if "--changelog" in self.myopts: - slot_atom = "%s:%s" % (portage.dep_getkey(pkg_key), - mydbapi.aux_get(pkg_key, ["SLOT"])[0]) - inst_matches = vardb.match(slot_atom) + inst_matches = vardb.match(pkg.slot_atom) if inst_matches: changelogs.extend(self.calc_changelog( portdb.findname(pkg_key), @@ -4770,7 +4768,7 @@ class depgraph(object): del e all_added = [] for k in self._sets: - if k in ("args", "world"): + if k in ("args", "world") or not root_config.sets[k].world_candidate: continue s = SETPREFIX + k if s in world_set: @@ -5889,6 +5887,7 @@ def unmerge(root_config, myopts, unmerge_action, if candidates: stop = False installed_sets += candidates + installed_sets = [x for x in installed_sets if x not in root_config.setconfig.active] del stop, pos # we don't want to unmerge packages that are still listed in user-editable package sets @@ -6029,6 +6028,9 @@ def unmerge(root_config, myopts, unmerge_action, if clean_world: sets["world"].cleanPackage(vartree.dbapi, y) emergelog(xterm_titles, " >>> unmerge success: "+y) + if clean_world: + for s in root_config.setconfig.active: + sets["world"].remove(SETPREFIX+s) return 1 def chk_updated_info_files(root, infodirs, prev_mtimes, retval): @@ -7959,6 +7961,7 @@ def action_build(settings, trees, mtimedb, portage.writemsg_stdout(colorize("WARN", "WARNING:") + " AUTOCLEAN is disabled. This can cause serious" + " problems due to overlapping packages.\n") + trees[settings["ROOT"]]["vartree"].dbapi.plib_registry.pruneNonExisting() if merge_count and not (buildpkgonly or fetchonly or pretend): post_emerge(trees, mtimedb, retval) diff --git a/pym/portage/dbapi/vartree.py b/pym/portage/dbapi/vartree.py index 3e941d541..0aaa158ad 100644 --- a/pym/portage/dbapi/vartree.py +++ b/pym/portage/dbapi/vartree.py @@ -27,7 +27,7 @@ from portage.elog import elog_process from portage.elog.messages import ewarn from portage.elog.filtering import filter_mergephases, filter_unmergephases -import os, re, sys, stat, errno, commands, copy, time +import os, re, sys, stat, errno, commands, copy, time, subprocess from itertools import izip try: @@ -135,38 +135,63 @@ class LinkageMap(object): def rebuild(self): libs = {} obj_properties = {} + lines = [] for cpv in self._dbapi.cpv_all(): - lines = grabfile(self._dbapi.getpath(cpv, filename="NEEDED.2")) - for l in lines: - fields = l.strip("\n").split(";") - if len(fields) < 5: - print "Error", fields - # insufficient field length - continue - arch = fields[0] - obj = fields[1] - soname = fields[2] - path = fields[3].replace("${ORIGIN}", os.path.dirname(obj)).replace("$ORIGIN", os.path.dirname(obj)).split(":") - needed = fields[4].split(",") - if soname: - libs.setdefault(soname, {arch: {"providers": [], "consumers": []}}) - libs[soname].setdefault(arch, {"providers": [], "consumers": []}) - libs[soname][arch]["providers"].append(obj) - for x in needed: - libs.setdefault(x, {arch: {"providers": [], "consumers": []}}) - libs[x].setdefault(arch, {"providers": [], "consumers": []}) - libs[x][arch]["consumers"].append(obj) - obj_properties[obj] = (arch, path, needed, soname) + lines += grabfile(self._dbapi.getpath(cpv, filename="NEEDED.ELF.2")) + + # 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(): + args = ["/usr/bin/scanelf", "-yqF", "%a;%F;%S;%r;%n"] + for items in self._dbapi.plib_registry.getPreservedLibs().values(): + args += items + proc = subprocess.Popen(args, stdout=subprocess.PIPE) + output = [l[3:] for l in proc.communicate()[0].split("\n")] + lines += output + + for l in lines: + if l.strip() == "": + continue + fields = l.strip("\n").split(";") + if len(fields) < 5: + print "Error", fields + # insufficient field length + continue + arch = fields[0] + obj = os.path.realpath(fields[1]) + soname = fields[2] + path = fields[3].replace("${ORIGIN}", os.path.dirname(obj)).replace("$ORIGIN", os.path.dirname(obj)).split(":") + needed = fields[4].split(",") + if soname: + libs.setdefault(soname, {arch: {"providers": [], "consumers": []}}) + libs[soname].setdefault(arch, {"providers": [], "consumers": []}) + libs[soname][arch]["providers"].append(obj) + for x in needed: + libs.setdefault(x, {arch: {"providers": [], "consumers": []}}) + libs[x].setdefault(arch, {"providers": [], "consumers": []}) + libs[x][arch]["consumers"].append(obj) + obj_properties[obj] = (arch, needed, path, soname) self._libs = libs self._obj_properties = obj_properties + + def listLibraryObjects(self): + rValue = [] + if not self._libs: + self.rebuild() + for soname in self._libs: + for arch in self._libs[soname]: + rValue.extend(self._libs[soname][arch]["providers"]) + return rValue 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) - arch, path, needed, soname = self._obj_properties[obj] + arch, needed, path, soname = self._obj_properties[obj] path.extend(self._defpath) path = [os.path.realpath(x) for x in path] for x in needed: @@ -181,13 +206,15 @@ class LinkageMap(object): return rValue def findConsumers(self, obj): + if not self._libs: + self.rebuild() obj = os.path.realpath(obj) rValue = set() for soname in self._libs: for arch in self._libs[soname]: if obj in self._libs[soname][arch]["providers"]: for x in self._libs[soname][arch]["consumers"]: - path = self._obj_properties[x][1] + path = self._obj_properties[x][2] path = [os.path.realpath(y) for y in path+self._defpath] if soname[0] == os.sep and os.path.realpath(soname) == os.path.realpath(obj): rValue.add(x) @@ -293,7 +320,6 @@ class vardbapi(dbapi): self._counter_path = os.path.join(root, CACHE_PATH.lstrip(os.path.sep), "counter") - self.libmap = LibraryPackageMap(os.path.join(self.root, CACHE_PATH.lstrip(os.sep), "library_consumers"), self) try: self.plib_registry = PreservedLibsRegistry( os.path.join(self.root, PRIVATE_PATH, "preserved_libs_registry")) @@ -301,6 +327,8 @@ class vardbapi(dbapi): # apparently this user isn't allowed to access PRIVATE_PATH self.plib_registry = None + self.linkmap = LinkageMap(self) + def getpath(self, mykey, filename=None): rValue = os.path.join(self.root, VDB_PATH, mykey) if filename != None: @@ -1271,31 +1299,35 @@ class dblink(object): return retval # regenerate reverse NEEDED map - self.vartree.dbapi.libmap.update() + self.vartree.dbapi.linkmap.rebuild() # remove preserved libraries that don't have any consumers left # FIXME: this code is quite ugly and can likely be optimized in several ways plib_dict = plib_registry.getPreservedLibs() for cpv in plib_dict: - keeplist = [] plib_dict[cpv].sort() + # for the loop below to work correctly, we need all + # symlinks to come before the actual files, such that + # the recorded symlinks (sonames) will be resolved into + # their real target before the object is found not to be + # in the reverse NEEDED map + def symlink_compare(x, y): + if os.path.islink(x): + if os.path.islink(y): + return 0 + else: + return -1 + elif os.path.islink(y): + return 1 + else: + return 0 + + plib_dict[cpv].sort(symlink_compare) for f in plib_dict[cpv]: - if not os.path.exists(f) or os.path.realpath(f) in keeplist: + if not os.path.exists(f): continue unlink_list = [] - while os.path.islink(f): - if os.path.basename(f) in self.vartree.dbapi.libmap.get(): - unlink_list = [] - keeplist.append(os.path.realpath(f)) - break - else: - unlink_list.append(f) - # only follow symlinks if the target is also a preserved lib object - if os.readlink(f) in plib_dict[cpv]: - f = os.readlink(f) - else: - break - if not os.path.islink(f) and not os.path.basename(f) in self.vartree.dbapi.libmap.get(): + if not self.vartree.dbapi.linkmap.findConsumers(f): unlink_list.append(f) for obj in unlink_list: try: @@ -1682,22 +1714,27 @@ class dblink(object): def _preserve_libs(self, srcroot, destroot, mycontents, counter): # read global reverse NEEDED map - libmap = self.vartree.dbapi.libmap.get() + linkmap = self.vartree.dbapi.linkmap + linkmap.rebuild() + liblist = linkmap.listLibraryObjects() # get list of libraries from old package instance old_contents = self._installed_instance.getcontents().keys() - old_libs = set([os.path.basename(x) for x in old_contents]).intersection(libmap) + old_libs = set(old_contents).intersection(liblist) # get list of libraries from new package instance - mylibs = set([os.path.basename(x) for x in mycontents]).intersection(libmap) + mylibs = set(mycontents).intersection(liblist) # check which libs are present in the old, but not the new package instance - preserve_libs = old_libs.difference(mylibs) + candidates = old_libs.difference(mylibs) + for x in old_contents: + if os.path.islink(x) and os.path.realpath(x) in candidates: + candidates.add(x) # ignore any libs that are only internally used by the package def has_external_consumers(lib, contents, otherlibs): - consumers = set(libmap[lib]) - contents_without_libs = [x for x in contents if not os.path.basename(x) in otherlibs] + consumers = linkmap.findConsumers(lib) + contents_without_libs = [x for x in contents if x not in otherlibs] # just used by objects that will be autocleaned if len(consumers.difference(contents_without_libs)) == 0: @@ -1714,23 +1751,34 @@ class dblink(object): else: return True - for lib in list(preserve_libs): - if not has_external_consumers(lib, old_contents, preserve_libs): - preserve_libs.remove(lib) - # only preserve the lib if there is no other copy in the search path - for path in getlibpaths(): - fullname = os.path.join(path, lib) - if fullname not in old_contents and os.path.exists(fullname) and lib in preserve_libs: - preserve_libs.remove(lib) - - # get the real paths for the libs - preserve_paths = [x for x in old_contents if os.path.basename(x) in preserve_libs] - del old_contents, old_libs, mylibs, preserve_libs - + for lib in list(candidates): + if not has_external_consumers(lib, old_contents, candidates): + candidates.remove(lib) + # only preserve the lib if there is no other copy to use for each consumer + keep = False + 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]: + if p not in candidates: + localkeep = False + break + break + if localkeep: + keep = True + + del mylibs, mycontents, old_contents, liblist + # inject files that should be preserved into our image dir import shutil missing_paths = [] - for x in preserve_paths: + for x in candidates: + # skip existing files so the 'new' libs aren't overwritten + if os.path.exists(os.path.join(srcroot, x.lstrip(os.sep))): + missing_paths.append(x) + continue print "injecting %s into %s" % (x, srcroot) if not os.path.exists(os.path.join(destroot, x.lstrip(os.sep))): print "%s does not exist so can't be preserved" % x @@ -1748,14 +1796,14 @@ class dblink(object): os.symlink(linktarget, os.path.join(srcroot, x.lstrip(os.sep))) if linktarget[0] != os.sep: linktarget = os.path.join(os.path.dirname(x), linktarget) - preserve_paths.append(linktarget) + candidates.add(linktarget) else: shutil.copy2(os.path.join(destroot, x.lstrip(os.sep)), os.path.join(srcroot, x.lstrip(os.sep))) - preserve_paths = [x for x in preserve_paths if x not in missing_paths] + preserve_paths = [x for x in candidates if x not in missing_paths] - del missing_paths + del missing_paths, candidates # keep track of the libs we preserved self.vartree.dbapi.plib_registry.register(self.mycpv, self.settings["SLOT"], counter, preserve_paths) @@ -2293,7 +2341,7 @@ class dblink(object): del conf_mem_file # regenerate reverse NEEDED map - self.vartree.dbapi.libmap.update() + self.vartree.dbapi.linkmap.rebuild() #do postinst script self.settings["PORTAGE_UPDATE_ENV"] = \ diff --git a/pym/portage/sets/__init__.py b/pym/portage/sets/__init__.py index 476aea4ca..d688164b5 100644 --- a/pym/portage/sets/__init__.py +++ b/pym/portage/sets/__init__.py @@ -32,7 +32,6 @@ class SetConfig(SafeConfigParser): self.settings = settings self._parsed = False self.active = [] - self.aliases = {} def _parse(self): if self._parsed: @@ -58,11 +57,19 @@ class SetConfig(SafeConfigParser): # create single or multiple instances of the given class depending on configuration if self.has_option(sname, "multiset") and self.getboolean(sname, "multiset"): if hasattr(setclass, "multiBuilder"): + newsets = {} try: - self.psets.update(setclass.multiBuilder(optdict, self.settings, self.trees)) + newsets = setclass.multiBuilder(optdict, self.settings, self.trees) except SetConfigError, e: self.errors.append("Configuration error in section '%s': %s" % (sname, str(e))) continue + for x in newsets: + if x in self.psets: + self.errors.append("Redefinition of set '%s' (sections: '%s', '%s')" % (setname, self.psets[setname].creator, sname)) + newsets[x].creator = sname + if self.has_option(sname, "world-candidate") and not self.getboolean(sname, "world-candidate"): + newsets[x].world_candidate = False + self.psets.update(newsets) else: self.errors.append("Section '%s' is configured as multiset, but '%s' doesn't support that configuration" % (sname, classname)) continue @@ -71,9 +78,14 @@ class SetConfig(SafeConfigParser): setname = self.get(sname, "name") except NoOptionError: setname = sname + if setname in self.psets: + self.errors.append("Redefinition of set '%s' (sections: '%s', '%s')" % (setname, self.psets[setname].creator, sname)) if hasattr(setclass, "singleBuilder"): try: self.psets[setname] = setclass.singleBuilder(optdict, self.settings, self.trees) + self.psets[setname].creator = sname + if self.has_option(sname, "world-candidate") and not self.getboolean(sname, "world-candidate"): + self.psets[setname].world_candidate = False except SetConfigError, e: self.errors.append("Configuration error in section '%s': %s" % (sname, str(e))) continue diff --git a/pym/portage/sets/base.py b/pym/portage/sets/base.py index 50702cff3..71547813e 100644 --- a/pym/portage/sets/base.py +++ b/pym/portage/sets/base.py @@ -24,6 +24,7 @@ class PackageSet(object): self._loading = False self.errors = [] self._nonatoms = set() + self.world_candidate = True def __contains__(self, atom): self._load() @@ -182,6 +183,7 @@ class EditablePackageSet(PackageSet): def remove(self, atom): self._load() self._atoms.discard(atom) + self._nonatoms.discard(atom) self._updateAtomMap() self.write() diff --git a/pym/portage/sets/dbapi.py b/pym/portage/sets/dbapi.py index c4f974aa9..fca742552 100644 --- a/pym/portage/sets/dbapi.py +++ b/pym/portage/sets/dbapi.py @@ -2,13 +2,9 @@ # Distributed under the terms of the GNU General Public License v2 # $Id$ -from portage.versions import catsplit, catpkgsplit +from portage.versions import catsplit from portage.sets.base import PackageSet from portage.sets import SetConfigError, get_boolean -from portage.dbapi.vartree import dblink -from portage.util import grabfile - -import os __all__ = ["CategorySet", "EverythingSet"] @@ -108,71 +104,3 @@ class CategorySet(PackageSet): return rValue multiBuilder = classmethod(multiBuilder) -class LibraryConsumerSet(PackageSet): - _operations = ["merge", "unmerge"] - - def __init__(self, vardbapi, debug=False): - super(LibraryConsumerSet, self).__init__() - self.dbapi = vardbapi - self.debug = debug - - def mapPathsToAtoms(self, paths): - rValue = set() - for cpv in self.dbapi.cpv_all(): - mysplit = catsplit(cpv) - link = dblink(mysplit[0], mysplit[1], myroot=self.dbapi.root, \ - mysettings=self.dbapi.settings, treetype='vartree', \ - vartree=self.dbapi.vartree) - if paths.intersection(link.getcontents()): - cat, pn = catpkgsplit(cpv)[:2] - slot = self.dbapi.aux_get(cpv, ["SLOT"])[0] - rValue.add("%s/%s:%s" % (cat, pn, slot)) - return rValue - - -class PreservedLibraryConsumerSet(LibraryConsumerSet): - def load(self): - reg = self.dbapi.plib_registry - libmap = self.dbapi.libmap.get() - consumers = set() - if reg: - for libs in reg.getPreservedLibs().values(): - for lib in libs: - paths = libmap.get(os.path.basename(lib), []) - consumers.update(paths) - else: - return - if not consumers: - return - self._setAtoms(self.mapPathsToAtoms(consumers)) - - def singleBuilder(cls, options, settings, trees): - return PreservedLibraryConsumerSet(trees["vartree"].dbapi) - singleBuilder = classmethod(singleBuilder) - -class MissingLibraryConsumerSet(LibraryConsumerSet): - _operations = ["merge", "unmerge"] - - def load(self): - atoms = set() - consumers = set() - for lib in self.dbapi.libmap.get(): - found=False - for searchdir in grabfile(os.path.join(os.sep, self.dbapi.root, "etc/ld.so.conf")): - if os.path.exists(os.path.join(searchdir, lib)): - found=True - break - if not found: - print "missing library: %s" % lib - print "consumers:" - for x in self.dbapi.libmap.get()[lib]: - print " ", x - consumers.update(self.dbapi.libmap.get()[lib]) - if not consumers: - return - self._setAtoms(self.mapPathsToAtoms(consumers)) - - def singleBuilder(cls, options, settings, trees): - debug = get_boolean(options, "debug", False) - return MissingLibraryConsumerSet(trees["vartree"].dbapi, debug=debug) - singleBuilder = classmethod(singleBuilder) diff --git a/pym/portage/sets/files.py b/pym/portage/sets/files.py index cfc594ffb..7ed29e2ec 100644 --- a/pym/portage/sets/files.py +++ b/pym/portage/sets/files.py @@ -107,7 +107,7 @@ class StaticFileSet(EditablePackageSet): def multiBuilder(self, options, settings, trees): rValue = {} directory = options.get("directory", os.path.join(settings["PORTAGE_CONFIGROOT"], USER_CONFIG_PATH.lstrip(os.sep), "sets")) - name_pattern = options.get("name_pattern", "sets/${name}") + name_pattern = options.get("name_pattern", "${name}") if not "$name" in name_pattern and not "${name}" in name_pattern: raise SetConfigError("name_pattern doesn't include ${name} placeholder") greedy = get_boolean(options, "greedy", False) diff --git a/pym/portage/sets/libs.py b/pym/portage/sets/libs.py new file mode 100644 index 000000000..4ab8a33fe --- /dev/null +++ b/pym/portage/sets/libs.py @@ -0,0 +1,50 @@ +# Copyright 2007 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Id$ + +from portage.sets.base import PackageSet +from portage.dbapi.vartree import dblink +from portage.versions import catsplit, catpkgsplit + +import os + +class LibraryConsumerSet(PackageSet): + _operations = ["merge", "unmerge"] + + def __init__(self, vardbapi, debug=False): + super(LibraryConsumerSet, self).__init__() + self.dbapi = vardbapi + self.debug = debug + + def mapPathsToAtoms(self, paths): + rValue = set() + for cpv in self.dbapi.cpv_all(): + mysplit = catsplit(cpv) + link = dblink(mysplit[0], mysplit[1], myroot=self.dbapi.root, \ + mysettings=self.dbapi.settings, treetype='vartree', \ + vartree=self.dbapi.vartree) + if paths.intersection(link.getcontents()): + cat, pn = catpkgsplit(cpv)[:2] + slot = self.dbapi.aux_get(cpv, ["SLOT"])[0] + rValue.add("%s/%s:%s" % (cat, pn, slot)) + return rValue + + +class PreservedLibraryConsumerSet(LibraryConsumerSet): + def load(self): + reg = self.dbapi.plib_registry + consumers = set() + if reg: + for libs in reg.getPreservedLibs().values(): + for lib in libs: + #print lib, self.dbapi.linkmap.findConsumers(lib) + consumers.update(self.dbapi.linkmap.findConsumers(lib)) + else: + return + if not consumers: + return + self._setAtoms(self.mapPathsToAtoms(consumers)) + + def singleBuilder(cls, options, settings, trees): + return PreservedLibraryConsumerSet(trees["vartree"].dbapi) + singleBuilder = classmethod(singleBuilder) -- 2.26.2