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

wahwah at users.sourceforge.net wahwah at users.sourceforge.net
Sun Feb 7 00:45:26 CET 2010


Revision: 8367
          http://gar.svn.sourceforge.net/gar/?rev=8367&view=rev
Author:   wahwah
Date:     2010-02-06 23:45:25 +0000 (Sat, 06 Feb 2010)

Log Message:
-----------
mGAR v2: checkpkg, overrides implemented. See http://wiki.opencsw.org/checkpkg for documentation.

Modified Paths:
--------------
    csw/mgar/gar/v2/bin/checkpkg
    csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-actionclasses.py
    csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-archall.py
    csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-libs.py
    csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-license.py
    csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-missing-symbols.py
    csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-obsolete-deps.py
    csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-you-can-write-your-own.py
    csw/mgar/gar/v2/lib/python/checkpkg.py
    csw/mgar/gar/v2/lib/python/checkpkg_test.py
    csw/mgar/gar/v2/lib/python/opencsw.py

Added Paths:
-----------
    csw/mgar/gar/v2/bin/analyze_module_results.py

Added: csw/mgar/gar/v2/bin/analyze_module_results.py
===================================================================
--- csw/mgar/gar/v2/bin/analyze_module_results.py	                        (rev 0)
+++ csw/mgar/gar/v2/bin/analyze_module_results.py	2010-02-06 23:45:25 UTC (rev 8367)
@@ -0,0 +1,47 @@
+#!/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((pkgname, checkpkg.CheckpkgTag(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 "The reported error tags are:"
+    for tag in tags_after_overrides:
+    	print "*", repr(tag)
+  sys.exit(exit_code)
+
+
+if __name__ == '__main__':
+  main()


Property changes on: csw/mgar/gar/v2/bin/analyze_module_results.py
___________________________________________________________________
Added: svn:executable
   + *
Added: svn:keywords
   + Id

Modified: csw/mgar/gar/v2/bin/checkpkg
===================================================================
--- csw/mgar/gar/v2/bin/checkpkg	2010-02-06 15:20:24 UTC (rev 8366)
+++ csw/mgar/gar/v2/bin/checkpkg	2010-02-06 23:45:25 UTC (rev 8367)
@@ -569,6 +569,7 @@
 checkpkg_scriptname=`basename $0`
 checkpkg_basedir=${0%/${checkpkg_scriptname}}
 plugindir=${checkpkg_basedir}/checkpkg.d
+checkpkg_module_tag="checkpkg-"
 
 # Cleaning up old *.pyc files which can cause grief.  This is because of the
 # move of Python libraries.
@@ -591,21 +592,26 @@
 module_name_format="%-40s"
 if [[ -d "$plugindir" ]]; then
 	echo "Running modular tests"
-	# echo plugin dir exists
-	for plugin in "${plugindir}"/checkpkg-*; do
+	for plugin in "${plugindir}/${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}"
 			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}"
-			${plugin} $extra_options -e "${EXTRACTDIR}" ${pkgnames} > "${plugin_log}" 2>&1
+			debugmsg "Executing: ${plugin} $extra_options -e \"${EXTRACTDIR}\" ${pkgnames}"
+			${plugin} \
+				$extra_options \
+				-e "${EXTRACTDIR}" \
+				-o "${EXTRACTDIR}/${error_tag_file}" \
+				${pkgnames} \
+				> "${plugin_log}" 2>&1
 			if [[ "$?" -ne 0 ]]; then
-				printf "\r${module_name_format} ${RED}[FAIL]${COLOR_RESET}        \\n" "${plugin_name}"
+				printf "\r${module_name_format} ${RED}[ERROR]${COLOR_RESET}        \\n" "${plugin_name}"
 				test_suite_ok=0
 			else
-				printf "\r${module_name_format} ${GREEN}[OK]${COLOR_RESET}        \\n" "${plugin_name}"
+				printf "\r${module_name_format} [Done]        \\n" "${plugin_name}"
 			fi
 		else
 			debugmsg "'${plugin}' is not executable"
@@ -626,11 +632,34 @@
 done
 
 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
 
