| #!/usr/bin/env python3 | 
 | # Copyright (c) 2017, 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. | 
 |  | 
 | import argparse | 
 | import gn_helpers | 
 | import os | 
 | import re | 
 | import shutil | 
 | import sys | 
 |  | 
 |  | 
 | def ParseArgs(args): | 
 |     args = args[1:] | 
 |     parser = argparse.ArgumentParser( | 
 |         description='A script to copy a file tree somewhere') | 
 |  | 
 |     parser.add_argument('--depfile', | 
 |                         '-d', | 
 |                         type=str, | 
 |                         help='Path to a depfile to write when copying.') | 
 |     parser.add_argument( | 
 |         '--exclude_patterns', | 
 |         '-e', | 
 |         type=str, | 
 |         help='Patterns to exclude [passed to shutil.copytree]') | 
 |     parser.add_argument( | 
 |         '--from', '-f', dest="copy_from", type=str, help='Source directory') | 
 |     parser.add_argument( | 
 |         '--stamp', | 
 |         '-s', | 
 |         type=str, | 
 |         help='The path to a stamp file to output when finished.') | 
 |     parser.add_argument('--to', '-t', type=str, help='Destination directory') | 
 |  | 
 |     return parser.parse_args(args) | 
 |  | 
 |  | 
 | def ValidateArgs(args): | 
 |     if not args.copy_from or not os.path.isdir(args.copy_from): | 
 |         print("--from argument must refer to a directory") | 
 |         return False | 
 |     if not args.to: | 
 |         print("--to is required") | 
 |         return False | 
 |     return True | 
 |  | 
 |  | 
 | # Returns a list of the files under 'src' that were copied. | 
 | def CopyTree(src, dst, ignore=None): | 
 |     copied_files = [] | 
 |  | 
 |     # Recursive helper method to collect errors but keep processing. | 
 |     def copy_tree(src, dst, ignore, errors): | 
 |         names = os.listdir(src) | 
 |         if ignore is not None: | 
 |             ignored_names = ignore(src, names) | 
 |         else: | 
 |             ignored_names = set() | 
 |  | 
 |         if not os.path.exists(dst): | 
 |             os.makedirs(dst) | 
 |         for name in names: | 
 |             if name in ignored_names: | 
 |                 continue | 
 |             srcname = os.path.join(src, name) | 
 |             dstname = os.path.join(dst, name) | 
 |             try: | 
 |                 if os.path.isdir(srcname): | 
 |                     copy_tree(srcname, dstname, ignore, errors) | 
 |                 else: | 
 |                     copied_files.append(srcname) | 
 |                     shutil.copy(srcname, dstname) | 
 |             except (IOError, os.error) as why: | 
 |                 errors.append((srcname, dstname, str(why))) | 
 |         try: | 
 |             shutil.copystat(src, dst) | 
 |         except WindowsError: | 
 |             # Can't copy file access times on Windows. | 
 |             pass | 
 |         except OSError as why: | 
 |             errors.append((src, dst, str(why))) | 
 |  | 
 |     # Format errors from file copies. | 
 |     def format_error(error): | 
 |         if len(error) == 1: | 
 |             return "Error: {msg}".format(msg=str(error[0])) | 
 |         return "From: {src}\nTo:   {dst}\n{msg}" \ | 
 |                 .format(src=error[0], dst=error[1], msg=error[2]) | 
 |  | 
 |     errors = [] | 
 |     copy_tree(src, dst, ignore, errors) | 
 |     if errors: | 
 |         failures = "\n\n".join(format_error(error) for error in errors) | 
 |         parts = ("Some file copies failed:", "=" * 78, failures) | 
 |         msg = '\n'.join(parts) | 
 |         raise RuntimeError(msg) | 
 |  | 
 |     return copied_files | 
 |  | 
 |  | 
 | def WriteDepfile(depfile, stamp, dep_list): | 
 |     os.makedirs(os.path.dirname(depfile), exist_ok=True) | 
 |     # Paths in the depfile must be relative to the root build output directory, | 
 |     # which is the cwd that ninja invokes the script from. | 
 |     cwd = os.getcwd() | 
 |     relstamp = os.path.relpath(stamp, cwd) | 
 |     reldep_list = [os.path.relpath(d, cwd) for d in dep_list] | 
 |     # Depfile paths must use an escape sequence for space characters. | 
 |     reldep_list = [path.replace(" ", r"\ ") for path in reldep_list] | 
 |     with open(depfile, 'w') as f: | 
 |         print("{0}: {1}".format(relstamp, " ".join(reldep_list)), file=f) | 
 |  | 
 |  | 
 | def Main(argv): | 
 |     args = ParseArgs(argv) | 
 |     if not ValidateArgs(args): | 
 |         return -1 | 
 |  | 
 |     if args.exclude_patterns == None: | 
 |         copied_files = CopyTree(args.copy_from, args.to) | 
 |     else: | 
 |         patterns = args.exclude_patterns.split(',') | 
 |         copied_files = CopyTree(args.copy_from, | 
 |                                 args.to, | 
 |                                 ignore=shutil.ignore_patterns(*patterns)) | 
 |  | 
 |     if args.depfile and args.stamp: | 
 |         WriteDepfile(args.depfile, args.stamp, copied_files) | 
 |  | 
 |     if args.stamp: | 
 |         open(args.stamp, 'w').close() | 
 |  | 
 |     return 0 | 
 |  | 
 |  | 
 | if __name__ == '__main__': | 
 |     sys.exit(Main(sys.argv)) |