Skip to content

Commit 5ad3f6f

Browse files
[python] - cpython - prev. version fallback - fix (#907)
* [python] - cpython - prev. version fallback - fix * according to comments
1 parent a674273 commit 5ad3f6f

4 files changed

Lines changed: 441 additions & 20 deletions

File tree

src/python/devcontainer-feature.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"id": "python",
3-
"version": "1.4.1",
3+
"version": "1.4.2",
44
"name": "Python",
55
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/python",
66
"description": "Installs the provided version of Python, as well as PIPX, and other common Python utilities. JupyterLab is conditionally installed with the python feature. Note: May require source code compilation.",

src/python/install.sh

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,48 @@ find_version_from_git_tags() {
248248
echo "${variable_name}=${!variable_name}"
249249
}
250250

251+
# Use semver logic to decrement a version number then look for the closest match
252+
find_prev_version_from_git_tags() {
253+
local variable_name=$1
254+
local current_version=${!variable_name}
255+
local repository=$2
256+
# Normally a "v" is used before the version number, but support alternate cases
257+
local prefix=${3:-"tags/v"}
258+
# Some repositories use "_" instead of "." for version number part separation, support that
259+
local separator=${4:-"."}
260+
# Some tools release versions that omit the last digit (e.g. go)
261+
local last_part_optional=${5:-"false"}
262+
# Some repositories may have tags that include a suffix (e.g. actions/node-versions)
263+
local version_suffix_regex=$6
264+
# Try one break fix version number less if we get a failure. Use "set +e" since "set -e" can cause failures in valid scenarios.
265+
set +e
266+
major="$(echo "${current_version}" | grep -oE '^[0-9]+' || echo '')"
267+
minor="$(echo "${current_version}" | grep -oP '^[0-9]+\.\K[0-9]+' || echo '')"
268+
breakfix="$(echo "${current_version}" | grep -oP '^[0-9]+\.[0-9]+\.\K[0-9]+' 2>/dev/null || echo '')"
269+
270+
if [ "${minor}" = "0" ] && [ "${breakfix}" = "0" ]; then
271+
((major=major-1))
272+
declare -g ${variable_name}="${major}"
273+
# Look for latest version from previous major release
274+
find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}"
275+
# Handle situations like Go's odd version pattern where "0" releases omit the last part
276+
elif [ "${breakfix}" = "" ] || [ "${breakfix}" = "0" ]; then
277+
((minor=minor-1))
278+
declare -g ${variable_name}="${major}.${minor}"
279+
# Look for latest version from previous minor release
280+
find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}"
281+
else
282+
((breakfix=breakfix-1))
283+
if [ "${breakfix}" = "0" ] && [ "${last_part_optional}" = "true" ]; then
284+
declare -g ${variable_name}="${major}.${minor}"
285+
else
286+
declare -g ${variable_name}="${major}.${minor}.${breakfix}"
287+
fi
288+
fi
289+
set -e
290+
}
291+
292+
251293
# Use Oryx to install something using a partial version match
252294
oryx_install() {
253295
local platform=$1
@@ -368,6 +410,29 @@ install_openssl3() {
368410
rm -rf /tmp/openssl3
369411
}
370412

413+
install_prev_vers_cpython() {
414+
VERSION=$1
415+
echo -e "\n(!) Failed to fetch the latest artifacts for cpython ${VERSION}..."
416+
find_prev_version_from_git_tags VERSION https://github.com/python/cpython
417+
echo -e "\nAttempting to install ${VERSION}"
418+
install_cpython "${VERSION}"
419+
}
420+
421+
install_cpython() {
422+
VERSION=$1
423+
INSTALL_PATH="${PYTHON_INSTALL_PATH}/${VERSION}"
424+
if [ -d "${INSTALL_PATH}" ]; then
425+
echo "(!) Python version ${VERSION} already exists."
426+
exit 1
427+
fi
428+
mkdir -p /tmp/python-src ${INSTALL_PATH}
429+
cd /tmp/python-src
430+
cpython_tgz_filename="Python-${VERSION}.tgz"
431+
cpython_tgz_url="https://www.python.org/ftp/python/${VERSION}/${cpython_tgz_filename}"
432+
echo "Downloading ${cpython_tgz_filename}..."
433+
curl -sSL -o "/tmp/python-src/${cpython_tgz_filename}" "${cpython_tgz_url}"
434+
}
435+
371436
install_from_source() {
372437
VERSION=$1
373438
echo "(*) Building Python ${VERSION} from source..."
@@ -378,13 +443,6 @@ install_from_source() {
378443
# Find version using soft match
379444
find_version_from_git_tags VERSION "https://github.com/python/cpython"
380445

381-
INSTALL_PATH="${PYTHON_INSTALL_PATH}/${VERSION}"
382-
383-
if [ -d "${INSTALL_PATH}" ]; then
384-
echo "(!) Python version ${VERSION} already exists."
385-
exit 1
386-
fi
387-
388446
# Some platforms/os versions need modern versions of openssl installed
389447
# via common package repositories, for now rhel-7 family, use case statement to
390448
# make it easy to expand
@@ -396,23 +454,21 @@ install_from_source() {
396454
;;
397455
esac
398456

399-
# Download tgz of source
400-
mkdir -p /tmp/python-src ${INSTALL_PATH}
401-
cd /tmp/python-src
402-
local tgz_filename="Python-${VERSION}.tgz"
403-
local tgz_url="https://www.python.org/ftp/python/${VERSION}/${tgz_filename}"
404-
echo "Downloading ${tgz_filename}..."
405-
curl -sSL -o "/tmp/python-src/${tgz_filename}" "${tgz_url}"
406-
457+
install_cpython "${VERSION}"
458+
if [ -f "/tmp/python-src/${cpython_tgz_filename}" ]; then
459+
if grep -q "404 Not Found" "/tmp/python-src/${cpython_tgz_filename}"; then
460+
install_prev_vers_cpython "${VERSION}"
461+
fi
462+
fi;
407463
# Verify signature
408464
if [[ ${VERSION_CODENAME} = "centos7" ]] || [[ ${VERSION_CODENAME} = "rhel7" ]]; then
409465
receive_gpg_keys_centos7 PYTHON_SOURCE_GPG_KEYS
410466
else
411467
receive_gpg_keys PYTHON_SOURCE_GPG_KEYS
412468
fi
413-
echo "Downloading ${tgz_filename}.asc..."
414-
curl -sSL -o "/tmp/python-src/${tgz_filename}.asc" "${tgz_url}.asc"
415-
gpg --verify "${tgz_filename}.asc"
469+
echo "Downloading ${cpython_tgz_filename}.asc..."
470+
curl -sSL -o "/tmp/python-src/${cpython_tgz_filename}.asc" "${cpython_tgz_url}.asc"
471+
gpg --verify "${cpython_tgz_filename}.asc"
416472

417473
# Update min protocol for testing only - https://bugs.python.org/issue41561
418474
if [ -f /etc/pki/tls/openssl.cnf ]; then
@@ -424,7 +480,7 @@ install_from_source() {
424480
export OPENSSL_CONF=/tmp/python-src/openssl.cnf
425481

426482
# Untar and build
427-
tar -xzf "/tmp/python-src/${tgz_filename}" -C "/tmp/python-src" --strip-components=1
483+
tar -xzf "/tmp/python-src/${cpython_tgz_filename}" -C "/tmp/python-src" --strip-components=1
428484
local config_args=""
429485
if [ "${OPTIMIZE_BUILD_FROM_SOURCE}" = "true" ]; then
430486
config_args="${config_args} --enable-optimizations"

0 commit comments

Comments
 (0)