#!/usr/bin/env bash PYODIDE_IMAGE_REPO="pyodide" PYODIDE_IMAGE_TAG="20220525-py310-chrome102-firefox100" PYODIDE_PREBUILT_IMAGE_TAG="0.20.0" DEFAULT_PYODIDE_DOCKER_IMAGE="${PYODIDE_IMAGE_REPO}/pyodide-env:${PYODIDE_IMAGE_TAG}" DEFAULT_PYODIDE_SYSTEM_PORT="none" DOCKER_COMMAND="/bin/bash" DOCKER_INTERACTIVE="--interactive" USER_HOME="/src/.docker_home" USER_NAME="$(id -u -n)" USER_ID="$(id -u)" USER_GID="$(id -g)" USER_COMMENT_FIELD="${USER_NAME} pyodide user alias" USER_INTERPRETER="/sbin/nologin" USER_FLAG=("--user" "$USER_ID:$USER_GID") HEALTHCHECK_MESSAGE="Done initialization" set -eo pipefail function usage() { cat > /dev/stdout < System port to which to forward. This is ignored if the env var PYODIDE_SYSTEM_PORT is set. If set to 'none', docker instance will not bind to any port. --non-interactive Run docker without the --interactive flag. Useful for running in headless mode on CI server. --root Run as root user inside the container Prerequisites: Docker has to be set up on your system. EOF } function error() { usage exit 255 } while [[ $# -gt 0 ]] do key="$1" case $key in -h|--help) usage exit 0 ;; --pre-built) if [[ -n ${PYODIDE_DOCKER_IMAGE} ]]; then echo "WARNING: will use the env var PYODIDE_DOCKER_IMAGE=${PYODIDE_DOCKER_IMAGE}, the flag --pre-built has no effect" fi DEFAULT_PYODIDE_DOCKER_IMAGE="pyodide/pyodide:${PYODIDE_PREBUILT_IMAGE_TAG}" shift ;; -p|--port) if [ "$#" -lt 2 ]; then >&2 echo "port cannot be empty" error fi if [[ -n ${PYODIDE_SYSTEM_PORT} ]]; then echo "WARNING: will use the env var PYODIDE_SYSTEM_PORT=${PYODIDE_SYSTEM_PORT} instead of the provided port" else PYODIDE_SYSTEM_PORT=$2 fi shift 2 ;; --non-interactive) DOCKER_INTERACTIVE="--interactive=false" shift ;; --root) USER_FLAG=() shift ;; -*) >&2 echo "Unknown option $1" error ;; *) DOCKER_COMMAND="$*" break ;; esac done PYODIDE_DOCKER_PORT=${PYODIDE_DOCKER_PORT:-"8000"} PYODIDE_SYSTEM_PORT=${PYODIDE_SYSTEM_PORT:-${DEFAULT_PYODIDE_SYSTEM_PORT}} PYODIDE_DOCKER_IMAGE=${PYODIDE_DOCKER_IMAGE:-${DEFAULT_PYODIDE_DOCKER_IMAGE}} # in case the port is not a number, do not bind the port case $PYODIDE_SYSTEM_PORT in none) PORT_CONFIGURATION_LINE=() ;; ''|*[!0-9]*) # contains a non-digit character, therefore it is not a number echo "WARNING: Invalid port argument '$PYODIDE_SYSTEM_PORT'. Port binding disabled." PORT_CONFIGURATION_LINE=() ;; *) PORT_CONFIGURATION_LINE=("-p" "$PYODIDE_SYSTEM_PORT:$PYODIDE_DOCKER_PORT") ;; esac mkdir -p .docker_home # Start a detached container as root, add the host uname and uid to /etc/passwd, # then run forever CONTAINER=$(\ docker run \ "${PORT_CONFIGURATION_LINE[@]}" \ -d --rm \ -v "$PWD":/src \ --user root \ --shm-size 2g \ "${PYODIDE_DOCKER_IMAGE}" \ /bin/bash -c " \ groupadd --gid '$USER_GID' '$USER_NAME'; \ useradd \ --home '$USER_HOME' \ --uid '$USER_ID' \ --gid '$USER_GID' \ --comment '$USER_COMMENT_FIELD' \ --shell '$USER_INTERPRETER' \ --groups sudo \ $USER_NAME \ ; \ echo '%sudo ALL=(ALL:ALL) NOPASSWD:ALL' >> /etc/sudoers ; \ echo '$HEALTHCHECK_MESSAGE'; \ tail -f /dev/null \ " \ ) until docker logs "$CONTAINER" 2>&1 | grep -q "$HEALTHCHECK_MESSAGE"; do echo "Waiting for initialization to finish..." sleep 0.2 done EXIT_STATUS=0 # Execute the provided command as the host user with HOME=/src docker exec \ "$DOCKER_INTERACTIVE" --tty \ "${USER_FLAG[@]}" \ "$CONTAINER" \ /bin/bash -c "${DOCKER_COMMAND}" || EXIT_STATUS=$? docker kill "$CONTAINER" > /dev/null exit $EXIT_STATUS