tools/userland-mangler
changeset 181 87e11e685b1f
child 379 c6a17bba1da3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/userland-mangler	Wed Apr 13 09:58:06 2011 -0700
@@ -0,0 +1,272 @@
+#!/usr/bin/python2.6
+#
+# 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) 2011, Oracle and/or its affiliates. All rights reserved.
+#
+#
+# userland-mangler - a file mangling utility
+#
+#  A simple program to mangle files to conform to Solaris WOS or Consoldation
+#  requirements.
+#
+
+import os
+import sys
+import re
+
+import pkg.fmri
+import pkg.manifest
+import pkg.actions
+import pkg.elf as elf
+
+attribute_table_header = """
+.SH ATTRIBUTES
+See
+.BR attributes (5)
+for descriptions of the following attributes:
+.sp
+.TS
+box;
+cbp-1 | cbp-1
+l | l .
+ATTRIBUTE TYPE	ATTRIBUTE VALUE """
+
+attribute_table_availability = """
+=
+Availability	%s"""
+
+attribute_table_stability = """
+=
+Stability	%s"""
+
+attribute_table_footer = """
+.TE 
+.PP
+"""
+def write_attributes_section(ofp, availability, stability):
+	# is there anything to do?
+	if availability is None and stability is None:
+		return
+
+	# append the ATTRIBUTES section
+	ofp.write(attribute_table_header)
+	if availability is not None:
+		ofp.write(attribute_table_availability % availability)
+	if stability is not None:
+		ofp.write(attribute_table_stability % stability.capitalize())
+	ofp.write(attribute_table_footer)
+
+
+notes_header = """
+.SH NOTES
+"""
+
+notes_community = """
+Further information about this software can be found on the open source community website at %s.
+"""
+notes_source = """
+This software was built from source available at http://opensolaris.org/.  The original community source was downloaded from  %s
+"""
+
+def write_notes_section(ofp, header_seen, community, source):
+	# is there anything to do?
+	if community is None and source is None:
+		return
+
+	# append the NOTES section
+	if header_seen == False:
+		ofp.write(notes_header)
+	if source is not None:
+		ofp.write(notes_source % source)
+	if community is not None:
+		ofp.write(notes_community % community)
+
+
+section_re = re.compile('\.SH "?([^"]+).*$', re.IGNORECASE)
+#
+# mangler.man.stability = (mangler.man.stability)
+# mangler.man.availability = (pkg.fmri)
+# mangler.man.source_url = (pkg.source_url)
+# mangler.man.upstream_url = (pkg.upstream_url)
+#
+def mangle_manpage(manifest, action, src, dest):
+	# manpages must have a taxonomy defined
+	stability = action.attrs.pop('mangler.man.stability', None)
+	if stability is None:
+		sys.stderr.write("ERROR: manpage action missing mangler.man.stability: %s" % action)
+		sys.exit(1)
+
+	attributes_written = False
+	notes_seen = False
+
+	if 'pkg.fmri' in manifest.attributes:
+		fmri = pkg.fmri.PkgFmri(manifest.attributes['pkg.fmri'])
+		availability = fmri.pkg_name
+
+	if 'info.upstream_url' in manifest.attributes:
+		community = manifest.attributes['info.upstream_url']
+
+	if 'info.source_url' in manifest.attributes:
+		source = manifest.attributes['info.source_url']
+
+	# create a directory to write to
+	destdir = os.path.dirname(dest)
+	if not os.path.exists(destdir):
+		os.makedirs(destdir)
+
+	# read the source document
+	ifp = open(src, "r")
+	lines = ifp.readlines()
+	ifp.close()
+
+	# skip reference only pages
+	if lines[0].startswith(".so "):
+		return
+
+	# open a destination
+	ofp = open(dest, "w+")
+
+	# tell man that we want tables (and eqn)
+	ofp.write("'\\\" te\n")
+
+	# write the orginal data
+	for line in lines:
+		match = section_re.match(line)
+		if match is not None:
+			section = match.group(1)
+			if section in ['SEE ALSO', 'NOTES']:
+				if attributes_written == False:
+					write_attributes_section(ofp,
+								 availability,
+								 stability)
+					attributes_written = True
+				if section == 'NOTES':
+					notes_seen = True
+		ofp.write(line)
+
+	if attributes_written == False:
+		write_attributes_section(ofp, availability, stability)
+
+	write_notes_section(ofp, notes_seen, community, source)
+
+	ofp.close()
+
+
+#
+# mangler.elf.strip = (true|false)
+#
+def mangle_elf(manifest, action, src, dest):
+	pass
+
+#
+# mangler.script.file-magic =
+#
+def mangle_script(manifest, action, src, dest):
+	pass
+
+def mangle_path(manifest, action, src, dest):
+	if 'facet.doc.man' in action.attrs:
+		 mangle_manpage(manifest, action, src, dest)
+	elif 'mode' in action.attrs and int(action.attrs['mode'], 8) & 0111 != 0:
+		if elf.is_elf_object(src):
+			 mangle_elf(manifest, action, src, dest)
+		else:
+			 mangle_script(manifest, action, src, dest)
+
+#
+# mangler.bypass = (true|false)
+#
+def mangle_paths(manifest, search_paths, destination):
+	for action in manifest.gen_actions_by_type("file"):
+		bypass = action.attrs.pop('mangler.bypass', 'false').lower()
+		if bypass == 'true':
+			continue
+
+		path = None
+		if 'path' in action.attrs:
+			path = action.attrs['path']
+		if action.hash and action.hash != 'NOHASH':
+			path = action.hash
+		if not path:
+			continue
+
+		dest = os.path.join(destination, path)
+		for directory in search_paths:
+			if directory != destination:
+				src = os.path.join(directory, path)
+				if os.path.exists(src):
+					mangle_path(manifest, action, src, dest)
+					break
+
+def load_manifest(manifest_file):
+	manifest = pkg.manifest.Manifest()
+	manifest.set_content(pathname=manifest_file)
+
+	return manifest
+
+def usage():
+	print "Usage: %s [-m|--manifest (file)] [-d|--search-directory (dir)] [-D|--destination (dir)] " % (sys.argv[0].split('/')[-1])
+	sys.exit(1)
+
+def main():
+	import getopt
+
+	# FLUSH STDOUT 
+	sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
+
+	search_paths = []
+	destination = None
+	manifests = []
+
+	try:
+		opts, args = getopt.getopt(sys.argv[1:], "D:d:m:",
+			["destination=", "search-directory=", "manifest="])
+	except getopt.GetoptError, err:
+		print str(err)
+		usage()
+
+	for opt, arg in opts:
+		if opt in [ "-D", "--destination" ]:
+			destination = arg
+		elif opt in [ "-d", "--search-directory" ]:
+			search_paths.append(arg)
+		elif opt in [ "-m", "--manifest" ]:
+			try:
+				manifest = load_manifest(arg)
+			except IOError, err:
+				print "oops, %s: %s" % (arg, str(err))
+				usage()
+			else:
+				manifests.append(manifest)
+		else:
+			usage()
+
+	if destination == None:
+		usage()
+
+	for manifest in manifests:
+		mangle_paths(manifest, search_paths, destination)
+		print manifest
+
+	sys.exit(0)
+
+if __name__ == "__main__":
+	main()