From 97b5c54c1d2e400e1f36fee358ba99c7ea69c9f3 Mon Sep 17 00:00:00 2001 From: Ian Koerich Maciel Date: Tue, 5 Jul 2022 18:01:23 -0300 Subject: [PATCH 1/6] Add suport for .devcontainer.json file Devcontainer configuration might be saved on .devcontainer folder or .devcontainer.json. This commit add the missing support for .devcontainer.json file. --- devcontainer.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/devcontainer.sh b/devcontainer.sh index e957cdc..6944e53 100755 --- a/devcontainer.sh +++ b/devcontainer.sh @@ -84,8 +84,15 @@ debug "CONFIG_DIR: ${CONFIG_DIR}" CONFIG_FILE=devcontainer.json debug "CONFIG_FILE: ${CONFIG_FILE}" if ! [ -e "$CONFIG_DIR/$CONFIG_FILE" ]; then - echo "Folder contains no devcontainer configuration" - exit + # Config file may also be ".devcontainer.json" on the project folder. + CONFIG_DIR=. + debug "CONFIG_DIR: ${CONFIG_DIR}" + CONFIG_FILE=.devcontainer.json + debug "CONFIG_FILE: ${CONFIG_FILE}" + if ! [ -e "$CONFIG_DIR/$CONFIG_FILE" ]; then + echo "Folder contains no devcontainer configuration" + exit + fi fi CONFIG="$(cat "$CONFIG_DIR/$CONFIG_FILE")" From bebe1fab386386f7c15fa68e36617ea829c52990 Mon Sep 17 00:00:00 2001 From: Ian Koerich Maciel Date: Thu, 7 Jul 2022 11:17:31 -0300 Subject: [PATCH 2/6] Mount workspace on the same location as vscode vscode mounts the entire project (where .git is located) on /workspace. This commit changes the script behavior to find the .git folder, mount this bind and use the current workspace inside the docker just like vscode. --- devcontainer.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/devcontainer.sh b/devcontainer.sh index 6944e53..d53eff3 100755 --- a/devcontainer.sh +++ b/devcontainer.sh @@ -66,17 +66,14 @@ while getopts "$optspec" opt; do esac done +PROJECT_ROOT=$(git rev-parse --show-toplevel) -WORKSPACE="${*:$OPTIND:1}" -WORKSPACE="${WORKSPACE:-$PWD}" - -if [[ ! -d "$WORKSPACE" ]]; then - echo "Directory $WORKSPACE does not exist!" >&2 +if [[ ! -d "$PROJECT_ROOT" ]]; then + echo "Directory $PROJECT_ROOT does not exist!" >&2 exit 6 fi - -echo "Using workspace ${WORKSPACE}" +echo "Using workspace ${PROJECT_ROOT}" CONFIG_DIR=./.devcontainer debug "CONFIG_DIR: ${CONFIG_DIR}" @@ -144,11 +141,14 @@ debug "PORTS: ${PORTS}" ENVS=$(echo "$CONFIG" | jq -r '.remoteEnv | to_entries? | map("-e \(.key)=\(.value)")? | join(" ")') debug "ENVS: ${ENVS}" -WORK_DIR="/workspace" -debug "WORK_DIR: ${WORK_DIR}" +TARGET_PROJECT_ROOT="/workspace/$(basename $PROJECT_ROOT)" +debug "TARGET_PROJECT_ROOT: ${TARGET_PROJECT_ROOT}" -MOUNT="${MOUNT} --mount type=bind,source=${WORKSPACE},target=${WORK_DIR}" -debug "MOUNT: ${MOUNT}" +MOUNT="${MOUNT} --mount type=bind,source=${PROJECT_ROOT},target=${TARGET_PROJECT_ROOT}" +debug "MOUNT: ${TARGET_PROJECT_ROOT}" + +WORK_DIR=$(echo "$TARGET_PROJECT_ROOT${PWD#"$PROJECT_ROOT"}") +debug "WORK_DIR: ${WORK_DIR}" echo "Building and starting container" From 11e1b07b2163458050713c5a51c4d6e20c99cc8a Mon Sep 17 00:00:00 2001 From: Ian Koerich Maciel Date: Thu, 7 Jul 2022 11:56:21 -0300 Subject: [PATCH 3/6] Remove verbose output Avoid docker build output buy using the debug function. The output will be displayed if the flag VERBOSE is enabled. --- devcontainer.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devcontainer.sh b/devcontainer.sh index d53eff3..4b67bcb 100755 --- a/devcontainer.sh +++ b/devcontainer.sh @@ -154,8 +154,9 @@ echo "Building and starting container" DOCKER_TAG=$(echo "$DOCKER_FILE" | md5sum - | awk '{ print $1 }') # shellcheck disable=SC2086 -docker build -f "$DOCKER_FILE" -t "$DOCKER_TAG" $ARGS . +BUILD_OUTPUT=$(docker build -f "$DOCKER_FILE" -t "$DOCKER_TAG" $ARGS .) build_status=$? +debug $BUILD_OUTPUT if [[ $build_status -ne 0 ]]; then echo "Building docker image failed..." >&2 From ce84c462001beda172a1d4d96b0f8b6f61365f70 Mon Sep 17 00:00:00 2001 From: Ian Koerich Maciel Date: Wed, 13 Jul 2022 17:14:36 -0300 Subject: [PATCH 4/6] Define bash as the default shell if not specified --- devcontainer.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/devcontainer.sh b/devcontainer.sh index 4b67bcb..b411f9e 100755 --- a/devcontainer.sh +++ b/devcontainer.sh @@ -133,6 +133,9 @@ ARGS=$(echo "$CONFIG" | jq -r '.build.args | to_entries? | map("--build-arg \(.k debug "ARGS: ${ARGS}" SHELL=$(echo "$CONFIG" | jq -r '.settings."terminal.integrated.shell.linux"') +if [ "$SHELL" == "null" ]; then + SHELL="/bin/bash" +fi debug "SHELL: ${SHELL}" PORTS=$(echo "$CONFIG" | jq -r '.forwardPorts | map("-p \(.):\(.)")? | join(" ")') From 4e24d546d002ad4f01b6784882fd65a2e3efc84f Mon Sep 17 00:00:00 2001 From: Ian Koerich Maciel Date: Wed, 13 Jul 2022 17:17:37 -0300 Subject: [PATCH 5/6] Run post actions only when the docker is modified Include support for POST_CREATE_COMMAND and only execute these type of command if the docker file has changed and the image has to be built again. --- devcontainer.sh | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/devcontainer.sh b/devcontainer.sh index b411f9e..4418af6 100755 --- a/devcontainer.sh +++ b/devcontainer.sh @@ -141,6 +141,9 @@ debug "SHELL: ${SHELL}" PORTS=$(echo "$CONFIG" | jq -r '.forwardPorts | map("-p \(.):\(.)")? | join(" ")') debug "PORTS: ${PORTS}" +POST_CREATE_COMMAND=$(echo "$CONFIG" | jq -r .postCreateCommand) +debug "POST_CREATE_COMMAND: ${POST_CREATE_COMMAND}" + ENVS=$(echo "$CONFIG" | jq -r '.remoteEnv | to_entries? | map("-e \(.key)=\(.value)")? | join(" ")') debug "ENVS: ${ENVS}" @@ -156,6 +159,10 @@ debug "WORK_DIR: ${WORK_DIR}" echo "Building and starting container" DOCKER_TAG=$(echo "$DOCKER_FILE" | md5sum - | awk '{ print $1 }') + +# Check if tag already exists, if not than do post actions after build. +(docker inspect --type=image $DOCKER_TAG 2> /dev/null && SHOULD_RUN_POST_ACTIONS=0 || SHOULD_RUN_POST_ACTIONS=1) > /dev/null + # shellcheck disable=SC2086 BUILD_OUTPUT=$(docker build -f "$DOCKER_FILE" -t "$DOCKER_TAG" $ARGS .) build_status=$? @@ -172,19 +179,26 @@ set -e PUID=$(id -u) PGID=$(id -g) +if [ $SHOULD_RUN_POST_ACTIONS ]; then + echo "running post actions..."; + + CONFIGURE_USER_ID="\ + if [ '$REMOTE_USER' != '' ] && command -v usermod &>/dev/null; \ + then \ + sudo='' + if [ \"$(stat -f -c '%u' "$(which sudo)")\" = '0' ]; then + sudo=sudo + fi; + \$sudo usermod -u $PUID $REMOTE_USER && \ + \$sudo groupmod -g $PGID $REMOTE_USER && \ + \$sudo passwd -d $REMOTE_USER && \ + \$sudo chown $REMOTE_USER:$REMOTE_USER -R ~$REMOTE_USER $TARGET_PROJECT_ROOT; \ + fi;" + + docker run -it $DOCKER_OPTS $PORTS $ENVS $MOUNT -w "$WORK_DIR" "$DOCKER_TAG" "$SHELL" -c "$CONFIGURE_USER_ID" + docker run -it $DOCKER_OPTS $PORTS $ENVS $MOUNT -w "$WORK_DIR" "$DOCKER_TAG" $POST_CREATE_COMMAND +fi + # shellcheck disable=SC2086 -docker run -it $DOCKER_OPTS $PORTS $ENVS $MOUNT -w "$WORK_DIR" "$DOCKER_TAG" "$SHELL" -c "\ -if [ '$REMOTE_USER' != '' ] && command -v usermod &>/dev/null; \ -then \ - sudo='' - if [ \"$(stat -f -c '%u' "$(which sudo)")\" = '0' ]; then - sudo=sudo - fi - \$sudo usermod -u $PUID $REMOTE_USER && \ - \$sudo groupmod -g $PGID $REMOTE_USER && \ - \$sudo passwd -d $REMOTE_USER && \ - \$sudo chown $REMOTE_USER:$REMOTE_USER -R ~$REMOTE_USER $WORK_DIR && \ - su $REMOTE_USER -s $SHELL; \ -else \ - $SHELL; \ -fi" \ No newline at end of file + +docker run -it $DOCKER_OPTS $PORTS $ENVS $MOUNT -w "$WORK_DIR" "$DOCKER_TAG" "$SHELL" From 4482c0dd087da3b8c3cbf29d43e2f7fe2bfe8ab6 Mon Sep 17 00:00:00 2001 From: Ian Koerich Maciel Date: Wed, 13 Jul 2022 17:20:45 -0300 Subject: [PATCH 6/6] No not try to change user id if already the same This initialization script were not working correctly on mcr.microsoft.com/vscode/devcontainers/base:0-ubuntu-20.04 image. The commit avoid this unecessary code as the microsoft image already has the same user id. --- devcontainer.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/devcontainer.sh b/devcontainer.sh index 4418af6..5d67632 100755 --- a/devcontainer.sh +++ b/devcontainer.sh @@ -183,7 +183,9 @@ if [ $SHOULD_RUN_POST_ACTIONS ]; then echo "running post actions..."; CONFIGURE_USER_ID="\ - if [ '$REMOTE_USER' != '' ] && command -v usermod &>/dev/null; \ + REMOTE_PUID=\$(id -u); \ + REMOTE_PGID=\$(id -g); \ + if [ '$REMOTE_USER' != '' ] && command -v usermod &>/dev/null && [ \"$PUID\" != \"\$REMOTE_PUID\" ] && [ \"$PGID\" != \"\$REMOTE_PGID\" ]; \ then \ sudo='' if [ \"$(stat -f -c '%u' "$(which sudo)")\" = '0' ]; then