[csw-devel] SF.net SVN: gar:[7856] csw/mgar/gar/v2
wahwah at users.sourceforge.net
wahwah at users.sourceforge.net
Mon Jan 4 11:28:16 CET 2010
Revision: 7856
http://gar.svn.sourceforge.net/gar/?rev=7856&view=rev
Author: wahwah
Date: 2010-01-04 10:28:15 +0000 (Mon, 04 Jan 2010)
Log Message:
-----------
mGAR v2: Merging the v2-checkpkg branch in
Modified Paths:
--------------
csw/mgar/gar/v2/bin/checkpkg
Added Paths:
-----------
csw/mgar/gar/v2/bin/checkpkg.d/
csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-dummy.py
csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-libs.py
csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-obsolete-deps.py
csw/mgar/gar/v2/bin/checkpkg.d/checkpkg.py
csw/mgar/gar/v2/bin/checkpkg.d/checkpkg_test.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/
csw/mgar/gar/v2/bin/checkpkg.d/testdata/__init__.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/checkpkg_test_data_CSWlibpq_84.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/checkpkg_test_data_CSWmysql51.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/checkpkg_test_data_CSWmysql51client.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/checkpkg_test_data_CSWmysql51devel.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/checkpkg_test_data_CSWmysql51rt.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/checkpkg_test_data_CSWmysql5client_8x.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/dump_output_1.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/dump_output_2.py
Removed Paths:
-------------
csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-dummy.py
csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-libs.py
csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-obsolete-deps.py
csw/mgar/gar/v2/bin/checkpkg.d/checkpkg.py
csw/mgar/gar/v2/bin/checkpkg.d/checkpkg_test.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/
csw/mgar/gar/v2/bin/checkpkg.d/testdata/__init__.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/checkpkg_test_data_CSWlibpq_84.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/checkpkg_test_data_CSWmysql51.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/checkpkg_test_data_CSWmysql51client.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/checkpkg_test_data_CSWmysql51devel.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/checkpkg_test_data_CSWmysql51rt.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/checkpkg_test_data_CSWmysql5client_8x.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/dump_output_1.py
csw/mgar/gar/v2/bin/checkpkg.d/testdata/dump_output_2.py
Property Changed:
----------------
csw/mgar/gar/v2/
csw/mgar/gar/v2/bin/checkpkg
csw/mgar/gar/v2/pkglib/csw/depend
Property changes on: csw/mgar/gar/v2
___________________________________________________________________
Modified: svn:mergeinfo
- /csw/mgar/gar/v2:4936-6678
/csw/mgar/gar/v2-collapsed-modulations:6895
/csw/mgar/gar/v2-migrateconf:7082-7211
/csw/mgar/gar/v2-skayser:6087-6132
+ /csw/mgar/gar/v2:4936-6678
/csw/mgar/gar/v2-checkpkg:7722-7855
/csw/mgar/gar/v2-collapsed-modulations:6895
/csw/mgar/gar/v2-migrateconf:7082-7211
/csw/mgar/gar/v2-skayser:6087-6132
Modified: csw/mgar/gar/v2/bin/checkpkg
===================================================================
--- csw/mgar/gar/v2/bin/checkpkg 2010-01-04 03:57:34 UTC (rev 7855)
+++ csw/mgar/gar/v2/bin/checkpkg 2010-01-04 10:28:15 UTC (rev 7856)
@@ -1,6 +1,13 @@
#!/bin/ksh -p
-
-# checkpkg 1.50 (diff to 1.46a: check multiple package files)
+#
+# $Id$
+#
+# checkpkg 1.51
+#
+# diff to 1.46a
+# - check multiple package files
+# - checkpkg.d plugin support
+#
# This script examines a package that has been put together
# for submittal to the CSW archive at opencsw.org
#
@@ -18,7 +25,22 @@
PATH=$PATH:/usr/sbin
LOCAL_ARCH=`uname -p`
+if [[ -z "${CHECKPKG_TMPDIR}" ]]; then
+ readonly CHECKPKG_TMPDIR="/var/tmp"
+else
+ readonly CHECKPKG_TMPDIR
+fi
+# Colors only when running interactively
+if [[ -t 1 ]]; then
+ GREEN="\\033[0;32;40m"
+ RED="\\033[1;31;40m"
+ COLOR_RESET="\\033[00m"
+else
+ GREEN=""
+ RED=""
+ COLOR_RESET=""
+fi
# always print out a warning message. (to stderr)
# exit script, if quit_on_warn set
@@ -28,11 +50,17 @@
if [[ -d "$EXTRACTDIR" ]] ; then
rm -rf $EXTRACTDIR
fi
- if [[ "$TMPARCHIVE" != "" ]] ; then
- [ -f "$TMPARCHIVE" ] && rm $TMPARCHIVE
- fi
+ cleantmparchives
}
+cleantmparchives() {
+ for TMPARCHIVE in $tmparchives; do
+ if [[ "$TMPARCHIVE" != "" ]]; then
+ [ -f "$TMPARCHIVE" ] && rm $TMPARCHIVE
+ fi
+ done
+}
+
cleanupset(){
if [ "`echo $SETINF*`" != "$SETINF*" ]; then
rm $SETINF*
@@ -54,6 +82,33 @@
exit 1
}
+debugmsg() {
+ if [[ "${DEBUG}" != "" ]]; then
+ print "DEBUG: $*" > /dev/fd/2
+ fi
+}
+
+set_variables_for_individual_package_check() {
+ f=$1
+ file $f |sed 's/^.*://' |grep gzip >/dev/null
+ if [ $? -eq 0 ] ; then
+ TMPARCHIVE=$CHECKPKG_TMPDIR/`basename $f`
+ if [[ -f $TMPARCHIVE ]] ; then
+ print ERROR: $TMPARCHIVE already exists
+
+ fi
+ gzcat $f >$TMPARCHIVE || exit 1
+ f=$TMPARCHIVE
+ fi
+ pkgname=`nawk 'NR == 2 {print $1; exit;}' $f`
+ pkgnames="$pkgnames $pkgname"
+}
+
+if [[ "$1" == "-d" ]] ; then
+ DEBUG=1
+ shift
+fi
+
if [[ "$1" == "-e" ]] ; then
quit_on_warn=1;
shift
@@ -65,11 +120,19 @@
fi
# a unique filename for the list of package deps and libs we see in a 'set'
-SETINF=/tmp/checkpkg.$$.`date +%Y%m%d%H%M%S`
+SETINF=$CHECKPKG_TMPDIR/checkpkg.$$.`date +%Y%m%d%H%M%S`
SETLIBS=$SETINF.libs
SETDEPS=$SETINF.deps
+pkgnames=""
+tmparchives=""
+EXTRACTDIR=$CHECKPKG_TMPDIR/dissect.$$
+if [ -d $EXTRACTDIR ] ; then
+ print ERROR: $EXTRACTDIR already exists
+ exit 1
+fi
+
for f in "$@"
do
@@ -82,9 +145,6 @@
case $f in
- cswutils-*)
- :
- ;;
*)
print Examining $f
@@ -111,30 +171,13 @@
done
esac
-print Extracting files for more detailed inspection...
+print Extracting all files for more detailed inspection...
-file $f |sed 's/^.*://' |grep gzip >/dev/null
-if [ $? -eq 0 ] ; then
- TMPARCHIVE=/tmp/`basename $f`
- if [[ -f $TMPARCHIVE ]] ; then
- print ERROR: $TMPARCHIVE already exists
-
- fi
- gzcat $f >$TMPARCHIVE || exit 1
- f=$TMPARCHIVE
-fi
+set_variables_for_individual_package_check "$f"
-pkgname=`nawk 'NR == 2 {print $1; exit;}' $f`
-
-EXTRACTDIR=/tmp/dissect.$$
-
-if [ -d $EXTRACTDIR ] ; then
- print ERROR: $EXTRACTDIR already exists
- exit 1
-fi
-
mkdir $EXTRACTDIR
+# FIXME: This doesn't support multiple packages
TMPFILE=$EXTRACTDIR/pkginfo
@@ -304,7 +347,6 @@
print Extracing pkg for examination of files...
pkgtrans $f $EXTRACTDIR $pkgname
-
#############################################################
# We now have the package expanded, in "directory" form, in
# $EXTRACTDIR/$pkgname
@@ -406,7 +448,7 @@
#cat $EXTRACTDIR/elflist| xargs ldd 2>/dev/null |fgrep '.so' |
# sed 's:^.*=>[^/]*::' | nawk '{print $1}' |sort -u >$EXTRACTDIR/liblist
- cat $EXTRACTDIR/elflist| xargs dump -Lv |nawk '$2=="NEEDED"{print $3}' |
+ cat $EXTRACTDIR/elflist| xargs /usr/ccs/bin/dump -Lv |nawk '$2=="NEEDED"{print $3}' |
sort -u | egrep -v $EXTRACTDIR >$EXTRACTDIR/liblist
@@ -443,13 +485,12 @@
exit 1
fi
-# Verify that there are no double depends
+# Verify that there are no multiple depends
repeated_depends="$(awk '{print $2}' $EXTRACTDIR/$pkgname/install/depend \
| sort | uniq -c | awk '{print $1}' | sort | uniq | wc -l)"
if [[ "$repeated_depends" -gt 1 ]]; then
cat $EXTRACTDIR/$pkgname/install/depend
- print ERROR: $pkgname has double depends
- exit 1
+ errmsg "$pkgname has multiple depends"
fi
#to retain a record of all packages currently being examined from $@
@@ -474,47 +515,6 @@
fi
done
-egrep -v 'SUNWbcp|SUNWowbcp|SUNWucb' /var/sadm/install/contents |
- fgrep -f $EXTRACTDIR/liblist >$EXTRACTDIR/shortcatalog
-
-
-
-for lib in `cat $EXTRACTDIR/liblist` ; do
- grep "[/=]$lib[ =]" $EXTRACTDIR/$pkgname/pkgmap
- if [[ $? -eq 0 ]] ; then
- echo $lib provided by package itself
- continue
- else
- grep "[/=]$lib[ =]" $SETLIBS
- if [[ $? -eq 0 ]]; then
- echo "$lib provided by package set being evaluated."
- continue
- fi
- fi
-
- libpkg=`grep /$lib $EXTRACTDIR/shortcatalog |
- sed 's/^.* \([^ ]*\)$/\1/' |sort -u`
-
- if [[ -z "$libpkg" ]] ; then
- echo "$lib $pkgname" >> $SETLIBS.missing
- print Cannot find package providing $lib. Storing for delayed validation.
- else
- print $libpkg | fmt -1 >>$EXTRACTDIR/libpkgs
- fi
-done
-
-sort -u $EXTRACTDIR/libpkgs >$EXTRACTDIR/libpkgs.x
-mv $EXTRACTDIR/libpkgs.x $EXTRACTDIR/libpkgs
-
-diff $EXTRACTDIR/deppkgs $EXTRACTDIR/libpkgs >/dev/null
-if [[ $? -ne 0 ]] ; then
- print SUGGESTION: you may want to add some or all of the following as depends:
- print ' (Feel free to ignore SUNW or SPRO packages)'
- diff $EXTRACTDIR/deppkgs $EXTRACTDIR/libpkgs | fgrep '>'
-fi
-
-
-
if [[ "$basedir" != "" ]] ; then
print
if [[ -f $EXTRACTDIR/elflist ]] ; then
@@ -530,13 +530,78 @@
fi
fi
+# Plugin section.
+#
+# Plugins should live in checkpkg.d subdirectory in the same directory in which
+# checkpkg is. Each plugin file name should be an executable and begin with
+# "checkpkg-".
-cleanup
+tmparchives="$tmparchives $TMPARCHIVE"
+done
-print ""
+# All packages have been extracted.
+# Now running all the plugin checks
+
+set_variables_for_individual_package_check "$f"
+
+echo "Running the experimental plugin infrastructure."
+test_suite_ok=1
+checkpkg_scriptname=`basename $0`
+checkpkg_basedir=${0%/${checkpkg_scriptname}}
+plugindir=${checkpkg_basedir}/checkpkg.d
+if [[ "${DEBUG}" != "" ]]; then
+ extra_options="--debug"
+fi
+debugmsg "plugindir: '$plugindir'"
+log_files=""
+if [[ -d "$plugindir" ]]; then
+ # echo plugin dir exists
+ for plugin in "${plugindir}"/checkpkg-*; do
+ if [[ -x "${plugin}" ]]; then
+ debugmsg "Executing: ${plugin} $extra_options -e \"${EXTRACTDIR}\" ${pkgnames}"
+ plugin_base_name=`basename ${plugin}`
+ plugin_log="${EXTRACTDIR}/${plugin_base_name}.log"
+ log_files="${log_files} ${plugin_log}"
+ printf "TEST: ${plugin} running..."
+ ${plugin} $extra_options -e "${EXTRACTDIR}" ${pkgnames} > "${plugin_log}" 2>&1
+ if [[ "$?" -ne 0 ]]; then
+ printf "\rTEST: ${plugin} ${RED}[FAIL]${COLOR_RESET} \\n"
+ test_suite_ok=0
+ else
+ printf "\rTEST: ${plugin} ${GREEN}[OK]${COLOR_RESET} \\n"
+ fi
+ else
+ debugmsg "'${plugin}' is not executable"
+ fi
+ done
+else
+ debugmsg "plugin dir does not exist"
+fi
+
+echo
+for log_file in ${log_files}; do
+ if [[ -s "${log_file}" ]]; then
+ echo "LOG START: ${log_file}"
+ echo
+ cat "${log_file}"
+ echo
+ echo "LOG END: ${log_file}"
+ fi
done
+echo
+if [[ ${test_suite_ok} -ne 1 ]]; then
+ errmsg "One or more tests have failed."
+else
+ print "All tests were successful."
+fi
+
+print ""
+
+# Cleaning up after all packages
+cleanup
+
if [ -s $SETDEPS.missing ]; then
print "Doing late evaluations of package dependencies."
while read mdep; do
@@ -551,19 +616,4 @@
done < $SETDEPS.missing
fi
-if [ -s $SETLIBS.missing ]; then
- print "Doing late evaluations of package library dependencies."
- while read ldep; do
- lib=`echo $ldep | nawk '{print $1}'`
- [ "$lib" = "libm.so.2" ] && continue
- pkg=`echo $ldep | nawk '{print $2}'`
- /usr/bin/grep "[/=]$lib[ =]" $SETLIBS >/dev/null
- if [ $? -ne 0 ]; then
- errmsg "Couldn't find a package providing $lib"
- else
- print "A package in the set being evaluated provides $lib"
- fi
- done < $SETLIBS.missing
-fi
-
cleanupset
Property changes on: csw/mgar/gar/v2/bin/checkpkg
___________________________________________________________________
Added: svn:keywords
+ Id
Deleted: csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-dummy.py
===================================================================
--- csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg-dummy.py 2010-01-04 03:57:34 UTC (rev 7855)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-dummy.py 2010-01-04 10:28:15 UTC (rev 7856)
@@ -1,21 +0,0 @@
-#!/opt/csw/bin/python2.6
-# $Id$
-
-import checkpkg
-import os.path
-import logging
-
-def main():
- options, args = checkpkg.GetOptions()
- if not os.path.isdir(options.extractdir):
- raise checkpkg.PackageError("The extract base directory doesn't exist: %s" % options.extractdir)
- for pkgname in args:
- pkgpath = os.path.join(options.extractdir, pkgname)
- if not os.path.isdir(pkgpath):
- raise checkpkg.PackageError("The package directory doesn't exist: %s" % pkgpath)
- logging.debug("Dummy plugin says the package %s is extracted to %s",
- pkgname, options.extractdir)
-
-
-if __name__ == '__main__':
- main()
Copied: csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-dummy.py (from rev 7855, csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg-dummy.py)
===================================================================
--- csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-dummy.py (rev 0)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-dummy.py 2010-01-04 10:28:15 UTC (rev 7856)
@@ -0,0 +1,21 @@
+#!/opt/csw/bin/python2.6
+# $Id$
+
+import checkpkg
+import os.path
+import logging
+
+def main():
+ options, args = checkpkg.GetOptions()
+ if not os.path.isdir(options.extractdir):
+ raise checkpkg.PackageError("The extract base directory doesn't exist: %s" % options.extractdir)
+ for pkgname in args:
+ pkgpath = os.path.join(options.extractdir, pkgname)
+ if not os.path.isdir(pkgpath):
+ raise checkpkg.PackageError("The package directory doesn't exist: %s" % pkgpath)
+ logging.debug("Dummy plugin says the package %s is extracted to %s",
+ pkgname, options.extractdir)
+
+
+if __name__ == '__main__':
+ main()
Deleted: csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-libs.py
===================================================================
--- csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg-libs.py 2010-01-04 03:57:34 UTC (rev 7855)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-libs.py 2010-01-04 10:28:15 UTC (rev 7856)
@@ -1,225 +0,0 @@
-#!/opt/csw/bin/python2.6
-#
-# $Id$
-#
-# A check for dependencies between shared libraries.
-#
-# This is currently more of a prototype than a mature program, but it has some
-# unit tests and it appears to be working. The main problem is that it's not
-# divided into smaller testable sections.
-
-import checkpkg
-import os
-import os.path
-import copy
-import re
-import subprocess
-import logging
-import sys
-import textwrap
-
-DUMP_BIN = "/usr/ccs/bin/dump"
-
-def GetIsalist():
- args = ["isalist"]
- isalist_proc = subprocess.Popen(args, stdout=subprocess.PIPE)
- stdout, stderr = isalist_proc.communicate()
- ret = isalist_proc.wait()
- if ret:
- logging.error("Calling isalist has failed.")
- isalist = re.split(r"\s+", stdout.strip())
- return isalist
-
-
-def main():
- result_ok = True
- errors = []
- options, args = checkpkg.GetOptions()
- pkgnames = args
- if options.debug:
- logging.basicConfig(level=logging.DEBUG)
- else:
- logging.basicConfig(level=logging.INFO)
- checkers = []
- for pkgname in pkgnames:
- checker = checkpkg.CheckpkgBase(options.extractdir, pkgname)
- checkers.append(checker)
- binaries = []
- binaries_by_pkgname = {}
- sonames_by_pkgname = {}
- pkg_by_any_filename = {}
- for checker in checkers:
- pkg_binary_paths = checker.ListBinaries()
- binaries_base = [os.path.split(x)[1] for x in pkg_binary_paths]
- binaries_by_pkgname[checker.pkgname] = binaries_base
- binaries.extend(pkg_binary_paths)
- for filename in checker.GetAllFilenames():
- pkg_by_any_filename[filename] = checker.pkgname
- # Making the binaries unique
- binaries = set(binaries)
- ws_re = re.compile(r"\s+")
-
- # man ld.so.1 for more info on this hack
- env = copy.copy(os.environ)
- env["LD_NOAUXFLTR"] = "1"
- needed_sonames_by_binary = {}
- filenames_by_soname = {}
- # Assembling a data structure with the data about binaries.
- # {
- # <binary1 name>: { checkpkg.NEEDED_SONAMES: [...],
- # checkpkg.RUNPATH: [...]},
- # <binary2 name>: ...,
- # ...
- # }
- #
- for binary in binaries:
- binary_base_name = binary.split("/")[-1]
- args = [DUMP_BIN, "-Lv", binary]
- dump_proc = subprocess.Popen(args, stdout=subprocess.PIPE, env=env)
- stdout, stderr = dump_proc.communicate()
- ret = dump_proc.wait()
- binary_data = checkpkg.ParseDumpOutput(stdout)
- needed_sonames_by_binary[binary_base_name] = binary_data
- if checkpkg.SONAME not in binary_data:
- logging.info("The %s shared library doesn't provide a SONAME.",
- binary_base_name)
- # The shared library doesn't tell its SONAME. We're guessing it's the
- # same as the base file name.
- binary_data[checkpkg.SONAME] = binary_base_name
- filenames_by_soname[binary_data[checkpkg.SONAME]] = binary_base_name
-
- isalist = GetIsalist()
-
- # Building indexes by soname to simplify further processing
- # These are indexes "by soname".
- (needed_sonames,
- binaries_by_soname,
- runpath_by_needed_soname) = checkpkg.BuildIndexesBySoname(
- needed_sonames_by_binary)
-
- pkgmap = checkpkg.SystemPkgmap()
- logging.debug("Determining the soname-package relationships.")
- # lines by soname is an equivalent of $EXTRACTDIR/shortcatalog
- lines_by_soname = checkpkg.GetLinesBySoname(
- pkgmap, needed_sonames, runpath_by_needed_soname, isalist)
-
- # Creating a map from files to packages.
- pkgs_by_filename = {}
- for soname, line in lines_by_soname.iteritems():
- # TODO: Find all the packages, not just the last field.
- fields = re.split(ws_re, line.strip())
- # For now, we'll assume that the last field is the package.
- pkgname = fields[-1]
- pkgs_by_filename[soname] = pkgname
-
- # A shared object dependency/provisioning report, plus checking.
- #
- # This section is somewhat overlapping with checkpkg.AnalyzeDependencies(),
- # it has a different purpose: it reports the relationships between shared
- # libraries, binaries using them and packages providing them. Ideally, the
- # same bit of code with do checking and reporting.
- #
- # TODO: Rewrite this using cheetah templates
- if needed_sonames:
- print "Analysis of sonames needed by the package set:"
- binaries_with_missing_sonames = set([])
- for soname in needed_sonames:
- logging.debug("Analyzing: %s", soname)
- if soname in filenames_by_soname:
- print "%s is provided by the package itself" % soname
- elif soname in lines_by_soname:
- print ("%s is provided by %s and required by:"
- % (soname,
- repr(pkgs_by_filename[soname])))
- filename_lines = " ".join(sorted(binaries_by_soname[soname]))
- for line in textwrap.wrap(filename_lines, 70):
- print " ", line
- else:
- print ("%s is required by %s, but we don't know what provides it."
- % (soname, binaries_by_soname[soname]))
- for binary in binaries_by_soname[soname]:
- binaries_with_missing_sonames.add(binary)
- if soname in checkpkg.ALLOWED_ORPHAN_SONAMES:
- print "However, it's a whitelisted soname."
- else:
- errors.append(
- checkpkg.Error("%s is required by %s, but "
- "we don't know what provides it."
- % (soname, binaries_by_soname[soname])))
- if binaries_with_missing_sonames:
- print "The following are binaries with missing sonames:"
- binary_lines = " ".join(sorted(binaries_with_missing_sonames))
- for line in textwrap.wrap(binary_lines, 70):
- print " ", line
- print
-
- dependent_pkgs = {}
- for checker in checkers:
- pkgname = checker.pkgname
- declared_dependencies = checker.GetDependencies()
- if options.debug:
- sanitized_pkgname = pkgname.replace("-", "_")
- data_file_name = "/var/tmp/checkpkg_test_data_%s.py" % sanitized_pkgname
- logging.warn("Saving test data to %s." % repr(data_file_name))
- test_fd = open(data_file_name, "w")
- print >>test_fd, "# Testing data for %s" % pkgname
- print >>test_fd, "# $Id$"
- print >>test_fd, "DATA_PKGNAME =", repr(pkgname)
- print >>test_fd, "DATA_DECLARED_DEPENDENCIES =", repr(declared_dependencies)
- print >>test_fd, "DATA_BINARIES_BY_PKGNAME =", repr(binaries_by_pkgname)
- print >>test_fd, "DATA_NEEDED_SONAMES_BY_BINARY =", repr(needed_sonames_by_binary)
- print >>test_fd, "DATA_PKGS_BY_FILENAME =", repr(pkgs_by_filename)
- print >>test_fd, "DATA_FILENAMES_BY_SONAME =", repr(filenames_by_soname)
- print >>test_fd, "DATA_PKG_BY_ANY_FILENAME =", repr(pkg_by_any_filename)
- print >>test_fd, "DATA_LINES_BY_SONAME =", repr(lines_by_soname)
- print >>test_fd, "DATA_PKGMAP_CACHE =", repr(pkgmap.cache)
- print >>test_fd, "DATA_BINARIES_BY_SONAME =", repr(binaries_by_soname)
- print >>test_fd, "DATA_ISALIST =", repr(isalist)
- test_fd.close()
-
- missing_deps, surplus_deps, orphan_sonames = checkpkg.AnalyzeDependencies(
- pkgname,
- declared_dependencies,
- binaries_by_pkgname,
- needed_sonames_by_binary,
- pkgs_by_filename,
- filenames_by_soname,
- pkg_by_any_filename)
-
- # TODO: Rewrite this using cheetah templates.
- print "%s:" % pkgname
- msg_printed = False
- if missing_deps:
- print "SUGGESTION: you may want to add some or all of the following as depends:"
- print " (Feel free to ignore SUNW or SPRO packages)"
- for dep_pkgname in sorted(missing_deps):
- print ">", dep_pkgname
- msg_printed = True
- if surplus_deps:
- print "The following packages might be unnecessary dependencies:"
- for dep_pkgname in surplus_deps:
- print "? ", dep_pkgname
- msg_printed = True
- if orphan_sonames:
- print "The following sonames don't belong to any package:"
- for soname in sorted(orphan_sonames):
- errors.append(checkpkg.Error("The following soname does't belong to "
- "any package: %s" % soname))
- print "! ", soname
- msg_printed = True
- if not msg_printed:
- print "+ Dependencies of %s look good." % pkgname
- print
-
- if errors:
- for error in errors:
- logging.error(error)
- sys.exit(1)
- else:
- sys.exit(0)
-
-
-if __name__ == '__main__':
- main()
-
-# vim:set sw=2 ts=2 sts=2 expandtab:
Copied: csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-libs.py (from rev 7855, csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg-libs.py)
===================================================================
--- csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-libs.py (rev 0)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-libs.py 2010-01-04 10:28:15 UTC (rev 7856)
@@ -0,0 +1,225 @@
+#!/opt/csw/bin/python2.6
+#
+# $Id$
+#
+# A check for dependencies between shared libraries.
+#
+# This is currently more of a prototype than a mature program, but it has some
+# unit tests and it appears to be working. The main problem is that it's not
+# divided into smaller testable sections.
+
+import checkpkg
+import os
+import os.path
+import copy
+import re
+import subprocess
+import logging
+import sys
+import textwrap
+
+DUMP_BIN = "/usr/ccs/bin/dump"
+
+def GetIsalist():
+ args = ["isalist"]
+ isalist_proc = subprocess.Popen(args, stdout=subprocess.PIPE)
+ stdout, stderr = isalist_proc.communicate()
+ ret = isalist_proc.wait()
+ if ret:
+ logging.error("Calling isalist has failed.")
+ isalist = re.split(r"\s+", stdout.strip())
+ return isalist
+
+
+def main():
+ result_ok = True
+ errors = []
+ options, args = checkpkg.GetOptions()
+ pkgnames = args
+ if options.debug:
+ logging.basicConfig(level=logging.DEBUG)
+ else:
+ logging.basicConfig(level=logging.INFO)
+ checkers = []
+ for pkgname in pkgnames:
+ checker = checkpkg.CheckpkgBase(options.extractdir, pkgname)
+ checkers.append(checker)
+ binaries = []
+ binaries_by_pkgname = {}
+ sonames_by_pkgname = {}
+ pkg_by_any_filename = {}
+ for checker in checkers:
+ pkg_binary_paths = checker.ListBinaries()
+ binaries_base = [os.path.split(x)[1] for x in pkg_binary_paths]
+ binaries_by_pkgname[checker.pkgname] = binaries_base
+ binaries.extend(pkg_binary_paths)
+ for filename in checker.GetAllFilenames():
+ pkg_by_any_filename[filename] = checker.pkgname
+ # Making the binaries unique
+ binaries = set(binaries)
+ ws_re = re.compile(r"\s+")
+
+ # man ld.so.1 for more info on this hack
+ env = copy.copy(os.environ)
+ env["LD_NOAUXFLTR"] = "1"
+ needed_sonames_by_binary = {}
+ filenames_by_soname = {}
+ # Assembling a data structure with the data about binaries.
+ # {
+ # <binary1 name>: { checkpkg.NEEDED_SONAMES: [...],
+ # checkpkg.RUNPATH: [...]},
+ # <binary2 name>: ...,
+ # ...
+ # }
+ #
+ for binary in binaries:
+ binary_base_name = binary.split("/")[-1]
+ args = [DUMP_BIN, "-Lv", binary]
+ dump_proc = subprocess.Popen(args, stdout=subprocess.PIPE, env=env)
+ stdout, stderr = dump_proc.communicate()
+ ret = dump_proc.wait()
+ binary_data = checkpkg.ParseDumpOutput(stdout)
+ needed_sonames_by_binary[binary_base_name] = binary_data
+ if checkpkg.SONAME not in binary_data:
+ logging.info("The %s shared library doesn't provide a SONAME.",
+ binary_base_name)
+ # The shared library doesn't tell its SONAME. We're guessing it's the
+ # same as the base file name.
+ binary_data[checkpkg.SONAME] = binary_base_name
+ filenames_by_soname[binary_data[checkpkg.SONAME]] = binary_base_name
+
+ isalist = GetIsalist()
+
+ # Building indexes by soname to simplify further processing
+ # These are indexes "by soname".
+ (needed_sonames,
+ binaries_by_soname,
+ runpath_by_needed_soname) = checkpkg.BuildIndexesBySoname(
+ needed_sonames_by_binary)
+
+ pkgmap = checkpkg.SystemPkgmap()
+ logging.debug("Determining the soname-package relationships.")
+ # lines by soname is an equivalent of $EXTRACTDIR/shortcatalog
+ lines_by_soname = checkpkg.GetLinesBySoname(
+ pkgmap, needed_sonames, runpath_by_needed_soname, isalist)
+
+ # Creating a map from files to packages.
+ pkgs_by_filename = {}
+ for soname, line in lines_by_soname.iteritems():
+ # TODO: Find all the packages, not just the last field.
+ fields = re.split(ws_re, line.strip())
+ # For now, we'll assume that the last field is the package.
+ pkgname = fields[-1]
+ pkgs_by_filename[soname] = pkgname
+
+ # A shared object dependency/provisioning report, plus checking.
+ #
+ # This section is somewhat overlapping with checkpkg.AnalyzeDependencies(),
+ # it has a different purpose: it reports the relationships between shared
+ # libraries, binaries using them and packages providing them. Ideally, the
+ # same bit of code with do checking and reporting.
+ #
+ # TODO: Rewrite this using cheetah templates
+ if needed_sonames:
+ print "Analysis of sonames needed by the package set:"
+ binaries_with_missing_sonames = set([])
+ for soname in needed_sonames:
+ logging.debug("Analyzing: %s", soname)
+ if soname in filenames_by_soname:
+ print "%s is provided by the package itself" % soname
+ elif soname in lines_by_soname:
+ print ("%s is provided by %s and required by:"
+ % (soname,
+ repr(pkgs_by_filename[soname])))
+ filename_lines = " ".join(sorted(binaries_by_soname[soname]))
+ for line in textwrap.wrap(filename_lines, 70):
+ print " ", line
+ else:
+ print ("%s is required by %s, but we don't know what provides it."
+ % (soname, binaries_by_soname[soname]))
+ for binary in binaries_by_soname[soname]:
+ binaries_with_missing_sonames.add(binary)
+ if soname in checkpkg.ALLOWED_ORPHAN_SONAMES:
+ print "However, it's a whitelisted soname."
+ else:
+ errors.append(
+ checkpkg.Error("%s is required by %s, but "
+ "we don't know what provides it."
+ % (soname, binaries_by_soname[soname])))
+ if binaries_with_missing_sonames:
+ print "The following are binaries with missing sonames:"
+ binary_lines = " ".join(sorted(binaries_with_missing_sonames))
+ for line in textwrap.wrap(binary_lines, 70):
+ print " ", line
+ print
+
+ dependent_pkgs = {}
+ for checker in checkers:
+ pkgname = checker.pkgname
+ declared_dependencies = checker.GetDependencies()
+ if options.debug:
+ sanitized_pkgname = pkgname.replace("-", "_")
+ data_file_name = "/var/tmp/checkpkg_test_data_%s.py" % sanitized_pkgname
+ logging.warn("Saving test data to %s." % repr(data_file_name))
+ test_fd = open(data_file_name, "w")
+ print >>test_fd, "# Testing data for %s" % pkgname
+ print >>test_fd, "# $Id$"
+ print >>test_fd, "DATA_PKGNAME =", repr(pkgname)
+ print >>test_fd, "DATA_DECLARED_DEPENDENCIES =", repr(declared_dependencies)
+ print >>test_fd, "DATA_BINARIES_BY_PKGNAME =", repr(binaries_by_pkgname)
+ print >>test_fd, "DATA_NEEDED_SONAMES_BY_BINARY =", repr(needed_sonames_by_binary)
+ print >>test_fd, "DATA_PKGS_BY_FILENAME =", repr(pkgs_by_filename)
+ print >>test_fd, "DATA_FILENAMES_BY_SONAME =", repr(filenames_by_soname)
+ print >>test_fd, "DATA_PKG_BY_ANY_FILENAME =", repr(pkg_by_any_filename)
+ print >>test_fd, "DATA_LINES_BY_SONAME =", repr(lines_by_soname)
+ print >>test_fd, "DATA_PKGMAP_CACHE =", repr(pkgmap.cache)
+ print >>test_fd, "DATA_BINARIES_BY_SONAME =", repr(binaries_by_soname)
+ print >>test_fd, "DATA_ISALIST =", repr(isalist)
+ test_fd.close()
+
+ missing_deps, surplus_deps, orphan_sonames = checkpkg.AnalyzeDependencies(
+ pkgname,
+ declared_dependencies,
+ binaries_by_pkgname,
+ needed_sonames_by_binary,
+ pkgs_by_filename,
+ filenames_by_soname,
+ pkg_by_any_filename)
+
+ # TODO: Rewrite this using cheetah templates.
+ print "%s:" % pkgname
+ msg_printed = False
+ if missing_deps:
+ print "SUGGESTION: you may want to add some or all of the following as depends:"
+ print " (Feel free to ignore SUNW or SPRO packages)"
+ for dep_pkgname in sorted(missing_deps):
+ print ">", dep_pkgname
+ msg_printed = True
+ if surplus_deps:
+ print "The following packages might be unnecessary dependencies:"
+ for dep_pkgname in surplus_deps:
+ print "? ", dep_pkgname
+ msg_printed = True
+ if orphan_sonames:
+ print "The following sonames don't belong to any package:"
+ for soname in sorted(orphan_sonames):
+ errors.append(checkpkg.Error("The following soname does't belong to "
+ "any package: %s" % soname))
+ print "! ", soname
+ msg_printed = True
+ if not msg_printed:
+ print "+ Dependencies of %s look good." % pkgname
+ print
+
+ if errors:
+ for error in errors:
+ logging.error(error)
+ sys.exit(1)
+ else:
+ sys.exit(0)
+
+
+if __name__ == '__main__':
+ main()
+
+# vim:set sw=2 ts=2 sts=2 expandtab:
Deleted: csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-obsolete-deps.py
===================================================================
--- csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg-obsolete-deps.py 2010-01-04 03:57:34 UTC (rev 7855)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-obsolete-deps.py 2010-01-04 10:28:15 UTC (rev 7856)
@@ -1,43 +0,0 @@
-#!/opt/csw/bin/python2.6
-# $Id$
-
-import checkpkg
-import logging
-import os.path
-import sys
-
-OBSOLETE_DEPS = {
- # "CSWfoo": {
- # "hint": "Do this...",
- # "url": "http://www.opencsw.org/bugtrack/view.php?id=..."
- # },
- "CSWpython-rt": {
- "hint": "CSWpython-rt is deprecated, use CSWpython instead.",
- "url": "http://www.opencsw.org/bugtrack/view.php?id=4031"
- },
-}
-
-def main():
- options, args = checkpkg.GetOptions()
- ok = True
- for pkgname in args:
- pkgpath = os.path.join(options.extractdir, pkgname)
- checker = checkpkg.CheckpkgBase(options.extractdir, pkgname)
- deps = set(checker.GetDependencies())
- obsolete_pkg_deps = deps.intersection(set(OBSOLETE_DEPS))
- if obsolete_pkg_deps:
- ok = False
- for pkg in obsolete_pkg_deps:
- print ("ERROR: Package %s should not depend on %s."
- % (checker.pkgname, pkg))
- if "hint" in OBSOLETE_DEPS[pkg]:
- print "Hint:", OBSOLETE_DEPS[pkg]["hint"]
- if "url" in OBSOLETE_DEPS[pkg]:
- print "URL:", OBSOLETE_DEPS[pkg]["url"]
- if ok:
- sys.exit(0)
- else:
- sys.exit(1)
-
-if __name__ == '__main__':
- main()
Copied: csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-obsolete-deps.py (from rev 7855, csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg-obsolete-deps.py)
===================================================================
--- csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-obsolete-deps.py (rev 0)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-obsolete-deps.py 2010-01-04 10:28:15 UTC (rev 7856)
@@ -0,0 +1,43 @@
+#!/opt/csw/bin/python2.6
+# $Id$
+
+import checkpkg
+import logging
+import os.path
+import sys
+
+OBSOLETE_DEPS = {
+ # "CSWfoo": {
+ # "hint": "Do this...",
+ # "url": "http://www.opencsw.org/bugtrack/view.php?id=..."
+ # },
+ "CSWpython-rt": {
+ "hint": "CSWpython-rt is deprecated, use CSWpython instead.",
+ "url": "http://www.opencsw.org/bugtrack/view.php?id=4031"
+ },
+}
+
+def main():
+ options, args = checkpkg.GetOptions()
+ ok = True
+ for pkgname in args:
+ pkgpath = os.path.join(options.extractdir, pkgname)
+ checker = checkpkg.CheckpkgBase(options.extractdir, pkgname)
+ deps = set(checker.GetDependencies())
+ obsolete_pkg_deps = deps.intersection(set(OBSOLETE_DEPS))
+ if obsolete_pkg_deps:
+ ok = False
+ for pkg in obsolete_pkg_deps:
+ print ("ERROR: Package %s should not depend on %s."
+ % (checker.pkgname, pkg))
+ if "hint" in OBSOLETE_DEPS[pkg]:
+ print "Hint:", OBSOLETE_DEPS[pkg]["hint"]
+ if "url" in OBSOLETE_DEPS[pkg]:
+ print "URL:", OBSOLETE_DEPS[pkg]["url"]
+ if ok:
+ sys.exit(0)
+ else:
+ sys.exit(1)
+
+if __name__ == '__main__':
+ main()
Deleted: csw/mgar/gar/v2/bin/checkpkg.d/checkpkg.py
===================================================================
--- csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg.py 2010-01-04 03:57:34 UTC (rev 7855)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg.py 2010-01-04 10:28:15 UTC (rev 7856)
@@ -1,486 +0,0 @@
-# $Id$
-#
-# This is the checkpkg library, common for all checkpkg tests written in
-# Python.
-
-import itertools
-import logging
-import optparse
-import os
-import os.path
-import re
-import socket
-import sqlite3
-import subprocess
-
-SYSTEM_PKGMAP = "/var/sadm/install/contents"
-WS_RE = re.compile(r"\s+")
-NEEDED_SONAMES = "needed sonames"
-RUNPATH = "runpath"
-SONAME = "soname"
-CONFIG_MTIME = "mtime"
-DO_NOT_REPORT_SURPLUS = set([u"CSWcommon", u"CSWcswclassutils", u"CSWisaexec"])
-DO_NOT_REPORT_MISSING = set([u"SUNWlibC", u"SUNWcsl", u"SUNWlibms",
- u"*SUNWcslr", u"*SUNWlibC", u"*SUNWlibms"])
-
-# This shared library is present on Solaris 10 on amd64, but it's missing on
-# Solaris 8 on i386. It's okay if it's missing.
-ALLOWED_ORPHAN_SONAMES = set([u"libm.so.2"])
-
-class Error(Exception):
- pass
-
-
-class ConfigurationError(Error):
- pass
-
-
-class PackageError(Error):
- pass
-
-
-def GetOptions():
- parser = optparse.OptionParser()
- parser.add_option("-e", dest="extractdir",
- help="The directory into which the package has been extracted")
- parser.add_option("-d", "--debug", dest="debug",
- default=False, action="store_true",
- help="Turn on debugging messages")
- (options, args) = parser.parse_args()
- if not options.extractdir:
- raise ConfigurationError("ERROR: -e option is missing.")
- # Using set() to make the arguments unique.
- return options, set(args)
-
-
-class CheckpkgBase(object):
- """This class has functionality overlapping with DirectoryFormatPackage
- from the opencsw.py library. The classes should be merged.
- """
-
- def __init__(self, extractdir, pkgname):
- self.extractdir = extractdir
- self.pkgname = pkgname
- self.pkgpath = os.path.join(self.extractdir, self.pkgname)
-
- def CheckPkgpathExists(self):
- if not os.path.isdir(self.pkgpath):
- raise PackageError("%s does not exist or is not a directory"
- % self.pkgpath)
-
- def ListBinaries(self):
- """Shells out to list all the binaries from a given package.
-
- Original checkpkg code:
-
- # #########################################
- # # find all executables and dynamic libs,and list their filenames.
- # listbinaries() {
- # if [ ! -d $1 ] ; then
- # print errmsg $1 not a directory
- # rm -rf $EXTRACTDIR
- # exit 1
- # fi
- #
- # find $1 -print | xargs file |grep ELF |nawk -F: '{print $1}'
- # }
- """
- self.CheckPkgpathExists()
- find_tmpl = "find %s -print | xargs file | grep ELF | nawk -F: '{print $1}'"
- find_proc = subprocess.Popen(find_tmpl % self.pkgpath,
- shell=True, stdout=subprocess.PIPE)
- stdout, stderr = find_proc.communicate()
- ret = find_proc.wait()
- if ret:
- logging.error("The find command returned an error.")
- return stdout.splitlines()
-
- def GetAllFilenames(self):
- self.CheckPkgpathExists()
- file_basenames = []
- for root, dirs, files in os.walk(self.pkgpath):
- file_basenames.extend(files)
- return file_basenames
-
- def GetDependencies(self):
- fd = open(os.path.join(self.pkgpath, "install", "depend"), "r")
- depends = {}
- for line in fd:
- fields = re.split(WS_RE, line)
- if fields[0] == "P":
- depends[fields[1]] = " ".join(fields[1:])
- fd.close()
- return depends
-
-
-class SystemPkgmap(object):
- """A class to hold and manipulate the /var/sadm/install/contents file.
-
- TODO: Implement timestamp checking and refreshing the cache.
- """
-
- STOP_PKGS = ["SUNWbcp", "SUNWowbcp", "SUNWucb"]
- CHECKPKG_DIR = ".checkpkg"
- SQLITE3_DBNAME_TMPL = "var-sadm-install-contents-cache-%s"
-
- def __init__(self):
- """There is no need to re-parse it each time.
-
- Read it slowly the first time and cache it for later."""
- self.cache = {}
- self.checkpkg_dir = os.path.join(os.environ["HOME"], self.CHECKPKG_DIR)
- self.fqdn = socket.getfqdn()
- self.db_path = os.path.join(self.checkpkg_dir,
- self.SQLITE3_DBNAME_TMPL % self.fqdn)
- self.file_mtime = None
- self.cache_mtime = None
- if os.path.exists(self.db_path):
- logging.debug("Connecting to the %s database.", self.db_path)
- self.conn = sqlite3.connect(self.db_path)
- if not self.IsDatabaseUpToDate():
- self.PurgeDatabase()
- self.PopulateDatabase()
- else:
- print "Building a cache of /var/sadm/install/contents."
- print "The cache will be kept in %s." % self.db_path
- if not os.path.exists(self.checkpkg_dir):
- logging.debug("Creating %s", self.checkpkg_dir)
- os.mkdir(self.checkpkg_dir)
- self.conn = sqlite3.connect(self.db_path)
- c = self.conn.cursor()
- c.execute("""
- CREATE TABLE systempkgmap (
- id INTEGER PRIMARY KEY,
- basename TEXT,
- path TEXT,
- line TEXT
- );
- """)
- logging.debug("Creating the config table.")
- c.execute("""
- CREATE TABLE config (
- key VARCHAR(255) PRIMARY KEY,
- float_value FLOAT,
- str_value VARCHAR(255)
- );
- """)
- self.PopulateDatabase()
-
- def PopulateDatabase(self):
- """Imports data into the database.
-
- Original bit of code from checkpkg:
-
- egrep -v 'SUNWbcp|SUNWowbcp|SUNWucb' /var/sadm/install/contents |
- fgrep -f $EXTRACTDIR/liblist >$EXTRACTDIR/shortcatalog
- """
-
- system_pkgmap_fd = open(SYSTEM_PKGMAP, "r")
- stop_re = re.compile("(%s)" % "|".join(self.STOP_PKGS))
- # Creating a data structure:
- # soname - {<path1>: <line1>, <path2>: <line2>, ...}
- logging.debug("Building sqlite3 cache db of the %s file",
- SYSTEM_PKGMAP)
- c = self.conn.cursor()
- count = itertools.count()
- for line in system_pkgmap_fd:
- i = count.next()
- if not i % 1000:
- print "\r%s" % i,
- if stop_re.search(line):
- continue
- fields = re.split(WS_RE, line)
- pkgmap_entry_path = fields[0].split("=")[0]
- pkgmap_entry_dir, pkgmap_entry_base_name = os.path.split(pkgmap_entry_path)
- sql = "INSERT INTO systempkgmap (basename, path, line) VALUES (?, ?, ?);"
- c.execute(sql, (pkgmap_entry_base_name, pkgmap_entry_dir, line.strip()))
- print
- print "Creating the main database index."
- sql = "CREATE INDEX basename_idx ON systempkgmap(basename);"
- c.execute(sql)
- self.SetDatabaseMtime()
- self.conn.commit()
-
- def SetDatabaseMtime(self):
- c = self.conn.cursor()
- sql = "DELETE FROM config WHERE key = ?;"
- c.execute(sql, [CONFIG_MTIME])
- mtime = self.GetFileMtime()
- logging.debug("Inserting the mtime (%s) into the database.", mtime)
- sql = """
- INSERT INTO config (key, float_value)
- VALUES (?, ?);
- """
- c.execute(sql, [CONFIG_MTIME, mtime])
-
- def GetPkgmapLineByBasename(self, filename):
- if filename in self.cache:
- return self.cache[filename]
- sql = "SELECT path, line FROM systempkgmap WHERE basename = ?;"
- c = self.conn.cursor()
- c.execute(sql, [filename])
- lines = {}
- for row in c:
- lines[row[0]] = row[1]
- if len(lines) == 0:
- logging.debug("Cache doesn't contain filename %s", filename)
- self.cache[filename] = lines
- return lines
-
- def GetDatabaseMtime(self):
- if not self.cache_mtime:
- sql = """
- SELECT float_value FROM config
- WHERE key = ?;
- """
- c = self.conn.cursor()
- c.execute(sql, [CONFIG_MTIME])
- row = c.fetchone()
- if not row:
- # raise ConfigurationError("Could not find the mtime setting")
- self.cache_mtime = 1
- else:
- self.cache_mtime = row[0]
- return self.cache_mtime
-
- def GetFileMtime(self):
- if not self.file_mtime:
- stat_data = os.stat(SYSTEM_PKGMAP)
- self.file_mtime = stat_data.st_mtime
- return self.file_mtime
-
- def IsDatabaseUpToDate(self):
- f_mtime = self.GetFileMtime()
- d_mtime = self.GetDatabaseMtime()
- logging.debug("f_mtime", f_mtime, "d_time", d_mtime)
- return self.GetFileMtime() <= self.GetDatabaseMtime()
-
- def PurgeDatabase(self):
- c = self.conn.cursor()
- sql = "DELETE FROM config;"
- c.execute(sql)
- sql = "DELETE FROM systempkgmap;"
- c.execute(sql)
- sql = "DROP INDEX basename_idx;"
- try:
- c.execute(sql)
- except sqlite3.OperationalError, e:
- logging.warn(e)
-
-def SharedObjectDependencies(pkgname,
- binaries_by_pkgname,
- needed_sonames_by_binary,
- pkgs_by_soname,
- filenames_by_soname,
- pkg_by_any_filename):
- """This is one of the more obscure and more important pieces of code.
-
- I tried to make it simpler, but given that the operations here involve
- whole sets of packages, it's not easy.
- """
- so_dependencies = set()
- orphan_sonames = set()
- self_provided = set()
- for binary in binaries_by_pkgname[pkgname]:
- needed_sonames = needed_sonames_by_binary[binary][NEEDED_SONAMES]
- for soname in needed_sonames:
- if soname in filenames_by_soname:
- filename = filenames_by_soname[soname]
- pkg = pkg_by_any_filename[filename]
- self_provided.add(soname)
- so_dependencies.add(pkg)
- elif soname in pkgs_by_soname:
- so_dependencies.add(pkgs_by_soname[soname])
- else:
- orphan_sonames.add(soname)
- return so_dependencies, self_provided, orphan_sonames
-
-
-def GuessDepsByFilename(pkgname, pkg_by_any_filename):
- """Guesses dependencies based on filename regexes."""
- guessed_deps = set()
- patterns = (
- (r".*\.py", u"CSWpython"),
- (r".*\.pl", u"CSWperl"),
- (r".*\.rb", u"CSWruby"),
- )
- for pattern, dep_pkgname in patterns:
- # If any file name matches, add the dep, go to the next pattern/pkg
- # combination.
- pattern_re = re.compile("^%s$" % pattern)
- for filename in pkg_by_any_filename:
- if (re.match(pattern_re, filename)
- and
- pkgname == pkg_by_any_filename[filename]):
- guessed_deps.add(dep_pkgname)
- break
- return guessed_deps
-
-
-def GuessDepsByPkgname(pkgname, pkg_by_any_filename):
- # More guessed dependencies: If one package is a substring of another, it
- # might be a hint. For example, CSWmysql51test should depend on CSWmysql51.
- # However, the rt (runtime) packages should not want to depend on the main
- # package.
- guessed_deps = set()
- all_other_pkgs = set(pkg_by_any_filename.values())
- for other_pkg in all_other_pkgs:
- other_pkg = unicode(other_pkg)
- if pkgname == other_pkg:
- continue
- if pkgname.startswith(other_pkg):
- endings = ["devel", "test", "bench", "dev"]
- for ending in endings:
- if pkgname.endswith(ending):
- guessed_deps.add(other_pkg)
- return guessed_deps
-
-
-def AnalyzeDependencies(pkgname,
- declared_dependencies,
- binaries_by_pkgname,
- needed_sonames_by_binary,
- pkgs_by_soname,
- filenames_by_soname,
- pkg_by_any_filename):
- """Gathers and merges dependency results from other functions.
-
- declared_dependencies: Dependencies that the package in question claims to
- have.
-
- binaries_by_pkgname: A dictionary mapping pkgnames (CSWfoo) to binary names
- (without paths)
-
- needed_sonames_by_binary: A dictionary mapping binary file name to
- a dictionary containing: "needed sonames",
- "soname", "rpath". Based on examining the binary
- files within the packages.
-
- pkgs_by_soname: A dictionary mapping sonames to pkgnames, based on the
- contents of the system wide pkgmap
- (/var/sadm/install/contents)
-
- filenames_by_soname: A dictionary mapping shared library sonames to filenames,
- based on files within packages
-
- pkg_by_any_filename: Mapping from file names to packages names, based on the
- contents of the packages under examination.
- """
- declared_dependencies_set = set(declared_dependencies)
-
- so_dependencies, self_provided, orphan_sonames = SharedObjectDependencies(
- pkgname,
- binaries_by_pkgname,
- needed_sonames_by_binary,
- pkgs_by_soname,
- filenames_by_soname,
- pkg_by_any_filename)
- auto_dependencies = reduce(lambda x, y: x.union(y),
- [
- so_dependencies,
- GuessDepsByFilename(pkgname, pkg_by_any_filename),
- GuessDepsByPkgname(pkgname, pkg_by_any_filename),
- ])
- missing_deps = auto_dependencies.difference(declared_dependencies_set)
- # Don't report itself as a suggested dependency.
- missing_deps = missing_deps.difference(set([pkgname]))
- missing_deps = missing_deps.difference(set(DO_NOT_REPORT_MISSING))
- surplus_deps = declared_dependencies_set.difference(auto_dependencies)
- surplus_deps = surplus_deps.difference(DO_NOT_REPORT_SURPLUS)
- orphan_sonames = orphan_sonames.difference(ALLOWED_ORPHAN_SONAMES)
- return missing_deps, surplus_deps, orphan_sonames
-
-
-def ExpandRunpath(runpath, isalist):
- # Emulating $ISALIST expansion
- if '$ISALIST' in runpath:
- expanded_list = [runpath.replace('$ISALIST', isa) for isa in isalist]
- else:
- expanded_list = [runpath]
- return expanded_list
-
-def Emulate64BitSymlinks(runpath_list):
- """Need to emulate the 64 -> amd64, 64 -> sparcv9 symlink
-
- Since we don't know the architecture, we'll adding both amd64 and sparcv9.
- It should be safe.
- """
- symlinked_list = []
- for runpath in runpath_list:
- if "/64" in runpath:
- symlinked_list.append(runpath.replace("/64", "/amd64"))
- symlinked_list.append(runpath.replace("/64", "/sparcv9"))
- else:
- symlinked_list.append(runpath)
- return symlinked_list
-
-
-def GetLinesBySoname(pkgmap, needed_sonames, runpath_by_needed_soname, isalist):
- """Works out which system pkgmap lines correspond to given sonames."""
- lines_by_soname = {}
- for soname in needed_sonames:
- # This is the critical part of the algorithm: it iterates over the
- # runpath and finds the first matching one.
- runpath_found = False
- for runpath in runpath_by_needed_soname[soname]:
- runpath_list = ExpandRunpath(runpath, isalist)
- runpath_list = Emulate64BitSymlinks(runpath_list)
- soname_runpath_data = pkgmap.GetPkgmapLineByBasename(soname)
- logging.debug("%s: will be looking for %s in %s" %
- (soname, runpath_list, soname_runpath_data.keys()))
- for runpath_expanded in runpath_list:
- if runpath_expanded in soname_runpath_data:
- lines_by_soname[soname] = soname_runpath_data[runpath_expanded]
- runpath_found = True
- # This break only goes out of the inner loop,
- # need another one below to finish the outer loop.
- break
- if runpath_found:
- break
- return lines_by_soname
-
-
-def BuildIndexesBySoname(needed_sonames_by_binary):
- """Builds data structures indexed by soname.
-
- Building indexes
- {"foo.so": ["/opt/csw/lib/gcc4", "/opt/csw/lib", ...],
- ...
- }
- """
- needed_sonames = set()
- binaries_by_soname = {}
- runpath_by_needed_soname = {}
- for binary_name, data in needed_sonames_by_binary.iteritems():
- for soname in data[NEEDED_SONAMES]:
- needed_sonames.add(soname)
- if soname not in runpath_by_needed_soname:
- runpath_by_needed_soname[soname] = []
- runpath_by_needed_soname[soname].extend(data[RUNPATH])
- if soname not in binaries_by_soname:
- binaries_by_soname[soname] = set()
- binaries_by_soname[soname].add(binary_name)
- return needed_sonames, binaries_by_soname, runpath_by_needed_soname
-
-
-def ParseDumpOutput(dump_output):
- binary_data = {RUNPATH: [],
- NEEDED_SONAMES: []}
- for line in dump_output.splitlines():
- fields = re.split(WS_RE, line)
- # TODO: Make it a unit test
- # logging.debug("%s says: %s", DUMP_BIN, fields)
- if len(fields) < 3:
- continue
- if fields[1] == "NEEDED":
- binary_data[NEEDED_SONAMES].append(fields[2])
- elif fields[1] == "RUNPATH":
- binary_data[RUNPATH].extend(fields[2].split(":"))
- elif fields[1] == "SONAME":
- binary_data[SONAME] = fields[2]
- # Adding the default runtime path search option.
- binary_data[RUNPATH].append("/usr/lib/$ISALIST")
- binary_data[RUNPATH].append("/usr/lib")
- binary_data[RUNPATH].append("/lib/$ISALIST")
- binary_data[RUNPATH].append("/lib")
- return binary_data
Copied: csw/mgar/gar/v2/bin/checkpkg.d/checkpkg.py (from rev 7855, csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg.py)
===================================================================
--- csw/mgar/gar/v2/bin/checkpkg.d/checkpkg.py (rev 0)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg.py 2010-01-04 10:28:15 UTC (rev 7856)
@@ -0,0 +1,486 @@
+# $Id$
+#
+# This is the checkpkg library, common for all checkpkg tests written in
+# Python.
+
+import itertools
+import logging
+import optparse
+import os
+import os.path
+import re
+import socket
+import sqlite3
+import subprocess
+
+SYSTEM_PKGMAP = "/var/sadm/install/contents"
+WS_RE = re.compile(r"\s+")
+NEEDED_SONAMES = "needed sonames"
+RUNPATH = "runpath"
+SONAME = "soname"
+CONFIG_MTIME = "mtime"
+DO_NOT_REPORT_SURPLUS = set([u"CSWcommon", u"CSWcswclassutils", u"CSWisaexec"])
+DO_NOT_REPORT_MISSING = set([u"SUNWlibC", u"SUNWcsl", u"SUNWlibms",
+ u"*SUNWcslr", u"*SUNWlibC", u"*SUNWlibms"])
+
+# This shared library is present on Solaris 10 on amd64, but it's missing on
+# Solaris 8 on i386. It's okay if it's missing.
+ALLOWED_ORPHAN_SONAMES = set([u"libm.so.2"])
+
+class Error(Exception):
+ pass
+
+
+class ConfigurationError(Error):
+ pass
+
+
+class PackageError(Error):
+ pass
+
+
+def GetOptions():
+ parser = optparse.OptionParser()
+ parser.add_option("-e", dest="extractdir",
+ help="The directory into which the package has been extracted")
+ parser.add_option("-d", "--debug", dest="debug",
+ default=False, action="store_true",
+ help="Turn on debugging messages")
+ (options, args) = parser.parse_args()
+ if not options.extractdir:
+ raise ConfigurationError("ERROR: -e option is missing.")
+ # Using set() to make the arguments unique.
+ return options, set(args)
+
+
+class CheckpkgBase(object):
+ """This class has functionality overlapping with DirectoryFormatPackage
+ from the opencsw.py library. The classes should be merged.
+ """
+
+ def __init__(self, extractdir, pkgname):
+ self.extractdir = extractdir
+ self.pkgname = pkgname
+ self.pkgpath = os.path.join(self.extractdir, self.pkgname)
+
+ def CheckPkgpathExists(self):
+ if not os.path.isdir(self.pkgpath):
+ raise PackageError("%s does not exist or is not a directory"
+ % self.pkgpath)
+
+ def ListBinaries(self):
+ """Shells out to list all the binaries from a given package.
+
+ Original checkpkg code:
+
+ # #########################################
+ # # find all executables and dynamic libs,and list their filenames.
+ # listbinaries() {
+ # if [ ! -d $1 ] ; then
+ # print errmsg $1 not a directory
+ # rm -rf $EXTRACTDIR
+ # exit 1
+ # fi
+ #
+ # find $1 -print | xargs file |grep ELF |nawk -F: '{print $1}'
+ # }
+ """
+ self.CheckPkgpathExists()
+ find_tmpl = "find %s -print | xargs file | grep ELF | nawk -F: '{print $1}'"
+ find_proc = subprocess.Popen(find_tmpl % self.pkgpath,
+ shell=True, stdout=subprocess.PIPE)
+ stdout, stderr = find_proc.communicate()
+ ret = find_proc.wait()
+ if ret:
+ logging.error("The find command returned an error.")
+ return stdout.splitlines()
+
+ def GetAllFilenames(self):
+ self.CheckPkgpathExists()
+ file_basenames = []
+ for root, dirs, files in os.walk(self.pkgpath):
+ file_basenames.extend(files)
+ return file_basenames
+
+ def GetDependencies(self):
+ fd = open(os.path.join(self.pkgpath, "install", "depend"), "r")
+ depends = {}
+ for line in fd:
+ fields = re.split(WS_RE, line)
+ if fields[0] == "P":
+ depends[fields[1]] = " ".join(fields[1:])
+ fd.close()
+ return depends
+
+
+class SystemPkgmap(object):
+ """A class to hold and manipulate the /var/sadm/install/contents file.
+
+ TODO: Implement timestamp checking and refreshing the cache.
+ """
+
+ STOP_PKGS = ["SUNWbcp", "SUNWowbcp", "SUNWucb"]
+ CHECKPKG_DIR = ".checkpkg"
+ SQLITE3_DBNAME_TMPL = "var-sadm-install-contents-cache-%s"
+
+ def __init__(self):
+ """There is no need to re-parse it each time.
+
+ Read it slowly the first time and cache it for later."""
+ self.cache = {}
+ self.checkpkg_dir = os.path.join(os.environ["HOME"], self.CHECKPKG_DIR)
+ self.fqdn = socket.getfqdn()
+ self.db_path = os.path.join(self.checkpkg_dir,
+ self.SQLITE3_DBNAME_TMPL % self.fqdn)
+ self.file_mtime = None
+ self.cache_mtime = None
+ if os.path.exists(self.db_path):
+ logging.debug("Connecting to the %s database.", self.db_path)
+ self.conn = sqlite3.connect(self.db_path)
+ if not self.IsDatabaseUpToDate():
+ self.PurgeDatabase()
+ self.PopulateDatabase()
+ else:
+ print "Building a cache of /var/sadm/install/contents."
+ print "The cache will be kept in %s." % self.db_path
+ if not os.path.exists(self.checkpkg_dir):
+ logging.debug("Creating %s", self.checkpkg_dir)
+ os.mkdir(self.checkpkg_dir)
+ self.conn = sqlite3.connect(self.db_path)
+ c = self.conn.cursor()
+ c.execute("""
+ CREATE TABLE systempkgmap (
+ id INTEGER PRIMARY KEY,
+ basename TEXT,
+ path TEXT,
+ line TEXT
+ );
+ """)
+ logging.debug("Creating the config table.")
+ c.execute("""
+ CREATE TABLE config (
+ key VARCHAR(255) PRIMARY KEY,
+ float_value FLOAT,
+ str_value VARCHAR(255)
+ );
+ """)
+ self.PopulateDatabase()
+
+ def PopulateDatabase(self):
+ """Imports data into the database.
+
+ Original bit of code from checkpkg:
+
+ egrep -v 'SUNWbcp|SUNWowbcp|SUNWucb' /var/sadm/install/contents |
+ fgrep -f $EXTRACTDIR/liblist >$EXTRACTDIR/shortcatalog
+ """
+
+ system_pkgmap_fd = open(SYSTEM_PKGMAP, "r")
+ stop_re = re.compile("(%s)" % "|".join(self.STOP_PKGS))
+ # Creating a data structure:
+ # soname - {<path1>: <line1>, <path2>: <line2>, ...}
+ logging.debug("Building sqlite3 cache db of the %s file",
+ SYSTEM_PKGMAP)
+ c = self.conn.cursor()
+ count = itertools.count()
+ for line in system_pkgmap_fd:
+ i = count.next()
+ if not i % 1000:
+ print "\r%s" % i,
+ if stop_re.search(line):
+ continue
+ fields = re.split(WS_RE, line)
+ pkgmap_entry_path = fields[0].split("=")[0]
+ pkgmap_entry_dir, pkgmap_entry_base_name = os.path.split(pkgmap_entry_path)
+ sql = "INSERT INTO systempkgmap (basename, path, line) VALUES (?, ?, ?);"
+ c.execute(sql, (pkgmap_entry_base_name, pkgmap_entry_dir, line.strip()))
+ print
+ print "Creating the main database index."
+ sql = "CREATE INDEX basename_idx ON systempkgmap(basename);"
+ c.execute(sql)
+ self.SetDatabaseMtime()
+ self.conn.commit()
+
+ def SetDatabaseMtime(self):
+ c = self.conn.cursor()
+ sql = "DELETE FROM config WHERE key = ?;"
+ c.execute(sql, [CONFIG_MTIME])
+ mtime = self.GetFileMtime()
+ logging.debug("Inserting the mtime (%s) into the database.", mtime)
+ sql = """
+ INSERT INTO config (key, float_value)
+ VALUES (?, ?);
+ """
+ c.execute(sql, [CONFIG_MTIME, mtime])
+
+ def GetPkgmapLineByBasename(self, filename):
+ if filename in self.cache:
+ return self.cache[filename]
+ sql = "SELECT path, line FROM systempkgmap WHERE basename = ?;"
+ c = self.conn.cursor()
+ c.execute(sql, [filename])
+ lines = {}
+ for row in c:
+ lines[row[0]] = row[1]
+ if len(lines) == 0:
+ logging.debug("Cache doesn't contain filename %s", filename)
+ self.cache[filename] = lines
+ return lines
+
+ def GetDatabaseMtime(self):
+ if not self.cache_mtime:
+ sql = """
+ SELECT float_value FROM config
+ WHERE key = ?;
+ """
+ c = self.conn.cursor()
+ c.execute(sql, [CONFIG_MTIME])
+ row = c.fetchone()
+ if not row:
+ # raise ConfigurationError("Could not find the mtime setting")
+ self.cache_mtime = 1
+ else:
+ self.cache_mtime = row[0]
+ return self.cache_mtime
+
+ def GetFileMtime(self):
+ if not self.file_mtime:
+ stat_data = os.stat(SYSTEM_PKGMAP)
+ self.file_mtime = stat_data.st_mtime
+ return self.file_mtime
+
+ def IsDatabaseUpToDate(self):
+ f_mtime = self.GetFileMtime()
+ d_mtime = self.GetDatabaseMtime()
+ logging.debug("f_mtime", f_mtime, "d_time", d_mtime)
+ return self.GetFileMtime() <= self.GetDatabaseMtime()
+
+ def PurgeDatabase(self):
+ c = self.conn.cursor()
+ sql = "DELETE FROM config;"
+ c.execute(sql)
+ sql = "DELETE FROM systempkgmap;"
+ c.execute(sql)
+ sql = "DROP INDEX basename_idx;"
+ try:
+ c.execute(sql)
+ except sqlite3.OperationalError, e:
+ logging.warn(e)
+
+def SharedObjectDependencies(pkgname,
+ binaries_by_pkgname,
+ needed_sonames_by_binary,
+ pkgs_by_soname,
+ filenames_by_soname,
+ pkg_by_any_filename):
+ """This is one of the more obscure and more important pieces of code.
+
+ I tried to make it simpler, but given that the operations here involve
+ whole sets of packages, it's not easy.
+ """
+ so_dependencies = set()
+ orphan_sonames = set()
+ self_provided = set()
+ for binary in binaries_by_pkgname[pkgname]:
+ needed_sonames = needed_sonames_by_binary[binary][NEEDED_SONAMES]
+ for soname in needed_sonames:
+ if soname in filenames_by_soname:
+ filename = filenames_by_soname[soname]
+ pkg = pkg_by_any_filename[filename]
+ self_provided.add(soname)
+ so_dependencies.add(pkg)
+ elif soname in pkgs_by_soname:
+ so_dependencies.add(pkgs_by_soname[soname])
+ else:
+ orphan_sonames.add(soname)
+ return so_dependencies, self_provided, orphan_sonames
+
+
+def GuessDepsByFilename(pkgname, pkg_by_any_filename):
+ """Guesses dependencies based on filename regexes."""
+ guessed_deps = set()
+ patterns = (
+ (r".*\.py", u"CSWpython"),
+ (r".*\.pl", u"CSWperl"),
+ (r".*\.rb", u"CSWruby"),
+ )
+ for pattern, dep_pkgname in patterns:
+ # If any file name matches, add the dep, go to the next pattern/pkg
+ # combination.
+ pattern_re = re.compile("^%s$" % pattern)
+ for filename in pkg_by_any_filename:
+ if (re.match(pattern_re, filename)
+ and
+ pkgname == pkg_by_any_filename[filename]):
+ guessed_deps.add(dep_pkgname)
+ break
+ return guessed_deps
+
+
+def GuessDepsByPkgname(pkgname, pkg_by_any_filename):
+ # More guessed dependencies: If one package is a substring of another, it
+ # might be a hint. For example, CSWmysql51test should depend on CSWmysql51.
+ # However, the rt (runtime) packages should not want to depend on the main
+ # package.
+ guessed_deps = set()
+ all_other_pkgs = set(pkg_by_any_filename.values())
+ for other_pkg in all_other_pkgs:
+ other_pkg = unicode(other_pkg)
+ if pkgname == other_pkg:
+ continue
+ if pkgname.startswith(other_pkg):
+ endings = ["devel", "test", "bench", "dev"]
+ for ending in endings:
+ if pkgname.endswith(ending):
+ guessed_deps.add(other_pkg)
+ return guessed_deps
+
+
+def AnalyzeDependencies(pkgname,
+ declared_dependencies,
+ binaries_by_pkgname,
+ needed_sonames_by_binary,
+ pkgs_by_soname,
+ filenames_by_soname,
+ pkg_by_any_filename):
+ """Gathers and merges dependency results from other functions.
+
+ declared_dependencies: Dependencies that the package in question claims to
+ have.
+
+ binaries_by_pkgname: A dictionary mapping pkgnames (CSWfoo) to binary names
+ (without paths)
+
+ needed_sonames_by_binary: A dictionary mapping binary file name to
+ a dictionary containing: "needed sonames",
+ "soname", "rpath". Based on examining the binary
+ files within the packages.
+
+ pkgs_by_soname: A dictionary mapping sonames to pkgnames, based on the
+ contents of the system wide pkgmap
+ (/var/sadm/install/contents)
+
+ filenames_by_soname: A dictionary mapping shared library sonames to filenames,
+ based on files within packages
+
+ pkg_by_any_filename: Mapping from file names to packages names, based on the
+ contents of the packages under examination.
+ """
+ declared_dependencies_set = set(declared_dependencies)
+
+ so_dependencies, self_provided, orphan_sonames = SharedObjectDependencies(
+ pkgname,
+ binaries_by_pkgname,
+ needed_sonames_by_binary,
+ pkgs_by_soname,
+ filenames_by_soname,
+ pkg_by_any_filename)
+ auto_dependencies = reduce(lambda x, y: x.union(y),
+ [
+ so_dependencies,
+ GuessDepsByFilename(pkgname, pkg_by_any_filename),
+ GuessDepsByPkgname(pkgname, pkg_by_any_filename),
+ ])
+ missing_deps = auto_dependencies.difference(declared_dependencies_set)
+ # Don't report itself as a suggested dependency.
+ missing_deps = missing_deps.difference(set([pkgname]))
+ missing_deps = missing_deps.difference(set(DO_NOT_REPORT_MISSING))
+ surplus_deps = declared_dependencies_set.difference(auto_dependencies)
+ surplus_deps = surplus_deps.difference(DO_NOT_REPORT_SURPLUS)
+ orphan_sonames = orphan_sonames.difference(ALLOWED_ORPHAN_SONAMES)
+ return missing_deps, surplus_deps, orphan_sonames
+
+
+def ExpandRunpath(runpath, isalist):
+ # Emulating $ISALIST expansion
+ if '$ISALIST' in runpath:
+ expanded_list = [runpath.replace('$ISALIST', isa) for isa in isalist]
+ else:
+ expanded_list = [runpath]
+ return expanded_list
+
+def Emulate64BitSymlinks(runpath_list):
+ """Need to emulate the 64 -> amd64, 64 -> sparcv9 symlink
+
+ Since we don't know the architecture, we'll adding both amd64 and sparcv9.
+ It should be safe.
+ """
+ symlinked_list = []
+ for runpath in runpath_list:
+ if "/64" in runpath:
+ symlinked_list.append(runpath.replace("/64", "/amd64"))
+ symlinked_list.append(runpath.replace("/64", "/sparcv9"))
+ else:
+ symlinked_list.append(runpath)
+ return symlinked_list
+
+
+def GetLinesBySoname(pkgmap, needed_sonames, runpath_by_needed_soname, isalist):
+ """Works out which system pkgmap lines correspond to given sonames."""
+ lines_by_soname = {}
+ for soname in needed_sonames:
+ # This is the critical part of the algorithm: it iterates over the
+ # runpath and finds the first matching one.
+ runpath_found = False
+ for runpath in runpath_by_needed_soname[soname]:
+ runpath_list = ExpandRunpath(runpath, isalist)
+ runpath_list = Emulate64BitSymlinks(runpath_list)
+ soname_runpath_data = pkgmap.GetPkgmapLineByBasename(soname)
+ logging.debug("%s: will be looking for %s in %s" %
+ (soname, runpath_list, soname_runpath_data.keys()))
+ for runpath_expanded in runpath_list:
+ if runpath_expanded in soname_runpath_data:
+ lines_by_soname[soname] = soname_runpath_data[runpath_expanded]
+ runpath_found = True
+ # This break only goes out of the inner loop,
+ # need another one below to finish the outer loop.
+ break
+ if runpath_found:
+ break
+ return lines_by_soname
+
+
+def BuildIndexesBySoname(needed_sonames_by_binary):
+ """Builds data structures indexed by soname.
+
+ Building indexes
+ {"foo.so": ["/opt/csw/lib/gcc4", "/opt/csw/lib", ...],
+ ...
+ }
+ """
+ needed_sonames = set()
+ binaries_by_soname = {}
+ runpath_by_needed_soname = {}
+ for binary_name, data in needed_sonames_by_binary.iteritems():
+ for soname in data[NEEDED_SONAMES]:
+ needed_sonames.add(soname)
+ if soname not in runpath_by_needed_soname:
+ runpath_by_needed_soname[soname] = []
+ runpath_by_needed_soname[soname].extend(data[RUNPATH])
+ if soname not in binaries_by_soname:
+ binaries_by_soname[soname] = set()
+ binaries_by_soname[soname].add(binary_name)
+ return needed_sonames, binaries_by_soname, runpath_by_needed_soname
+
+
+def ParseDumpOutput(dump_output):
+ binary_data = {RUNPATH: [],
+ NEEDED_SONAMES: []}
+ for line in dump_output.splitlines():
+ fields = re.split(WS_RE, line)
+ # TODO: Make it a unit test
+ # logging.debug("%s says: %s", DUMP_BIN, fields)
+ if len(fields) < 3:
+ continue
+ if fields[1] == "NEEDED":
+ binary_data[NEEDED_SONAMES].append(fields[2])
+ elif fields[1] == "RUNPATH":
+ binary_data[RUNPATH].extend(fields[2].split(":"))
+ elif fields[1] == "SONAME":
+ binary_data[SONAME] = fields[2]
+ # Adding the default runtime path search option.
+ binary_data[RUNPATH].append("/usr/lib/$ISALIST")
+ binary_data[RUNPATH].append("/usr/lib")
+ binary_data[RUNPATH].append("/lib/$ISALIST")
+ binary_data[RUNPATH].append("/lib")
+ return binary_data
Deleted: csw/mgar/gar/v2/bin/checkpkg.d/checkpkg_test.py
===================================================================
--- csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg_test.py 2010-01-04 03:57:34 UTC (rev 7855)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg_test.py 2010-01-04 10:28:15 UTC (rev 7856)
@@ -1,438 +0,0 @@
-#!/opt/csw/bin/python2.6
-# $Id$
-
-import unittest
-import mox
-import checkpkg
-import testdata.checkpkg_test_data_CSWmysql51rt as d1
-import testdata.checkpkg_test_data_CSWmysql51client as d2
-import testdata.checkpkg_test_data_CSWmysql51 as d3
-import testdata.checkpkg_test_data_CSWmysql51devel as d4
-import testdata.checkpkg_test_data_CSWlibpq_84 as d5
-import testdata.checkpkg_test_data_CSWmysql5client_8x as d6
-import testdata.dump_output_1 as dump_1
-import testdata.dump_output_2 as dump_2
-
-"""A set of unit tests for the library checking code.
-
-A bunch of lines to test in the interactive Python shell.
-
-import sys
-sys.path.append("gar/bin/checkpkg.d")
-import checkpkg
-import testdata.checkpkg_test_data_CSWmysql5client_8x as d6
-
-checkpkg.SharedObjectDependencies("CSWmysql5client",
-d6.DATA_BINARIES_BY_PKGNAME, d6.DATA_NEEDED_SONAMES_BY_BINARY,
-d6.DATA_PKGS_BY_FILENAME, d6.DATA_FILENAMES_BY_SONAME,
-d6.DATA_PKG_BY_ANY_FILENAME)
-
-sqlite3 ~/.checkpkg/var-sadm-install-contents-cache-build8x
-SELECT * FROM systempkgmap WHERE basename = 'libncursesw.so.5';
-"""
-
-class DependenciesUnitTest_1(unittest.TestCase):
-
- def setUp(self):
- self.missing_deps, self.surplus_deps, self.orphan_sonames = checkpkg.AnalyzeDependencies(
- d1.DATA_PKGNAME,
- d1.DATA_DECLARED_DEPENDENCIES,
- d1.DATA_BINARIES_BY_PKGNAME,
- d1.DATA_NEEDED_SONAMES_BY_BINARY,
- d1.DATA_PKGS_BY_FILENAME,
- d1.DATA_FILENAMES_BY_SONAME,
- d1.DATA_PKG_BY_ANY_FILENAME,
- )
-
- def testSurplusDeps(self):
- self.assertEquals(set([]), self.surplus_deps)
-
- def testOrphanSonames(self):
- self.assertEquals(set([]), self.orphan_sonames)
-
- def testMissingDeps(self):
- expected = set([])
- self.assertEquals(expected, self.missing_deps)
-
-
-class DependenciesUnitTest_2(unittest.TestCase):
-
- def setUp(self):
- self.missing_deps, self.surplus_deps, self.orphan_sonames = checkpkg.AnalyzeDependencies(
- d2.DATA_PKGNAME,
- d2.DATA_DECLARED_DEPENDENCIES,
- d2.DATA_BINARIES_BY_PKGNAME,
- d2.DATA_NEEDED_SONAMES_BY_BINARY,
- d2.DATA_PKGS_BY_FILENAME,
- d2.DATA_FILENAMES_BY_SONAME,
- d2.DATA_PKG_BY_ANY_FILENAME,
- )
-
- def testSurplusDeps(self):
- self.assertEquals(set([]), self.surplus_deps)
-
- def testOrphanSonames(self):
- self.assertEquals(set([]), self.orphan_sonames)
-
- def testMissingDeps(self):
- expected = set([])
- self.assertEquals(expected, self.missing_deps)
-
-
-class DependenciesUnitTest_3(unittest.TestCase):
-
- def setUp(self):
- self.missing_deps, self.surplus_deps, self.orphan_sonames = checkpkg.AnalyzeDependencies(
- d3.DATA_PKGNAME,
- d3.DATA_DECLARED_DEPENDENCIES,
- d3.DATA_BINARIES_BY_PKGNAME,
- d3.DATA_NEEDED_SONAMES_BY_BINARY,
- d3.DATA_PKGS_BY_FILENAME,
- d3.DATA_FILENAMES_BY_SONAME,
- d3.DATA_PKG_BY_ANY_FILENAME,
- )
-
- def testSurplusDeps(self):
- self.assertEquals(set([u'CSWmysql51client']), self.surplus_deps)
-
- def testOrphanSonames(self):
- self.assertEquals(set([]), self.orphan_sonames)
-
- def testMissingDeps(self):
- expected = set(['CSWmysql51rt'])
- self.assertEquals(expected, self.missing_deps)
-
-
-class DependenciesUnitTest_4(unittest.TestCase):
-
- def setUp(self):
- self.missing_deps, self.surplus_deps, self.orphan_sonames = checkpkg.AnalyzeDependencies(
- d4.DATA_PKGNAME,
- d4.DATA_DECLARED_DEPENDENCIES,
- d4.DATA_BINARIES_BY_PKGNAME,
- d4.DATA_NEEDED_SONAMES_BY_BINARY,
- d4.DATA_PKGS_BY_FILENAME,
- d4.DATA_FILENAMES_BY_SONAME,
- d4.DATA_PKG_BY_ANY_FILENAME,
- )
-
- def testSurplusDeps(self):
- self.assertEquals(set([]), self.surplus_deps)
-
- def testOrphanSonames(self):
- self.assertEquals(set([]), self.orphan_sonames)
-
- def testMissingDeps(self):
- expected = set([])
- self.assertEquals(expected, self.missing_deps)
-
-
-class DependenciesUnitTest_5(unittest.TestCase):
-
- def setUp(self):
- self.missing_deps, self.surplus_deps, self.orphan_sonames = checkpkg.AnalyzeDependencies(
- d5.DATA_PKGNAME,
- d5.DATA_DECLARED_DEPENDENCIES,
- d5.DATA_BINARIES_BY_PKGNAME,
- d5.DATA_NEEDED_SONAMES_BY_BINARY,
- d5.DATA_PKGS_BY_FILENAME,
- d5.DATA_FILENAMES_BY_SONAME,
- d5.DATA_PKG_BY_ANY_FILENAME,
- )
-
- def testSurplusDeps(self):
- self.assertEquals(set([]), self.surplus_deps)
-
- def testOrphanSonames(self):
- self.assertEquals(set([]), self.orphan_sonames)
-
- def testMissingDeps(self):
- # This tends to report itself...
- expected = set([u'SUNWgss'])
- self.assertEquals(expected, self.missing_deps)
-
-
-class DependenciesUnitTest_6(unittest.TestCase):
-
- def setUp(self):
- (self.missing_deps,
- self.surplus_deps,
- self.orphan_sonames) = checkpkg.AnalyzeDependencies(
- d6.DATA_PKGNAME,
- d6.DATA_DECLARED_DEPENDENCIES,
- d6.DATA_BINARIES_BY_PKGNAME,
- d6.DATA_NEEDED_SONAMES_BY_BINARY,
- d6.DATA_PKGS_BY_FILENAME,
- d6.DATA_FILENAMES_BY_SONAME,
- d6.DATA_PKG_BY_ANY_FILENAME,
- )
-
- def testSurplusDeps(self):
- self.assertEquals(set([]), self.surplus_deps)
-
- def testOrphanSonames(self):
- self.assertEquals(set([]), self.orphan_sonames)
-
- def testMissingDeps(self):
- expected = set([])
- self.assertEquals(expected, self.missing_deps)
-
-
-class GuessDepsUnitTest(unittest.TestCase):
-
- def testGuessDepsByFilename1(self):
- expected = set([u"CSWpython"])
- pkgname = u"CSWfoo"
- pkg_by_filename = {
- "/opt/csw/bin/bar": u"CSWfoo",
- "/opt/csw/lib/python/site-packages/foo.py": u"CSWfoo",
- }
- self.assertEqual(expected,
- checkpkg.GuessDepsByFilename(pkgname, pkg_by_filename))
-
- def testGuessDepsByFilename2(self):
- expected = set([])
- pkgname = u"CSWfoo"
- pkg_by_filename = {
- "/opt/csw/bin/bar": u"CSWfoo",
- "/opt/csw/lib/python/site-packages/foo.py": u"CSWbar",
- }
- self.assertEqual(expected,
- checkpkg.GuessDepsByFilename(pkgname, pkg_by_filename))
-
- def testGuessDepsByPkgname1(self):
- expected = set([u"CSWfoo"])
- pkgname = u"CSWfoo-devel"
- pkg_by_filename = {
- "/opt/csw/bin/bar": u"CSWfoo",
- "/opt/csw/bin/barfoo": u"CSWfoobar",
- "/opt/csw/lib/python/site-packages/foo.py": u"CSWfoo",
- }
- self.assertEqual(expected,
- checkpkg.GuessDepsByPkgname(pkgname, pkg_by_filename))
-
- def testGuessDepsByPkgname2(self):
- expected = set([])
- pkgname = u"CSWzfoo-devel"
- pkg_by_filename = {
- "/opt/csw/bin/bar": u"CSWfoo",
- "/opt/csw/bin/barfoo": u"CSWfoobar",
- "/opt/csw/lib/python/site-packages/foo.py": u"CSWfoo",
- }
- self.assertEqual(expected,
- checkpkg.GuessDepsByPkgname(pkgname, pkg_by_filename))
-
- def testGuessDepsByPkgname3(self):
- self.assertEqual(set([u"CSWmysql51"]),
- checkpkg.GuessDepsByPkgname(u"CSWmysql51devel",
- d4.DATA_PKG_BY_ANY_FILENAME))
-
- def testGuessDepsByPkgname4(self):
- data1 = set(['CSWmysql51', 'CSWmysql51rt', 'CSWmysql51test',
- 'CSWmysql51client', 'CSWmysql51bench', 'CSWmysql51devel'])
- data2 = dict(((x, x) for x in data1))
- self.assertEqual(set([u"CSWmysql51"]), checkpkg.GuessDepsByPkgname(u"CSWmysql51devel", data2))
-
- def testGuessDepsByPkgname4(self):
- data1 = set(['CSWmysql51', 'CSWmysql51rt', 'CSWmysql51test',
- 'CSWmysql51client', 'CSWmysql51bench', 'CSWmysql51devel'])
- data2 = dict(((x, x) for x in data1))
- self.assertEqual(set([]), checkpkg.GuessDepsByPkgname(u"CSWmysql51rt", data2))
-
-
-class GetLinesBySonameUnitTest(unittest.TestCase):
-
- class PkgmapStub(object):
-
- def __init__(self, cache):
- self.cache = cache
-
- def GetPkgmapLineByBasename(self, soname):
- return self.cache[soname]
-
- def setUp(self):
- self.pkgmap_mocker = mox.Mox()
-
- def testExpandRunpath_1(self):
- isalist = ["foo", "bar"]
- runpath = "/opt/csw/lib/$ISALIST"
- expected = ["/opt/csw/lib/foo", "/opt/csw/lib/bar"]
- self.assertEquals(expected, checkpkg.ExpandRunpath(runpath, isalist))
-
- 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, checkpkg.ExpandRunpath(runpath, isalist))
-
- def testEmulate64BitSymlinks_1(self):
- runpath_list = ["/opt/csw/mysql5/lib/foo/mysql/64"]
- expected = "/opt/csw/mysql5/lib/foo/mysql/amd64"
- self.assertTrue(expected in checkpkg.Emulate64BitSymlinks(runpath_list))
-
- def testEmulate64BitSymlinks_2(self):
- runpath_list = ["/opt/csw/mysql5/lib/64/mysql/foo"]
- expected = "/opt/csw/mysql5/lib/amd64/mysql/foo"
- result = checkpkg.Emulate64BitSymlinks(runpath_list)
- self.assertTrue(expected in result, "%s not in %s" % (expected, result))
-
- def testGetLinesBySoname(self):
- expected = {'foo.so.1': '/opt/csw/lib/isa-value-1/foo.so.1 foo'}
- pkgmap = self.pkgmap_mocker.CreateMock(checkpkg.SystemPkgmap)
- pkgmap.GetPkgmapLineByBasename("foo")
- lines1 = {"/opt/csw/lib/isa-value-1": "/opt/csw/lib/isa-value-1/foo.so.1 foo",
- "/usr/lib": "/usr/lib/foo.so.1 foo"}
- # pkgmap.GetPkgmapLineByBasename("foo.so.1").AndReturn(lines1)
- pkgmap.GetPkgmapLineByBasename("foo.so.1").AndReturn(lines1)
- self.pkgmap_mocker.ReplayAll()
- pkgmap.GetPkgmapLineByBasename("foo")
- needed_sonames = set(["foo.so.1"])
- runpath_by_needed_soname = {"foo.so.1": ["/opt/csw/lib/$ISALIST", "/usr/lib"]}
- isalist = ["isa-value-1", "isa-value-2"]
- result = checkpkg.GetLinesBySoname(pkgmap, needed_sonames, runpath_by_needed_soname, isalist)
- self.pkgmap_mocker.VerifyAll()
- self.assertEqual(expected, result)
-
- def testGetLinesBySoname_3(self):
- expected = {'foo.so.1': '/opt/csw/lib/isa-value-1/foo.so.1 foo'}
- pkgmap = self.pkgmap_mocker.CreateMock(checkpkg.SystemPkgmap)
- pkgmap.GetPkgmapLineByBasename("foo")
- lines1 = {
- "/opt/csw/lib/isa-value-1": "/opt/csw/lib/isa-value-1/foo.so.1 foo",
- "/opt/csw/lib": "/opt/csw/lib/foo.so.1 foo",
- "/usr/lib": "/usr/lib/foo.so.1 foo"}
- # pkgmap.GetPkgmapLineByBasename("foo.so.1").AndReturn(lines1)
- pkgmap.GetPkgmapLineByBasename("foo.so.1").AndReturn(lines1)
- self.pkgmap_mocker.ReplayAll()
- pkgmap.GetPkgmapLineByBasename("foo")
- needed_sonames = set(["foo.so.1"])
- runpath_by_needed_soname = {
- "foo.so.1": ["/opt/csw/lib/$ISALIST", "/usr/lib"]}
- isalist = ["isa-value-1", "isa-value-2"]
- result = checkpkg.GetLinesBySoname(
- pkgmap, needed_sonames, runpath_by_needed_soname, isalist)
- self.pkgmap_mocker.VerifyAll()
- self.assertEqual(expected, result)
-
- def testGetLinesBySoname_4(self):
- """A more complex test, four ISAs."""
- expected = {'foo.so.1': '/opt/csw/lib/isa-value-1/foo.so.1 foo'}
- pkgmap = self.pkgmap_mocker.CreateMock(checkpkg.SystemPkgmap)
- pkgmap.GetPkgmapLineByBasename("foo")
- lines1 = {
- "/opt/csw/lib/isa-value-1":
- "/opt/csw/lib/isa-value-1/foo.so.1 foo",
- "/opt/csw/mysql5/lib/isa-value-2":
- "/opt/csw/mysql5/lib/isa-value-2/foo.so.1 foo",
- "/opt/csw/mysql5/lib/isa-value-1":
- "/opt/csw/mysql5/lib/isa-value-1/foo.so.1 foo",
- "/opt/csw/lib":
- "/opt/csw/lib/foo.so.1 foo",
- "/usr/lib":
- "/usr/lib/foo.so.1 foo"}
- pkgmap.GetPkgmapLineByBasename("foo.so.1").AndReturn(lines1)
- pkgmap.GetPkgmapLineByBasename("foo.so.1").AndReturn(lines1)
- self.pkgmap_mocker.ReplayAll()
- pkgmap.GetPkgmapLineByBasename("foo")
- needed_sonames = set(["foo.so.1"])
- runpath_by_needed_soname = {
- "foo.so.1": ["/opt/csw/mysql5/lib/$ISALIST/mysql",
- "/opt/csw/lib/$ISALIST",
- "/usr/lib"]}
- isalist = ["isa-value-1", "isa-value-2"]
- result = checkpkg.GetLinesBySoname(
- pkgmap, needed_sonames, runpath_by_needed_soname, isalist)
- self.pkgmap_mocker.VerifyAll()
- self.assertEqual(expected, result)
-
- def testGetLinesBySoname_5(self):
- """Based on CSWmysql5client on build8x."""
- soname = u'libm.so.1'
- expected = {u'libm.so.1': u'/usr/lib/libm.so.1 f none 0755 root bin '
- u'99844 3884 1050525375 SUNWlibms\n'}
-
- pkgmap_stub = self.PkgmapStub(d6.DATA_PKGMAP_CACHE)
- (needed_sonames,
- binaries_by_soname,
- runpath_by_needed_soname) = checkpkg.BuildIndexesBySoname(
- d6.DATA_NEEDED_SONAMES_BY_BINARY)
- result = checkpkg.GetLinesBySoname(
- pkgmap_stub,
- set([soname]),
- runpath_by_needed_soname,
- d6.DATA_ISALIST)
- self.assertEqual(expected, result)
-
- def testGetLinesBySoname_6(self):
- """Based on CSWmysql5client on build8x."""
- soname = u'libz.so.1'
- expected = {u'libz.so.1': u'/opt/csw/lib/pentium_pro+mmx/libz.so.1=libz.so.1.2.3 '
- u's none CSWzlib\n'}
- pkgmap_stub = self.PkgmapStub(d6.DATA_PKGMAP_CACHE)
- (needed_sonames,
- binaries_by_soname,
- runpath_by_needed_soname) = checkpkg.BuildIndexesBySoname(
- d6.DATA_NEEDED_SONAMES_BY_BINARY)
- result = checkpkg.GetLinesBySoname(
- pkgmap_stub,
- set([soname]),
- runpath_by_needed_soname,
- d6.DATA_ISALIST)
- self.assertEqual(expected, result)
-
- def testGetLinesBySoname_7(self):
- """A test for 64-bit symlink expansion."""
- soname = u'libncursesw.so.5'
- # To test the 64-bit symlink expansion
- expected = {
- u'libncursesw.so.5':
- u'/opt/csw/lib/amd64/libncursesw.so.5=libncursesw.so.5.7 '
- u's none CSWncurses\n'}
- pkgmap_stub = self.PkgmapStub(d6.DATA_PKGMAP_CACHE)
- (needed_sonames,
- binaries_by_soname,
- runpath_by_needed_soname) = checkpkg.BuildIndexesBySoname(
- d6.DATA_NEEDED_SONAMES_BY_BINARY)
- result = checkpkg.GetLinesBySoname(
- pkgmap_stub,
- set([soname]),
- runpath_by_needed_soname,
- d6.DATA_ISALIST)
- self.assertEqual(expected, result)
-
-
-class ParseDumpOutputUnitTest(unittest.TestCase):
-
- def test_1(self):
- expected = {
- 'soname': 'libmysqlclient.so.15',
- 'runpath': ['/opt/csw/lib/$ISALIST',
- '/opt/csw/lib',
- '/opt/csw/mysql5/lib/$ISALIST',
- '/opt/csw/mysql5/lib',
- '/opt/csw/mysql5/lib/$ISALIST/mysql',
- # These four are artificially appended
- '/usr/lib/$ISALIST',
- '/usr/lib',
- '/lib/$ISALIST',
- '/lib'],
- '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']}
- self.assertEqual(expected,
- checkpkg.ParseDumpOutput(dump_1.DATA_DUMP_OUTPUT))
-
- def test_2(self):
- expected_runpath = ['/usr/lib/$ISALIST', '/usr/lib', '/lib/$ISALIST', '/lib']
- self.assertEqual(
- expected_runpath,
- checkpkg.ParseDumpOutput(dump_2.DATA_DUMP_OUTPUT)["runpath"])
-
-
-if __name__ == '__main__':
- unittest.main()
Copied: csw/mgar/gar/v2/bin/checkpkg.d/checkpkg_test.py (from rev 7855, csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/checkpkg_test.py)
===================================================================
--- csw/mgar/gar/v2/bin/checkpkg.d/checkpkg_test.py (rev 0)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg_test.py 2010-01-04 10:28:15 UTC (rev 7856)
@@ -0,0 +1,438 @@
+#!/opt/csw/bin/python2.6
+# $Id$
+
+import unittest
+import mox
+import checkpkg
+import testdata.checkpkg_test_data_CSWmysql51rt as d1
+import testdata.checkpkg_test_data_CSWmysql51client as d2
+import testdata.checkpkg_test_data_CSWmysql51 as d3
+import testdata.checkpkg_test_data_CSWmysql51devel as d4
+import testdata.checkpkg_test_data_CSWlibpq_84 as d5
+import testdata.checkpkg_test_data_CSWmysql5client_8x as d6
+import testdata.dump_output_1 as dump_1
+import testdata.dump_output_2 as dump_2
+
+"""A set of unit tests for the library checking code.
+
+A bunch of lines to test in the interactive Python shell.
+
+import sys
+sys.path.append("gar/bin/checkpkg.d")
+import checkpkg
+import testdata.checkpkg_test_data_CSWmysql5client_8x as d6
+
+checkpkg.SharedObjectDependencies("CSWmysql5client",
+d6.DATA_BINARIES_BY_PKGNAME, d6.DATA_NEEDED_SONAMES_BY_BINARY,
+d6.DATA_PKGS_BY_FILENAME, d6.DATA_FILENAMES_BY_SONAME,
+d6.DATA_PKG_BY_ANY_FILENAME)
+
+sqlite3 ~/.checkpkg/var-sadm-install-contents-cache-build8x
+SELECT * FROM systempkgmap WHERE basename = 'libncursesw.so.5';
+"""
+
+class DependenciesUnitTest_1(unittest.TestCase):
+
+ def setUp(self):
+ self.missing_deps, self.surplus_deps, self.orphan_sonames = checkpkg.AnalyzeDependencies(
+ d1.DATA_PKGNAME,
+ d1.DATA_DECLARED_DEPENDENCIES,
+ d1.DATA_BINARIES_BY_PKGNAME,
+ d1.DATA_NEEDED_SONAMES_BY_BINARY,
+ d1.DATA_PKGS_BY_FILENAME,
+ d1.DATA_FILENAMES_BY_SONAME,
+ d1.DATA_PKG_BY_ANY_FILENAME,
+ )
+
+ def testSurplusDeps(self):
+ self.assertEquals(set([]), self.surplus_deps)
+
+ def testOrphanSonames(self):
+ self.assertEquals(set([]), self.orphan_sonames)
+
+ def testMissingDeps(self):
+ expected = set([])
+ self.assertEquals(expected, self.missing_deps)
+
+
+class DependenciesUnitTest_2(unittest.TestCase):
+
+ def setUp(self):
+ self.missing_deps, self.surplus_deps, self.orphan_sonames = checkpkg.AnalyzeDependencies(
+ d2.DATA_PKGNAME,
+ d2.DATA_DECLARED_DEPENDENCIES,
+ d2.DATA_BINARIES_BY_PKGNAME,
+ d2.DATA_NEEDED_SONAMES_BY_BINARY,
+ d2.DATA_PKGS_BY_FILENAME,
+ d2.DATA_FILENAMES_BY_SONAME,
+ d2.DATA_PKG_BY_ANY_FILENAME,
+ )
+
+ def testSurplusDeps(self):
+ self.assertEquals(set([]), self.surplus_deps)
+
+ def testOrphanSonames(self):
+ self.assertEquals(set([]), self.orphan_sonames)
+
+ def testMissingDeps(self):
+ expected = set([])
+ self.assertEquals(expected, self.missing_deps)
+
+
+class DependenciesUnitTest_3(unittest.TestCase):
+
+ def setUp(self):
+ self.missing_deps, self.surplus_deps, self.orphan_sonames = checkpkg.AnalyzeDependencies(
+ d3.DATA_PKGNAME,
+ d3.DATA_DECLARED_DEPENDENCIES,
+ d3.DATA_BINARIES_BY_PKGNAME,
+ d3.DATA_NEEDED_SONAMES_BY_BINARY,
+ d3.DATA_PKGS_BY_FILENAME,
+ d3.DATA_FILENAMES_BY_SONAME,
+ d3.DATA_PKG_BY_ANY_FILENAME,
+ )
+
+ def testSurplusDeps(self):
+ self.assertEquals(set([u'CSWmysql51client']), self.surplus_deps)
+
+ def testOrphanSonames(self):
+ self.assertEquals(set([]), self.orphan_sonames)
+
+ def testMissingDeps(self):
+ expected = set(['CSWmysql51rt'])
+ self.assertEquals(expected, self.missing_deps)
+
+
+class DependenciesUnitTest_4(unittest.TestCase):
+
+ def setUp(self):
+ self.missing_deps, self.surplus_deps, self.orphan_sonames = checkpkg.AnalyzeDependencies(
+ d4.DATA_PKGNAME,
+ d4.DATA_DECLARED_DEPENDENCIES,
+ d4.DATA_BINARIES_BY_PKGNAME,
+ d4.DATA_NEEDED_SONAMES_BY_BINARY,
+ d4.DATA_PKGS_BY_FILENAME,
+ d4.DATA_FILENAMES_BY_SONAME,
+ d4.DATA_PKG_BY_ANY_FILENAME,
+ )
+
+ def testSurplusDeps(self):
+ self.assertEquals(set([]), self.surplus_deps)
+
+ def testOrphanSonames(self):
+ self.assertEquals(set([]), self.orphan_sonames)
+
+ def testMissingDeps(self):
+ expected = set([])
+ self.assertEquals(expected, self.missing_deps)
+
+
+class DependenciesUnitTest_5(unittest.TestCase):
+
+ def setUp(self):
+ self.missing_deps, self.surplus_deps, self.orphan_sonames = checkpkg.AnalyzeDependencies(
+ d5.DATA_PKGNAME,
+ d5.DATA_DECLARED_DEPENDENCIES,
+ d5.DATA_BINARIES_BY_PKGNAME,
+ d5.DATA_NEEDED_SONAMES_BY_BINARY,
+ d5.DATA_PKGS_BY_FILENAME,
+ d5.DATA_FILENAMES_BY_SONAME,
+ d5.DATA_PKG_BY_ANY_FILENAME,
+ )
+
+ def testSurplusDeps(self):
+ self.assertEquals(set([]), self.surplus_deps)
+
+ def testOrphanSonames(self):
+ self.assertEquals(set([]), self.orphan_sonames)
+
+ def testMissingDeps(self):
+ # This tends to report itself...
+ expected = set([u'SUNWgss'])
+ self.assertEquals(expected, self.missing_deps)
+
+
+class DependenciesUnitTest_6(unittest.TestCase):
+
+ def setUp(self):
+ (self.missing_deps,
+ self.surplus_deps,
+ self.orphan_sonames) = checkpkg.AnalyzeDependencies(
+ d6.DATA_PKGNAME,
+ d6.DATA_DECLARED_DEPENDENCIES,
+ d6.DATA_BINARIES_BY_PKGNAME,
+ d6.DATA_NEEDED_SONAMES_BY_BINARY,
+ d6.DATA_PKGS_BY_FILENAME,
+ d6.DATA_FILENAMES_BY_SONAME,
+ d6.DATA_PKG_BY_ANY_FILENAME,
+ )
+
+ def testSurplusDeps(self):
+ self.assertEquals(set([]), self.surplus_deps)
+
+ def testOrphanSonames(self):
+ self.assertEquals(set([]), self.orphan_sonames)
+
+ def testMissingDeps(self):
+ expected = set([])
+ self.assertEquals(expected, self.missing_deps)
+
+
+class GuessDepsUnitTest(unittest.TestCase):
+
+ def testGuessDepsByFilename1(self):
+ expected = set([u"CSWpython"])
+ pkgname = u"CSWfoo"
+ pkg_by_filename = {
+ "/opt/csw/bin/bar": u"CSWfoo",
+ "/opt/csw/lib/python/site-packages/foo.py": u"CSWfoo",
+ }
+ self.assertEqual(expected,
+ checkpkg.GuessDepsByFilename(pkgname, pkg_by_filename))
+
+ def testGuessDepsByFilename2(self):
+ expected = set([])
+ pkgname = u"CSWfoo"
+ pkg_by_filename = {
+ "/opt/csw/bin/bar": u"CSWfoo",
+ "/opt/csw/lib/python/site-packages/foo.py": u"CSWbar",
+ }
+ self.assertEqual(expected,
+ checkpkg.GuessDepsByFilename(pkgname, pkg_by_filename))
+
+ def testGuessDepsByPkgname1(self):
+ expected = set([u"CSWfoo"])
+ pkgname = u"CSWfoo-devel"
+ pkg_by_filename = {
+ "/opt/csw/bin/bar": u"CSWfoo",
+ "/opt/csw/bin/barfoo": u"CSWfoobar",
+ "/opt/csw/lib/python/site-packages/foo.py": u"CSWfoo",
+ }
+ self.assertEqual(expected,
+ checkpkg.GuessDepsByPkgname(pkgname, pkg_by_filename))
+
+ def testGuessDepsByPkgname2(self):
+ expected = set([])
+ pkgname = u"CSWzfoo-devel"
+ pkg_by_filename = {
+ "/opt/csw/bin/bar": u"CSWfoo",
+ "/opt/csw/bin/barfoo": u"CSWfoobar",
+ "/opt/csw/lib/python/site-packages/foo.py": u"CSWfoo",
+ }
+ self.assertEqual(expected,
+ checkpkg.GuessDepsByPkgname(pkgname, pkg_by_filename))
+
+ def testGuessDepsByPkgname3(self):
+ self.assertEqual(set([u"CSWmysql51"]),
+ checkpkg.GuessDepsByPkgname(u"CSWmysql51devel",
+ d4.DATA_PKG_BY_ANY_FILENAME))
+
+ def testGuessDepsByPkgname4(self):
+ data1 = set(['CSWmysql51', 'CSWmysql51rt', 'CSWmysql51test',
+ 'CSWmysql51client', 'CSWmysql51bench', 'CSWmysql51devel'])
+ data2 = dict(((x, x) for x in data1))
+ self.assertEqual(set([u"CSWmysql51"]), checkpkg.GuessDepsByPkgname(u"CSWmysql51devel", data2))
+
+ def testGuessDepsByPkgname4(self):
+ data1 = set(['CSWmysql51', 'CSWmysql51rt', 'CSWmysql51test',
+ 'CSWmysql51client', 'CSWmysql51bench', 'CSWmysql51devel'])
+ data2 = dict(((x, x) for x in data1))
+ self.assertEqual(set([]), checkpkg.GuessDepsByPkgname(u"CSWmysql51rt", data2))
+
+
+class GetLinesBySonameUnitTest(unittest.TestCase):
+
+ class PkgmapStub(object):
+
+ def __init__(self, cache):
+ self.cache = cache
+
+ def GetPkgmapLineByBasename(self, soname):
+ return self.cache[soname]
+
+ def setUp(self):
+ self.pkgmap_mocker = mox.Mox()
+
+ def testExpandRunpath_1(self):
+ isalist = ["foo", "bar"]
+ runpath = "/opt/csw/lib/$ISALIST"
+ expected = ["/opt/csw/lib/foo", "/opt/csw/lib/bar"]
+ self.assertEquals(expected, checkpkg.ExpandRunpath(runpath, isalist))
+
+ 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, checkpkg.ExpandRunpath(runpath, isalist))
+
+ def testEmulate64BitSymlinks_1(self):
+ runpath_list = ["/opt/csw/mysql5/lib/foo/mysql/64"]
+ expected = "/opt/csw/mysql5/lib/foo/mysql/amd64"
+ self.assertTrue(expected in checkpkg.Emulate64BitSymlinks(runpath_list))
+
+ def testEmulate64BitSymlinks_2(self):
+ runpath_list = ["/opt/csw/mysql5/lib/64/mysql/foo"]
+ expected = "/opt/csw/mysql5/lib/amd64/mysql/foo"
+ result = checkpkg.Emulate64BitSymlinks(runpath_list)
+ self.assertTrue(expected in result, "%s not in %s" % (expected, result))
+
+ def testGetLinesBySoname(self):
+ expected = {'foo.so.1': '/opt/csw/lib/isa-value-1/foo.so.1 foo'}
+ pkgmap = self.pkgmap_mocker.CreateMock(checkpkg.SystemPkgmap)
+ pkgmap.GetPkgmapLineByBasename("foo")
+ lines1 = {"/opt/csw/lib/isa-value-1": "/opt/csw/lib/isa-value-1/foo.so.1 foo",
+ "/usr/lib": "/usr/lib/foo.so.1 foo"}
+ # pkgmap.GetPkgmapLineByBasename("foo.so.1").AndReturn(lines1)
+ pkgmap.GetPkgmapLineByBasename("foo.so.1").AndReturn(lines1)
+ self.pkgmap_mocker.ReplayAll()
+ pkgmap.GetPkgmapLineByBasename("foo")
+ needed_sonames = set(["foo.so.1"])
+ runpath_by_needed_soname = {"foo.so.1": ["/opt/csw/lib/$ISALIST", "/usr/lib"]}
+ isalist = ["isa-value-1", "isa-value-2"]
+ result = checkpkg.GetLinesBySoname(pkgmap, needed_sonames, runpath_by_needed_soname, isalist)
+ self.pkgmap_mocker.VerifyAll()
+ self.assertEqual(expected, result)
+
+ def testGetLinesBySoname_3(self):
+ expected = {'foo.so.1': '/opt/csw/lib/isa-value-1/foo.so.1 foo'}
+ pkgmap = self.pkgmap_mocker.CreateMock(checkpkg.SystemPkgmap)
+ pkgmap.GetPkgmapLineByBasename("foo")
+ lines1 = {
+ "/opt/csw/lib/isa-value-1": "/opt/csw/lib/isa-value-1/foo.so.1 foo",
+ "/opt/csw/lib": "/opt/csw/lib/foo.so.1 foo",
+ "/usr/lib": "/usr/lib/foo.so.1 foo"}
+ # pkgmap.GetPkgmapLineByBasename("foo.so.1").AndReturn(lines1)
+ pkgmap.GetPkgmapLineByBasename("foo.so.1").AndReturn(lines1)
+ self.pkgmap_mocker.ReplayAll()
+ pkgmap.GetPkgmapLineByBasename("foo")
+ needed_sonames = set(["foo.so.1"])
+ runpath_by_needed_soname = {
+ "foo.so.1": ["/opt/csw/lib/$ISALIST", "/usr/lib"]}
+ isalist = ["isa-value-1", "isa-value-2"]
+ result = checkpkg.GetLinesBySoname(
+ pkgmap, needed_sonames, runpath_by_needed_soname, isalist)
+ self.pkgmap_mocker.VerifyAll()
+ self.assertEqual(expected, result)
+
+ def testGetLinesBySoname_4(self):
+ """A more complex test, four ISAs."""
+ expected = {'foo.so.1': '/opt/csw/lib/isa-value-1/foo.so.1 foo'}
+ pkgmap = self.pkgmap_mocker.CreateMock(checkpkg.SystemPkgmap)
+ pkgmap.GetPkgmapLineByBasename("foo")
+ lines1 = {
+ "/opt/csw/lib/isa-value-1":
+ "/opt/csw/lib/isa-value-1/foo.so.1 foo",
+ "/opt/csw/mysql5/lib/isa-value-2":
+ "/opt/csw/mysql5/lib/isa-value-2/foo.so.1 foo",
+ "/opt/csw/mysql5/lib/isa-value-1":
+ "/opt/csw/mysql5/lib/isa-value-1/foo.so.1 foo",
+ "/opt/csw/lib":
+ "/opt/csw/lib/foo.so.1 foo",
+ "/usr/lib":
+ "/usr/lib/foo.so.1 foo"}
+ pkgmap.GetPkgmapLineByBasename("foo.so.1").AndReturn(lines1)
+ pkgmap.GetPkgmapLineByBasename("foo.so.1").AndReturn(lines1)
+ self.pkgmap_mocker.ReplayAll()
+ pkgmap.GetPkgmapLineByBasename("foo")
+ needed_sonames = set(["foo.so.1"])
+ runpath_by_needed_soname = {
+ "foo.so.1": ["/opt/csw/mysql5/lib/$ISALIST/mysql",
+ "/opt/csw/lib/$ISALIST",
+ "/usr/lib"]}
+ isalist = ["isa-value-1", "isa-value-2"]
+ result = checkpkg.GetLinesBySoname(
+ pkgmap, needed_sonames, runpath_by_needed_soname, isalist)
+ self.pkgmap_mocker.VerifyAll()
+ self.assertEqual(expected, result)
+
+ def testGetLinesBySoname_5(self):
+ """Based on CSWmysql5client on build8x."""
+ soname = u'libm.so.1'
+ expected = {u'libm.so.1': u'/usr/lib/libm.so.1 f none 0755 root bin '
+ u'99844 3884 1050525375 SUNWlibms\n'}
+
+ pkgmap_stub = self.PkgmapStub(d6.DATA_PKGMAP_CACHE)
+ (needed_sonames,
+ binaries_by_soname,
+ runpath_by_needed_soname) = checkpkg.BuildIndexesBySoname(
+ d6.DATA_NEEDED_SONAMES_BY_BINARY)
+ result = checkpkg.GetLinesBySoname(
+ pkgmap_stub,
+ set([soname]),
+ runpath_by_needed_soname,
+ d6.DATA_ISALIST)
+ self.assertEqual(expected, result)
+
+ def testGetLinesBySoname_6(self):
+ """Based on CSWmysql5client on build8x."""
+ soname = u'libz.so.1'
+ expected = {u'libz.so.1': u'/opt/csw/lib/pentium_pro+mmx/libz.so.1=libz.so.1.2.3 '
+ u's none CSWzlib\n'}
+ pkgmap_stub = self.PkgmapStub(d6.DATA_PKGMAP_CACHE)
+ (needed_sonames,
+ binaries_by_soname,
+ runpath_by_needed_soname) = checkpkg.BuildIndexesBySoname(
+ d6.DATA_NEEDED_SONAMES_BY_BINARY)
+ result = checkpkg.GetLinesBySoname(
+ pkgmap_stub,
+ set([soname]),
+ runpath_by_needed_soname,
+ d6.DATA_ISALIST)
+ self.assertEqual(expected, result)
+
+ def testGetLinesBySoname_7(self):
+ """A test for 64-bit symlink expansion."""
+ soname = u'libncursesw.so.5'
+ # To test the 64-bit symlink expansion
+ expected = {
+ u'libncursesw.so.5':
+ u'/opt/csw/lib/amd64/libncursesw.so.5=libncursesw.so.5.7 '
+ u's none CSWncurses\n'}
+ pkgmap_stub = self.PkgmapStub(d6.DATA_PKGMAP_CACHE)
+ (needed_sonames,
+ binaries_by_soname,
+ runpath_by_needed_soname) = checkpkg.BuildIndexesBySoname(
+ d6.DATA_NEEDED_SONAMES_BY_BINARY)
+ result = checkpkg.GetLinesBySoname(
+ pkgmap_stub,
+ set([soname]),
+ runpath_by_needed_soname,
+ d6.DATA_ISALIST)
+ self.assertEqual(expected, result)
+
+
+class ParseDumpOutputUnitTest(unittest.TestCase):
+
+ def test_1(self):
+ expected = {
+ 'soname': 'libmysqlclient.so.15',
+ 'runpath': ['/opt/csw/lib/$ISALIST',
+ '/opt/csw/lib',
+ '/opt/csw/mysql5/lib/$ISALIST',
+ '/opt/csw/mysql5/lib',
+ '/opt/csw/mysql5/lib/$ISALIST/mysql',
+ # These four are artificially appended
+ '/usr/lib/$ISALIST',
+ '/usr/lib',
+ '/lib/$ISALIST',
+ '/lib'],
+ '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']}
+ self.assertEqual(expected,
+ checkpkg.ParseDumpOutput(dump_1.DATA_DUMP_OUTPUT))
+
+ def test_2(self):
+ expected_runpath = ['/usr/lib/$ISALIST', '/usr/lib', '/lib/$ISALIST', '/lib']
+ self.assertEqual(
+ expected_runpath,
+ checkpkg.ParseDumpOutput(dump_2.DATA_DUMP_OUTPUT)["runpath"])
+
+
+if __name__ == '__main__':
+ unittest.main()
Deleted: csw/mgar/gar/v2/bin/checkpkg.d/testdata/checkpkg_test_data_CSWlibpq_84.py
===================================================================
--- csw/mgar/gar/v2-checkpkg/bin/checkpkg.d/testdata/checkpkg_test_data_CSWlibpq_84.py 2010-01-04 03:57:34 UTC (rev 7855)
+++ csw/mgar/gar/v2/bin/checkpkg.d/testdata/checkpkg_test_data_CSWlibpq_84.py 2010-01-04 10:28:15 UTC (rev 7856)
@@ -1,10 +0,0 @@
-# Testing data for CSWlibpq-84
-# $Id$
-DATA_PKGNAME = 'CSWlibpq-84'
-DATA_DECLARED_DEPENDENCIES = {'CSWlibxml2': 'CSWlibxml2 libxml2 - XML Parser Library ', 'CSWkrb5lib': 'CSWkrb5lib krb5_lib - MIT Kerberos 5 core libraries ', 'CSWlibxslt': 'CSWlibxslt libxslt - XSLT engine runtime package ', 'CSWcommon': 'CSWcommon common - common files and dirs for CSW packages ', 'CSWisaexec': 'CSWisaexec isaexec - sneaky wrapper around Sun isaexec ', 'CSWzlib': 'CSWzlib zlib - Zlib Data Compression Library ', 'CSWosslrt': 'CSWosslrt openssl_rt - Openssl runtime libraries '}
@@ Diff output truncated at 100000 characters. @@
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