[csw-devel] SF.net SVN: gar:[10479] csw/mgar/gar/v2/lib/python

wahwah at users.sourceforge.net wahwah at users.sourceforge.net
Fri Jul 9 11:50:35 CEST 2010


Revision: 10479
          http://gar.svn.sourceforge.net/gar/?rev=10479&view=rev
Author:   wahwah
Date:     2010-07-09 09:50:35 +0000 (Fri, 09 Jul 2010)

Log Message:
-----------
mGAR checkpkg: support for $ORIGIN in rpath, one-time message support in the messenger class.

Modified Paths:
--------------
    csw/mgar/gar/v2/lib/python/checkpkg.py
    csw/mgar/gar/v2/lib/python/checkpkg_test.py
    csw/mgar/gar/v2/lib/python/dependency_checks.py
    csw/mgar/gar/v2/lib/python/package_checks.py
    csw/mgar/gar/v2/lib/python/package_checks_test.py

Modified: csw/mgar/gar/v2/lib/python/checkpkg.py
===================================================================
--- csw/mgar/gar/v2/lib/python/checkpkg.py	2010-07-09 01:27:36 UTC (rev 10478)
+++ csw/mgar/gar/v2/lib/python/checkpkg.py	2010-07-09 09:50:35 UTC (rev 10479)
@@ -18,6 +18,7 @@
 import socket
 import sqlite3
 import sqlobject
+import time
 from sqlobject import sqlbuilder
 import subprocess
 import textwrap
@@ -523,8 +524,10 @@
     return schema_on_disk
 
   def IsDatabaseUpToDate(self):
-    f_mtime = self.GetFileMtime()
-    d_mtime = self.GetDatabaseMtime()
+    f_mtime_epoch = self.GetFileMtime()
+    d_mtime_epoch = self.GetDatabaseMtime()
+    f_mtime = time.gmtime(int(f_mtime_epoch))
+    d_mtime = time.gmtime(int(d_mtime_epoch))
     logging.debug("IsDatabaseUpToDate: f_mtime %s, d_time: %s", f_mtime, d_mtime)
     # Rounding up to integer seconds.  There is a race condition: 
     # pkgadd finishes at 100.1
@@ -532,7 +535,7 @@
     # new pkgadd runs and finishes at 100.3
     # subsequent checkpkg runs won't pick up the last change.
     # I don't expect pkgadd to run under 1s.
-    fresh = int(f_mtime) <= int(d_mtime)
+    fresh = f_mtime <= d_mtime
     good_version = self.GetDatabaseSchemaVersion() >= DB_SCHEMA_VERSION
     logging.debug("IsDatabaseUpToDate: good_version=%s, fresh=%s",
                   repr(good_version), repr(fresh))
@@ -562,21 +565,45 @@
   """
   def __init__(self):
     self.runpath_expand_cache = {}
+    self.runpath_origin_expand_cache = {}
     self.symlink_expand_cache = {}
     self.symlink64_cache = {}
     self.runpath_sanitize_cache = {}
 
-  def ExpandRunpath(self, runpath, isalist):
+  def ExpandRunpath(self, runpath, isalist, binary_path):
+    """Expands a signle runpath element.
+
+    Args:
+      runpath: e.g. "/opt/csw/lib/$ISALIST"
+      isalist: isalist elements
+      binary_path: Necessary to expand $ORIGIN
+    """
     # TODO: Implement $ORIGIN support
     # Probably not here as it would make caching unusable.
     key = (runpath, tuple(isalist))
     if key not in self.runpath_expand_cache:
-      # Emulating $ISALIST expansion
+      origin_present = False
+      # Emulating $ISALIST and $ORIGIN expansion
+      if '$ORIGIN' in runpath:
+        origin_present = True
+      if origin_present:
+        key_o = (runpath, tuple(isalist), binary_path)
+        if key_o in self.runpath_origin_expand_cache:
+          return self.runpath_origin_expand_cache[key_o]
+        else:
+          if not binary_path.startswith("/"):
+            binary_path = "/" + binary_path
+          runpath = runpath.replace('$ORIGIN', binary_path)
       if '$ISALIST' in runpath:
         expanded_list = [runpath.replace('$ISALIST', isa) for isa in isalist]
       else:
         expanded_list = [runpath]
-      self.runpath_expand_cache[key] = expanded_list
+      expanded_list = [os.path.abspath(p) for p in expanded_list]
+      if not origin_present:
+        self.runpath_expand_cache[key] = expanded_list
+      else:
+        self.runpath_origin_expand_cache[key_o] = expanded_list
+        return self.runpath_origin_expand_cache[key_o]
     return self.runpath_expand_cache[key]
 
   def ExpandSymlink(self, symlink, target, input_path):
@@ -624,7 +651,7 @@
     return self.runpath_sanitize_cache[runpath]
 
 
-  def ResolveSoname(self, runpath, soname, isalist, path_list):
+  def ResolveSoname(self, runpath_list, soname, isalist, path_list, binary_path):
     """Emulates ldd behavior, minimal implementation.
 
     runpath: e.g. ["/opt/csw/lib/$ISALIST", "/usr/lib"]
