-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpactivate
181 lines (167 loc) · 8.12 KB
/
pactivate
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
# pactivate version 0.5.7 https://github.com/cynic-net/pactivate
# https://stackoverflow.com/a/28776166/107294
# This test works only with Bash, not sh, ksh or zsh, which do not
# check for this `return` error. ksh and zsh users who run this will
# (perhaps mysteriously) find their virtualenv not activated.
# (Virtualenv's bin/activate script has the same issue.)
(return 0 2>/dev/null) \
|| { echo 1>&2 "don't run pactivate, source (.) it."; exit 9; }
# This uses various Bashisms, such as `[[`, and so requires a reasonably
# Bash-compatible shell. As far as we know, these are just ksh and zsh,
# so fail immediately if we're not running on Bash or one of those.
[ -n "${BASH_VERSION-}""${KSH_VERSION-}""${ZSH_VERSION-}" ] || {
echo 1>&2 "source (.) this with bash, ksh or zsh."
# Here we don't know if the "being sourced" check above succeeded, so
# we first do a `return` which will exit if we're being sourced, and
# then an `exit` which will exit if the return failed because we're
# not being sourced.
return 9
exit 9
}
# This has seen very limited testing under ksh or zsh (the test framework
# doesn't test under these shells at all), so print a warning to help
# with debugging issues reported by users.
[ -n "$BASH_VERSION" ] || { echo 1>&2 \
"WARNING: You're not using Bash. Let's hope you're compatible!"; }
__pa_cleanup() {
unset __pa_cleanup __pa_echo \
__pa_builddir __pa_quiet __pa_python __pa_python_deref __pa_pyver \
__pa_bootdir __pa_basedir __pa_requirements
}
__pa_echo() { [[ -n $__pa_quiet ]] || echo "$@"; }
__pa_basedir=$(cd "$(dirname "$BASH_SOURCE")" && pwd -P)
__pa_builddir=
__pa_quiet=
while [[ $# -gt 0 ]]; do case "$1" in
-b) shift; __pa_builddir="$1"; shift;;
-B) shift; __pa_basedir="$1"; shift;;
-q) shift; __pa_quiet=-q;;
*) echo 1>&2 "pactivate: unknown argument: $1"; __pa_cleanup; return 2;;
esac; done;
if [[ -e $__pa_basedir/.python || -L $__pa_basedir/.python ]]; then
# Even if it's a dangling link (-e fails) we use it so that the
# user sees the error.
__pa_python=$__pa_basedir/.python
else
# We test `py` only in Windows/MINGW because the Unix `py` program
# (from the pythonpy package) is a different thing we never want to use.
for __pa_python in ${MSYSTEM:+py} python3 python PYTHON_NOT_FOUND; do
"$__pa_python" --version >/dev/null 2>&1 && break
done
fi
"$__pa_python" --version >/dev/null 2>&1 || {
[[ -L $__pa_python ]] \
&& echo "$__pa_python -> $(readlink "$__pa_python")"
$__pa_python --version || true # Display the suppressed error message
echo 1>&2 "pactivate: bad python interpreter"
__pa_cleanup; return 3
}
# $__pa_pyver is empty for "modern" versions of Python (i.e., those that
# can use the current get-pip.py, 3.8 and above) and otherwise is the
# major.minor revision number, suitable for use in the URL to download
# an alternate version of get-pip.py.
__pa_pyver=$("$__pa_python" -c '
# Reminder: this script must be compatible with Python 2 syntax.
import sys
M, m = sys.version_info[0], sys.version_info[1] # Major, minor
if (M < 3 or (M == 3 and m < 8)):
print("{}.{}".format(M, m))
')
__pa_requirements="$__pa_basedir/requirements.txt"
[[ -z $__pa_builddir ]] && __pa_builddir=$(cd "$__pa_basedir" && pwd -P)/.build
__pa_bootdir="$__pa_builddir/bootstrap/pactivate${__pa_pyver}"
mkdir -p "$__pa_bootdir" # also ensures that $__pa_builddir exists
# Unlike virtualenv, pip -t does not change the bin/ directory to
# Scripts/ on Windows, so we can hardcode our bootstrap/bin/pip path.
[[ -x $__pa_bootdir/bin/pip ]] || {
echo "----- Installing bootstrap pip (ver=${__pa_pyver:-latest})"
# Debian-based systems do not incude distutils in the standard
# python3 package; check that it's available and, if not, print a
# more informative message than the ModuleNotFoundError.
"$__pa_python" -c '
import sys
M, m = sys.version_info[0], sys.version_info[1] # Major, minor
if (M < 3 or (M == 3 and m < 11)): import distutils.cmd # deprecated ≥3.11
' || {
echo 1>&2 \
"Cannot import 'distuils.cmd'; apt-get install python3-distutils?"
return 3
}
# • get-pip.py produces spurious upgrade notices on older Python versions
# such as 3.6 or 2.7; --disable-pip-version-check suppresses these.
# • curl sometimes seems to resolve only an IPv6 for bootstrap.pypa.io;
# on failure try again forcing IPv4.
curl '-#' ${__pa_quiet:+--silent} \
"https://bootstrap.pypa.io/pip/$__pa_pyver/get-pip.py" \
| "$__pa_python" - \
$__pa_quiet -t "$__pa_bootdir" --disable-pip-version-check \
|| curl --ipv4 '-#' ${__pa_quiet:+--silent} \
"https://bootstrap.pypa.io/pip/$__pa_pyver/get-pip.py" \
| "$__pa_python" - \
$__pa_quiet -t "$__pa_bootdir" --disable-pip-version-check \
|| return $?
PYTHONPATH="$__pa_bootdir" "$__pa_bootdir/bin/pip" --version
}
[[ -d $__pa_bootdir/virtualenv/ ]] || {
echo '----- Installing bootstrap virtualenv'
# This install produces spurious "bootstrap/.../bin already exists"
# messages; --upgrade suppresses these. However, --upgrade also seems
# to entirely remove the bin/ directory, so we "re-install" pip
# (which will not re-download it) to restore bin/pip as well.
# Note that we _must_ use `python -m pip` because, on Windows due to
# file locking, pip is unable to replace itself if you run it as pip.exe.
PYTHONPATH="$__pa_bootdir" "$__pa_python" -m pip \
$__pa_quiet install --upgrade -t "$__pa_bootdir" pip virtualenv
}
[[ -d $__pa_builddir/virtualenv/ ]] || {
echo '----- Building virtualenv'
echo -n "Using $__pa_python"
if [[ -L $__pa_python ]]; then
# MacOS readlink has no -f option, so we must do this the hard
# way. Fortunately we already know that the binary exists and is
# a Python interpreter.
__pa_python_deref=$(readlink "$__pa_python")
__pa_python_deref=$(cd "$__pa_basedir" \
&& cd $(dirname "$__pa_python_deref") \
&& pwd -P)/$(basename "$__pa_python_deref")
echo " -> $__pa_python_deref"
else
__pa_python_deref="$__pa_python"
echo
fi
echo -n "Version: " && "$__pa_python" --version
# 1. Use virtualenv to create the new virtualenv.
# 2. Upgrade pip to the latest version, because often the get_pip.py
# version is old enough that we'll get annoying upgrade messages
# with every use if we don't do this. To reduce output size, we
# do this quietly and display the new version after. (The old
# version is displayed in the virtualenv creation output.)
# 3. If we have a requirements file, install its contents.
# Note that we _must_ use `python -m pip` because, on Windows due to
# file locking, pip is unable to replace itself if you run it as pip.exe.
PYTHONPATH="$__pa_bootdir" "$__pa_python_deref" -s -m virtualenv \
$__pa_quiet --prompt $(basename "$__pa_basedir") \
"$__pa_builddir/virtualenv/" \
&& "$__pa_builddir"/virtualenv/[bS]*/python -m pip install -q -U pip \
&& "$__pa_builddir"/virtualenv/[bS]*/pip --version \
&& [[ -f "$__pa_requirements" ]] \
&& "$__pa_builddir"/virtualenv/[bS]*/pip \
install $__pa_quiet -r "$__pa_requirements"
}
# On Windows when we're using the default `py` "interpreter," we're
# actually using a program that selects a Python interpreter. The
# selected interpreter will be the binary installed into Scripts/python
# in the virtualenv, but that's obviously not the py program, so the
# following check would always fail.
[[ $__pa_python == py ]] \
|| cmp -s "$(type -p "$__pa_python")" \
"$__pa_builddir"/virtualenv/[bS]*/python \
|| (
echo 1>&2 "WARNING:" \
"${__pa_builddir#$__pa_basedir/}"/virtualenv/[bS]*/python \
"($("$__pa_builddir"/virtualenv/[bS]*/python --version 2>&1))" \
"is not $__pa_python" \
"($("$__pa_python" --version 2>&1))" \
)
. "$__pa_builddir"/virtualenv/[bS]*/activate
__pa_cleanup