[csw-devel] SF.net SVN: gar:[8698] csw/mgar/gar/v2-git

wahwah at users.sourceforge.net wahwah at users.sourceforge.net
Sat Feb 20 12:24:30 CET 2010


Revision: 8698
          http://gar.svn.sourceforge.net/gar/?rev=8698&view=rev
Author:   wahwah
Date:     2010-02-20 11:24:28 +0000 (Sat, 20 Feb 2010)

Log Message:
-----------
mGAR v2-git: Merged changes from the v2 branch.

Modified Paths:
--------------
    csw/mgar/gar/v2-git/Makefile
    csw/mgar/gar/v2-git/bin/checkpkg
    csw/mgar/gar/v2-git/bin/checkpkg.d/README
    csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-actionclasses.py
    csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-libs.py
    csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-obsolete-deps.py
    csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-you-can-write-your-own.py
    csw/mgar/gar/v2-git/bin/fixlibtool
    csw/mgar/gar/v2-git/bin/update-commondirs
    csw/mgar/gar/v2-git/categories/cpan/category.mk
    csw/mgar/gar/v2-git/categories/x11/category.mk
    csw/mgar/gar/v2-git/etc/commondirs-i386
    csw/mgar/gar/v2-git/etc/commondirs-sparc
    csw/mgar/gar/v2-git/gar.conf.mk
    csw/mgar/gar/v2-git/gar.lib.mk
    csw/mgar/gar/v2-git/gar.mk
    csw/mgar/gar/v2-git/gar.pkg.mk
    csw/mgar/gar/v2-git/lib/python/checkpkg.py
    csw/mgar/gar/v2-git/lib/python/checkpkg_test.py
    csw/mgar/gar/v2-git/lib/python/opencsw.py
    csw/mgar/gar/v2-git/tests/run_tests.py

Added Paths:
-----------
    csw/mgar/gar/v2-git/bin/analyze_module_results.py
    csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-archall.py
    csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-basic.py
    csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-license.py
    csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-missing-symbols.py
    csw/mgar/gar/v2-git/bin/checkpkg_collect_stats.py
    csw/mgar/gar/v2-git/bin/checkpkg_collect_stats_test.py
    csw/mgar/gar/v2-git/bin/custom-pkgtrans
    csw/mgar/gar/v2-git/bin/submitpkg
    csw/mgar/gar/v2-git/bin/update_contents_cache.py
    csw/mgar/gar/v2-git/lib/python/package_checks.py
    csw/mgar/gar/v2-git/lib/python/package_checks_test.py
    csw/mgar/gar/v2-git/lib/python/submit_to_newpkgs.py
    csw/mgar/gar/v2-git/lib/python/testdata/example-1-pkginfo.yml
    csw/mgar/gar/v2-git/lib/python/testdata/example-1-pkgmap.yml
    csw/mgar/gar/v2-git/lib/sh/
    csw/mgar/gar/v2-git/lib/sh/libcheckpkg.sh
    csw/mgar/gar/v2-git/tests/overrides_test.py

Removed Paths:
-------------
    csw/mgar/gar/v2-git/lib/sh/libcheckpkg.sh

Property Changed:
----------------
    csw/mgar/gar/v2-git/
    csw/mgar/gar/v2-git/lib/python/opencsw.py
    csw/mgar/gar/v2-git/pkglib/csw/depend


Property changes on: csw/mgar/gar/v2-git
___________________________________________________________________
Modified: svn:mergeinfo
   - /csw/mgar/gar/v2:4936-6678,6915-8229
/csw/mgar/gar/v2-checkpkg:7722-7855
/csw/mgar/gar/v2-collapsed-modulations:6895
/csw/mgar/gar/v2-dirpackage:8125-8180
/csw/mgar/gar/v2-migrateconf:7082-7211
/csw/mgar/gar/v2-skayser:6087-6132
   + /csw/mgar/gar/v2:4936-6678,6915-8697
/csw/mgar/gar/v2-checkpkg:7722-7855
/csw/mgar/gar/v2-checkpkg-stats:8454-8649
/csw/mgar/gar/v2-collapsed-modulations:6895
/csw/mgar/gar/v2-dirpackage:8125-8180
/csw/mgar/gar/v2-migrateconf:7082-7211
/csw/mgar/gar/v2-skayser:6087-6132

Modified: csw/mgar/gar/v2-git/Makefile
===================================================================
--- csw/mgar/gar/v2-git/Makefile	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/Makefile	2010-02-20 11:24:28 UTC (rev 8698)
@@ -1,3 +1,7 @@
+
+stoptheunwary:
+	$(error "*** You are in the GAR directory and probably didn't mean to call make")
+
 FILTER_DIRS = CVS/ bin/ meta/
 # top-level Makefile for the entire tree.
 %:

Copied: csw/mgar/gar/v2-git/bin/analyze_module_results.py (from rev 8697, csw/mgar/gar/v2/bin/analyze_module_results.py)
===================================================================
--- csw/mgar/gar/v2-git/bin/analyze_module_results.py	                        (rev 0)
+++ csw/mgar/gar/v2-git/bin/analyze_module_results.py	2010-02-20 11:24:28 UTC (rev 8698)
@@ -0,0 +1,53 @@
+#!/opt/csw/bin/python2.6
+# $Id$
+
+import optparse
+import os
+import sys
+
+# The following bit of code sets the correct path to Python libraries
+# distributed with GAR.
+path_list = [os.path.dirname(__file__),
+             "..", "lib", "python"]
+sys.path.append(os.path.join(*path_list))
+import checkpkg
+import opencsw
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option("-e", "--extract-dir", dest="extractdir",
+                    help="Directory with extracted packages")
+  options, args = parser.parse_args()
+  pkgnames = args
+  packages = [opencsw.DirectoryFormatPackage(
+                  os.path.join(options.extractdir, pkgname))
+              for pkgname in pkgnames]
+  overrides_list = [pkg.GetOverrides() for pkg in packages]
+  files = os.listdir(options.extractdir)
+  error_tags = []
+  for file_name in files:
+    if file_name.startswith("tags."):
+      fd = open(os.path.join(options.extractdir, file_name))
+      for line in fd:
+        if line.startswith("#"):
+          continue
+        pkgname, tag_name, tag_info = checkpkg.ParseTagLine(line)
+        error_tags.append(checkpkg.CheckpkgTag(pkgname, tag_name, tag_info))
+  overrides = reduce(lambda x, y: x + y, overrides_list)
+  tags_after_overrides = checkpkg.ApplyOverrides(error_tags, overrides)
+  exit_code = bool(tags_after_overrides)
+  if tags_after_overrides:
+    print "There were errors reported."
+    print "If you know they are false positives, you can override them:"
+    for tag in tags_after_overrides:
+      if tag.tag_info:
+        tag_postfix = "|%s" % tag.tag_info.replace(" ", "|")
+      else:
+        tag_postfix = ""
+      print ("CHECKPKG_OVERRIDES_%s += %s%s"
+             % (tag.pkgname, tag.tag_name, tag_postfix))
+  sys.exit(exit_code)
+
+
+if __name__ == '__main__':
+  main()

Modified: csw/mgar/gar/v2-git/bin/checkpkg
===================================================================
--- csw/mgar/gar/v2-git/bin/checkpkg	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/bin/checkpkg	2010-02-20 11:24:28 UTC (rev 8698)
@@ -21,10 +21,15 @@
 # you know you are tracking the most current version.
 # 
 
-
 PATH=$PATH:/usr/sbin
 readonly NAME_MAX_LENGTH=${NAME_MAX_LENGTH:-20}
 
+command_basename=`basename $0`
+command_basedir="${0%/${command_basename}}"
+libshdir="${command_basedir}/../lib/sh"
+readonly command_basename command_basedir libshdir
+. "${libshdir}/libcheckpkg.sh"
+
 LOCAL_ARCH=`uname -p`
 if [[ -z "${CHECKPKG_TMPDIR}" ]]; then
   readonly CHECKPKG_TMPDIR="/var/tmp"
@@ -36,15 +41,18 @@
 if [[ -t 1 ]]; then
 	GREEN="\\033[0;32;40m"
 	RED="\\033[1;31;40m"
+	BOLD="\\033[1m"
 	COLOR_RESET="\\033[00m"
 else
 	GREEN=""
 	RED=""
+	BOLD=""
 	COLOR_RESET=""
 fi
+readonly GREEN RED BOLD COLOR_RESET
 
 readonly selfpath="$0"
-readonly selfargs="$*"
+readonly selfargs="$@"
 
 # always print out a warning message. (to stderr)
 # exit script, if quit_on_warn set
@@ -122,8 +130,9 @@
 	shift
 fi
 if [[ "$1" == "-h" ]] ; then
-	print 'Usage: checkpkg [-e] pkg1 [pkg2 ....]'
-	print '   -e = "exit on warnings"'
+	print 'Usage: checkpkg [-d] [-e] pkg1 [pkg2 ....]'
+	print '   -d  display debug messages'
+	print '   -e  exit on warnings (soon to be obsolete)'
 	shift
 fi
 
@@ -207,12 +216,6 @@
 basedir=`sed -n 's/^BASEDIR=//p' $TMPFILE`
 pkgarch=`sed -n 's/^ARCH=//p' $TMPFILE|head -1`
 
-case $software in
-     *[A-Z]*)
-	errmsg "$software must be all lowercase"
-	;;
-esac
-
 case `basename $f` in
 	${software}-${version}-*)
 		# file name looks okay
@@ -263,8 +266,12 @@
 	print basedir="'$basedir'"
 fi
 