+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
+
+# Collecting errors and applying the overrides.
+${checkpkg_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/bin/checkpkg.d/checkpkg-actionclasses.py
===================================================================
--- csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-actionclasses.py	2010-02-06 15:20:24 UTC (rev 8366)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-actionclasses.py	2010-02-06 23:45:25 UTC (rev 8367)
@@ -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,7 +22,7 @@
 import opencsw
 
 
-def CheckActionClasses(pkg):
+def CheckActionClasses(pkg, debug):
   """Checks the consistency between classes in the prototype and pkginfo."""
   errors = []
   pkginfo = pkg.GetParsedPkginfo()
@@ -29,29 +31,33 @@
   pkgmap_classes = pkgmap.GetClasses()
   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(
+        "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("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)
+  check_manager = checkpkg.CheckpkgManager(CHECKPKG_MODULE_NAME,
+                                           options.extractdir,
+                                           pkgnames,
+                                           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)
 
 

Modified: csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-archall.py
===================================================================
--- csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-archall.py	2010-02-06 15:20:24 UTC (rev 8366)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-archall.py	2010-02-06 23:45:25 UTC (rev 8367)
@@ -1,4 +1,5 @@
 #!/opt/csw/bin/python2.6
+#
 # $Id$
 
 """Verifies the architecture of the package."""
@@ -15,15 +16,15 @@
 sys.path.append(os.path.join(*path_list))
 import checkpkg
 
-def CheckArchitectureVsContents(pkg):
+def CheckArchitectureVsContents(pkg, debug):
   """Verifies the relationship between package contents and architecture."""
   errors = []
   binaries = pkg.ListBinaries()
   pkginfo = pkg.GetParsedPkginfo()
   arch = pkginfo["ARCH"]
   if binaries and arch == "all":
-    errors.append(checkpkg.PackageError(
-      "The package can't be ARCHALL = 1 and contain binaries."))
+    for binary in binaries:
+    	errors.append(checkpkg.CheckpkgTag("archall-with-binaries"), binary)
   elif not binaries and arch != "all":
     # This is not a clean way of handling messages for the user, but there's
     # not better way at the moment.
@@ -42,11 +43,18 @@
                                            options.extractdir,
                                            pkgnames,
                                            options.debug)
+
   check_manager.RegisterIndividualCheck(CheckArchitectureVsContents)
-  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)
 
 
 if __name__ == '__main__':
   main()
+
+# vim:set sw=2 ts=2 sts=2 expandtab:

Modified: csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-libs.py
===================================================================
--- csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-libs.py	2010-02-06 15:20:24 UTC (rev 8366)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-libs.py	2010-02-06 23:45:25 UTC (rev 8367)
@@ -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__),
@@ -38,24 +41,14 @@
   return isalist
 
 
-def main():
+def CheckSharedLibraryConsistency(pkgs, debug):
   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:
+  for checker in pkgs:
     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
@@ -128,7 +121,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 +143,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 +158,11 @@
     print
 
   dependent_pkgs = {}
-  for checker in checkers:
+  for checker in pkgs:
     pkgname = checker.pkgname
     dir_format_pkg = opencsw.DirectoryFormatPackage(checker.pkgpath)
     declared_dependencies = dir_format_pkg.GetDependencies()
-    if options.debug:
+    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 +190,46 @@
         pkgs_by_filename,
         filenames_by_soname,
         pkg_by_any_filename)
-    print checker.FormatDepsReport(missing_deps,
-                                   surplus_deps,
-                                   orphan_sonames)
+    namespace = {
+        "pkgname": checker.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(
+            "orphan-soname",
+            soname))
+    for missing_dep in missing_deps:
+    	errors.append(
+    	    checkpkg.CheckpkgTag(
+    	      "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()
+  pkgnames = args
+  check_manager = checkpkg.CheckpkgManager(CHECKPKG_MODULE_NAME,
+                                           options.extractdir,
+                                           pkgnames,
+                                           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()
 

Modified: csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-license.py
===================================================================
--- csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-license.py	2010-02-06 15:20:24 UTC (rev 8366)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-license.py	2010-02-06 23:45:25 UTC (rev 8367)
@@ -19,7 +19,7 @@
 
 LICENSE_TMPL = "/opt/csw/share/doc/%s/license"
 
-def CheckLicenseFile(pkg):
+def CheckLicenseFile(pkg, debug):
   """Checks for the presence of the license file."""
   errors = []
   pkgmap = pkg.GetPkgmap()
@@ -27,12 +27,9 @@
   license_path = LICENSE_TMPL % catalogname
   if license_path not in pkgmap.entries_by_path:
     errors.append(
-        opencsw.PackageError(
-          "%s file not present in the %s package"
-          % (repr(license_path), pkg.pkgname)))
-    errors.append(
-        opencsw.PackageError(
-          "See also: http://sourceforge.net/apps/trac/gar/wiki/CopyRight"))
+        checkpkg.CheckpkgTag(
+          "license-missing",
+          msg="See http://sourceforge.net/apps/trac/gar/wiki/CopyRight"))
   return errors
 
 
@@ -45,8 +42,12 @@
                                            options.debug)
   # Registering functions defined above.
   check_manager.RegisterIndividualCheck(CheckLicenseFile)
-  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/bin/checkpkg.d/checkpkg-missing-symbols.py
===================================================================
--- csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-missing-symbols.py	2010-02-06 15:20:24 UTC (rev 8366)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-missing-symbols.py	2010-02-06 23:45:25 UTC (rev 8367)
@@ -22,7 +22,7 @@
 
 # Defining checking functions.
 
-def CheckForMissingSymbols(pkg):
+def CheckForMissingSymbols(pkg, debug):
   """Looks for "symbol not found" in ldd -r output."""
   errors = []
   binaries = pkg.ListBinaries()
@@ -37,9 +37,13 @@
     stdout, stderr = ldd_proc.communicate()
     retcode = ldd_proc.wait()
     lines = stdout.splitlines()
+    missing_symbols = False
     for line in lines:
       if re.search(symbol_re, line):
-        errors.append(checkpkg.PackageError("%s: %s" % (pkg.pkgname, line)))
+      	missing_symbols = True
+    binary_base = os.path.basename(binary)
+    if missing_symbols:
+    	errors.append(checkpkg.CheckpkgTag("symbol-not-found", binary_base))
   return errors
 
 
@@ -55,8 +59,11 @@
   # Registering functions defined above.
   check_manager.RegisterIndividualCheck(CheckForMissingSymbols)
   # 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)
 
 

Modified: csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-obsolete-deps.py
===================================================================
--- csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-obsolete-deps.py	2010-02-06 15:20:24 UTC (rev 8366)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-obsolete-deps.py	2010-02-06 23:45:25 UTC (rev 8367)
@@ -26,23 +26,24 @@
     },
 }
 
