Skip to content

Commit f60d321

Browse files
zandersoCommit Queue
authored andcommitted
[gn] Deprecate copy_trees()
Part of flutter/flutter#144430 Previously, this code did backflips to accomplish two goals 1. Collect the paths of all files that would be copied from one place to another after applying regex filters so that they could be listed as the "inputs" to a GN action. 2. Arrange so that the python script doing the above would only be invoked once during GN to reduce the cost of calling out to python. However, this is exactly the use-case for the "depfile" parameter to a GN action. Instead of running the script during GN to populate the "inputs" list, when we run the copy_tree.py script, we can instead ask it to generate a depfile to collect all the input files that were actually copied after applying the regex filter. Using that, we don't have to run the python script at all during GN. TEST=it builds Change-Id: I41a251ce4659119cdc3997bb2d6fc7ee0831bb6d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/356481 Reviewed-by: Siva Annamalai <[email protected]> Commit-Queue: Zach Anderson <[email protected]> Reviewed-by: Alexander Aprelev <[email protected]>
1 parent 9efa956 commit f60d321

File tree

5 files changed

+88
-185
lines changed

5 files changed

+88
-185
lines changed

build/dart/copy_tree.gni

Lines changed: 12 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,11 @@ _dart_root = rebase_path("../..")
1010
# Optional parameters:
1111
# exclude - A comma separated list that is passed to shutil.ignore_patterns()
1212
# in tools/copy_tree.py.
13-
template("_copy_tree") {
13+
template("copy_tree") {
1414
assert(defined(invoker.source), "copy_tree must define 'source'")
1515
assert(defined(invoker.dest), "copy_tree must define 'dest'")
16-
assert(defined(invoker.inputs), "copy_tree must define 'inputs'")
1716
source = invoker.source
1817
dest = invoker.dest
19-
inputs = invoker.inputs
2018
action(target_name) {
2119
if (defined(invoker.visibility)) {
2220
visibility = invoker.visibility
@@ -27,11 +25,18 @@ template("_copy_tree") {
2725
deps += invoker.deps
2826
}
2927

28+
depfile = "$target_gen_dir/$target_name.d"
29+
stampfile = "$target_gen_dir/$target_name.stamp"
30+
3031
common_args = [
3132
"--from",
3233
rebase_path(source),
3334
"--to",
3435
rebase_path(dest),
36+
"--depfile",
37+
rebase_path(depfile),
38+
"--stamp",
39+
rebase_path(stampfile),
3540
]
3641
if (defined(invoker.exclude)) {
3742
common_args += [
@@ -40,33 +45,14 @@ template("_copy_tree") {
4045
]
4146
}
4247

43-
relative_files = rebase_path(inputs, rebase_path(source))
44-
45-
output_files = []
46-
foreach(input, relative_files) {
47-
output_files += [ "$dest/$input" ]
48-
}
49-
50-
outputs = output_files
48+
outputs = [ stampfile ]
5149
script = "$_dart_root/tools/copy_tree.py"
5250
args = common_args
5351
}
5452
}
5553

56-
# copy_trees() arranges to invoke copy_tree.py only once to gather the list of
57-
# input source files for every _copy_tree() target. It takes a list of scopes as
58-
# a parameter. The scopes should contain the following mappings.
59-
#
60-
# target: The target name for the _copy_tree() target.
61-
# visibility: The visibility for the _copy_tree() target.
62-
# source: The source directory relative to this directory.
63-
# dest: The destination directory for the _copy_tree() target.
64-
# deps: Any deps needed for the _copy_tree() target.
65-
# ignore_patterns: Patterns to ignore when walking the directory tree.
66-
# This should be '{}' if nothing should be ignored.
67-
#
68-
# copy_trees() will then make sure each invocation of _copy_tree() has the
69-
# correct 'inputs' parameter
54+
# DEPRECATED: This can be removed after the uses in the flutter/engine tree
55+
# are migrated to use copy_tree().
7056
template("copy_trees") {
7157
assert(defined(invoker.sources), "$target_name must define 'source'")
7258
sources = invoker.sources
@@ -78,28 +64,18 @@ template("copy_trees") {
7864
]
7965
}
8066

81-
# Evaluate script output as GN, producing a scope containing a single value
82-
# "sources"
83-
copy_tree_inputs_scope = exec_script("$_dart_root/tools/copy_tree.py",
84-
[ "--gn" ] + copy_tree_source_paths,
85-
"scope")
86-
8767
# A list of lists of input source files for copy_tree.
88-
copy_tree_inputs = copy_tree_inputs_scope.sources
89-
copy_tree_inputs_index = 0
9068
foreach(copy_tree_spec, sources) {
91-
_copy_tree(copy_tree_spec.target) {
69+
copy_tree(copy_tree_spec.target) {
9270
visibility = copy_tree_spec.visibility
9371
source = copy_tree_spec.source
9472
dest = copy_tree_spec.dest
95-
inputs = copy_tree_inputs[copy_tree_inputs_index]
9673
if (defined(copy_tree_spec.deps)) {
9774
deps = copy_tree_spec.deps
9875
}
9976
if (copy_tree_spec.ignore_patterns != "{}") {
10077
exclude = copy_tree_spec.ignore_patterns
10178
}
10279
}
103-
copy_tree_inputs_index = copy_tree_inputs_index + 1
10480
}
10581
}

runtime/observatory/BUILD.gn

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -74,39 +74,25 @@ if (!is_debug) {
7474
observatory_ignore_patterns += [ "*.map" ]
7575
}
7676

77-
# The ignore_patterns entry in the scopes accepted by copy_trees() is a
77+
# The ignore_patterns entry in the scopes accepted by copy_tree() is a
7878
# string of comma delimited patterns.
7979
observatory_ignore_string = "\$sdk"
8080
foreach(pattern, observatory_ignore_patterns) {
8181
observatory_ignore_string = "$observatory_ignore_string,$pattern"
8282
}
8383

84-
copy_tree_specs = []
85-
86-
copy_tree_specs += [
87-
{
88-
target = "copy_web_package"
89-
visibility = [ ":deploy_observatory" ]
90-
source = "web"
91-
dest = "$target_out_dir/observatory/deployed/web"
92-
ignore_patterns = observatory_ignore_string
93-
},
94-
]
95-
96-
copy_tree_specs += [
97-
{
98-
target = "copy_observatory_package"
99-
visibility = [ ":deploy_observatory" ]
100-
source = "lib"
101-
dest = "$target_out_dir/observatory/deployed/web/packages/observatory"
102-
ignore_patterns = observatory_ignore_string
103-
},
104-
]
84+
copy_tree("copy_web_package") {
85+
visibility = [ ":deploy_observatory" ]
86+
source = "web"
87+
dest = "$target_out_dir/observatory/deployed/web"
88+
exclude = observatory_ignore_string
89+
}
10590

106-
# This is not a rule, rather, it generates rules with names of the form:
107-
# "copy_$package_package" for the packages in observatory_pub_packages.
108-
copy_trees("copy_observatory_packages") {
109-
sources = copy_tree_specs
91+
copy_tree("copy_observatory_package") {
92+
visibility = [ ":deploy_observatory" ]
93+
source = "lib"
94+
dest = "$target_out_dir/observatory/deployed/web/packages/observatory"
95+
exclude = observatory_ignore_string
11096
}
11197

11298
copy("copy_main_dart_js") {

sdk/BUILD.gn

Lines changed: 27 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -212,66 +212,44 @@ _full_sdk_libraries = [
212212
# ]
213213
_platform_sdk_libraries = _full_sdk_libraries
214214

215-
# From here down to the copy_trees() invocation, we collect all the information
216-
# about trees that need to be copied in the list of scopes, copy_tree_specs.
217-
copy_tree_specs = []
218-
219215
# This rule copies dartdoc templates to
220216
# bin/resources/dartdoc/templates
221-
copy_tree_specs += [
222-
{
223-
target = "copy_dartdoc_templates"
224-
visibility = [ ":copy_dartdoc_files" ]
225-
source = "../third_party/pkg/dartdoc/lib/templates"
226-
dest = "$root_out_dir/$dart_sdk_output/bin/resources/dartdoc/templates"
227-
ignore_patterns = "{}"
228-
},
229-
]
217+
copy_tree("copy_dartdoc_templates") {
218+
visibility = [ ":copy_dartdoc_files" ]
219+
source = "../third_party/pkg/dartdoc/lib/templates"
220+
dest = "$root_out_dir/$dart_sdk_output/bin/resources/dartdoc/templates"
221+
exclude = "{}"
222+
}
230223

231224
# This rule copies dartdoc resources to
232225
# bin/resources/dartdoc/resources
233-
copy_tree_specs += [
234-
{
235-
target = "copy_dartdoc_resources"
236-
visibility = [ ":copy_dartdoc_files" ]
237-
source = "../third_party/pkg/dartdoc/lib/resources"
238-
dest = "$root_out_dir/$dart_sdk_output/bin/resources/dartdoc/resources"
239-
ignore_patterns = "{}"
240-
},
241-
]
226+
copy_tree("copy_dartdoc_resources") {
227+
visibility = [ ":copy_dartdoc_files" ]
228+
source = "../third_party/pkg/dartdoc/lib/resources"
229+
dest = "$root_out_dir/$dart_sdk_output/bin/resources/dartdoc/resources"
230+
exclude = "{}"
231+
}
242232

243233
# This rule copies the pre-built DevTools application to
244234
# bin/resources/devtools/
245-
copy_tree_specs += [
246-
{
247-
target = "copy_prebuilt_devtools"
248-
visibility = [ ":create_common_sdk" ]
249-
source = "../third_party/devtools/web"
250-
dest = "$root_out_dir/$dart_sdk_output/bin/resources/devtools"
251-
ignore_patterns = "{}"
252-
},
253-
]
235+
copy_tree("copy_prebuilt_devtools") {
236+
visibility = [ ":create_common_sdk" ]
237+
source = "../third_party/devtools/web"
238+
dest = "$root_out_dir/$dart_sdk_output/bin/resources/devtools"
239+
exclude = "{}"
240+
}
254241

255242
# This loop generates rules to copy libraries to lib/
256243
foreach(library, _full_sdk_libraries) {
257-
copy_tree_specs += [
258-
{
259-
target = "copy_${library}_library"
260-
visibility = [
261-
":copy_full_sdk_libraries",
262-
":copy_platform_sdk_libraries",
263-
]
264-
source = "lib/$library"
265-
dest = "$root_out_dir/$dart_sdk_output/lib/$library"
266-
ignore_patterns = "*.svn,doc,*.py,*.gypi,*.sh,.gitignore"
267-
},
268-
]
269-
}
270-
271-
# This generates targets for everything in copy_tree_specs. The targets have the
272-
# same name as the "target" fields in the scopes of copy_tree_specs.
273-
copy_trees("copy_trees") {
274-
sources = copy_tree_specs
244+
copy_tree("copy_${library}_library") {
245+
visibility = [
246+
":copy_full_sdk_libraries",
247+
":copy_platform_sdk_libraries",
248+
]
249+
source = "lib/$library"
250+
dest = "$root_out_dir/$dart_sdk_output/lib/$library"
251+
exclude = "*.svn,doc,*.py,*.gypi,*.sh,.gitignore"
252+
}
275253
}
276254

277255
_has_dot_sym = !is_win && rebase_path(".") == rebase_path("//sdk")

tools/copy_tree.py

Lines changed: 32 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ def ParseArgs(args):
1616
parser = argparse.ArgumentParser(
1717
description='A script to copy a file tree somewhere')
1818

19+
parser.add_argument('--depfile',
20+
'-d',
21+
type=str,
22+
help='Path to a depfile to write when copying.')
1923
parser.add_argument(
2024
'--exclude_patterns',
2125
'-e',
@@ -24,33 +28,16 @@ def ParseArgs(args):
2428
parser.add_argument(
2529
'--from', '-f', dest="copy_from", type=str, help='Source directory')
2630
parser.add_argument(
27-
'--gn',
28-
'-g',
29-
dest='gn',
30-
default=False,
31-
action='store_true',
32-
help='Output for GN for multiple sources, but do not copy anything.')
33-
parser.add_argument(
34-
'gn_paths',
35-
metavar='name path ignore_pattern',
31+
'--stamp',
32+
'-s',
3633
type=str,
37-
nargs='*',
38-
default=None,
39-
help='When --gn is given, the specification of source paths to list.')
34+
help='The path to a stamp file to output when finished.')
4035
parser.add_argument('--to', '-t', type=str, help='Destination directory')
4136

4237
return parser.parse_args(args)
4338

4439

4540
def ValidateArgs(args):
46-
if args.gn:
47-
if args.exclude_patterns or args.copy_from or args.to:
48-
print("--gn mode does not accept other switches")
49-
return False
50-
if not args.gn_paths:
51-
print("--gn mode requires a list of source specifications")
52-
return False
53-
return True
5441
if not args.copy_from or not os.path.isdir(args.copy_from):
5542
print("--from argument must refer to a directory")
5643
return False
@@ -60,7 +47,10 @@ def ValidateArgs(args):
6047
return True
6148

6249

50+
# Returns a list of the files under 'src' that were copied.
6351
def CopyTree(src, dst, ignore=None):
52+
copied_files = []
53+
6454
# Recursive helper method to collect errors but keep processing.
6555
def copy_tree(src, dst, ignore, errors):
6656
names = os.listdir(src)
@@ -80,6 +70,7 @@ def copy_tree(src, dst, ignore, errors):
8070
if os.path.isdir(srcname):
8171
copy_tree(srcname, dstname, ignore, errors)
8272
else:
73+
copied_files.append(srcname)
8374
shutil.copy(srcname, dstname)
8475
except (IOError, os.error) as why:
8576
errors.append((srcname, dstname, str(why)))
@@ -106,62 +97,39 @@ def format_error(error):
10697
msg = '\n'.join(parts)
10798
raise RuntimeError(msg)
10899

109-
110-
def ListTree(src, ignore=None):
111-
names = os.listdir(src)
112-
if ignore is not None:
113-
ignored_names = ignore(src, names)
114-
else:
115-
ignored_names = set()
116-
117-
srcnames = []
118-
for name in names:
119-
if name in ignored_names:
120-
continue
121-
srcname = os.path.join(src, name)
122-
if os.path.isdir(srcname):
123-
srcnames.extend(ListTree(srcname, ignore))
124-
else:
125-
srcnames.append(srcname)
126-
return srcnames
100+
return copied_files
127101

128102

129-
# source_dirs is organized such that sources_dirs[n] is the path for the source
130-
# directory, and source_dirs[n+1] is a list of ignore patterns.
131-
def SourcesToGN(source_dirs):
132-
if len(source_dirs) % 2 != 0:
133-
print("--gn list length should be a multiple of 2.")
134-
return False
135-
data = []
136-
for i in range(0, len(source_dirs), 2):
137-
path = source_dirs[i]
138-
ignores = source_dirs[i + 1]
139-
if ignores in ["{}"]:
140-
sources = ListTree(path)
141-
else:
142-
patterns = ignores.split(',')
143-
sources = ListTree(path, ignore=shutil.ignore_patterns(*patterns))
144-
data.append(sources)
145-
scope_data = {"sources": data}
146-
print(gn_helpers.ToGNString(scope_data))
147-
return True
103+
def WriteDepfile(depfile, stamp, dep_list):
104+
os.makedirs(os.path.dirname(depfile), exist_ok=True)
105+
# Paths in the depfile must be relative to the root build output directory,
106+
# which is the cwd that ninja invokes the script from.
107+
cwd = os.getcwd()
108+
relstamp = os.path.relpath(stamp, cwd)
109+
reldep_list = [os.path.relpath(d, cwd) for d in dep_list]
110+
with open(depfile, 'w') as f:
111+
print("{0}: {1}".format(relstamp, " ".join(reldep_list)), file=f)
148112

149113

150114
def Main(argv):
151115
args = ParseArgs(argv)
152116
if not ValidateArgs(args):
153117
return -1
154118

155-
if args.gn:
156-
SourcesToGN(args.gn_paths)
157-
return 0
158-
159119
if args.exclude_patterns == None:
160-
CopyTree(args.copy_from, args.to)
120+
copied_files = CopyTree(args.copy_from, args.to)
161121
else:
162122
patterns = args.exclude_patterns.split(',')
163-
CopyTree(
164-
args.copy_from, args.to, ignore=shutil.ignore_patterns(*patterns))
123+
copied_files = CopyTree(args.copy_from,
124+
args.to,
125+
ignore=shutil.ignore_patterns(*patterns))
126+
127+
if args.depfile and args.stamp:
128+
WriteDepfile(args.depfile, args.stamp, copied_files)
129+
130+
if args.stamp:
131+
open(args.stamp, 'w').close()
132+
165133
return 0
166134

167135

0 commit comments

Comments
 (0)