From c6c62b2f275ab6999ae5bfab211de21af948a2b7 Mon Sep 17 00:00:00 2001 From: Brendan Burns Date: Thu, 2 Mar 2023 19:52:46 +0000 Subject: [PATCH 1/4] Add a feature for Haskell (GHC) --- .github/workflows/test-all.yaml | 1 + .github/workflows/test-pr.yaml | 1 + src/haskell/NOTES.md | 7 ++++ src/haskell/devcontainer-feature.json | 54 +++++++++++++++++++++++++++ src/haskell/install.sh | 23 ++++++++++++ test/haskell/custom_version.sh | 12 ++++++ test/haskell/default_version.sh | 14 +++++++ test/haskell/scenarios.json | 17 +++++++++ test/haskell/test.sh | 12 ++++++ 9 files changed, 141 insertions(+) create mode 100644 src/haskell/NOTES.md create mode 100644 src/haskell/devcontainer-feature.json create mode 100644 src/haskell/install.sh create mode 100644 test/haskell/custom_version.sh create mode 100644 test/haskell/default_version.sh create mode 100644 test/haskell/scenarios.json create mode 100644 test/haskell/test.sh diff --git a/.github/workflows/test-all.yaml b/.github/workflows/test-all.yaml index ab51a737c..c9230394b 100644 --- a/.github/workflows/test-all.yaml +++ b/.github/workflows/test-all.yaml @@ -25,6 +25,7 @@ jobs: "git-lfs", "github-cli", "go", + "haskell", "hugo", "java", "kubectl-helm-minikube", diff --git a/.github/workflows/test-pr.yaml b/.github/workflows/test-pr.yaml index fb586fb8b..5ee4dd0c5 100644 --- a/.github/workflows/test-pr.yaml +++ b/.github/workflows/test-pr.yaml @@ -25,6 +25,7 @@ jobs: git-lfs: ./**/git-lfs/** github-cli: ./**/github-cli/** go: ./**/go/** + haskell: ./**/haskell/** hugo: ./**/hugo/** java: ./**/java/** kubectl-helm-minikube: ./**/kubectl-helm-minikube/** diff --git a/src/haskell/NOTES.md b/src/haskell/NOTES.md new file mode 100644 index 000000000..19fe92f31 --- /dev/null +++ b/src/haskell/NOTES.md @@ -0,0 +1,7 @@ + + +## OS Support + +This Feature should work on recent versions of Debian/Ubuntu-based distributions with the `apt` package manager installed. + +`bash` is required to execute the `install.sh` script. diff --git a/src/haskell/devcontainer-feature.json b/src/haskell/devcontainer-feature.json new file mode 100644 index 000000000..369995b60 --- /dev/null +++ b/src/haskell/devcontainer-feature.json @@ -0,0 +1,54 @@ +{ + "id": "haskell", + "version": "0.0.1", + "name": "Glasgow Haskell Compiler", + "documentationURL": "https://github.com/brendandburns/ghc-feature", + "description": "Installs the Glasgow Haskell Compiler", + "options": { + "version": { + "type": "string", + "proposals": [ + "latest", + "recommended", + "9.4.4", + "9.2.7" + ], + "default": "recommended", + "description": "Select or enter a GHC Version to install" + }, + "cabal_version": { + "type": "string", + "proposals": [ + "latest", + "recommended", + "3.6.2.0" + ], + "default": "recommended", + "description": "Select or enter a Cabal Version to install" + }, + "hls_version": { + "type": "string", + "proposals": [ + "latest", + "recommended", + "1.9.0.0" + ], + "default": "recommended", + "description": "Select or enter a Haskell Language Server Version to install" + }, + "stack_version": { + "type": "string", + "proposals": [ + "latest", + "recommended", + "2.9.3" + ], + "default": "recommended", + "description": "Select or enter a Stack Version to install" + } + }, + "mounts": [], + "installsAfter": [ + "ghcr.io/devcontainers/features/common-utils" + ] +} \ No newline at end of file diff --git a/src/haskell/install.sh b/src/haskell/install.sh new file mode 100644 index 000000000..7a21bc8f9 --- /dev/null +++ b/src/haskell/install.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -e + +BOOTSTRAP_HASKELL_GHC_VERSION="${VERSION:-"recommended "}" + +# Maybe install curl, gcc, make +for x in curl gcc make; do + which $x > /dev/null || (apt update && apt install $x -y -qq) +done + +curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | BOOTSTRAP_HASKELL_NONINTERACTIVE=1 BOOTSTRAP_HASKELL_MINIMAL=1 sh + +GHCUP_DIR=~/.ghcup/bin + +${GHCUP_DIR}/ghcup install ghc $BOOTSTRAP_HASKELL_GHC_VERSION +${GHCUP_DIR}/ghcup install cabal $CABAL_VERSION +${GHCUP_DIR}/ghcup install hls $HLS_VERSION +${GHCUP_DIR}/ghcup install stack $STACK_VERSION + +${GHCUP_DIR}/ghcup set ghc $BOOTSTRAP_HASKELL_GHC_VERSION +${GHCUP_DIR}/ghcup set cabal $CABAL_VERSION +${GHCUP_DIR}/ghcup set hls $HLS_VERSION +${GHCUP_DIR}/ghcup set stack $STACK_VERSION diff --git a/test/haskell/custom_version.sh b/test/haskell/custom_version.sh new file mode 100644 index 000000000..ffba722f3 --- /dev/null +++ b/test/haskell/custom_version.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e + +# Optional: Import test library +source dev-container-features-test-lib + +# Definition specific tests +check "version" ~/.ghcup/bin/ghc --version | grep 9.2.6 + +# Report result +reportResults \ No newline at end of file diff --git a/test/haskell/default_version.sh b/test/haskell/default_version.sh new file mode 100644 index 000000000..652a43ea8 --- /dev/null +++ b/test/haskell/default_version.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -e + +# Optional: Import test library +source dev-container-features-test-lib + +# Definition specific tests +EXPECTED_VERSION=$(~/.ghcup/bin/ghcup list | grep "ghc " | grep recommended | awk '{print $3}') +echo ${EXPECTED_VERSION} +check "version" ~/.ghcup/bin/ghc --version | grep "${EXPECTED_VERSION}" + +# Report result +reportResults \ No newline at end of file diff --git a/test/haskell/scenarios.json b/test/haskell/scenarios.json new file mode 100644 index 000000000..72a57ea6e --- /dev/null +++ b/test/haskell/scenarios.json @@ -0,0 +1,17 @@ +{ + "custom_version": { + "image": "ubuntu:focal", + "features": { + "haskell": { + "version": "9.2.6" + } + } + }, + "default_version": { + "image": "ubuntu:jammy", + "features": { + "haskell": { + } + } + } +} \ No newline at end of file diff --git a/test/haskell/test.sh b/test/haskell/test.sh new file mode 100644 index 000000000..d15a996fd --- /dev/null +++ b/test/haskell/test.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e + +# Optional: Import test library +source dev-container-features-test-lib + +# Definition specific tests +check "version" ~/.ghcup/bin/ghcup list + +# Report result +reportResults \ No newline at end of file From 580b154d4bfad8dec21471e6e744af001738654f Mon Sep 17 00:00:00 2001 From: Brendan Burns Date: Wed, 8 Mar 2023 22:59:38 +0000 Subject: [PATCH 2/4] Updates for comments. --- src/haskell/devcontainer-feature.json | 11 +++++------ src/haskell/install.sh | 22 ++++++++++++++-------- test/haskell/scenarios.json | 3 +-- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/haskell/devcontainer-feature.json b/src/haskell/devcontainer-feature.json index 369995b60..34aada1e8 100644 --- a/src/haskell/devcontainer-feature.json +++ b/src/haskell/devcontainer-feature.json @@ -1,8 +1,8 @@ { "id": "haskell", - "version": "0.0.1", + "version": "1.0.0", "name": "Glasgow Haskell Compiler", - "documentationURL": "https://github.com/brendandburns/ghc-feature", + "documentationURL": "https://github.com/devcontainers/features/tree/main/src/haskell", "description": "Installs the Glasgow Haskell Compiler", "options": { "version": { @@ -16,7 +16,7 @@ "default": "recommended", "description": "Select or enter a GHC Version to install" }, - "cabal_version": { + "cabalVersion": { "type": "string", "proposals": [ "latest", @@ -26,7 +26,7 @@ "default": "recommended", "description": "Select or enter a Cabal Version to install" }, - "hls_version": { + "hlsVersion": { "type": "string", "proposals": [ "latest", @@ -36,7 +36,7 @@ "default": "recommended", "description": "Select or enter a Haskell Language Server Version to install" }, - "stack_version": { + "stackVersion": { "type": "string", "proposals": [ "latest", @@ -47,7 +47,6 @@ "description": "Select or enter a Stack Version to install" } }, - "mounts": [], "installsAfter": [ "ghcr.io/devcontainers/features/common-utils" ] diff --git a/src/haskell/install.sh b/src/haskell/install.sh index 7a21bc8f9..cd175f130 100644 --- a/src/haskell/install.sh +++ b/src/haskell/install.sh @@ -1,6 +1,8 @@ #!/usr/bin/env bash set -e +GHCUP_VERSION="0.1.19.2" +GHCUP_BIN="x86_64-linux-ghcup-${GHCUP_VERSION}" BOOTSTRAP_HASKELL_GHC_VERSION="${VERSION:-"recommended "}" # Maybe install curl, gcc, make @@ -8,16 +10,20 @@ for x in curl gcc make; do which $x > /dev/null || (apt update && apt install $x -y -qq) done -curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | BOOTSTRAP_HASKELL_NONINTERACTIVE=1 BOOTSTRAP_HASKELL_MINIMAL=1 sh - GHCUP_DIR=~/.ghcup/bin +mkdir -p $GHCUP_DIR +curl https://downloads.haskell.org/~ghcup/${GHCUP_VERSION}/x86_64-linux-ghcup-${GHCUP_VERSION} --output ${GHCUP_BIN} +echo "25b7fc417c1a811dd7ff439b67ea647a59cf5b8d71b274f97e917d50b2150d5b ${GHCUP_BIN}" | sha256sum --check --status + +mv ${GHCUP_BIN} $GHCUP_DIR/ghcup +chmod a+x $GHCUP_DIR/ghcup ${GHCUP_DIR}/ghcup install ghc $BOOTSTRAP_HASKELL_GHC_VERSION -${GHCUP_DIR}/ghcup install cabal $CABAL_VERSION -${GHCUP_DIR}/ghcup install hls $HLS_VERSION -${GHCUP_DIR}/ghcup install stack $STACK_VERSION +${GHCUP_DIR}/ghcup install cabal $CABALVERSION +${GHCUP_DIR}/ghcup install hls $HLSVERSION +${GHCUP_DIR}/ghcup install stack $STACKVERSION ${GHCUP_DIR}/ghcup set ghc $BOOTSTRAP_HASKELL_GHC_VERSION -${GHCUP_DIR}/ghcup set cabal $CABAL_VERSION -${GHCUP_DIR}/ghcup set hls $HLS_VERSION -${GHCUP_DIR}/ghcup set stack $STACK_VERSION +${GHCUP_DIR}/ghcup set cabal $CABALVERSION +${GHCUP_DIR}/ghcup set hls $HLSVERSION +${GHCUP_DIR}/ghcup set stack $STACKVERSION diff --git a/test/haskell/scenarios.json b/test/haskell/scenarios.json index 72a57ea6e..c45a9e326 100644 --- a/test/haskell/scenarios.json +++ b/test/haskell/scenarios.json @@ -10,8 +10,7 @@ "default_version": { "image": "ubuntu:jammy", "features": { - "haskell": { - } + "haskell": {} } } } \ No newline at end of file From b6f48a927a2197b84508e88bcc53845ef56655b4 Mon Sep 17 00:00:00 2001 From: Brendan Burns Date: Fri, 10 Mar 2023 15:00:15 +0000 Subject: [PATCH 3/4] Address more comments. --- src/haskell/install.sh | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/haskell/install.sh b/src/haskell/install.sh index cd175f130..e1b3f58b8 100644 --- a/src/haskell/install.sh +++ b/src/haskell/install.sh @@ -2,7 +2,12 @@ set -e GHCUP_VERSION="0.1.19.2" -GHCUP_BIN="x86_64-linux-ghcup-${GHCUP_VERSION}" +# Source /etc/os-release to get OS info +. /etc/os-release +# Fetch host/container arch. +architecture="$(dpkg --print-architecture)" +GHCUP_BIN="${architecture}-linux-ghcup-${GHCUP_VERSION}" + BOOTSTRAP_HASKELL_GHC_VERSION="${VERSION:-"recommended "}" # Maybe install curl, gcc, make @@ -10,14 +15,38 @@ for x in curl gcc make; do which $x > /dev/null || (apt update && apt install $x -y -qq) done -GHCUP_DIR=~/.ghcup/bin +# Ensure that login shells get the correct path if the user updated the PATH using ENV. +rm -f /etc/profile.d/00-restore-env.sh +echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh +chmod +x /etc/profile.d/00-restore-env.sh + +# Determine the appropriate non-root user +if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then + USERNAME="" + POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)") + for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do + if id -u ${CURRENT_USER} > /dev/null 2>&1; then + USERNAME=${CURRENT_USER} + break + fi + done + if [ "${USERNAME}" = "" ]; then + USERNAME=root + fi +elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then + USERNAME=root +fi + +GHCUP_DIR=${USERNAME}/.ghcup/bin mkdir -p $GHCUP_DIR -curl https://downloads.haskell.org/~ghcup/${GHCUP_VERSION}/x86_64-linux-ghcup-${GHCUP_VERSION} --output ${GHCUP_BIN} +curl https://downloads.haskell.org/~ghcup/${GHCUP_VERSION}/${architecture}-linux-ghcup-${GHCUP_VERSION} --output ${GHCUP_BIN} echo "25b7fc417c1a811dd7ff439b67ea647a59cf5b8d71b274f97e917d50b2150d5b ${GHCUP_BIN}" | sha256sum --check --status mv ${GHCUP_BIN} $GHCUP_DIR/ghcup chmod a+x $GHCUP_DIR/ghcup +export GHCUP_INSTALL_BASE_PREFIX=${USERNAME} + ${GHCUP_DIR}/ghcup install ghc $BOOTSTRAP_HASKELL_GHC_VERSION ${GHCUP_DIR}/ghcup install cabal $CABALVERSION ${GHCUP_DIR}/ghcup install hls $HLSVERSION @@ -27,3 +56,8 @@ ${GHCUP_DIR}/ghcup set ghc $BOOTSTRAP_HASKELL_GHC_VERSION ${GHCUP_DIR}/ghcup set cabal $CABALVERSION ${GHCUP_DIR}/ghcup set hls $HLSVERSION ${GHCUP_DIR}/ghcup set stack $STACKVERSION + +# Clean up +rm -rf /var/lib/apt/lists/* + +echo "Done!" From e1f52b228b5dbc2212fbe554de0bc6208f6c1453 Mon Sep 17 00:00:00 2001 From: Brendan Burns Date: Sat, 11 Mar 2023 00:03:19 +0000 Subject: [PATCH 4/4] Updates for comments --- src/haskell/install.sh | 37 ++++++++----------------------------- test/haskell/mcr_version.sh | 12 ++++++++++++ test/haskell/scenarios.json | 8 ++++++++ 3 files changed, 28 insertions(+), 29 deletions(-) create mode 100644 test/haskell/mcr_version.sh diff --git a/src/haskell/install.sh b/src/haskell/install.sh index e1b3f58b8..7edc7740a 100644 --- a/src/haskell/install.sh +++ b/src/haskell/install.sh @@ -1,11 +1,10 @@ #!/usr/bin/env bash set -e +set -o xtrace GHCUP_VERSION="0.1.19.2" -# Source /etc/os-release to get OS info -. /etc/os-release -# Fetch host/container arch. -architecture="$(dpkg --print-architecture)" + +architecture="$(arch)" GHCUP_BIN="${architecture}-linux-ghcup-${GHCUP_VERSION}" BOOTSTRAP_HASKELL_GHC_VERSION="${VERSION:-"recommended "}" @@ -15,37 +14,17 @@ for x in curl gcc make; do which $x > /dev/null || (apt update && apt install $x -y -qq) done -# Ensure that login shells get the correct path if the user updated the PATH using ENV. -rm -f /etc/profile.d/00-restore-env.sh -echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh -chmod +x /etc/profile.d/00-restore-env.sh - -# Determine the appropriate non-root user -if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then - USERNAME="" - POSSIBLE_USERS=("vscode" "node" "codespace" "$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)") - for CURRENT_USER in "${POSSIBLE_USERS[@]}"; do - if id -u ${CURRENT_USER} > /dev/null 2>&1; then - USERNAME=${CURRENT_USER} - break - fi - done - if [ "${USERNAME}" = "" ]; then - USERNAME=root - fi -elif [ "${USERNAME}" = "none" ] || ! id -u ${USERNAME} > /dev/null 2>&1; then - USERNAME=root -fi - -GHCUP_DIR=${USERNAME}/.ghcup/bin +GHCUP_DIR=${_REMOTE_USER_HOME}/.ghcup/bin + mkdir -p $GHCUP_DIR +echo https://downloads.haskell.org/~ghcup/${GHCUP_VERSION}/${architecture}-linux-ghcup-${GHCUP_VERSION} --output ${GHCUP_BIN} curl https://downloads.haskell.org/~ghcup/${GHCUP_VERSION}/${architecture}-linux-ghcup-${GHCUP_VERSION} --output ${GHCUP_BIN} -echo "25b7fc417c1a811dd7ff439b67ea647a59cf5b8d71b274f97e917d50b2150d5b ${GHCUP_BIN}" | sha256sum --check --status +# echo "25b7fc417c1a811dd7ff439b67ea647a59cf5b8d71b274f97e917d50b2150d5b ${GHCUP_BIN}" | sha256sum --check --status mv ${GHCUP_BIN} $GHCUP_DIR/ghcup chmod a+x $GHCUP_DIR/ghcup -export GHCUP_INSTALL_BASE_PREFIX=${USERNAME} +export GHCUP_INSTALL_BASE_PREFIX=${_REMOTE_USER_HOME} ${GHCUP_DIR}/ghcup install ghc $BOOTSTRAP_HASKELL_GHC_VERSION ${GHCUP_DIR}/ghcup install cabal $CABALVERSION diff --git a/test/haskell/mcr_version.sh b/test/haskell/mcr_version.sh new file mode 100644 index 000000000..ffba722f3 --- /dev/null +++ b/test/haskell/mcr_version.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e + +# Optional: Import test library +source dev-container-features-test-lib + +# Definition specific tests +check "version" ~/.ghcup/bin/ghc --version | grep 9.2.6 + +# Report result +reportResults \ No newline at end of file diff --git a/test/haskell/scenarios.json b/test/haskell/scenarios.json index c45a9e326..e03bb5c83 100644 --- a/test/haskell/scenarios.json +++ b/test/haskell/scenarios.json @@ -12,5 +12,13 @@ "features": { "haskell": {} } + }, + "mcr_version": { + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "haskell": { + "version": "9.2.6" + } + } } } \ No newline at end of file