-
Notifications
You must be signed in to change notification settings - Fork 0
/
pants
executable file
·193 lines (166 loc) · 6.73 KB
/
pants
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#!/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_ini_config_value {
if [[ ! -f 'pants.ini' ]]; then
return 0
fi
config_key="$1"
valid_delimiters="[:=]"
optional_space="[[:space:]]*"
prefix="^${config_key}${optional_space}${valid_delimiters}${optional_space}"
sed -ne "/${prefix}/ s#${prefix}##p" pants.ini
}
function get_python_major_minor_version {
python_exe="$1"
"$python_exe" <<EOF
import sys
major_minor_version = ''.join(str(version_num) for version_num in sys.version_info[0:2])
print(major_minor_version)
EOF
}
# The high-level flow:
# 1.) Resolve the Pants version from pants.ini or from the latest stable
# release to PyPi, so that we know what to name the venv folder and which
# Python versions we can use.
# 2.) Resolve the Python interpreter, first reading from the env var $PYTHON,
# then reading from pants.ini, then determining the default based off of
# which Python versions the Pants version supports.
# 3.) Check if the venv (virtual environment) already exists via a naming/path convention,
# and create the venv if not found.
# 4.) Execute Pants with the resolved Python interpreter and venv.
#
# After that, Pants itself will handle making sure any requested plugins
# are installed and up to date.
function determine_pants_version {
pants_version="$(get_pants_ini_config_value 'pants_version')"
if [[ -n "${pants_version}" ]]; then
echo "${pants_version}"
else
curl -sSL https://pypi.python.org/pypi/pantsbuild.pants/json |
python -c "import json, sys; print(json.load(sys.stdin)['info']['version'])"
fi
}
function determine_default_python_exe {
pants_version="$1"
pants_major_version="$(echo "${pants_version}" | cut -d '.' -f1)"
pants_minor_version="$(echo "${pants_version}" | cut -d '.' -f2)"
if [[ "${pants_major_version}" -eq 1 && "${pants_minor_version}" -le 14 ]]; then
supported_python_versions=('2.7')
supported_message='2.7'
elif [[ "${pants_major_version}" -eq 1 && "${pants_minor_version}" -eq 15 ]]; then
supported_python_versions=('3.6' '2.7')
supported_message='2.7 or 3.6'
elif [[ "${pants_major_version}" -eq 1 && "${pants_minor_version}" -eq 16 ]]; then
supported_python_versions=('3.6' '3.7' '2.7')
supported_message='2.7, 3.6, or 3.7'
elif [[ "${pants_major_version}" -eq 1 && "${pants_minor_version}" -eq 17 ]]; then
supported_python_versions=('3.6' '3.7' '3.8' '3.9')
supported_message='3.6+'
else
supported_python_versions=('3.9' '3.8' '3.7' '3.6')
supported_message='3.6+'
fi
for version in "${supported_python_versions[@]}"; do
command -v "python${version}" && return 0
done
die "No valid Python interpreter found. For this Pants version, Pants requires Python ${supported_message}."
}
function determine_python_exe {
pants_version="$1"
if [[ "${PYTHON_BIN_NAME}" != 'unspecified' ]]; then
python_bin_name="${PYTHON_BIN_NAME}"
else
interpreter_version="$(get_pants_ini_config_value 'pants_runtime_python_version')"
if [[ -n "${interpreter_version}" ]]; then
python_bin_name="python${interpreter_version}"
else
python_bin_name="$(determine_default_python_exe "${pants_version}")"
fi
fi
get_exe_path_or_die "${python_bin_name}"
}
# 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 "${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)"
pants_version="$(determine_pants_version)"
python="$(determine_python_exe "${pants_version}")"
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" "$@"