-def CheckObsoleteDeps(pkg):
+def CheckObsoleteDeps(pkg, debug):
   """Checks for obsolete dependencies."""
   errors = []
   deps = set(pkg.GetDependencies())
   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("obsolete-dependency", obsolete_pkg, msg=msg))
   return errors
 
 
@@ -54,8 +55,12 @@
                                            pkgnames,
                                            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/bin/checkpkg.d/checkpkg-you-can-write-your-own.py
===================================================================
--- csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-you-can-write-your-own.py	2010-02-06 15:20:24 UTC (rev 8366)
+++ csw/mgar/gar/v2/bin/checkpkg.d/checkpkg-you-can-write-your-own.py	2010-02-06 23:45:25 UTC (rev 8367)
@@ -18,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, 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("tag-name"))
 
-  errors.append(checkpkg.PackageError("There's something wrong."))
+  You can also add a parameter:
+  errors.append(checkpkg.CheckpkgTag("tag-name", "/opt/csw/bin/problem"))
   """
   errors = []
   # Checking code for an individual package goes here.  See the
@@ -37,11 +40,11 @@
   # 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("example-problem", "thing"))
   return errors
 
 
-def MyCheckForAsetOfPackages(pkgs):
+def MyCheckForAsetOfPackages(pkgs, debug):
   """Checks a set of packages.
 
   Sometimes individual checks aren't enough. If you need to write code which
@@ -67,8 +70,11 @@
   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)
 
 

Modified: csw/mgar/gar/v2/lib/python/checkpkg.py
===================================================================
--- csw/mgar/gar/v2/lib/python/checkpkg.py	2010-02-06 15:20:24 UTC (rev 8366)
+++ csw/mgar/gar/v2/lib/python/checkpkg.py	2010-02-06 23:45:25 UTC (rev 8367)
@@ -80,6 +80,18 @@
 #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
 
@@ -99,6 +111,8 @@
   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.")
@@ -106,29 +120,18 @@
   return options, set(args)
 
 
-class CheckpkgBase(opencsw.DirectoryFormatPackage):
-  """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)
-    super(CheckpkgBase, self).__init__(self.pkgpath)
 
-  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.
 
@@ -534,6 +537,20 @@
   return binary_data
 
 
+class CheckpkgTag(object):
+  """Represents a tag to be written to the checkpkg tag file."""
+
+  def __init__(self, tag_name, tag_info=None, severity=None, msg=None):
+    self.tag_name = tag_name
+    self.tag_info = tag_info
+    self.severity = severity
+    self.msg = msg
+
+  def __repr__(self):
+    return (u"CheckpkgTag(%s, %s, ...)"
+            % (repr(self.tag_name), repr(self.tag_info)))
+
+
 class CheckpkgManager(object):
   """Takes care of calling checking functions"""
 
@@ -553,31 +570,130 @@
   def RegisterSetCheck(self, function):
     self.set_checks.append(function)
 
-  def Run(self):
-    """Runs all the checks
-
-    Returns a tuple of an exit code and a report.
-    """
+  def GetDirectoryFormatPackages(self):
     packages = []
-    errors = {}
     for pkgname in self.pkgname_list:
         pkg_path = os.path.join(self.extractdir, pkgname)
         packages.append(opencsw.DirectoryFormatPackage(pkg_path))
+    return packages
+
+  def GetAllTags(self, packages):
+    errors = {}
     for pkg in packages:
       for function in self.individual_checks:
-        errors_for_pkg = function(pkg)
+        errors_for_pkg = function(pkg, debug=self.debug)
         if errors_for_pkg:
           errors[pkg.pkgname] = errors_for_pkg
     # Set checks
     for function in self.set_checks:
-      set_errors = function(packages)
+      set_errors = function(packages, debug=self.debug)
       if set_errors:
-        errors["The package set"] = set_errors
+        errors["package-set"] = set_errors
+    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(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 = self.GetDirectoryFormatPackages()
+    errors = self.GetAllTags(packages)
+    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, pkgname, 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"] = 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
+    # print "comparing", basket_a, basket_b
+    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."""
+  tags_after_overrides = []
+  # This can be done more efficiently after creating indexes, but I'm going to
+  # do an O(N*M) as if I didn't know anything about programming. :-P
+  for pkgname, tag in error_tags:
+    override_applies = False
+    for override in overrides:
+      if override.DoesApply(pkgname, tag):
+        override_applies = True
+    if not override_applies:
+      tags_after_overrides.append((pkgname, tag))
+  return tags_after_overrides

