xref: /aosp_15_r20/external/pigweed/pw_build/python_venv.gni (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker# Copyright 2022 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker#
3*61c4878aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker# use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker# the License at
6*61c4878aSAndroid Build Coastguard Worker#
7*61c4878aSAndroid Build Coastguard Worker#     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker#
9*61c4878aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker# License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker# the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Workerimport("//build_overrides/pigweed.gni")
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Workerimport("$dir_pw_build/python.gni")
18*61c4878aSAndroid Build Coastguard Workerimport("$dir_pw_build/python_action.gni")
19*61c4878aSAndroid Build Coastguard Worker
20*61c4878aSAndroid Build Coastguard Worker# Defines and creates a Python virtualenv. This template is used by Pigweed in
21*61c4878aSAndroid Build Coastguard Worker# https://cs.pigweed.dev/pigweed/+/main:pw_env_setup/BUILD.gn to
22*61c4878aSAndroid Build Coastguard Worker# create a virtualenv for use within the GN build that all Python actions will
23*61c4878aSAndroid Build Coastguard Worker# run in.
24*61c4878aSAndroid Build Coastguard Worker#
25*61c4878aSAndroid Build Coastguard Worker# Example:
26*61c4878aSAndroid Build Coastguard Worker#
27*61c4878aSAndroid Build Coastguard Worker#   pw_python_venv("test_venv") {
28*61c4878aSAndroid Build Coastguard Worker#     path = "test-venv"
29*61c4878aSAndroid Build Coastguard Worker#     constraints = [ "//tools/constraints.list" ]
30*61c4878aSAndroid Build Coastguard Worker#     requirements = [ "//tools/requirements.txt" ]
31*61c4878aSAndroid Build Coastguard Worker#     source_packages = [
32*61c4878aSAndroid Build Coastguard Worker#       "$dir_pw_cli/py",
33*61c4878aSAndroid Build Coastguard Worker#       "$dir_pw_console/py",
34*61c4878aSAndroid Build Coastguard Worker#       "//tools:another_pw_python_package",
35*61c4878aSAndroid Build Coastguard Worker#     ]
36*61c4878aSAndroid Build Coastguard Worker#   }
37*61c4878aSAndroid Build Coastguard Worker#
38*61c4878aSAndroid Build Coastguard Worker# Args:
39*61c4878aSAndroid Build Coastguard Worker#   path: The directory where the virtualenv will be created. This is relative
40*61c4878aSAndroid Build Coastguard Worker#     to the GN root and must begin with "$root_build_dir/" if it lives in the
41*61c4878aSAndroid Build Coastguard Worker#     output directory or "//" if it lives in elsewhere.
42*61c4878aSAndroid Build Coastguard Worker#
43*61c4878aSAndroid Build Coastguard Worker#   constraints: A list of constraint files used when performing pip install
44*61c4878aSAndroid Build Coastguard Worker#     into this virtualenv. By default this is set to pw_build_PIP_CONSTRAINTS
45*61c4878aSAndroid Build Coastguard Worker#
46*61c4878aSAndroid Build Coastguard Worker#   requirements: A list of requirements files to install into this virtualenv
47*61c4878aSAndroid Build Coastguard Worker#     on creation. By default this is set to pw_build_PIP_REQUIREMENTS
48*61c4878aSAndroid Build Coastguard Worker#
49*61c4878aSAndroid Build Coastguard Worker#   pip_generate_hashes: (Default: false) Use --generate-hashes When
50*61c4878aSAndroid Build Coastguard Worker#     running pip-compile to compute the final requirements.txt
51*61c4878aSAndroid Build Coastguard Worker#
52*61c4878aSAndroid Build Coastguard Worker#   source_packages: A list of in-tree pw_python_package targets that will be
53*61c4878aSAndroid Build Coastguard Worker#     checked for external third_party pip dependencies to install into this
54*61c4878aSAndroid Build Coastguard Worker#     virtualenv. Note this list of targets isn't actually installed into the
55*61c4878aSAndroid Build Coastguard Worker#     virtualenv. Only packages defined inside the [options] install_requires
56*61c4878aSAndroid Build Coastguard Worker#     section of each pw_python_package's setup.cfg will be pip installed. See
57*61c4878aSAndroid Build Coastguard Worker#     this page for a setup.cfg example:
58*61c4878aSAndroid Build Coastguard Worker#     https://setuptools.pypa.io/en/latest/userguide/declarative_config.html
59*61c4878aSAndroid Build Coastguard Worker#
60*61c4878aSAndroid Build Coastguard Worker#   output_logs: (Default: true) Commands will output logs.
61*61c4878aSAndroid Build Coastguard Worker#
62*61c4878aSAndroid Build Coastguard Workertemplate("pw_python_venv") {
63*61c4878aSAndroid Build Coastguard Worker  assert(defined(invoker.path), "pw_python_venv requires a 'path'")
64*61c4878aSAndroid Build Coastguard Worker
65*61c4878aSAndroid Build Coastguard Worker  _path = invoker.path
66*61c4878aSAndroid Build Coastguard Worker
67*61c4878aSAndroid Build Coastguard Worker  _generated_requirements_file =
68*61c4878aSAndroid Build Coastguard Worker      "$target_gen_dir/$target_name/generated_requirements.txt"
69*61c4878aSAndroid Build Coastguard Worker
70*61c4878aSAndroid Build Coastguard Worker  _compiled_requirements_file =
71*61c4878aSAndroid Build Coastguard Worker      "$target_gen_dir/$target_name/compiled_requirements.txt"
72*61c4878aSAndroid Build Coastguard Worker
73*61c4878aSAndroid Build Coastguard Worker  _source_packages = []
74*61c4878aSAndroid Build Coastguard Worker  if (defined(invoker.source_packages)) {
75*61c4878aSAndroid Build Coastguard Worker    _source_packages += invoker.source_packages
76*61c4878aSAndroid Build Coastguard Worker  } else {
77*61c4878aSAndroid Build Coastguard Worker    not_needed([
78*61c4878aSAndroid Build Coastguard Worker                 "_source_packages",
79*61c4878aSAndroid Build Coastguard Worker                 "_generated_requirements_file",
80*61c4878aSAndroid Build Coastguard Worker               ])
81*61c4878aSAndroid Build Coastguard Worker  }
82*61c4878aSAndroid Build Coastguard Worker  _output_logs = true
83*61c4878aSAndroid Build Coastguard Worker  if (defined(invoker.output_logs)) {
84*61c4878aSAndroid Build Coastguard Worker    _output_logs = invoker.output_logs
85*61c4878aSAndroid Build Coastguard Worker  }
86*61c4878aSAndroid Build Coastguard Worker  if (!defined(invoker.output_logs) ||
87*61c4878aSAndroid Build Coastguard Worker      current_toolchain != pw_build_PYTHON_TOOLCHAIN) {
88*61c4878aSAndroid Build Coastguard Worker    not_needed([ "_output_logs" ])
89*61c4878aSAndroid Build Coastguard Worker  }
90*61c4878aSAndroid Build Coastguard Worker
91*61c4878aSAndroid Build Coastguard Worker  _source_package_labels = []
92*61c4878aSAndroid Build Coastguard Worker  foreach(pkg, _source_packages) {
93*61c4878aSAndroid Build Coastguard Worker    _source_package_labels += [ get_label_info(pkg, "label_no_toolchain") ]
94*61c4878aSAndroid Build Coastguard Worker  }
95*61c4878aSAndroid Build Coastguard Worker
96*61c4878aSAndroid Build Coastguard Worker  if (defined(invoker.requirements)) {
97*61c4878aSAndroid Build Coastguard Worker    _requirements = invoker.requirements
98*61c4878aSAndroid Build Coastguard Worker  } else {
99*61c4878aSAndroid Build Coastguard Worker    _requirements = pw_build_PIP_REQUIREMENTS
100*61c4878aSAndroid Build Coastguard Worker  }
101*61c4878aSAndroid Build Coastguard Worker
102*61c4878aSAndroid Build Coastguard Worker  if (defined(invoker.constraints)) {
103*61c4878aSAndroid Build Coastguard Worker    _constraints = invoker.constraints
104*61c4878aSAndroid Build Coastguard Worker  } else {
105*61c4878aSAndroid Build Coastguard Worker    _constraints = pw_build_PIP_CONSTRAINTS
106*61c4878aSAndroid Build Coastguard Worker  }
107*61c4878aSAndroid Build Coastguard Worker
108*61c4878aSAndroid Build Coastguard Worker  _python_interpreter = _path + "/bin/python"
109*61c4878aSAndroid Build Coastguard Worker  if (host_os == "win") {
110*61c4878aSAndroid Build Coastguard Worker    _python_interpreter = _path + "/Scripts/python.exe"
111*61c4878aSAndroid Build Coastguard Worker  }
112*61c4878aSAndroid Build Coastguard Worker
113*61c4878aSAndroid Build Coastguard Worker  _venv_metadata_json_file = "$target_gen_dir/$target_name/venv_metadata.json"
114*61c4878aSAndroid Build Coastguard Worker  _venv_metadata = {
115*61c4878aSAndroid Build Coastguard Worker    gn_target_name =
116*61c4878aSAndroid Build Coastguard Worker        get_label_info(":${invoker.target_name}", "label_no_toolchain")
117*61c4878aSAndroid Build Coastguard Worker    path = rebase_path(_path, root_build_dir)
118*61c4878aSAndroid Build Coastguard Worker    generated_requirements =
119*61c4878aSAndroid Build Coastguard Worker        rebase_path(_generated_requirements_file, root_build_dir)
120*61c4878aSAndroid Build Coastguard Worker    compiled_requirements =
121*61c4878aSAndroid Build Coastguard Worker        rebase_path(_compiled_requirements_file, root_build_dir)
122*61c4878aSAndroid Build Coastguard Worker    requirements = rebase_path(_requirements, root_build_dir)
123*61c4878aSAndroid Build Coastguard Worker    constraints = rebase_path(_constraints, root_build_dir)
124*61c4878aSAndroid Build Coastguard Worker    interpreter = rebase_path(_python_interpreter, root_build_dir)
125*61c4878aSAndroid Build Coastguard Worker    source_packages = _source_package_labels
126*61c4878aSAndroid Build Coastguard Worker  }
127*61c4878aSAndroid Build Coastguard Worker  write_file(_venv_metadata_json_file, _venv_metadata, "json")
128*61c4878aSAndroid Build Coastguard Worker
129*61c4878aSAndroid Build Coastguard Worker  pw_python_action("${target_name}._create_virtualenv") {
130*61c4878aSAndroid Build Coastguard Worker    _pw_internal_run_in_venv = false
131*61c4878aSAndroid Build Coastguard Worker
132*61c4878aSAndroid Build Coastguard Worker    # Note: The if the venv isn't in the out dir then we can't declare
133*61c4878aSAndroid Build Coastguard Worker    # outputs and must stamp instead.
134*61c4878aSAndroid Build Coastguard Worker    stamp = true
135*61c4878aSAndroid Build Coastguard Worker
136*61c4878aSAndroid Build Coastguard Worker    # The virtualenv should depend on the version of Python currently in use.
137*61c4878aSAndroid Build Coastguard Worker    stampfile = "$target_gen_dir/$target_name.pw_pystamp"
138*61c4878aSAndroid Build Coastguard Worker    depfile = "$target_gen_dir/$target_name.d"
139*61c4878aSAndroid Build Coastguard Worker    script = "$dir_pw_build/py/pw_build/create_gn_venv.py"
140*61c4878aSAndroid Build Coastguard Worker    args = [
141*61c4878aSAndroid Build Coastguard Worker      "--depfile",
142*61c4878aSAndroid Build Coastguard Worker      rebase_path(depfile, root_build_dir),
143*61c4878aSAndroid Build Coastguard Worker      "--destination-dir",
144*61c4878aSAndroid Build Coastguard Worker      rebase_path(_path, root_build_dir),
145*61c4878aSAndroid Build Coastguard Worker      "--stampfile",
146*61c4878aSAndroid Build Coastguard Worker      rebase_path(stampfile, root_build_dir),
147*61c4878aSAndroid Build Coastguard Worker    ]
148*61c4878aSAndroid Build Coastguard Worker  }
149*61c4878aSAndroid Build Coastguard Worker
150*61c4878aSAndroid Build Coastguard Worker  if (defined(invoker.source_packages) &&
151*61c4878aSAndroid Build Coastguard Worker      current_toolchain == pw_build_PYTHON_TOOLCHAIN) {
152*61c4878aSAndroid Build Coastguard Worker    pw_python_action("${target_name}._generate_3p_requirements") {
153*61c4878aSAndroid Build Coastguard Worker      inputs = _requirements + _constraints
154*61c4878aSAndroid Build Coastguard Worker
155*61c4878aSAndroid Build Coastguard Worker      _pw_internal_run_in_venv = false
156*61c4878aSAndroid Build Coastguard Worker      _forward_python_metadata_deps = true
157*61c4878aSAndroid Build Coastguard Worker
158*61c4878aSAndroid Build Coastguard Worker      script = "$dir_pw_build/py/pw_build/generate_python_requirements.py"
159*61c4878aSAndroid Build Coastguard Worker
160*61c4878aSAndroid Build Coastguard Worker      _pkg_gn_labels = []
161*61c4878aSAndroid Build Coastguard Worker      foreach(pkg, _source_packages) {
162*61c4878aSAndroid Build Coastguard Worker        _pkg_gn_labels += [ get_label_info(pkg, "label_no_toolchain") +
163*61c4878aSAndroid Build Coastguard Worker                            "($pw_build_PYTHON_TOOLCHAIN)" ]
164*61c4878aSAndroid Build Coastguard Worker      }
165*61c4878aSAndroid Build Coastguard Worker
166*61c4878aSAndroid Build Coastguard Worker      # Add target packages to the python_metadata_deps. This will let
167*61c4878aSAndroid Build Coastguard Worker      # GN expand the transitive pw_python_package deps which are read
168*61c4878aSAndroid Build Coastguard Worker      # by generate_python_requirements.py
169*61c4878aSAndroid Build Coastguard Worker      python_metadata_deps = _pkg_gn_labels
170*61c4878aSAndroid Build Coastguard Worker
171*61c4878aSAndroid Build Coastguard Worker      args = [
172*61c4878aSAndroid Build Coastguard Worker        "--gn-root-build-dir",
173*61c4878aSAndroid Build Coastguard Worker        rebase_path(root_build_dir, root_build_dir),
174*61c4878aSAndroid Build Coastguard Worker        "--output-requirement-file",
175*61c4878aSAndroid Build Coastguard Worker        rebase_path(_generated_requirements_file, root_build_dir),
176*61c4878aSAndroid Build Coastguard Worker      ]
177*61c4878aSAndroid Build Coastguard Worker
178*61c4878aSAndroid Build Coastguard Worker      if (_constraints != []) {
179*61c4878aSAndroid Build Coastguard Worker        args += [ "--constraint-files" ]
180*61c4878aSAndroid Build Coastguard Worker      }
181*61c4878aSAndroid Build Coastguard Worker      foreach(_constraints_file, _constraints) {
182*61c4878aSAndroid Build Coastguard Worker        args += [ rebase_path(_constraints_file, root_build_dir) ]
183*61c4878aSAndroid Build Coastguard Worker      }
184*61c4878aSAndroid Build Coastguard Worker
185*61c4878aSAndroid Build Coastguard Worker      args += [
186*61c4878aSAndroid Build Coastguard Worker        "--gn-packages",
187*61c4878aSAndroid Build Coastguard Worker        string_join(",", _pkg_gn_labels),
188*61c4878aSAndroid Build Coastguard Worker      ]
189*61c4878aSAndroid Build Coastguard Worker
190*61c4878aSAndroid Build Coastguard Worker      outputs = [ _generated_requirements_file ]
191*61c4878aSAndroid Build Coastguard Worker      deps = [ ":${invoker.target_name}._create_virtualenv($pw_build_PYTHON_TOOLCHAIN)" ]
192*61c4878aSAndroid Build Coastguard Worker    }
193*61c4878aSAndroid Build Coastguard Worker  } else {
194*61c4878aSAndroid Build Coastguard Worker    group("${target_name}._generate_3p_requirements") {
195*61c4878aSAndroid Build Coastguard Worker    }
196*61c4878aSAndroid Build Coastguard Worker  }
197*61c4878aSAndroid Build Coastguard Worker
198*61c4878aSAndroid Build Coastguard Worker  _pip_generate_hashes = false
199*61c4878aSAndroid Build Coastguard Worker  if (defined(invoker.pip_generate_hashes)) {
200*61c4878aSAndroid Build Coastguard Worker    _pip_generate_hashes = invoker.pip_generate_hashes
201*61c4878aSAndroid Build Coastguard Worker  } else {
202*61c4878aSAndroid Build Coastguard Worker    not_needed([ "_pip_generate_hashes" ])
203*61c4878aSAndroid Build Coastguard Worker  }
204*61c4878aSAndroid Build Coastguard Worker
205*61c4878aSAndroid Build Coastguard Worker  if (defined(invoker.source_packages) || defined(invoker.requirements)) {
206*61c4878aSAndroid Build Coastguard Worker    if (current_toolchain == pw_build_PYTHON_TOOLCHAIN) {
207*61c4878aSAndroid Build Coastguard Worker      # Compile requirements with hashes
208*61c4878aSAndroid Build Coastguard Worker      pw_python_action("${target_name}._compile_requirements") {
209*61c4878aSAndroid Build Coastguard Worker        module = "piptools"
210*61c4878aSAndroid Build Coastguard Worker
211*61c4878aSAndroid Build Coastguard Worker        # Set the venv to run this pip install in.
212*61c4878aSAndroid Build Coastguard Worker        _pw_internal_run_in_venv = true
213*61c4878aSAndroid Build Coastguard Worker        _skip_installing_external_python_deps = true
214*61c4878aSAndroid Build Coastguard Worker        venv = get_label_info(":${invoker.target_name}", "label_no_toolchain")
215*61c4878aSAndroid Build Coastguard Worker
216*61c4878aSAndroid Build Coastguard Worker        _pip_args = []
217*61c4878aSAndroid Build Coastguard Worker        if (pw_build_PYTHON_PIP_INSTALL_OFFLINE) {
218*61c4878aSAndroid Build Coastguard Worker          _pip_args += [ "--no-index" ]
219*61c4878aSAndroid Build Coastguard Worker        }
220*61c4878aSAndroid Build Coastguard Worker        if (pw_build_PYTHON_PIP_INSTALL_DISABLE_CACHE) {
221*61c4878aSAndroid Build Coastguard Worker          _pip_args += [ "--no-cache-dir" ]
222*61c4878aSAndroid Build Coastguard Worker        }
223*61c4878aSAndroid Build Coastguard Worker        if (pw_build_PYTHON_PIP_INSTALL_FIND_LINKS != []) {
224*61c4878aSAndroid Build Coastguard Worker          foreach(link_dir, pw_build_PYTHON_PIP_INSTALL_FIND_LINKS) {
225*61c4878aSAndroid Build Coastguard Worker            _pip_args +=
226*61c4878aSAndroid Build Coastguard Worker                [ "--find-links=" + rebase_path(link_dir, root_build_dir) ]
227*61c4878aSAndroid Build Coastguard Worker          }
228*61c4878aSAndroid Build Coastguard Worker        }
229*61c4878aSAndroid Build Coastguard Worker
230*61c4878aSAndroid Build Coastguard Worker        args = [ "compile" ]
231*61c4878aSAndroid Build Coastguard Worker
232*61c4878aSAndroid Build Coastguard Worker        if (_pip_generate_hashes) {
233*61c4878aSAndroid Build Coastguard Worker          args += [
234*61c4878aSAndroid Build Coastguard Worker            "--generate-hashes",
235*61c4878aSAndroid Build Coastguard Worker            "--reuse-hashes",
236*61c4878aSAndroid Build Coastguard Worker          ]
237*61c4878aSAndroid Build Coastguard Worker        }
238*61c4878aSAndroid Build Coastguard Worker
239*61c4878aSAndroid Build Coastguard Worker        args += [
240*61c4878aSAndroid Build Coastguard Worker          "--resolver=backtracking",
241*61c4878aSAndroid Build Coastguard Worker
242*61c4878aSAndroid Build Coastguard Worker          # --allow-unsafe will force pinning pip and setuptools.
243*61c4878aSAndroid Build Coastguard Worker          "--allow-unsafe",
244*61c4878aSAndroid Build Coastguard Worker          "--output-file",
245*61c4878aSAndroid Build Coastguard Worker          rebase_path(_compiled_requirements_file, root_build_dir),
246*61c4878aSAndroid Build Coastguard Worker
247*61c4878aSAndroid Build Coastguard Worker          # Input requirements file:
248*61c4878aSAndroid Build Coastguard Worker          rebase_path(_generated_requirements_file, root_build_dir),
249*61c4878aSAndroid Build Coastguard Worker        ]
250*61c4878aSAndroid Build Coastguard Worker
251*61c4878aSAndroid Build Coastguard Worker        # Pass offline related pip args through the pip-compile command.
252*61c4878aSAndroid Build Coastguard Worker        if (_pip_args != []) {
253*61c4878aSAndroid Build Coastguard Worker          args += [
254*61c4878aSAndroid Build Coastguard Worker            "--pip-args",
255*61c4878aSAndroid Build Coastguard Worker            string_join(" ", _pip_args),
256*61c4878aSAndroid Build Coastguard Worker          ]
257*61c4878aSAndroid Build Coastguard Worker        }
258*61c4878aSAndroid Build Coastguard Worker
259*61c4878aSAndroid Build Coastguard Worker        # Extra requirements files
260*61c4878aSAndroid Build Coastguard Worker        foreach(_requirements_file, _requirements) {
261*61c4878aSAndroid Build Coastguard Worker          args += [ rebase_path(_requirements_file, root_build_dir) ]
262*61c4878aSAndroid Build Coastguard Worker        }
263*61c4878aSAndroid Build Coastguard Worker
264*61c4878aSAndroid Build Coastguard Worker        inputs = []
265*61c4878aSAndroid Build Coastguard Worker
266*61c4878aSAndroid Build Coastguard Worker        # NOTE: constraint files are included in the content of the
267*61c4878aSAndroid Build Coastguard Worker        # _generated_requirements_file. This occurs in the
268*61c4878aSAndroid Build Coastguard Worker        # ._generate_3p_requirements target.
269*61c4878aSAndroid Build Coastguard Worker        inputs += _constraints
270*61c4878aSAndroid Build Coastguard Worker        inputs += _requirements
271*61c4878aSAndroid Build Coastguard Worker        inputs += [ _generated_requirements_file ]
272*61c4878aSAndroid Build Coastguard Worker
273*61c4878aSAndroid Build Coastguard Worker        deps = [
274*61c4878aSAndroid Build Coastguard Worker          ":${invoker.target_name}._generate_3p_requirements($pw_build_PYTHON_TOOLCHAIN)",
275*61c4878aSAndroid Build Coastguard Worker          ":${invoker.target_name}._install_base_3p_deps($pw_build_PYTHON_TOOLCHAIN)",
276*61c4878aSAndroid Build Coastguard Worker        ]
277*61c4878aSAndroid Build Coastguard Worker        outputs = [ _compiled_requirements_file ]
278*61c4878aSAndroid Build Coastguard Worker      }
279*61c4878aSAndroid Build Coastguard Worker
280*61c4878aSAndroid Build Coastguard Worker      # This target will run 'pip install' in the venv to provide base
281*61c4878aSAndroid Build Coastguard Worker      # dependencies needed to run piptools commands. That is required for the
282*61c4878aSAndroid Build Coastguard Worker      # _compile_requirements sub target.
283*61c4878aSAndroid Build Coastguard Worker      pw_python_action("${target_name}._install_base_3p_deps") {
284*61c4878aSAndroid Build Coastguard Worker        module = "pip"
285*61c4878aSAndroid Build Coastguard Worker
286*61c4878aSAndroid Build Coastguard Worker        # Set the venv to run this pip install in.
287*61c4878aSAndroid Build Coastguard Worker        _pw_internal_run_in_venv = true
288*61c4878aSAndroid Build Coastguard Worker        _skip_installing_external_python_deps = true
289*61c4878aSAndroid Build Coastguard Worker        venv = get_label_info(":${invoker.target_name}", "label_no_toolchain")
290*61c4878aSAndroid Build Coastguard Worker
291*61c4878aSAndroid Build Coastguard Worker        _base_requirement_file = "$dir_pw_env_setup/py/pw_env_setup/virtualenv_setup/python_base_requirements.txt"
292*61c4878aSAndroid Build Coastguard Worker
293*61c4878aSAndroid Build Coastguard Worker        args = [
294*61c4878aSAndroid Build Coastguard Worker          "install",
295*61c4878aSAndroid Build Coastguard Worker          "--requirement",
296*61c4878aSAndroid Build Coastguard Worker          rebase_path(_base_requirement_file, root_build_dir),
297*61c4878aSAndroid Build Coastguard Worker        ]
298*61c4878aSAndroid Build Coastguard Worker        if (_output_logs) {
299*61c4878aSAndroid Build Coastguard Worker          _pip_install_log_file =
300*61c4878aSAndroid Build Coastguard Worker              "$target_gen_dir/$target_name/pip_install_log.txt"
301*61c4878aSAndroid Build Coastguard Worker          args += [
302*61c4878aSAndroid Build Coastguard Worker            "--log",
303*61c4878aSAndroid Build Coastguard Worker            rebase_path(_pip_install_log_file, root_build_dir),
304*61c4878aSAndroid Build Coastguard Worker          ]
305*61c4878aSAndroid Build Coastguard Worker          outputs = [ _pip_install_log_file ]
306*61c4878aSAndroid Build Coastguard Worker        }
307*61c4878aSAndroid Build Coastguard Worker
308*61c4878aSAndroid Build Coastguard Worker        # NOTE: Constraints should be ignored for this step.
309*61c4878aSAndroid Build Coastguard Worker
310*61c4878aSAndroid Build Coastguard Worker        if (pw_build_PYTHON_PIP_INSTALL_OFFLINE) {
311*61c4878aSAndroid Build Coastguard Worker          args += [ "--no-index" ]
312*61c4878aSAndroid Build Coastguard Worker        }
313*61c4878aSAndroid Build Coastguard Worker        if (pw_build_PYTHON_PIP_INSTALL_DISABLE_CACHE) {
314*61c4878aSAndroid Build Coastguard Worker          args += [ "--no-cache-dir" ]
315*61c4878aSAndroid Build Coastguard Worker        }
316*61c4878aSAndroid Build Coastguard Worker        if (pw_build_PYTHON_PIP_INSTALL_FIND_LINKS != []) {
317*61c4878aSAndroid Build Coastguard Worker          foreach(link_dir, pw_build_PYTHON_PIP_INSTALL_FIND_LINKS) {
318*61c4878aSAndroid Build Coastguard Worker            args += [
319*61c4878aSAndroid Build Coastguard Worker              "--find-links",
320*61c4878aSAndroid Build Coastguard Worker              rebase_path(link_dir, root_build_dir),
321*61c4878aSAndroid Build Coastguard Worker            ]
322*61c4878aSAndroid Build Coastguard Worker          }
323*61c4878aSAndroid Build Coastguard Worker        }
324*61c4878aSAndroid Build Coastguard Worker
325*61c4878aSAndroid Build Coastguard Worker        deps = [ ":${invoker.target_name}._create_virtualenv($pw_build_PYTHON_TOOLCHAIN)" ]
326*61c4878aSAndroid Build Coastguard Worker        stamp = true
327*61c4878aSAndroid Build Coastguard Worker        pool = "$dir_pw_build/pool:pip($default_toolchain)"
328*61c4878aSAndroid Build Coastguard Worker      }
329*61c4878aSAndroid Build Coastguard Worker
330*61c4878aSAndroid Build Coastguard Worker      # Install all 3rd party Python dependencies.
331*61c4878aSAndroid Build Coastguard Worker      pw_python_action("${target_name}._install_3p_deps") {
332*61c4878aSAndroid Build Coastguard Worker        module = "pip"
333*61c4878aSAndroid Build Coastguard Worker
334*61c4878aSAndroid Build Coastguard Worker        # Set the venv to run this pip install in.
335*61c4878aSAndroid Build Coastguard Worker        _pw_internal_run_in_venv = true
336*61c4878aSAndroid Build Coastguard Worker        _skip_installing_external_python_deps = true
337*61c4878aSAndroid Build Coastguard Worker        venv = get_label_info(":${invoker.target_name}", "label_no_toolchain")
338*61c4878aSAndroid Build Coastguard Worker
339*61c4878aSAndroid Build Coastguard Worker        args = pw_build_PYTHON_PIP_DEFAULT_OPTIONS
340*61c4878aSAndroid Build Coastguard Worker        args += [
341*61c4878aSAndroid Build Coastguard Worker          "install",
342*61c4878aSAndroid Build Coastguard Worker          "--upgrade",
343*61c4878aSAndroid Build Coastguard Worker        ]
344*61c4878aSAndroid Build Coastguard Worker
345*61c4878aSAndroid Build Coastguard Worker        if (_output_logs) {
346*61c4878aSAndroid Build Coastguard Worker          _pip_install_log_file =
347*61c4878aSAndroid Build Coastguard Worker              "$target_gen_dir/$target_name/pip_install_log.txt"
348*61c4878aSAndroid Build Coastguard Worker          args += [
349*61c4878aSAndroid Build Coastguard Worker            "--log",
350*61c4878aSAndroid Build Coastguard Worker            rebase_path(_pip_install_log_file, root_build_dir),
351*61c4878aSAndroid Build Coastguard Worker          ]
352*61c4878aSAndroid Build Coastguard Worker        }
353*61c4878aSAndroid Build Coastguard Worker
354*61c4878aSAndroid Build Coastguard Worker        if (_pip_generate_hashes) {
355*61c4878aSAndroid Build Coastguard Worker          args += [ "--require-hashes" ]
356*61c4878aSAndroid Build Coastguard Worker        }
357*61c4878aSAndroid Build Coastguard Worker
358*61c4878aSAndroid Build Coastguard Worker        if (pw_build_PYTHON_PIP_INSTALL_OFFLINE) {
359*61c4878aSAndroid Build Coastguard Worker          args += [ "--no-index" ]
360*61c4878aSAndroid Build Coastguard Worker        }
361*61c4878aSAndroid Build Coastguard Worker        if (pw_build_PYTHON_PIP_INSTALL_DISABLE_CACHE) {
362*61c4878aSAndroid Build Coastguard Worker          args += [ "--no-cache-dir" ]
363*61c4878aSAndroid Build Coastguard Worker        }
364*61c4878aSAndroid Build Coastguard Worker        if (pw_build_PYTHON_PIP_INSTALL_FIND_LINKS != []) {
365*61c4878aSAndroid Build Coastguard Worker          foreach(link_dir, pw_build_PYTHON_PIP_INSTALL_FIND_LINKS) {
366*61c4878aSAndroid Build Coastguard Worker            args += [
367*61c4878aSAndroid Build Coastguard Worker              "--find-links",
368*61c4878aSAndroid Build Coastguard Worker              rebase_path(link_dir, root_build_dir),
369*61c4878aSAndroid Build Coastguard Worker            ]
370*61c4878aSAndroid Build Coastguard Worker          }
371*61c4878aSAndroid Build Coastguard Worker        }
372*61c4878aSAndroid Build Coastguard Worker
373*61c4878aSAndroid Build Coastguard Worker        # Note: --no-build-isolation should be avoided for installing 3rd party
374*61c4878aSAndroid Build Coastguard Worker        # Python packages that use C/C++ extension modules.
375*61c4878aSAndroid Build Coastguard Worker        # https://setuptools.pypa.io/en/latest/userguide/ext_modules.html
376*61c4878aSAndroid Build Coastguard Worker        inputs = _constraints + _requirements + [ _compiled_requirements_file ]
377*61c4878aSAndroid Build Coastguard Worker
378*61c4878aSAndroid Build Coastguard Worker        # Use the pip-tools compiled requiremets file. This contains the fully
379*61c4878aSAndroid Build Coastguard Worker        # expanded list of deps with constraints applied.
380*61c4878aSAndroid Build Coastguard Worker        if (defined(invoker.source_packages)) {
381*61c4878aSAndroid Build Coastguard Worker          inputs += [ _compiled_requirements_file ]
382*61c4878aSAndroid Build Coastguard Worker          args += [
383*61c4878aSAndroid Build Coastguard Worker            "--requirement",
384*61c4878aSAndroid Build Coastguard Worker            rebase_path(_compiled_requirements_file, root_build_dir),
385*61c4878aSAndroid Build Coastguard Worker          ]
386*61c4878aSAndroid Build Coastguard Worker        }
387*61c4878aSAndroid Build Coastguard Worker
388*61c4878aSAndroid Build Coastguard Worker        deps = [
389*61c4878aSAndroid Build Coastguard Worker          ":${invoker.target_name}._compile_requirements($pw_build_PYTHON_TOOLCHAIN)",
390*61c4878aSAndroid Build Coastguard Worker          ":${invoker.target_name}._generate_3p_requirements($pw_build_PYTHON_TOOLCHAIN)",
391*61c4878aSAndroid Build Coastguard Worker          ":${invoker.target_name}._install_base_3p_deps($pw_build_PYTHON_TOOLCHAIN)",
392*61c4878aSAndroid Build Coastguard Worker        ]
393*61c4878aSAndroid Build Coastguard Worker        stamp = true
394*61c4878aSAndroid Build Coastguard Worker        pool = "$dir_pw_build/pool:pip($default_toolchain)"
395*61c4878aSAndroid Build Coastguard Worker      }
396*61c4878aSAndroid Build Coastguard Worker
397*61c4878aSAndroid Build Coastguard Worker      # Target to create a Python package cache for this pw_python_venv.
398*61c4878aSAndroid Build Coastguard Worker      pw_python_action("${target_name}.vendor_wheels") {
399*61c4878aSAndroid Build Coastguard Worker        _wheel_output_dir = "$target_gen_dir/$target_name/wheels"
400*61c4878aSAndroid Build Coastguard Worker        _pip_download_logfile =
401*61c4878aSAndroid Build Coastguard Worker            "$target_gen_dir/$target_name/pip_download_log.txt"
402*61c4878aSAndroid Build Coastguard Worker        _pip_wheel_logfile = "$target_gen_dir/$target_name/pip_wheel_log.txt"
403*61c4878aSAndroid Build Coastguard Worker        metadata = {
404*61c4878aSAndroid Build Coastguard Worker          pw_python_package_wheels = [ _wheel_output_dir ]
405*61c4878aSAndroid Build Coastguard Worker        }
406*61c4878aSAndroid Build Coastguard Worker
407*61c4878aSAndroid Build Coastguard Worker        script = "$dir_pw_build/py/pw_build/generate_python_wheel_cache.py"
408*61c4878aSAndroid Build Coastguard Worker
409*61c4878aSAndroid Build Coastguard Worker        # Set the venv to run this pip install in.
410*61c4878aSAndroid Build Coastguard Worker        _pw_internal_run_in_venv = true
411*61c4878aSAndroid Build Coastguard Worker        _skip_installing_external_python_deps = true
412*61c4878aSAndroid Build Coastguard Worker        venv = get_label_info(":${invoker.target_name}", "label_no_toolchain")
413*61c4878aSAndroid Build Coastguard Worker
414*61c4878aSAndroid Build Coastguard Worker        args = [
415*61c4878aSAndroid Build Coastguard Worker          "--pip-download-log",
416*61c4878aSAndroid Build Coastguard Worker          rebase_path(_pip_download_logfile, root_build_dir),
417*61c4878aSAndroid Build Coastguard Worker          "--wheel-dir",
418*61c4878aSAndroid Build Coastguard Worker          rebase_path(_wheel_output_dir, root_build_dir),
419*61c4878aSAndroid Build Coastguard Worker          "-r",
420*61c4878aSAndroid Build Coastguard Worker          rebase_path(_compiled_requirements_file, root_build_dir),
421*61c4878aSAndroid Build Coastguard Worker        ]
422*61c4878aSAndroid Build Coastguard Worker
423*61c4878aSAndroid Build Coastguard Worker        if (pw_build_PYTHON_PIP_DOWNLOAD_ALL_PLATFORMS) {
424*61c4878aSAndroid Build Coastguard Worker          args += [ "--download-all-platforms" ]
425*61c4878aSAndroid Build Coastguard Worker        }
426*61c4878aSAndroid Build Coastguard Worker
427*61c4878aSAndroid Build Coastguard Worker        deps = [
428*61c4878aSAndroid Build Coastguard Worker          ":${invoker.target_name}._compile_requirements($pw_build_PYTHON_TOOLCHAIN)",
429*61c4878aSAndroid Build Coastguard Worker          ":${invoker.target_name}._generate_3p_requirements($pw_build_PYTHON_TOOLCHAIN)",
430*61c4878aSAndroid Build Coastguard Worker        ]
431*61c4878aSAndroid Build Coastguard Worker
432*61c4878aSAndroid Build Coastguard Worker        outputs = [
433*61c4878aSAndroid Build Coastguard Worker          _wheel_output_dir,
434*61c4878aSAndroid Build Coastguard Worker          _pip_wheel_logfile,
435*61c4878aSAndroid Build Coastguard Worker          _pip_download_logfile,
436*61c4878aSAndroid Build Coastguard Worker        ]
437*61c4878aSAndroid Build Coastguard Worker        pool = "$dir_pw_build/pool:pip($default_toolchain)"
438*61c4878aSAndroid Build Coastguard Worker      }
439*61c4878aSAndroid Build Coastguard Worker
440*61c4878aSAndroid Build Coastguard Worker      # End pw_build_PYTHON_TOOLCHAIN check
441*61c4878aSAndroid Build Coastguard Worker    } else {
442*61c4878aSAndroid Build Coastguard Worker      group("${target_name}._compile_requirements") {
443*61c4878aSAndroid Build Coastguard Worker        public_deps = [ ":${target_name}($pw_build_PYTHON_TOOLCHAIN)" ]
444*61c4878aSAndroid Build Coastguard Worker      }
445*61c4878aSAndroid Build Coastguard Worker      group("${target_name}._install_3p_deps") {
446*61c4878aSAndroid Build Coastguard Worker        public_deps = [ ":${target_name}($pw_build_PYTHON_TOOLCHAIN)" ]
447*61c4878aSAndroid Build Coastguard Worker      }
448*61c4878aSAndroid Build Coastguard Worker      group("${target_name}.vendor_wheels") {
449*61c4878aSAndroid Build Coastguard Worker        public_deps = [ ":${target_name}($pw_build_PYTHON_TOOLCHAIN)" ]
450*61c4878aSAndroid Build Coastguard Worker      }
451*61c4878aSAndroid Build Coastguard Worker    }
452*61c4878aSAndroid Build Coastguard Worker  } else {
453*61c4878aSAndroid Build Coastguard Worker    group("${target_name}._compile_requirements") {
454*61c4878aSAndroid Build Coastguard Worker    }
455*61c4878aSAndroid Build Coastguard Worker    group("${target_name}._install_3p_deps") {
456*61c4878aSAndroid Build Coastguard Worker    }
457*61c4878aSAndroid Build Coastguard Worker    group("${target_name}.vendor_wheels") {
458*61c4878aSAndroid Build Coastguard Worker    }
459*61c4878aSAndroid Build Coastguard Worker  }
460*61c4878aSAndroid Build Coastguard Worker
461*61c4878aSAndroid Build Coastguard Worker  # Have this target directly depend on _install_3p_deps
462*61c4878aSAndroid Build Coastguard Worker  group("$target_name") {
463*61c4878aSAndroid Build Coastguard Worker    public_deps =
464*61c4878aSAndroid Build Coastguard Worker        [ ":${target_name}._install_3p_deps($pw_build_PYTHON_TOOLCHAIN)" ]
465*61c4878aSAndroid Build Coastguard Worker  }
466*61c4878aSAndroid Build Coastguard Worker}
467