@@ -635,9 +662,6 @@
 
     The function returns the one path.
     """
-    runpath = self.SanitizeRunpath(runpath)
-    runpath_list = self.ExpandRunpath(runpath, isalist)
-    runpath_list = self.Emulate64BitSymlinks(runpath_list)
     # Emulating the install time symlinks, for instance, if the prototype contains
     # /opt/csw/lib/i386/foo.so.0 and /opt/csw/lib/i386 is a symlink to ".",
     # the shared library ends up in /opt/csw/lib/foo.so.0 and should be
@@ -862,11 +886,16 @@
   """Class responsible for passing messages from checks to the user."""
   def __init__(self):
     self.messages = []
+    self.one_time_messages = {}
     self.gar_lines = []
 
   def Message(self, m):
     self.messages.append(m)
 
+  def OneTimeMessage(self, key, m):
+    if key not in self.one_time_messages:
+      self.one_time_messages[key] = m
+
   def SuggestGarLine(self, m):
     self.gar_lines.append(m)
 
@@ -934,7 +963,8 @@
       function(pkgs_data, check_interface, logger=logger, messenger=messenger)
       if check_interface.errors:
         errors = self.SetErrorsToDict(check_interface.errors, errors)
-    return errors, messenger.messages, messenger.gar_lines
+    messages = messenger.messages + messenger.one_time_messages.values()
+    return errors, messages, messenger.gar_lines
 
   def Run(self):
     self._AutoregisterChecks()

Modified: csw/mgar/gar/v2/lib/python/checkpkg_test.py
===================================================================
--- csw/mgar/gar/v2/lib/python/checkpkg_test.py	2010-07-09 01:27:36 UTC (rev 10478)
+++ csw/mgar/gar/v2/lib/python/checkpkg_test.py	2010-07-09 09:50:35 UTC (rev 10479)
@@ -45,15 +45,59 @@
     isalist = ["foo", "bar"]
     runpath = "/opt/csw/lib/$ISALIST"
     expected = ["/opt/csw/lib/foo", "/opt/csw/lib/bar"]
-    self.assertEquals(expected, self.e.ExpandRunpath(runpath, isalist))
+    bin_path = "opt/csw/lib"
+    self.assertEquals(expected, self.e.ExpandRunpath(runpath, isalist, bin_path))
 
   def testExpandRunpath_2(self):
     isalist = ["foo", "bar"]
     runpath = "/opt/csw/mysql5/lib/$ISALIST/mysql"
     expected = ["/opt/csw/mysql5/lib/foo/mysql",
                 "/opt/csw/mysql5/lib/bar/mysql"]
-    self.assertEquals(expected, self.e.ExpandRunpath(runpath, isalist))
+    bin_path = "opt/csw/lib"
+    self.assertEquals(expected, self.e.ExpandRunpath(runpath, isalist, bin_path))
 
+  def testExpandRunpath_OriginSimple(self):
+    isalist = ()
+    runpath = "$ORIGIN"
+    expected = ["/opt/csw/lib"]
+    bin_path = "opt/csw/lib"
+    self.assertEquals(expected, self.e.ExpandRunpath(runpath, isalist, bin_path))
+
+  def testExpandRunpath_OriginDots(self):
+    isalist = ()
+    runpath = "$ORIGIN/.."
+    expected = ["/opt/csw/lib"]
+    bin_path = "opt/csw/lib/subdir"
+    self.assertEquals(expected, self.e.ExpandRunpath(runpath, isalist, bin_path))
+
+  def testExpandRunpath_Caching(self):
+    """Make sure that the cache doesn't mess it up.
+
+    Two invocations, where the only difference is the binary path.
+    """
+    isalist = ()
+    runpath = "/opt/csw/lib/foo"
+    expected = ["/opt/csw/lib/foo"]
+    bin_path = "opt/csw/lib"
+    self.assertEquals(expected, self.e.ExpandRunpath(runpath, isalist, bin_path))
+    expected = ["/opt/csw/lib/foo"]
+    bin_path = "/opt/csw/lib/foo"
+    self.assertEquals(expected, self.e.ExpandRunpath(runpath, isalist, bin_path))
+
+  def testExpandRunpath_OriginCaching(self):
+    """Make sure that the cache doesn't mess it up.
+
+    Two invocations, where the only difference is the binary path.
+    """
+    isalist = ()
+    runpath = "$ORIGIN"
+    expected = ["/opt/csw/lib"]
+    bin_path = "opt/csw/lib"
+    self.assertEquals(expected, self.e.ExpandRunpath(runpath, isalist, bin_path))
+    expected = ["/opt/csw/foo/lib"]
+    bin_path = "/opt/csw/foo/lib"
+    self.assertEquals(expected, self.e.ExpandRunpath(runpath, isalist, bin_path))
+
   def testEmulate64BitSymlinks_1(self):
     runpath_list = ["/opt/csw/mysql5/lib/foo/mysql/64"]
     expected = "/opt/csw/mysql5/lib/foo/mysql/amd64"
@@ -130,14 +174,14 @@
         'RPATH set': True,
         'RUNPATH RPATH the same': True,
         'RUNPATH set': True,
-        'needed sonames': ['librt.so.1',
+        'needed sonames': ('librt.so.1',
                            'libresolv.so.2',
                            'libc.so.1',
                            'libgen.so.1',
                            'libsocket.so.1',
                            'libnsl.so.1',
                            'libm.so.1',
-                           'libz.so.1'],
+                           'libz.so.1'),
         'runpath': ('/opt/csw/lib/$ISALIST',
                     '/opt/csw/lib',
                     '/opt/csw/mysql5/lib/$ISALIST',
@@ -159,14 +203,14 @@
         'RPATH set': True,
         'RUNPATH RPATH the same': False,
         'RUNPATH set': False,
-        'needed sonames': ['librt.so.1',
+        'needed sonames': ('librt.so.1',
                            'libresolv.so.2',
                            'libc.so.1',
                            'libgen.so.1',
                            'libsocket.so.1',
                            'libnsl.so.1',
                            'libm.so.1',
-                           'libz.so.1'],
+                           'libz.so.1'),
         'runpath': ('/opt/csw/lib/$ISALIST',
                     '/opt/csw/lib',
                     '/opt/csw/mysql5/lib/$ISALIST',

Modified: csw/mgar/gar/v2/lib/python/dependency_checks.py
===================================================================
--- csw/mgar/gar/v2/lib/python/dependency_checks.py	2010-07-09 01:27:36 UTC (rev 10478)
+++ csw/mgar/gar/v2/lib/python/dependency_checks.py	2010-07-09 09:50:35 UTC (rev 10479)
@@ -1,6 +1,7 @@
 # $Id$
 
 import checkpkg
+import os.path
 import re
 
 DEPRECATED_LIBRARY_LOCATIONS = (
@@ -17,7 +18,7 @@
     r'^opt/csw/lib/python/site-packages.*',
 )
 
-def Libraries(pkg_data, error_mgr, logger, path_and_pkg_by_basename):
+def Libraries(pkg_data, error_mgr, logger, messenger, path_and_pkg_by_basename):
   pkgname = pkg_data["basic_stats"]["pkgname"]
   logger.debug("Libraries(): pkgname = %s", repr(pkgname))
   orphan_sonames = []
@@ -25,6 +26,7 @@
   isalist = pkg_data["isalist"]
   ldd_emulator = checkpkg.LddEmulator()
   for binary_info in pkg_data["binaries_dump_info"]:
+    binary_path, binary_basename = os.path.split(binary_info["path"])
     for soname in binary_info["needed sonames"]:
       resolved = False
       path_list = path_and_pkg_by_basename[soname].keys()
@@ -35,11 +37,18 @@
                    path_list)
       runpath_tuple = (tuple(binary_info["runpath"])
                       + tuple(checkpkg.SYS_DEFAULT_RUNPATH))
+      runpath_history = []
       for runpath in runpath_tuple:
-        resolved_path = ldd_emulator.ResolveSoname(runpath,
+        runpath = ldd_emulator.SanitizeRunpath(runpath)
+        runpath_list = ldd_emulator.ExpandRunpath(runpath, isalist, binary_path)
+        runpath_list = ldd_emulator.Emulate64BitSymlinks(runpath_list)
+        # To accumulate all the runpaths that we were looking at
+        runpath_history += runpath_list
+        resolved_path = ldd_emulator.ResolveSoname(runpath_list,
                                                    soname,
                                                    isalist,
-                                                   path_list)
+                                                   path_list,
+                                                   binary_path)
         if resolved_path:
           logger.debug("%s needed by %s:",
                  soname, binary_info["path"])
@@ -61,6 +70,10 @@
           break
       if not resolved:
         orphan_sonames.append((soname, binary_info["path"]))
+        messenger.Message(
+            "%s could not be resolved for %s, with rpath %s, expanded to %s, "
+            "while the file was available at the following paths: %s"
+            % (soname, binary_info["path"], runpath_tuple, runpath_history, path_list))
   orphan_sonames = set(orphan_sonames)
   for soname, binary_path in orphan_sonames:
     error_mgr.ReportError(
@@ -69,7 +82,7 @@
   # TODO: Report orphan sonames here
   return required_deps
 
-def ByFilename(pkg_data, error_mgr, logger, path_and_pkg_by_basename):
+def ByFilename(pkg_data, error_mgr, logger, messenger, path_and_pkg_by_basename):
   pkgname = pkg_data["basic_stats"]["pkgname"]
   req_pkgs_reasons = []
   dep_regexes = [(re.compile(x), x, y)

Modified: csw/mgar/gar/v2/lib/python/package_checks.py
===================================================================
--- csw/mgar/gar/v2/lib/python/package_checks.py	2010-07-09 01:27:36 UTC (rev 10478)
+++ csw/mgar/gar/v2/lib/python/package_checks.py	2010-07-09 09:50:35 UTC (rev 10479)
@@ -298,14 +298,18 @@
   # Resolving sonames for each binary
   for pkg_data in pkgs_data:
     pkgname = pkg_data["basic_stats"]["pkgname"]
-    check_args = (pkg_data, error_mgr, logger, path_and_pkg_by_basename)
+    check_args = (pkg_data, error_mgr, logger, messenger,
+                  path_and_pkg_by_basename)
     req_pkgs_reasons = depchecks.Libraries(*check_args)
     req_pkgs_reasons.extend(depchecks.ByFilename(*check_args))
     missing_reasons_by_pkg = {}
     for pkg, reason in req_pkgs_reasons:
       if pkg not in missing_reasons_by_pkg:
-        missing_reasons_by_pkg[pkg] = set()
-      missing_reasons_by_pkg[pkg].add(reason)
+        missing_reasons_by_pkg[pkg] = list()
+      if len(missing_reasons_by_pkg[pkg]) < 4:
+        missing_reasons_by_pkg[pkg].append(reason)
+      elif len(missing_reasons_by_pkg[pkg]) == 4:
+        missing_reasons_by_pkg[pkg].append("...and more.")
     declared_deps = pkg_data["depends"]
     declared_deps_set = set([x[0] for x in declared_deps])
     req_pkgs_set = set([x[0] for x in req_pkgs_reasons])
@@ -876,7 +880,8 @@
             metadata["path"],
             metadata["machine_id"],
             cpu_type))
-      messenger.Message(
+      messenger.OneTimeMessage(
+          "binary-placement",
           "Files compiled for specific architectures must be placed in "
           "subdirectories that match the architecture.  "
           "For example, a sparcv8+ binary must not be placed under "

Modified: csw/mgar/gar/v2/lib/python/package_checks_test.py
===================================================================
--- csw/mgar/gar/v2/lib/python/package_checks_test.py	2010-07-09 01:27:36 UTC (rev 10478)
+++ csw/mgar/gar/v2/lib/python/package_checks_test.py	2010-07-09 09:50:35 UTC (rev 10479)
@@ -339,7 +339,8 @@
     binaries_dump_info[0]["runpath"] = tuple(testdata.rpaths.all_rpaths)
     self.pkg_data["binaries_dump_info"] = binaries_dump_info[0:1]
     BAD_PATHS = [
-        '$ORIGIN/..',
+        # Whether this is a valid rpath, is debatable.
+        # '$ORIGIN/..',
         '$ORIGIN/../../../usr/lib/v9',
         '$ORIGIN/../../usr/lib',
         '$ORIGIN/../lib',


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.


More information about the devel mailing list