Modified: csw/mgar/gar/v2/lib/python/checkpkg_test.py
===================================================================
--- csw/mgar/gar/v2/lib/python/checkpkg_test.py	2010-02-06 15:20:24 UTC (rev 8366)
+++ csw/mgar/gar/v2/lib/python/checkpkg_test.py	2010-02-06 23:45:25 UTC (rev 8367)
@@ -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
@@ -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,19 +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")
+    testdata = ("CSWfoo", missing_deps, surplus_deps, orphan_sonames)
+    checker = opencsw.DirectoryFormatPackage("/tmp/nonexistent/CSWfoo")
     expected = u""
-    result = checker.FormatDepsReport(*testdata)
+    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("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("foo-tag", "foo-info"),
+          checkpkg.CheckpkgTag("bar-tag", "bar-info"),
+          checkpkg.CheckpkgTag("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 = [(None, checkpkg.CheckpkgTag("foo-tag"))]
+    overrides = []
+    self.assertEqual(tags, checkpkg.ApplyOverrides(tags, overrides))
+
+  def test_1b(self):
+    """One override, matching by tag name only."""
+    tags = [(None, checkpkg.CheckpkgTag("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 = [(None, checkpkg.CheckpkgTag("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 = [(None, checkpkg.CheckpkgTag("foo-tag", "tag-info-1"))]
+    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 = [(None, checkpkg.CheckpkgTag("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 = [("CSWfoo", checkpkg.CheckpkgTag("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 = [("CSWfoo", checkpkg.CheckpkgTag("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 = [("CSWfoo", checkpkg.CheckpkgTag("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/lib/python/opencsw.py
===================================================================
--- csw/mgar/gar/v2/lib/python/opencsw.py	2010-02-06 15:20:24 UTC (rev 8366)
+++ csw/mgar/gar/v2/lib/python/opencsw.py	2010-02-06 23:45:25 UTC (rev 8367)
@@ -23,6 +23,7 @@
 import subprocess
 import tempfile
 import urllib2
+import checkpkg
 
 ARCHITECTURES = ["i386", "sparc", "all"]
 MAJOR_VERSION = "major version"
@@ -536,6 +537,7 @@
   def __init__(self, directory):
     self.directory = directory
     self.pkgname = os.path.split(directory)[1]
+    self.pkgpath = self.directory
     self.pkginfo_dict = None
 
   def GetCatalogname(self):
@@ -694,7 +696,37 @@
       file_basenames.extend(files)
     return file_basenames
 
+  def _GetOverridesStream(self):
+    catalogname = self.GetCatalogname()
+    file_path = os.path.join(self.directory,
+                             "root",
+                             "opt/csw/share/checkpkg/overrides",
+                             catalogname)
+    # This might potentially cause a file descriptor leak, but I'm not going to
+    # worry about that at this stage.
+    logging.debug("Trying to open %s", repr(file_path))
+    if os.path.isfile(file_path):
+    	return open(file_path, "r")
+    else:
+    	return None
 
+  def _ParseOverridesStream(self, stream):
+    overrides = []
+    for line in stream:
+      if line.startswith("#"):
+      	continue
+      overrides.append(checkpkg.ParseOverrideLine(line))
+    return overrides
+
+  def GetOverrides(self):
+    """Returns overrides, a list of checkpkg.Override instances."""
+    stream = self._GetOverridesStream()
+    if stream:
+    	return self._ParseOverridesStream(stream)
+    else:
+    	return list()
+
+
 class Pkgmap(object):
   """Represents the pkgmap of the package.
 


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