| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 2 # Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| 3 # for details. All rights reserved. Use of this source code is governed by a | 3 # for details. All rights reserved. Use of this source code is governed by a |
| 4 # BSD-style license that can be found in the LICENSE file. | 4 # BSD-style license that can be found in the LICENSE file. |
| 5 | 5 |
| 6 import argparse | 6 import argparse |
| 7 import gn_helpers |
| 7 import os | 8 import os |
| 8 import re | 9 import re |
| 9 import shutil | 10 import shutil |
| 10 import sys | 11 import sys |
| 11 | 12 |
| 12 def ParseArgs(args): | 13 def ParseArgs(args): |
| 13 args = args[1:] | 14 args = args[1:] |
| 14 parser = argparse.ArgumentParser( | 15 parser = argparse.ArgumentParser( |
| 15 description='A script to copy a file tree somewhere') | 16 description='A script to copy a file tree somewhere') |
| 16 | 17 |
| 17 parser.add_argument('--dry-run', '-d', | |
| 18 dest='dryrun', | |
| 19 default=False, | |
| 20 action='store_true', | |
| 21 help='Print the paths of the source files, but do not copy anything.') | |
| 22 parser.add_argument('--exclude_patterns', '-e', | 18 parser.add_argument('--exclude_patterns', '-e', |
| 23 type=str, | 19 type=str, |
| 24 help='Patterns to exclude [passed to shutil.copytree]') | 20 help='Patterns to exclude [passed to shutil.copytree]') |
| 25 parser.add_argument('--from', '-f', | 21 parser.add_argument('--from', '-f', |
| 26 dest="copy_from", | 22 dest="copy_from", |
| 27 type=str, | 23 type=str, |
| 28 required=True, | |
| 29 help='Source directory') | 24 help='Source directory') |
| 25 parser.add_argument('--gn', '-g', |
| 26 dest='gn', |
| 27 default=False, |
| 28 action='store_true', |
| 29 help='Output for GN for multiple sources, but do not copy anything.') |
| 30 parser.add_argument('gn_paths', |
| 31 metavar='name path ignore_pattern', |
| 32 type=str, |
| 33 nargs='*', |
| 34 default=None, |
| 35 help='When --gn is given, the specification of source paths to list.') |
| 30 parser.add_argument('--to', '-t', | 36 parser.add_argument('--to', '-t', |
| 31 type=str, | 37 type=str, |
| 32 required=True, | |
| 33 help='Destination directory') | 38 help='Destination directory') |
| 34 | 39 |
| 35 return parser.parse_args(args) | 40 return parser.parse_args(args) |
| 36 | 41 |
| 37 | 42 |
| 38 def ValidateArgs(args): | 43 def ValidateArgs(args): |
| 39 if not os.path.isdir(args.copy_from): | 44 if args.gn: |
| 45 if args.exclude_patterns or args.copy_from or args.to: |
| 46 print "--gn mode does not accept other switches" |
| 47 return False |
| 48 if not args.gn_paths: |
| 49 print "--gn mode requires a list of source specifications" |
| 50 return False |
| 51 return True |
| 52 if not args.copy_from or not os.path.isdir(args.copy_from): |
| 40 print "--from argument must refer to a directory" | 53 print "--from argument must refer to a directory" |
| 41 return False | 54 return False |
| 55 if not args.to: |
| 56 print "--to is required" |
| 57 return False |
| 42 return True | 58 return True |
| 43 | 59 |
| 44 | 60 |
| 45 def CopyTree(src, dst, dryrun=False, symlinks=False, ignore=None): | 61 def CopyTree(src, dst, ignore=None): |
| 46 names = os.listdir(src) | 62 names = os.listdir(src) |
| 47 if ignore is not None: | 63 if ignore is not None: |
| 48 ignored_names = ignore(src, names) | 64 ignored_names = ignore(src, names) |
| 49 else: | 65 else: |
| 50 ignored_names = set() | 66 ignored_names = set() |
| 51 | 67 |
| 52 if not dryrun: | 68 os.makedirs(dst) |
| 53 os.makedirs(dst) | |
| 54 errors = [] | 69 errors = [] |
| 55 for name in names: | 70 for name in names: |
| 56 if name in ignored_names: | 71 if name in ignored_names: |
| 57 continue | 72 continue |
| 58 srcname = os.path.join(src, name) | 73 srcname = os.path.join(src, name) |
| 59 dstname = os.path.join(dst, name) | 74 dstname = os.path.join(dst, name) |
| 60 try: | 75 try: |
| 61 if os.path.isdir(srcname): | 76 if os.path.isdir(srcname): |
| 62 CopyTree(srcname, dstname, dryrun, symlinks, ignore) | 77 CopyTree(srcname, dstname, ignore) |
| 63 else: | 78 else: |
| 64 if dryrun: | 79 shutil.copy(srcname, dstname) |
| 65 print srcname | |
| 66 else: | |
| 67 shutil.copy(srcname, dstname) | |
| 68 except (IOError, os.error) as why: | 80 except (IOError, os.error) as why: |
| 69 errors.append((srcname, dstname, str(why))) | 81 errors.append((srcname, dstname, str(why))) |
| 70 # catch the Error from the recursive CopyTree so that we can | 82 # catch the Error from the recursive CopyTree so that we can |
| 71 # continue with other files | 83 # continue with other files |
| 72 except Error as err: | 84 except Error as err: |
| 73 errors.extend(err.args[0]) | 85 errors.extend(err.args[0]) |
| 74 try: | 86 try: |
| 75 if not dryrun: | 87 shutil.copystat(src, dst) |
| 76 shutil.copystat(src, dst) | |
| 77 except WindowsError: | 88 except WindowsError: |
| 78 # can't copy file access times on Windows | 89 # can't copy file access times on Windows |
| 79 pass | 90 pass |
| 80 except OSError as why: | 91 except OSError as why: |
| 81 errors.extend((src, dst, str(why))) | 92 errors.extend((src, dst, str(why))) |
| 82 if errors: | 93 if errors: |
| 83 raise Error(errors) | 94 raise Error(errors) |
| 84 | 95 |
| 85 | 96 |
| 97 def ListTree(src, ignore=None): |
| 98 names = os.listdir(src) |
| 99 if ignore is not None: |
| 100 ignored_names = ignore(src, names) |
| 101 else: |
| 102 ignored_names = set() |
| 103 |
| 104 srcnames = [] |
| 105 for name in names: |
| 106 if name in ignored_names: |
| 107 continue |
| 108 srcname = os.path.join(src, name) |
| 109 if os.path.isdir(srcname): |
| 110 srcnames.extend(ListTree(srcname, ignore)) |
| 111 else: |
| 112 srcnames.append(srcname) |
| 113 return srcnames |
| 114 |
| 115 |
| 116 # source_dirs is organized such that sources_dirs[n] is the path for the source |
| 117 # directory, and source_dirs[n+1] is a list of ignore patterns. |
| 118 def SourcesToGN(source_dirs): |
| 119 if len(source_dirs) % 2 != 0: |
| 120 print "--gn list length should be a multiple of 2." |
| 121 return False |
| 122 data = [] |
| 123 for i in xrange(0, len(source_dirs), 2): |
| 124 path = source_dirs[i] |
| 125 ignores = source_dirs[i + 1] |
| 126 if ignores in ["{}"]: |
| 127 sources = ListTree(path) |
| 128 else: |
| 129 patterns = ignores.split(',') |
| 130 sources = ListTree(path, ignore=shutil.ignore_patterns(*patterns)) |
| 131 data.append(sources) |
| 132 scope_data = {"sources": data} |
| 133 print gn_helpers.ToGNString(scope_data) |
| 134 return True |
| 135 |
| 136 |
| 86 def Main(argv): | 137 def Main(argv): |
| 87 args = ParseArgs(argv) | 138 args = ParseArgs(argv) |
| 88 if not ValidateArgs(args): | 139 if not ValidateArgs(args): |
| 89 return -1 | 140 return -1 |
| 90 | 141 |
| 91 if os.path.exists(args.to) and not args.dryrun: | 142 if args.gn: |
| 143 SourcesToGN(args.gn_paths) |
| 144 return 0 |
| 145 |
| 146 if os.path.exists(args.to): |
| 92 shutil.rmtree(args.to) | 147 shutil.rmtree(args.to) |
| 93 if args.exclude_patterns == None: | 148 if args.exclude_patterns == None: |
| 94 CopyTree(args.copy_from, args.to, dryrun=args.dryrun) | 149 CopyTree(args.copy_from, args.to) |
| 95 else: | 150 else: |
| 96 patterns = args.exclude_patterns.split(',') | 151 patterns = args.exclude_patterns.split(',') |
| 97 CopyTree(args.copy_from, args.to, dryrun=args.dryrun, | 152 CopyTree(args.copy_from, args.to, ignore=shutil.ignore_patterns(*patterns)) |
| 98 ignore=shutil.ignore_patterns(*patterns)) | |
| 99 return 0 | 153 return 0 |
| 100 | 154 |
| 101 | 155 |
| 102 if __name__ == '__main__': | 156 if __name__ == '__main__': |
| 103 sys.exit(Main(sys.argv)) | 157 sys.exit(Main(sys.argv)) |
| OLD | NEW |