Norm Jacobs
2011-04-13 4158c02ccf09e2f646cf2e9e5599f186ec8c7302
commit | author | age
4158c0 1 #!/usr/bin/python2.6
NJ 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()