5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
22 # Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
25 # userland-mangler - a file mangling utility
27 # A simple program to mangle files to conform to Solaris WOS or Consoldation
40 attribute_oracle_table_header = """
41 .\\\" Oracle has added the ARC stability level to this manual page"""
43 attribute_table_header = """
47 for descriptions of the following attributes:
53 ATTRIBUTE TYPE ATTRIBUTE VALUE """
55 attribute_table_availability = """
59 attribute_table_stability = """
63 attribute_table_footer = """
67 def attributes_section_text(availability, stability, modified_date):
70 # is there anything to do?
71 if availability is not None or stability is not None:
72 result = attribute_oracle_table_header
73 if modified_date is not None:
74 result += ("\n.\\\" on %s" % modified_date)
75 result += attribute_table_header
77 if availability is not None:
78 result += (attribute_table_availability % availability)
79 if stability is not None:
80 result += (attribute_table_stability % stability.capitalize())
81 result += attribute_table_footer
85 notes_oracle_comment = """
86 .\\\" Oracle has added source availability information to this manual page"""
93 Further information about this software can be found on the open source community website at %s.
96 This software was built from source available at http://opensolaris.org/. The original community source was downloaded from %s
99 def notes_section_text(header_seen, community, source, modified_date):
102 # is there anything to do?
103 if community is not None or source is not None:
104 if header_seen == False:
105 result += notes_header
106 result += notes_oracle_comment
107 if modified_date is not None:
108 result += ("\n.\\\" on %s" % modified_date)
109 if source is not None:
110 result += (notes_source % source)
111 if community is not None:
112 result += (notes_community % community)
116 so_re = re.compile('^\.so.+$', re.MULTILINE)
117 section_re = re.compile('\.SH "?([^"]+).*$', re.IGNORECASE)
118 TH_re = re.compile('\.TH\s+(?:"[^"]+"|\S+)\s+(\S+)', re.IGNORECASE)
120 # mangler.man.stability = (mangler.man.stability)
121 # mangler.man.modified_date = (mangler.man.modified-date)
122 # mangler.man.availability = (pkg.fmri)
123 # mangler.man.source-url = (pkg.source-url)
124 # mangler.man.upstream-url = (pkg.upstream-url)
126 def mangle_manpage(manifest, action, text):
127 # manpages must have a taxonomy defined
128 stability = action.attrs.pop('mangler.man.stability', None)
129 if stability is None:
130 sys.stderr.write("ERROR: manpage action missing mangler.man.stability: %s" % action)
133 # manpages may have a 'modified date'
134 modified_date = action.attrs.pop('mangler.man.modified-date', None)
136 # Rewrite the section in the .TH line to match the section in which
137 # we're delivering it.
138 rewrite_sect = action.attrs.pop('mangler.man.rewrite-section', 'true')
140 attributes_written = False
143 if 'pkg.fmri' in manifest.attributes:
144 fmri = pkg.fmri.PkgFmri(manifest.attributes['pkg.fmri'])
145 availability = fmri.pkg_name
148 if 'info.upstream-url' in manifest.attributes:
149 community = manifest.attributes['info.upstream-url']
152 if 'info.source-url' in manifest.attributes:
153 source = manifest.attributes['info.source-url']
154 elif 'info.repository-url' in manifest.attributes:
155 source = manifest.attributes['info.repository-url']
157 # skip reference only pages
158 if so_re.match(text) is not None:
161 # tell man that we want tables (and eqn)
162 result = "'\\\" te\n"
164 # write the orginal data
165 for line in text.split('\n'):
166 match = section_re.match(line)
167 if match is not None:
168 section = match.group(1)
169 if section in ['SEE ALSO', 'NOTES']:
170 if attributes_written == False:
171 result += attributes_section_text(
175 attributes_written = True
176 if section == 'NOTES':
178 match = TH_re.match(line)
179 if match and rewrite_sect.lower() == "true":
180 # Use the section defined by the filename, rather than
181 # the directory in which it sits.
182 sect = os.path.splitext(action.attrs["path"])[1][1:]
183 line = line[:match.span(1)[0]] + sect + \
184 line[match.span(1)[1]:]
186 result += ("%s\n" % line)
188 if attributes_written == False:
189 result += attributes_section_text(availability, stability,
192 result += notes_section_text(notes_seen, community, source,
199 # mangler.elf.strip = (true|false)
201 def mangle_elf(manifest, action, src, dest):
205 # mangler.script.file-magic =
207 def mangle_script(manifest, action, text):
211 # mangler.strip_cddl = false
213 def mangle_cddl(manifest, action, text):
214 strip_cddl = action.attrs.pop('mangler.strip_cddl', 'true')
215 if strip_cddl is 'false':
217 cddl_re = re.compile('^[^\n]*CDDL HEADER START.+CDDL HEADER END[^\n]*$',
218 re.MULTILINE|re.DOTALL)
219 return cddl_re.sub('', text)
221 def mangle_path(manifest, action, src, dest):
222 if elf.is_elf_object(src):
223 mangle_elf(manifest, action, src, dest)
225 # a 'text' document (script, man page, config file, ...
230 # remove the CDDL from files
231 result = mangle_cddl(manifest, action, text)
233 if 'facet.doc.man' in action.attrs:
234 result = mangle_manpage(manifest, action, result)
235 elif 'mode' in action.attrs and int(action.attrs['mode'], 8) & 0111 != 0:
236 result = mangle_script(manifest, action, result)
239 destdir = os.path.dirname(dest)
240 if not os.path.exists(destdir):
242 with open(dest, 'w') as ofp:
246 # mangler.bypass = (true|false)
248 def mangle_paths(manifest, search_paths, destination):
249 for action in manifest.gen_actions_by_type("file"):
250 bypass = action.attrs.pop('mangler.bypass', 'false').lower()
255 if 'path' in action.attrs:
256 path = action.attrs['path']
257 if action.hash and action.hash != 'NOHASH':
262 if not os.path.exists(destination):
263 os.makedirs(destination)
265 dest = os.path.join(destination, path)
266 for directory in search_paths:
267 if directory != destination:
268 src = os.path.join(directory, path)
269 if os.path.isfile(src):
270 mangle_path(manifest, action, src, dest)
273 def load_manifest(manifest_file):
274 manifest = pkg.manifest.Manifest()
275 manifest.set_content(pathname=manifest_file)
280 print "Usage: %s [-m|--manifest (file)] [-d|--search-directory (dir)] [-D|--destination (dir)] " % (sys.argv[0].split('/')[-1])
287 sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
294 opts, args = getopt.getopt(sys.argv[1:], "D:d:m:",
295 ["destination=", "search-directory=", "manifest="])
296 except getopt.GetoptError, err:
300 for opt, arg in opts:
301 if opt in [ "-D", "--destination" ]:
303 elif opt in [ "-d", "--search-directory" ]:
304 search_paths.append(arg)
305 elif opt in [ "-m", "--manifest" ]:
307 manifest = load_manifest(arg)
309 print "oops, %s: %s" % (arg, str(err))
312 manifests.append(manifest)
316 if destination == None:
319 for manifest in manifests:
320 mangle_paths(manifest, search_paths, destination)
325 if __name__ == "__main__":