2017-04-19 16:00:12 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# 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
|
2017-08-09 18:13:59 +00:00
|
|
|
import gn_helpers
|
2017-04-19 16:00:12 +00:00
|
|
|
import os
|
|
|
|
import re
|
|
|
|
import shutil
|
|
|
|
import sys
|
|
|
|
|
2019-08-05 20:34:31 +00:00
|
|
|
|
2017-04-19 16:00:12 +00:00
|
|
|
def ParseArgs(args):
|
2019-08-05 20:34:31 +00:00
|
|
|
args = args[1:]
|
|
|
|
parser = argparse.ArgumentParser(
|
|
|
|
description='A script to copy a file tree somewhere')
|
|
|
|
|
|
|
|
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(
|
|
|
|
'--gn',
|
|
|
|
'-g',
|
|
|
|
dest='gn',
|
|
|
|
default=False,
|
|
|
|
action='store_true',
|
|
|
|
help='Output for GN for multiple sources, but do not copy anything.')
|
|
|
|
parser.add_argument(
|
|
|
|
'gn_paths',
|
|
|
|
metavar='name path ignore_pattern',
|
|
|
|
type=str,
|
|
|
|
nargs='*',
|
|
|
|
default=None,
|
|
|
|
help='When --gn is given, the specification of source paths to list.')
|
|
|
|
parser.add_argument('--to', '-t', type=str, help='Destination directory')
|
|
|
|
|
|
|
|
return parser.parse_args(args)
|
2017-04-19 16:00:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
def ValidateArgs(args):
|
2019-08-05 20:34:31 +00:00
|
|
|
if args.gn:
|
|
|
|
if args.exclude_patterns or args.copy_from or args.to:
|
|
|
|
print("--gn mode does not accept other switches")
|
|
|
|
return False
|
|
|
|
if not args.gn_paths:
|
|
|
|
print("--gn mode requires a list of source specifications")
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
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
|
2017-08-09 18:13:59 +00:00
|
|
|
return True
|
2017-04-19 16:00:12 +00:00
|
|
|
|
|
|
|
|
2017-08-09 18:13:59 +00:00
|
|
|
def CopyTree(src, dst, ignore=None):
|
2019-08-05 20:34:31 +00:00
|
|
|
# Recusive 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:
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
|
|
def ListTree(src, ignore=None):
|
2019-08-02 18:05:08 +00:00
|
|
|
names = os.listdir(src)
|
|
|
|
if ignore is not None:
|
2019-08-05 20:34:31 +00:00
|
|
|
ignored_names = ignore(src, names)
|
2019-08-02 18:05:08 +00:00
|
|
|
else:
|
2019-08-05 20:34:31 +00:00
|
|
|
ignored_names = set()
|
2017-05-11 16:46:13 +00:00
|
|
|
|
2019-08-05 20:34:31 +00:00
|
|
|
srcnames = []
|
2019-08-02 18:05:08 +00:00
|
|
|
for name in names:
|
2019-08-05 20:34:31 +00:00
|
|
|
if name in ignored_names:
|
|
|
|
continue
|
|
|
|
srcname = os.path.join(src, name)
|
2019-08-02 18:05:08 +00:00
|
|
|
if os.path.isdir(srcname):
|
2019-08-05 20:34:31 +00:00
|
|
|
srcnames.extend(ListTree(srcname, ignore))
|
2019-08-02 18:05:08 +00:00
|
|
|
else:
|
2019-08-05 20:34:31 +00:00
|
|
|
srcnames.append(srcname)
|
|
|
|
return srcnames
|
2017-08-09 18:13:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
# source_dirs is organized such that sources_dirs[n] is the path for the source
|
|
|
|
# directory, and source_dirs[n+1] is a list of ignore patterns.
|
|
|
|
def SourcesToGN(source_dirs):
|
2019-08-05 20:34:31 +00:00
|
|
|
if len(source_dirs) % 2 != 0:
|
|
|
|
print("--gn list length should be a multiple of 2.")
|
|
|
|
return False
|
|
|
|
data = []
|
|
|
|
for i in range(0, len(source_dirs), 2):
|
|
|
|
path = source_dirs[i]
|
|
|
|
ignores = source_dirs[i + 1]
|
|
|
|
if ignores in ["{}"]:
|
|
|
|
sources = ListTree(path)
|
|
|
|
else:
|
|
|
|
patterns = ignores.split(',')
|
|
|
|
sources = ListTree(path, ignore=shutil.ignore_patterns(*patterns))
|
|
|
|
data.append(sources)
|
|
|
|
scope_data = {"sources": data}
|
|
|
|
print(gn_helpers.ToGNString(scope_data))
|
|
|
|
return True
|
2017-08-09 18:13:59 +00:00
|
|
|
|
|
|
|
|
2017-04-19 16:00:12 +00:00
|
|
|
def Main(argv):
|
2019-08-05 20:34:31 +00:00
|
|
|
args = ParseArgs(argv)
|
|
|
|
if not ValidateArgs(args):
|
|
|
|
return -1
|
2017-05-11 16:46:13 +00:00
|
|
|
|
2019-08-05 20:34:31 +00:00
|
|
|
if args.gn:
|
|
|
|
SourcesToGN(args.gn_paths)
|
|
|
|
return 0
|
2017-08-09 18:13:59 +00:00
|
|
|
|
2019-08-05 20:34:31 +00:00
|
|
|
if args.exclude_patterns == None:
|
|
|
|
CopyTree(args.copy_from, args.to)
|
|
|
|
else:
|
|
|
|
patterns = args.exclude_patterns.split(',')
|
|
|
|
CopyTree(
|
|
|
|
args.copy_from, args.to, ignore=shutil.ignore_patterns(*patterns))
|
|
|
|
return 0
|
2017-04-19 16:00:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2019-08-05 20:34:31 +00:00
|
|
|
sys.exit(Main(sys.argv))
|