diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 7760128..436d7e2 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -7,8 +7,8 @@ ARG VSCODE_COMMIT COPY ./vscode-init /opt/vscode-init RUN cd /opt/vscode-init \ && ./00-install-vscode-server.sh ${VSCODE_COMMIT} \ - && ./01-install-vscode-extensions.sh ${VSCODE_COMMIT} \ - && ./02-download-container-tools-extension.sh + && ./01-install-extensions.sh ${VSCODE_COMMIT} \ + && ./02-download-extensions.sh WORKDIR /workspace diff --git a/.devcontainer/vscode-init/01-install-vscode-extensions.sh b/.devcontainer/vscode-init/01-install-extensions.sh similarity index 97% rename from .devcontainer/vscode-init/01-install-vscode-extensions.sh rename to .devcontainer/vscode-init/01-install-extensions.sh index 2bbbbd5..4ac30a2 100755 --- a/.devcontainer/vscode-init/01-install-vscode-extensions.sh +++ b/.devcontainer/vscode-init/01-install-extensions.sh @@ -6,7 +6,7 @@ set -e VSCODE_COMMIT=${1:-"7adae6a56e34cb64d08899664b814cf620465925"} VSCODE_SERVER_HOME="/root/.vscode-server/bin/${VSCODE_COMMIT}" -EXTENSIONS_FILE="vscode-extensions.txt" +EXTENSIONS_FILE="extensions-to-install.txt" # Check if VS Code server is installed if [ ! -f "${VSCODE_SERVER_HOME}/bin/code-server" ]; then diff --git a/.devcontainer/vscode-init/02-download-container-tools-extension.sh b/.devcontainer/vscode-init/02-download-container-tools-extension.sh deleted file mode 100755 index 0cde65b..0000000 --- a/.devcontainer/vscode-init/02-download-container-tools-extension.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/env bash -set -e - -# Container Tools Extension download script -# This script downloads the compatible Container Tools extension (ms-vscode-remote.remote-containers) -# VSIX file for the specified VS Code commit to /opt/ - -DOWNLOAD_DIR="/opt" -EXTENSION_PUBLISHER="ms-vscode-remote" -EXTENSION_NAME="remote-containers" - -EXTENSION_ID="${EXTENSION_PUBLISHER}.${EXTENSION_NAME}" -EXTENSION_FILEPATH="${DOWNLOAD_DIR}/${EXTENSION_PUBLISHER}.${EXTENSION_NAME}.vsix" -DOWNLOAD_URL="https://${EXTENSION_PUBLISHER}.gallery.vsassets.io/_apis/public/gallery/publisher/${EXTENSION_PUBLISHER}/extension/${EXTENSION_NAME}/latest/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage" - -# Download the extension VSIX file -echo "Downloading ${EXTENSION_ID} extension..." -echo "Target directory: ${DOWNLOAD_DIR}" -echo "Download URL: ${DOWNLOAD_URL}" -curl -sSL -o "${EXTENSION_FILEPATH}" "${DOWNLOAD_URL}" - -# Verify the download -if [ -f "${EXTENSION_FILEPATH}" ]; then - echo "Container Tools extension downloaded successfully to ${EXTENSION_FILEPATH}" - - # Display file information - echo "File size: $(du -h "${EXTENSION_FILEPATH}" | cut -f1)" -else - echo "Error: Failed to download Container Tools extension" - # exit 1 -fi - -echo "Container Tools extension download completed successfully" diff --git a/.devcontainer/vscode-init/02-download-extensions.sh b/.devcontainer/vscode-init/02-download-extensions.sh new file mode 100755 index 0000000..06c28d2 --- /dev/null +++ b/.devcontainer/vscode-init/02-download-extensions.sh @@ -0,0 +1,87 @@ +#!/bin/env bash +set -e + +# Some extensions are for the system VS Code, e.g. Dev Containers. +# Because installed extensions are enabled by default, and an extension +# like e.g. VS Code Vim would be disruptive to most users, we can +# download them instead. Then it is up to the user to extract and +# install the extension into their system VS Code in the TRE. +# In some cases, such as for VS Code Vim, the system VS Code install +# of the extension and its functionality gets inherited by devcontainers. + +EXTENSIONS_FILE="extensions-to-download.txt" +DOWNLOAD_DIR="/opt" +SUCCESSFUL_DOWNLOADS=() + +if [ ! -f "${EXTENSIONS_FILE}" ]; then + echo "Error: Extensions file not found at ${EXTENSIONS_FILE}" + exit 1 +fi + +echo "" +echo "Reading extensions from: ${EXTENSIONS_FILE}" +echo "Target directory: ${DOWNLOAD_DIR}" +echo "" + +download_extension() { + local extension_id="$1" + + # Skip empty lines and comments + if [[ -z "$extension_id" || "$extension_id" =~ ^[[:space:]]*# ]]; then + return 0 + fi + + # Example of valid ID: publisher-name.extension-name + if [[ "$extension_id" != *.* ]]; then + echo "Invalid extension ID format '$extension_id' - check for typos" + exit 1 + fi + + local publisher="${extension_id%.*}" + local extension_name="${extension_id#*.}" + + local extension_filepath="${DOWNLOAD_DIR}/${extension_id}.vsix" + local download_url="https://${publisher}.gallery.vsassets.io/_apis/public/gallery/publisher/${publisher}/extension/${extension_name}/latest/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage" + + echo "Downloading ${extension_id}..." + + if curl -sSL -o "${extension_filepath}" "${download_url}"; then + if [ -f "${extension_filepath}" ] && [ -s "${extension_filepath}" ]; then + if [ "$(cat "${extension_filepath}" | jq -r '.typeKey' 2>/dev/null)" = "ExtensionDoesNotExistException" ]; then + echo " ✗ Download failed: $extension_id does not exist" + echo "Response from Microsoft:" + cat "${extension_filepath}" | jq . + exit 1 + fi + fi + + if [ -f "${extension_filepath}" ] && [ -s "${extension_filepath}" ]; then + echo " ✓ Downloaded successfully ($(du -h "${extension_filepath}" | cut -f1))" + SUCCESSFUL_DOWNLOADS+=("$extension_id") + else + echo " ✗ Download failed - file is empty or missing" + [ -f "${extension_filepath}" ] && rm -f "${extension_filepath}" + exit 1 + fi + else + echo " ✗ Download failed - curl error" + [ -f "${extension_filepath}" ] && rm -f "${extension_filepath}" + exit 1 + fi +} + +# Read and process each extension +while IFS= read -r extension_id || [ -n "$extension_id" ]; do + # Remove leading/trailing whitespace + extension_id=$(echo "$extension_id" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') + download_extension "$extension_id" +done < "${EXTENSIONS_FILE}" + +if [ ${#SUCCESSFUL_DOWNLOADS[@]} -eq 0 ]; then + echo "No extensions found in ${EXTENSIONS_FILE}." + echo "" +else + echo "All extensions downloaded successfully:" + printf " ✓ %s\n" "${SUCCESSFUL_DOWNLOADS[@]}" + echo "" +fi diff --git a/.devcontainer/vscode-init/extensions-to-download.txt b/.devcontainer/vscode-init/extensions-to-download.txt new file mode 100644 index 0000000..ae18db9 --- /dev/null +++ b/.devcontainer/vscode-init/extensions-to-download.txt @@ -0,0 +1,6 @@ +# VS Code extensions list for downloading +# These extensions are to be extracted from the image and installed +# into the user's VS Code. They will not be available in the devcontainer. +# One extension ID per line. +ms-vscode-remote.remote-containers +vscodevim.vim \ No newline at end of file diff --git a/.devcontainer/vscode-init/extensions-to-install.txt b/.devcontainer/vscode-init/extensions-to-install.txt new file mode 100644 index 0000000..feafa5f --- /dev/null +++ b/.devcontainer/vscode-init/extensions-to-install.txt @@ -0,0 +1,15 @@ +# VS Code Extensions List +# These extensions will be enabled for all users of the devcontainer. +# One extension ID per line. +charliermarsh.ruff +Continue.continue +DavidAnson.vscode-markdownlint +eamodio.gitlens +marimo-team.vscode-marimo +mechatroner.rainbow-csv +ms-python.black-formatter +ms-toolsai.datawrangler +ms-toolsai.jupyter +REditorSupport.r +REditorSupport.r-syntax +yzhang.markdown-all-in-one \ No newline at end of file diff --git a/.devcontainer/vscode-init/vscode-extensions.txt b/.devcontainer/vscode-init/vscode-extensions.txt deleted file mode 100644 index 793d1da..0000000 --- a/.devcontainer/vscode-init/vscode-extensions.txt +++ /dev/null @@ -1,9 +0,0 @@ -# VS Code Extensions List -# One extension ID per line -Continue.continue -ms-python.black-formatter -ms-toolsai.jupyter -yzhang.markdown-all-in-one -mechatroner.rainbow-csv -marimo-team.vscode-marimo -ms-toolsai.datawrangler diff --git a/DEVCONTAINER.md b/DEVCONTAINER.md index f409a34..8c2ad03 100644 --- a/DEVCONTAINER.md +++ b/DEVCONTAINER.md @@ -95,15 +95,18 @@ The container is automatically built and published using GitHub Actions: │ ├── Dockerfile # Custom Docker build │ └── vscode-init/ # VS Code server and extensions setup │ ├── 00-install-vscode-server.sh -│ ├── 01-install-vscode-extensions.sh -| ├── 02-download-container-tools-extension.sh -│ └── vscode-extensions.txt +│ ├── 01-install-extensions.sh +│ ├── 02-download-extensions.sh +│ ├── extensions-to-download.txt +│ └── extensions-to-install.txt ├── .github/workflows/ -│ └── build-devcontainer.yml # Build and publish workflow -├── examples/ -│ └── USAGE.md # Usage examples -├── DEVCONTAINER.md # Detailed documentation -└── README.md # Overview and quick start +│ ├── build-devcontainer.yml # Build and publish workflow +│ └── build-publish-container.yml +├── assets/ # Documentation assets +├── docs/ # Additional documentation +├── DEVCONTAINER.md # Detailed documentation +├── README.md # Overview and quick start +└── SDF_TRE_SETUP.md # SDF TRE setup guide ``` ## 🔧 Customization