-if [[ ${#software} -gt ${NAME_MAX_LENGTH} ]] ; then errmsg $f: software name greater than 20 chars ; fi
-if [[ ${#pkgname} -gt ${NAME_MAX_LENGTH} ]] ; then errmsg $f: pkg name greater than 20 chars; fi
+if [[ ${#software} -gt ${NAME_MAX_LENGTH} ]] ; then
+	errmsg "$f: software name longer than ${NAME_MAX_LENGTH} chars"
+fi
+if [[ ${#pkgname} -gt ${NAME_MAX_LENGTH} ]] ; then
+	errmsg "$f: pkg name longer than ${NAME_MAX_LENGTH} chars"
+fi
 
 if [ "$software" = "" ] ; then errmsg $f: software field not set properly in NAME ; fi
 if [ "$pkgname" = "" ] ; then errmsg $f: pkgname field blank ; fi
@@ -331,38 +338,9 @@
 #	exit 0
 #fi
 
-
-# This function exists, because pkgtrans is BROKEN!!
-# It leaves a directory in /var/tmp/aaXXXXXXX, even after clean quit
-# SO, emulate pkgtrans behaviour, for "pkgtrans src destdir pkgname"
-#   Except that we ignore pkgname arg, and just do first one we find.
-#  and we are a bit hacky about how we do things.
-pkgtrans(){
-	if [[ ! -d $2 ]] ; then
-		print ERROR: $2 is not a directory >/dev/fd/2
-		return 1
-	fi
-	hdrblks=`(dd if=$1 skip=1 2>/dev/null| cpio -i -t  >/dev/null) 2>&1 |
-		nawk '{print $1; exit;}'`
-
-	## print initial hdrblks=$hdrblks
-
-	hdrblks=$(($hdrblks + 1))
-	mkdir $2/$3 || return 1
-
-	dd if=$1 skip=$hdrblks 2>/dev/null | (cd $2/$3 ; cpio -ivdm)
-	# on fail, SOMETIMES cpio returns 1, but sometimes it returns 0!!
-	if [[ ! -d $2/$3/install ]] ; then
-		print retrying extract with different archive offset...
-		# no, I cant tell in advance why/when the prev fails
-		hdrblks=$(($hdrblks + 1))
-		dd if=$1 skip=$hdrblks 2>/dev/null| (cd $2/$3 ; cpio -ivdm)
-	fi
-}
-
 print ""
 print Extracing pkg for examination of files...
-pkgtrans $f $EXTRACTDIR $pkgname
+custom_pkgtrans $f $EXTRACTDIR $pkgname
 
 #############################################################
 # We now have the package expanded, in "directory" form, in
@@ -506,7 +484,7 @@
   | sort | uniq -c | awk '{print $1}' | sort | uniq | wc -l)"
 if [[ "$repeated_depends" -gt 1 ]]; then
         cat $EXTRACTDIR/$pkgname/install/depend
-        errmsg "$pkgname has multiple depends"
+        errmsg "$pkgname lists a dependency more than once, see above"
 fi
 
 #to retain a record of all packages currently being examined from $@
@@ -520,8 +498,8 @@
     if [[ $? -ne 0 ]]; then
 	#if we've already looked at the package named $dep,
 	#it'll be in the file.
- 	awk "\$1 == \"$dep\" {print}" $SETDEPS | /usr/bin/grep $dep >/dev/null
- 	if [[ $? -ne 0 ]]; then #we haven't yet seen this package in our set
+	awk "\$1 == \"$dep\" {print}" $SETDEPS | /usr/bin/grep $dep >/dev/null
+	if [[ $? -ne 0 ]]; then #we haven't yet seen this package in our set
 	    echo "Can't validate dependence on $dep.  Storing for delayed validation."
 	    #store for validation at the end.
 	    echo "$dep $pkgname" >> $SETDEPS.missing
@@ -560,71 +538,105 @@
 set_variables_for_individual_package_check "$f"
 
 test_suite_ok=1
-checkpkg_scriptname=`basename $0`
-checkpkg_basedir=${0%/${checkpkg_scriptname}}
-plugindir=${checkpkg_basedir}/checkpkg.d
+checkpkg_module_dir=${command_basedir}/checkpkg.d
+checkpkg_module_tag="checkpkg-"
+checkpkg_stats_basedir="${HOME}/.checkpkg/stats"
 
 # Cleaning up old *.pyc files which can cause grief.  This is because of the
 # move of Python libraries.
-for pyc_file in ${plugindir}/opencsw.pyc \
-                ${plugindir}/checkpkg.pyc; do
+for pyc_file in ${checkpkg_module_dir}/opencsw.pyc \
+                ${checkpkg_module_dir}/checkpkg.pyc; do
   if [ -f "${pyc_file}" ]; then
     echo "Removing old pyc file: '${pyc_file}'"
     rm "${pyc_file}"
   fi
 done
 
-# /var/sadm/install/contents cache update
-${plugindir}/update_contents_cache.py
-
 if [[ "${DEBUG}" != "" ]]; then
 	extra_options="--debug"
 fi
-debugmsg "plugindir: '$plugindir'"
+
+# /var/sadm/install/contents cache update
+${command_basedir}/update_contents_cache.py
+# Collects package stats to be later analyzed
+${command_basedir}/checkpkg_collect_stats.py ${extra_options} "$@"
+
+debugmsg "checkpkg_module_dir: '$checkpkg_module_dir'"
 log_files=""
-if [[ -d "$plugindir" ]]; then
-  echo "Running modular tests"
-	# echo plugin dir exists
-	for plugin in "${plugindir}"/checkpkg-*; do
+module_name_format="%-40s"
+md5sums=`gmd5sum "$@" | awk '{print $1}'`
+if [[ -d "${checkpkg_module_dir}" ]]; then
+	echo "Running modular tests in ${checkpkg_module_dir}"
+	for plugin in "${checkpkg_module_dir}/${checkpkg_module_tag}"*; 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
+			plugin_name="`echo ${plugin} | sed -e 's+.*/checkpkg-++' | sed -e 's+\.py$++'`"
+			error_tag_file="tags.${plugin_name}"
+			printf "${BOLD}${module_name_format}${COLOR_RESET} running..." "${plugin_name}"
+			debugmsg "Executing: ${plugin} $extra_options -b \"${checkpkg_stats_basedir}\" -o \"${EXTRACTDIR}/${error_tag_file}\" ${md5sums}"
+			${plugin} \
+				$extra_options \
+				-b "${checkpkg_stats_basedir}" \
+				-o "${EXTRACTDIR}/${error_tag_file}" \
+				${md5sums} \
+				> "${plugin_log}" 2>&1
 			if [[ "$?" -ne 0 ]]; then
-				printf "\rTEST: ${plugin} ${RED}[FAIL]${COLOR_RESET}        \\n"
+				printf "\r${module_name_format} ${RED}[ERROR]${COLOR_RESET}        \\n" "${plugin_name}"
 				test_suite_ok=0
 			else
-				printf "\rTEST: ${plugin} ${GREEN}[OK]${COLOR_RESET}        \\n"
+				printf "\r${module_name_format} [Done]        \\n" "${plugin_name}"
 			fi
 		else
 			debugmsg "'${plugin}' is not executable"
 		fi
 	done
 else
-	debugmsg "plugin dir does not exist"
+	debugmsg "module dir ${checkpkg_module_dir} does not exist"
 fi
 
-echo
 for log_file in ${log_files}; do
-	if [[ -s "${log_file}" ]]; then
+	if [[ `gwc -c "${log_file}" | awk '{print $1}'` -gt 1 ]]; then
 		debugmsg ">> LOG START: ${log_file}"
 		cat "${log_file}"
 		debugmsg "<< LOG END: ${log_file}"
-  else
-  	debugmsg "-- LOG ${log_file} is empty"
+	else
+		debugmsg "-- LOG ${log_file} is empty"
 	fi
 done
-echo
 
 if [[ ${test_suite_ok} -ne 1 ]]; then
-	errmsg "One or more modular tests have failed."
+	errmsg "One or more modular tests have finished with an error."
 else
-	print "All modular tests were successful."
+	print "All modular tests completed.  Analyzing the reports."
 fi
 
+if [[ "${DEBUG}" != "" ]]; then
+	override_info_printed=0
+	for tagfile in ${EXTRACTDIR}/tags.*; do
+		if [[ -s "${tagfile}" ]]; then
+			if [[ "${override_info_printed}" -ne 1 ]]; then
+				echo "# You can use the following lines to create overrides"
+				echo "# See http://wiki.opencsw.org/checkpkg"
+				override_info_printed=1
+			fi
+			echo "# ${tagfile}:"
+			cat "${tagfile}"
+		fi
+	done
+fi
+
+# Collecting errors and applying the overrides.
+${command_basedir}/analyze_module_results.py \
+	-e "${EXTRACTDIR}" \
+	${pkgnames}
+if [[ "$?" -ne 0 ]]; then
+	errmsg "${RED}Modular checks are reporting errors.${COLOR_RESET}"
+else
+	print "${GREEN}All modular tests were successful.${COLOR_RESET}"
+fi
+
 print ""
 
 # Cleaning up after all packages

Modified: csw/mgar/gar/v2-git/bin/checkpkg.d/README
===================================================================
--- csw/mgar/gar/v2-git/bin/checkpkg.d/README	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/bin/checkpkg.d/README	2010-02-20 11:24:28 UTC (rev 8698)
@@ -2,10 +2,12 @@
 
 This directory contains modular checks.  Each check is an executable file,
 written in any language, accepting specific command line options and returning
-the result as a status exit code.
+the result by writing to a text file.
 
 To see the required flags, issue:
 
-./checkpkg-dummy.py -h
+./checkpkg-you-can-write-your-own.py -h
 
 Each test's file name must begin with "checkpkg-".
+
+See http://wiki.opencsw.org/checkpkg for more information.

Modified: csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-actionclasses.py
===================================================================
--- csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-actionclasses.py	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-actionclasses.py	2010-02-20 11:24:28 UTC (rev 8698)
@@ -11,6 +11,8 @@
 import sys
 import re
 
+CHECKPKG_MODULE_NAME = "class action scripts / prototype integrity"
+
 # The following bit of code sets the correct path to Python libraries
 # distributed with GAR.
 path_list = [os.path.dirname(__file__),
@@ -20,38 +22,52 @@
 import opencsw
 
 
-def CheckActionClasses(pkg):
+def CheckActionClasses(pkg_data, debug):
   """Checks the consistency between classes in the prototype and pkginfo."""
   errors = []
-  pkginfo = pkg.GetParsedPkginfo()
-  pkgmap = pkg.GetPkgmap()
+  pkginfo = pkg_data["pkginfo"]
+  pkgmap = pkg_data["pkgmap"]
   pkginfo_classes = set(re.split(opencsw.WS_RE, pkginfo["CLASSES"]))
-  pkgmap_classes = pkgmap.GetClasses()
+  pkgmap_classes = set()
+  for entry in pkgmap:
+    if entry["class"]:  # might be None
+      pkgmap_classes.add(entry["class"])
   only_in_pkginfo = pkginfo_classes.difference(pkgmap_classes)
   only_in_pkgmap = pkgmap_classes.difference(pkginfo_classes)
-  for cls in only_in_pkginfo:
-    print "Class %s of %s is only in pkginfo" % (repr(cls), pkg.pkgname)
-    print "This shouldn't cause any problems, but it might be not necessary."
-  for cls in only_in_pkgmap:
+  for action_class in only_in_pkginfo:
+    error = checkpkg.CheckpkgTag(
+        pkg_data["basic_stats"]["pkgname"],
+        "action-class-only-in-pkginfo",
+        action_class,
+        msg="This shouldn't cause any problems, but it might be not necessary.")
+    errors.append(error)
+  for action_class in only_in_pkgmap:
     errors.append(
-        opencsw.PackageError("Class %s is only in pkgmap" % repr(cls)))
-  if only_in_pkginfo or only_in_pkgmap:
-    print ("pkginfo_classes: %s, pkgmap classes: %s"
-           % (pkginfo_classes, pkgmap_classes))
+        checkpkg.CheckpkgTag(pkg.pkgname, "action-class-only-in-pkgmap", action_class))
   return errors
 
 
 def main():
   options, args = checkpkg.GetOptions()
-  pkgnames = args
-  check_manager = checkpkg.CheckpkgManager(
-      "class action scripts / prototype integrity",
-      options.extractdir,
-      pkgnames,
-      options.debug)
+  if options.debug:
+  	logging.basicConfig(level=logging.DEBUG)
+  else:
+  	logging.basicConfig(level=logging.INFO)
+  md5sums = args
+  # CheckpkgManager class abstracts away things such as the collection of
+  # results.
+  check_manager = checkpkg.CheckpkgManager(CHECKPKG_MODULE_NAME,
+                                           options.stats_basedir,
+                                           md5sums,
+                                           options.debug)
+  # Registering functions defined above.
   check_manager.RegisterIndividualCheck(CheckActionClasses)
-  exit_code, report = check_manager.Run()
-  print report.strip()
+  # Running the checks, reporting and exiting.
+  exit_code, screen_report, tags_report = check_manager.Run()
+  f = open(options.output, "w")
+  f.write(tags_report)
+  f.close()
+  print screen_report.strip()
   sys.exit(exit_code)
 
 

Copied: csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-archall.py (from rev 8697, csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-archall.py)
===================================================================
--- csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-archall.py	                        (rev 0)
+++ csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-archall.py	2010-02-20 11:24:28 UTC (rev 8698)
@@ -0,0 +1,44 @@
+#!/opt/csw/bin/python2.6
+#
+# $Id$
+
+"""Verifies the architecture of the package."""
+
+import os.path
+import re
+import sys
+
+CHECKPKG_MODULE_NAME = "architecture check"
+
+# The following bit of code sets the correct path to Python libraries
+# distributed with GAR.
+path_list = [os.path.dirname(__file__),
+             "..", "..", "lib", "python"]
+sys.path.append(os.path.join(*path_list))
+import checkpkg
+import package_checks
+
+def main():
+  options, args = checkpkg.GetOptions()
+  md5sums = args
+  # CheckpkgManager class abstracts away things such as the collection of
+  # results.
+  check_manager = checkpkg.CheckpkgManager(CHECKPKG_MODULE_NAME,
+                                           options.stats_basedir,
+                                           md5sums,
+                                           options.debug)
+
+  check_manager.RegisterIndividualCheck(
+      package_checks.CheckArchitectureVsContents)
+  exit_code, screen_report, tags_report = check_manager.Run()
+  f = open(options.output, "w")
+  f.write(tags_report)
+  f.close()
+  print screen_report.strip()
+  sys.exit(exit_code)
+
+
+if __name__ == '__main__':
+  main()
+
+# vim:set sw=2 ts=2 sts=2 expandtab:

Copied: csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-basic.py (from rev 8697, csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-basic.py)
===================================================================
--- csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-basic.py	                        (rev 0)
+++ csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-basic.py	2010-02-20 11:24:28 UTC (rev 8698)
@@ -0,0 +1,44 @@
+#!/opt/csw/bin/python2.6
+# $Id: checkpkg-you-can-write-your-own.py 8571 2010-02-16 09:05:51Z wahwah $
+
+"""This is a dummy module. You can use it as a boilerplate for your own modules.
+
+Copy it and modify.
+"""
+
+import os.path
+import sys
+
+CHECKPKG_MODULE_NAME = "basic checks ported from Korn shell"
+
+# The following bit of code sets the correct path to Python libraries
+# distributed with GAR.
+path_list = [os.path.dirname(__file__),
+             "..", "..", "lib", "python"]
+sys.path.append(os.path.join(*path_list))
+import checkpkg
+import package_checks
+
+def main():
+  options, args = checkpkg.GetOptions()
+  md5sums = args
+  # CheckpkgManager class abstracts away things such as the collection of
+  # results.
+  check_manager = checkpkg.CheckpkgManager(CHECKPKG_MODULE_NAME,
+                                           options.stats_basedir,
+                                           md5sums,
+                                           options.debug)
+  # Registering functions defined above.
+  check_manager.RegisterIndividualCheck(package_checks.CatalognameLowercase)
+  check_manager.RegisterIndividualCheck(package_checks.FileNameSanity)
+  # Running the checks, reporting and exiting.
+  exit_code, screen_report, tags_report = check_manager.Run()
+  f = open(options.output, "w")
+  f.write(tags_report)
+  f.close()
+  print screen_report.strip()
+  sys.exit(exit_code)
+
+
+if __name__ == '__main__':
+  main()

Modified: csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-libs.py
===================================================================
--- csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-libs.py	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-libs.py	2010-02-20 11:24:28 UTC (rev 8698)
@@ -1,13 +1,13 @@
 #!/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.
 
+"""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 os
 import os.path
 import copy
@@ -16,7 +16,10 @@
 import logging
 import sys
 import textwrap
+from Cheetah import Template
 
+CHECKPKG_MODULE_NAME = "shared library linking consistency"
+
 # The following bit of code sets the correct path to Python libraries
 # distributed with GAR.
 path_list = [os.path.dirname(__file__),
@@ -25,79 +28,32 @@
 import checkpkg
 import opencsw
 
-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():
+def CheckSharedLibraryConsistency(pkgs_data, debug):
+  ws_re = re.compile(r"\s+")
   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
+  needed_sonames_by_binary = {}
+  filenames_by_soname = {}
+  for pkg_data in pkgs_data:
+    binaries_base = [os.path.basename(x) for x in pkg_data["binaries"]]
+    pkgname = pkg_data["basic_stats"]["pkgname"]
+    binaries_by_pkgname[pkgname] = binaries_base
+    binaries.extend(pkg_data["binaries"])
+    for filename in pkg_data["all_filenames"]:
+      pkg_by_any_filename[filename] = pkgname
+    for binary_data in pkg_data["binaries_dump_info"]:
+      binary_base_name = os.path.basename(binary_data["base_name"])
+      needed_sonames_by_binary[binary_base_name] = binary_data
+      filenames_by_soname[binary_data[checkpkg.SONAME]] = binary_base_name
+    
   # Making the binaries unique
   binaries = set(binaries)
-  ws_re = re.compile(r"\s+")
+  isalist = pkg_data["isalist"]
 
-  # 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.debug("The %s binary doesn't provide a SONAME. "
-                    "(It might be an executable)",
-                   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,
@@ -128,7 +84,7 @@
   # same bit of code with do checking and reporting.
   #
   # TODO: Rewrite this using cheetah templates
-  if options.debug and needed_sonames:
+  if debug and needed_sonames:
     print "Analysis of sonames needed by the package set:"
     binaries_with_missing_sonames = set([])
     for soname in needed_sonames:
@@ -150,10 +106,13 @@
         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])))
+          pass
+          # The error checking needs to be unified: done in one place only.
+          # errors.append(
+          #     checkpkg.CheckpkgTag(
+          #       "%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))
@@ -162,11 +121,10 @@
     print
 
   dependent_pkgs = {}
-  for checker in checkers:
-    pkgname = checker.pkgname
-    dir_format_pkg = opencsw.DirectoryFormatPackage(checker.pkgpath)
-    declared_dependencies = dir_format_pkg.GetDependencies()
-    if options.debug:
+  for checker in pkgs_data:
+    pkgname = checker["basic_stats"]["pkgname"]
+    declared_dependencies = checker["depends"]
+    if 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))
@@ -194,22 +152,50 @@
         pkgs_by_filename,
         filenames_by_soname,
         pkg_by_any_filename)
-    print checker.FormatDepsReport(missing_deps,
-                                   surplus_deps,
-                                   orphan_sonames)
+    namespace = {
+        "pkgname": pkgname,
+        "missing_deps": missing_deps,
+        "surplus_deps": surplus_deps,
+        "orphan_sonames": orphan_sonames,
+    }
+    t = Template.Template(checkpkg.REPORT_TMPL, searchList=[namespace])
+    print unicode(t)
 
     for soname in orphan_sonames:
-      errors.append(checkpkg.Error("The following soname does't belong to "
-                                   "any package: %s" % soname))
+      errors.append(
+          checkpkg.CheckpkgTag(
+            pkgname,
+            "orphan-soname",
+            soname))
+    for missing_dep in missing_deps:
+      errors.append(
+          checkpkg.CheckpkgTag(
+            pkgname,
+            "missing-dependency",
+            missing_dep))
+  return errors
 
-  if errors:
-    for error in errors:
-      logging.error(error)
-    sys.exit(1)
-  else:
-    sys.exit(0)
 
+def main():
+  options, args = checkpkg.GetOptions()
+  md5sums = args
+  # CheckpkgManager class abstracts away things such as the collection of
+  # results.
+  check_manager = checkpkg.CheckpkgManager(CHECKPKG_MODULE_NAME,
+                                           options.stats_basedir,
+                                           md5sums,
+                                           options.debug)
 
+  check_manager.RegisterSetCheck(CheckSharedLibraryConsistency)
+
+  exit_code, screen_report, tags_report = check_manager.Run()
+  f = open(options.output, "w")
+  f.write(tags_report)
+  f.close()
+  print screen_report.strip()
+  sys.exit(exit_code)
+
+
 if __name__ == '__main__':
   main()
 

Copied: csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-license.py (from rev 8697, csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-license.py)
===================================================================
--- csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-license.py	                        (rev 0)
+++ csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-license.py	2010-02-20 11:24:28 UTC (rev 8698)
@@ -0,0 +1,59 @@
+#!/opt/csw/bin/python2.6
+# $Id$
+
+"""Checks for the existence of the license file."""
+
+import logging
+import os.path
+import sys
+
+CHECKPKG_MODULE_NAME = "license presence"
+
+# The following bit of code sets the correct path to Python libraries
+# distributed with GAR.
+path_list = [os.path.dirname(__file__),
+             "..", "..", "lib", "python"]
+sys.path.append(os.path.join(*path_list))
+import checkpkg
+import opencsw
+
+LICENSE_TMPL = "/opt/csw/share/doc/%s/license"
+
+def CheckLicenseFile(pkg_data, debug):
+  """Checks for the presence of the license file."""
+  errors = []
+  pkgmap = pkg_data["pkgmap"]
+  catalogname = pkg_data["basic_stats"]["catalogname"]
+  license_path = LICENSE_TMPL % catalogname
+  pkgmap_paths = [x["path"] for x in pkgmap]
+  if license_path not in pkgmap_paths:
+    errors.append(
+        checkpkg.CheckpkgTag(
+          pkg_data["basic_stats"]["pkgname"],
+          "license-missing",
+          msg="See http://sourceforge.net/apps/trac/gar/wiki/CopyRight"))
+  return errors
+
+
+def main():
+  options, args = checkpkg.GetOptions()
+  md5sums = args
+  # CheckpkgManager class abstracts away things such as the collection of
+  # results.
+  check_manager = checkpkg.CheckpkgManager(CHECKPKG_MODULE_NAME,
+                                           options.stats_basedir,
+                                           md5sums,
+                                           options.debug)
+  # Registering functions defined above.
+  check_manager.RegisterIndividualCheck(CheckLicenseFile)
+  # Running the checks, reporting and exiting.
+  exit_code, screen_report, tags_report = check_manager.Run()
+  f = open(options.output, "w")
+  f.write(tags_report)
+  f.close()
+  print screen_report.strip()
+  sys.exit(exit_code)
+
+
+if __name__ == '__main__':
+  main()

Copied: csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-missing-symbols.py (from rev 8697, csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-missing-symbols.py)
===================================================================
--- csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-missing-symbols.py	                        (rev 0)
+++ csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-missing-symbols.py	2010-02-20 11:24:28 UTC (rev 8698)
@@ -0,0 +1,65 @@
+#!/opt/csw/bin/python2.6
+# $Id$
+
+"""Check for missing symbols in binaries.
+
+http://sourceforge.net/tracker/?func=detail&aid=2939416&group_id=229205&atid=1075770
+"""
+
+import os.path
+import re
+import sys
+import subprocess
+
+CHECKPKG_MODULE_NAME = "missing symbols"
+
+# The following bit of code sets the correct path to Python libraries
+# distributed with GAR.
+path_list = [os.path.dirname(__file__),
+             "..", "..", "lib", "python"]
+sys.path.append(os.path.join(*path_list))
+import checkpkg
+
+# Defining checking functions.
+
+def CheckForMissingSymbols(pkg_data, debug):
+  """Looks for "symbol not found" in ldd -r output."""
+  errors = []
+  binaries = pkg_data["binaries"]
+  symbol_re = re.compile(r"symbol not found:")
+  for binary in binaries:
+    lines = pkg_data["ldd_dash_r"][binary]
+    missing_symbols = False
+    for line in lines:
+      if re.search(symbol_re, line):
+      	missing_symbols = True
+    binary_base = os.path.basename(binary)
+    if missing_symbols:
+    	errors.append(checkpkg.CheckpkgTag(
+    	  pkg_data["basic_stats"]["pkgname"],
+    	  "symbol-not-found", binary_base))
+  return errors
+
+
+def main():
+  options, args = checkpkg.GetOptions()
+  md5sums = args
+  # CheckpkgManager class abstracts away things such as the collection of
+  # results.
+  check_manager = checkpkg.CheckpkgManager(CHECKPKG_MODULE_NAME,
+                                           options.stats_basedir,
+                                           md5sums,
+                                           options.debug)
+  # Registering functions defined above.
+  check_manager.RegisterIndividualCheck(CheckForMissingSymbols)
+  # Running the checks, reporting and exiting.
+  exit_code, screen_report, tags_report = check_manager.Run()
+  f = open(options.output, "w")
+  f.write(tags_report)
+  f.close()
+  print screen_report.strip()
+  sys.exit(exit_code)
+
+
+if __name__ == '__main__':
+  main()

Modified: csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-obsolete-deps.py
===================================================================
--- csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-obsolete-deps.py	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-obsolete-deps.py	2010-02-20 11:24:28 UTC (rev 8698)
@@ -8,6 +8,8 @@
 import os.path
 import sys
 
+CHECKPKG_MODULE_NAME = "obsolete dependencies"
+
 # The following bit of code sets the correct path to Python libraries
 # distributed with GAR.
 path_list = [os.path.dirname(__file__),
@@ -26,36 +28,45 @@
     },
 }
 
-def CheckObsoleteDeps(pkg):
+def CheckObsoleteDeps(pkg_data, debug):
   """Checks for obsolete dependencies."""
   errors = []
-  deps = set(pkg.GetDependencies())
+  deps = set(pkg_data["depends"])
   obsolete_pkg_deps = deps.intersection(set(OBSOLETE_DEPS))
   if obsolete_pkg_deps:
     for obsolete_pkg in obsolete_pkg_deps:
-      errors.append(
-          checkpkg.PackageError(
-            "Package %s should not depend on %s."
-             % (pkg.pkgname, obsolete_pkg)))
+      msg = ""
       if "hint" in OBSOLETE_DEPS[obsolete_pkg]:
-        errors.append(
-            checkpkg.PackageError("Hint: %s" % OBSOLETE_DEPS[obsolete_pkg]["hint"]))
+        msg += "Hint: %s" % OBSOLETE_DEPS[obsolete_pkg]["hint"]
       if "url" in OBSOLETE_DEPS[obsolete_pkg]:
-      	errors.append(
-      	    checkpkg.PackageError("URL: %s" % OBSOLETE_DEPS[obsolete_pkg]["url"]))
+        if msg:
+          msg += ", "
+        msg += "URL: %s" % OBSOLETE_DEPS[obsolete_pkg]["url"]
+      if not msg:
+        msg = None
+      errors.append(
+          checkpkg.CheckpkgTag(
+    	      pkg_data["basic_stats"]["pkgname"],
+            "obsolete-dependency", obsolete_pkg, msg=msg))
   return errors
 
 
 def main():
   options, args = checkpkg.GetOptions()
-  pkgnames = args
-  check_manager = checkpkg.CheckpkgManager("obsolete dependencies",
-                                           options.extractdir,
-                                           pkgnames,
+  md5sums = args
+  # CheckpkgManager class abstracts away things such as the collection of
+  # results.
+  check_manager = checkpkg.CheckpkgManager(CHECKPKG_MODULE_NAME,
+                                           options.stats_basedir,
+                                           md5sums,
                                            options.debug)
   check_manager.RegisterIndividualCheck(CheckObsoleteDeps)
-  exit_code, report = check_manager.Run()
-  print report.strip()
+  # Running the checks, reporting and exiting.
+  exit_code, screen_report, tags_report = check_manager.Run()
+  f = open(options.output, "w")
+  f.write(tags_report)
+  f.close()
+  print screen_report.strip()
   sys.exit(exit_code)
 
 

Modified: csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-you-can-write-your-own.py
===================================================================
--- csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-you-can-write-your-own.py	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/bin/checkpkg.d/checkpkg-you-can-write-your-own.py	2010-02-20 11:24:28 UTC (rev 8698)
@@ -9,6 +9,8 @@
 import os.path
 import sys
 
+CHECKPKG_MODULE_NAME = "a template of a checkpkg module"
+
 # The following bit of code sets the correct path to Python libraries
 # distributed with GAR.
 path_list = [os.path.dirname(__file__),
@@ -16,16 +18,19 @@
 sys.path.append(os.path.join(*path_list))
 import checkpkg
 
-# Defining checking functions.
+# Defining the checking functions.  They come in two flavors: individual
+# package checks and set checks.
 
-def MyCheckForAsinglePackage(pkg):
+def MyCheckForAsinglePackage(pkg_data, debug):
   """Checks an individual package.
   
   Gets a DirctoryFormatPackage as an argument, and returns a list of errors.
 
-  Errors should be a list of checkpkg.PackageError objects:
+  Errors should be a list of checkpkg.CheckpkgTag objects:
+  errors.append(checkpkg.CheckpkgTag(pkg.pkgname, "tag-name"))
 
-  errors.append(checkpkg.PackageError("There's something wrong."))
+  You can also add a parameter:
+  errors.append(checkpkg.CheckpkgTag(pkg.pkgname, "tag-name", "/opt/csw/bin/problem"))
   """
   errors = []
   # Checking code for an individual package goes here.  See the
@@ -35,11 +40,13 @@
   # Here's how to report an error:
   something_is_wrong = False
   if something_is_wrong:
-    errors.append(checkpkg.PackageError("There's something wrong."))
+    errors.append(checkpkg.CheckpkgTag(
+      pkg_data["basic_stats"]["pkgname"],
+      "example-problem", "thing"))
   return errors
 
 
-def MyCheckForAsetOfPackages(pkgs):
+def MyCheckForAsetOfPackages(pkgs_data, debug):
   """Checks a set of packages.
 
   Sometimes individual checks aren't enough. If you need to write code which
@@ -54,19 +61,22 @@
 
 def main():
   options, args = checkpkg.GetOptions()
-  pkgnames = args
+  md5sums = args
   # CheckpkgManager class abstracts away things such as the collection of
   # results.
-  check_manager = checkpkg.CheckpkgManager("a template of a checkpkg module",
-                                           options.extractdir,
-                                           pkgnames,
+  check_manager = checkpkg.CheckpkgManager(CHECKPKG_MODULE_NAME,
+                                           options.stats_basedir,
+                                           md5sums,
                                            options.debug)
   # Registering functions defined above.
   check_manager.RegisterIndividualCheck(MyCheckForAsinglePackage)
   check_manager.RegisterSetCheck(MyCheckForAsetOfPackages)
   # Running the checks, reporting and exiting.
-  exit_code, report = check_manager.Run()
-  print report.strip()
+  exit_code, screen_report, tags_report = check_manager.Run()
+  f = open(options.output, "w")
+  f.write(tags_report)
+  f.close()
+  print screen_report.strip()
   sys.exit(exit_code)
 
 

Copied: csw/mgar/gar/v2-git/bin/checkpkg_collect_stats.py (from rev 8697, csw/mgar/gar/v2/bin/checkpkg_collect_stats.py)
===================================================================
--- csw/mgar/gar/v2-git/bin/checkpkg_collect_stats.py	                        (rev 0)
+++ csw/mgar/gar/v2-git/bin/checkpkg_collect_stats.py	2010-02-20 11:24:28 UTC (rev 8698)
@@ -0,0 +1,42 @@
+#!/opt/csw/bin/python2.6
+#
+# $Id$
+#
+# Collects statistics about a package and saves to a directory, for later use
+# by checkpkg modules.
+
+import logging
+import optparse
+import os
+import os.path
+import subprocess
+import sys
+
+# The following bit of code sets the correct path to Python libraries
+# distributed with GAR.
+path_list = [os.path.dirname(__file__),
+             "..", "lib", "python"]
+sys.path.append(os.path.join(*path_list))
+import checkpkg
+import opencsw
+
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option("-d", "--debug", dest="debug",
+                    default=False, action="store_true",
+                    help="Turn on debugging messages")
+  options, args = parser.parse_args()
+  if options.debug:
+    logging.basicConfig(level=logging.DEBUG)
+  else:
+    logging.basicConfig(level=logging.INFO)
+  logging.info("Collecting statistics about given package files.")
+  logging.debug("calling: %s, please be patient", args)
+  packages = [opencsw.CswSrv4File(x, options.debug) for x in args]
+  stats_list = [checkpkg.PackageStats(pkg) for pkg in packages]
+  for pkg_stats in stats_list:
+  	pkg_stats.CollectStats()
+
+if __name__ == '__main__':
+	main()

Copied: csw/mgar/gar/v2-git/bin/checkpkg_collect_stats_test.py (from rev 8697, csw/mgar/gar/v2/bin/checkpkg_collect_stats_test.py)
===================================================================
--- csw/mgar/gar/v2-git/bin/checkpkg_collect_stats_test.py	                        (rev 0)
+++ csw/mgar/gar/v2-git/bin/checkpkg_collect_stats_test.py	2010-02-20 11:24:28 UTC (rev 8698)
@@ -0,0 +1,34 @@
+#!/opt/csw/bin/python2.6
+
+import os
+import sys
+import unittest
+import mox
+import checkpkg_collect_stats as ccs
+
+# The following bit of code sets the correct path to Python libraries
+# distributed with GAR.
+path_list = [os.path.dirname(__file__),
+             "..", "lib", "python"]
+sys.path.append(os.path.join(*path_list))
+import checkpkg
+import opencsw
+
+
+class PackageStatsUnitTest(unittest.TestCase):
+
+  def setUp(self):
+    self.mocker = mox.Mox()
+
+  def testGetStatsPath(self):
+    mock_pkg = self.mocker.CreateMock(opencsw.CswSrv4File)
+    mock_pkg.GetMd5sum().AndReturn("abcdef")
+    self.mocker.ReplayAll()
+    sc = ccs.PackageStats(mock_pkg)
+    expected = "/home/joe/.checkpkg/stats/ab/abcdef"
+    self.assertEqual(expected, sc.GetStatsPath("/home/joe"))
+    self.mocker.VerifyAll()
+
+
+if __name__ == '__main__':
+	unittest.main()

Copied: csw/mgar/gar/v2-git/bin/custom-pkgtrans (from rev 8697, csw/mgar/gar/v2/bin/custom-pkgtrans)
===================================================================
--- csw/mgar/gar/v2-git/bin/custom-pkgtrans	                        (rev 0)
+++ csw/mgar/gar/v2-git/bin/custom-pkgtrans	2010-02-20 11:24:28 UTC (rev 8698)
@@ -0,0 +1,22 @@
+#!/bin/ksh -p
+# 
+# $Id$
+#
+# This file exists in order to avoid implementing pipelines in Python.  It
+# could be integrated into the package stats collection program.
+
+command_basename=`basename $0`
+command_basedir="${0%/${command_basename}}"
+libshdir="${command_basedir}/../lib/sh"
+readonly command_basename command_basedir libshdir
+. "${libshdir}/libcheckpkg.sh"
+
+if [[ -z "$1" || -z "$2" || -z "$3" ]]; then
+	print >&2 "usage: $0 <file.pkg> <targetdir> <pkgname>"
+	exit 1
+fi
+if [[ "$3" == "all" ]]; then
+  print >&2 "This script can't handle 'all' as the third argument"
+  exit 1
+fi
+custom_pkgtrans "$1" "$2" "$3"

Modified: csw/mgar/gar/v2-git/bin/fixlibtool
===================================================================
--- csw/mgar/gar/v2-git/bin/fixlibtool	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/bin/fixlibtool	2010-02-20 11:24:28 UTC (rev 8698)
@@ -21,7 +21,6 @@
 #       @$(MAKECOOKIE)
 #
 ####################################################
-
 umask 0022
 PATH=/opt/csw/bin
 
@@ -34,7 +33,8 @@
 ## Fix Makefiles
 for mk in $(gfind ${BASEPATH} -name Makefile -print); do
     gcp ${mk} ${mk}.orig
-    LT_FILES=$(for lib in $(ggrep '/opt/csw.*/lib/.*\.la' ${mk}); do \
+    LT_FILES=$(for lib in $(gegrep -v '^#|^$' ${mk} | \
+                   ggrep '/opt/csw.*/lib/.*\.la'); do \
                    echo $lib |gsed -ne '/\/opt.*\.la/p'; done)
     for file in ${LT_FILES}; do
         LIB_NAME=$(ggrep 'dlname=' ${file} | \
@@ -44,7 +44,7 @@
         fixpath=$(gecho $file |gsed 's/\//\\\//g')
         gsed "s/${fixpath}/-l${LIB_NAME}/g" ${mk} >${mk}.new
         LIB_DIR=$(ggrep 'libdir=' ${file} | gsed -e "s/.*'\(.*\)'/\1/")
-        gsed "s,\(LDFLAGS =.*\),\1 -R${LIB_DIR} -L${LIB_DIR}," ${mk}.new >${mk}
+        perl -pe 's,(LDFLAGS =[^\\]*)(\\)?\n,$1 -R'${LIB_DIR}' -L'${LIB_DIR}' $2\n,' ${mk}.new >${mk}
         gchmod +x ${mk}
     done
 done

Copied: csw/mgar/gar/v2-git/bin/submitpkg (from rev 8697, csw/mgar/gar/v2/bin/submitpkg)
===================================================================
--- csw/mgar/gar/v2-git/bin/submitpkg	                        (rev 0)
+++ csw/mgar/gar/v2-git/bin/submitpkg	2010-02-20 11:24:28 UTC (rev 8698)
@@ -0,0 +1 @@
+link ../lib/python/submit_to_newpkgs.py
\ No newline at end of file

Modified: csw/mgar/gar/v2-git/bin/update-commondirs
===================================================================
--- csw/mgar/gar/v2-git/bin/update-commondirs	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/bin/update-commondirs	2010-02-20 11:24:28 UTC (rev 8698)
@@ -29,7 +29,10 @@
   print ($l[3] =~ /([^=]*)/);
   print "\n";
 }
-  ' $TMPDIR/CSWcommon/pkgmap; echo "/var"; echo "/var/run") > ../etc/commondirs-$1
+  ' $TMPDIR/CSWcommon/pkgmap
+    echo "/var"; echo "/var/run"
+    echo "/usr"; echo "/usr/sadm"; echo "/usr/sadm/install"; echo "/usr/sadm/install/scripts"
+  ) > ../etc/commondirs-$1
 
   rm -rf $TMPDIR
 }

Copied: csw/mgar/gar/v2-git/bin/update_contents_cache.py (from rev 8697, csw/mgar/gar/v2/bin/update_contents_cache.py)
===================================================================
--- csw/mgar/gar/v2-git/bin/update_contents_cache.py	                        (rev 0)
+++ csw/mgar/gar/v2-git/bin/update_contents_cache.py	2010-02-20 11:24:28 UTC (rev 8698)
@@ -0,0 +1,27 @@
+#!/opt/csw/bin/python2.6
+#
+# $Id$
+#
+# This file only creates an instance of SystemPkgmap in order to update the
+# package cache (if necessary), and display the information about the update.
+
+import os
+import os.path
+import sys
+import logging
+
+# The following bit of code sets the correct path to Python libraries
+# distributed with GAR.
+path_list = [os.path.dirname(__file__),
+             "..", "lib", "python"]
+sys.path.append(os.path.join(*path_list))
+import checkpkg
+
+def main():
+  print "Checking if the package cache is up to date."
+  logging.basicConfig(level=logging.INFO)
+  test_pkgmap = checkpkg.SystemPkgmap()
+
+
+if __name__ == '__main__':
+	main()

Modified: csw/mgar/gar/v2-git/categories/cpan/category.mk
===================================================================
--- csw/mgar/gar/v2-git/categories/cpan/category.mk	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/categories/cpan/category.mk	2010-02-20 11:24:28 UTC (rev 8698)
@@ -62,10 +62,11 @@
 INSTALL_ENV   += PERL5LIB=$(PERL5LIB)
 
 # Configure a target using Makefile.PL
+_CATEGORY_LD_OPTIONS ?= -L$(libdir) -lperl
 PERL_CONFIGURE_ARGS ?= INSTALLDIRS=vendor $(EXTRA_PERL_CONFIGURE_ARGS)
 configure-%/Makefile.PL:
 	@echo " ==> Running Makefile.PL in $*"
-	@( cd $* ; \
+	( cd $* ; \
 	    $(CONFIGURE_ENV) perl Makefile.PL \
 	        $(CONFIGURE_ARGS) $(PERL_CONFIGURE_ARGS) )
 	@$(MAKECOOKIE)
@@ -73,14 +74,14 @@
 PERLBUILD_CONFIGURE_ARGS ?= installdirs=vendor $(EXTRA_PERLBUILD_CONFIGURE_ARGS)
 configure-%/Build.PL:
 	@echo " ==> Running Build.PL in $*"
-	@( cd $* ; \
+	( cd $* ; \
 	    $(CONFIGURE_ENV) perl Build.PL \
 	        $(PERLBUILD_CONFIGURE_ARGS) $(CONFIGURE_ARGS) )
 	@$(MAKECOOKIE)
 
 build-%/Build:
 	@echo " ==> Running Build in $*"
-	@( cd $* ; $(BUILD_ENV) ./Build )
+	( cd $* ; $(BUILD_ENV) ./Build )
 	@$(MAKECOOKIE)
 
 test-%/Build:

Modified: csw/mgar/gar/v2-git/categories/x11/category.mk
===================================================================
--- csw/mgar/gar/v2-git/categories/x11/category.mk	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/categories/x11/category.mk	2010-02-20 11:24:28 UTC (rev 8698)
@@ -1,7 +1,7 @@
 # X11
 
 # Version of X11 
-X11_RELEASE_VERSION = X11R7.4
+X11_RELEASE_VERSION = X11R7.5
 
 # Definition of the URL to access sources
 X11_PROTO_MASTER_SITE = http://xorg.freedesktop.org/releases/$(X11_RELEASE_VERSION)/src/proto/

Modified: csw/mgar/gar/v2-git/etc/commondirs-i386
===================================================================
--- csw/mgar/gar/v2-git/etc/commondirs-i386	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/etc/commondirs-i386	2010-02-20 11:24:28 UTC (rev 8698)
@@ -156,3 +156,7 @@
 /var/opt/csw/pkg-hooks
 /var
 /var/run
+/usr
+/usr/sadm
+/usr/sadm/install
+/usr/sadm/install/scripts

Modified: csw/mgar/gar/v2-git/etc/commondirs-sparc
===================================================================
--- csw/mgar/gar/v2-git/etc/commondirs-sparc	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/etc/commondirs-sparc	2010-02-20 11:24:28 UTC (rev 8698)
@@ -160,3 +160,7 @@
 /var/opt/csw/pkg-hooks
 /var
 /var/run
+/usr
+/usr/sadm
+/usr/sadm/install
+/usr/sadm/install/scripts

Modified: csw/mgar/gar/v2-git/gar.conf.mk
===================================================================
--- csw/mgar/gar/v2-git/gar.conf.mk	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/gar.conf.mk	2010-02-20 11:24:28 UTC (rev 8698)
@@ -179,6 +179,7 @@
 DEF_BASE_PKGS += CSWgsed
 DEF_BASE_PKGS += CSWgtar
 DEF_BASE_PKGS += CSWpy-cheetah
+DEF_BASE_PKGS += CSWpy-yaml
 DEF_BASE_PKGS += CSWpython
 DEF_BASE_PKGS += CSWtextutils
 DEF_BASE_PKGS += CSWwget
@@ -497,10 +498,10 @@
 # may not be a subdirectory for the 32-bit standard case (this would normally
 # be a symlink of the form lib/sparcv8 -> . and lib/i386 -> .). This is most likely
 # the case for libraries in $(EXTRA_LIB) for which no links generated in CSWcommon.
-RUNPATH_DIRS ?= $(libpath_install) $(filter-out $(libpath_install),$(libdir_install)) $(EXTRA_LIB) $(EXTRA_RUNPATH_DIRS)
+RUNPATH_DIRS ?= $(EXTRA_RUNPATH_DIRS) $(EXTRA_LIB) $(filter-out $(libpath_install),$(libdir_install)) $(libpath_install)
 
 ifndef NOISALIST
-RUNPATH_ISALIST ?= $(libpath_install) $(filter-out $(libpath_install),$(libdir_install)) $(EXTRA_LIB) $(EXTRA_RUNPATH_ISALIST)
+RUNPATH_ISALIST ?= $(EXTRA_RUNPATH_DIRS) $(EXTRA_LIB) $(filter-out $(libpath_install),$(libdir_install)) $(libpath_install)
 endif
 
 # Iterate over all directories in RUNPATH_DIRS, prefix each directory with one
@@ -508,7 +509,7 @@
 RUNPATH_LINKER_FLAGS ?= $(foreach D,$(RUNPATH_DIRS),$(addprefix -R,$(addsuffix /\$$ISALIST,$(filter $D,$(RUNPATH_ISALIST))) $(abspath $D/$(MM_LIBDIR)))) $(addprefix -R,$(filter-out $(RUNPATH_DIRS),$(RUNPATH_ISALIST))) $(EXTRA_RUNPATH_LINKER_FLAGS)
 endif
 
-LINKER_FLAGS ?= $(foreach ELIB,$(libpath_install) $(filter-out $(libpath_install),$(libdir_install)) $(EXTRA_LIB),-L$(abspath $(ELIB)/$(MM_LIBDIR))) $(EXTRA_LINKER_FLAGS)
+LINKER_FLAGS ?= $(foreach ELIB,$(EXTRA_LIB) $(filter-out $(libpath_install),$(libdir_install)) $(libpath_install),-L$(abspath $(ELIB)/$(MM_LIBDIR))) $(EXTRA_LINKER_FLAGS)
 
 CC_HOME  = $($(GARCOMPILER)_CC_HOME)
 CC       = $($(GARCOMPILER)_CC)
@@ -525,7 +526,7 @@
 SOS11_LD_OPTIONS = $(EXTRA_SOS11_LD_OPTIONS) $(EXTRA_SOS_LD_OPTIONS)
 SOS12_LD_OPTIONS = $(EXTRA_SOS12_LD_OPTIONS) $(EXTRA_SOS_LD_OPTIONS)
 
-LD_OPTIONS ?= $(strip $($(GARCOMPILER)_LD_OPTIONS) $(RUNPATH_LINKER_FLAGS) $(EXTRA_LD_OPTIONS))
+LD_OPTIONS ?= $(strip $($(GARCOMPILER)_LD_OPTIONS) $(RUNPATH_LINKER_FLAGS) $(EXTRA_LD_OPTIONS) $(_CATEGORY_LD_OPTIONS))
 
 # 1. Make sure everything works fine for SOS12
 # 2. Allow us to use programs we just built. This is a bit complicated,

Modified: csw/mgar/gar/v2-git/gar.lib.mk
===================================================================
--- csw/mgar/gar/v2-git/gar.lib.mk	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/gar.lib.mk	2010-02-20 11:24:28 UTC (rev 8698)
@@ -196,6 +196,8 @@
 #				  echo ""; \
 #				  echo "Please consider updating your package. Documentation is available from this link : http://www.opencsw.org" ; \
 #				  echo ""; \
+#				  echo "Questions, problem report or help should be sent to mailto:maintainers at lists.opencsw.org"; \
+#				  echo ""; \
 #				  echo "--"; \
 #				  echo "Kindest regards"; \
 #				  echo "upstream notification job"; } | $(GARBIN)/mail2maintainer -s '[svn] $(GARNAME) upstream update notification' $(GARNAME); \
@@ -222,6 +224,8 @@
 				echo "    $(UPSTREAM_MASTER_SITES)"; \
 				echo ""; \
 				echo "Please consider updating your package." ; \
+			        echo ""; \
+    			        echo "Questions, problem report or help should be sent to mailto:maintainers at lists.opencsw.org"; \
 				echo ""; \
 				echo "--"; \
 				echo "Kindest regards"; \

Modified: csw/mgar/gar/v2-git/gar.mk
===================================================================
--- csw/mgar/gar/v2-git/gar.mk	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/gar.mk	2010-02-20 11:24:28 UTC (rev 8698)
@@ -295,7 +295,7 @@
 	@echo "[===== NOW BUILDING: $(DISTNAME) MODULATION $(MODULATION): $(foreach M,$(MODULATORS),$M=$($M)) =====]"
 
 # prerequisite	- Make sure that the system is in a sane state for building the package
-PREREQUISITE_TARGETS = $(addprefix prerequisitepkg-,$(PREREQUISITE_BASE_PKGS) $(BUILD_DEP_PKGS)) $(addprefix prerequisite-,$(PREREQUISITE_SCRIPTS))
+PREREQUISITE_TARGETS = $(addprefix prerequisitepkg-,$(PREREQUISITE_BASE_PKGS) $(BUILD_DEP_PKGS) $(DEP_PKGS) $(foreach S,$(_PKG_SPECS),$(DEP_PKGS_$S))) $(addprefix prerequisite-,$(PREREQUISITE_SCRIPTS))
 
 # Force to be called in global modulation
 prerequisite: $(if $(filter global,$(MODULATION)),announce pre-everything $(COOKIEDIR) $(DOWNLOADDIR) $(PARTIALDIR) $(addprefix dep-$(GARDIR)/,$(FETCHDEPS)) pre-prerequisite $(PREREQUISITE_TARGETS) post-prerequisite)
@@ -650,24 +650,10 @@
 # These directories get relocated into their ISA subdirectories
 MERGE_DIRS ?= $(MERGE_DIRS_$(MODULATION))
 
-# The files in ISAEXEC get relocated and will be replaced by the isaexec-wrapper
-_ISAEXEC_EXCLUDE_FILES = $(bindir)/%-config $(bindir)/%/%-config
-_ISAEXEC_FILES = $(filter-out $(foreach F,$(_ISAEXEC_EXCLUDE_FILES) $(ISAEXEC_EXCLUDE_FILES),$(PKGROOT)$(F)), \
-			$(wildcard $(foreach D,$(ISAEXEC_DIRS),$(PKGROOT)$(D)/* )) \
-		)
-ISAEXEC_FILES ?= $(if $(_ISAEXEC_FILES),$(patsubst $(PKGROOT)%,%,		\
-	$(shell for F in $(_ISAEXEC_FILES); do		\
-		if test -f "$$F" -a \! -h "$$F"; then echo $$F; fi;	\
-	done)),)
-
 ifneq ($(COMMON_PKG_DEPENDS),)
 _EXTRA_GAR_PKGS += $(COMMON_PKG_DEPENDS)
 endif
 
-ifneq ($(ISAEXEC_FILES),)
-_EXTRA_GAR_PKGS += CSWisaexec
-endif
-
 # These merge-rules are actually processed for the current modulation
 MERGE_TARGETS ?= $(addprefix merge-,$(MERGE_SCRIPTS_$(MODULATION))) $(EXTRA_MERGE_TARGETS)
 
@@ -749,7 +735,7 @@
 
 
 # The basic merge merges the compiles for all ISAs on the current architecture
-merge: checksum pre-merge merge-do merge-license merge-classutils $(if $(COMPILE_ELISP),compile-elisp) $(if $(NOSOURCEPACKAGE),,merge-src) post-merge
+merge: checksum pre-merge merge-do merge-license merge-classutils merge-checkpkgoverrides merge-alternatives $(if $(COMPILE_ELISP),compile-elisp) $(if $(NOSOURCEPACKAGE),,merge-src) post-merge
 	@$(DONADA)
 
 merge-do: $(if $(PARALLELMODULATIONS),merge-parallel,merge-sequential)
@@ -825,7 +811,7 @@
 .PHONY: remerge reset-merge reset-merge-modulated
 remerge: reset-merge merge
 
-reset-merge: reset-package $(addprefix reset-merge-,$(MODULATIONS)) reset-merge-license reset-merge-classutils reset-merge-src
+reset-merge: reset-package $(addprefix reset-merge-,$(MODULATIONS)) reset-merge-license reset-merge-classutils reset-merge-checkpkgoverrides reset-merge-alternatives reset-merge-src
 	@rm -f $(COOKIEDIR)/pre-merge $(foreach M,$(MODULATIONS),$(COOKIEDIR)/merge-$M) $(COOKIEDIR)/merge $(COOKIEDIR)/post-merge
 	@rm -rf $(PKGROOT)
 	@$(DONADA)

Modified: csw/mgar/gar/v2-git/gar.pkg.mk
===================================================================
--- csw/mgar/gar/v2-git/gar.pkg.mk	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/gar.pkg.mk	2010-02-20 11:24:28 UTC (rev 8698)
@@ -32,10 +32,12 @@
 
 ifeq ($(origin PACKAGES), undefined)
 PACKAGES        = $(if $(filter %.gspec,$(DISTFILES)),,CSW$(GARNAME))
+CATALOGNAME     = $(if $(filter %.gspec,$(DISTFILES)),,$(GARNAME))
 SRCPACKAGE_BASE = $(firstword $(basename $(filter %.gspec,$(DISTFILES))) $(PACKAGES))
 SRCPACKAGE     ?= $(SRCPACKAGE_BASE)-src
 SPKG_SPECS     ?= $(basename $(filter %.gspec,$(DISTFILES))) $(PACKAGES) $(if $(NOSOURCEPACKAGE),,$(SRCPACKAGE))
 else
+CATALOGNAME    ?= $(if $(filter-out $(firstword $(PACKAGES)),$(PACKAGES)),,$(patsubst CSW%,%,$(PACKAGES)))
 SRCPACKAGE_BASE = $(firstword $(PACKAGES))
 SRCPACKAGE     ?= $(SRCPACKAGE_BASE)-src
 SPKG_SPECS     ?= $(sort $(basename $(filter %.gspec,$(DISTFILES))) $(PACKAGES) $(if $(NOSOURCEPACKAGE),,$(SRCPACKAGE)))
@@ -67,6 +69,13 @@
 GARPKG_v2 = CSWgar-v2
 RUNTIME_DEP_PKGS_$(SRCPACKAGE) ?= $(or $(GARPKG_$(GARSYSTEMVERSION)),$(error GAR version $(GARSYSTEMVERSION) unknown))
 
+# Sanity checks for r8335
+$(if $(NO_ISAEXEC),$(error The deprecated variable 'NO_ISAEXEC' is defined, please replace it with NOISAEXEC))
+$(if $(PREREQUISITE_PKGS),$(error The deprecated variable 'PREREQUISITE_PKGS' is defined, please replace it with BUILD_DEP_PKGS))
+$(foreach P,$(SPKG_SPECS),$(if $(PREREQUISITE_PKGS_$P),$(error The deprecated variable 'PREREQUISITE_PKGS_$P' is defined, please replace it with BUILD_DEP_PKGS_$P)))
+$(if $(REQUIRED_PKGS),$(error The deprecated variable 'REQUIRED_PKGS' is defined, please replace it with RUNTIME_DEP_PKGS))
+$(foreach P,$(SPKG_SPECS),$(if $(REQUIRED_PKGS_$P),$(error The deprecated variable 'REQUIRED_PACKAGES_$P' is defined, please replace it with RUNTIME_DEP_PKGS_$P)))
+
 _PKG_SPECS      = $(filter-out $(NOPACKAGE),$(SPKG_SPECS))
 
 # pkgname - Get the name of a package from a gspec-name or package-name
@@ -205,6 +214,7 @@
 _CSWCLASSES += cswinetd
 _CSWCLASSES += cswinitsmf
 _CSWCLASSES += cswtexinfo
+_CSWCLASSES += cswpostmsg
 
 # Make sure the configuration files always have a .CSW suffix and rename the
 # configuration files to this if necessary during merge.
@@ -344,7 +354,7 @@
 
 _PROTOTYPE_MODIFIERS = | perl -ane '\
 		$(foreach M,$(PROTOTYPE_MODIFIERS),\
-			$(if $(PROTOTYPE_FILES_$M),if( $$F[2] =~ m(^$(PROTOTYPE_FILES_$M)$$) ) {)\
+			$(if $(PROTOTYPE_FILES_$M),if( $$F[2] =~ m(^$(shell echo $(PROTOTYPE_FILES_$M) | /usr/bin/tr " " "|")$$) ) {)\
 				$(if $(PROTOTYPE_FTYPE_$M),$$F[0] = "$(PROTOTYPE_FTYPE_$M)";)\
 				$(if $(PROTOTYPE_CLASS_$M),$$F[1] = "$(PROTOTYPE_CLASS_$M)";)\
 				$(if $(PROTOTYPE_PERMS_$M),$$F[3] = "$(PROTOTYPE_PERMS_$M)";)\
@@ -352,6 +362,8 @@
 				$(if $(PROTOTYPE_GROUP_$M),$$F[5] = "$(PROTOTYPE_GROUP_$M)";)\
 			$(if $(PROTOTYPE_FILES_$M),})\
 		)\
+		$(foreach F,$(POSTMSG),$$F[1] = "cswpostmsg" if( $$F[2] eq "$F" );)\
+		$$F[1] = "cswalternatives" if( $$F[2] =~ m,^/opt/csw/share/alternatives/[^/]+$$, );\
                 print join(" ", at F),"\n";'
 
 
@@ -382,8 +394,18 @@
 	      -n "$(_PKGFILES_EXCLUDE)" -o \
 	      -n "$(ISAEXEC_FILES_$*)" -o \
 	      -n "$(ISAEXEC_FILES)" ]; then \
-	  (pathfilter $(if $(or $(_PKGFILES_EXCLUDE),$(_PKGFILES_INCLUDE)),-I $(call licensedir,$*)/license -I /etc/opt/csw/pkg/$*/cswmigrateconf) \
-		      $(foreach S,$(filter-out $*,$(SPKG_SPECS)),-X $(call licensedir,$S)/license -X /etc/opt/csw/pkg/$S/cswmigrateconf) \
+	  (pathfilter $(if $(or $(_PKGFILES_EXCLUDE),$(_PKGFILES_INCLUDE)),\
+				-I $(call licensedir,$*)/license \
+				-I /etc/opt/csw/pkg/$*/cswmigrateconf \
+		      		-I /opt/csw/share/alternatives/$(call catalogname,$*) \
+				-I /opt/csw/share/checkpkg/overrides/$(call catalogname,$*) \
+		      )\
+		      $(foreach S,$(filter-out $*,$(SPKG_SPECS)),\
+				-X $(call licensedir,$S)/license \
+				-X /etc/opt/csw/pkg/$S/cswmigrateconf \
+				-X /opt/csw/share/alternatives/$(call catalogname,$S) \
+				-X /opt/csw/share/checkpkg/overrides/$(call catalogname,$S) \
+		      ) \
 		      $(foreach I,$(EXTRA_PKGFILES_INCLUDED) $(EXTRA_PKGFILES_INCLUDED_$*),-i '$I') \
 		      $(foreach X,$(EXTRA_PKGFILES_EXCLUDED) $(EXTRA_PKGFILES_EXCLUDED_$*),-x '$X') \
 		      $(foreach FILE,$(_PKGFILES_INCLUDE),-i '$(FILE)') \
@@ -422,14 +444,15 @@
 # The dependencies to CSWcswclassutils and CSWtexinfo are only added if there are files
 # actually matching the _TEXINFO_FILTER. This is done at the prototype-level.
 $(WORKDIR)/%.depend: $(WORKDIR)/$*.prototype
+$(WORKDIR)/%.depend: _EXTRA_GAR_PKGS += $(if $(strip $(shell cat $(WORKDIR)/$*.prototype | perl -ane 'print "yes" if( $$F[1] eq "cswalternatives")')),CSWalternatives)
 $(WORKDIR)/%.depend: _EXTRA_GAR_PKGS += $(if $(strip $(shell cat $(WORKDIR)/$*.prototype | perl -ane '$(foreach C,$(_CSWCLASSES),print "$C\n" if( $$F[1] eq "$C");)')),CSWcswclassutils)
 
 $(WORKDIR)/%.depend: $(WORKDIR)
-	$(_DBG)$(if $(_EXTRA_GAR_PKGS)$(RUNTIME_DEP_PKGS_$*)$(RUNTIME_DEP_PKGS)$(INCOMPATIBLE_PKGS)$(INCOMPATIBLE_PKGS_$*), \
+	$(_DBG)$(if $(_EXTRA_GAR_PKGS)$(RUNTIME_DEP_PKGS_$*)$(RUNTIME_DEP_PKGS)$(DEP_PKGS)$(DEP_PKGS_$*)$(INCOMPATIBLE_PKGS)$(INCOMPATIBLE_PKGS_$*), \
 		($(foreach PKG,$(INCOMPATIBLE_PKGS_$*) $(INCOMPATIBLE_PKGS),\
 			echo "I $(PKG)";\
 		)\
-		$(foreach PKG,$(sort $(_EXTRA_GAR_PKGS)) $(RUNTIME_DEP_PKGS_$*) $(RUNTIME_DEP_PKGS),\
+		$(foreach PKG,$(sort $(_EXTRA_GAR_PKGS)) $(or $(RUNTIME_DEP_PKGS_$*),$(RUNTIME_DEP_PKGS),$(DEP_PKGS_$*),$(DEP_PKGS)),\
 			$(if $(SPKG_DESC_$(PKG)), \
 				echo "P $(PKG) $(call catalogname,$(PKG)) - $(SPKG_DESC_$(PKG))";, \
 				echo "$(shell (/usr/bin/pkginfo $(PKG) || echo "P $(PKG) - ") | $(GAWK) '{ $$1 = "P"; print } ')"; \
@@ -527,6 +550,7 @@
 
 # The texinfo filter has been taken out of the normal filters as TEXINFO has a default.
 $(WORKDIR)/%.pkginfo: $(WORKDIR)/%.prototype
+$(WORKDIR)/%.pkginfo: SPKG_CLASSES += $(if $(strip $(shell cat $(WORKDIR)/$*.prototype | perl -ane 'print "yes" if( $$F[1] eq "cswalternatives")')),cswalternatives)
 $(WORKDIR)/%.pkginfo: SPKG_CLASSES += $(shell cat $(WORKDIR)/$*.prototype | perl -e 'while(<>){@F=split;$$c{$$F[1]}++};$(foreach C,$(_CSWCLASSES),print "$C\n" if( $$c{$C});)')
 
 $(WORKDIR)/%.pkginfo: $(WORKDIR)
@@ -540,8 +564,9 @@
 	echo "PSTAMP=$(LOGNAME)@$(shell hostname)-$(shell date '+%Y%m%d%H%M%S')"; \
 	echo "CLASSES=$(call pkgvar,SPKG_CLASSES,$*)"; \
 	echo "HOTLINE=http://www.opencsw.org/bugtrack/"; \
+	echo "OPENCSW_CATALOGNAME=$(call catalogname,$*)"; \
+	echo "OPENCSW_MODE64=$(call mode64,$*)"; \
 	echo "OPENCSW_REPOSITORY=$(call _URL)@$(call _REVISION)"; \
-	echo "OPENCSW_MODE64=$(call mode64,$*)"; \
 	) >$@
 
 
@@ -600,8 +625,8 @@
 	@echo "X: $(MIGRATE_FILES_$*) Y: $(MIGRATE_FILES)"
 	$(_DBG)ginstall -d $(PKGROOT)/etc/opt/csw/pkg/$*
 	$(_DBG)(echo "MIGRATE_FILES=\"$(or $(MIGRATE_FILES_$*),$(MIGRATE_FILES))\"";\
-		 $(if $(MIGRATE_SOURCE_DIR_$*),echo "SOURCE_DIR___default__=\"$(MIGRATE_SOURCE_DIR_$*)\"";)\
-		 $(if $(MIGRATE_DEST_DIR_$*),echo "DEST_DIR___default__=\"$(MIGRATE_DEST_DIR_$*)\"";)\
+		 $(if $(or $(MIGRATE_SOURCE_DIR_$*),$(MIGRATE_SOURCE_DIR)),echo "SOURCE_DIR___default__=\"$(or $(MIGRATE_SOURCE_DIR_$*),$(MIGRATE_SOURCE_DIR))\"";)\
+		 $(if $(or $(MIGRATE_DEST_DIR_$*),$(MIGRATE_DEST_DIR)),echo "DEST_DIR___default__=\"$(or $(MIGRATE_DEST_DIR_$*),$(MIGRATE_DEST_DIR))\"";)\
 		 $(foreach F,$(or $(MIGRATE_FILES_$*),$(MIGRATE_FILES)),\
 			$(if $(MIGRATE_SOURCE_DIR_$F),echo "SOURCE_DIR_$(subst .,_,$F)=\"$(MIGRATE_SOURCE_DIR_$F)\"";)\
 			$(if $(MIGRATE_DEST_DIR_$F),echo "DEST_DIR_$(subst .,_,$F)=\"$(MIGRATE_DEST_DIR_$F)\"";)\
@@ -649,6 +674,31 @@
 reset-merge-etcservices:
 	@rm -f $(COOKIEDIR)/merge-etcservices $(foreach SPEC,$(_PKG_SPECS),$(COOKIEDIR)/merge-etcservices-$(SPEC))
 
+merge-checkpkgoverrides-%:
+	@echo "[ Generating checkpkg override for package $* ]"
+	$(_DBG)ginstall -d $(PKGROOT)/opt/csw/share/checkpkg/overrides
+	$(_DBG)($(foreach O,$(or $(CHECKPKG_OVERRIDES_$*),$(CHECKPKG_OVERRIDES)),echo "$O";)) | \
+		perl -F'\|' -ane 'unshift @F,"$*"; $$F[0].=":"; print join(" ", at F );' \
+		> $(PKGROOT)/opt/csw/share/checkpkg/overrides/$(call catalogname,$*)
+	@$(MAKECOOKIE)
+
+merge-checkpkgoverrides: $(foreach S,$(SPKG_SPECS),$(if $(or $(CHECKPKG_OVERRIDES_$S),$(CHECKPKG_OVERRIDES)),merge-checkpkgoverrides-$S))
+
+reset-merge-checkpkgoverrides:
+	@rm -f $(COOKIEDIR)/merge-checkpkgoverrides $(foreach SPEC,$(_PKG_SPECS),$(COOKIEDIR)/merge-checkpkgoverrides-$(SPEC))
+
+merge-alternatives-%:
+	@echo "[ Generating alternatives for package $* ]"
+	$(_DBG)ginstall -d $(PKGROOT)/opt/csw/share/alternatives
+	$(_DBG)($(foreach A,$(or $(ALTERNATIVES_$*),$(ALTERNATIVES)),echo "$(ALTERNATIVE_$A)";)) \
+		> $(PKGROOT)/opt/csw/share/alternatives/$(call catalogname,$*)
+	@$(MAKECOOKIE)
+
+merge-alternatives: $(foreach S,$(SPKG_SPECS),$(if $(or $(ALTERNATIVES_$S),$(ALTERNATIVES)),merge-alternatives-$S))
+
+reset-merge-alternatives:
+	@rm -f $(COOKIEDIR)/merge-alternatives $(foreach SPEC,$(_PKG_SPECS),$(COOKIEDIR)/merge-alternatives-$(SPEC))
+
 merge-src: _SRCDIR=$(PKGROOT)$(sourcedir)/$(call catalogname,$(SRCPACKAGE_BASE))
 merge-src: fetch
 	$(_DBG)mkdir -p $(_SRCDIR)/files
@@ -694,7 +744,22 @@
 # unpacked to global/ for packaging. E. g. 'merge' depends only on the specific
 # modulations and does not fill global/.
 ENABLE_CHECK ?= 1
-_package: validateplatform extract-global merge $(SPKG_DESTDIRS) pre-package $(PACKAGE_TARGETS) post-package $(if $(ENABLE_CHECK),pkgcheck)
+
+# The files in ISAEXEC get relocated and will be replaced by the isaexec-wrapper.
+# The trick is to delay the calculcation of the variable values until that time
+# when PKGROOT has already been populated.
+_ISAEXEC_EXCLUDE_FILES = $(bindir)/%-config $(bindir)/%/%-config
+_buildpackage: _ISAEXEC_FILES=$(filter-out $(foreach F,$(_ISAEXEC_EXCLUDE_FILES) $(ISAEXEC_EXCLUDE_FILES),$(PKGROOT)$(F)), \
+			$(wildcard $(foreach D,$(ISAEXEC_DIRS),$(PKGROOT)$(D)/* )) \
+		)
+_buildpackage: ISAEXEC_FILES ?= $(if $(_ISAEXEC_FILES),$(patsubst $(PKGROOT)%,%,               \
+			$(shell for F in $(_ISAEXEC_FILES); do          \
+				if test -f "$$F" -a \! -h "$$F"; then echo $$F; fi;     \
+			done)),)
+_buildpackage: _EXTRA_GAR_PKGS += $(if $(ISAEXEC_FILES),CSWisaexec)
+_buildpackage: pre-package $(PACKAGE_TARGETS) post-package $(if $(ENABLE_CHECK),pkgcheck)
+
+_package: validateplatform extract-global merge $(SPKG_DESTDIRS) _buildpackage
 	@$(MAKECOOKIE)
 
 package: _package
@@ -770,8 +835,9 @@
 
 # This rule automatically logs into every host where a package for this software should
 # be built. It is especially suited for automated build bots.
+platforms: _PACKAGING_PLATFORMS=$(if $(ARCHALL),$(firstword $(PACKAGING_PLATFORMS)),$(PACKAGING_PLATFORMS))
 platforms:
-	$(foreach P,$(PACKAGING_PLATFORMS),\
+	$(foreach P,$(_PACKAGING_PLATFORMS),\
 		$(if $(PACKAGING_HOST_$P),\
 			$(if $(filter $(THISHOST),$(PACKAGING_HOST_$P)),\
 				$(MAKE) PLATFORM=$P _package && ,\
@@ -783,8 +849,9 @@
 	@echo
 	@echo "The following packages have been built during this invocation:"
 	@echo
-	@$(foreach P,$(PACKAGING_PLATFORMS),\
+	@$(foreach P,$(_PACKAGING_PLATFORMS),\
 		echo "* Platform $P\c";\
+		$(if $(ARCHALL),echo " (suitable for all architectures)\c";) \
 		$(if $(filter $(THISHOST),$(PACKAGING_HOST_$P)),\
 			echo " (built on this host)";\
 			  $(MAKE) -s PLATFORM=$P _pkgshow;echo;,\
@@ -794,11 +861,12 @@
 	)
 	@$(MAKECOOKIE)
 
+platforms-%: _PACKAGING_PLATFORMS=$(if $(ARCHALL),$(firstword $(PACKAGING_PLATFORMS)),$(PACKAGING_PLATFORMS))
 platforms-%:
-	$(foreach P,$(PACKAGING_PLATFORMS),\
+	$(foreach P,$(_PACKAGING_PLATFORMS),\
 		$(if $(PACKAGING_HOST_$P),\
 			$(if $(filter $(THISHOST),$(PACKAGING_HOST_$P)),\
-				$(MAKE) PLATFORM=$P $* && ,\
+				$(MAKE) -s PLATFORM=$P $* && ,\
 				$(SSH) -t $(PACKAGING_HOST_$P) "PATH=$$PATH:/opt/csw/bin $(MAKE) -C $(CURDIR) PLATFORM=$P $*" && \
 			),\
 			$(error *** No host has been defined for platform $P)\

Modified: csw/mgar/gar/v2-git/lib/python/checkpkg.py
===================================================================
--- csw/mgar/gar/v2-git/lib/python/checkpkg.py	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/lib/python/checkpkg.py	2010-02-20 11:24:28 UTC (rev 8698)
@@ -3,6 +3,9 @@
 # This is the checkpkg library, common for all checkpkg tests written in
 # Python.
 
+import copy
+import cPickle
+import errno
 import itertools
 import logging
 import optparse
@@ -12,6 +15,7 @@
 import socket
 import sqlite3
 import subprocess
+import yaml
 from Cheetah import Template
 import opencsw
 
@@ -22,26 +26,30 @@
 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",
-                             u"SUNWcslx"])
+DO_NOT_REPORT_MISSING = set([])
+DO_NOT_REPORT_MISSING_RE = [r"SUNW.*", r"\*SUNW.*"]
+DUMP_BIN = "/usr/ccs/bin/dump"
+
 SYSTEM_SYMLINKS = (
-    ("/opt/csw/bdb4", ["/opt/csw/bdb42"]),
-    ("/64", ["/amd64", "/sparcv9"]),
+    ("/opt/csw/bdb4",     ["/opt/csw/bdb42"]),
+    ("/64",               ["/amd64", "/sparcv9"]),
     ("/opt/csw/lib/i386", ["/opt/csw/lib"]),
 )
+INSTALL_CONTENTS_AVG_LINE_LENGTH = 102.09710677919261
 
 # 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"])
 DEPENDENCY_FILENAME_REGEXES = (
-    (r".*\.pl", u"CSWperl"),
-    (r".*\.pm", u"CSWperl"),
-    (r".*\.py", u"CSWpython"),
-    (r".*\.rb", u"CSWruby"),
+    (r".*\.pl$", u"CSWperl"),
+    (r".*\.pm$", u"CSWperl"),
+    (r".*\.py$", u"CSWpython"),
+    (r".*\.rb$", u"CSWruby"),
 )
 
-REPORT_TMPL = u"""# $pkgname:
+REPORT_TMPL = u"""#if $missing_deps or $surplus_deps or $orphan_sonames
+# $pkgname:
+#end if
 #if $missing_deps
 # SUGGESTION: you may want to add some or all of the following as depends:
 #    (Feel free to ignore SUNW or SPRO packages)
@@ -61,12 +69,9 @@
 # ! $soname
 #end for
 #end if
-#if not $missing_deps and not $surplus_deps and not $orphan_sonames
-# + Dependencies of $pkgname look good.
-#end if
 """
 
-ERROR_REPORT_TMPL = u"""#if $errors
+SCREEN_ERROR_REPORT_TMPL = u"""#if $errors and $debug
 ERROR: One or more errors have been found by $name.
 #for $pkgname in $errors
 $pkgname:
@@ -76,11 +81,23 @@
 #end for
 #else
 #if $debug
-OK: $name found no problems.
+OK: $repr($name) module found no problems.
 #end if
 #end if
 """
 
+# http://www.cheetahtemplate.org/docs/users_guide_html_multipage/language.directives.closures.html
+TAG_REPORT_TMPL = u"""#if $errors
+# Tags reported by $name module
+#for $pkgname in $errors
+#for $tag in $errors[$pkgname]
+$pkgname: ${tag.tag_name}#if $tag.tag_info# $tag.tag_info#end if#
+#end for
+#end for
+#end if
+"""
+
+
 class Error(Exception):
   pass
 
@@ -95,79 +112,35 @@
 
 def GetOptions():
   parser = optparse.OptionParser()
-  parser.add_option("-e", dest="extractdir",
-                    help="The directory into which the package has been extracted")
+  parser.add_option("-b", dest="stats_basedir",
+                    help=("The base directory with package statistics "
+                          "in yaml format, e.g. ~/.checkpkg/stats"))
   parser.add_option("-d", "--debug", dest="debug",
                     default=False, action="store_true",
                     help="Turn on debugging messages")
+  parser.add_option("-o", "--output", dest="output",
+                    help="Output error tag file")
   (options, args) = parser.parse_args()
-  if not options.extractdir:
-    raise ConfigurationError("ERROR: -e option is missing.")
+  if not options.stats_basedir:
+    raise ConfigurationError("ERROR: the -b option is missing.")
+  if not options.output:
+    raise ConfigurationError("ERROR: the -o 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 FormatDepsReport(pkgname, missing_deps, surplus_deps, orphan_sonames):
+  """To be removed."""
+  namespace = {
+      "pkgname": pkgname,
+      "missing_deps": missing_deps,
+      "surplus_deps": surplus_deps,
+      "orphan_sonames": orphan_sonames,
+  }
+  t = Template.Template(REPORT_TMPL, searchList=[namespace])
+  return unicode(t)
 
-  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 FormatDepsReport(self, missing_deps, surplus_deps, orphan_sonames):
-    """To be removed."""
-    namespace = {
-        "pkgname": self.pkgname,
-        "missing_deps": missing_deps,
-        "surplus_deps": surplus_deps,
-        "orphan_sonames": orphan_sonames,
-    }
-    t = Template.Template(REPORT_TMPL, searchList=[namespace])
-    return unicode(t)
-
-
 class SystemPkgmap(object):
   """A class to hold and manipulate the /var/sadm/install/contents file.
 
@@ -235,26 +208,31 @@
         fgrep -f $EXTRACTDIR/liblist >$EXTRACTDIR/shortcatalog
     """
 
+    contents_length = os.stat(SYSTEM_PKGMAP).st_size
+    estimated_lines = contents_length / INSTALL_CONTENTS_AVG_LINE_LENGTH
     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)
+    print "Processing %s" % 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,
+        print "\r~%3.1f%%" % (100.0 * i / estimated_lines,),
       if stop_re.search(line):
         continue
+      if line.startswith("#"):
+        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 "\rAll lines of %s were processed." % SYSTEM_PKGMAP
     print "Creating the main database index."
     sql = "CREATE INDEX basename_idx ON systempkgmap(basename);"
     c.execute(sql)
@@ -316,17 +294,18 @@
     return self.GetFileMtime() <= self.GetDatabaseMtime()
 
   def PurgeDatabase(self):
-    logging.info("Purging the cache database")
     c = self.conn.cursor()
-    sql = "DELETE FROM config;"
-    c.execute(sql)
-    sql = "DELETE FROM systempkgmap;"
-    c.execute(sql)
+    logging.info("Dropping the index.")
     sql = "DROP INDEX basename_idx;"
     try:
       c.execute(sql)
     except sqlite3.OperationalError, e:
       logging.warn(e)
+    logging.info("Deleting all rows from the cache database")
+    sql = "DELETE FROM config;"
+    c.execute(sql)
+    sql = "DELETE FROM systempkgmap;"
+    c.execute(sql)
 
 def SharedObjectDependencies(pkgname,
                              binaries_by_pkgname,
@@ -441,6 +420,11 @@
   # 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))
+  for re_str in DO_NOT_REPORT_MISSING_RE:
+    padded_re = "^%s$" % re_str
+    missing_deps = filter(lambda x: not re.match(padded_re, x),
+                          missing_deps)
+  missing_deps = set(missing_deps)
   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)
@@ -573,14 +557,29 @@
   return binary_data
 
 
+class CheckpkgTag(object):
+  """Represents a tag to be written to the checkpkg tag file."""
+
+  def __init__(self, pkgname, tag_name, tag_info=None, severity=None, msg=None):
+    self.pkgname = pkgname
+    self.tag_name = tag_name
+    self.tag_info = tag_info
+    self.severity = severity
+    self.msg = msg
+
+  def __repr__(self):
+    return (u"CheckpkgTag(%s, %s, %s, ...)"
+            % (repr(self.pkgname), repr(self.tag_name), repr(self.tag_info)))
+
+
 class CheckpkgManager(object):
   """Takes care of calling checking functions"""
 
-  def __init__(self, name, extractdir, pkgname_list, debug=False):
+  def __init__(self, name, stats_basedir, md5sum_list, debug=False):
     self.debug = debug
     self.name = name
-    self.extractdir = extractdir
-    self.pkgname_list = pkgname_list
+    self.md5sum_list = md5sum_list
+    self.stats_basedir = stats_basedir
     self.errors = []
     self.individual_checks = []
     self.set_checks = []
@@ -592,31 +591,372 @@
   def RegisterSetCheck(self, function):
     self.set_checks.append(function)
 
-  def Run(self):
-    """Runs all the checks
+  def GetPackageStatsList(self):
+    stats_list = []
+    for md5sum in self.md5sum_list:
+      stats_list.append(PackageStats(None, self.stats_basedir, md5sum))
+    return stats_list
 
-    Returns a tuple of an exit code and a report.
-    """
-    packages = []
+  def GetAllTags(self, packages_data):
     errors = {}
-    for pkgname in self.pkgname_list:
-        pkg_path = os.path.join(self.extractdir, pkgname)
-        packages.append(opencsw.DirectoryFormatPackage(pkg_path))
-    for pkg in packages:
+    for pkg_data in packages_data:
       for function in self.individual_checks:
-        errors_for_pkg = function(pkg)
+        all_stats = pkg_data.GetAllStats()
+        errors_for_pkg = function(all_stats, debug=self.debug)
         if errors_for_pkg:
-          errors[pkg.pkgname] = errors_for_pkg
+          errors[all_stats["basic_stats"]["pkgname"]] = errors_for_pkg
     # Set checks
     for function in self.set_checks:
-      set_errors = function(packages)
+      set_errors = function([x.GetAllStats() for x in packages_data],
+                            debug=self.debug)
       if set_errors:
-        errors["The package set"] = set_errors
+        # These were generated by a set, but are likely to be bound to specific
+        # packages. We'll try to preserve the package assignments.
+        for tag in set_errors:
+          if tag.pkgname:
+            if not tag.pkgname in errors:
+              errors[tag.pkgname] = []
+            errors[tag.pkgname].append(tag)
+          else:
+            if "package-set" not in errors:
+              errors["package-set"] = []
+            errors["package-set"].append(error)
+    return errors
+
+  def FormatReports(self, errors):
     namespace = {
         "name": self.name,
         "errors": errors,
         "debug": self.debug,
     }
-    t = Template.Template(ERROR_REPORT_TMPL, searchList=[namespace])
-    exit_code = bool(errors)
-    return (exit_code, unicode(t))
+    screen_t = Template.Template(SCREEN_ERROR_REPORT_TMPL, searchList=[namespace])
+    tags_report_t = Template.Template(TAG_REPORT_TMPL, searchList=[namespace])
+    screen_report = unicode(screen_t)
+    tags_report = unicode(tags_report_t)
+    return screen_report, tags_report
+
+  def Run(self):
+    """Runs all the checks
+
+    Returns a tuple of an exit code and a report.
+    """
+    packages_data = self.GetPackageStatsList()
+    errors = self.GetAllTags(packages_data)
+    screen_report, tags_report = self.FormatReports(errors)
+    exit_code = 0
+    return (exit_code, screen_report, tags_report)
+
+
+def ParseTagLine(line):
+  """Parses a line from the tag.${module} file.
+
+  Returns a triplet of pkgname, tagname, tag_info.
+  """
+  level_1 = line.strip().split(":")
+  if len(level_1) > 1:
+    data_1 = level_1[1]
+    pkgname = level_1[0]
+  else:
+    data_1 = level_1[0]
+    pkgname = None
+  level_2 = re.split(WS_RE, data_1.strip())
+  tag_name = level_2[0]
+  if len(level_2) > 1:
+    tag_info = " ".join(level_2[1:])
+  else:
+    tag_info = None
+  return (pkgname, tag_name, tag_info)
+
+
+class Override(object):
+  """Represents an override of a certain checkpkg tag.
+
+  It's similar to checkpkg.CheckpkgTag, but serves a different purpose.
+  """
+
+  def __init__(self, pkgname, tag_name, tag_info):
+    self.pkgname = pkgname
+    self.tag_name = tag_name
+    self.tag_info = tag_info
+
+  def __repr__(self):
+    return (u"Override(%s, %s, %s)"
+            % (self.pkgname, self.tag_name, self.tag_info))
+
+  def DoesApply(self, tag):
+    """Figures out if this override applies to the given tag."""
+    basket_a = {}
+    basket_b = {}
+    if self.pkgname:
+      basket_a["pkgname"] = self.pkgname
+      basket_b["pkgname"] = tag.pkgname
+    if self.tag_info:
+      basket_a["tag_info"] = self.tag_info
+      basket_b["tag_info"] = tag.tag_info
+    basket_a["tag_name"] = self.tag_name
+    basket_b["tag_name"] = tag.tag_name
+    return basket_a == basket_b
+
+def ParseOverrideLine(line):
+  level_1 = line.split(":")
+  if len(level_1) > 1:
+    pkgname = level_1[0]
+    data_1 = level_1[1]
+  else:
+    pkgname = None
+    data_1 = level_1[0]
+  level_2 = re.split(WS_RE, data_1.strip())
+  if len(level_2) > 1:
+    tag_name = level_2[0]
+    tag_info = " ".join(level_2[1:])
+  else:
+    tag_name = level_2[0]
+    tag_info = None
+  return Override(pkgname, tag_name, tag_info)
+
+
+def ApplyOverrides(error_tags, overrides):
+  """Filters out all the error tags that overrides apply to.
+  
+  O(N * M), but N and M are always small.
+  """
+  tags_after_overrides = []
+  for tag in error_tags:
+    override_applies = False
+    for override in overrides:
+      if override.DoesApply(tag):
+        override_applies = True
+    if not override_applies:
+      tags_after_overrides.append(tag)
+  return tags_after_overrides
+
+
+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
+
+
+class PackageStats(object):
+  """Collects stats about a package and saves it."""
+  STATS_VERSION = 1L
+  # This list needs to be synchronized with the CollectStats() method.
+  STAT_FILES = [
+      "all_filenames",
+      "basic_stats",
+      "binaries",
+      "binaries_dump_info",
+      "depends",
+      "isalist",
+      "ldd_dash_r",
+      "overrides",
+      "pkginfo",
+      "pkgmap",
+  ]
+
+  def __init__(self, srv4_pkg, stats_basedir=None, md5sum=None):
+    self.srv4_pkg = srv4_pkg
+    self.md5sum = md5sum
+    self.dir_format_pkg = None
+    self.stats_path = None
+    self.all_stats = {}
+    self.stats_basedir = stats_basedir
+    if not self.stats_basedir:
+      home = os.environ["HOME"]
+      parts = [home, ".checkpkg", "stats"]
+      self.stats_basedir = os.path.join(*parts)
+
+  def GetMd5sum(self):
+    if not self.md5sum:
+      self.md5sum = self.srv4_pkg.GetMd5sum()
+    return self.md5sum
+
+  def GetStatsPath(self):
+    if not self.stats_path:
+      md5sum = self.GetMd5sum()
+      two_chars = md5sum[0:2]
+      parts = [self.stats_basedir, two_chars, md5sum]
+      self.stats_path = os.path.join(*parts)
+    return self.stats_path
+
+  def StatsExist(self):
+    """Checks if statistics of a package exist.
+
+    Returns:
+      bool
+    """
+    if not self.StatsDirExists():
+      return False
+    # More checks can be added in the future.
+    return True
+
+  def StatsDirExists(self):
+    return os.path.isdir(self.GetStatsPath())
+
+  def GetDirFormatPkg(self):
+    if not self.dir_format_pkg:
+      self.dir_format_pkg = self.srv4_pkg.GetDirFormatPkg()
+    return self.dir_format_pkg
+
+  def MakeStatsDir(self):
+    """mkdir -p equivalent.
+
+    http://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python
+    """
+    stats_path = self.GetStatsPath()
+    try:
+      os.makedirs(stats_path)
+    except OSError, e:
+      if e.errno == errno.EEXIST:
+        pass
+      else:
+        raise
+
+  def GetBinaryDumpInfo(self):
+    dir_pkg = self.GetDirFormatPkg()
+    # Binaries. This could be split off to a separate function.
+    # man ld.so.1 for more info on this hack
+    env = copy.copy(os.environ)
+    env["LD_NOAUXFLTR"] = "1"
+    binaries_dump_info = []
+    for binary in dir_pkg.ListBinaries():
+      binary_abs_path = os.path.join(dir_pkg.directory, "root", binary)
+      binary_base_name = os.path.basename(binary)
+      args = [DUMP_BIN, "-Lv", binary_abs_path]
+      dump_proc = subprocess.Popen(args, stdout=subprocess.PIPE, env=env)
+      stdout, stderr = dump_proc.communicate()
+      ret = dump_proc.wait()
+      binary_data = ParseDumpOutput(stdout)
+      binary_data["path"] = binary
+      binary_data["soname_guessed"] = False
+      binary_data["base_name"] = binary_base_name
+      if SONAME not in binary_data:
+        logging.debug("The %s binary doesn't provide a SONAME. "
+                      "(It might be an executable)",
+                     binary_base_name)
+        # The binary doesn't tell its SONAME.  We're guessing it's the
+        # same as the base file name.
+        binary_data[SONAME] = binary_base_name
+        binary_data["soname_guessed"] = True
+      binaries_dump_info.append(binary_data)
+    return binaries_dump_info
+
+  def GetBasicStats(self):
+    dir_pkg = self.GetDirFormatPkg()
+    basic_stats = {}
+    basic_stats["stats_version"] = self.STATS_VERSION
+    basic_stats["pkg_path"] = self.srv4_pkg.pkg_path
+    basic_stats["pkg_basename"] = os.path.basename(self.srv4_pkg.pkg_path)
+    basic_stats["parsed_basename"] = opencsw.ParsePackageFileName(basic_stats["pkg_basename"])
+    basic_stats["pkgname"] = dir_pkg.pkgname
+    basic_stats["catalogname"] = dir_pkg.GetCatalogname()
+    return basic_stats
+
+  def GetOverrides(self):
+    dir_pkg = self.GetDirFormatPkg()
+    overrides = dir_pkg.GetOverrides()
+    def OverrideToDict(override):
+      d = {}
+      d["pkgname"] = override.pkgname
+      d["tag_name"] = override.tag_name
+      d["tag_info"] = override.tag_info
+      return d
+    overrides_simple = [OverrideToDict(x) for x in overrides]
+    return overrides_simple
+
+  def GetLddMinusRlines(self):
+    """Returns ldd -r output."""
+    dir_pkg = self.GetDirFormatPkg()
+    binaries = dir_pkg.ListBinaries()
+    ldd_output = {}
+    for binary in binaries:
+      binary_abspath = os.path.join(dir_pkg.directory, "root", binary)
+      # this could be potentially moved into the DirectoryFormatPackage class.
+      # ldd needs the binary to be executable
+      os.chmod(binary_abspath, 0755)
+      args = ["ldd", "-r", binary_abspath]
+      ldd_proc = subprocess.Popen(
+          args,
+          stdout=subprocess.PIPE,
+          stderr=subprocess.PIPE)
+      stdout, stderr = ldd_proc.communicate()
+      retcode = ldd_proc.wait()
+      if retcode:
+        logging.error("%s returned an error: %s", args, stderr)
+      lines = stdout.splitlines()
+      ldd_output[binary] = lines
+    return ldd_output
+
+
+  def CollectStats(self):
+    stats_path = self.GetStatsPath()
+    self.MakeStatsDir()
+    dir_pkg = self.GetDirFormatPkg()
+    logging.info("Collecting %s package statistics.", repr(dir_pkg.pkgname))
+    self.DumpObject(dir_pkg.GetAllFilenames(), "all_filenames")
+    self.DumpObject(self.GetBasicStats(), "basic_stats")
+    self.DumpObject(dir_pkg.ListBinaries(), "binaries")
+    self.DumpObject(self.GetBinaryDumpInfo(), "binaries_dump_info")
+    self.DumpObject(dir_pkg.GetDependencies(), "depends")
+    self.DumpObject(GetIsalist(), "isalist")
+    self.DumpObject(self.GetOverrides(), "overrides")
+    self.DumpObject(dir_pkg.GetParsedPkginfo(), "pkginfo")
+    self.DumpObject(dir_pkg.GetPkgmap().entries, "pkgmap")
+    self.DumpObject(self.GetLddMinusRlines(), "ldd_dash_r")
+    logging.debug("Statistics collected.")
+
+  def GetAllStats(self):
+    if self.StatsExist():
+      self.all_stats = self.ReadSavedStats()
+    else:
+      self.CollectStats()
+    return self.all_stats
+
+  def DumpObject(self, obj, name):
+    """Saves an object.
+
+    TODO(maciej): Implement pickling with cPickle.
+    """
+    stats_path = self.GetStatsPath()
+    # yaml
+    out_file_name = os.path.join(stats_path, "%s.yml" % name)
+    logging.debug("DumpObject(): writing %s", repr(out_file_name))
+    f = open(out_file_name, "w")
+    f.write(yaml.safe_dump(obj))
+    f.close()
+    # pickle
+    out_file_name_pickle = os.path.join(stats_path, "%s.pickle" % name)
+    f = open(out_file_name_pickle, "wb")
+    cPickle.dump(obj, f)
+    f.close()
+    self.all_stats[name] = obj
+
+  def ReadObject(self, name):
+    """Reads an object."""
+    stats_path = self.GetStatsPath()
+    in_file_name = os.path.join(stats_path, "%s.yml" % name)
+    in_file_name_pickle = os.path.join(stats_path, "%s.pickle" % name)
+    if os.path.exists(in_file_name_pickle):
+      logging.debug("ReadObject(): reading %s", repr(in_file_name_pickle))
+      f = open(in_file_name_pickle, "r")
+      obj = cPickle.load(f)
+      f.close()
+      logging.debug("ReadObject(): finished reading %s", repr(in_file_name_pickle))
+    else:
+      logging.debug("ReadObject(): reading %s", repr(in_file_name))
+      f = open(in_file_name, "r")
+      obj = yaml.safe_load(f)
+      f.close()
+      logging.debug("ReadObject(): finished reading %s", repr(in_file_name))
+    return obj
+
+  def ReadSavedStats(self):
+    all_stats = {}
+    for name in self.STAT_FILES:
+      all_stats[name] = self.ReadObject(name)
+    return all_stats

Modified: csw/mgar/gar/v2-git/lib/python/checkpkg_test.py
===================================================================
--- csw/mgar/gar/v2-git/lib/python/checkpkg_test.py	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/lib/python/checkpkg_test.py	2010-02-20 11:24:28 UTC (rev 8698)
@@ -5,6 +5,7 @@
 import mox
 import difflib
 import checkpkg
+import opencsw
 import testdata.checkpkg_test_data_CSWmysql51rt as d1
 import testdata.checkpkg_test_data_CSWmysql51client as d2
 import testdata.checkpkg_test_data_CSWmysql51 as d3
@@ -150,7 +151,7 @@
 
   def testMissingDeps(self):
     # This tends to report itself...
-    expected = set([u'SUNWgss'])
+    expected = set([])
     self.assertEquals(expected, self.missing_deps)
 
 
@@ -556,8 +557,8 @@
     missing_deps = set([u'SUNWgss', u'*SUNWlxsl'])
     surplus_deps = set(['CSWsudo', 'CSWlibxslt'])
     orphan_sonames = set([u'libm.so.2'])
-    testdata = (missing_deps, surplus_deps, orphan_sonames)
-    checker = checkpkg.CheckpkgBase("/tmp/nonexistent", "CSWfoo")
+    testdata = ("CSWfoo", missing_deps, surplus_deps, orphan_sonames)
+    checker = opencsw.DirectoryFormatPackage("/tmp/nonexistent/CSWfoo")
     expected = u"""# CSWfoo:
 # SUGGESTION: you may want to add some or all of the following as depends:
 #    (Feel free to ignore SUNW or SPRO packages)
@@ -569,21 +570,151 @@
 # The following required sonames would not be found at runtime:
 # ! libm.so.2
 """
-    result = checker.FormatDepsReport(*testdata)
+    result = checkpkg.FormatDepsReport(*testdata)
     self.AssertTextEqual(result, expected)
 
   def testNone(self):
     missing_deps = set([])
     surplus_deps = set([])
     orphan_sonames = set([])
-    testdata = (missing_deps, surplus_deps, orphan_sonames)
-    checker = checkpkg.CheckpkgBase("/tmp/nonexistent", "CSWfoo")
-    expected = u"""# CSWfoo:
-# + Dependencies of CSWfoo look good.
-"""
-    result = checker.FormatDepsReport(*testdata)
+    testdata = ("CSWfoo", missing_deps, surplus_deps, orphan_sonames)
+    checker = opencsw.DirectoryFormatPackage("/tmp/nonexistent/CSWfoo")
+    expected = u""
+    result = checkpkg.FormatDepsReport(*testdata)
     self.AssertTextEqual(result, expected)
 
 
+class CheckpkgTagsUnitTest(unittest.TestCase):
+  
+  def test_1(self):
+    m = checkpkg.CheckpkgManager("testname", "/tmp", ["CSWfoo"])
+    tags = {
+        "CSWfoo": [
+          checkpkg.CheckpkgTag("CSWfoo", "foo-tag", "foo-info"),
+        ],
+    }
+    screen_report, tags_report = m.FormatReports(tags)
+    expected = u'# Tags reported by testname module\nCSWfoo: foo-tag foo-info\n'
+    self.assertEqual(expected, tags_report)
+
+  def test_2(self):
+    m = checkpkg.CheckpkgManager("testname", "/tmp", ["CSWfoo"])
+    tags = {
+        "CSWfoo": [
+          checkpkg.CheckpkgTag("CSWfoo", "foo-tag", "foo-info"),
+          checkpkg.CheckpkgTag("CSWfoo", "bar-tag", "bar-info"),
+          checkpkg.CheckpkgTag("CSWfoo", "baz-tag"),
+        ],
+    }
+    screen_report, tags_report = m.FormatReports(tags)
+    expected = (u'# Tags reported by testname module\n'
+                u'CSWfoo: foo-tag foo-info\n'
+                u'CSWfoo: bar-tag bar-info\n'
+                u'CSWfoo: baz-tag\n')
+    self.assertEqual(expected, tags_report)
+
+  def testParseTagLine1(self):
+    line = "foo-tag"
+    self.assertEquals((None, "foo-tag", None), checkpkg.ParseTagLine(line))
+
+  def testParseTagLine2(self):
+    line = "CSWfoo: foo-tag"
+    self.assertEquals(("CSWfoo", "foo-tag", None), checkpkg.ParseTagLine(line))
+
+  def testParseTagLine3(self):
+    line = "CSWfoo: foo-tag foo-info"
+    self.assertEquals(("CSWfoo", "foo-tag", "foo-info"), checkpkg.ParseTagLine(line))
+
+  def testParseTagLine4(self):
+    line = "CSWfoo: foo-tag foo-info1 foo-info2"
+    self.assertEquals(("CSWfoo", "foo-tag", "foo-info1 foo-info2"), checkpkg.ParseTagLine(line))
+
+
+class ParseOverrideLineUnitTest(unittest.TestCase):
+  
+  def setUp(self):
+    line1 = "CSWfoo: foo-override"
+    line2 = "CSWfoo: foo-override foo-info"
+    line3 = "CSWfoo: foo-override foo-info-1 foo-info-2"
+    self.o1 = checkpkg.ParseOverrideLine(line1)
+    self.o2 = checkpkg.ParseOverrideLine(line2)
+    self.o3 = checkpkg.ParseOverrideLine(line3)
+
+  def test_ParseOverridesLine1(self):
+    self.assertEqual("CSWfoo", self.o1.pkgname)
+
+  def test_ParseOverridesLine2(self):
+    self.assertEqual("foo-override", self.o1.tag_name)
+
+  def test_ParseOverridesLine3(self):
+    self.assertEqual(None, self.o1.tag_info)
+
+  def test_ParseOverridesLine4(self):
+    self.assertEqual("foo-info", self.o2.tag_info)
+
+  def test_ParseOverridesLine5(self):
+    self.assertEqual("CSWfoo", self.o3.pkgname)
+
+  def test_ParseOverridesLine6(self):
+    self.assertEqual("foo-override", self.o3.tag_name)
+
+  def test_ParseOverridesLine7(self):
+    self.assertEqual("foo-info-1 foo-info-2", self.o3.tag_info)
+
+
+class ApplyOverridesUnitTest(unittest.TestCase):
+
+  # This would be better, more terse. But requires metaclasses.
+  DATA_1 = (
+      (None, 'tag1', 'info1', None, 'tag1', 'info1', None),
+  )
+
+  def test_1a(self):
+    """One tag, no overrides."""
+    tags = [checkpkg.CheckpkgTag("CSWfoo", "foo-tag")]
+    overrides = []
+    self.assertEqual(tags, checkpkg.ApplyOverrides(tags, overrides))
+
+  def test_1b(self):
+    """One override, matching by tag name only."""
+    tags = [checkpkg.CheckpkgTag("CSWfoo", "foo-tag")]
+    overrides = [checkpkg.Override(None, "foo-tag", None)]
+    self.assertEqual([], checkpkg.ApplyOverrides(tags, overrides))
+
+  def test_1c(self):
+    """One override, matching by tag name only, no pkgname."""
+    tags = [checkpkg.CheckpkgTag("CSWfoo", "foo-tag")]
+    overrides = [checkpkg.Override(None, "foo-tag", None)]
+    self.assertEqual([], checkpkg.ApplyOverrides(tags, overrides))
+
+  def test_2(self):
+    """One override, matching by tag name and tag info, no pkgname."""
+    tags = [checkpkg.CheckpkgTag("CSWfoo", "foo-tag")]
+    overrides = [checkpkg.Override(None, "foo-tag", None)]
+    self.assertEqual([], checkpkg.ApplyOverrides(tags, overrides))
+
+  def test_3(self):
+    """One override, matching by tag name, mismatching tag info, no pkgname."""
+    tags = [checkpkg.CheckpkgTag("CSWfoo", "foo-tag", "tag-info-1")]
+    overrides = [checkpkg.Override(None, "foo-tag", "tag-info-2")]
+    self.assertEqual(tags, checkpkg.ApplyOverrides(tags, overrides))
+
+  def test_4(self):
+    tags = [checkpkg.CheckpkgTag("CSWfoo", "foo-tag", "tag-info-1")]
+    overrides = [checkpkg.Override(None, "foo-tag", "tag-info-1")]
+    self.assertEqual([], checkpkg.ApplyOverrides(tags, overrides))
+
+  def test_5(self):
+    tags = [checkpkg.CheckpkgTag("CSWfoo", "foo-tag", "tag-info-1")]
+    overrides = [checkpkg.Override("CSWfoo", "foo-tag", "tag-info-1")]
+    self.assertEqual([], checkpkg.ApplyOverrides(tags, overrides))
+
+  def test_5(self):
+    """Pkgname mismatch."""
+    tags = [checkpkg.CheckpkgTag("CSWfoo", "foo-tag", "tag-info-1")]
+    overrides = [checkpkg.Override("CSWbar", "foo-tag", "tag-info-1")]
+    self.assertEqual(tags, checkpkg.ApplyOverrides(tags, overrides))
+
+
 if __name__ == '__main__':
   unittest.main()

Modified: csw/mgar/gar/v2-git/lib/python/opencsw.py
===================================================================
--- csw/mgar/gar/v2-git/lib/python/opencsw.py	2010-02-20 08:31:40 UTC (rev 8697)
+++ csw/mgar/gar/v2-git/lib/python/opencsw.py	2010-02-20 11:24:28 UTC (rev 8698)
@@ -15,6 +15,7 @@
 import copy
 import datetime
 import difflib
+import hashlib
 import logging
 import os
 import os.path
@@ -23,6 +24,7 @@
 import subprocess
 import tempfile
 import urllib2
+import checkpkg
 
 ARCHITECTURES = ["i386", "sparc", "all"]
 MAJOR_VERSION = "major version"
@@ -57,14 +59,13 @@
 
 EMAIL_TMPL = """From: %(from)s
 To: %(to)s
-Cc: %(cc)s
-Date: %(date)s
+%(optional_cc)sDate: %(date)s
 Subject: newpkgs %(pkgnames)s
 
 %(body)s
 
 -- 
-$Id$
+Generated by submitpkg, $Rev$.
 """
 
 
@@ -209,7 +210,7 @@
     for line in catalog_source:
       # Working around the GPG signature
       if line.startswith("#"): continue
-      if "BEGIN PGP SIGNED MESSAGE" in line: continue 
+      if "BEGIN PGP SIGNED MESSAGE" in line: continue
       if line.startswith("Hash:"): continue
       if len(line.strip()) <= 0: continue 
       if "BEGIN PGP SIGNATURE" in line: break
@@ -272,7 +273,9 @@
     self.pkgnames = pkgnames
     self.paths = paths
     self.release_mgr = u"%s <%s>" % (release_mgr_name, release_mgr_email)
-    self.release_cc = u"%s" % release_cc
+    self.release_cc = release_cc
+    if self.release_cc:
+      self.release_cc = unicode(release_cc)
 
   def FormatMail(self):
     body_list = ["The following package files are ready to be released:"]
@@ -317,14 +320,17 @@
       body_list.extend(msg)
     body_list.append("")
     body = "\n".join(body_list)
+    # TODO: This needs to be rewritten using Cheetah
     d = {
         'from': self.sender,
         'to': self.release_mgr,
-        'cc': self.release_cc,
+        'optional_cc': '',
         'pkgnames': ", ".join(self.pkgnames),
         'body': body,
         'date': datetime.datetime.now(),
     }
+    if self.release_cc:
+      d['optional_cc'] = "cc: %s\n" % self.release_cc
     mail_text = EMAIL_TMPL % d
     return mail_text
 
@@ -342,14 +348,13 @@
   def ShellCommand(self, args, quiet=False):
     logging.debug("Calling: %s", repr(args))
     if quiet:
-      sub_stdout = subprocess.PIPE
-      sub_stderr = subprocess.PIPE
+      process = subprocess.Popen(args,
+                                 stdout=subprocess.PIPE,
+                                 stderr=subprocess.PIPE)
+      stdout, stderr = process.communicate()
+      retcode = process.wait()
     else:
-      sub_stdout = None
-      sub_stderr = None
-    retcode = subprocess.call(args,
-                              stdout=sub_stdout,
-                              stderr=sub_stderr)
+      retcode = subprocess.call(args)
     if retcode:
       raise Error("Running %s has failed." % repr(args))
     return retcode
@@ -358,13 +363,17 @@
 class CswSrv4File(ShellMixin, object):
   """Represents a package in the srv4 format (pkg)."""
 
-  def __init__(self, pkg_path):
+  def __init__(self, pkg_path, debug=False):
     self.pkg_path = pkg_path
     self.workdir = None
     self.gunzipped_path = None
     self.transformed = False
     self.dir_format_pkg = None
+    self.debug = debug
 
+  def __repr__(self):
+    return u"CswSrv4File(%s)" % repr(self.pkg_path)
+
   def GetWorkDir(self):
     if not self.workdir:
       self.workdir = tempfile.mkdtemp(prefix="pkg_")
@@ -394,11 +403,49 @@
                     "%s or %s." % (gzip_suffix, pkg_suffix))
     return self.gunzipped_path
 
+  def Pkgtrans(self, src_file, destdir, pkgname):
+    """A proxy for the pkgtrans command.
+
+    This requires custom-pkgtrans to be available.
+    """
+    if not os.path.isdir(destdir):
+      raise PackageError("%s doesn't exist or is not a directory" % destdir)
+    args = [os.path.join(os.path.dirname(__file__), "custom-pkgtrans"),
+           src_file, destdir, pkgname ]
+    pkgtrans_proc = subprocess.Popen(args)
+    pkgtrans_proc.communicate()
+    ret = pkgtrans_proc.wait()
+    if ret:
+      logging.error("% has failed" % args)
+
+  def GetPkgname(self):
+    """It's necessary to figure out the pkgname from the .pkg file.
+    # nawk 'NR == 2 {print $1; exit;} $f
+    """
+    gunzipped_path = self.GetGunzippedPath()
+    args = ["nawk", "NR == 2 {print $1; exit;}", gunzipped_path]
+    nawk_proc = subprocess.Popen(args, stdout=subprocess.PIPE)
+    stdout, stderr = nawk_proc.communicate()
+    ret_code = nawk_proc.wait()
+    pkgname = stdout.strip()
+    logging.debug("GetPkgname(): %s", repr(pkgname))
+    return pkgname
+
   def TransformToDir(self):
+    """Transforms the file to the directory format.
+
+    This uses the Pkgtrans function at the top, because pkgtrans behaves
+    differently on Solaris 8 and 10.  Having our own implementation helps
+    achieve consistent behavior.
+    """

@@ 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