|
1 #!/usr/bin/python2.6 |
|
2 # |
|
3 # CDDL HEADER START |
|
4 # |
|
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. |
|
8 # |
|
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. |
|
13 # |
|
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] |
|
19 # |
|
20 # CDDL HEADER END |
|
21 # |
|
22 # Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. |
|
23 # |
|
24 # |
|
25 # userland-mangler - a file mangling utility |
|
26 # |
|
27 # A simple program to mangle files to conform to Solaris WOS or Consoldation |
|
28 # requirements. |
|
29 # |
|
30 |
|
31 import os |
|
32 import sys |
|
33 import re |
|
34 |
|
35 import pkg.fmri |
|
36 import pkg.manifest |
|
37 import pkg.actions |
|
38 import pkg.elf as elf |
|
39 |
|
40 attribute_table_header = """ |
|
41 .SH ATTRIBUTES |
|
42 See |
|
43 .BR attributes (5) |
|
44 for descriptions of the following attributes: |
|
45 .sp |
|
46 .TS |
|
47 box; |
|
48 cbp-1 | cbp-1 |
|
49 l | l . |
|
50 ATTRIBUTE TYPE ATTRIBUTE VALUE """ |
|
51 |
|
52 attribute_table_availability = """ |
|
53 = |
|
54 Availability %s""" |
|
55 |
|
56 attribute_table_stability = """ |
|
57 = |
|
58 Stability %s""" |
|
59 |
|
60 attribute_table_footer = """ |
|
61 .TE |
|
62 .PP |
|
63 """ |
|
64 def write_attributes_section(ofp, availability, stability): |
|
65 # is there anything to do? |
|
66 if availability is None and stability is None: |
|
67 return |
|
68 |
|
69 # append the ATTRIBUTES section |
|
70 ofp.write(attribute_table_header) |
|
71 if availability is not None: |
|
72 ofp.write(attribute_table_availability % availability) |
|
73 if stability is not None: |
|
74 ofp.write(attribute_table_stability % stability.capitalize()) |
|
75 ofp.write(attribute_table_footer) |
|
76 |
|
77 |
|
78 notes_header = """ |
|
79 .SH NOTES |
|
80 """ |
|
81 |
|
82 notes_community = """ |
|
83 Further information about this software can be found on the open source community website at %s. |
|
84 """ |
|
85 notes_source = """ |
|
86 This software was built from source available at http://opensolaris.org/. The original community source was downloaded from %s |
|
87 """ |
|
88 |
|
89 def write_notes_section(ofp, header_seen, community, source): |
|
90 # is there anything to do? |
|
91 if community is None and source is None: |
|
92 return |
|
93 |
|
94 # append the NOTES section |
|
95 if header_seen == False: |
|
96 ofp.write(notes_header) |
|
97 if source is not None: |
|
98 ofp.write(notes_source % source) |
|
99 if community is not None: |
|
100 ofp.write(notes_community % community) |
|
101 |
|
102 |
|
103 section_re = re.compile('\.SH "?([^"]+).*$', re.IGNORECASE) |
|
104 # |
|
105 # mangler.man.stability = (mangler.man.stability) |
|
106 # mangler.man.availability = (pkg.fmri) |
|
107 # mangler.man.source_url = (pkg.source_url) |
|
108 # mangler.man.upstream_url = (pkg.upstream_url) |
|
109 # |
|
110 def mangle_manpage(manifest, action, src, dest): |
|
111 # manpages must have a taxonomy defined |
|
112 stability = action.attrs.pop('mangler.man.stability', None) |
|
113 if stability is None: |
|
114 sys.stderr.write("ERROR: manpage action missing mangler.man.stability: %s" % action) |
|
115 sys.exit(1) |
|
116 |
|
117 attributes_written = False |
|
118 notes_seen = False |
|
119 |
|
120 if 'pkg.fmri' in manifest.attributes: |
|
121 fmri = pkg.fmri.PkgFmri(manifest.attributes['pkg.fmri']) |
|
122 availability = fmri.pkg_name |
|
123 |
|
124 if 'info.upstream_url' in manifest.attributes: |
|
125 community = manifest.attributes['info.upstream_url'] |
|
126 |
|
127 if 'info.source_url' in manifest.attributes: |
|
128 source = manifest.attributes['info.source_url'] |
|
129 |
|
130 # create a directory to write to |
|
131 destdir = os.path.dirname(dest) |
|
132 if not os.path.exists(destdir): |
|
133 os.makedirs(destdir) |
|
134 |
|
135 # read the source document |
|
136 ifp = open(src, "r") |
|
137 lines = ifp.readlines() |
|
138 ifp.close() |
|
139 |
|
140 # skip reference only pages |
|
141 if lines[0].startswith(".so "): |
|
142 return |
|
143 |
|
144 # open a destination |
|
145 ofp = open(dest, "w+") |
|
146 |
|
147 # tell man that we want tables (and eqn) |
|
148 ofp.write("'\\\" te\n") |
|
149 |
|
150 # write the orginal data |
|
151 for line in lines: |
|
152 match = section_re.match(line) |
|
153 if match is not None: |
|
154 section = match.group(1) |
|
155 if section in ['SEE ALSO', 'NOTES']: |
|
156 if attributes_written == False: |
|
157 write_attributes_section(ofp, |
|
158 availability, |
|
159 stability) |
|
160 attributes_written = True |
|
161 if section == 'NOTES': |
|
162 notes_seen = True |
|
163 ofp.write(line) |
|
164 |
|
165 if attributes_written == False: |
|
166 write_attributes_section(ofp, availability, stability) |
|
167 |
|
168 write_notes_section(ofp, notes_seen, community, source) |
|
169 |
|
170 ofp.close() |
|
171 |
|
172 |
|
173 # |
|
174 # mangler.elf.strip = (true|false) |
|
175 # |
|
176 def mangle_elf(manifest, action, src, dest): |
|
177 pass |
|
178 |
|
179 # |
|
180 # mangler.script.file-magic = |
|
181 # |
|
182 def mangle_script(manifest, action, src, dest): |
|
183 pass |
|
184 |
|
185 def mangle_path(manifest, action, src, dest): |
|
186 if 'facet.doc.man' in action.attrs: |
|
187 mangle_manpage(manifest, action, src, dest) |
|
188 elif 'mode' in action.attrs and int(action.attrs['mode'], 8) & 0111 != 0: |
|
189 if elf.is_elf_object(src): |
|
190 mangle_elf(manifest, action, src, dest) |
|
191 else: |
|
192 mangle_script(manifest, action, src, dest) |
|
193 |
|
194 # |
|
195 # mangler.bypass = (true|false) |
|
196 # |
|
197 def mangle_paths(manifest, search_paths, destination): |
|
198 for action in manifest.gen_actions_by_type("file"): |
|
199 bypass = action.attrs.pop('mangler.bypass', 'false').lower() |
|
200 if bypass == 'true': |
|
201 continue |
|
202 |
|
203 path = None |
|
204 if 'path' in action.attrs: |
|
205 path = action.attrs['path'] |
|
206 if action.hash and action.hash != 'NOHASH': |
|
207 path = action.hash |
|
208 if not path: |
|
209 continue |
|
210 |
|
211 dest = os.path.join(destination, path) |
|
212 for directory in search_paths: |
|
213 if directory != destination: |
|
214 src = os.path.join(directory, path) |
|
215 if os.path.exists(src): |
|
216 mangle_path(manifest, action, src, dest) |
|
217 break |
|
218 |
|
219 def load_manifest(manifest_file): |
|
220 manifest = pkg.manifest.Manifest() |
|
221 manifest.set_content(pathname=manifest_file) |
|
222 |
|
223 return manifest |
|
224 |
|
225 def usage(): |
|
226 print "Usage: %s [-m|--manifest (file)] [-d|--search-directory (dir)] [-D|--destination (dir)] " % (sys.argv[0].split('/')[-1]) |
|
227 sys.exit(1) |
|
228 |
|
229 def main(): |
|
230 import getopt |
|
231 |
|
232 # FLUSH STDOUT |
|
233 sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) |
|
234 |
|
235 search_paths = [] |
|
236 destination = None |
|
237 manifests = [] |
|
238 |
|
239 try: |
|
240 opts, args = getopt.getopt(sys.argv[1:], "D:d:m:", |
|
241 ["destination=", "search-directory=", "manifest="]) |
|
242 except getopt.GetoptError, err: |
|
243 print str(err) |
|
244 usage() |
|
245 |
|
246 for opt, arg in opts: |
|
247 if opt in [ "-D", "--destination" ]: |
|
248 destination = arg |
|
249 elif opt in [ "-d", "--search-directory" ]: |
|
250 search_paths.append(arg) |
|
251 elif opt in [ "-m", "--manifest" ]: |
|
252 try: |
|
253 manifest = load_manifest(arg) |
|
254 except IOError, err: |
|
255 print "oops, %s: %s" % (arg, str(err)) |
|
256 usage() |
|
257 else: |
|
258 manifests.append(manifest) |
|
259 else: |
|
260 usage() |
|
261 |
|
262 if destination == None: |
|
263 usage() |
|
264 |
|
265 for manifest in manifests: |
|
266 mangle_paths(manifest, search_paths, destination) |
|
267 print manifest |
|
268 |
|
269 sys.exit(0) |
|
270 |
|
271 if __name__ == "__main__": |
|
272 main() |