Commit 6696a919 authored by xiezhi's avatar xiezhi

multi version support

parent aa4e1721
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"name": "Python 3.10 Development Environment", "name": "Python 3.10 Development Environment",
"image": "hb.eazytec-cloud.com/eazytec/eazydevelop-base:ubuntu", "image": "hb.eazytec-cloud.com/eazytec/eazydevelop-base:ubuntu",
"features": { "features": {
"ghcr.io/devcontainers/features/python:1.7.1": { "./python": {
"version": "3.10", "version": "3.10",
"installTools": true, "installTools": true,
"toolsToInstall": "black,flake8,mypy,pytest,pylint" "toolsToInstall": "black,flake8,mypy,pytest,pylint"
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"name": "Python Development Environment", "name": "Python Development Environment",
"image": "hb.eazytec-cloud.com/eazytec/eazydevelop-base:ubuntu", "image": "hb.eazytec-cloud.com/eazytec/eazydevelop-base:ubuntu",
"features": { "features": {
"ghcr.io/devcontainers/features/python:1.7.1": { "./python": {
"version": "3.11", "version": "3.11",
"installTools": true, "installTools": true,
"toolsToInstall": "black,flake8,mypy,pytest,pylint" "toolsToInstall": "black,flake8,mypy,pytest,pylint"
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"name": "Python 3.12 Development Environment", "name": "Python 3.12 Development Environment",
"image": "hb.eazytec-cloud.com/eazytec/eazydevelop-base:ubuntu", "image": "hb.eazytec-cloud.com/eazytec/eazydevelop-base:ubuntu",
"features": { "features": {
"ghcr.io/devcontainers/features/python:1.7.1": { "./python": {
"version": "3.12", "version": "3.12",
"installTools": true, "installTools": true,
"toolsToInstall": "black,flake8,mypy,pytest,pylint" "toolsToInstall": "black,flake8,mypy,pytest,pylint"
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"name": "Python 3.9 Development Environment", "name": "Python 3.9 Development Environment",
"image": "hb.eazytec-cloud.com/eazytec/eazydevelop-base:ubuntu", "image": "hb.eazytec-cloud.com/eazytec/eazydevelop-base:ubuntu",
"features": { "features": {
"ghcr.io/devcontainers/features/python:1.7.1": { "./python": {
"version": "3.9", "version": "3.9",
"installTools": true, "installTools": true,
"toolsToInstall": "black,flake8,mypy,pytest,pylint" "toolsToInstall": "black,flake8,mypy,pytest,pylint"
......
## OS Support
This Feature should work on recent versions of Debian/Ubuntu, RedHat Enterprise Linux, Fedora, Alma, and RockyLinux distributions with the apt, yum, dnf, or microdnf package manager installed.
`bash` is required to execute the `install.sh` script.
# Python (python)
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.
## Example Usage
```json
"features": {
"ghcr.io/devcontainers/features/python:1": {}
}
```
## Options
| Options Id | Description | Type | Default Value |
|-----|-----|-----|-----|
| version | Select a Python version to install. | string | os-provided |
| installTools | Flag indicating whether or not to install the tools specified via the 'toolsToInstall' option. Default is 'true'. | boolean | true |
| toolsToInstall | Comma-separated list of tools to install when 'installTools' is true. Defaults to a set of common Python tools like pylint. | string | flake8,autopep8,black,yapf,mypy,pydocstyle,pycodestyle,bandit,pipenv,virtualenv,pytest,pylint |
| optimize | Optimize Python for performance when compiled (slow) | boolean | false |
| enableShared | Enable building a shared Python library | boolean | false |
| installPath | The path where python will be installed. | string | /usr/local/python |
| installJupyterlab | Install JupyterLab, a web-based interactive development environment for notebooks | boolean | false |
| configureJupyterlabAllowOrigin | Configure JupyterLab to accept HTTP requests from the specified origin | string | - |
| httpProxy | Connect to GPG keyservers using a proxy for fetching source code signatures by configuring this option | string | - |
## Customizations
### VS Code Extensions
- `ms-python.python`
- `ms-python.vscode-pylance`
- `ms-python.autopep8`
## OS Support
This Feature should work on recent versions of Debian/Ubuntu, RedHat Enterprise Linux, Fedora, Alma, and RockyLinux distributions with the apt, yum, dnf, or microdnf package manager installed.
`bash` is required to execute the `install.sh` script.
---
_Note: This file was auto-generated from the [devcontainer-feature.json](https://github.com/devcontainers/features/blob/main/src/python/devcontainer-feature.json). Add additional notes to a `NOTES.md`._
{
"id": "python",
"version": "1.7.1",
"name": "Python",
"documentationURL": "https://github.com/devcontainers/features/tree/main/src/python",
"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.",
"options": {
"version": {
"type": "string",
"proposals": [
"latest",
"os-provided",
"none",
"3.12",
"3.11",
"3.10",
"3.9",
"3.8",
"3.7",
"3.6"
],
"default": "os-provided",
"description": "Select a Python version to install."
},
"installTools": {
"type": "boolean",
"default": true,
"description": "Flag indicating whether or not to install the tools specified via the 'toolsToInstall' option. Default is 'true'."
},
"toolsToInstall": {
"type": "string",
"default": "flake8,autopep8,black,yapf,mypy,pydocstyle,pycodestyle,bandit,pipenv,virtualenv,pytest,pylint",
"description": "Comma-separated list of tools to install when 'installTools' is true. Defaults to a set of common Python tools like pylint."
},
"optimize": {
"type": "boolean",
"default": false,
"description": "Optimize Python for performance when compiled (slow)"
},
"enableShared": {
"type": "boolean",
"default": false,
"description": "Enable building a shared Python library"
},
"installPath": {
"type": "string",
"default": "/usr/local/python",
"description": "The path where python will be installed."
},
"installJupyterlab": {
"type": "boolean",
"default": false,
"description": "Install JupyterLab, a web-based interactive development environment for notebooks"
},
"configureJupyterlabAllowOrigin": {
"type": "string",
"default": "",
"description": "Configure JupyterLab to accept HTTP requests from the specified origin"
},
"httpProxy": {
"type": "string",
"default": "",
"description": "Connect to GPG keyservers using a proxy for fetching source code signatures by configuring this option"
}
},
"containerEnv": {
"PYTHON_PATH": "/usr/local/python/current",
"PIPX_HOME": "/usr/local/py-utils",
"PIPX_BIN_DIR": "/usr/local/py-utils/bin",
"PATH": "/usr/local/python/current/bin:/usr/local/py-utils/bin:/usr/local/jupyter:${PATH}"
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"ms-python.autopep8"
],
"settings": {
"github.copilot.chat.codeGeneration.instructions": [
{
"text": "This dev container includes `python3` and `pip3` pre-installed and available on the `PATH`, along with the Python language extensions for Python development."
}
],
"python.defaultInterpreterPath": "/usr/local/python/current/bin/python",
"[python]": {
"editor.defaultFormatter": "ms-python.autopep8"
}
}
}
},
"installsAfter": [
"ghcr.io/devcontainers/features/common-utils",
"ghcr.io/devcontainers/features/oryx"
]
}
\ No newline at end of file
#!/usr/bin/env bash
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------
#
# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/python.md
# Maintainer: The VS Code and Codespaces Teams
PYTHON_VERSION="${VERSION:-"latest"}" # 'system' or 'os-provided' checks the base image first, else installs 'latest'
INSTALL_PYTHON_TOOLS="${INSTALLTOOLS:-"true"}"
SKIP_VULNERABILITY_PATCHING="${SKIPVULNERABILITYPATCHING:-"false"}"
OPTIMIZE_BUILD_FROM_SOURCE="${OPTIMIZE:-"false"}"
ENABLE_SHARED_FROM_SOURCE="${ENABLESHARED:-"false"}"
PYTHON_INSTALL_PATH="${INSTALLPATH:-"/usr/local/python"}"
OVERRIDE_DEFAULT_VERSION="${OVERRIDEDEFAULTVERSION:-"true"}"
export PIPX_HOME=${PIPX_HOME:-"/usr/local/py-utils"}
USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}"
UPDATE_RC="${UPDATE_RC:-"true"}"
USE_ORYX_IF_AVAILABLE="${USEORYXIFAVAILABLE:-"true"}"
INSTALL_JUPYTERLAB="${INSTALLJUPYTERLAB:-"false"}"
CONFIGURE_JUPYTERLAB_ALLOW_ORIGIN="${CONFIGUREJUPYTERLABALLOWORIGIN:-""}"
# Comma-separated list of python versions to be installed
# alongside PYTHON_VERSION, but not set as default.
ADDITIONAL_VERSIONS="${ADDITIONALVERSIONS:-""}"
# Comma-separated list of additional tools to be installed via pipx.
IFS="," read -r -a DEFAULT_UTILS <<< "${TOOLSTOINSTALL:-flake8,autopep8,black,yapf,mypy,pydocstyle,pycodestyle,bandit,pipenv,virtualenv,pytest}"
PYTHON_SOURCE_GPG_KEYS="64E628F8D684696D B26995E310250568 2D347EA6AA65421D FB9921286F5E1540 3A5CA953F73C700D 04C367C218ADD4FF 0EDDC5F26A45C816 6AF053F07D9DC8D2 C9BE28DEE6DF025C 126EB563A74B06BF D9866941EA5BBD71 ED9D77D5 A821E680E5FA6305"
KEYSERVER_PROXY="${HTTPPROXY:-"${HTTP_PROXY:-""}"}"
set -e
if [ "$(id -u)" -ne 0 ]; then
echo -e 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
exit 1
fi
# Bring in ID, ID_LIKE, VERSION_ID, VERSION_CODENAME
. /etc/os-release
# Get an adjusted ID independent of distro variants
MAJOR_VERSION_ID=$(echo ${VERSION_ID} | cut -d . -f 1)
if [ "${ID}" = "debian" ] || [ "${ID_LIKE}" = "debian" ]; then
ADJUSTED_ID="debian"
elif [[ "${ID}" = "rhel" || "${ID}" = "fedora" || "${ID}" = "mariner" || "${ID_LIKE}" = *"rhel"* || "${ID_LIKE}" = *"fedora"* || "${ID_LIKE}" = *"mariner"* ]]; then
ADJUSTED_ID="rhel"
if [[ "${ID}" = "rhel" ]] || [[ "${ID}" = *"alma"* ]] || [[ "${ID}" = *"rocky"* ]]; then
VERSION_CODENAME="rhel${MAJOR_VERSION_ID}"
else
VERSION_CODENAME="${ID}${MAJOR_VERSION_ID}"
fi
else
echo "Linux distro ${ID} not supported."
exit 1
fi
if [ "${ADJUSTED_ID}" = "rhel" ] && [ "${VERSION_CODENAME-}" = "centos7" ]; then
# As of 1 July 2024, mirrorlist.centos.org no longer exists.
# Update the repo files to reference vault.centos.org.
sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo
sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo
sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo
fi
# To find some devel packages, some rhel need to enable specific extra repos, but not on RedHat ubi images...
INSTALL_CMD_ADDL_REPO=""
if [ ${ADJUSTED_ID} = "rhel" ] && [ ${ID} != "rhel" ]; then
if [ ${MAJOR_VERSION_ID} = "8" ]; then
INSTALL_CMD_ADDL_REPOS="--enablerepo powertools"
elif [ ${MAJOR_VERSION_ID} = "9" ]; then
INSTALL_CMD_ADDL_REPOS="--enablerepo crb"
fi
fi
# Setup INSTALL_CMD & PKG_MGR_CMD
if type apt-get > /dev/null 2>&1; then
PKG_MGR_CMD=apt-get
INSTALL_CMD="${PKG_MGR_CMD} -y install --no-install-recommends"
elif type microdnf > /dev/null 2>&1; then
PKG_MGR_CMD=microdnf
INSTALL_CMD="${PKG_MGR_CMD} ${INSTALL_CMD_ADDL_REPOS} -y install --refresh --best --nodocs --noplugins --setopt=install_weak_deps=0"
elif type dnf > /dev/null 2>&1; then
PKG_MGR_CMD=dnf
INSTALL_CMD="${PKG_MGR_CMD} ${INSTALL_CMD_ADDL_REPOS} -y install --refresh --best --nodocs --noplugins --setopt=install_weak_deps=0"
else
PKG_MGR_CMD=yum
INSTALL_CMD="${PKG_MGR_CMD} ${INSTALL_CMD_ADDL_REPOS} -y install --noplugins --setopt=install_weak_deps=0"
fi
# Clean up
clean_up() {
case ${ADJUSTED_ID} in
debian)
rm -rf /var/lib/apt/lists/*
;;
rhel)
rm -rf /var/cache/dnf/* /var/cache/yum/*
rm -rf /tmp/yum.log
rm -rf ${GPG_INSTALL_PATH}
;;
esac
}
clean_up
updaterc() {
local _bashrc
local _zshrc
if [ "${UPDATE_RC}" = "true" ]; then
case $ADJUSTED_ID in
debian) echo "Updating /etc/bash.bashrc and /etc/zsh/zshrc..."
_bashrc=/etc/bash.bashrc
_zshrc=/etc/zsh/zshrc
;;
rhel) echo "Updating /etc/bashrc and /etc/zshrc..."
_bashrc=/etc/bashrc
_zshrc=/etc/zshrc
;;
esac
if [[ "$(cat ${_bashrc})" != *"$1"* ]]; then
echo -e "$1" >> ${_bashrc}
fi
if [ -f "${_zshrc}" ] && [[ "$(cat ${_zshrc})" != *"$1"* ]]; then
echo -e "$1" >> ${_zshrc}
fi
fi
}
# Get the list of GPG key servers that are reachable
get_gpg_key_servers() {
declare -A keyservers_curl_map=(
["hkp://keyserver.ubuntu.com"]="http://keyserver.ubuntu.com:11371"
["hkp://keyserver.ubuntu.com:80"]="http://keyserver.ubuntu.com"
["hkps://keys.openpgp.org"]="https://keys.openpgp.org"
["hkp://keyserver.pgp.com"]="http://keyserver.pgp.com:11371"
)
local curl_args=""
local keyserver_reachable=false # Flag to indicate if any keyserver is reachable
if [ ! -z "${KEYSERVER_PROXY}" ]; then
curl_args="--proxy ${KEYSERVER_PROXY}"
fi
for keyserver in "${!keyservers_curl_map[@]}"; do
local keyserver_curl_url="${keyservers_curl_map[${keyserver}]}"
if curl -s ${curl_args} --max-time 5 ${keyserver_curl_url} > /dev/null; then
echo "keyserver ${keyserver}"
keyserver_reachable=true
else
echo "(*) Keyserver ${keyserver} is not reachable." >&2
fi
done
if ! $keyserver_reachable; then
echo "(!) No keyserver is reachable." >&2
exit 1
fi
}
# Import the specified key in a variable name passed in as
receive_gpg_keys() {
local keys=${!1}
local keyring_args=""
local gpg_cmd="gpg"
if [ ! -z "$2" ]; then
mkdir -p "$(dirname \"$2\")"
keyring_args="--no-default-keyring --keyring $2"
fi
if [ ! -z "${KEYSERVER_PROXY}" ]; then
keyring_args="${keyring_args} --keyserver-options http-proxy=${KEYSERVER_PROXY}"
fi
# Install curl
if ! type curl > /dev/null 2>&1; then
check_packages curl
fi
# Use a temporary location for gpg keys to avoid polluting image
export GNUPGHOME="/tmp/tmp-gnupg"
mkdir -p ${GNUPGHOME}
chmod 700 ${GNUPGHOME}
echo -e "disable-ipv6\n$(get_gpg_key_servers)" > ${GNUPGHOME}/dirmngr.conf
# GPG key download sometimes fails for some reason and retrying fixes it.
local retry_count=0
local gpg_ok="false"
set +e
until [ "${gpg_ok}" = "true" ] || [ "${retry_count}" -eq "5" ];
do
echo "(*) Downloading GPG key..."
( echo "${keys}" | xargs -n 1 gpg -q ${keyring_args} --recv-keys) 2>&1 && gpg_ok="true"
if [ "${gpg_ok}" != "true" ]; then
echo "(*) Failed getting key, retrying in 10s..."
(( retry_count++ ))
sleep 10s
fi
done
set -e
if [ "${gpg_ok}" = "false" ]; then
echo "(!) Failed to get gpg key."
exit 1
fi
}
# RHEL7/CentOS7 has an older gpg that does not have dirmngr
# Iterate through keyservers until we have all the keys downloaded
receive_gpg_keys_centos7() {
local keys=${!1}
local keyring_args=""
local gpg_cmd="gpg"
if [ ! -z "$2" ]; then
mkdir -p "$(dirname \"$2\")"
keyring_args="--no-default-keyring --keyring $2"
fi
if [ ! -z "${KEYSERVER_PROXY}" ]; then
keyring_args="${keyring_args} --keyserver-options http-proxy=${KEYSERVER_PROXY}"
fi
# Install curl
if ! type curl > /dev/null 2>&1; then
check_packages curl
fi
# Use a temporary location for gpg keys to avoid polluting image
export GNUPGHOME="/tmp/tmp-gnupg"
mkdir -p ${GNUPGHOME}
chmod 700 ${GNUPGHOME}
# GPG key download sometimes fails for some reason and retrying fixes it.
local retry_count=0
local gpg_ok="false"
num_keys=$(echo ${keys} | wc -w)
set +e
echo "(*) Downloading GPG keys..."
until [ "${gpg_ok}" = "true" ] || [ "${retry_count}" -eq "5" ]; do
for keyserver in $(echo "$(get_gpg_key_servers)" | sed 's/keyserver //'); do
( echo "${keys}" | xargs -n 1 gpg -q ${keyring_args} --recv-keys --keyserver=${keyserver} ) 2>&1
downloaded_keys=$(gpg --list-keys | grep ^pub | wc -l)
if [[ ${num_keys} = ${downloaded_keys} ]]; then
gpg_ok="true"
break
fi
done
if [ "${gpg_ok}" != "true" ]; then
echo "(*) Failed getting key, retrying in 10s..."
(( retry_count++ ))
sleep 10s
fi
done
set -e
if [ "${gpg_ok}" = "false" ]; then
echo "(!) Failed to get gpg key."
exit 1
fi
}
# Figure out correct version of a three part version number is not passed
find_version_from_git_tags() {
local variable_name=$1
local requested_version=${!variable_name}
if [ "${requested_version}" = "none" ]; then return; fi
local repository=$2
local prefix=${3:-"tags/v"}
local separator=${4:-"."}
local last_part_optional=${5:-"false"}
if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then
local escaped_separator=${separator//./\\.}
local last_part
if [ "${last_part_optional}" = "true" ]; then
last_part="(${escaped_separator}[0-9]+)?"
else
last_part="${escaped_separator}[0-9]+"
fi
local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${last_part}$"
local version_list="$(git ls-remote --tags ${repository} | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)"
if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then
declare -g ${variable_name}="$(echo "${version_list}" | head -n 1)"
else
set +e
declare -g ${variable_name}="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")"
set -e
fi
fi
if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" > /dev/null 2>&1; then
echo -e "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2
exit 1
fi
echo "${variable_name}=${!variable_name}"
}
# Use semver logic to decrement a version number then look for the closest match
find_prev_version_from_git_tags() {
local variable_name=$1
local current_version=${!variable_name}
local repository=$2
# Normally a "v" is used before the version number, but support alternate cases
local prefix=${3:-"tags/v"}
# Some repositories use "_" instead of "." for version number part separation, support that
local separator=${4:-"."}
# Some tools release versions that omit the last digit (e.g. go)
local last_part_optional=${5:-"false"}
# Some repositories may have tags that include a suffix (e.g. actions/node-versions)
local version_suffix_regex=$6
# Try one break fix version number less if we get a failure. Use "set +e" since "set -e" can cause failures in valid scenarios.
set +e
major="$(echo "${current_version}" | grep -oE '^[0-9]+' || echo '')"
minor="$(echo "${current_version}" | grep -oP '^[0-9]+\.\K[0-9]+' || echo '')"
breakfix="$(echo "${current_version}" | grep -oP '^[0-9]+\.[0-9]+\.\K[0-9]+' 2>/dev/null || echo '')"
if [ "${minor}" = "0" ] && [ "${breakfix}" = "0" ]; then
((major=major-1))
declare -g ${variable_name}="${major}"
# Look for latest version from previous major release
find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}"
# Handle situations like Go's odd version pattern where "0" releases omit the last part
elif [ "${breakfix}" = "" ] || [ "${breakfix}" = "0" ]; then
((minor=minor-1))
declare -g ${variable_name}="${major}.${minor}"
# Look for latest version from previous minor release
find_version_from_git_tags "${variable_name}" "${repository}" "${prefix}" "${separator}" "${last_part_optional}"
else
((breakfix=breakfix-1))
if [ "${breakfix}" = "0" ] && [ "${last_part_optional}" = "true" ]; then
declare -g ${variable_name}="${major}.${minor}"
else
declare -g ${variable_name}="${major}.${minor}.${breakfix}"
fi
fi
set -e
}
# Use Oryx to install something using a partial version match
oryx_install() {
local platform=$1
local requested_version=$2
local target_folder=${3:-none}
local ldconfig_folder=${4:-none}
echo "(*) Installing ${platform} ${requested_version} using Oryx..."
check_packages jq
# Soft match if full version not specified
if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then
local version_list="$(oryx platforms --json | jq -r ".[] | select(.Name == \"${platform}\") | .Versions | sort | reverse | @tsv" | tr '\t' '\n' | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$')"
if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then
requested_version="$(echo "${version_list}" | head -n 1)"
else
set +e
requested_version="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")"
set -e
fi
if [ -z "${requested_version}" ] || ! echo "${version_list}" | grep "^${requested_version//./\\.}$" > /dev/null 2>&1; then
echo -e "(!) Oryx does not support ${platform} version $2\nValid values:\n${version_list}" >&2
return 1
fi
echo "(*) Using ${requested_version} in place of $2."
fi
export ORYX_ENV_TYPE=vsonline-present ORYX_PREFER_USER_INSTALLED_SDKS=true ENABLE_DYNAMIC_INSTALL=true DYNAMIC_INSTALL_ROOT_DIR=/opt
oryx prep --skip-detection --platforms-and-versions "${platform}=${requested_version}"
local opt_folder="/opt/${platform}/${requested_version}"
if [ "${target_folder}" != "none" ] && [ "${target_folder}" != "${opt_folder}" ]; then
ln -s "${opt_folder}" "${target_folder}"
fi
# Update library path add to conf
if [ "${ldconfig_folder}" != "none" ]; then
echo "/opt/${platform}/${requested_version}/lib" >> "/etc/ld.so.conf.d/${platform}.conf"
ldconfig
fi
}
pkg_mgr_update() {
case $ADJUSTED_ID in
debian)
if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then
echo "Running apt-get update..."
${PKG_MGR_CMD} update -y
fi
;;
rhel)
if [ ${PKG_MGR_CMD} = "microdnf" ]; then
if [ "$(ls /var/cache/yum/* 2>/dev/null | wc -l)" = 0 ]; then
echo "Running ${PKG_MGR_CMD} makecache ..."
${PKG_MGR_CMD} makecache
fi
else
if [ "$(ls /var/cache/${PKG_MGR_CMD}/* 2>/dev/null | wc -l)" = 0 ]; then
echo "Running ${PKG_MGR_CMD} check-update ..."
set +e
${PKG_MGR_CMD} check-update
rc=$?
if [ $rc != 0 ] && [ $rc != 100 ]; then
exit 1
fi
set -e
fi
fi
;;
esac
}
# Checks if packages are installed and installs them if not
check_packages() {
case ${ADJUSTED_ID} in
debian)
if ! dpkg -s "$@" > /dev/null 2>&1; then
pkg_mgr_update
${INSTALL_CMD} "$@"
fi
;;
rhel)
if ! rpm -q "$@" > /dev/null 2>&1; then
pkg_mgr_update
${INSTALL_CMD} "$@"
fi
;;
esac
}
add_symlink() {
if [[ ! -d "${CURRENT_PATH}" ]]; then
ln -s -r "${INSTALL_PATH}" "${CURRENT_PATH}"
fi
if [ "${OVERRIDE_DEFAULT_VERSION}" = "true" ]; then
if [[ $(ls -l ${CURRENT_PATH}) != *"-> ${INSTALL_PATH}"* ]] ; then
rm "${CURRENT_PATH}"
ln -s -r "${INSTALL_PATH}" "${CURRENT_PATH}"
fi
fi
}
install_openssl3() {
mkdir /tmp/openssl3
(
cd /tmp/openssl3
openssl3_version="3.0"
# Find version using soft match
find_version_from_git_tags openssl3_version "https://github.com/openssl/openssl" "openssl-"
local tgz_filename="openssl-${openssl3_version}.tar.gz"
local tgz_url="https://github.com/openssl/openssl/releases/download/openssl-${openssl3_version}/${tgz_filename}"
echo "Downloading ${tgz_filename}..."
curl -sSL -o "/tmp/openssl3/${tgz_filename}" "${tgz_url}"
tar xzf ${tgz_filename}
cd openssl-${openssl3_version}
./config --libdir=lib
make -j $(nproc)
make install_dev
)
rm -rf /tmp/openssl3
}
install_prev_vers_cpython() {
VERSION=$1
echo -e "\n(!) Failed to fetch the latest artifacts for cpython ${VERSION}..."
find_prev_version_from_git_tags VERSION https://github.com/python/cpython
echo -e "\nAttempting to install ${VERSION}"
install_cpython "${VERSION}"
}
install_cpython() {
VERSION=$1
INSTALL_PATH="${PYTHON_INSTALL_PATH}/${VERSION}"
# Check if the specified Python version is already installed
if [ -d "${INSTALL_PATH}" ]; then
echo "(!) Python version ${VERSION} already exists."
else
mkdir -p /tmp/python-src ${INSTALL_PATH}
cd /tmp/python-src
cpython_tgz_filename="Python-${VERSION}.tgz"
cpython_tgz_url="https://mirrors.huaweicloud.com/python/${VERSION}/${cpython_tgz_filename}"
echo "Downloading ${cpython_tgz_filename}..."
curl -sSL -o "/tmp/python-src/${cpython_tgz_filename}" "${cpython_tgz_url}"
fi
}
install_from_source() {
VERSION=$1
echo "(*) Building Python ${VERSION} from source..."
if ! type git > /dev/null 2>&1; then
check_packages git
fi
# Find version using soft match
find_version_from_git_tags VERSION "https://github.com/python/cpython"
# Some platforms/os versions need modern versions of openssl installed
# via common package repositories, for now rhel-7 family, use case statement to
# make it easy to expand
SSL_INSTALL_PATH="/usr/local"
case ${VERSION_CODENAME} in
centos7|rhel7)
check_packages perl-IPC-Cmd
install_openssl3
ADDL_CONFIG_ARGS="--with-openssl=${SSL_INSTALL_PATH} --with-openssl-rpath=${SSL_INSTALL_PATH}/lib"
;;
esac
install_cpython "${VERSION}"
if [ -f "/tmp/python-src/${cpython_tgz_filename}" ]; then
if grep -q "404 Not Found" "/tmp/python-src/${cpython_tgz_filename}"; then
install_prev_vers_cpython "${VERSION}"
fi
fi;
# Verify signature
if [[ ${VERSION_CODENAME} = "centos7" ]] || [[ ${VERSION_CODENAME} = "rhel7" ]]; then
receive_gpg_keys_centos7 PYTHON_SOURCE_GPG_KEYS
else
receive_gpg_keys PYTHON_SOURCE_GPG_KEYS
fi
echo "Downloading ${cpython_tgz_filename}.asc..."
curl -sSL -o "/tmp/python-src/${cpython_tgz_filename}.asc" "${cpython_tgz_url}.asc"
gpg --verify "${cpython_tgz_filename}.asc"
# Update min protocol for testing only - https://bugs.python.org/issue41561
if [ -f /etc/pki/tls/openssl.cnf ]; then
cp /etc/pki/tls/openssl.cnf /tmp/python-src/
else
cp /etc/ssl/openssl.cnf /tmp/python-src/
fi
sed -i -E 's/MinProtocol[=\ ]+.*/MinProtocol = TLSv1.0/g' /tmp/python-src/openssl.cnf
export OPENSSL_CONF=/tmp/python-src/openssl.cnf
# Untar and build
tar -xzf "/tmp/python-src/${cpython_tgz_filename}" -C "/tmp/python-src" --strip-components=1
local config_args=""
if [ "${OPTIMIZE_BUILD_FROM_SOURCE}" = "true" ]; then
config_args="${config_args} --enable-optimizations"
fi
if [ "${ENABLESHARED}" = "true" ]; then
config_args=" ${config_args} --enable-shared"
# need double-$: LDFLAGS ends up in Makefile $$ becomes $ when evaluated.
# backslash needed for shell that Make calls escape the $.
export LDFLAGS="${LDFLAGS} -Wl,-rpath="'\$$ORIGIN'"/../lib"
fi
if [ -n "${ADDL_CONFIG_ARGS}" ]; then
config_args="${config_args} ${ADDL_CONFIG_ARGS}"
fi
./configure --prefix="${INSTALL_PATH}" --with-ensurepip=install ${config_args}
make -j 8
make install
cd /tmp
rm -rf /tmp/python-src ${GNUPGHOME} /tmp/vscdc-settings.env
ln -s "${INSTALL_PATH}/bin/python3" "${INSTALL_PATH}/bin/python"
ln -s "${INSTALL_PATH}/bin/pip3" "${INSTALL_PATH}/bin/pip"
ln -s "${INSTALL_PATH}/bin/idle3" "${INSTALL_PATH}/bin/idle"
ln -s "${INSTALL_PATH}/bin/pydoc3" "${INSTALL_PATH}/bin/pydoc"
ln -s "${INSTALL_PATH}/bin/python3-config" "${INSTALL_PATH}/bin/python-config"
add_symlink
}
install_using_oryx() {
VERSION=$1
INSTALL_PATH="${PYTHON_INSTALL_PATH}/${VERSION}"
# Check if the specified Python version is already installed
if [ -d "${INSTALL_PATH}" ]; then
echo "(!) Python version ${VERSION} already exists."
else
# The python install root path may not exist, so create it
mkdir -p "${PYTHON_INSTALL_PATH}"
oryx_install "python" "${VERSION}" "${INSTALL_PATH}" "lib" || return 1
ln -s "${INSTALL_PATH}/bin/idle3" "${INSTALL_PATH}/bin/idle"
ln -s "${INSTALL_PATH}/bin/pydoc3" "${INSTALL_PATH}/bin/pydoc"
ln -s "${INSTALL_PATH}/bin/python3-config" "${INSTALL_PATH}/bin/python-config"
add_symlink
fi
}
sudo_if() {
COMMAND="$*"
if [ "$(id -u)" -eq 0 ] && [ "$USERNAME" != "root" ]; then
su - "$USERNAME" -c "$COMMAND"
else
$COMMAND
fi
}
install_user_package() {
INSTALL_UNDER_ROOT="$1"
PACKAGE="$2"
if [ "$INSTALL_UNDER_ROOT" = true ]; then
sudo_if "${PYTHON_SRC}" -m pip install --upgrade --no-cache-dir "$PACKAGE"
else
sudo_if "${PYTHON_SRC}" -m pip install --user --upgrade --no-cache-dir "$PACKAGE"
fi
}
add_user_jupyter_config() {
CONFIG_DIR="$1"
CONFIG_FILE="$2"
# Make sure the config file exists or create it with proper permissions
test -d "$CONFIG_DIR" || sudo_if mkdir "$CONFIG_DIR"
test -f "$CONFIG_FILE" || sudo_if touch "$CONFIG_FILE"
# Don't write the same config more than once
grep -q "$3" "$CONFIG_FILE" || echo "$3" >> "$CONFIG_FILE"
}
install_python() {
version=$1
# If the os-provided versions are "good enough", detect that and bail out.
if [ ${version} = "os-provided" ] || [ ${version} = "system" ]; then
if [ ${ADJUSTED_ID} = "debian" ]; then
check_packages python3 python3-doc python3-pip python3-venv python3-dev python3-tk
else
if [ ${ID} != "mariner" ]; then
check_packages python3 python3-pip python3-devel python3-tkinter
else
check_packages python3 python3-pip python3-devel
fi
fi
INSTALL_PATH="/usr"
local current_bin_path="${CURRENT_PATH}/bin"
if [ "${OVERRIDE_DEFAULT_VERSION}" = "true" ]; then
rm -rf "${current_bin_path}"
fi
if [ ! -d "${current_bin_path}" ] ; then
mkdir -p "${current_bin_path}"
# Add an interpreter symlink but point it to "/usr" since python is at /usr/bin/python, add other alises
ln -s "${INSTALL_PATH}/bin/python3" "${current_bin_path}/python3"
ln -s "${INSTALL_PATH}/bin/python3" "${current_bin_path}/python"
ln -s "${INSTALL_PATH}/bin/pydoc3" "${current_bin_path}/pydoc3"
ln -s "${INSTALL_PATH}/bin/pydoc3" "${current_bin_path}/pydoc"
ln -s "${INSTALL_PATH}/bin/python3-config" "${current_bin_path}/python3-config"
ln -s "${INSTALL_PATH}/bin/python3-config" "${current_bin_path}/python-config"
fi
should_install_from_source=false
elif [ ${ADJUSTED_ID} = "debian" ] && [ "$(dpkg --print-architecture)" = "amd64" ] && [ "${USE_ORYX_IF_AVAILABLE}" = "true" ] && type oryx > /dev/null 2>&1; then
install_using_oryx $version || should_install_from_source=true
else
should_install_from_source=true
fi
if [ "${should_install_from_source}" = "true" ]; then
install_from_source $version
fi
}
python_is_externally_managed() {
local _python_cmd=$1
local python_stdlib_dir=$(
${_python_cmd} -c '
import sys
import sysconfig
sys.prefix == sys.base_prefix and print(sysconfig.get_path("stdlib", sysconfig.get_default_scheme()))'
)
if [ -f ${python_stdlib_dir}/EXTERNALLY-MANAGED ]; then
return 0
else
return 1
fi
}
# Ensure that login shells get the correct path if the user updated the PATH using ENV.
rm -f /etc/profile.d/00-restore-env.sh
echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh
chmod +x /etc/profile.d/00-restore-env.sh
# Some distributions do not install awk by default (e.g. Mariner)
if ! type awk >/dev/null 2>&1; then
check_packages awk
fi
# Determine the appropriate non-root user
if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then
USERNAME=""
POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)")
for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do
if id -u ${CURRENT_USER} > /dev/null 2>&1; then
USERNAME=${CURRENT_USER}
break
fi
done
if [ "${USERNAME}" = "" ]; then
USERNAME=root
fi
elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then
USERNAME=root
fi
# Ensure apt is in non-interactive to avoid prompts
export DEBIAN_FRONTEND=noninteractive
# General requirements
REQUIRED_PKGS=""
case ${ADJUSTED_ID} in
debian)
REQUIRED_PKGS="${REQUIRED_PKGS} \
ca-certificates \
curl \
dirmngr \
gcc \
gnupg2 \
libbz2-dev \
libffi-dev \
libgdbm-dev \
liblzma-dev \
libncurses5-dev \
libreadline-dev \
libsqlite3-dev \
libssl-dev \
libxml2-dev \
libxmlsec1-dev \
make \
tar \
tk-dev \
uuid-dev \
xz-utils \
zlib1g-dev"
;;
rhel)
REQUIRED_PKGS="${REQUIRED_PKGS} \
bzip2-devel \
ca-certificates \
findutils \
gcc \
gnupg2 \
libffi-devel \
libxml2-devel \
make \
ncurses-devel \
openssl-devel \
shadow-utils \
sqlite-devel \
tar \
which \
xz-devel \
xz \
zlib-devel"
if ! type curl >/dev/null 2>&1; then
REQUIRED_PKGS="${REQUIRED_PKGS} \
curl"
fi
# Mariner does not have tk-devel package available, RedHat ubi8 and ubi9 do not have tk-devel
if [ ${ID} != "mariner" ] && [ ${ID} != "rhel" ]; then
REQUIRED_PKGS="${REQUIRED_PKGS} \
tk-devel"
fi
# Redhat ubi8 and ubi9 do not have some packages by default, only add them
# if we're not on RedHat ...
if [ ${ID} != "rhel" ]; then
REQUIRED_PKGS="${REQUIRED_PKGS} \
gdbm-devel \
readline-devel \
uuid-devel \
xmlsec1-devel"
fi
;;
esac
check_packages ${REQUIRED_PKGS}
# Function to get the major version from a SemVer string
get_major_version() {
local version="$1"
echo "$version" | cut -d '.' -f 1
}
# Install Python from source if needed
if [ "${PYTHON_VERSION}" != "none" ]; then
if ! cat /etc/group | grep -e "^python:" > /dev/null 2>&1; then
groupadd -r python
fi
usermod -a -G python "${USERNAME}"
CURRENT_PATH="${PYTHON_INSTALL_PATH}/current"
install_python ${PYTHON_VERSION}
# Additional python versions to be installed but not be set as default.
if [ ! -z "${ADDITIONAL_VERSIONS}" ]; then
OLD_INSTALL_PATH="${INSTALL_PATH}"
OLDIFS=$IFS
IFS=","
read -a additional_versions <<< "$ADDITIONAL_VERSIONS"
major_version=$(get_major_version ${VERSION})
if type apt-get > /dev/null 2>&1; then
# Debian/Ubuntu: Use update-alternatives
update-alternatives --install ${CURRENT_PATH} python${major_version} ${PYTHON_INSTALL_PATH}/${VERSION} $((${#additional_versions[@]}+1))
update-alternatives --set python${major_version} ${PYTHON_INSTALL_PATH}/${VERSION}
elif type dnf > /dev/null 2>&1 || type yum > /dev/null 2>&1 || type microdnf > /dev/null 2>&1; then
# Fedora/RHEL/CentOS: Use alternatives
alternatives --install ${CURRENT_PATH} python${major_version} ${PYTHON_INSTALL_PATH}/${VERSION} $((${#additional_versions[@]}+1))
alternatives --set python${major_version} ${PYTHON_INSTALL_PATH}/${VERSION}
fi
for i in "${!additional_versions[@]}"; do
version=${additional_versions[$i]}
OVERRIDE_DEFAULT_VERSION="false"
install_python $version
if type apt-get > /dev/null 2>&1; then
# Debian/Ubuntu: Use update-alternatives
update-alternatives --install ${CURRENT_PATH} python${major_version} ${PYTHON_INSTALL_PATH}/${VERSION} $((${i}+1))
elif type dnf > /dev/null 2>&1 || type yum > /dev/null 2>&1 || type microdnf > /dev/null 2>&1; then
# Fedora/RHEL/CentOS: Use alternatives
alternatives --install ${CURRENT_PATH} python${major_version} ${PYTHON_INSTALL_PATH}/${VERSION} $((${i}+1))
fi
done
INSTALL_PATH="${OLD_INSTALL_PATH}"
IFS=$OLDIFS
fi
if [ ${PYTHON_VERSION} != "os-provided" ] && [ ${PYTHON_VERSION} != "system" ]; then
updaterc "if [[ \"\${PATH}\" != *\"${CURRENT_PATH}/bin\"* ]]; then export PATH=${CURRENT_PATH}/bin:\${PATH}; fi"
PATH="${INSTALL_PATH}/bin:${PATH}"
fi
# Updates the symlinks for os-provided, or the installed python version in other cases
chown -R "${USERNAME}:python" "${PYTHON_INSTALL_PATH}"
chmod -R g+r+w "${PYTHON_INSTALL_PATH}"
find "${PYTHON_INSTALL_PATH}" -type d -print0 | xargs -0 -n 1 chmod g+s
PYTHON_SRC="${INSTALL_PATH}/bin/python3"
if ! type pip >/dev/null 2>&1 && type pip3 >/dev/null 2>&1; then
ln -s /usr/bin/pip3 /usr/bin/pip
fi
else
PYTHON_SRC=$(which python)
fi
# Install Python tools if needed
if [[ "${INSTALL_PYTHON_TOOLS}" = "true" ]] && [[ -n "${PYTHON_SRC}" ]]; then
echo 'Installing Python tools...'
export PIPX_BIN_DIR="${PIPX_HOME}/bin"
PATH="${PATH}:${PIPX_BIN_DIR}"
# Create pipx group, dir, and set sticky bit
if ! cat /etc/group | grep -e "^pipx:" > /dev/null 2>&1; then
groupadd -r pipx
fi
usermod -a -G pipx ${USERNAME}
umask 0002
mkdir -p ${PIPX_BIN_DIR}
chown -R "${USERNAME}:pipx" ${PIPX_HOME}
chmod -R g+r+w "${PIPX_HOME}"
find "${PIPX_HOME}" -type d -print0 | xargs -0 -n 1 chmod g+s
# Update pip if not using os provided python
if [[ -n "${PYTHON_SRC}" ]] && [[ ${PYTHON_VERSION} != "os-provided" ]] && [[ ${PYTHON_VERSION} != "system" ]] && [[ ${PYTHON_VERSION} != "none" ]]; then
echo "Updating pip..."
${PYTHON_SRC} -m pip install --no-cache-dir --upgrade pip -i https://pypi.tuna.tsinghua.edu.cn/simple/
fi
# Install tools
export PYTHONUSERBASE=/tmp/pip-tmp
export PIP_CACHE_DIR=/tmp/pip-tmp/cache
PIPX_DIR=""
if ! type pipx > /dev/null 2>&1; then
if python_is_externally_managed ${PYTHON_SRC}; then
check_packages pipx
else
pip3 install --disable-pip-version-check --no-cache-dir --user pipx -i https://pypi.tuna.tsinghua.edu.cn/simple/ 2>&1
/tmp/pip-tmp/bin/pipx install --pip-args=--no-cache-dir pipx
PIPX_DIR="/tmp/pip-tmp/bin/"
fi
fi
for util in "${DEFAULT_UTILS[@]}"; do
if ! type ${util} > /dev/null 2>&1; then
"${PIPX_DIR}pipx" install --system-site-packages --pip-args '--no-cache-dir --force-reinstall -i https://pypi.tuna.tsinghua.edu.cn/simple/' ${util}
else
echo "${util} already installed. Skipping."
fi
done
# Temporary: Removes “setup tools” metadata directory due to https://github.com/advisories/GHSA-r9hx-vwmv-q579
if [[ $SKIP_VULNERABILITY_PATCHING = "false" ]]; then
VULNERABLE_VERSIONS=("3.10" "3.11")
RUN_TIME_PY_VER_DETECT=$(${PYTHON_SRC} --version 2>&1)
PY_MAJOR_MINOR_VER=${RUN_TIME_PY_VER_DETECT:7:4};
if [[ ${VULNERABLE_VERSIONS[*]} =~ $PY_MAJOR_MINOR_VER ]]; then
rm -rf ${PIPX_HOME}/shared/lib/"python${PY_MAJOR_MINOR_VER}"/site-packages/setuptools-65.5.0.dist-info
if [[ -e "/usr/local/lib/python${PY_MAJOR_MINOR_VER}/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl" ]]; then
# remove the vulnerable setuptools-65.5.0-py3-none-any.whl file
rm /usr/local/lib/python${PY_MAJOR_MINOR_VER}/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl
# create and change to the setuptools_downloaded directory
mkdir -p /tmp/setuptools_downloaded
cd /tmp/setuptools_downloaded
# download the source distribution for setuptools using pip
pip download setuptools==65.5.1 --no-binary :all:
# extract the filename of the setuptools-*.tar.gz file
filename=$(find . -maxdepth 1 -type f)
# create a directory to store unpacked contents of the source distribution
mkdir -p /tmp/setuptools_src_dist
# extract the contents inside the new directory
tar -xzf $filename -C /tmp/setuptools_src_dist
# move to the setuptools-* directory inside /setuptools_src_dist
cd /tmp/setuptools_src_dist/setuptools-65.5.1/
# look for setup.py file in the current directory and create a wheel file
python setup.py bdist_wheel
# move inside the dist directory in pwd
cd dist
# copy this file to the ensurepip/_bundled directory
cp setuptools-65.5.1-py3-none-any.whl /usr/local/lib/python${PY_MAJOR_MINOR_VER}/ensurepip/_bundled/
# replace the version in __init__.py file with the installed version
sed -i 's/_SETUPTOOLS_VERSION = \"65\.5\.0\"/_SETUPTOOLS_VERSION = "65.5.1"/g' /usr/local/lib/"python${PY_MAJOR_MINOR_VER}"/ensurepip/__init__.py
# cleanup created dir's
rm -rf /tmp/setuptools_downloaded /tmp/setuptools_src_dist
fi
fi
fi
rm -rf /tmp/pip-tmp
updaterc "export PIPX_HOME=\"${PIPX_HOME}\""
updaterc "export PIPX_BIN_DIR=\"${PIPX_BIN_DIR}\""
updaterc "if [[ \"\${PATH}\" != *\"\${PIPX_BIN_DIR}\"* ]]; then export PATH=\"\${PATH}:\${PIPX_BIN_DIR}\"; fi"
fi
# Install JupyterLab if needed
if [ "${INSTALL_JUPYTERLAB}" = "true" ]; then
if [ -z "${PYTHON_SRC}" ]; then
echo "(!) Could not install Jupyterlab. Python not found."
exit 1
fi
INSTALL_UNDER_ROOT=true
if [ "$(id -u)" -eq 0 ] && [ "$USERNAME" != "root" ]; then
INSTALL_UNDER_ROOT=false
fi
install_user_package $INSTALL_UNDER_ROOT jupyterlab -i https://pypi.tuna.tsinghua.edu.cn/simple/
install_user_package $INSTALL_UNDER_ROOT jupyterlab-git -i https://pypi.tuna.tsinghua.edu.cn/simple/
# Create a symlink to the JupyterLab binary for non root users
if [ "$INSTALL_UNDER_ROOT" = false ]; then
JUPYTER_INPATH=/home/${USERNAME}/.local/bin
if [ ! -d "$JUPYTER_INPATH" ]; then
echo "Error: $JUPYTER_INPATH does not exist."
exit 1
fi
JUPYTER_PATH=/usr/local/jupyter
ln -s "$JUPYTER_INPATH" "$JUPYTER_PATH"
fi
# Configure JupyterLab if needed
if [ -n "${CONFIGURE_JUPYTERLAB_ALLOW_ORIGIN}" ]; then
# Resolve config directory
CONFIG_DIR="/root/.jupyter"
if [ "$INSTALL_UNDER_ROOT" = false ]; then
CONFIG_DIR="/home/$USERNAME/.jupyter"
fi
CONFIG_FILE="$CONFIG_DIR/jupyter_server_config.py"
add_user_jupyter_config $CONFIG_DIR $CONFIG_FILE "c.ServerApp.allow_origin = '${CONFIGURE_JUPYTERLAB_ALLOW_ORIGIN}'"
add_user_jupyter_config $CONFIG_DIR $CONFIG_FILE "c.NotebookApp.allow_origin = '${CONFIGURE_JUPYTERLAB_ALLOW_ORIGIN}'"
fi
fi
# Clean up
clean_up
echo "Done!"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment