public inbox for gentoo-portage-dev@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-portage-dev] [PATCH] missing-rebuild package set
@ 2008-08-03 14:03 Lucian Poston
  2008-08-08 22:10 ` Zac Medico
  0 siblings, 1 reply; 4+ messages in thread
From: Lucian Poston @ 2008-08-03 14:03 UTC (permalink / raw
  To: gentoo-portage-dev

[-- Attachment #1: Type: text/plain, Size: 1641 bytes --]

The following patchs add a library dependency rebuilder as a package
set, @missing-rebuild, to portage-2.2_rc6.  Similar to the --library
flag in revdep-rebuild, the user can additionally emerge the set of
packages containing consumers of libraries matched by a (python)
regular expression; however, until a better solution is found, the
regexp must be passed through the LIBRARY environment variable to
enable that feature.

Known issues: I expect some false positives. I've inserted hard coded
directory/library masks for those I've found. I noticed a situation
that required a second emerge due to a provider package satisfying 3
conditions: 1) the package is installed and an updated version is
available in its slot, 2) the updated version is in the set due to a
dependency of another package (or it may contains a broken binary),
and 3) a consumer package of a library within the updated package is
emerged before the updated dependency is emerged, causing a package to
be compiled against the old library before the library version
changes.  I guess that if a package is already installed, it is not
necessarily placed before its consumer packages in the merge order.

Attached are patches for pym/portage/dbapi/vartree.py,
pym/portage/sets/libs.py and /usr/share/portage/config/sets.conf.
These can also be found in the project's repository:
http://repo.or.cz/w/revdep-rebuild-reimplementation.git?a=tree;h=refs/heads/rc1;hb=refs/heads/rc1

I warmly welcome all feedback, in particular any suggestions to remove
the necessity of directory and library masks in /etc/revdep-rebuild/*,
which I've been unable to entirely avoid.

Lucian

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: sets.conf.2.2_rc6.patch --]
[-- Type: text/x-patch; name=sets.conf.2.2_rc6.patch, Size: 364 bytes --]

--- /usr/share/portage/config/sets.conf	2008-08-01 15:37:18.000000000 -0500
+++ sets.conf	2008-08-03 06:38:41.000000000 -0500
@@ -59,3 +59,8 @@
 [downgrade]
 class = portage.sets.dbapi.DowngradeSet
 world-candidate = False
+
+# Packages to rebuild broken library dependencies.
+[missing-rebuild]
+class = portage.sets.libs.MissingLibraryConsumerSet
+debug = False

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: libs.py.2.2_rc6.patch --]
[-- Type: text/x-patch; name=libs.py.2.2_rc6.patch, Size: 11541 bytes --]

--- libs.py.2.2_rc6	2008-08-01 15:41:14.000000000 -0500
+++ pym/portage/sets/libs.py	2008-08-03 07:16:00.000000000 -0500
@@ -2,10 +2,18 @@
 # Distributed under the terms of the GNU General Public License v2
 # $Id: libs.py 10759 2008-06-22 04:04:50Z zmedico $
 
+import os
+import re
+import time
+from portage.dbapi.vartree import dblink
+from portage.versions import catsplit
 from portage.sets.base import PackageSet
 from portage.sets import get_boolean
 from portage.versions import catpkgsplit
 
+__all__ = ["LibraryConsumerSet", "PreservedLibraryConsumerSet",
+		"MissingLibraryConsumerSet"]
+
 class LibraryConsumerSet(PackageSet):
 	_operations = ["merge", "unmerge"]
 
@@ -45,3 +53,310 @@
 		debug = get_boolean(options, "debug", False)
 		return PreservedLibraryConsumerSet(trees["vartree"].dbapi, debug)
 	singleBuilder = classmethod(singleBuilder)
+
+
+class MissingLibraryConsumerSet(LibraryConsumerSet):
+
+	"""
+	This class is the set of packages to emerge due to missing libraries.
+
+	This class scans binaries for missing and broken shared library dependencies
+	and fixes them by emerging the packages containing the broken binaries.
+
+	The user may also emerge packages containing consumers of specified
+	libraries by passing the name or a python regular expression through the
+	environment variable, LIBRARY.  Due to a limitation in passing flags to
+	package sets through the portage cli, the user must set environment
+	variables to modify the behaviour of this package set.  So if the
+	environment variable LIBRARY is set, the behaviour of this set changes.
+
+	"""
+
+	description = "The set of packages to emerge due to missing libraries."
+	_operations = ["merge"]
+
+	def __init__(self, vardbapi, debug=False):
+		super(MissingLibraryConsumerSet, self).__init__(vardbapi, debug)
+		# FIXME Since we can't get command line arguments from the user, the
+		# soname can be passed through an environment variable for now.
+		self.libraryRegexp = os.getenv("LIBRARY")
+		self.root = self.dbapi.root
+		self.linkmap = self.dbapi.linkmap
+
+	def load(self):
+		# brokenDependencies: object -> set-of-unsatisfied-dependencies, where
+		# object is an installed binary/library and
+		# set-of-unsatisfied-dependencies are sonames or libraries required by
+		# the object but have no corresponding libraries to fulfill the
+		# dependency.
+		brokenDependencies = {}
+		atoms = set()
+
+		# If the LIBRARY environment variable is set, the resulting package set
+		# will be packages containing consumers of the libraries matched by the
+		# variable.
+		if self.libraryRegexp:
+			atoms = self.findAtomsOfLibraryConsumers(self.libraryRegexp)
+			self._setAtoms(atoms)
+			if self.debug:
+				print
+				print "atoms to be emerged:"
+				for x in sorted(atoms):
+					print x
+			return
+
+		# Get the list of broken dependencies from LinkageMap.
+		if self.debug:
+			timeStart = time.time()
+		brokenDependencies = self.linkmap.listBrokenBinaries()
+		if self.debug:
+			timeListBrokenBinaries = time.time() - timeStart
+
+		# Add broken libtool libraries into the brokenDependencies dict.
+		if self.debug:
+			timeStart = time.time()
+		brokenDependencies.update(self.listBrokenLibtoolLibraries())
+		if self.debug:
+			timeLibtool = time.time() - timeStart
+
+		# FIXME Too many atoms may be emerged because libraries in binary
+		# packages are not being handled properly eg openoffice, nvidia-drivers,
+		# sun-jdk.  Certain binaries are run in an environment where additional
+		# library paths are added via LD_LIBRARY_PATH.  Since these paths aren't
+		# registered in _obj_properties, they appear broken (and are if not run
+		# in the correct environment).  I have to determine if libraries and lib
+		# paths should be masked using /etc/revdep-rebuild/* as done in
+		# revdep-rebuild or if there is a better way to identify and deal with
+		# these problematic packages (or if something entirely different should
+		# be done).  For now directory and library masks are used.
+
+		# Remove masked directories and libraries.
+		if self.debug:
+			timeStart = time.time()
+		if brokenDependencies:
+			brokenDependencies = self.removeMaskedDependencies(brokenDependencies)
+		if self.debug:
+			timeMask = time.time() - timeStart
+
+		# Determine atoms to emerge based on broken objects in
+		# brokenDependencies.
+		if self.debug:
+			timeStart = time.time()
+		if brokenDependencies:
+			atoms = self.mapPathsToAtoms(set(brokenDependencies.keys()))
+		if self.debug:
+			timeAtoms = time.time() - timeStart
+
+		# Debug output
+		if self.debug:
+			print
+			print len(brokenDependencies), "brokenDependencies:"
+			for x in sorted(brokenDependencies.keys()):
+				print
+				print x, "->"
+				print '\t', brokenDependencies[x]
+			print
+			print "atoms to be emerged:"
+			for x in sorted(atoms):
+				print x
+			print
+			print "Broken binaries time:", timeListBrokenBinaries
+			print "Broken libtool time:", timeLibtool
+			print "Remove mask time:", timeMask
+			print "mapPathsToAtoms time:", timeAtoms
+			print
+
+		self._setAtoms(atoms)
+
+	def removeMaskedDependencies(self, dependencies):
+		"""
+		Remove all masked dependencies and return the updated mapping.
+
+		@param dependencies: dependencies from which to removed masked
+			dependencies
+		@type dependencies: dict (example: {'/usr/bin/foo': set(['libfoo.so'])})
+		@rtype: dict
+		@return: shallow copy of dependencies with masked items removed
+
+		"""
+		rValue = dependencies.copy()
+		dirMask, libMask = self.getDependencyMasks()
+
+		# Remove entries that are masked.
+		if dirMask or libMask:
+			if self.debug:
+				print "The following are masked:"
+			for binary, libSet in rValue.items():
+				for dir in dirMask:
+					# Check if the broken binary lies within the masked directory or
+					# its subdirectories.
+					# XXX Perhaps we should allow regexps as masks.
+					if binary.startswith(dir):
+						del rValue[binary]
+						if self.debug:
+							print "dirMask:",binary
+						break
+				# Check if all the required libraries are masked.
+				if binary in rValue and libSet.issubset(libMask):
+					del rValue[binary]
+					if self.debug:
+						print "libMask:", binary, libSet & libMask
+
+		if self.debug:
+			print
+			print "Directory mask:", dirMask
+			print
+			print "Library mask:", libMask
+
+		return rValue
+
+	def getDependencyMasks(self):
+		"""
+		Return all dependency masks as a tuple.
+
+		@rtype: 2-tuple of sets of strings
+		@return: 2-tuple in which the first component is a set of directory
+			masks and the second component is a set of library masks
+
+		"""
+		dirMask = set()
+		libMask = set()
+		_dirMask_re = re.compile(r'SEARCH_DIRS_MASK\s*=\s*"([^"]*)"')
+		_libMask_re = re.compile(r'LD_LIBRARY_MASK\s*=\s*"([^"]*)"')
+		lines = []
+
+		# Reads the contents of /etc/revdep-rebuild/*
+		libMaskDir = os.path.join(self.root, "etc", "revdep-rebuild")
+		if os.path.exists(libMaskDir):
+			for file in os.listdir(libMaskDir):
+				try:
+					f = open(os.path.join(libMaskDir, file), "r")
+					try:
+						lines.extend(f.readlines())
+					finally:
+						f.close()
+				except IOError: # OSError?
+					continue
+			# The following parses SEARCH_DIRS_MASK and LD_LIBRARY_MASK variables
+			# from /etc/revdep-rebuild/*
+			for line in lines:
+				matchDir = _dirMask_re.match(line)
+				matchLib = _libMask_re.match(line)
+				if matchDir:
+					dirMask.update(set(matchDir.group(1).split()))
+				if matchLib:
+					libMask.update(set(matchLib.group(1).split()))
+
+		# These directories contain specially evaluated libraries.
+		# app-emulation/vmware-workstation-6.0.1.55017
+		dirMask.add('/opt/vmware/workstation/lib')
+		# app-emulation/vmware-server-console-1.0.6.91891
+		dirMask.add('/opt/vmware/server/console/lib')
+		# www-client/mozilla-firefox-2.0.0.15
+		dirMask.add('/usr/lib/mozilla-firefox/plugins')
+		dirMask.add('/usr/lib64/mozilla-firefox/plugins')
+		# app-office/openoffice-2.4.1
+		dirMask.add('/opt/OpenOffice')
+		dirMask.add('/usr/lib/openoffice')
+		# dev-libs/libmix-2.05  libmix.so is missing soname entry
+		libMask.add('libmix.so')
+
+		return (dirMask, libMask)
+
+	def findAtomsOfLibraryConsumers(self, searchString):
+		"""
+		Return atoms containing consumers of libraries matching the argument.
+
+		@param searchString: a string used to search for libraries
+		@type searchString: string to be compiled as a regular expression
+			(example: 'libfoo.*')
+		@rtype: set of strings
+		@return: the returned set of atoms are valid to be used by package sets
+
+		"""
+		atoms = set()
+		consumers = set()
+		matchedLibraries = set()
+		libraryObjects = []
+		_librarySearch_re = re.compile(searchString)
+
+		# Find libraries matching searchString.
+		libraryObjects = self.linkmap.listLibraryObjects()
+		for library in libraryObjects:
+			m = _librarySearch_re.search(library)
+			if m:
+				matchedLibraries.add(library)
+				consumers.update(self.linkmap.findConsumers(library))
+
+		print
+		print "Consumers of the following libraries will be emerged:"
+		for x in matchedLibraries:
+			print x
+
+		if consumers:
+			# The following prevents emerging the packages that own the matched
+			# libraries.  Note that this will prevent updating the packages owning
+			# the libraries if there are newer versions available in the installed
+			# slot.  See bug #30095
+			atoms = self.mapPathsToAtoms(consumers)
+			libraryOwners = self.mapPathsToAtoms(matchedLibraries)
+			atoms.difference_update(libraryOwners)
+
+		return atoms
+
+	def listBrokenLibtoolLibraries(self):
+		"""
+		Find broken libtool libraries and their missing dependencies.
+
+		@rtype: dict (example: {'/lib/libfoo.la': set(['/lib/libbar.la'])})
+		@return: The return value is a library -> set-of-libraries mapping, where
+			library is a broken library and the set consists of dependencies
+			needed by library that do not exist on the filesystem.
+
+		"""
+		rValue = {}
+		lines = []
+		dependencies = []
+		_la_re = re.compile(r".*\.la$")
+		_dependency_libs_re = re.compile(r"^dependency_libs\s*=\s*'(.*)'")
+
+		# Loop over the contents of all packages.
+		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)
+			for file in link.getcontents():
+				# Check if the file ends with '.la'.
+				matchLib = _la_re.match(file)
+				if matchLib:
+					# Read the lines from the library.
+					lines = []
+					try:
+						f = open(file, "r")
+						try:
+							lines.extend(f.readlines())
+						finally:
+							f.close()
+					except IOError:
+						continue
+					# Find the line listing the dependencies.
+					for line in lines:
+						matchLine = _dependency_libs_re.match(line)
+						if matchLine:
+							dependencies = matchLine.group(1).split()
+							# For each dependency that is a pathname (begins with
+							# os.sep), check that it exists on the filesystem.  If it
+							# does not exist, then add the library and the missing
+							# dependency to rValue.
+							for dependency in dependencies:
+								if dependency[0] == os.sep and \
+										not os.path.isfile(dependency):
+									rValue.setdefault(file, set()).add(dependency)
+
+		return rValue
+
+	def singleBuilder(self, options, settings, trees):
+		debug = get_boolean(options, "debug", False)
+		return MissingLibraryConsumerSet(trees["vartree"].dbapi, debug)
+	singleBuilder = classmethod(singleBuilder)

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: vartree.py.2.2_rc6.patch --]
[-- Type: text/x-patch; name=vartree.py.2.2_rc6.patch, Size: 7502 bytes --]

--- vartree.py.2.2_rc6	2008-08-01 15:41:03.000000000 -0500
+++ pym/portage/dbapi/vartree.py	2008-08-03 06:11:55.000000000 -0500
@@ -173,8 +173,18 @@
 			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(",")
+			# When fields[3]=="", this prevents the empty string from being
+			# inserted in paths.
+			if fields[3]:
+				path = fields[3].replace("${ORIGIN}", os.path.dirname(obj)).replace("$ORIGIN", os.path.dirname(obj)).split(":")
+			else:
+				path = []
+			# When fields[4]=="", this prevents the empty string from being
+			# inserted as a key into libs.
+			if fields[4]:
+				needed = fields[4].split(",")
+			else:
+				needed = []
 			if soname:
 				libs.setdefault(soname, {arch: {"providers": [], "consumers": []}})
 				libs[soname].setdefault(arch, {"providers": [], "consumers": []})
@@ -188,6 +198,159 @@
 		self._libs = libs
 		self._obj_properties = obj_properties
 
+	def listBrokenBinaries(self):
+		"""
+		Find binaries and their needed sonames, which have no providers.
+
+		@rtype: dict (example: {'/usr/bin/foo': set(['libbar.so'])})
+		@return: The return value is an object -> set-of-sonames mapping, where
+			object is a broken binary and the set consists of sonames needed by
+			object that have no corresponding libraries to fulfill the dependency.
+
+		"""
+		class LibraryCache(object):
+
+			"""
+			Caches sonames and realpaths associated with paths.
+
+			The purpose of this class is to prevent multiple calls of
+			os.path.realpath and os.path.isfile on the same paths.
+
+			"""
+
+			def __init__(cache_self):
+				cache_self.cache = {}
+
+			def get(cache_self, path):
+				"""
+				Caches and returns the soname and realpath for a path.
+
+				@param path: absolute path (can be symlink)
+				@type path: string (example: '/usr/lib/libfoo.so')
+				@rtype: 3-tuple with types (string or None, string, boolean)
+				@return: 3-tuple with the following components:
+					1. soname as a string or None if it does not exist,
+					2. realpath as a string,
+					3. the result of os.path.isfile(realpath)
+					(example: ('libfoo.so.1', '/usr/lib/libfoo.so.1.5.1', True))
+
+				"""
+				if path in cache_self.cache:
+					return cache_self.cache[path]
+				else:
+					realpath = os.path.realpath(path)
+					# Check that the library exists on the filesystem.
+					if os.path.isfile(realpath):
+						# Get the soname from LinkageMap._obj_properties if it
+						# exists. Otherwise, None.
+						soname = self._obj_properties.get(realpath, (None,)*3)[3]
+						# Both path and realpath are cached and the result is
+						# returned.
+						cache_self.cache.setdefault(realpath, \
+								(soname, realpath, True))
+						return cache_self.cache.setdefault(path, \
+								(soname, realpath, True))
+					else:
+						# realpath is not cached here, because the majority of cases
+						# where realpath is not a file, path is the same as realpath.
+						# Thus storing twice slows down the cache performance.
+						return cache_self.cache.setdefault(path, \
+								(None, realpath, False))
+
+		debug = False
+		rValue = {}
+		cache = LibraryCache()
+		providers = self.listProviders()
+#		providers = self.listProvidersForReachableBinaries(self.getBinaries())
+
+		# Iterate over all binaries and their providers.
+		for obj, sonames in providers.items():
+			# Iterate over each needed soname and the set of library paths that
+			# fulfill the soname to determine if the dependency is broken.
+			for soname, libraries in sonames.items():
+				# validLibraries is used to store libraries, which satisfy soname,
+				# so if no valid libraries are found, the soname is not satisfied
+				# for obj.  Thus obj must be emerged.
+				validLibraries = set()
+				# It could be the case that the library to satisfy the soname is
+				# not in the obj's runpath, but a symlink to the library is (eg
+				# libnvidia-tls.so.1 in nvidia-drivers).  Also, since LinkageMap
+				# does not catalog symlinks, broken or missing symlinks may go
+				# unnoticed.  As a result of these cases, check that a file with
+				# the same name as the soname exists in obj's runpath.
+				path = self._obj_properties[obj][2] + self._defpath
+				for dir in path:
+					cachedSoname, cachedRealpath, cachedExists = \
+							cache.get(os.path.join(dir, soname))
+					# Check that the this library provides the needed soname.  Doing
+					# this, however, will cause consumers of libraries missing
+					# sonames to be unnecessarily emerged. (eg libmix.so)
+					if cachedSoname == soname:
+						validLibraries.add(cachedRealpath)
+						if debug and cachedRealpath not in libraries:
+							print "Found provider outside of findProviders:", \
+									os.path.join(dir, soname), "->", cachedRealpath
+						# A valid library has been found, so there is no need to
+						# continue.
+						break
+					if debug and cachedRealpath in self._obj_properties:
+						print "Broken symlink or missing/bad soname:", \
+								os.path.join(dir, soname), '->', cachedRealpath, \
+								"with soname", cachedSoname, "but expecting", soname
+				# This conditional checks if there are no libraries to satisfy the
+				# soname (empty set).
+				if not validLibraries:
+					rValue.setdefault(obj, set()).add(soname)
+					# If no valid libraries have been found by this point, then
+					# there are no files named with the soname within obj's runpath,
+					# but if there are libraries (from the providers mapping), it is
+					# likely that symlinks or the actual libraries are missing.
+					# Thus possible symlinks and missing libraries are added to
+					# rValue in order to emerge corrupt library packages.
+					for lib in libraries:
+						cachedSoname, cachedRealpath, cachedExists = cache.get(lib)
+						if not cachedExists:
+							# The library's package needs to be emerged to repair the
+							# missing library.
+							rValue.setdefault(lib, set()).add(soname)
+						else:
+							# A library providing the soname exists in the obj's
+							# runpath, but no file named as the soname exists, so add
+							# the path constructed from the lib's directory and the
+							# soname to rValue to fix cases of vanishing (or modified)
+							# symlinks.  This path is not guaranteed to exist, but it
+							# follows the symlink convention found in the majority of
+							# packages.
+							rValue.setdefault(os.path.join(os.path.dirname(lib), \
+									soname), set()).add(soname)
+						if debug:
+							if not cachedExists:
+								print "Missing library:", lib
+							else:
+								print "Possibly missing symlink:", \
+										os.path.join(os.path.dirname(lib), soname)
+
+		return rValue
+
+	def listProviders(self):
+		"""
+		Find the providers for all binaries.
+
+		@rtype: dict (example:
+			{'/usr/bin/foo': {'libbar.so': set(['/lib/libbar.so.1.5'])}})
+		@return: The return value is an object -> providers mapping, where
+			providers is a mapping of soname -> set-of-library-paths returned
+			from the findProviders method.
+
+		"""
+		rValue = {}
+		if not self._libs:
+			self.rebuild()
+		# Iterate over all binaries within LinkageMap.
+		for obj in self._obj_properties.keys():
+			rValue.setdefault(obj, self.findProviders(obj))
+		return rValue
+
 	def isMasterLink(self, obj):
 		basename = os.path.basename(obj)
 		if obj not in self._obj_properties:

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [gentoo-portage-dev] [PATCH] missing-rebuild package set
  2008-08-03 14:03 [gentoo-portage-dev] [PATCH] missing-rebuild package set Lucian Poston
@ 2008-08-08 22:10 ` Zac Medico
  2009-02-18  6:17   ` Alec Warner
  0 siblings, 1 reply; 4+ messages in thread
From: Zac Medico @ 2008-08-08 22:10 UTC (permalink / raw
  To: gentoo-portage-dev

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Lucian Poston wrote:
> The following patchs add a library dependency rebuilder as a package
> set, @missing-rebuild, to portage-2.2_rc6.  Similar to the --library
> flag in revdep-rebuild, the user can additionally emerge the set of
> packages containing consumers of libraries matched by a (python)
> regular expression; however, until a better solution is found, the
> regexp must be passed through the LIBRARY environment variable to
> enable that feature.
> 
> Known issues: I expect some false positives. I've inserted hard coded
> directory/library masks for those I've found. I noticed a situation
> that required a second emerge due to a provider package satisfying 3
> conditions: 1) the package is installed and an updated version is
> available in its slot, 2) the updated version is in the set due to a
> dependency of another package (or it may contains a broken binary),
> and 3) a consumer package of a library within the updated package is
> emerged before the updated dependency is emerged, causing a package to
> be compiled against the old library before the library version
> changes.  I guess that if a package is already installed, it is not
> necessarily placed before its consumer packages in the merge order.
> 
> Attached are patches for pym/portage/dbapi/vartree.py,
> pym/portage/sets/libs.py and /usr/share/portage/config/sets.conf.
> These can also be found in the project's repository:
> http://repo.or.cz/w/revdep-rebuild-reimplementation.git?a=tree;h=refs/heads/rc1;hb=refs/heads/rc1

Thanks, I've merged your LinkageMap changes.

Side note: I suspect that we might be able to improve efficiency in
LinkageMap path comparisons by comparing tuples of device and inode
numbers instead of using realpath. We currently use the device/inode
number approach to test identity of paths in dblink.isowner().

> I warmly welcome all feedback, in particular any suggestions to remove
> the necessity of directory and library masks in /etc/revdep-rebuild/*,
> which I've been unable to entirely avoid.
> 
> Lucian
> 

I haven't merged the MissingLibraryConsumerSet yet since I'd like to
see if we can improve it a bit first. I don't have any ideas right
now but hopefully we can come up with something soon.

Zac



-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (GNU/Linux)

iEYEARECAAYFAkicxEsACgkQ/ejvha5XGaNcyACfX7oKKCbYraRk8AwckkA9Reu6
cRkAoMa/vK5SXDTdw8+nYqpBAlUXz096
=zskl
-----END PGP SIGNATURE-----



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [gentoo-portage-dev] [PATCH] missing-rebuild package set
  2008-08-08 22:10 ` Zac Medico
