#!/usr/bin/env bash # Copyright 2015 Pants project contributors (see CONTRIBUTORS.md). # Licensed under the Apache License, Version 2.0 (see LICENSE). # =============================== NOTE =============================== # This ./pants bootstrap script comes from the pantsbuild/setup # project and is intended to be checked into your code repository so # that any developer can check out your code and be building it with # Pants with no prior setup needed. # # You can learn more here: https://www.pantsbuild.org/install.html # ==================================================================== set -eou pipefail PYTHON_BIN_NAME="${PYTHON:-unspecified}" PANTS_HOME="${PANTS_HOME:-${XDG_CACHE_HOME:-$HOME/.cache}/pants/setup}" PANTS_BOOTSTRAP="${PANTS_HOME}/bootstrap-$(uname -s)-$(uname -m)" VENV_VERSION=${VENV_VERSION:-16.4.3} VENV_PACKAGE=virtualenv-${VENV_VERSION} VENV_TARBALL=${VENV_PACKAGE}.tar.gz COLOR_RED="\x1b[31m" COLOR_GREEN="\x1b[32m" COLOR_RESET="\x1b[0m" function log() { echo -e "$@" 1>&2 } function die() { (($# > 0)) && log "${COLOR_RED}$*${COLOR_RESET}" exit 1 } function green() { (($# > 0)) && log "${COLOR_GREEN}$*${COLOR_RESET}" } function tempdir { mktemp -d "$1"/pants.XXXXXX } function get_exe_path_or_die { exe="$1" if ! command -v "${exe}"; then die "Could not find ${exe}. Please ensure ${exe} is on your PATH." fi } function get_pants_config_value { config_key="$1" optional_space="[[:space:]]*" if [[ -f 'pants.ini' ]]; then valid_delimiters="[:=]" prefix="^${config_key}${optional_space}${valid_delimiters}${optional_space}" sed -ne "/${prefix}/ s#${prefix}##p" pants.ini && return 0 fi if [[ -f 'pants.toml' ]]; then prefix="^${config_key}${optional_space}=${optional_space}" raw_value="$(sed -ne "/${prefix}/ s#${prefix}##p" pants.toml)" echo "${raw_value}" | tr -d \"\' && return 0 fi return 0 } function get_python_major_minor_version { python_exe="$1" "$python_exe" <&1 > /dev/null)" == "pyenv: python${version}"* ]]; then continue fi echo "${interpreter_path}" && return 0 done } function determine_python_exe { if [[ "${PYTHON_BIN_NAME}" != 'unspecified' ]]; then python_bin_name="${PYTHON_BIN_NAME}" else python_bin_name="$(determine_default_python_exe)" if [[ -z "${python_bin_name}" ]]; then die "No valid Python interpreter found. Pants requires Python 3.6+ to run." fi fi python_exe="$(get_exe_path_or_die "${python_bin_name}")" major_minor_version="$(get_python_major_minor_version "${python_exe}")" for valid_version in '36' '37' '38' '39'; do if [[ "${major_minor_version}" == "${valid_version}" ]]; then echo "${python_exe}" && return 0 fi done die "Invalid Python interpreter version for ${python_exe}. Pants requires Python 3.6+ to run." } # TODO(John Sirois): GC race loser tmp dirs leftover from bootstrap_XXX # functions. Any tmp dir w/o a symlink pointing to it can go. function bootstrap_venv { if [[ ! -d "${PANTS_BOOTSTRAP}/${VENV_PACKAGE}" ]]; then ( mkdir -p "${PANTS_BOOTSTRAP}" staging_dir=$(tempdir "${PANTS_BOOTSTRAP}") cd "${staging_dir}" curl -LO "https://pypi.io/packages/source/v/virtualenv/${VENV_TARBALL}" tar -xzf "${VENV_TARBALL}" ln -s "${staging_dir}/${VENV_PACKAGE}" "${staging_dir}/latest" mv "${staging_dir}/latest" "${PANTS_BOOTSTRAP}/${VENV_PACKAGE}" ) 1>&2 fi echo "${PANTS_BOOTSTRAP}/${VENV_PACKAGE}" } function bootstrap_pants { pants_version="$1" python="$2" pants_requirement="pantsbuild.pants==${pants_version}" python_major_minor_version="$(get_python_major_minor_version "${python}")" target_folder_name="${pants_version}_py${python_major_minor_version}" if [[ ! -d "${PANTS_BOOTSTRAP}/${target_folder_name}" ]]; then ( venv_path="$(bootstrap_venv)" staging_dir=$(tempdir "${PANTS_BOOTSTRAP}") "${python}" "${venv_path}/virtualenv.py" --no-download "${staging_dir}/install" "${staging_dir}/install/bin/pip" install -U pip "${staging_dir}/install/bin/pip" install --progress-bar off "${pants_requirement}" ln -s "${staging_dir}/install" "${staging_dir}/${target_folder_name}" mv "${staging_dir}/${target_folder_name}" "${PANTS_BOOTSTRAP}/${target_folder_name}" green "New virtual environment successfully created at ${PANTS_BOOTSTRAP}/${target_folder_name}." ) 1>&2 fi echo "${PANTS_BOOTSTRAP}/${target_folder_name}" } # Ensure we operate from the context of the ./pants buildroot. cd "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" python="$(determine_python_exe)" pants_version="$(determine_pants_version "${python}")" pants_dir="$(bootstrap_pants "${pants_version}" "${python}")" # We set the env var no_proxy to '*', to work around an issue with urllib using non # async-signal-safe syscalls after we fork a process that has already spawned threads. # # See https://blog.phusion.nl/2017/10/13/why-ruby-app-servers-break-on-macos-high-sierra-and-what-can-be-done-about-it/ export no_proxy='*' exec "${pants_dir}/bin/python" "${pants_dir}/bin/pants" "$@"