Skip to content

Commit e99bc62

Browse files
authored
Merge JupyterLab feature into Python feature (#40)
* Restructure tools installation * Tweak bash and zsh config * Remove extra space * Update comments * Add option to install JupyterLab * Add option to configure JupyterLab * Add option to install ML packages * Remove deprecated JuptyerLab feature * Add new arguments to Python feature * Remove trailing whitespace * Organize new arguments * Resolve feedback * Create new scenario for JupyterLab * Fix user in JupyterLab scenario * Revert changes to Python test * Remove ML packages * Update test names * Rename CORS option
1 parent b947d0e commit e99bc62

10 files changed

Lines changed: 126 additions & 166 deletions

File tree

.github/workflows/test-all.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ jobs:
2727
"go",
2828
"hugo",
2929
"java",
30-
"python jupyterlab", # Install 'python', then 'jupyterlab'
3130
"kubectl-helm-minikube",
3231
"node",
3332
"oryx",

.github/workflows/test-pr.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ jobs:
2727
go: ./**/go/**
2828
hugo: ./**/hugo/**
2929
java: ./**/java/**
30-
'python jupyterlab': ./**/jupyterlab/**
3130
kubectl-helm-minikube: ./**/kubectl-helm-minikube/**
3231
node: ./**/node/**
3332
oryx: ./**/oryx/**

src/jupyterlab/devcontainer-feature.json

Lines changed: 0 additions & 33 deletions
This file was deleted.

src/jupyterlab/install.sh

Lines changed: 0 additions & 71 deletions
This file was deleted.

src/python/devcontainer-feature.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@
3737
"type": "boolean",
3838
"default": "true",
3939
"description": "If true, overrides existing version (if any) of python on the PATH"
40+
},
41+
"install_jupyterlab": {
42+
"type": "boolean",
43+
"default": false,
44+
"description": "Install JupyterLab, a web-based interactive development environment for notebooks"
45+
},
46+
"configure_jupyterlab_allow_origin": {
47+
"type": "string",
48+
"default": "",
49+
"description": "Configure JupyterLab to accept HTTP requests from the specified origin"
4050
}
4151
},
4252
"containerEnv": {

src/python/install.sh

Lines changed: 84 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ USERNAME=${USERNAME:-"automatic"}
1919
UPDATE_RC=${UPDATE_RC:-"true"}
2020
USE_ORYX_IF_AVAILABLE=${USE_ORYX_IF_AVAILABLE:-"true"}
2121

22+
INSTALL_JUPYTERLAB=${INSTALL_JUPYTERLAB:-"false"}
23+
CONFIGURE_JUPYTERLAB_ALLOW_ORIGIN=${CONFIGURE_JUPYTERLAB_ALLOW_ORIGIN:-""}
24+
2225
DEFAULT_UTILS=("pylint" "flake8" "autopep8" "black" "yapf" "mypy" "pydocstyle" "pycodestyle" "bandit" "pipenv" "virtualenv")
2326
PYTHON_SOURCE_GPG_KEYS="64E628F8D684696D B26995E310250568 2D347EA6AA65421D FB9921286F5E1540 3A5CA953F73C700D 04C367C218ADD4FF 0EDDC5F26A45C816 6AF053F07D9DC8D2 C9BE28DEE6DF025C 126EB563A74B06BF D9866941EA5BBD71 ED9D77D5"
2427
GPG_KEY_SERVERS="keyserver hkp://keyserver.ubuntu.com:80
@@ -301,6 +304,32 @@ install_using_oryx() {
301304
add_symlink
302305
}
303306

307+
sudo_if() {
308+
COMMAND="$*"
309+
if [ "$(id -u)" -eq 0 ] && [ "$USERNAME" != "root" ]; then
310+
su - "$USERNAME" -c "$COMMAND"
311+
else
312+
"$COMMAND"
313+
fi
314+
}
315+
316+
install_user_package() {
317+
PACKAGE="$1"
318+
sudo_if "$INSTALL_PATH/bin/python3" -m pip install --user --upgrade --no-cache-dir "$PACKAGE"
319+
}
320+
321+
add_user_jupyter_config() {
322+
CONFIG_DIR="/home/$USERNAME/.jupyter"
323+
CONFIG_FILE="$CONFIG_DIR/jupyter_notebook_config.py"
324+
325+
# Make sure the config file exists or create it with proper permissions
326+
test -d "$CONFIG_DIR" || sudo_if mkdir "$CONFIG_DIR"
327+
test -f "$CONFIG_FILE" || sudo_if touch "$CONFIG_FILE"
328+
329+
# Don't write the same config more than once
330+
grep -q "$1" "$CONFIG_FILE" || echo "$1" >> "$CONFIG_FILE"
331+
}
332+
304333
# Ensure apt is in non-interactive to avoid prompts
305334
export DEBIAN_FRONTEND=noninteractive
306335

@@ -310,7 +339,7 @@ check_packages curl ca-certificates gnupg2 tar make gcc libssl-dev zlib1g-dev li
310339
libxmlsec1-dev libsqlite3-dev libffi-dev liblzma-dev uuid-dev
311340

312341

313-
# Install python from source if needed
342+
# Install Python from source if needed
314343
if [ "${PYTHON_VERSION}" != "none" ]; then
315344
CURRENT_PATH="${PYTHON_INSTALL_PATH}/current"
316345
# If the os-provided versions are "good enough", detect that and bail out.
@@ -330,53 +359,62 @@ if [ "${PYTHON_VERSION}" != "none" ]; then
330359
updaterc "if [[ \"\${PATH}\" != *\"${CURRENT_PATH}/bin\"* ]]; then export PATH=${CURRENT_PATH}/bin:\${PATH}; fi"
331360
fi
332361

333-
# If not installing python tools, exit
334-
if [ "${INSTALL_PYTHON_TOOLS}" != "true" ]; then
335-
echo "Done!"
336-
exit 0
337-
fi
362+
# Install Python tools if needed
363+
if [ "${INSTALL_PYTHON_TOOLS}" = "true" ]; then
364+
echo 'Installing Python tools...'
365+
export PIPX_BIN_DIR="${PIPX_HOME}/bin"
366+
export PATH="${CURRENT_PATH}/bin:${PIPX_BIN_DIR}:${PATH}"
338367

339-
export PIPX_BIN_DIR="${PIPX_HOME}/bin"
340-
export PATH="${CURRENT_PATH}/bin:${PIPX_BIN_DIR}:${PATH}"
368+
# Create pipx group, dir, and set sticky bit
369+
if ! cat /etc/group | grep -e "^pipx:" > /dev/null 2>&1; then
370+
groupadd -r pipx
371+
fi
372+
usermod -a -G pipx ${USERNAME}
373+
umask 0002
374+
mkdir -p ${PIPX_BIN_DIR}
375+
chown :pipx ${PIPX_HOME} ${PIPX_BIN_DIR}
376+
chmod g+s ${PIPX_HOME} ${PIPX_BIN_DIR}
377+
378+
# Update pip if not using os provided python
379+
if [ ${PYTHON_VERSION} != "os-provided" ] && [ ${PYTHON_VERSION} != "system" ] && [ ${PYTHON_VERSION} != "none" ]; then
380+
echo "Updating pip..."
381+
"${INSTALL_PATH}/bin/python3" -m pip install --no-cache-dir --upgrade pip
382+
fi
341383

342-
# Create pipx group, dir, and set sticky bit
343-
if ! cat /etc/group | grep -e "^pipx:" > /dev/null 2>&1; then
344-
groupadd -r pipx
345-
fi
346-
usermod -a -G pipx ${USERNAME}
347-
umask 0002
348-
mkdir -p ${PIPX_BIN_DIR}
349-
chown :pipx ${PIPX_HOME} ${PIPX_BIN_DIR}
350-
chmod g+s ${PIPX_HOME} ${PIPX_BIN_DIR}
351-
352-
# Update pip if not using os provided python
353-
if [ ${PYTHON_VERSION} != "os-provided" ] && [ ${PYTHON_VERSION} != "system" ] && [ ${PYTHON_VERSION} != "none" ]; then
354-
echo "Updating pip..."
355-
${INSTALL_PATH}/bin/python3 -m pip install --no-cache-dir --upgrade pip
356-
fi
384+
# Install tools
385+
echo "Installing Python tools..."
386+
export PYTHONUSERBASE=/tmp/pip-tmp
387+
export PIP_CACHE_DIR=/tmp/pip-tmp/cache
388+
PIPX_DIR=""
389+
if ! type pipx > /dev/null 2>&1; then
390+
pip3 install --disable-pip-version-check --no-cache-dir --user pipx 2>&1
391+
/tmp/pip-tmp/bin/pipx install --pip-args=--no-cache-dir pipx
392+
PIPX_DIR="/tmp/pip-tmp/bin"
393+
fi
394+
for util in "${DEFAULT_UTILS[@]}"; do
395+
if ! type ${util} > /dev/null 2>&1; then
396+
"${PIPX_DIR}/pipx" install --system-site-packages --pip-args '--no-cache-dir --force-reinstall' ${util}
397+
else
398+
echo "${util} already installed. Skipping."
399+
fi
400+
done
401+
rm -rf /tmp/pip-tmp
357402

358-
# Install tools
359-
echo "Installing Python tools..."
360-
export PYTHONUSERBASE=/tmp/pip-tmp
361-
export PIP_CACHE_DIR=/tmp/pip-tmp/cache
362-
pipx_path=""
363-
if ! type pipx > /dev/null 2>&1; then
364-
pip3 install --disable-pip-version-check --no-cache-dir --user pipx 2>&1
365-
/tmp/pip-tmp/bin/pipx install --pip-args=--no-cache-dir pipx
366-
pipx_path="/tmp/pip-tmp/bin/"
403+
updaterc "export PIPX_HOME=\"${PIPX_HOME}\""
404+
updaterc "export PIPX_BIN_DIR=\"${PIPX_BIN_DIR}\""
405+
updaterc "if [[ \"\${PATH}\" != *\"\${PIPX_BIN_DIR}\"* ]]; then export PATH=\"\${PATH}:\${PIPX_BIN_DIR}\"; fi"
367406
fi
368-
for util in "${DEFAULT_UTILS[@]}"; do
369-
if ! type ${util} > /dev/null 2>&1; then
370-
${pipx_path}pipx install --system-site-packages --pip-args '--no-cache-dir --force-reinstall' ${util}
371-
else
372-
echo "${util} already installed. Skipping."
407+
408+
# Install JupyterLab if needed
409+
if [ "${INSTALL_JUPYTERLAB}" = "true" ]; then
410+
install_user_package jupyterlab
411+
412+
# Configure JupyterLab if needed
413+
# TODO: True if it's not empty
414+
if [ -n "${CONFIGURE_JUPYTERLAB_ALLOW_ORIGIN}" ]; then
415+
add_user_jupyter_config "c.ServerApp.allow_origin = '${CONFIGURE_JUPYTERLAB_ALLOW_ORIGIN}'"
416+
add_user_jupyter_config "c.NotebookApp.allow_origin = '${CONFIGURE_JUPYTERLAB_ALLOW_ORIGIN}'"
373417
fi
374-
done
375-
rm -rf /tmp/pip-tmp
376-
377-
updaterc "$(cat << EOF
378-
export PIPX_HOME="${PIPX_HOME}"
379-
export PIPX_BIN_DIR="${PIPX_BIN_DIR}"
380-
if [[ "\${PATH}" != *"\${PIPX_BIN_DIR}"* ]]; then export PATH="\${PATH}:\${PIPX_BIN_DIR}"; fi
381-
EOF
382-
)"
418+
fi
419+
420+
echo "Done!"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
# Optional: Import test library
6+
source dev-container-features-test-lib
7+
8+
check "version" jupyter lab --version
9+
check "config" grep ".*.allow_origin = '*'" /home/vscode/.jupyter/jupyter_notebook_config.py
10+
11+
# Report result
12+
reportResults

test-scenarios/scenarios.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,24 @@
1616
}
1717
}
1818
]
19+
},
20+
"install_jupyterlab": {
21+
"image": "mcr.microsoft.com/vscode/devcontainers/base:focal",
22+
"remoteUser": "vscode",
23+
"features": [
24+
{
25+
"id": "common",
26+
"options": {
27+
"username": "vscode"
28+
}
29+
},
30+
{
31+
"id": "python",
32+
"options": {
33+
"install_jupyterlab": true,
34+
"configure_jupyterlab_allow_origin": "*"
35+
}
36+
}
37+
]
1938
}
2039
}

test/jupyterlab/test.sh

Lines changed: 0 additions & 12 deletions
This file was deleted.

v1/feature-scripts.env

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ _BUILD_ARG_AWS_CLI="./aws-cli/install.sh ${_B
1010
_BUILD_ARG_AZURE_CLI="./az-cli/install.sh ${_BUILD_ARG_AZURE_CLI_VERSION:-latest}"
1111
_BUILD_ARG_SSHD="./sshd/install.sh"
1212
_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}"
13-
_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}"
13+
_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:-''}"
1414
_BUILD_ARG_GO="./go/install.sh ${_BUILD_ARG_GOLANG_VERSION:-latest}"
1515
_BUILD_ARG_JAVA="./java/wrapper.sh ${_BUILD_ARG_JAVA_VERSION:-latest}"
1616
_BUILD_ARG_GRADLE="./gradle/install.sh ${_BUILD_ARG_GRADLE_VERSION:-latest}"
@@ -20,7 +20,6 @@ _BUILD_ARG_RUST="./rust/install.sh /usr
2020
_BUILD_ARG_POWERSHELL="./powershell/install.sh ${_BUILD_ARG_POWERSHELL_VERSION:-latest}"
2121
_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}"
2222
_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}"
23-
_BUILD_ARG_JUPYTERLAB="./jupyterlab/install.sh ${_BUILD_ARG_JUPYTERLAB_VERSION:-latest} automatic ${_BUILD_ARG_JUPYTERLAB_PYTHONBINARY:-python} true"
2423
_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}"
2524
_BUILD_ARG_ORYX="./oryx/install.sh automatic true"
2625
_BUILD_ARG_HUGO="./hugo/install.sh ${_BUILD_ARG_HUGO_VERSION:-latest} automatic true"

0 commit comments

Comments
 (0)