@ 2009-02-18  6:17   ` Alec Warner
  2009-02-18 21:54     ` Zac Medico
  0 siblings, 1 reply; 4+ messages in thread
From: Alec Warner @ 2009-02-18  6:17 UTC (permalink / raw
  To: gentoo-portage-dev

On Fri, Aug 8, 2008 at 2:10 PM, Zac Medico <zmedico@gentoo.org> wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Lucian Poston wrote:
>> The following patchs add a library dependency rebuilder as a package
>> set, @missing-rebuild, to portage-2.2_rc6.  Similar to the --library
>> flag in revdep-rebuild, the user can additionally emerge the set of
>> packages containing consumers of libraries matched by a (python)
>> regular expression; however, until a better solution is found, the
>> regexp must be passed through the LIBRARY environment variable to
>> enable that feature.
>>
>> Known issues: I expect some false positives. I've inserted hard coded
>> directory/library masks for those I've found. I noticed a situation
>> that required a second emerge due to a provider package satisfying 3
>> conditions: 1) the package is installed and an updated version is
>> available in its slot, 2) the updated version is in the set due to a
>> dependency of another package (or it may contains a broken binary),
>> and 3) a consumer package of a library within the updated package is
>> emerged before the updated dependency is emerged, causing a package to
>> be compiled against the old library before the library version
>> changes.  I guess that if a package is already installed, it is not
>> necessarily placed before its consumer packages in the merge order.
>>
>> Attached are patches for pym/portage/dbapi/vartree.py,
>> pym/portage/sets/libs.py and /usr/share/portage/config/sets.conf.
>> These can also be found in the project's repository:
>> http://repo.or.cz/w/revdep-rebuild-reimplementation.git?a=tree;h=refs/heads/rc1;hb=refs/heads/rc1
>
> Thanks, I've merged your LinkageMap changes.
>
> Side note: I suspect that we might be able to improve efficiency in
> LinkageMap path comparisons by comparing tuples of device and inode
> numbers instead of using realpath. We currently use the device/inode
> number approach to test identity of paths in dblink.isowner().

