• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2019 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("python_action.gni")
16
17# Runs a program which isn't in Python.
18#
19# This is provided to avoid having to write a new Python wrapper script every
20# time a program needs to be run from GN.
21#
22# Args:
23#  program: The program to run. Can be a full path or just a name (in which case
24#    $PATH is searched).
25#
26#  args: Optional list of arguments to the program.
27#
28#  deps: Dependencies for this target.
29#
30#  public_deps: Public dependencies for this target. In addition to outputs from
31#    this target, outputs generated by public dependencies can be used as inputs
32#    from targets that depend on this one. This is not the case for private
33#    deps.
34#
35#  inputs: Optional list of build inputs to the program.
36#
37#  outputs: Optional list of artifacts produced by the program's execution.
38#
39#  env: Optional list of key-value pairs defining environment variables for
40#    the program.
41#
42#  env_file: Optional path to a file containing a list of newline-separated
43#    key-value pairs defining environment variables for the program.
44#
45#  args_file: Optional path to a file containing additional positional arguments
46#    to the program. Each line of the file is appended to the invocation. Useful
47#    for specifying arguments from GN metadata.
48#
49#  skip_empty_args: If args_file is provided, boolean indicating whether to skip
50#    running the program if the file is empty. Used to avoid running commands
51#    which error when called without arguments.
52#
53#  capture_output: If true, output from the program is hidden unless the program
54#    exits with an error. Defaults to true.
55#
56#  working_directory: The working directory to execute the subprocess with. If
57#    not specified it will not be set and the subprocess will have whatever the
58#    parent current working directory is.
59#
60#  venv: Python virtualenv to pass along to the underlying pw_python_action.
61#
62#  visibility: GN visibility to apply to the underlying target.
63#
64# Example:
65#
66#   pw_exec("hello_world") {
67#     program = "/bin/sh"
68#     args = [
69#       "-c",
70#       "echo hello \$WORLD",
71#     ]
72#     env = [
73#       "WORLD=world",
74#     ]
75#   }
76#
77template("pw_exec") {
78  assert(defined(invoker.program), "pw_exec requires a program to run")
79
80  _script_args = [
81    "--target",
82    target_name,
83  ]
84
85  if (defined(invoker.env_file)) {
86    _script_args += [
87      "--env-file",
88      rebase_path(invoker.env_file, root_build_dir),
89    ]
90  }
91
92  if (defined(invoker.args_file)) {
93    _script_args += [
94      "--args-file",
95      rebase_path(invoker.args_file, root_build_dir),
96    ]
97
98    if (defined(invoker.skip_empty_args) && invoker.skip_empty_args) {
99      _script_args += [ "--skip-empty-args" ]
100    }
101  }
102
103  if (defined(invoker.env)) {
104    foreach(_env, invoker.env) {
105      _script_args += [
106        "--env",
107        _env,
108      ]
109    }
110  }
111
112  if (!defined(invoker.capture_output) || invoker.capture_output) {
113    _script_args += [ "--capture-output" ]
114    _capture_output = true
115  } else {
116    _capture_output = false
117  }
118
119  if (defined(invoker.working_directory)) {
120    _script_args += [
121      "--working-directory",
122      invoker.working_directory,
123    ]
124  }
125
126  _script_args += [
127    "--",
128    invoker.program,
129  ]
130  if (defined(invoker.args)) {
131    _script_args += invoker.args
132  }
133
134  pw_python_action(target_name) {
135    script = "$dir_pw_build/py/pw_build/exec.py"
136    args = _script_args
137    capture_output = _capture_output
138
139    forward_variables_from(invoker,
140                           [
141                             "deps",
142                             "inputs",
143                             "pool",
144                             "public_deps",
145                             "venv",
146                             "visibility",
147                           ])
148
149    if (!defined(inputs)) {
150      inputs = []
151    }
152    if (defined(invoker.env_file)) {
153      inputs += [ invoker.env_file ]
154    }
155
156    if (defined(invoker.outputs)) {
157      outputs = invoker.outputs
158    } else {
159      stamp = true
160    }
161  }
162}
163