aboutsummaryrefslogtreecommitdiff
path: root/pw_build/py/pw_build/pip_install_python_deps.py
diff options
context:
space:
mode:
Diffstat (limited to 'pw_build/py/pw_build/pip_install_python_deps.py')
-rw-r--r--pw_build/py/pw_build/pip_install_python_deps.py122
1 files changed, 122 insertions, 0 deletions
diff --git a/pw_build/py/pw_build/pip_install_python_deps.py b/pw_build/py/pw_build/pip_install_python_deps.py
new file mode 100644
index 000000000..4768bed9c
--- /dev/null
+++ b/pw_build/py/pw_build/pip_install_python_deps.py
@@ -0,0 +1,122 @@
+# Copyright 2022 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+"""Pip install Pigweed Python packages."""
+
+import argparse
+from pathlib import Path
+import subprocess
+import sys
+from typing import List, Tuple
+
+try:
+ from pw_build.python_package import load_packages
+except ImportError:
+ # Load from python_package from this directory if pw_build is not available.
+ from python_package import load_packages # type: ignore
+
+
+def _parse_args() -> Tuple[argparse.Namespace, List[str]]:
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ '--python-dep-list-files',
+ type=Path,
+ required=True,
+ help=(
+ 'Path to a text file containing the list of Python package '
+ 'metadata json files.'
+ ),
+ )
+ parser.add_argument(
+ '--gn-packages',
+ required=True,
+ help=(
+ 'Comma separated list of GN python package ' 'targets to install.'
+ ),
+ )
+ parser.add_argument(
+ '--editable-pip-install',
+ action='store_true',
+ help=(
+ 'If true run the pip install command with the '
+ '\'--editable\' option.'
+ ),
+ )
+ return parser.parse_known_args()
+
+
+class NoMatchingGnPythonDependency(Exception):
+ """An error occurred while processing a Python dependency."""
+
+
+def main(
+ python_dep_list_files: Path,
+ editable_pip_install: bool,
+ gn_targets: List[str],
+ pip_args: List[str],
+) -> int:
+ """Find matching python packages to pip install."""
+ pip_target_dirs: List[str] = []
+
+ py_packages = load_packages([python_dep_list_files], ignore_missing=True)
+ for pkg in py_packages:
+ valid_target = [target in pkg.gn_target_name for target in gn_targets]
+ if not any(valid_target):
+ continue
+ top_level_source_dir = pkg.package_dir
+ pip_target_dirs.append(str(top_level_source_dir.parent.resolve()))
+
+ if not pip_target_dirs:
+ raise NoMatchingGnPythonDependency(
+ 'No matching GN Python dependency found to install.\n'
+ 'GN Targets to pip install:\n' + '\n'.join(gn_targets) + '\n\n'
+ 'Declared Python Dependencies:\n'
+ + '\n'.join(pkg.gn_target_name for pkg in py_packages)
+ + '\n\n'
+ )
+
+ for target in pip_target_dirs:
+ command_args = [sys.executable, "-m", "pip"]
+ command_args += pip_args
+ if editable_pip_install:
+ command_args.append('--editable')
+ command_args.append(target)
+
+ process = subprocess.run(
+ command_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
+ )
+ pip_output = process.stdout.decode()
+ if process.returncode != 0:
+ print(pip_output)
+ return process.returncode
+ return 0
+
+
+if __name__ == '__main__':
+ # Parse this script's args and pass any remaining args to pip.
+ argparse_args, remaining_args_for_pip = _parse_args()
+
+ # Split the comma separated string and remove leading slashes.
+ gn_target_names = [
+ target.lstrip('/')
+ for target in argparse_args.gn_packages.split(',')
+ if target # The last target may be an empty string.
+ ]
+
+ result = main(
+ python_dep_list_files=argparse_args.python_dep_list_files,
+ editable_pip_install=argparse_args.editable_pip_install,
+ gn_targets=gn_target_names,
+ pip_args=remaining_args_for_pip,
+ )
+ sys.exit(result)