|
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) 2010, Oracle and/or its affiliates. All rights reserved. |
|
23 |
|
24 import sys |
|
25 import os |
|
26 import getopt |
|
27 from subprocess import Popen, PIPE |
|
28 |
|
29 |
|
30 XSLT_PROC="/usr/bin/xsltproc" |
|
31 XSLT_FILE="old-to-new.xslt" |
|
32 |
|
33 |
|
34 def usage(exitcode=1): |
|
35 ''' |
|
36 Print help page and exit script. |
|
37 |
|
38 Default exit code is 1, which indicates an error. To exit |
|
39 normally, set keyword param exitcode to 0. |
|
40 ''' |
|
41 this_script = os.path.basename(sys.argv[0]) |
|
42 |
|
43 print "" |
|
44 print "%s - Convert old-style XML AI Manifests to the new schema." % this_script |
|
45 print "" |
|
46 print "For convenience, the command-line interface has similar semantics to cp(1)." |
|
47 print "" |
|
48 print "Usage:" |
|
49 print "\t%s [options] infile outfile" % this_script |
|
50 print "\t%s [options] infile... outdir" % this_script |
|
51 print "\t%s -r [options] indir... outdir" % this_script |
|
52 print "\nOptions:" |
|
53 print "\t-f : force overwrite if output already exists" |
|
54 print "\t-r : recursively transform .xml files in named sub-directory" |
|
55 print "\t-h --help : print this help page and exit" |
|
56 |
|
57 sys.exit(exitcode) |
|
58 |
|
59 |
|
60 def run_cmd(cmd): |
|
61 ''' |
|
62 Execute the given command in a subprocess. |
|
63 |
|
64 On success, returns the stdout from running the command. |
|
65 On failure, raises one of: |
|
66 OSError |
|
67 ValueError |
|
68 Exception |
|
69 ''' |
|
70 |
|
71 try: |
|
72 cmd_popen = Popen(cmd, shell=True, stdout=PIPE) |
|
73 (cmd_stdout, cmd_stderr) = cmd_popen.communicate() |
|
74 except OSError, err: |
|
75 print "ERROR running [%s] : [%s]" % \ |
|
76 (cmd, str(err)) |
|
77 raise |
|
78 except ValueError, err: |
|
79 print "ERROR running [%s] : [%s]" % \ |
|
80 (cmd, str(err)) |
|
81 raise |
|
82 |
|
83 if cmd_popen.returncode != 0: |
|
84 errstr = "ERROR: command [%s] returned [%d] : [%s]" % \ |
|
85 (cmd, cmd_popen.returncode, str(cmd_stderr)) |
|
86 print errstr |
|
87 raise Exception, (errstr) |
|
88 |
|
89 if cmd_stderr is not None: |
|
90 print "WARNING: command [%s] produced stderr output: [%s]" % \ |
|
91 (cmd, cmd_stderr) |
|
92 |
|
93 return cmd_stdout |
|
94 |
|
95 |
|
96 def do_transform(xsltfile, infile, outfile, mkdirs=False, overwrite=False): |
|
97 ''' |
|
98 Create the output directory, if appropriate, and run the xsltproc |
|
99 command to transform infile to oufile. |
|
100 |
|
101 On success, returns True. |
|
102 On failure, returns False. |
|
103 ''' |
|
104 |
|
105 # Normalize the paths so we can check if they are really the same file |
|
106 # (doesn't always work, eg for paths beginning with "..") |
|
107 infile = os.path.normpath(infile) |
|
108 outfile = os.path.normpath(outfile) |
|
109 |
|
110 if infile == outfile: |
|
111 print "ERROR: source [%s] and target [%s] are the same" % \ |
|
112 (infile, outfile) |
|
113 return False |
|
114 |
|
115 outdir = os.path.dirname(outfile) |
|
116 if (len(outdir)) and (not os.path.isdir(outdir)): |
|
117 if os.path.exists(outdir): |
|
118 print "ERROR: target dir [%s] is not a directory" % \ |
|
119 outdir |
|
120 return False |
|
121 |
|
122 if not mkdirs: |
|
123 print "ERROR: target dir [%s] doesn't exist" % \ |
|
124 outdir |
|
125 return False |
|
126 |
|
127 try: |
|
128 os.makedirs(outdir) |
|
129 except OSError, err: |
|
130 print "ERROR: failed to make dir [%s] : [%s]" % \ |
|
131 (outdir, str(err)) |
|
132 return False |
|
133 |
|
134 if (os.path.exists(outfile)) and (not overwrite): |
|
135 print "ERROR: target file [%s] already exists. Use -f." % \ |
|
136 outfile |
|
137 return False |
|
138 |
|
139 # Construct command |
|
140 cmd = "%s -o %s %s %s" % (XSLT_PROC, outfile, xsltfile, infile) |
|
141 |
|
142 try: |
|
143 output = run_cmd(cmd) |
|
144 except: |
|
145 return False |
|
146 |
|
147 return True |
|
148 |
|
149 |
|
150 def do_main(): |
|
151 ''' |
|
152 Process command line options and call do_transform() for |
|
153 each file to be processed. |
|
154 |
|
155 Returns: nothing. |
|
156 ''' |
|
157 |
|
158 sources = [] |
|
159 target = None |
|
160 force_overwrite = False |
|
161 recursive = False |
|
162 target_exists = False |
|
163 |
|
164 # Check xsltproc is installed |
|
165 if not os.access(XSLT_PROC, os.X_OK): |
|
166 print "ERROR: Cannot find %s" % XSLT_PROC |
|
167 print "You may be able to install it with:" |
|
168 print "\tpfexec pkg install pkg:/library/libxslt" |
|
169 sys.exit(1) |
|
170 |
|
171 # Check xsl transform file is available in same dir this |
|
172 # script was run from |
|
173 xsltdir = os.path.dirname(sys.argv[0]) |
|
174 xsltfile = "%s/%s" % (xsltdir, XSLT_FILE) |
|
175 if (not os.path.exists(xsltfile)): |
|
176 print "XSLT file [%s] is missing from directory [%s]" % \ |
|
177 (XSLT_FILE, xsltdir) |
|
178 sys.exit(1) |
|
179 |
|
180 # Fetch and process command line params and options |
|
181 try: |
|
182 optlist, args = getopt.getopt(sys.argv[1:], "frh", ["help"]) |
|
183 except getopt.GetoptError: |
|
184 usage() |
|
185 |
|
186 for opt, arg in optlist: |
|
187 if (opt == "-f"): |
|
188 force_overwrite = True |
|
189 if (opt == "-r"): |
|
190 recursive = True |
|
191 if (opt == "-h") or (opt == "--help"): |
|
192 usage(exitcode=0) |
|
193 |
|
194 # There must be at least 2 params. The last param is the |
|
195 # target; all the other params are the source(s). |
|
196 if len(args) < 2: |
|
197 usage() |
|
198 |
|
199 sources = args[:len(args) - 1] |
|
200 target = args[len(args) - 1] |
|
201 |
|
202 # note whether the target existed before we started |
|
203 if os.path.exists(target): |
|
204 target_exists = True |
|
205 |
|
206 # Check for invalid paramaters (pt. 1) |
|
207 if ((len(sources) > 1) and |
|
208 (not os.path.isdir(target))): |
|
209 # if there are multiple sources (files or dirs), then |
|
210 # target must be an existing directory |
|
211 print "ERROR: [%s] is not a directory" % \ |
|
212 target |
|
213 sys.exit(1) |
|
214 |
|
215 for source in sources: |
|
216 # normalize source path |
|
217 source = os.path.normpath(source) |
|
218 |
|
219 # Check for invalid paramaters (pt. 2) |
|
220 if source == "/": |
|
221 print "ERROR: '/' not allowed" |
|
222 sys.exit(1) |
|
223 if not os.path.exists(source): |
|
224 print "ERROR: no such file or directory: [%s]" % \ |
|
225 source |
|
226 sys.exit(1) |
|
227 if (os.path.isdir(source)) and (not recursive): |
|
228 print "ERROR: [%s] is a directory, but '-r' not specified" % \ |
|
229 source |
|
230 sys.exit(1) |
|
231 if (not os.path.isdir(source)) and (recursive): |
|
232 print "ERROR: [%s] is not a directory, but '-r' was specified" % \ |
|
233 source |
|
234 sys.exit(1) |
|
235 if ((os.path.isdir(source)) and |
|
236 (os.path.exists(target)) and |
|
237 (not os.path.isdir(target))): |
|
238 print "ERROR: [%s] is not a directory" % \ |
|
239 target |
|
240 sys.exit(1) |
|
241 |
|
242 if os.path.isdir(source): |
|
243 # recursively iterate through source dir, processing each file |
|
244 for dirpath, dirnames, filenames in os.walk(source): |
|
245 # alter dirnames in-place to skip .* |
|
246 dirnames[:] = [d for d in dirnames if not d.startswith('.')] |
|
247 |
|
248 for name in filenames: |
|
249 srcfile = os.path.join(dirpath, name) |
|
250 |
|
251 partial_dstfile = os.path.join(dirpath, name) |
|
252 |
|
253 # replicate how cp -r treats sub-dirs: |
|
254 # 1. if source contains multiple sub-dirs, eg "a/b/c" |
|
255 # then only create rightmost one, eg "c", under target |
|
256 index = source.rfind("/", 1) |
|
257 if index != -1: |
|
258 # ensure partial_dstfile begins with source |
|
259 if partial_dstfile.find(source) == 0: |
|
260 partial_dstfile = partial_dstfile[index+1:] |
|
261 |
|
262 # replicate how cp -r treats sub-dirs: |
|
263 # 2. if target already existed then chop off leftmost |
|
264 # dir of source from target |
|
265 if not target_exists: |
|
266 index = partial_dstfile.find("/", 1) |
|
267 if index != -1: |
|
268 partial_dstfile = partial_dstfile[index+1:] |
|
269 |
|
270 dstfile = os.path.join(target, partial_dstfile) |
|
271 |
|
272 if not do_transform(xsltfile, srcfile, dstfile, |
|
273 mkdirs=True, overwrite=force_overwrite): |
|
274 print "ERROR: Transform failed." |
|
275 sys.exit(1) |
|
276 elif os.path.isdir(target): |
|
277 dstfile = os.path.join(target, os.path.basename(source)) |
|
278 |
|
279 if not do_transform(xsltfile, source, dstfile, |
|
280 mkdirs=False, overwrite=force_overwrite): |
|
281 print "ERROR: Transform failed." |
|
282 sys.exit(1) |
|
283 else: |
|
284 # this must be a simple "single infile" -> "single outfile" job |
|
285 if not do_transform(xsltfile, source, target, |
|
286 mkdirs=False, overwrite=force_overwrite): |
|
287 print "ERROR: Transform failed." |
|
288 sys.exit(1) |
|
289 |
|
290 |
|
291 if __name__ == "__main__": |
|
292 do_main() |
|
293 |
|
294 sys.exit(0) |