OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 | 2 |
3 # Copyright 2014 The Chromium Authors. All rights reserved. | 3 # Copyright 2014 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 '''Produces various output formats from a set of JavaScript files with | 7 '''Produces various output formats from a set of JavaScript files with |
8 closure style require/provide calls. | 8 closure style require/provide calls. |
9 | 9 |
10 Scans one or more directory trees for JavaScript files. Then, from a | 10 Scans one or more directory trees for JavaScript files. Then, from a |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 base.GetInPath(), | 229 base.GetInPath(), |
230 base.GetOutPath()) | 230 base.GetOutPath()) |
231 | 231 |
232 def LinkOrCopyFiles(sources, dest_dir): | 232 def LinkOrCopyFiles(sources, dest_dir): |
233 '''Copies a list of sources to a destination directory.''' | 233 '''Copies a list of sources to a destination directory.''' |
234 | 234 |
235 def LinkOrCopyOneFile(src, dst): | 235 def LinkOrCopyOneFile(src, dst): |
236 if not os.path.exists(os.path.dirname(dst)): | 236 if not os.path.exists(os.path.dirname(dst)): |
237 os.makedirs(os.path.dirname(dst)) | 237 os.makedirs(os.path.dirname(dst)) |
238 if os.path.exists(dst): | 238 if os.path.exists(dst): |
239 # Avoid clobbering the inode if source and destination refer to the | |
240 # same file already. | |
241 if os.path.samefile(src, dst): | |
242 return | |
243 os.unlink(dst) | 239 os.unlink(dst) |
244 try: | 240 try: |
245 os.link(src, dst) | 241 os.link(src, dst) |
246 except: | 242 except: |
247 shutil.copy(src, dst) | 243 shutil.copy(src, dst) |
248 | 244 |
249 for source in sources: | 245 for source in sources: |
250 LinkOrCopyOneFile(source.GetInPath(), | 246 LinkOrCopyOneFile(source.GetInPath(), |
251 os.path.join(dest_dir, source.GetOutPath())) | 247 os.path.join(dest_dir, source.GetOutPath())) |
252 | 248 |
(...skipping 17 matching lines...) Expand all Loading... |
270 HTML_TEMPLATE = '<script src=\'%s\'>' | 266 HTML_TEMPLATE = '<script src=\'%s\'>' |
271 script_lines = (HTML_TEMPLATE % p for p in bundle.GetOutPaths()) | 267 script_lines = (HTML_TEMPLATE % p for p in bundle.GetOutPaths()) |
272 out_file.write('\n'.join(script_lines)) | 268 out_file.write('\n'.join(script_lines)) |
273 elif format == 'bundle': | 269 elif format == 'bundle': |
274 out_file.write(bundle.GetUncompressedSource()) | 270 out_file.write(bundle.GetUncompressedSource()) |
275 elif format == 'compressed_bundle': | 271 elif format == 'compressed_bundle': |
276 out_file.write(bundle.GetCompressedSource()) | 272 out_file.write(bundle.GetCompressedSource()) |
277 out_file.write('\n') | 273 out_file.write('\n') |
278 | 274 |
279 | 275 |
| 276 def WriteDepfile(depfile, outfile, infiles): |
| 277 '''Writes a depfile. |
| 278 |
| 279 Args: |
| 280 depfile, string: name of dep file to write |
| 281 outfile, string: Name of output file to use as the target in the generated |
| 282 .d file. |
| 283 infiles, list: File names to list as dependencies in the .d file. |
| 284 ''' |
| 285 content = '%s: %s' % (outfile, ' '.join(infiles)) |
| 286 open(depfile, 'w').write(content) |
| 287 |
| 288 |
280 def CreateOptionParser(): | 289 def CreateOptionParser(): |
281 parser = optparse.OptionParser(description=__doc__) | 290 parser = optparse.OptionParser(description=__doc__) |
282 parser.usage = '%prog [options] <top_level_file>...' | 291 parser.usage = '%prog [options] <top_level_file>...' |
283 parser.add_option('-d', '--dest_dir', action='store', metavar='DIR', | 292 parser.add_option('-d', '--dest_dir', action='store', metavar='DIR', |
284 help=('Destination directory. Used when translating ' + | 293 help=('Destination directory. Used when translating ' + |
285 'input paths to output paths and when copying ' | 294 'input paths to output paths and when copying ' |
286 'files.')) | 295 'files.')) |
287 parser.add_option('-o', '--output_file', action='store', metavar='FILE', | 296 parser.add_option('-o', '--output_file', action='store', metavar='FILE', |
288 help=('File to output result to for modes that output ' | 297 help=('File to output result to for modes that output ' |
289 'a single file.')) | 298 'a single file.')) |
290 parser.add_option('-r', '--root', dest='roots', action='append', default=[], | 299 parser.add_option('-r', '--root', dest='roots', action='append', default=[], |
291 metavar='ROOT', | 300 metavar='ROOT', |
292 help='Roots of directory trees to scan for sources.') | 301 help='Roots of directory trees to scan for sources.') |
| 302 parser.add_option('-M', '--module', dest='modules', action='append', |
| 303 default=[], metavar='FILENAME', |
| 304 help='Source modules to load') |
293 parser.add_option('-w', '--rewrite_prefix', action='append', default=[], | 305 parser.add_option('-w', '--rewrite_prefix', action='append', default=[], |
294 dest='prefix_map', metavar='SPEC', | 306 dest='prefix_map', metavar='SPEC', |
295 help=('Two path prefixes, separated by colons ' + | 307 help=('Two path prefixes, separated by colons ' + |
296 'specifying that a file whose (relative) path ' + | 308 'specifying that a file whose (relative) path ' + |
297 'name starts with the first prefix should have ' + | 309 'name starts with the first prefix should have ' + |
298 'that prefix replaced by the second prefix to ' + | 310 'that prefix replaced by the second prefix to ' + |
299 'form a path relative to the output directory.')) | 311 'form a path relative to the output directory.')) |
300 parser.add_option('-m', '--mode', type='choice', action='store', | 312 parser.add_option('-m', '--mode', type='choice', action='store', |
301 choices=['list', 'html', 'bundle', | 313 choices=['list', 'html', 'bundle', |
302 'compressed_bundle', 'copy'], | 314 'compressed_bundle', 'copy'], |
303 default='list', metavar='MODE', | 315 default='list', metavar='MODE', |
304 help=("Otput mode. One of 'list', 'html', 'bundle', " + | 316 help=("Otput mode. One of 'list', 'html', 'bundle', " + |
305 "'compressed_bundle' or 'copy'.")) | 317 "'compressed_bundle' or 'copy'.")) |
306 parser.add_option('-x', '--exclude', action='append', default=[], | 318 parser.add_option('-x', '--exclude', action='append', default=[], |
307 help=('Exclude files whose full path contains a match for ' | 319 help=('Exclude files whose full path contains a match for ' |
308 'the given regular expression. Does not apply to ' | 320 'the given regular expression. Does not apply to ' |
309 'filenames given as arguments.')) | 321 'filenames given as arguments or with the ' |
| 322 '-m option.')) |
| 323 parser.add_option('--depfile', metavar='FILENAME', |
| 324 help='Store .d style dependencies in FILENAME') |
310 return parser | 325 return parser |
311 | 326 |
312 | 327 |
313 def main(): | 328 def main(): |
314 options, args = CreateOptionParser().parse_args() | 329 options, args = CreateOptionParser().parse_args() |
315 if len(args) < 1: | 330 if len(args) < 1: |
316 Die('At least one top-level source file must be specified.') | 331 Die('At least one top-level source file must be specified.') |
| 332 if options.depfile and not options.output_file: |
| 333 Die('--depfile requires an output file') |
317 will_output_source_text = options.mode in ('bundle', 'compressed_bundle') | 334 will_output_source_text = options.mode in ('bundle', 'compressed_bundle') |
318 path_rewriter = PathRewriter(options.prefix_map) | 335 path_rewriter = PathRewriter(options.prefix_map) |
319 exclude = [re.compile(r) for r in options.exclude] | 336 exclude = [re.compile(r) for r in options.exclude] |
320 sources = ReadSources(options.roots, args, will_output_source_text, | 337 sources = ReadSources(options.roots, options.modules + args, |
| 338 will_output_source_text or len(options.modules) > 0, |
321 path_rewriter, exclude) | 339 path_rewriter, exclude) |
322 if will_output_source_text: | 340 if will_output_source_text: |
323 _MarkAsCompiled(sources) | 341 _MarkAsCompiled(sources) |
324 bundle = Bundle() | 342 bundle = Bundle() |
325 if len(options.roots) > 0: | 343 if len(options.roots) > 0 or len(options.modules) > 0: |
326 CalcDeps(bundle, sources, args) | 344 CalcDeps(bundle, sources, args) |
327 bundle.Add((sources[name] for name in args)) | 345 bundle.Add((sources[name] for name in args)) |
328 if options.mode == 'copy': | 346 if options.mode == 'copy': |
329 if options.dest_dir is None: | 347 if options.dest_dir is None: |
330 Die('Must specify --dest_dir when copying.') | 348 Die('Must specify --dest_dir when copying.') |
331 LinkOrCopyFiles(bundle.GetSources(), options.dest_dir) | 349 LinkOrCopyFiles(bundle.GetSources(), options.dest_dir) |
332 else: | 350 else: |
333 if options.output_file: | 351 if options.output_file: |
334 out_file = open(options.output_file, 'w') | 352 out_file = open(options.output_file, 'w') |
335 else: | 353 else: |
336 out_file = sys.stdout | 354 out_file = sys.stdout |
337 try: | 355 try: |
338 WriteOutput(bundle, options.mode, out_file, options.dest_dir) | 356 WriteOutput(bundle, options.mode, out_file, options.dest_dir) |
339 finally: | 357 finally: |
340 if options.output_file: | 358 if options.output_file: |
341 out_file.close() | 359 out_file.close() |
342 | 360 if options.depfile: |
| 361 WriteDepfile(options.depfile, options.output_file, bundle.GetInPaths()) |
343 | 362 |
344 if __name__ == '__main__': | 363 if __name__ == '__main__': |
345 main() | 364 main() |
OLD | NEW |