aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/test-all.yaml1
-rw-r--r--.github/workflows/test-pr.yaml1
-rw-r--r--src/jupyterlab/devcontainer-feature.json33
-rw-r--r--src/jupyterlab/install.sh71
-rw-r--r--src/python/devcontainer-feature.json10
-rwxr-xr-xsrc/python/install.sh130
-rw-r--r--test-scenarios/install_jupyterlab.sh12
-rw-r--r--test-scenarios/scenarios.json19
-rw-r--r--test/jupyterlab/test.sh12
-rw-r--r--v1/feature-scripts.env3
10 files changed, 126 insertions, 166 deletions
diff --git a/.github/workflows/test-all.yaml b/.github/workflows/test-all.yaml
index 31a664f..be86dc8 100644
--- a/.github/workflows/test-all.yaml
+++ b/.github/workflows/test-all.yaml
@@ -27,7 +27,6 @@ jobs:
"go",
"hugo",
"java",
- "python jupyterlab", # Install 'python', then 'jupyterlab'
"kubectl-helm-minikube",
"node",
"oryx",
diff --git a/.github/workflows/test-pr.yaml b/.github/workflows/test-pr.yaml
index 22c04ef..e242ad1 100644
--- a/.github/workflows/test-pr.yaml
+++ b/.github/workflows/test-pr.yaml
@@ -27,7 +27,6 @@ jobs:
go: ./**/go/**
hugo: ./**/hugo/**
java: ./**/java/**
- 'python jupyterlab': ./**/jupyterlab/**
kubectl-helm-minikube: ./**/kubectl-helm-minikube/**
node: ./**/node/**
oryx: ./**/oryx/**
diff --git a/src/jupyterlab/devcontainer-feature.json b/src/jupyterlab/devcontainer-feature.json
deleted file mode 100644
index 8546925..0000000
--- a/src/jupyterlab/devcontainer-feature.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "id": "jupyterlab",
- "name": "Jupyter Lab",
- "options": {
- "version": {
- "type": "string",
- "proposals": [
- "latest",
- "3.6.2"
- ],
- "default": "latest",
- "description": "Select or enter a jupyterlab version."
- },
- "python_binary": {
- "type": "string",
- "proposals": [
- "python",
- "/usr/local/python/bin/python"
- ],
- "default": "python",
- "description": "Select or enter the python binary path."
- }
- },
- "extensions": [
- "ms-python.python",
- "ms-python.vscode-pylance",
- "ms-toolsai.jupyter"
- ],
- "install": {
- "app": "",
- "file": "install.sh"
- }
-} \ No newline at end of file
diff --git a/src/jupyterlab/install.sh b/src/jupyterlab/install.sh
deleted file mode 100644
index f6c30d3..0000000
--- a/src/jupyterlab/install.sh
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/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/jupyterlab.md
-# Maintainer: The VS Code and Codespaces Teams
-
-set -ex
-
-VERSION=${VERSION:-"latest"}
-PYTHON=${PYTHON_BINARY:-"python"}
-
-USERNAME=${USERNAME:-"automatic"}
-ALLOW_ALL_ORIGINS=${ALLOW_ALL_ORIGINS:-""}
-
-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
-
-# If in automatic mode, determine if a user already exists, if not use vscode
-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=vscode
- fi
-elif [ "${USERNAME}" = "none" ]; then
- USERNAME=root
- USER_UID=0
- USER_GID=0
-fi
-
-addToJupyterConfig() {
- JUPYTER_DIR="/home/${USERNAME}/.jupyter"
- JUPYTER_CONFIG="${JUPYTER_DIR}/jupyter_notebook_config.py"
-
- # Make sure the config file exists
- test -d ${JUPYTER_DIR} || mkdir ${JUPYTER_DIR}
- test -f ${JUPYTER_CONFIG} || touch ${JUPYTER_CONFIG}
-
- # Don't write the same line more than once
- grep -q ${1} ${JUPYTER_CONFIG} || echo ${1} >> ${JUPYTER_CONFIG}
-}
-
-# Make sure that Python is available
-if ! ${PYTHON} --version > /dev/null ; then
- echo "You need to install Python before installing JupyterLab."
- exit 1
-fi
-
-# pip skips installation if JupyterLab is already installed
-echo "Installing JupyterLab..."
-if [ "${VERSION}" = "latest" ]; then
- ${PYTHON} -m pip install jupyterlab --no-cache-dir
-else
- ${PYTHON} -m pip install jupyterlab=="${VERSION}" --no-cache-dir
-fi
-
-if [ "${ALLOW_ALL_ORIGINS}" = 'true' ]; then
- addToJupyterConfig "c.ServerApp.allow_origin = '*'"
- addToJupyterConfig "c.NotebookApp.allow_origin = '*'"
-fi \ No newline at end of file
diff --git a/src/python/devcontainer-feature.json b/src/python/devcontainer-feature.json
index 238b8d1..c32e18a 100644
--- a/src/python/devcontainer-feature.json
+++ b/src/python/devcontainer-feature.json
@@ -37,6 +37,16 @@
"type": "boolean",
"default": "true",
"description": "If true, overrides existing version (if any) of python on the PATH"
+ },
+ "install_jupyterlab": {
+ "type": "boolean",
+ "default": false,
+ "description": "Install JupyterLab, a web-based interactive development environment for notebooks"
+ },
+ "configure_jupyterlab_allow_origin": {
+ "type": "string",
+ "default": "",
+ "description": "Configure JupyterLab to accept HTTP requests from the specified origin"
}
},
"containerEnv": {
diff --git a/src/python/install.sh b/src/python/install.sh
index a3516da..c976671 100755
--- a/src/python/install.sh
+++ b/src/python/install.sh
@@ -19,6 +19,9 @@ USERNAME=${USERNAME:-"automatic"}
UPDATE_RC=${UPDATE_RC:-"true"}
USE_ORYX_IF_AVAILABLE=${USE_ORYX_IF_AVAILABLE:-"true"}
+INSTALL_JUPYTERLAB=${INSTALL_JUPYTERLAB:-"false"}
+CONFIGURE_JUPYTERLAB_ALLOW_ORIGIN=${CONFIGURE_JUPYTERLAB_ALLOW_ORIGIN:-""}
+
DEFAULT_UTILS=("pylint" "flake8" "autopep8" "black" "yapf" "mypy" "pydocstyle" "pycodestyle" "bandit" "pipenv" "virtualenv")
PYTHON_SOURCE_GPG_KEYS="64E628F8D684696D B26995E310250568 2D347EA6AA65421D FB9921286F5E1540 3A5CA953F73C700D 04C367C218ADD4FF 0EDDC5F26A45C816 6AF053F07D9DC8D2 C9BE28DEE6DF025C 126EB563A74B06BF D9866941EA5BBD71 ED9D77D5"
GPG_KEY_SERVERS="keyserver hkp://keyserver.ubuntu.com:80
@@ -301,6 +304,32 @@ install_using_oryx() {
add_symlink
}
+sudo_if() {
+ COMMAND="$*"
+ if [ "$(id -u)" -eq 0 ] && [ "$USERNAME" != "root" ]; then
+ su - "$USERNAME" -c "$COMMAND"
+ else
+ "$COMMAND"
+ fi
+}
+
+install_user_package() {
+ PACKAGE="$1"
+ sudo_if "$INSTALL_PATH/bin/python3" -m pip install --user --upgrade --no-cache-dir "$PACKAGE"
+}
+
+add_user_jupyter_config() {
+ CONFIG_DIR="/home/$USERNAME/.jupyter"
+ CONFIG_FILE="$CONFIG_DIR/jupyter_notebook_config.py"
+
+ # 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 "$1" "$CONFIG_FILE" || echo "$1" >> "$CONFIG_FILE"
+}
+
# Ensure apt is in non-interactive to avoid prompts
export DEBIAN_FRONTEND=noninteractive
@@ -310,7 +339,7 @@ check_packages curl ca-certificates gnupg2 tar make gcc libssl-dev zlib1g-dev li
libxmlsec1-dev libsqlite3-dev libffi-dev liblzma-dev uuid-dev
-# Install python from source if needed
+# Install Python from source if needed
if [ "${PYTHON_VERSION}" != "none" ]; then
CURRENT_PATH="${PYTHON_INSTALL_PATH}/current"
# If the os-provided versions are "good enough", detect that and bail out.
@@ -330,53 +359,62 @@ if [ "${PYTHON_VERSION}" != "none" ]; then
updaterc "if [[ \"\${PATH}\" != *\"${CURRENT_PATH}/bin\"* ]]; then export PATH=${CURRENT_PATH}/bin:\${PATH}; fi"
fi
-# If not installing python tools, exit
-if [ "${INSTALL_PYTHON_TOOLS}" != "true" ]; then
- echo "Done!"
- exit 0
-fi
+# Install Python tools if needed
+if [ "${INSTALL_PYTHON_TOOLS}" = "true" ]; then
+ echo 'Installing Python tools...'
+ export PIPX_BIN_DIR="${PIPX_HOME}/bin"
+ export PATH="${CURRENT_PATH}/bin:${PIPX_BIN_DIR}:${PATH}"
-export PIPX_BIN_DIR="${PIPX_HOME}/bin"
-export PATH="${CURRENT_PATH}/bin:${PIPX_BIN_DIR}:${PATH}"
+ # 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 :pipx ${PIPX_HOME} ${PIPX_BIN_DIR}
+ chmod g+s ${PIPX_HOME} ${PIPX_BIN_DIR}
+
+ # Update pip if not using os provided python
+ if [ ${PYTHON_VERSION} != "os-provided" ] && [ ${PYTHON_VERSION} != "system" ] && [ ${PYTHON_VERSION} != "none" ]; then
+ echo "Updating pip..."
+ "${INSTALL_PATH}/bin/python3" -m pip install --no-cache-dir --upgrade pip
+ fi
-# 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 :pipx ${PIPX_HOME} ${PIPX_BIN_DIR}
-chmod g+s ${PIPX_HOME} ${PIPX_BIN_DIR}
-
-# Update pip if not using os provided python
-if [ ${PYTHON_VERSION} != "os-provided" ] && [ ${PYTHON_VERSION} != "system" ] && [ ${PYTHON_VERSION} != "none" ]; then
- echo "Updating pip..."
- ${INSTALL_PATH}/bin/python3 -m pip install --no-cache-dir --upgrade pip
-fi
+ # Install tools
+ echo "Installing Python tools..."
+ export PYTHONUSERBASE=/tmp/pip-tmp
+ export PIP_CACHE_DIR=/tmp/pip-tmp/cache
+ PIPX_DIR=""
+ if ! type pipx > /dev/null 2>&1; then
+ pip3 install --disable-pip-version-check --no-cache-dir --user pipx 2>&1
+ /tmp/pip-tmp/bin/pipx install --pip-args=--no-cache-dir pipx
+ PIPX_DIR="/tmp/pip-tmp/bin"
+ 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' ${util}
+ else
+ echo "${util} already installed. Skipping."
+ fi
+ done
+ rm -rf /tmp/pip-tmp
-# Install tools
-echo "Installing Python tools..."
-export PYTHONUSERBASE=/tmp/pip-tmp
-export PIP_CACHE_DIR=/tmp/pip-tmp/cache
-pipx_path=""
-if ! type pipx > /dev/null 2>&1; then
- pip3 install --disable-pip-version-check --no-cache-dir --user pipx 2>&1
- /tmp/pip-tmp/bin/pipx install --pip-args=--no-cache-dir pipx
- pipx_path="/tmp/pip-tmp/bin/"
+ 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
-for util in "${DEFAULT_UTILS[@]}"; do
- if ! type ${util} > /dev/null 2>&1; then
- ${pipx_path}pipx install --system-site-packages --pip-args '--no-cache-dir --force-reinstall' ${util}
- else
- echo "${util} already installed. Skipping."
+
+# Install JupyterLab if needed
+if [ "${INSTALL_JUPYTERLAB}" = "true" ]; then
+ install_user_package jupyterlab
+
+ # Configure JupyterLab if needed
+ # TODO: True if it's not empty
+ if [ -n "${CONFIGURE_JUPYTERLAB_ALLOW_ORIGIN}" ]; then
+ add_user_jupyter_config "c.ServerApp.allow_origin = '${CONFIGURE_JUPYTERLAB_ALLOW_ORIGIN}'"
+ add_user_jupyter_config "c.NotebookApp.allow_origin = '${CONFIGURE_JUPYTERLAB_ALLOW_ORIGIN}'"
fi
-done
-rm -rf /tmp/pip-tmp
-
-updaterc "$(cat << EOF
-export PIPX_HOME="${PIPX_HOME}"
-export PIPX_BIN_DIR="${PIPX_BIN_DIR}"
-if [[ "\${PATH}" != *"\${PIPX_BIN_DIR}"* ]]; then export PATH="\${PATH}:\${PIPX_BIN_DIR}"; fi
-EOF
-)"
+fi
+
+echo "Done!"
diff --git a/test-scenarios/install_jupyterlab.sh b/test-scenarios/install_jupyterlab.sh
new file mode 100644
index 0000000..2a4aaa3
--- /dev/null
+++ b/test-scenarios/install_jupyterlab.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+set -e
+
+# Optional: Import test library
+source dev-container-features-test-lib
+
+check "version" jupyter lab --version
+check "config" grep ".*.allow_origin = '*'" /home/vscode/.jupyter/jupyter_notebook_config.py
+
+# Report result
+reportResults
diff --git a/test-scenarios/scenarios.json b/test-scenarios/scenarios.json
index e97b853..bbb61e7 100644
--- a/test-scenarios/scenarios.json
+++ b/test-scenarios/scenarios.json
@@ -16,5 +16,24 @@
}
}
]
+ },
+ "install_jupyterlab": {
+ "image": "mcr.microsoft.com/vscode/devcontainers/base:focal",
+ "remoteUser": "vscode",
+ "features": [
+ {
+ "id": "common",
+ "options": {
+ "username": "vscode"
+ }
+ },
+ {
+ "id": "python",
+ "options": {
+ "install_jupyterlab": true,
+ "configure_jupyterlab_allow_origin": "*"
+ }
+ }
+ ]
}
} \ No newline at end of file
diff --git a/test/jupyterlab/test.sh b/test/jupyterlab/test.sh
deleted file mode 100644
index 67249bf..0000000
--- a/test/jupyterlab/test.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-
-set -e
-
-# Optional: Import test library
-source dev-container-features-test-lib
-
-# Definition specific tests
-check "version" jupyter --version
-
-# Report result
-reportResults \ No newline at end of file
diff --git a/v1/feature-scripts.env b/v1/feature-scripts.env
index 7503ce5..c3e9936 100644
--- a/v1/feature-scripts.env
+++ b/v1/feature-scripts.env
@@ -10,7 +10,7 @@ _BUILD_ARG_AWS_CLI="./aws-cli/install.sh ${_B
_BUILD_ARG_AZURE_CLI="./az-cli/install.sh ${_BUILD_ARG_AZURE_CLI_VERSION:-latest}"
_BUILD_ARG_SSHD="./sshd/install.sh"
_BUILD_ARG_NODE="./node/install.sh ${_BUILD_ARG_NODE_NVMINSTALLPATH:-/usr/local/share/nvm} ${_BUILD_ARG_NODE_VERSION:-lts/*} automatic true ${_BUILD_ARG_NODE_NODEGYPDEPENDENCIES:-true}"
-_BUILD_ARG_PYTHON="./python/install.sh ${_BUILD_ARG_PYTHON_VERSION:-latest} ${_BUILD_ARG_PYTHON_INSTALLPATH:-/usr/local/python} /usr/local/py-utils automatic true ${_BUILD_ARG_PYTHON_INSTALLTOOLS:-true} true ${_BUILD_ARG_PYTHON_OPTIMIZE:-false} ${_BUILD_ARG_PYTHON_OVERRIDEDEFAULTVERSION:-true}"
+_BUILD_ARG_PYTHON="./python/install.sh ${_BUILD_ARG_PYTHON_VERSION:-latest} ${_BUILD_ARG_PYTHON_INSTALLPATH:-/usr/local/python} /usr/local/py-utils automatic true ${_BUILD_ARG_PYTHON_INSTALLTOOLS:-true} true ${_BUILD_ARG_PYTHON_OPTIMIZE:-false} ${_BUILD_ARG_PYTHON_OVERRIDEDEFAULTVERSION:-true} ${_BUILD_ARG_PYTHON_INSTALLJUPYTERLAB:-false} ${_BUILD_ARG_PYTHON_CONFIGUREJUPYTERLABALLOWORIGIN:-''}"
_BUILD_ARG_GO="./go/install.sh ${_BUILD_ARG_GOLANG_VERSION:-latest}"
_BUILD_ARG_JAVA="./java/wrapper.sh ${_BUILD_ARG_JAVA_VERSION:-latest}"
_BUILD_ARG_GRADLE="./gradle/install.sh ${_BUILD_ARG_GRADLE_VERSION:-latest}"
@@ -20,7 +20,6 @@ _BUILD_ARG_RUST="./rust/install.sh /usr
_BUILD_ARG_POWERSHELL="./powershell/install.sh ${_BUILD_ARG_POWERSHELL_VERSION:-latest}"
_BUILD_ARG_DESKTOP_LITE="./desktop-lite/install.sh automatic ${_BUILD_ARG_DESKTOP_LITE_PASSWORD:-vscode} true ${_BUILD_ARG_DESKTOP_LITE_VNCPORT:-5901} ${_BUILD_ARG_DESKTOP_LITE_WEBPORT:-6080}"
_BUILD_ARG_DOTNET="./dotnet/install.sh ${_BUILD_ARG_DOTNET_VERSION:-latest} ${_BUILD_ARG_DOTNET_RUNTIMEONLY:-false} automatic true /usr/local/dotnet dotnet ${_BUILD_ARG_DOTNET_OVERRIDEDEFAULTVERSION:-true} ${_BUILD_ARG_DOTNET_INSTALLUSINGAPT:-true}"
-_BUILD_ARG_JUPYTERLAB="./jupyterlab/install.sh ${_BUILD_ARG_JUPYTERLAB_VERSION:-latest} automatic ${_BUILD_ARG_JUPYTERLAB_PYTHONBINARY:-python} true"
_BUILD_ARG_PHP="./php/install.sh ${_BUILD_ARG_PHP_VERSION:-latest} /usr/local/php ${_BUILD_ARG_PHP_INSTALLCOMPOSER:-true} automatic true ${_BUILD_ARG_PHP_OVERRIDEDEFAULTVERSION:-true}"
_BUILD_ARG_ORYX="./oryx/install.sh automatic true"
_BUILD_ARG_HUGO="./hugo/install.sh ${_BUILD_ARG_HUGO_VERSION:-latest} automatic true"