| #!/usr/bin/env python3 | 
 | # Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file | 
 | # for details. All rights reserved. Use of this source code is governed by a | 
 | # BSD-style license that can be found in the LICENSE file. | 
 | """Used to merge and copy dart source files for deployment to AppEngine""" | 
 |  | 
 | import fileinput | 
 | import sys | 
 | import os | 
 | import re | 
 | from os.path import basename, dirname, exists, isabs, join | 
 | from glob import glob | 
 |  | 
 | re_directive = re.compile(r'^(library|import|part|native|resource)\s+(.*);$') | 
 | re_comment = re.compile(r'^(///|/\*| \*).*$') | 
 |  | 
 |  | 
 | class Library(object): | 
 |  | 
 |     def __init__(self, name, imports, sources, natives, code, comment): | 
 |         self.name = name | 
 |         self.imports = imports | 
 |         self.sources = sources | 
 |         self.natives = natives | 
 |         self.code = code | 
 |         self.comment = comment | 
 |  | 
 |  | 
 | def parseLibrary(library): | 
 |     """ Parses a .dart source file that is the root of a library, and returns | 
 |       information about it: the name, the imports, included sources, and any | 
 |       code in the file. | 
 |   """ | 
 |     libraryname = None | 
 |     imports = [] | 
 |     sources = [] | 
 |     natives = [] | 
 |     inlinecode = [] | 
 |     librarycomment = [] | 
 |     if exists(library): | 
 |         # TODO(sigmund): stop parsing when import/source | 
 |         for line in fileinput.input(library): | 
 |             match = re_directive.match(line) | 
 |             if match: | 
 |                 directive = match.group(1) | 
 |                 if directive == 'library': | 
 |                     assert libraryname is None | 
 |                     libraryname = match.group(2) | 
 |                 elif directive == 'part': | 
 |                     suffix = match.group(2) | 
 |                     if not suffix.startswith('of '): | 
 |                         sources.append(match.group(2).strip('"\'')) | 
 |                 elif directive == 'import': | 
 |                     imports.append(match.group(2)) | 
 |                 else: | 
 |                     raise Exception( | 
 |                         'unknown directive %s in %s' % (directive, line)) | 
 |             else: | 
 |                 # Check for library comment. | 
 |                 if not libraryname and re_comment.match(line): | 
 |                     librarycomment.append(line) | 
 |                 else: | 
 |                     inlinecode.append(line) | 
 |         fileinput.close() | 
 |     return Library(libraryname, imports, sources, natives, inlinecode, | 
 |                    librarycomment) | 
 |  | 
 |  | 
 | def normjoin(*args): | 
 |     return os.path.normpath(os.path.join(*args)) | 
 |  | 
 |  | 
 | def mergefiles(srcs, dstfile): | 
 |     for src in srcs: | 
 |         with open(src, 'r') as s: | 
 |             for line in s: | 
 |                 if not line.startswith('part of '): | 
 |                     dstfile.write(line) | 
 |  | 
 |  | 
 | def main(outdir=None, *inputs): | 
 |     if not outdir or not inputs: | 
 |         print("""Usage: %s OUTDIR INPUTS | 
 |   OUTDIR is the war directory to copy to | 
 |   INPUTS is a list of files or patterns used to specify the input | 
 |    .dart files | 
 | This script should be run from the client root directory. | 
 | Files will be merged and copied to: OUTDIR/relative-path-of-file, | 
 | except for dart files with absolute paths, which will be copied to | 
 |  OUTDIR/absolute-path-as-directories""" % sys.argv[0]) | 
 |         return 1 | 
 |  | 
 |     entry_libraries = [] | 
 |     for i in inputs: | 
 |         entry_libraries.extend(glob(i)) | 
 |  | 
 |     for entrypoint in entry_libraries: | 
 |         # Get the transitive set of dart files this entrypoint depends on, merging | 
 |         # each library along the way. | 
 |         worklist = [os.path.normpath(entrypoint)] | 
 |         seen = set() | 
 |         while len(worklist) > 0: | 
 |             lib = worklist.pop() | 
 |             if lib in seen: | 
 |                 continue | 
 |  | 
 |             seen.add(lib) | 
 |  | 
 |             if (dirname(dirname(lib)).endswith('dom/generated/src') or | 
 |                     dirname(lib).endswith('dom/src')): | 
 |                 continue | 
 |  | 
 |             library = parseLibrary(lib) | 
 |  | 
 |             # Ensure output directory exists | 
 |             outpath = join(outdir, lib[1:] if isabs(lib) else lib) | 
 |             dstpath = dirname(outpath) | 
 |             if not exists(dstpath): | 
 |                 os.makedirs(dstpath) | 
 |  | 
 |             # Create file containing all imports, and inlining all sources | 
 |             with open(outpath, 'w') as f: | 
 |                 prefix = os.environ.get('DART_HTML_PREFIX') | 
 |                 if prefix: | 
 |                     f.write(prefix + '\n') | 
 |                 if library.name: | 
 |                     if library.comment: | 
 |                         f.write('%s' % (''.join(library.comment))) | 
 |                     f.write("library %s;\n\n" % library.name) | 
 |                 else: | 
 |                     f.write("library %s;\n\n" % basename(lib)) | 
 |                 for importfile in library.imports: | 
 |                     f.write("import %s;\n" % importfile) | 
 |                 f.write('%s' % (''.join(library.code))) | 
 |                 mergefiles([normjoin(dirname(lib), s) for s in library.sources], | 
 |                            f) | 
 |  | 
 |             for suffix in library.imports: | 
 |                 m = re.match(r'[\'"]([^\'"]+)[\'"](\s+as\s+\w+)?.*$', suffix) | 
 |                 uri = m.group(1) | 
 |                 if not uri.startswith('dart:'): | 
 |                     worklist.append(normjoin(dirname(lib), uri)) | 
 |  | 
 |     return 0 | 
 |  | 
 |  | 
 | if __name__ == '__main__': | 
 |     sys.exit(main(*sys.argv[1:])) |