diff --git a/src/common-utils/devcontainer-feature.json b/src/common-utils/devcontainer-feature.json index 3fa6487df..715f5a55c 100644 --- a/src/common-utils/devcontainer-feature.json +++ b/src/common-utils/devcontainer-feature.json @@ -64,6 +64,31 @@ "type": "boolean", "default": false, "description": "Add packages from non-free Debian repository? (Debian only)" + }, + "allowShellHistory": { + "type": "boolean", + "default": false, + "description": "Preserve shell history across dev container instances? (Currently supports bash, zsh, and fish)" } - } -} + }, + "containerEnv": { + "DOCKER_BUILDKIT": "1" + }, + "postCreateCommand": "export DEVCONTAINER_ID=${devcontainerId} && . /etc/setup_history.sh", + "mounts": [{ + "source": "devcontainers", + "target": "/devcontainers", + "type": "volume" + }, + { + "source": "dind-var-lib-docker-${devcontainerId}", + "target": "/var/lib/docker", + "type": "volume" + }, + { + "source": "/var/run/docker.sock", + "target": "/var/run/docker.sock", + "type": "bind" + }], + "entrypoint": "/usr/local/share/docker-init.sh" +} diff --git a/src/common-utils/main.sh b/src/common-utils/main.sh index b5fe11f57..19f28bade 100644 --- a/src/common-utils/main.sh +++ b/src/common-utils/main.sh @@ -18,6 +18,7 @@ USERNAME="${USERNAME:-"automatic"}" USER_UID="${USERUID:-"automatic"}" USER_GID="${USERGID:-"automatic"}" ADD_NON_FREE_PACKAGES="${NONFREEPACKAGES:-"false"}" +ALLOW_SHELL_HISTORY="${ALLOWSHELLHISTORY:-"false"}" MARKER_FILE="/usr/local/etc/vscode-dev-containers/common" @@ -567,6 +568,20 @@ if [ "${INSTALL_ZSH}" = "true" ]; then fi fi +# ********************************* +# ** Enable shell history ** +# ********************************* + +echo export ALLOW_SHELL_HISTORY="${ALLOW_SHELL_HISTORY}" > /etc/env.sh +echo export user_home="${user_home}" >> /etc/env.sh +echo export USERNAME="${USERNAME}" >> /etc/env.sh + +chown "$USERNAME":"$USERNAME" "/etc/env.sh" +chmod u+rx "/etc/env.sh" + +cp -f "${FEATURE_DIR}/scripts/setup_history.sh" /etc/setup_history.sh +chmod +x /etc/setup_history.sh + # ********************************* # ** Ensure config directory ** # ********************************* diff --git a/src/common-utils/scripts/setup_history.sh b/src/common-utils/scripts/setup_history.sh new file mode 100755 index 000000000..8c8c9bf78 --- /dev/null +++ b/src/common-utils/scripts/setup_history.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +set -e + +# Source the environment variables from env.sh +if [ -f /etc/env.sh ]; then + echo "importing values from env.sh.." + . /etc/env.sh +else + echo "env.sh not found!" +fi + +if [ "${ALLOW_SHELL_HISTORY}" = "true" ]; then + echo "Activating feature 'shell-history'" + echo "User: ${USERNAME} User home: ${user_home}" + + echo "Creating sub-folder with ${DEVCONTAINER_ID}.." + + # Create the shell history directory in the mounted volume + BASE_HISTORY_DIR="/devcontainers" + HISTORY_DIR="${BASE_HISTORY_DIR}/${DEVCONTAINER_ID}/shellHistory" + USER_HISTORY_FILE="${user_home}/.bash_history" + VOLUME_HISTORY_FILE="${HISTORY_DIR}/.bash_history" + + # Create the history directory in the volume, if it doesn’t already exist + sudo mkdir -p "${HISTORY_DIR}" + sudo chown -R "${USERNAME}" "${HISTORY_DIR}" + sudo chmod -R u+rwx "${HISTORY_DIR}" + + # Ensure the volume's history file exists and set permissions + sudo touch "${VOLUME_HISTORY_FILE}" + sudo chown -R "${USERNAME}" "${VOLUME_HISTORY_FILE}" + sudo chmod -R u+rwx "${VOLUME_HISTORY_FILE}" + + # Symlink for Bash history + sudo ln -sf ${USER_HISTORY_FILE} ${VOLUME_HISTORY_FILE} + + # Configure immediate history saving to the volume + if ! grep -q "PROMPT_COMMAND" "${user_home}/.bashrc"; then + echo 'PROMPT_COMMAND="history -a; history -r;"' >> "${user_home}/.bashrc" + fi + + echo "Shell history setup for history persistence amongst active containers is complete." +fi diff --git a/test/common-utils/allow_shell_history.sh b/test/common-utils/allow_shell_history.sh new file mode 100644 index 000000000..efe4449e6 --- /dev/null +++ b/test/common-utils/allow_shell_history.sh @@ -0,0 +1,124 @@ +#!/bin/bash + +set -e + +# Optional: Import test library +source dev-container-features-test-lib + +# Name of the generated script file +SCRIPT_NAME="build_and_run.sh" + +# Dynamically write the script to a file +cat > $SCRIPT_NAME <<'EOF' +#!/bin/bash + +# Parameters +BASE_IMAGE=${1:-"ubuntu:latest"} +IMAGE_NAME=${2:-"custom-image"} + +cat > setup_history.sh <> "/home/vscode/.bashrc" +fi + +echo "Shell history setup for history persistence amongst active containers is complete." +EOL + +# Create entrypoint script +cat > entrypoint.sh < /var/log/entrypoint.log + +# Execute setup history script +chmod +x /usr/local/bin/setup_history.sh >> /var/log/entrypoint.log 2>&1 +/usr/local/bin/setup_history.sh >> /var/log/entrypoint.log 2>&1 + +# Keep the container running +tail -f /dev/null +EOL + +# Create Dockerfile +cat > Dockerfile < /dev/null + +# Output the container ID to a file +echo "CONTAINER_ID=$CONTAINER_ID" > /tmp/container_id.txt + +echo "Started container: $CONTAINER_ID" +EOF + +# Make the generated script executable +chmod +x $SCRIPT_NAME +./$SCRIPT_NAME "mcr.microsoft.com/devcontainers/python:latest" "python-app" + +# Function to add shell history +add_shell_history() { + local container_id=$1 + local history_message=$2 + echo -e "\nWriting shell history: $history_message"; + sudo docker exec -i $container_id /bin/bash -c "echo \"$history_message\" >> ~/.bash_history" +} + +# Function to check shell history +check_shell_history() { + local container_id=$1 + echo -e "\nChecking shell history from container: "; + sudo docker exec -i $container_id /bin/bash -c "cat ~/.bash_history" +} + +source /tmp/container_id.txt + +# Start the container and add shell history +sudo docker start $CONTAINER_ID > /dev/null +add_shell_history $CONTAINER_ID "Shell History for First Container Created." +sudo docker stop $CONTAINER_ID > /dev/null + +# Start the container and check shell history persistence +sudo docker start $CONTAINER_ID > /dev/null +check_shell_history $CONTAINER_ID + +# Report result +reportResults diff --git a/test/common-utils/scenarios.json b/test/common-utils/scenarios.json index a929f534a..b500675a5 100644 --- a/test/common-utils/scenarios.json +++ b/test/common-utils/scenarios.json @@ -1,4 +1,20 @@ { + "allow_shell_history": { + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "docker-in-docker": {}, + "common-utils": { + "installZsh": true, + "allowShellHistory": true + } + }, + "overrideFeatureInstallOrder": [ + "./common-utils", + "./docker-in-docker" + ], + "remoteUser": "vscode", + "containerUser": "vscode" + }, "bionic": { "image": "ubuntu:bionic", "remoteUser": "devcontainer",