As it is time for gSoC 2009; I want to inquire at the status of this
code integration.
Looking at HEAD it seems there are some changes left to merge.  Is
this on the roadmap?

-Alec

>
>> I warmly welcome all feedback, in particular any suggestions to remove
>> the necessity of directory and library masks in /etc/revdep-rebuild/*,
>> which I've been unable to entirely avoid.
>>
>> Lucian
>>
>
> I haven't merged the MissingLibraryConsumerSet yet since I'd like to
> see if we can improve it a bit first. I don't have any ideas right
> now but hopefully we can come up with something soon.
>
> Zac
>
>
>
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v2.0.9 (GNU/Linux)
>
> iEYEARECAAYFAkicxEsACgkQ/ejvha5XGaNcyACfX7oKKCbYraRk8AwckkA9Reu6
> cRkAoMa/vK5SXDTdw8+nYqpBAlUXz096
> =zskl
> -----END PGP SIGNATURE-----
>
>



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [gentoo-portage-dev] [PATCH] missing-rebuild package set
  2009-02-18  6:17   ` Alec Warner
@ 2009-02-18 21:54     ` Zac Medico
  0 siblings, 0 replies; 4+ messages in thread
From: Zac Medico @ 2009-02-18 21:54 UTC (permalink / raw
  To: gentoo-portage-dev

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Alec Warner wrote:
>> As it is time for gSoC 2009; I want to inquire at the status of this
>> code integration.
>> Looking at HEAD it seems there are some changes left to merge.  Is
>> this on the roadmap?

The hardcoded libraries/paths (used to filter "false positives")
still need to be split out into config files before I can merge it.
I'll get to that eventually but I've got lots of other more pressing
things to work on a them moment.

For preserve-libs, the main problems that are left are:

1) There is no protection against building packages which depend on
packages for which libs are still preserved [1].

2) Library preservation currently does not work for binutils
upgrades since the binutils libraries are added to the library path
via symlinks which are created by binutils-config (unlike most
packages the provide libraries, the paths of libraries to which the
symlinks point are not included directly in ld.so.conf).

[1]
http://blog.flameeyes.eu/2008/06/30/a-few-risks-i-see-related-to-the-new-portage-2-2-preserve-libs-behaviour

- --
Thanks,
Zac
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.10 (GNU/Linux)

iEYEARECAAYFAkmcg4sACgkQ/ejvha5XGaNaSQCg00Bcs0xCzj7/iE2cf5rxMuwT
SqwAoNkSNV+mF6JIGVyttoDKKZ6fOtVs
=NK/Z
-----END PGP SIGNATURE-----



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2009-02-18 21:54 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-03 14:03 [gentoo-portage-dev] [PATCH] missing-rebuild package set Lucian Poston
2008-08-08 22:10 ` Zac Medico
2009-02-18  6:17   ` Alec Warner
2009-02-18 21:54     ` Zac Medico

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox