3321N/A#!/usr/bin/python2.7
181N/A#
181N/A# CDDL HEADER START
181N/A#
181N/A# The contents of this file are subject to the terms of the
181N/A# Common Development and Distribution License (the "License").
181N/A# You may not use this file except in compliance with the License.
181N/A#
181N/A# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
181N/A# or http://www.opensolaris.org/os/licensing.
181N/A# See the License for the specific language governing permissions
181N/A# and limitations under the License.
181N/A#
181N/A# When distributing Covered Code, include this CDDL HEADER in each
181N/A# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
181N/A# If applicable, add the following below this CDDL HEADER, with the
181N/A# fields enclosed by brackets "[]" replaced with your own identifying
181N/A# information: Portions Copyright [yyyy] [name of copyright owner]
181N/A#
181N/A# CDDL HEADER END
181N/A#
5680N/A
5680N/A#
5565N/A# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
181N/A#
181N/A#
181N/A# userland-mangler - a file mangling utility
181N/A#
181N/A# A simple program to mangle files to conform to Solaris WOS or Consoldation
181N/A# requirements.
181N/A#
181N/A
181N/Aimport os
181N/Aimport sys
181N/Aimport re
181N/A
181N/Aimport pkg.fmri
181N/Aimport pkg.manifest
181N/Aimport pkg.actions
181N/Aimport pkg.elf as elf
181N/A
1113N/Aattribute_oracle_table_header = """
1113N/A.\\\" Oracle has added the ARC stability level to this manual page"""
1113N/A
181N/Aattribute_table_header = """
181N/A.SH ATTRIBUTES
181N/ASee
5565N/A.BR attributes (7)
181N/Afor descriptions of the following attributes:
181N/A.sp
181N/A.TS
181N/Abox;
181N/Acbp-1 | cbp-1
181N/Al | l .
181N/AATTRIBUTE TYPE ATTRIBUTE VALUE """
181N/A
181N/Aattribute_table_availability = """
181N/A=
181N/AAvailability %s"""
181N/A
181N/Aattribute_table_stability = """
181N/A=
181N/AStability %s"""
181N/A
181N/Aattribute_table_footer = """
181N/A.TE
181N/A.PP
181N/A"""
1113N/Adef attributes_section_text(availability, stability, modified_date):
448N/A result = ''
448N/A
181N/A # is there anything to do?
448N/A if availability is not None or stability is not None:
1113N/A result = attribute_oracle_table_header
1113N/A if modified_date is not None:
1113N/A result += ("\n.\\\" on %s" % modified_date)
1113N/A result += attribute_table_header
181N/A
448N/A if availability is not None:
448N/A result += (attribute_table_availability % availability)
448N/A if stability is not None:
448N/A result += (attribute_table_stability % stability.capitalize())
448N/A result += attribute_table_footer
181N/A
448N/A return result
181N/A
1113N/Anotes_oracle_comment = """
1113N/A.\\\" Oracle has added source availability information to this manual page"""
1113N/A
181N/Anotes_header = """
181N/A.SH NOTES
181N/A"""
181N/A
181N/Anotes_community = """
181N/AFurther information about this software can be found on the open source community website at %s.
181N/A"""
181N/Anotes_source = """
2104N/AThis software was built from source available at https://java.net/projects/solaris-userland. The original community source was downloaded from %s
181N/A"""
181N/A
1113N/Adef notes_section_text(header_seen, community, source, modified_date):
448N/A result = ''
181N/A
448N/A # is there anything to do?
448N/A if community is not None or source is not None:
448N/A if header_seen == False:
448N/A result += notes_header
1113N/A result += notes_oracle_comment
1113N/A if modified_date is not None:
1113N/A result += ("\n.\\\" on %s" % modified_date)
448N/A if source is not None:
448N/A result += (notes_source % source)
448N/A if community is not None:
448N/A result += (notes_community % community)
181N/A
448N/A return result
181N/A
448N/Aso_re = re.compile('^\.so.+$', re.MULTILINE)
181N/Asection_re = re.compile('\.SH "?([^"]+).*$', re.IGNORECASE)
2018N/ATH_re = re.compile('\.TH\s+(?:"[^"]+"|\S+)\s+(\S+)', re.IGNORECASE)
181N/A#
181N/A# mangler.man.stability = (mangler.man.stability)
1113N/A# mangler.man.modified_date = (mangler.man.modified-date)
181N/A# mangler.man.availability = (pkg.fmri)
464N/A# mangler.man.source-url = (pkg.source-url)
464N/A# mangler.man.upstream-url = (pkg.upstream-url)
2018N/A# mangler.man.rewrite-section = ('true'/'false') default 'true'
181N/A#
448N/Adef mangle_manpage(manifest, action, text):
181N/A # manpages must have a taxonomy defined
181N/A stability = action.attrs.pop('mangler.man.stability', None)
181N/A if stability is None:
181N/A sys.stderr.write("ERROR: manpage action missing mangler.man.stability: %s" % action)
181N/A sys.exit(1)
181N/A
1113N/A # manpages may have a 'modified date'
1113N/A modified_date = action.attrs.pop('mangler.man.modified-date', None)
1113N/A
2018N/A
2018N/A # Rewrite the section in the .TH line to match the section in which
2018N/A # we're delivering it.
2018N/A rewrite_sect = action.attrs.pop('mangler.man.rewrite-section', 'true')
2018N/A
181N/A attributes_written = False
181N/A notes_seen = False
181N/A
181N/A if 'pkg.fmri' in manifest.attributes:
181N/A fmri = pkg.fmri.PkgFmri(manifest.attributes['pkg.fmri'])
181N/A availability = fmri.pkg_name
181N/A
379N/A community = None
464N/A if 'info.upstream-url' in manifest.attributes:
464N/A community = manifest.attributes['info.upstream-url']
181N/A
379N/A source = None
464N/A if 'info.source-url' in manifest.attributes:
464N/A source = manifest.attributes['info.source-url']
464N/A elif 'info.repository-url' in manifest.attributes:
464N/A source = manifest.attributes['info.repository-url']
181N/A
181N/A # skip reference only pages
448N/A if so_re.match(text) is not None:
448N/A return text
181N/A
181N/A # tell man that we want tables (and eqn)
448N/A result = "'\\\" te\n"
181N/A
181N/A # write the orginal data
448N/A for line in text.split('\n'):
181N/A match = section_re.match(line)
181N/A if match is not None:
181N/A section = match.group(1)
181N/A if section in ['SEE ALSO', 'NOTES']:
181N/A if attributes_written == False:
448N/A result += attributes_section_text(
181N/A availability,
1113N/A stability,
1113N/A modified_date)
181N/A attributes_written = True
181N/A if section == 'NOTES':
181N/A notes_seen = True
2018N/A
2018N/A match = TH_re.match(line)
2018N/A if match and rewrite_sect.lower() == "true":
2018N/A # Use the section defined by the filename, rather than
2018N/A # the directory in which it sits.
2018N/A sect = os.path.splitext(action.attrs["path"])[1][1:]
2018N/A line = line[:match.span(1)[0]] + sect + \
2018N/A line[match.span(1)[1]:]
2018N/A
448N/A result += ("%s\n" % line)
181N/A
181N/A if attributes_written == False:
1113N/A result += attributes_section_text(availability, stability,
1113N/A modified_date)
181N/A
1113N/A result += notes_section_text(notes_seen, community, source,
1113N/A modified_date)
181N/A
448N/A return result
181N/A
181N/A
181N/A#
181N/A# mangler.elf.strip = (true|false)
181N/A#
181N/Adef mangle_elf(manifest, action, src, dest):
181N/A pass
181N/A
181N/A#
181N/A# mangler.script.file-magic =
181N/A#
448N/Adef mangle_script(manifest, action, text):
448N/A return text
448N/A
448N/A#
448N/A# mangler.strip_cddl = false
448N/A#
448N/Adef mangle_cddl(manifest, action, text):
448N/A strip_cddl = action.attrs.pop('mangler.strip_cddl', 'true')
448N/A if strip_cddl is 'false':
448N/A return text
3368N/A cddl_re = re.compile('^[^\n]*CDDL HEADER START.+CDDL HEADER END[^\n]*\n',
448N/A re.MULTILINE|re.DOTALL)
448N/A return cddl_re.sub('', text)
181N/A
181N/Adef mangle_path(manifest, action, src, dest):
448N/A if elf.is_elf_object(src):
448N/A mangle_elf(manifest, action, src, dest)
448N/A else:
448N/A # a 'text' document (script, man page, config file, ...
448N/A ifp = open(src, 'r')
448N/A text = ifp.read()
448N/A ifp.close()
448N/A
448N/A # remove the CDDL from files
448N/A result = mangle_cddl(manifest, action, text)
448N/A
448N/A if 'facet.doc.man' in action.attrs:
448N/A result = mangle_manpage(manifest, action, result)
448N/A elif 'mode' in action.attrs and int(action.attrs['mode'], 8) & 0111 != 0:
448N/A result = mangle_script(manifest, action, result)
448N/A
448N/A if text != result:
448N/A destdir = os.path.dirname(dest)
448N/A if not os.path.exists(destdir):
448N/A os.makedirs(destdir)
448N/A with open(dest, 'w') as ofp:
448N/A ofp.write(result)
181N/A
181N/A#
181N/A# mangler.bypass = (true|false)
181N/A#
181N/Adef mangle_paths(manifest, search_paths, destination):
181N/A for action in manifest.gen_actions_by_type("file"):
181N/A bypass = action.attrs.pop('mangler.bypass', 'false').lower()
181N/A if bypass == 'true':
181N/A continue
181N/A
181N/A path = None
181N/A if 'path' in action.attrs:
181N/A path = action.attrs['path']
181N/A if action.hash and action.hash != 'NOHASH':
181N/A path = action.hash
181N/A if not path:
181N/A continue
181N/A
448N/A if not os.path.exists(destination):
448N/A os.makedirs(destination)
448N/A
181N/A dest = os.path.join(destination, path)
181N/A for directory in search_paths:
181N/A if directory != destination:
181N/A src = os.path.join(directory, path)
452N/A if os.path.isfile(src):
181N/A mangle_path(manifest, action, src, dest)
181N/A break
181N/A
3321N/Adef mangle_manifest(manifest):
3321N/A # Check for file content and remove tpno data and license actions if
3321N/A # there is no content in the package that can be licensed.
3321N/A manifest_has_file_content = False
3321N/A
3321N/A for action in manifest.gen_actions_by_type("file"):
3321N/A manifest_has_file_content = True
3321N/A break
3321N/A
3321N/A if not manifest_has_file_content:
3321N/A # search for and remove 'set name=com.oracle.info.tpno ...'
3321N/A for action in manifest.gen_actions_by_type("set"):
3321N/A if (action.attrs["name"] == "com.oracle.info.tpno"):
3321N/A manifest.actions.remove(action)
3321N/A for action in manifest.gen_actions_by_type("license"):
3321N/A manifest.actions.remove(action)
3321N/A
4971N/A # Check for pkg.obsolete and if found, remove any depend actions.
5173N/A # Also remove any require dependency on the release/evalauation
5173N/A # package for renamed packages.
4971N/A manifest_is_obsolete = False
5173N/A manifest_is_renamed = False
4971N/A
4971N/A for action in manifest.gen_actions_by_type("set"):
4971N/A if (action.attrs["name"] == "pkg.obsolete" and
4971N/A action.attrs["value"] == "true"):
4971N/A manifest_is_obsolete = True
5173N/A if (action.attrs["name"] == "pkg.renamed" and
5173N/A action.attrs["value"] == "true"):
5173N/A manifest_is_renamed = True
4971N/A
4971N/A if manifest_is_obsolete:
4971N/A for action in manifest.gen_actions_by_type("depend"):
4971N/A manifest.actions.remove(action)
4971N/A
5173N/A if manifest_is_renamed:
5173N/A for action in manifest.gen_actions_by_type("depend"):
5173N/A if (action.attrs["type"] == "require" and
5173N/A action.attrs["fmri"] == "release/evaluation"):
5173N/A manifest.actions.remove(action)
5173N/A
181N/Adef load_manifest(manifest_file):
181N/A manifest = pkg.manifest.Manifest()
181N/A manifest.set_content(pathname=manifest_file)
181N/A
181N/A return manifest
181N/A
181N/Adef usage():
181N/A print "Usage: %s [-m|--manifest (file)] [-d|--search-directory (dir)] [-D|--destination (dir)] " % (sys.argv[0].split('/')[-1])
181N/A sys.exit(1)
181N/A
181N/Adef main():
181N/A import getopt
181N/A
181N/A # FLUSH STDOUT
181N/A sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
181N/A
181N/A search_paths = []
181N/A destination = None
181N/A manifests = []
181N/A
181N/A try:
181N/A opts, args = getopt.getopt(sys.argv[1:], "D:d:m:",
181N/A ["destination=", "search-directory=", "manifest="])
181N/A except getopt.GetoptError, err:
181N/A print str(err)
181N/A usage()
181N/A
181N/A for opt, arg in opts:
181N/A if opt in [ "-D", "--destination" ]:
181N/A destination = arg
181N/A elif opt in [ "-d", "--search-directory" ]:
181N/A search_paths.append(arg)
181N/A elif opt in [ "-m", "--manifest" ]:
181N/A try:
181N/A manifest = load_manifest(arg)
181N/A except IOError, err:
181N/A print "oops, %s: %s" % (arg, str(err))
181N/A usage()
181N/A else:
181N/A manifests.append(manifest)
181N/A else:
181N/A usage()
181N/A
181N/A if destination == None:
181N/A usage()
181N/A
181N/A for manifest in manifests:
181N/A mangle_paths(manifest, search_paths, destination)
3321N/A mangle_manifest(manifest)
181N/A print manifest
181N/A
181N/A sys.exit(0)
181N/A
181N/Aif __name__ == "__main__":
181N/A main()