diff --git a/build/dart/copy_tree.gni b/build/dart/copy_tree.gni index 284b106f103..a17e52976af 100644 --- a/build/dart/copy_tree.gni +++ b/build/dart/copy_tree.gni @@ -10,11 +10,13 @@ _dart_root = rebase_path("../..") # Optional parameters: # exclude - A comma separated list that is passed to shutil.ignore_patterns() # in tools/copy_tree.py. -template("copy_tree") { +template("_copy_tree") { assert(defined(invoker.source), "copy_tree must define 'source'") assert(defined(invoker.dest), "copy_tree must define 'dest'") + assert(defined(invoker.inputs), "copy_tree must define 'inputs'") source = invoker.source dest = invoker.dest + inputs = invoker.inputs action(target_name) { if (defined(invoker.visibility)) { visibility = invoker.visibility @@ -25,18 +27,11 @@ template("copy_tree") { deps += invoker.deps } - depfile = "$target_gen_dir/$target_name.d" - stampfile = "$target_gen_dir/$target_name.stamp" - common_args = [ "--from", rebase_path(source), "--to", rebase_path(dest), - "--depfile", - rebase_path(depfile), - "--stamp", - rebase_path(stampfile), ] if (defined(invoker.exclude)) { common_args += [ @@ -45,14 +40,33 @@ template("copy_tree") { ] } - outputs = [ stampfile ] + relative_files = rebase_path(inputs, rebase_path(source)) + + output_files = [] + foreach(input, relative_files) { + output_files += [ "$dest/$input" ] + } + + outputs = output_files script = "$_dart_root/tools/copy_tree.py" args = common_args } } -# DEPRECATED: This can be removed after the uses in the flutter/engine tree -# are migrated to use copy_tree(). +# copy_trees() arranges to invoke copy_tree.py only once to gather the list of +# input source files for every _copy_tree() target. It takes a list of scopes as +# a parameter. The scopes should contain the following mappings. +# +# target: The target name for the _copy_tree() target. +# visibility: The visibility for the _copy_tree() target. +# source: The source directory relative to this directory. +# dest: The destination directory for the _copy_tree() target. +# deps: Any deps needed for the _copy_tree() target. +# ignore_patterns: Patterns to ignore when walking the directory tree. +# This should be '{}' if nothing should be ignored. +# +# copy_trees() will then make sure each invocation of _copy_tree() has the +# correct 'inputs' parameter template("copy_trees") { assert(defined(invoker.sources), "$target_name must define 'source'") sources = invoker.sources @@ -64,12 +78,21 @@ template("copy_trees") { ] } + # Evaluate script output as GN, producing a scope containing a single value + # "sources" + copy_tree_inputs_scope = exec_script("$_dart_root/tools/copy_tree.py", + [ "--gn" ] + copy_tree_source_paths, + "scope") + # A list of lists of input source files for copy_tree. + copy_tree_inputs = copy_tree_inputs_scope.sources + copy_tree_inputs_index = 0 foreach(copy_tree_spec, sources) { - copy_tree(copy_tree_spec.target) { + _copy_tree(copy_tree_spec.target) { visibility = copy_tree_spec.visibility source = copy_tree_spec.source dest = copy_tree_spec.dest + inputs = copy_tree_inputs[copy_tree_inputs_index] if (defined(copy_tree_spec.deps)) { deps = copy_tree_spec.deps } @@ -77,5 +100,6 @@ template("copy_trees") { exclude = copy_tree_spec.ignore_patterns } } + copy_tree_inputs_index = copy_tree_inputs_index + 1 } } diff --git a/runtime/observatory/BUILD.gn b/runtime/observatory/BUILD.gn index df4d91693c7..518b6322048 100644 --- a/runtime/observatory/BUILD.gn +++ b/runtime/observatory/BUILD.gn @@ -74,25 +74,39 @@ if (!is_debug) { observatory_ignore_patterns += [ "*.map" ] } -# The ignore_patterns entry in the scopes accepted by copy_tree() is a +# The ignore_patterns entry in the scopes accepted by copy_trees() is a # string of comma delimited patterns. observatory_ignore_string = "\$sdk" foreach(pattern, observatory_ignore_patterns) { observatory_ignore_string = "$observatory_ignore_string,$pattern" } -copy_tree("copy_web_package") { - visibility = [ ":deploy_observatory" ] - source = "web" - dest = "$target_out_dir/observatory/deployed/web" - exclude = observatory_ignore_string -} +copy_tree_specs = [] -copy_tree("copy_observatory_package") { - visibility = [ ":deploy_observatory" ] - source = "lib" - dest = "$target_out_dir/observatory/deployed/web/packages/observatory" - exclude = observatory_ignore_string +copy_tree_specs += [ + { + target = "copy_web_package" + visibility = [ ":deploy_observatory" ] + source = "web" + dest = "$target_out_dir/observatory/deployed/web" + ignore_patterns = observatory_ignore_string + }, +] + +copy_tree_specs += [ + { + target = "copy_observatory_package" + visibility = [ ":deploy_observatory" ] + source = "lib" + dest = "$target_out_dir/observatory/deployed/web/packages/observatory" + ignore_patterns = observatory_ignore_string + }, +] + +# This is not a rule, rather, it generates rules with names of the form: +# "copy_$package_package" for the packages in observatory_pub_packages. +copy_trees("copy_observatory_packages") { + sources = copy_tree_specs } copy("copy_main_dart_js") { diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn index ed3fcbf98c9..50fa5e0da5d 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn @@ -212,44 +212,66 @@ _full_sdk_libraries = [ # ] _platform_sdk_libraries = _full_sdk_libraries +# From here down to the copy_trees() invocation, we collect all the information +# about trees that need to be copied in the list of scopes, copy_tree_specs. +copy_tree_specs = [] + # This rule copies dartdoc templates to # bin/resources/dartdoc/templates -copy_tree("copy_dartdoc_templates") { - visibility = [ ":copy_dartdoc_files" ] - source = "../third_party/pkg/dartdoc/lib/templates" - dest = "$root_out_dir/$dart_sdk_output/bin/resources/dartdoc/templates" - exclude = "{}" -} +copy_tree_specs += [ + { + target = "copy_dartdoc_templates" + visibility = [ ":copy_dartdoc_files" ] + source = "../third_party/pkg/dartdoc/lib/templates" + dest = "$root_out_dir/$dart_sdk_output/bin/resources/dartdoc/templates" + ignore_patterns = "{}" + }, +] # This rule copies dartdoc resources to # bin/resources/dartdoc/resources -copy_tree("copy_dartdoc_resources") { - visibility = [ ":copy_dartdoc_files" ] - source = "../third_party/pkg/dartdoc/lib/resources" - dest = "$root_out_dir/$dart_sdk_output/bin/resources/dartdoc/resources" - exclude = "{}" -} +copy_tree_specs += [ + { + target = "copy_dartdoc_resources" + visibility = [ ":copy_dartdoc_files" ] + source = "../third_party/pkg/dartdoc/lib/resources" + dest = "$root_out_dir/$dart_sdk_output/bin/resources/dartdoc/resources" + ignore_patterns = "{}" + }, +] # This rule copies the pre-built DevTools application to # bin/resources/devtools/ -copy_tree("copy_prebuilt_devtools") { - visibility = [ ":create_common_sdk" ] - source = "../third_party/devtools/web" - dest = "$root_out_dir/$dart_sdk_output/bin/resources/devtools" - exclude = "{}" -} +copy_tree_specs += [ + { + target = "copy_prebuilt_devtools" + visibility = [ ":create_common_sdk" ] + source = "../third_party/devtools/web" + dest = "$root_out_dir/$dart_sdk_output/bin/resources/devtools" + ignore_patterns = "{}" + }, +] # This loop generates rules to copy libraries to lib/ foreach(library, _full_sdk_libraries) { - copy_tree("copy_${library}_library") { - visibility = [ - ":copy_full_sdk_libraries", - ":copy_platform_sdk_libraries", - ] - source = "lib/$library" - dest = "$root_out_dir/$dart_sdk_output/lib/$library" - exclude = "*.svn,doc,*.py,*.gypi,*.sh,.gitignore" - } + copy_tree_specs += [ + { + target = "copy_${library}_library" + visibility = [ + ":copy_full_sdk_libraries", + ":copy_platform_sdk_libraries", + ] + source = "lib/$library" + dest = "$root_out_dir/$dart_sdk_output/lib/$library" + ignore_patterns = "*.svn,doc,*.py,*.gypi,*.sh,.gitignore" + }, + ] +} + +# This generates targets for everything in copy_tree_specs. The targets have the +# same name as the "target" fields in the scopes of copy_tree_specs. +copy_trees("copy_trees") { + sources = copy_tree_specs } _has_dot_sym = !is_win && rebase_path(".") == rebase_path("//sdk") diff --git a/tools/copy_tree.py b/tools/copy_tree.py index 155ce490009..a3ef4c2ebdf 100755 --- a/tools/copy_tree.py +++ b/tools/copy_tree.py @@ -16,10 +16,6 @@ def ParseArgs(args): 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', @@ -28,16 +24,33 @@ def ParseArgs(args): parser.add_argument( '--from', '-f', dest="copy_from", type=str, help='Source directory') parser.add_argument( - '--stamp', - '-s', + '--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, - help='The path to a stamp file to output when finished.') + 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 @@ -47,10 +60,7 @@ def ValidateArgs(args): 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) @@ -70,7 +80,6 @@ def CopyTree(src, dst, ignore=None): 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))) @@ -97,18 +106,45 @@ def CopyTree(src, dst, ignore=None): msg = '\n'.join(parts) raise RuntimeError(msg) - return copied_files + +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 -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] - with open(depfile, 'w') as f: - print("{0}: {1}".format(relstamp, " ".join(reldep_list)), file=f) +# 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 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 def Main(argv): @@ -116,20 +152,16 @@ def Main(argv): if not ValidateArgs(args): return -1 + if args.gn: + SourcesToGN(args.gn_paths) + return 0 + if args.exclude_patterns == None: - copied_files = CopyTree(args.copy_from, args.to) + 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() - + CopyTree( + args.copy_from, args.to, ignore=shutil.ignore_patterns(*patterns)) return 0 diff --git a/utils/dartdev/BUILD.gn b/utils/dartdev/BUILD.gn index 338c04320c1..ad9756b2a8f 100644 --- a/utils/dartdev/BUILD.gn +++ b/utils/dartdev/BUILD.gn @@ -37,9 +37,14 @@ application_snapshot("generate_dartdev_snapshot") { output = "$root_gen_dir/dartdev.dart.snapshot" } -copy_tree("copy_prebuilt_devtools") { - visibility = [ ":dartdev" ] - source = "../../third_party/devtools/web" - dest = "$root_out_dir/devtools" - exclude = "{}" +copy_trees("copy_prebuilt_devtools") { + sources = [ + { + target = "copy_prebuilt_devtools" + visibility = [ ":dartdev" ] + source = "../../third_party/devtools/web" + dest = "$root_out_dir/devtools" + ignore_patterns = "{}" + }, + ] }