[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