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
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
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 }
# 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]
# - 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
# 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
isn't stricly required, but it should always be used as the default
handler might be changed in future versions.</para></footnote>.
That option defines which handler class should be used to
- create the set. Another universal option available for single sets is
- <varname>name</varname>, however it's usually not needed as the name
+ create the set. Other universal options available for single sets are
+ <varname>name</varname> (which is usually not needed as the name
of the set is generated from the section name if <varname>name</varname>
- is missing. Some handler classes might require additional
- options for their configuration, these will be covered later in
- this chapter.
+ is missing) and <varname>world-candidate</varname>, which determines if
+ given package should be added to the <varname>world</varname> set. Some
+ handler classes might require additional options for their configuration,
+ these will be covered later in this chapter.
</para>
<para>
Here are a few examples for single sets taken from the default
# The classic world set
[world]
class = portage.sets.files.WorldSet
+ world-candidate = False
# The classic system set
[system]
sets each section still requires the <varname>class</varname> option,
but to indicate that the section should generate multiple sets it's
also necessary to set the <varname>multiset</varname> option to
- <parameter>true</parameter>.
+ <parameter>true</parameter>. The <varname>world-candidate</varname>
+ option is also supported like with single sets.
</para>
<para>
As it doesn't make much sense to specify a single name for multiple sets
<itemizedlist>
<listitem><varname>filename</varname>: Required. Specifies the path to the file
that should be used for the package set.</listitem>
+ <listitem><varname>greedy</varname>: Optional, defaults to <parameter>false</parameter>.
+ Determines if atoms in the package should include all installed slots (when set to
+ <parameter>true</parameter>) or if no slot expansion is wanted (when set to
+ <parameter>false</parameter>). This option only affects packages that have multiple
+ slots available (e.g. <parameter>sys-kernel/gentoo-sources</parameter>).</listitem>
</itemizedlist>
</para>
</sect3>
that location a separate package set is created.
</listitem>
<listitem><varname>name_pattern</varname>: Optional, defaults to
- <parameter>sets/$name</parameter>. This describes the naming pattern
+ <parameter>$name</parameter>. This describes the naming pattern
to be used for creating the sets. It must contain either
<parameter>$name</parameter> or <parameter>${name}</parameter>, which
will be replaced by the filename (without any directory components).
No other files in that directory will be used.
</listitem>
<listitem><varname>name_pattern</varname>: Optional, defaults to
- <parameter>sets/package_$suffix</parameter>. This describes the naming
+ <parameter>package_$suffix</parameter>. This describes the naming
pattern to be used for creating the sets. It must contain either
<parameter>$suffix</parameter> or <parameter>${suffix}</parameter>,
which will be replaced by the file suffix (e.g.
<sect3>
<title>Single Set Configuraton</title>
<para>
- This class does not support any options.
+ This class doesn't support any extra options.
</para>
</sect3>
</sect2>
<sect3>
<title>Single Set Configuration</title>
<para>
- This class does not support any options.
+ This class doesn't support any extra options.
</para>
</sect3>
</sect2>
<sect3>
<title>Single Set Configuration</title>
<para>
- This class does not support any options.
+ This class doesn't support any extra options.
+ </para>
+ </sect3>
+ </sect2>
+ <sect2 id='config-set-classes-PreservedLibraryConsumerSet'>
+ <title>portage.sets.libs.PreservedLibraryConsumerSet</title>
+ <para>
+ A special set used to rebuild all packages that need a preserved library that only
+ remains due to <varname>FEATURES="preserve-libs"</varname>.
+ </para>
+
+ <sect3>
+ <title>Single Set Configuration</title>
+ <para>
+ This class supports the following option:
+ <itemizedlist>
+ <listitem><varname>debug</varname>: Generate extra output useful to figure out why
+ certain packages are included in the set, as it's not always obvious.
+ </listitem>
+ </itemizedlist>
</para>
</sect3>
</sect2>
<listitem><varname>world</varname>: uses <classname>WorldSet</classname></listitem>
<listitem><varname>security</varname>: uses <classname>NewAffectedSet</classname> with default options</listitem>
<listitem><varname>everything</varname>: uses <classname>EverythingSet</classname></listitem>
+ <listitem><varname>preserved-rebuild</varname>: uses <classname>PreservedLibraryConsumerSet</classname></listitem>
</itemizedlist>
Additionally the default configuration includes a multi set section based on
the <classname>StaticFileSet</classname> defaults that creates a set for each
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
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),
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:
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
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):
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)
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:
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:
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)
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"))
# 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:
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:
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:
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
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)
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"] = \
self.settings = settings
self._parsed = False
self.active = []
- self.aliases = {}
def _parse(self):
if self._parsed:
# 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
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
self._loading = False
self.errors = []
self._nonatoms = set()
+ self.world_candidate = True
def __contains__(self, atom):
self._load()
def remove(self, atom):
self._load()
self._atoms.discard(atom)
+ self._nonatoms.discard(atom)
self._updateAtomMap()
self.write()
# 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"]
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)
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)
--- /dev/null
+# 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)