1# Copyright 2021 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14
15import("//build_overrides/pigweed.gni")
16
17import("$dir_pw_build/python_action.gni")
18
19# Mirrors a directory structure to the output directory.
20#
21# This is similar to a GN copy target, with some differences:
22#
23#   - The outputs list is generated by the template based on the source_root and
24#     directory arguments, rather than using source expansion.
25#   - The source_root argument can be used to trim prefixes from source files.
26#   - pw_mirror_tree uses hard links instead of copies for efficiency.
27#
28# Args:
29#
30#   directory: Output directory for the files.
31#   sources: List of files to mirror to the output directory.
32#   source_root: Root path for sources; defaults to ".".
33#   path_data_keys: GN metadata data_keys from which to extract file or
34#       directory paths to add to the list of sources.
35#
36template("pw_mirror_tree") {
37  assert(defined(invoker.sources) || defined(invoker.path_data_keys),
38         "At least one of 'sources' or 'path_data_keys' must be provided")
39  assert(defined(invoker.directory) && invoker.directory != "",
40         "The output path must be specified as 'directory'")
41
42  if (defined(invoker.source_root)) {
43    _root = invoker.source_root
44  } else {
45    _root = "."
46  }
47
48  _args = [
49    "--source-root",
50    rebase_path(_root),
51    "--directory",
52    rebase_path(invoker.directory),
53  ]
54
55  _deps = []
56  if (defined(invoker.deps)) {
57    _deps += invoker.deps
58  }
59
60  _public_deps = []
61  if (defined(invoker.public_deps)) {
62    _public_deps += invoker.public_deps
63  }
64
65  if (defined(invoker.path_data_keys)) {
66    generated_file("$target_name._path_list") {
67      data_keys = invoker.path_data_keys
68      rebase = root_build_dir
69      outputs = [ "$target_gen_dir/$target_name.txt" ]
70      deps = _deps + _public_deps
71
72      assert(deps != [],
73             "'path_data_keys' requires at least one dependency in 'deps'")
74    }
75
76    _deps += [ ":$target_name._path_list" ]
77    _args += [ "--path-file" ] +
78             rebase_path(get_target_outputs(":$target_name._path_list"))
79  }
80
81  pw_python_action(target_name) {
82    script = "$dir_pw_build/py/pw_build/mirror_tree.py"
83    args = _args
84
85    outputs = []
86
87    if (defined(invoker.sources)) {
88      args += rebase_path(invoker.sources)
89
90      foreach(path, rebase_path(invoker.sources, _root)) {
91        outputs += [ "${invoker.directory}/$path" ]
92      }
93    }
94
95    # If path_data_keys is used, the outputs may be unknown.
96    if (outputs == []) {
97      stamp = true
98    }
99
100    deps = _deps
101    public_deps = _public_deps
102
103    _ignore_args = [
104      "script",
105      "args",
106      "outputs",
107      "directory",
108      "deps",
109      "public_deps",
110    ]
111    forward_variables_from(invoker, "*", _ignore_args)
112  }
113}
114