initial content validation check extension for pkglint
authorNorm Jacobs <Norm.Jacobs@Sun.COM>
Tue, 09 Nov 2010 10:32:06 -0600
changeset 45 536ea324b223
parent 44 c031e1c884ef
child 46 d4d60962c33f
initial content validation check extension for pkglint
tools/pkglintrc
tools/python/pkglint/__init__.py
tools/python/pkglint/userland.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/pkglintrc	Tue Nov 09 10:32:06 2010 -0600
@@ -0,0 +1,26 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+[pkglint]
+
+pkglint.ext.content = pkglint.userland
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/pkglint/__init__.py	Tue Nov 09 10:32:06 2010 -0600
@@ -0,0 +1,22 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/python/pkglint/userland.py	Tue Nov 09 10:32:06 2010 -0600
@@ -0,0 +1,138 @@
+#!/usr/bin/python
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+# Some userland consolidation specific lint checks
+
+import pkg.lint.base as base
+import re
+import os.path
+
+class UserlandActionChecker(base.ActionChecker):
+        """An opensolaris.org-specific class to check actions."""
+
+        name = "userland.action"
+
+        def __init__(self, config):
+                self.description = _(
+                    "checks Userland packages for common content errors")
+		self.prototype = os.getenv('PROTO_DIR')
+		self.runpath_re = [
+			re.compile('^/lib/'),
+			re.compile('^/usr/'),
+			re.compile('^\$ORIGIN/')
+		]
+                super(UserlandActionChecker, self).__init__(config)
+
+	def startup(self, engine):
+		if self.prototype != None:
+			engine.info(_("including prototype checks: %s") % self.prototype, msgid=self.name)
+
+	def file_exists(self, action, manifest, engine, pkglint_id="001"):
+		"""Checks for existence in the proto area."""
+
+		if self.prototype is None:
+			return
+
+		if action.name not in ["file", "dir", "link", "hardlink"]:
+			return
+
+		path = action.attrs["path"]
+		fullpath = self.prototype + "/" + path
+		if not os.path.exists(fullpath):
+			engine.error(
+				_("packaged path '%s' missing from proto area") % path, 
+				msgid="%s%s.0" % (self.name, pkglint_id))
+
+	file_exists.pkglint_desc = _("Paths should exist in the proto area.")
+
+	def file_content(self, action, manifest, engine, pkglint_id="002"):
+		"""Checks for file content issues."""
+
+		if self.prototype is None:
+			return
+
+		if action.name is not "file":
+			return
+
+		import pkg.elf as elf
+
+		path = action.attrs["path"]
+		fullpath = self.prototype + "/" + path
+
+		if elf.is_elf_object(fullpath):
+			ed = elf.get_dynamic(fullpath)
+			for dir in ed.get("runpath", "").split(":"):
+				if dir == None or dir == '':
+					continue
+
+				match = False
+				for expr in self.runpath_re:
+					if expr.match(dir):
+						match = True
+						break
+
+				if match == False:
+					engine.error(
+						_("%s has bad RUNPATH, "
+					  	"includes: %s") % (path, dir),
+						msgid="%s%s.1" % (self.name, pkglint_id))
+		# additional checks for different content types should go here
+
+	file_content.pkglint_desc = _("Paths should not deliver common mistakes.")
+
+class UserlandManifestChecker(base.ManifestChecker):
+        """An opensolaris.org-specific class to check manifests."""
+
+        name = "userland.manifest"
+
+	def __init__(self, config):
+		self.prototype = os.getenv('PROTO_DIR')
+		super(UserlandManifestChecker, self).__init__(config)
+
+	def unpackaged_files(self, manifest, engine, pkglint_id="001"):
+		if self.prototype == None:
+			return
+
+		return	# skip this check for now.  It needs more work
+
+		manifest_paths = []
+
+		for action in manifest.gen_actions():
+			if action.name in ["file", "dir", "link", "hardlink"]:
+				manifest_paths.append(action.attrs.get("path"))
+
+		for dirname, dirnames, filenames in os.walk(self.prototype):
+			dir = dirname[len(self.prototype):]
+			for name in filenames + dirnames:
+				path = dir + '/' + name
+				if path not in manifest_paths:
+					engine.error(
+						_("unpackaged path '%s' missing from manifest") % path, 
+					msgid="%s%s.0" % (self.name, pkglint_id))
+
+	unpackaged_files.pkglint_dest = _(
+		"Prototype paths should be present.")
+