blob: 5d727504eba8ab42a372aadf100a627d415fec05 [file] [log] [blame]
#!/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
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('--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)
def ValidateArgs(args):
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
return True
def CopyTree(src, dst, ignore=None):
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)
errors = []
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):
CopyTree(srcname, dstname, ignore)
else:
shutil.copy(srcname, dstname)
except (IOError, os.error) as why:
errors.append((srcname, dstname, str(why)))
# catch the Error from the recursive CopyTree so that we can
# continue with other files
except Exception as err:
errors.extend(err.args[0])
try:
shutil.copystat(src, dst)
except WindowsError:
# can't copy file access times on Windows
pass
except OSError as why:
errors.extend((src, dst, str(why)))
if errors:
raise Error(errors)
def ListTree(src, ignore=None):
names = os.listdir(src)
if ignore is not None:
ignored_names = ignore(src, names)
else:
ignored_names = set()
srcnames = []
for name in names:
if name in ignored_names:
continue
srcname = os.path.join(src, name)
if os.path.isdir(srcname):
srcnames.extend(ListTree(srcname, ignore))
else:
srcnames.append(srcname)
return srcnames
# 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):
if len(source_dirs) % 2 != 0:
print "--gn list length should be a multiple of 2."
return False
data = []
for i in xrange(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
def Main(argv):
args = ParseArgs(argv)
if not ValidateArgs(args):
return -1
if args.gn:
SourcesToGN(args.gn_paths)
return 0
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
if __name__ == '__main__':
sys.exit(Main(sys.argv))