blob: d35154cd7c320be9929e7646f2f87e2ed929f7fb [file] [log] [blame]
# 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)