-
Notifications
You must be signed in to change notification settings - Fork 2
/
30_get-pipenv
309 lines (272 loc) · 10.5 KB
/
30_get-pipenv
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
#!/usr/bin/env bash
# This script should not be sourced, but called, or else bad things could happen.
#*# docker/recipes/get-pipenv
# Temp fix for https://github.com/pypa/virtualenv/issues/1949
if [ -f "${VSI_COMMON_DIR-}/linux/real_path" ]; then
source "${VSI_COMMON_DIR}/linux/real_path"
else
if command -v realpath > /dev/null 2>&1; then
function real_path()
{
realpath ${@+"${@}"}
}
elif readlink -f / > /dev/null 2>&1; then
function real_path()
{
readlink -f ${@+"${@}"}
}
else
function real_path()
{
for x in "${@}"; do
real_path_manual "${x}"
done
}
fi
function real_path_manual()
{
pushd "$(dirname "${1}")" &> /dev/null
local target="$(basename "${1}")"
while [ -L "${target}" ]
do
target="$(readlink "${target}")"
cd "$(dirname "${target}")"
target="$(basename "${target}")"
done
local physical_dir="$(pwd -P)"
if [ "${target}" = "." ]; then
target=""
else
target="/${target}"
fi
popd &> /dev/null
if [ "${physical_dir}" = "/" ]; then
if [ "${target}" = "//" ] || [ "${target}" = "" ]; then
echo /
else
echo "${target}"
fi
else
echo "${physical_dir}${target}"
fi
}
fi
# download to file: ${VSI_COMMON_DIR}/linux/web_tools.bsh be available, use that. Otherwise, necessary functions for download_to_file (for wget, curl, & python options) are copied from web_tools.bsh.
if [ -f "${VSI_COMMON_DIR-}/linux/web_tools.bsh" ]; then
source "${VSI_COMMON_DIR}/linux/web_tools.bsh"
else
# download to stdout using wget
function download_to_stdout_wget()
{
if command -v "${WGET-wget}" &> /dev/null; then
"${WGET-wget}" ${WGET_ARGS[@]+"${WGET_ARGS[@]}"} "${1}" -qO - && return || return
fi
return 100
}
# download to stdout using curl
function download_to_stdout_curl()
{
if command -v "${CURL-curl}" &> /dev/null; then
"${CURL-curl}" ${CURL_ARGS[@]+"${CURL_ARGS[@]}"} -fsSL "${1}" && return || return
fi
return 100
}
# download to stdout using python
function download_to_stdout_python()
{
if command -v "${PYTHON-python}" &> /dev/null; then
"${PYTHON-python}" -c 'if True:
try:
import requests
os.write(1, requests.get("'"${1}"'").content)
except:
try:
import urllib2 as u
except:
import urllib.request as u
import os
os.write(1,u.urlopen("'"${1}"'").read())' && return || return
fi
return 100
}
# download to file using python
function download_to_file_python()
{
local python
local success=100
for python in "${PYTHON-}" python3 python python2; do
if command -v "${python}" &> /dev/null; then
PYTHON="${python}" download_to_stdout_python "${1}" > "${2}" && return || success="${?}"
fi
done
return ${success}
}
function download_to_stdout_ruby() { return 100; }
function download_to_stdout_perl() { return 100; }
# download to file (try wget, then curl, then python)
function download_to_file()
{
local found=100
local rv
download_to_stdout_wget "${1}" > "${2}" && return || rv="${?}"
if [ "${rv}" != "100" ]; then
found="${rv}"
fi
download_to_stdout_curl "${1}" > "${2}" && return || rv="${?}"
if [ "${rv}" != "100" ]; then
found="${rv}"
fi
download_to_file_python "${1}" "${2}" && return || rv="${?}"
if [ "${rv}" != "100" ]; then
found="${rv}"
fi
download_to_stdout_ruby "${1}" > "${2}" && return || rv="${?}"
if [ "${rv}" != "100" ]; then
found="${rv}"
fi
download_to_stdout_perl "${1}" > "${2}" && return || rv="${?}"
if [ "${rv}" != "100" ]; then
found="${rv}"
fi
return "${found}"
}
fi
#**
# .. default-domain:: bash
#
# .. _get_pipenv:
#
# ==========
# Get Pipenv
# ==========
#
# .. file:: get_pipenv
#
# Functions to help install pipenv with only python installed and no elevated privileges, no ``pip`` or ``sudo`` required
#
# .. function:: install_pipenv
#
# Install pipenv into a virtualenv. Does not need to have pip already installed and does not use privileged permissions. Makes use of the virtualenv zipapp, as per https://virtualenv.pypa.io/en/latest/installation.html#via-zipapp
#
# While virtualenv documentation recommends download of the virtualenv zipapp file from https://bootstrap.pypa.io/virtualenv, this script instead downloads from https://github.com/pypa/get-virtualenv/ which offered versioned zipapp files. This avoids possible breaking changes introduced at the pypa bootstrap site.
#
# Prefer use of ``RECIPE_*`` environment variables (e.g., prefer ``RECIPE_PIPENV_VERSION`` over ``PIPENV_VERSION``). Pipenv uses ``PIPENV_{FLAG_NAME}`` to control command line execution via environment variables, as per https://github.com/pypa/pipenv/blob/master/CHANGELOG.rst#features--improvements-4. Use of ``PIPENV_VERSION`` to control the installed pipenv version may cause subsequent calls to pipenv to fail with the error ``Error: Invalid value for '--version': 2020.11.15 is not a valid boolean``.
#
# Environment variables not starting with ``RECIPE_*`` may be deprecated in the future.
#
# :Arguments: [``$1``] - The location of the virtualenv, defaults to ``${RECIPE_PIPENV_VIRTUALENV-${PIPENV_VIRTUALENV-${HOME}/pipenv}}``
# :Parameters: * ``RECIPE_PIPENV_PYTHON`` or ``PIPENV_PYTHON`` - Optionally specify which python you want to use. Default is to favor python3, trying ``python3``, ``python``, then finally falling back to ``python2``.
# * ``RECIPE_PIPENV_VERSION`` or ``PIPENV_VERSION`` - The version of pipenv to install, defaults - ``2022.1.8``
# * ``RECIPE_VIRTUALENV_PYZ`` or ``VIRTUALENV_PYZ`` - Name of downloaded ``virtualenv.pyz``, else it will attempt to download it itself.
# * ``RECIPE_VIRTUALENV_VERSION`` or ``VIRTUALENV_VERSION`` - The version of virtualenv to use, affecting both the virtualenv zipapp version and the virtualenv version used by pipenv environment. defaults to ``20.13.3``
#
#**
install_pipenv()
{
# python executable
local python_exe="${RECIPE_PIPENV_PYTHON:-${PIPENV_PYTHON:-"$( (command -v python3 || command -v python || command -v python2) | head -n 1)"}}"
# Make sure python was found
if [ -z "${python_exe}" ]; then
echo "install_pipenv cannot find python executable. Try setting RECIPE_PIPENV_PYTHON to point to python" >&2
return 1
fi
# setup
local output_dir="${1-${RECIPE_PIPENV_VIRTUALENV-${PIPENV_VIRTUALENV-${HOME}/pipenv}}}"
local pipenv_ver="${RECIPE_PIPENV_VERSION:-${PIPENV_VERSION:-2022.1.8}}"
local virtualenv_pyz="${RECIPE_VIRTUALENV_PYZ:-${VIRTUALENV_PYZ:-}}"
local virtualenv_version="${RECIPE_VIRTUALENV_VERSION:-${VIRTUALENV_VERSION:-20.13.3}}"
# use existing virtualenv
virtualenv_ver="$("${python_exe}" -m virtualenv --version 2>/dev/null || :)"
if [ -n "${virtualenv_ver}" ]; then
echo "Found virtualenv (${virtualenv_ver})" >&2
"${python_exe}" -m virtualenv "${output_dir}"
# use virtualenv zipapp
# https://virtualenv.pypa.io/en/latest/installation.html#via-zipapp
else
echo "Using virtualenv zipapp" >&2
# temporary directory
local tmp_dir="$(mktemp -d)"
# download virtualenv_pyz
if [ ! -r "${virtualenv_pyz}" ]; then
# source url
# download versioned virtualenv.pyz from github
# https://github.com/pypa/virtualenv/issues/1930#issuecomment-683390781
#
# Download top-level zipapp, as python verioned zipapps are symlinked to the top-level file (for now)
# https://github.com/pypa/get-virtualenv/issues/1#issuecomment-580811273
local url="https://github.com/pypa/get-virtualenv/raw/${virtualenv_version}/public/virtualenv.pyz"
echo "Download virtualenv zipapp from <${url}>" >&2
# download to file
virtualenv_pyz="${tmp_dir}/virtualenv.pyz"
PYTHON="${python_exe}" download_to_file "${url}" "${virtualenv_pyz}"
fi
# Temp fix for https://github.com/pypa/virtualenv/issues/1949
virtualenv_pyz="$(real_path "${virtualenv_pyz}")"
# create output virtualenv
"${python_exe}" "${virtualenv_pyz}" "${output_dir}"
# cleanup
rm -rf "${tmp_dir}" || :
# "rm -f" and "|| :" handles cases like `this <https://github.com/moby/moby/issues/27358>`_
fi
# add pipenv to output virtualenv
local output_pip
if [ "${OS-}" = "Windows_NT" ]; then
output_pip="${output_dir}/Scripts/pip"
else
output_pip="${output_dir}/bin/pip"
fi
"${output_pip}" install --no-cache-dir \
virtualenv=="${virtualenv_version}" \
pipenv=="${pipenv_ver}"
}
#**
# .. function:: setup_container_pipenv
#
# Sets up some additional behavior, useful in a container. Creates a symlink in the path to ``pipenv`` and adds a ``fake_package`` script to the bin directory for faking out local packages in pipenv during container build stages.
#
# :Arguments: * [``$1``] - The location of the virtualenv, defaults to ``${HOME}/pipenv``
# * [``$2``] - The location of the symlink for pipenv, defaults to ``/usr/local/bin/pipenv``
#**
setup_container_pipenv()
{
local virtualenv_dir="${1-${RECIPE_PIPENV_VIRTUALENV-${PIPENV_VIRTUALENV-${HOME}/pipenv}}}"
ln -s "${virtualenv_dir}/bin/pipenv" "${2-/usr/local/bin/pipenv}"
cat - > "${virtualenv_dir}/bin/fake_package" << "EOF"
#!/usr/bin/env sh
set -eu
# Useful for creating a fake editable package for when you plan on mounting it
# in at runtime
# $1 - name
# $2 - subdir
mkdir -p "${2-${1}}"
touch "${2-${1}}/init.py"
if [ ! -e "setup.py" ]; then
echo "from distutils.core import setup" > setup.py
echo "setup(name='${1}', packages=['${2-${1}}'], description='Project')" >> setup.py
fi
EOF
chmod 755 "${virtualenv_dir}/bin/fake_package"
}
if [ -n "${BASH_SOURCE+set}" ]; then
if [ "${BASH_SOURCE[0]}" = "${0}" ] || [ "$(basename "${BASH_SOURCE[0]}")" = "${0}" ]; then
set -eu
install_pipenv ${@+"${@}"}
setup_container_pipenv ${@+"${@}"}
# Self delete this file, so that pipenv doesn't try to get installed twice if
# /usr/local/share/just/container_build_patch/* is called twice
exec bash -c "rm '${BASH_SOURCE[0]}'"
fi
else
case "${0}" in
*30_get-pipenv) # Ran
set -eu
install_pipenv ${@+"${@}"}
setup_container_pipenv ${@+"${@}"}
# sh doesn't have BASH_SOURCE or exact equivalent, this is closest, unless
# they are sourcing it, then bad things can happen, hence the guards
exec bash -c "rm '${0}'"
;;
*sh) # Sourced for sh/dash/etc...
;;
esac
fi