From f7164dbf9e8fbbef2699d3c705680352ea87414f Mon Sep 17 00:00:00 2001 From: Legonois <74224353+Legonois@users.noreply.github.com> Date: Wed, 30 Oct 2024 20:43:28 -0500 Subject: [PATCH 01/13] Began simple json file --- .../devcontainer-feature.json | 19 ++ src/databricks-homebrew/install.sh | 23 +++ src/databricks-homebrew/library_scripts.sh | 177 ++++++++++++++++++ src/hugo-homebrew/install.sh | 4 +- 4 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 src/databricks-homebrew/devcontainer-feature.json create mode 100644 src/databricks-homebrew/install.sh create mode 100644 src/databricks-homebrew/library_scripts.sh diff --git a/src/databricks-homebrew/devcontainer-feature.json b/src/databricks-homebrew/devcontainer-feature.json new file mode 100644 index 0000000..1c6f57a --- /dev/null +++ b/src/databricks-homebrew/devcontainer-feature.json @@ -0,0 +1,19 @@ +{ + "name": "Databricks CLI (via Homebrew)", + "id": "databricks-homebrew", + "version": "1.0.0", + "description": "Installs Databricks CLI via Homebrew.", + "options": { + "version": { + "default": "latest", + "description": "Select the version to install.", + "proposals": [ + "latest" + ], + "type": "string" + } + }, + "installsAfter": [ + "ghcr.io/devcontainers-extra/features/wget-homebrew" + ] +} diff --git a/src/databricks-homebrew/install.sh b/src/databricks-homebrew/install.sh new file mode 100644 index 0000000..41e2768 --- /dev/null +++ b/src/databricks-homebrew/install.sh @@ -0,0 +1,23 @@ +#!/bin/bash -i + +set -e + +source ./library_scripts.sh + +# nanolayer is a cli utility which keeps container layers as small as possible +# source code: https://github.com/devcontainers-contrib/nanolayer +# `ensure_nanolayer` is a bash function that will find any existing nanolayer installations, +# and if missing - will download a temporary copy that automatically get deleted at the end +# of the script +ensure_nanolayer nanolayer_location "v0.5.6" + + +$nanolayer_location \ + install \ + devcontainer-feature \ + "ghcr.io/devcontainers-contrib/features/homebrew-package:1" \ + --option tap='databricks/tap' \ + --option package='databricks' \ + --option version="$VERSION" + +echo 'Done!' \ No newline at end of file diff --git a/src/databricks-homebrew/library_scripts.sh b/src/databricks-homebrew/library_scripts.sh new file mode 100644 index 0000000..564b1c2 --- /dev/null +++ b/src/databricks-homebrew/library_scripts.sh @@ -0,0 +1,177 @@ +#!/bin/bash -i +# https://github.com/paul-gilber/devcontainer-features/blob/0b6eef97dd4c4876c332df0e2ecb97db4dfd3993/src/openshift-cli-homebrew/library_scripts.sh + +clean_download() { + # The purpose of this function is to download a file with minimal impact on container layer size + # this means if no valid downloader is found (curl or wget) then we install a downloader (currently wget) in a + # temporary manner, and making sure to + # 1. uninstall the downloader at the return of the function + # 2. revert back any changes to the package installer database/cache (for example apt-get lists) + # The above steps will minimize the leftovers being created while installing the downloader + # Supported distros: + # debian/ubuntu/alpine + + url=$1 + output_location=$2 + tempdir=$(mktemp -d) + downloader_installed="" + + function _apt_get_install() { + tempdir=$1 + + # copy current state of apt list - in order to revert back later (minimize contianer layer size) + cp -p -R /var/lib/apt/lists $tempdir + apt-get update -y + apt-get -y install --no-install-recommends wget ca-certificates + } + + function _apt_get_cleanup() { + tempdir=$1 + + echo "removing wget" + apt-get -y purge wget --auto-remove + + echo "revert back apt lists" + rm -rf /var/lib/apt/lists/* + rm -r /var/lib/apt/lists && mv $tempdir/lists /var/lib/apt/lists + } + + function _apk_install() { + tempdir=$1 + # copy current state of apk cache - in order to revert back later (minimize contianer layer size) + cp -p -R /var/cache/apk $tempdir + + apk add --no-cache wget + } + + function _apk_cleanup() { + tempdir=$1 + + echo "removing wget" + apk del wget + } + # try to use either wget or curl if one of them already installer + if type curl >/dev/null 2>&1; then + downloader=curl + elif type wget >/dev/null 2>&1; then + downloader=wget + else + downloader="" + fi + + # in case none of them is installed, install wget temporarly + if [ -z $downloader ] ; then + if [ -x "/usr/bin/apt-get" ] ; then + _apt_get_install $tempdir + elif [ -x "/sbin/apk" ] ; then + _apk_install $tempdir + else + echo "distro not supported" + exit 1 + fi + downloader="wget" + downloader_installed="true" + fi + + if [ $downloader = "wget" ] ; then + wget -q $url -O $output_location + else + curl -sfL $url -o $output_location + fi + + # NOTE: the cleanup procedure was not implemented using `trap X RETURN` only because + # alpine lack bash, and RETURN is not a valid signal under sh shell + if ! [ -z $downloader_installed ] ; then + if [ -x "/usr/bin/apt-get" ] ; then + _apt_get_cleanup $tempdir + elif [ -x "/sbin/apk" ] ; then + _apk_cleanup $tempdir + else + echo "distro not supported" + exit 1 + fi + fi + +} + + +ensure_nanolayer() { + # Ensure existance of the nanolayer cli program + local variable_name=$1 + + local required_version=$2 + # normalize version + if ! [[ $required_version == v* ]]; then + required_version=v$required_version + fi + + local nanolayer_location="" + + # If possible - try to use an already installed nanolayer + if [[ -z "${NANOLAYER_FORCE_CLI_INSTALLATION}" ]]; then + if [[ -z "${NANOLAYER_CLI_LOCATION}" ]]; then + if type nanolayer >/dev/null 2>&1; then + echo "Found a pre-existing nanolayer in PATH" + nanolayer_location=nanolayer + fi + elif [ -f "${NANOLAYER_CLI_LOCATION}" ] && [ -x "${NANOLAYER_CLI_LOCATION}" ] ; then + nanolayer_location=${NANOLAYER_CLI_LOCATION} + echo "Found a pre-existing nanolayer which were given in env variable: $nanolayer_location" + fi + + # make sure its of the required version + if ! [[ -z "${nanolayer_location}" ]]; then + local current_version + current_version=$($nanolayer_location --version) + if ! [[ $current_version == v* ]]; then + current_version=v$current_version + fi + + if ! [ $current_version == $required_version ]; then + echo "skipping usage of pre-existing nanolayer. (required version $required_version does not match existing version $current_version)" + nanolayer_location="" + fi + fi + + fi + + # If not previuse installation found, download it temporarly and delete at the end of the script + if [[ -z "${nanolayer_location}" ]]; then + + if [ "$(uname -sm)" == "Linux x86_64" ] || [ "$(uname -sm)" == "Linux aarch64" ]; then + tmp_dir=$(mktemp -d -t nanolayer-XXXXXXXXXX) + + clean_up () { + ARG=$? + rm -rf $tmp_dir + exit $ARG + } + trap clean_up EXIT + + + if [ -x "/sbin/apk" ] ; then + clib_type=musl + else + clib_type=gnu + fi + + tar_filename=nanolayer-"$(uname -m)"-unknown-linux-$clib_type.tgz + + # clean download will minimize leftover in case a downloaderlike wget or curl need to be installed + clean_download https://github.com/devcontainers-contrib/cli/releases/download/$required_version/$tar_filename $tmp_dir/$tar_filename + + tar xfzv $tmp_dir/$tar_filename -C "$tmp_dir" + chmod a+x $tmp_dir/nanolayer + nanolayer_location=$tmp_dir/nanolayer + + + else + echo "No binaries compiled for non-x86-linux architectures yet: $(uname -m)" + exit 1 + fi + fi + + # Expose outside the resolved location + declare -g ${variable_name}=$nanolayer_location + +} \ No newline at end of file diff --git a/src/hugo-homebrew/install.sh b/src/hugo-homebrew/install.sh index 8de5155..e518ab1 100644 --- a/src/hugo-homebrew/install.sh +++ b/src/hugo-homebrew/install.sh @@ -16,7 +16,7 @@ $nanolayer_location \ install \ devcontainer-feature \ "ghcr.io/devcontainers-contrib/features/homebrew-package:1" \ - --option package='hugo' --option version="$VERSION" - + --option package='hugo' \ + --option version="$VERSION" echo 'Done!' \ No newline at end of file From ba6d89e3e955a692f3da73dbbeef48502fc007d7 Mon Sep 17 00:00:00 2001 From: Legonois <74224353+Legonois@users.noreply.github.com> Date: Wed, 30 Oct 2024 21:00:09 -0500 Subject: [PATCH 02/13] Added the proper package name --- src/databricks-homebrew/install.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/databricks-homebrew/install.sh b/src/databricks-homebrew/install.sh index 41e2768..0c386f6 100644 --- a/src/databricks-homebrew/install.sh +++ b/src/databricks-homebrew/install.sh @@ -16,8 +16,7 @@ $nanolayer_location \ install \ devcontainer-feature \ "ghcr.io/devcontainers-contrib/features/homebrew-package:1" \ - --option tap='databricks/tap' \ - --option package='databricks' \ + --option package='databricks/tap/databricks' \ --option version="$VERSION" echo 'Done!' \ No newline at end of file From 3ae8a1b1206c2445d4e4b46ab4ff51ce2f041ce5 Mon Sep 17 00:00:00 2001 From: Legonois <74224353+Legonois@users.noreply.github.com> Date: Wed, 30 Oct 2024 21:05:25 -0500 Subject: [PATCH 03/13] Added tests --- .devcontainer/devcontainer.json | 3 ++- .github/workflows/test.yaml | 2 ++ src/databricks-homebrew/devcontainer-feature.json | 5 +---- src/hugo-homebrew/devcontainer-feature.json | 5 +---- test/databricks-homebrew/scenarios.json | 11 +++++++++++ test/databricks-homebrew/with_brew.sh | 14 ++++++++++++++ test/hugo-homebrew/scenarios.json | 1 - test/hugo-homebrew/with_brew.sh | 2 +- 8 files changed, 32 insertions(+), 11 deletions(-) create mode 100644 test/databricks-homebrew/scenarios.json create mode 100644 test/databricks-homebrew/with_brew.sh diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 7228d7f..18e8137 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -14,7 +14,8 @@ }, "extensions": [ "mads-hartmann.bash-ide-vscode", - "GitHub.copilot" + "GitHub.copilot", + "github.vscode-github-actions" ] } }, diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 3e71a92..cee5939 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -14,6 +14,7 @@ jobs: matrix: features: - hugo-homebrew + - databricks-homebrew baseImage: - debian:latest - ubuntu:latest @@ -34,6 +35,7 @@ jobs: matrix: features: - hugo-homebrew + - databricks-homebrew steps: - uses: actions/checkout@v4 diff --git a/src/databricks-homebrew/devcontainer-feature.json b/src/databricks-homebrew/devcontainer-feature.json index 1c6f57a..23ad25b 100644 --- a/src/databricks-homebrew/devcontainer-feature.json +++ b/src/databricks-homebrew/devcontainer-feature.json @@ -12,8 +12,5 @@ ], "type": "string" } - }, - "installsAfter": [ - "ghcr.io/devcontainers-extra/features/wget-homebrew" - ] + } } diff --git a/src/hugo-homebrew/devcontainer-feature.json b/src/hugo-homebrew/devcontainer-feature.json index b375d2c..e1ff844 100644 --- a/src/hugo-homebrew/devcontainer-feature.json +++ b/src/hugo-homebrew/devcontainer-feature.json @@ -12,8 +12,5 @@ ], "type": "string" } - }, - "installsAfter": [ - "ghcr.io/devcontainers-extra/features/wget-homebrew" - ] + } } diff --git a/test/databricks-homebrew/scenarios.json b/test/databricks-homebrew/scenarios.json new file mode 100644 index 0000000..ca66eaf --- /dev/null +++ b/test/databricks-homebrew/scenarios.json @@ -0,0 +1,11 @@ +{ + "with_brew": { + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "ghcr.io/devcontainers/features/common-utils:1": { + "upgradePackages": true + }, + "databricks-homebrew": {} + } + } +} \ No newline at end of file diff --git a/test/databricks-homebrew/with_brew.sh b/test/databricks-homebrew/with_brew.sh new file mode 100644 index 0000000..13a0dbe --- /dev/null +++ b/test/databricks-homebrew/with_brew.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -e + +# Optional: Import test library bundled with the devcontainer CLI +source dev-container-features-test-lib + +# Feature-specific tests +# The 'check' command comes from the dev-container-features-test-lib. +check "execute command" bash -c "databricks --version" + +# Report result +# If any of the checks above exited with a non-zero exit code, the test will fail. +reportResults diff --git a/test/hugo-homebrew/scenarios.json b/test/hugo-homebrew/scenarios.json index 6a916e4..b814073 100644 --- a/test/hugo-homebrew/scenarios.json +++ b/test/hugo-homebrew/scenarios.json @@ -5,7 +5,6 @@ "ghcr.io/devcontainers/features/common-utils:1": { "upgradePackages": true }, - "ghcr.io/devcontainers-extra/features/wget-homebrew:1": {}, "hugo-homebrew": {} } } diff --git a/test/hugo-homebrew/with_brew.sh b/test/hugo-homebrew/with_brew.sh index d6ca376..d78ac8d 100644 --- a/test/hugo-homebrew/with_brew.sh +++ b/test/hugo-homebrew/with_brew.sh @@ -7,7 +7,7 @@ source dev-container-features-test-lib # Feature-specific tests # The 'check' command comes from the dev-container-features-test-lib. -check "execute command" bash -c "hugo help | grep 'Hugo is a Fast and Flexible Static Site Generator'" +check "execute command" bash -c "hugo --help" # Report result # If any of the checks above exited with a non-zero exit code, the test will fail. From e0e3da264939813773eef4abe4658f1c5fb35269 Mon Sep 17 00:00:00 2001 From: Legonois <74224353+Legonois@users.noreply.github.com> Date: Wed, 30 Oct 2024 21:15:28 -0500 Subject: [PATCH 04/13] Added test files --- test/databricks-homebrew/test.sh | 14 ++++++++++++++ test/hugo-homebrew/test.sh | 14 ++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 test/databricks-homebrew/test.sh create mode 100644 test/hugo-homebrew/test.sh diff --git a/test/databricks-homebrew/test.sh b/test/databricks-homebrew/test.sh new file mode 100644 index 0000000..13a0dbe --- /dev/null +++ b/test/databricks-homebrew/test.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -e + +# Optional: Import test library bundled with the devcontainer CLI +source dev-container-features-test-lib + +# Feature-specific tests +# The 'check' command comes from the dev-container-features-test-lib. +check "execute command" bash -c "databricks --version" + +# Report result +# If any of the checks above exited with a non-zero exit code, the test will fail. +reportResults diff --git a/test/hugo-homebrew/test.sh b/test/hugo-homebrew/test.sh new file mode 100644 index 0000000..d78ac8d --- /dev/null +++ b/test/hugo-homebrew/test.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -e + +# Optional: Import test library bundled with the devcontainer CLI +source dev-container-features-test-lib + +# Feature-specific tests +# The 'check' command comes from the dev-container-features-test-lib. +check "execute command" bash -c "hugo --help" + +# Report result +# If any of the checks above exited with a non-zero exit code, the test will fail. +reportResults From 4a2b88efc604354e8929657e769a278319c11967 Mon Sep 17 00:00:00 2001 From: Legonois <74224353+Legonois@users.noreply.github.com> Date: Wed, 30 Oct 2024 21:29:48 -0500 Subject: [PATCH 05/13] added more tests --- .github/workflows/test.yaml | 1 + .../devcontainer-feature.json | 2 +- src/add-apt-repository/install.sh | 26 ++- src/add-apt-repository/library_scripts.sh | 177 ++++++++++++++++++ test/add-apt-repository/scenarios.json | 11 ++ test/add-apt-repository/test.sh | 14 ++ .../add-apt-repository/ubuntu-common-utils.sh | 14 ++ 7 files changed, 236 insertions(+), 9 deletions(-) create mode 100644 src/add-apt-repository/library_scripts.sh create mode 100644 test/add-apt-repository/scenarios.json create mode 100644 test/add-apt-repository/test.sh create mode 100644 test/add-apt-repository/ubuntu-common-utils.sh diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index cee5939..3943d74 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -13,6 +13,7 @@ jobs: strategy: matrix: features: + - add-apt-repository - hugo-homebrew - databricks-homebrew baseImage: diff --git a/src/add-apt-repository/devcontainer-feature.json b/src/add-apt-repository/devcontainer-feature.json index ca12967..12c2096 100644 --- a/src/add-apt-repository/devcontainer-feature.json +++ b/src/add-apt-repository/devcontainer-feature.json @@ -1,7 +1,7 @@ { "name": "Add 'add-apt-repository' command", "id": "add-apt-repository", - "version": "1.0.1", + "version": "1.0.2", "description": "Installs the 'add-apt-repository' command with apt.", "options": { "version": { diff --git a/src/add-apt-repository/install.sh b/src/add-apt-repository/install.sh index 192ef9e..156133d 100644 --- a/src/add-apt-repository/install.sh +++ b/src/add-apt-repository/install.sh @@ -1,10 +1,20 @@ -# TODO: Add a check to see if the package is already installed -# TODO: Add a check to see if apt-get is installed +#!/bin/bash -i -sudo apt update -y -sudo apt install software-properties-common -y +set -e -# if sudo apt-get --simulate install packageThatDoesntExist -# then echo "we're good" -# else echo "oops, something happened" -# fi +source ./library_scripts.sh + +# nanolayer is a cli utility which keeps container layers as small as possible +# source code: https://github.com/devcontainers-contrib/nanolayer +# `ensure_nanolayer` is a bash function that will find any existing nanolayer installations, +# and if missing - will download a temporary copy that automatically get deleted at the end +# of the script +ensure_nanolayer nanolayer_location "v0.5.6" + + +$nanolayer_location \ + install \ + apt-get \ + "software-properties-common" + +echo 'Done!' \ No newline at end of file diff --git a/src/add-apt-repository/library_scripts.sh b/src/add-apt-repository/library_scripts.sh new file mode 100644 index 0000000..564b1c2 --- /dev/null +++ b/src/add-apt-repository/library_scripts.sh @@ -0,0 +1,177 @@ +#!/bin/bash -i +# https://github.com/paul-gilber/devcontainer-features/blob/0b6eef97dd4c4876c332df0e2ecb97db4dfd3993/src/openshift-cli-homebrew/library_scripts.sh + +clean_download() { + # The purpose of this function is to download a file with minimal impact on container layer size + # this means if no valid downloader is found (curl or wget) then we install a downloader (currently wget) in a + # temporary manner, and making sure to + # 1. uninstall the downloader at the return of the function + # 2. revert back any changes to the package installer database/cache (for example apt-get lists) + # The above steps will minimize the leftovers being created while installing the downloader + # Supported distros: + # debian/ubuntu/alpine + + url=$1 + output_location=$2 + tempdir=$(mktemp -d) + downloader_installed="" + + function _apt_get_install() { + tempdir=$1 + + # copy current state of apt list - in order to revert back later (minimize contianer layer size) + cp -p -R /var/lib/apt/lists $tempdir + apt-get update -y + apt-get -y install --no-install-recommends wget ca-certificates + } + + function _apt_get_cleanup() { + tempdir=$1 + + echo "removing wget" + apt-get -y purge wget --auto-remove + + echo "revert back apt lists" + rm -rf /var/lib/apt/lists/* + rm -r /var/lib/apt/lists && mv $tempdir/lists /var/lib/apt/lists + } + + function _apk_install() { + tempdir=$1 + # copy current state of apk cache - in order to revert back later (minimize contianer layer size) + cp -p -R /var/cache/apk $tempdir + + apk add --no-cache wget + } + + function _apk_cleanup() { + tempdir=$1 + + echo "removing wget" + apk del wget + } + # try to use either wget or curl if one of them already installer + if type curl >/dev/null 2>&1; then + downloader=curl + elif type wget >/dev/null 2>&1; then + downloader=wget + else + downloader="" + fi + + # in case none of them is installed, install wget temporarly + if [ -z $downloader ] ; then + if [ -x "/usr/bin/apt-get" ] ; then + _apt_get_install $tempdir + elif [ -x "/sbin/apk" ] ; then + _apk_install $tempdir + else + echo "distro not supported" + exit 1 + fi + downloader="wget" + downloader_installed="true" + fi + + if [ $downloader = "wget" ] ; then + wget -q $url -O $output_location + else + curl -sfL $url -o $output_location + fi + + # NOTE: the cleanup procedure was not implemented using `trap X RETURN` only because + # alpine lack bash, and RETURN is not a valid signal under sh shell + if ! [ -z $downloader_installed ] ; then + if [ -x "/usr/bin/apt-get" ] ; then + _apt_get_cleanup $tempdir + elif [ -x "/sbin/apk" ] ; then + _apk_cleanup $tempdir + else + echo "distro not supported" + exit 1 + fi + fi + +} + + +ensure_nanolayer() { + # Ensure existance of the nanolayer cli program + local variable_name=$1 + + local required_version=$2 + # normalize version + if ! [[ $required_version == v* ]]; then + required_version=v$required_version + fi + + local nanolayer_location="" + + # If possible - try to use an already installed nanolayer + if [[ -z "${NANOLAYER_FORCE_CLI_INSTALLATION}" ]]; then + if [[ -z "${NANOLAYER_CLI_LOCATION}" ]]; then + if type nanolayer >/dev/null 2>&1; then + echo "Found a pre-existing nanolayer in PATH" + nanolayer_location=nanolayer + fi + elif [ -f "${NANOLAYER_CLI_LOCATION}" ] && [ -x "${NANOLAYER_CLI_LOCATION}" ] ; then + nanolayer_location=${NANOLAYER_CLI_LOCATION} + echo "Found a pre-existing nanolayer which were given in env variable: $nanolayer_location" + fi + + # make sure its of the required version + if ! [[ -z "${nanolayer_location}" ]]; then + local current_version + current_version=$($nanolayer_location --version) + if ! [[ $current_version == v* ]]; then + current_version=v$current_version + fi + + if ! [ $current_version == $required_version ]; then + echo "skipping usage of pre-existing nanolayer. (required version $required_version does not match existing version $current_version)" + nanolayer_location="" + fi + fi + + fi + + # If not previuse installation found, download it temporarly and delete at the end of the script + if [[ -z "${nanolayer_location}" ]]; then + + if [ "$(uname -sm)" == "Linux x86_64" ] || [ "$(uname -sm)" == "Linux aarch64" ]; then + tmp_dir=$(mktemp -d -t nanolayer-XXXXXXXXXX) + + clean_up () { + ARG=$? + rm -rf $tmp_dir + exit $ARG + } + trap clean_up EXIT + + + if [ -x "/sbin/apk" ] ; then + clib_type=musl + else + clib_type=gnu + fi + + tar_filename=nanolayer-"$(uname -m)"-unknown-linux-$clib_type.tgz + + # clean download will minimize leftover in case a downloaderlike wget or curl need to be installed + clean_download https://github.com/devcontainers-contrib/cli/releases/download/$required_version/$tar_filename $tmp_dir/$tar_filename + + tar xfzv $tmp_dir/$tar_filename -C "$tmp_dir" + chmod a+x $tmp_dir/nanolayer + nanolayer_location=$tmp_dir/nanolayer + + + else + echo "No binaries compiled for non-x86-linux architectures yet: $(uname -m)" + exit 1 + fi + fi + + # Expose outside the resolved location + declare -g ${variable_name}=$nanolayer_location + +} \ No newline at end of file diff --git a/test/add-apt-repository/scenarios.json b/test/add-apt-repository/scenarios.json new file mode 100644 index 0000000..c1311bc --- /dev/null +++ b/test/add-apt-repository/scenarios.json @@ -0,0 +1,11 @@ +{ + "ubuntu-common-utils": { + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "ghcr.io/devcontainers/features/common-utils:1": { + "upgradePackages": true + }, + "databricks-homebrew": {} + } + } +} \ No newline at end of file diff --git a/test/add-apt-repository/test.sh b/test/add-apt-repository/test.sh new file mode 100644 index 0000000..1fa2427 --- /dev/null +++ b/test/add-apt-repository/test.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -e + +# Optional: Import test library bundled with the devcontainer CLI +source dev-container-features-test-lib + +# Feature-specific tests +# The 'check' command comes from the dev-container-features-test-lib. +check "execute command" bash -c "add-apt-repository --help" + +# Report result +# If any of the checks above exited with a non-zero exit code, the test will fail. +reportResults diff --git a/test/add-apt-repository/ubuntu-common-utils.sh b/test/add-apt-repository/ubuntu-common-utils.sh new file mode 100644 index 0000000..1fa2427 --- /dev/null +++ b/test/add-apt-repository/ubuntu-common-utils.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -e + +# Optional: Import test library bundled with the devcontainer CLI +source dev-container-features-test-lib + +# Feature-specific tests +# The 'check' command comes from the dev-container-features-test-lib. +check "execute command" bash -c "add-apt-repository --help" + +# Report result +# If any of the checks above exited with a non-zero exit code, the test will fail. +reportResults From b1581ee682c56d20a2dcc0a375d5908f5a09688a Mon Sep 17 00:00:00 2001 From: Legonois <74224353+Legonois@users.noreply.github.com> Date: Thu, 31 Oct 2024 00:18:05 -0500 Subject: [PATCH 06/13] Added install via homebrew --- .../devcontainer-feature.json | 0 src/homebrew-package/install.sh | 116 ++++++++++++ src/homebrew-package/library_scripts.sh | 177 ++++++++++++++++++ 3 files changed, 293 insertions(+) create mode 100644 src/homebrew-package/devcontainer-feature.json create mode 100644 src/homebrew-package/install.sh create mode 100644 src/homebrew-package/library_scripts.sh diff --git a/src/homebrew-package/devcontainer-feature.json b/src/homebrew-package/devcontainer-feature.json new file mode 100644 index 0000000..e69de29 diff --git a/src/homebrew-package/install.sh b/src/homebrew-package/install.sh new file mode 100644 index 0000000..1b5f824 --- /dev/null +++ b/src/homebrew-package/install.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash +set -ex + +source ./library_scripts.sh + +PACKAGE=${PACKAGE:-""} +VERSION=${VERSION:-"latest"} +INSTALLATION_FLAGS=${INSTALLATION_FLAGS:-""} + +if [ -z "$PACKAGE" ]; then + echo -e "'package' variable is empty, skipping" + exit 0 +fi + +if [ "$(id -u)" -ne 0 ]; then + echo -e 'Script must be run as + root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +check_packages() { + if ! dpkg -s "$@" >/dev/null 2>&1; then + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update -y + fi + apt-get -y install --no-install-recommends "$@" + fi +} + +ensure_curl () { + if ! type curl >/dev/null 2>&1; then + apt-get update -y && apt-get -y install --no-install-recommends curl ca-certificates + fi +} + + + +install_via_homebrew() { + package=$1 + version=$2 + installation_flags=$3 + + # install Homebrew if does not exists + if ! type brew >/dev/null 2>&1; then + echo "Installing Homebrew..." + + # nanolayer is a cli utility which keeps container layers as small as possible + # source code: https://github.com/devcontainers-contrib/nanolayer + # `ensure_nanolayer` is a bash function that will find any existing nanolayer installations, + # and if missing - will download a temporary copy that automatically get deleted at the end + # of the script + ensure_nanolayer nanolayer_location "v0.4.29" + + $nanolayer_location \ + install \ + devcontainer-feature \ + "ghcr.io/meaningful-ooo/devcontainer-features/homebrew:2.0.3" \ + --option shallow_clone='true' --option update="true" + source /etc/profile.d/nanolayer-homebrew.sh + fi + + + if [ "$version" = "latest" ]; then + package_full="$package" + else + package_full="${package}@${version}" + fi + # Solves CVE-2022-24767 mitigation in Git >2.35.2 + # For more information: https://github.blog/2022-04-12-git-security-vulnerability-announced/ + git config --system --add safe.directory "$(brew --prefix)/Homebrew/Library/Taps/homebrew/homebrew-core" + + su - "$_REMOTE_USER" </dev/null 2>&1; then + downloader=curl + elif type wget >/dev/null 2>&1; then + downloader=wget + else + downloader="" + fi + + # in case none of them is installed, install wget temporarly + if [ -z $downloader ] ; then + if [ -x "/usr/bin/apt-get" ] ; then + _apt_get_install $tempdir + elif [ -x "/sbin/apk" ] ; then + _apk_install $tempdir + else + echo "distro not supported" + exit 1 + fi + downloader="wget" + downloader_installed="true" + fi + + if [ $downloader = "wget" ] ; then + wget -q $url -O $output_location + else + curl -sfL $url -o $output_location + fi + + # NOTE: the cleanup procedure was not implemented using `trap X RETURN` only because + # alpine lack bash, and RETURN is not a valid signal under sh shell + if ! [ -z $downloader_installed ] ; then + if [ -x "/usr/bin/apt-get" ] ; then + _apt_get_cleanup $tempdir + elif [ -x "/sbin/apk" ] ; then + _apk_cleanup $tempdir + else + echo "distro not supported" + exit 1 + fi + fi + +} + + +ensure_nanolayer() { + # Ensure existance of the nanolayer cli program + local variable_name=$1 + + local required_version=$2 + # normalize version + if ! [[ $required_version == v* ]]; then + required_version=v$required_version + fi + + local nanolayer_location="" + + # If possible - try to use an already installed nanolayer + if [[ -z "${NANOLAYER_FORCE_CLI_INSTALLATION}" ]]; then + if [[ -z "${NANOLAYER_CLI_LOCATION}" ]]; then + if type nanolayer >/dev/null 2>&1; then + echo "Found a pre-existing nanolayer in PATH" + nanolayer_location=nanolayer + fi + elif [ -f "${NANOLAYER_CLI_LOCATION}" ] && [ -x "${NANOLAYER_CLI_LOCATION}" ] ; then + nanolayer_location=${NANOLAYER_CLI_LOCATION} + echo "Found a pre-existing nanolayer which were given in env variable: $nanolayer_location" + fi + + # make sure its of the required version + if ! [[ -z "${nanolayer_location}" ]]; then + local current_version + current_version=$($nanolayer_location --version) + if ! [[ $current_version == v* ]]; then + current_version=v$current_version + fi + + if ! [ $current_version == $required_version ]; then + echo "skipping usage of pre-existing nanolayer. (required version $required_version does not match existing version $current_version)" + nanolayer_location="" + fi + fi + + fi + + # If not previuse installation found, download it temporarly and delete at the end of the script + if [[ -z "${nanolayer_location}" ]]; then + + if [ "$(uname -sm)" == "Linux x86_64" ] || [ "$(uname -sm)" == "Linux aarch64" ]; then + tmp_dir=$(mktemp -d -t nanolayer-XXXXXXXXXX) + + clean_up () { + ARG=$? + rm -rf $tmp_dir + exit $ARG + } + trap clean_up EXIT + + + if [ -x "/sbin/apk" ] ; then + clib_type=musl + else + clib_type=gnu + fi + + tar_filename=nanolayer-"$(uname -m)"-unknown-linux-$clib_type.tgz + + # clean download will minimize leftover in case a downloaderlike wget or curl need to be installed + clean_download https://github.com/devcontainers-contrib/cli/releases/download/$required_version/$tar_filename $tmp_dir/$tar_filename + + tar xfzv $tmp_dir/$tar_filename -C "$tmp_dir" + chmod a+x $tmp_dir/nanolayer + nanolayer_location=$tmp_dir/nanolayer + + + else + echo "No binaries compiled for non-x86-linux architectures yet: $(uname -m)" + exit 1 + fi + fi + + # Expose outside the resolved location + declare -g ${variable_name}=$nanolayer_location + +} \ No newline at end of file From b7ccd07d180ac26f612bdb2acdf36f2abf08a7ff Mon Sep 17 00:00:00 2001 From: Legonois <74224353+Legonois@users.noreply.github.com> Date: Thu, 31 Oct 2024 00:18:36 -0500 Subject: [PATCH 07/13] Added a permalink --- src/homebrew-package/install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/src/homebrew-package/install.sh b/src/homebrew-package/install.sh index 1b5f824..0608e06 100644 --- a/src/homebrew-package/install.sh +++ b/src/homebrew-package/install.sh @@ -1,3 +1,4 @@ +#https://github.com/devcontainers-extra/features/blob/d946acc92748f39f0d4dca08565295c07bc0ee13/archive/src/homebrew-package/install.sh #!/usr/bin/env bash set -ex From c7e6852f9c411df0cb4fce327a2e2c8ff53a7d28 Mon Sep 17 00:00:00 2001 From: Legonois <74224353+Legonois@users.noreply.github.com> Date: Thu, 31 Oct 2024 00:25:44 -0500 Subject: [PATCH 08/13] Added tap option --- .../devcontainer-feature.json | 47 +++++++++++++++++++ src/homebrew-package/install.sh | 8 +++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/homebrew-package/devcontainer-feature.json b/src/homebrew-package/devcontainer-feature.json index e69de29..027e109 100644 --- a/src/homebrew-package/devcontainer-feature.json +++ b/src/homebrew-package/devcontainer-feature.json @@ -0,0 +1,47 @@ +{ + "name": "Homebrew Package", + "id": "homebrew-package", + "version": "1.0.7", + "description": "Installs a Homebrew package.", + "documentationURL": "http://github.com/devcontainers-contrib/features/tree/main/src/homebrew-package", + "installsAfter": [ + "ghcr.io/meaningful-ooo/devcontainer-features/homebrew:2" + ], + "options": { + "package": { + "type": "string", + "proposals": [ + "typescript", + "vtop", + "fkill-cli" + ], + "default": "", + "description": "Select the Homebrew package to install." + }, + "version": { + "type": "string", + "proposals": [ + "latest" + ], + "default": "latest", + "description": "Select the version of the Homebrew package to install." + }, + "tap": { + "type": "string", + "proposals": [ + "homebrew/core" + ], + "default": "", + "description": "Select the Homebrew tap to use for this installation. If not provided, the default tap will be used. (`brew tap `)" + }, + "installation_flags": { + "type": "string", + "proposals": [ + "--ignore-dependencies" + ], + "default": "", + "description": "Additional installation flags. These would be used as extra arguments to the brew command (`brew install @`)" + } + + } +} \ No newline at end of file diff --git a/src/homebrew-package/install.sh b/src/homebrew-package/install.sh index 0608e06..201f9dd 100644 --- a/src/homebrew-package/install.sh +++ b/src/homebrew-package/install.sh @@ -7,6 +7,7 @@ source ./library_scripts.sh PACKAGE=${PACKAGE:-""} VERSION=${VERSION:-"latest"} INSTALLATION_FLAGS=${INSTALLATION_FLAGS:-""} +TAP=${TAP:-""} if [ -z "$PACKAGE" ]; then echo -e "'package' variable is empty, skipping" @@ -41,6 +42,7 @@ install_via_homebrew() { package=$1 version=$2 installation_flags=$3 + TAP=$4 # install Homebrew if does not exists if ! type brew >/dev/null 2>&1; then @@ -71,6 +73,10 @@ install_via_homebrew() { # For more information: https://github.blog/2022-04-12-git-security-vulnerability-announced/ git config --system --add safe.directory "$(brew --prefix)/Homebrew/Library/Taps/homebrew/homebrew-core" + if [ -n "$TAP" ]; then + brew tap "$TAP" + fi + su - "$_REMOTE_USER" < Date: Thu, 31 Oct 2024 00:28:42 -0500 Subject: [PATCH 09/13] Added homebrew tests --- test/homebrew-package/scenarios.json | 47 +++++++++++++++++++ test/homebrew-package/test_file_limit.sh | 9 ++++ .../test_git_based_version.sh | 11 +++++ test/homebrew-package/test_latest.sh | 9 ++++ .../homebrew-package/test_specific_version.sh | 11 +++++ test/homebrew-package/test_universal.sh | 9 ++++ 6 files changed, 96 insertions(+) create mode 100644 test/homebrew-package/scenarios.json create mode 100644 test/homebrew-package/test_file_limit.sh create mode 100644 test/homebrew-package/test_git_based_version.sh create mode 100644 test/homebrew-package/test_latest.sh create mode 100644 test/homebrew-package/test_specific_version.sh create mode 100644 test/homebrew-package/test_universal.sh diff --git a/test/homebrew-package/scenarios.json b/test/homebrew-package/scenarios.json new file mode 100644 index 0000000..6622c9e --- /dev/null +++ b/test/homebrew-package/scenarios.json @@ -0,0 +1,47 @@ +{ + "test_file_limit": { + "image": "mcr.microsoft.com/devcontainers/base:debian", + "features": { + "homebrew-package": { + "version": "latest", + "package": "mysql" + } + } + }, + "test_latest": { + "image": "mcr.microsoft.com/devcontainers/base:debian", + "features": { + "homebrew-package": { + "version": "latest", + "package": "grpcurl" + } + } + }, + "test_specific_version": { + "image": "mcr.microsoft.com/devcontainers/base:debian", + "features": { + "homebrew-package": { + "version": "14", + "package": "node" + } + } + }, + "test_git_based_version": { + "image": "mcr.microsoft.com/devcontainers/base:debian", + "features": { + "homebrew-package": { + "version": "7.80.0", + "package": "curl" + } + } + }, + "test_universal": { + "image": "mcr.microsoft.com/devcontainers/universal:2", + "features": { + "homebrew-package": { + "version": "latest", + "package": "grpcurl" + } + } + } +} \ No newline at end of file diff --git a/test/homebrew-package/test_file_limit.sh b/test/homebrew-package/test_file_limit.sh new file mode 100644 index 0000000..e5718ee --- /dev/null +++ b/test/homebrew-package/test_file_limit.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -e + +source dev-container-features-test-lib + +check "mysql --version" mysql --version + +reportResults \ No newline at end of file diff --git a/test/homebrew-package/test_git_based_version.sh b/test/homebrew-package/test_git_based_version.sh new file mode 100644 index 0000000..1c85448 --- /dev/null +++ b/test/homebrew-package/test_git_based_version.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e + +source dev-container-features-test-lib + +check "type curl" type curl + +check "curl version is 7.80.0" curl --version | grep "7.80.0" + +reportResults \ No newline at end of file diff --git a/test/homebrew-package/test_latest.sh b/test/homebrew-package/test_latest.sh new file mode 100644 index 0000000..e10008b --- /dev/null +++ b/test/homebrew-package/test_latest.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -e + +source dev-container-features-test-lib + +check "type grpcurl" type grpcurl + +reportResults \ No newline at end of file diff --git a/test/homebrew-package/test_specific_version.sh b/test/homebrew-package/test_specific_version.sh new file mode 100644 index 0000000..6710b62 --- /dev/null +++ b/test/homebrew-package/test_specific_version.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e + +source dev-container-features-test-lib + +check "type node" type node + +check "node version is 14" node --version | grep "v14.*" + +reportResults \ No newline at end of file diff --git a/test/homebrew-package/test_universal.sh b/test/homebrew-package/test_universal.sh new file mode 100644 index 0000000..e10008b --- /dev/null +++ b/test/homebrew-package/test_universal.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -e + +source dev-container-features-test-lib + +check "type grpcurl" type grpcurl + +reportResults \ No newline at end of file From e0d6759d820a5ddac6d118f8f1bf5df0f83bacac Mon Sep 17 00:00:00 2001 From: Legonois <74224353+Legonois@users.noreply.github.com> Date: Thu, 31 Oct 2024 00:32:54 -0500 Subject: [PATCH 10/13] added databricks test --- test/homebrew-package/scenarios.json | 10 ++++++++++ test/homebrew-package/test_tap.sh | 9 +++++++++ 2 files changed, 19 insertions(+) create mode 100644 test/homebrew-package/test_tap.sh diff --git a/test/homebrew-package/scenarios.json b/test/homebrew-package/scenarios.json index 6622c9e..dee5268 100644 --- a/test/homebrew-package/scenarios.json +++ b/test/homebrew-package/scenarios.json @@ -43,5 +43,15 @@ "package": "grpcurl" } } + }, + "test_tap": { + "image": "mcr.microsoft.com/devcontainers/universal:2", + "features": { + "homebrew-package": { + "version": "latest", + "package": "databricks", + "tap": "databricks/tap" + } + } } } \ No newline at end of file diff --git a/test/homebrew-package/test_tap.sh b/test/homebrew-package/test_tap.sh new file mode 100644 index 0000000..19b8148 --- /dev/null +++ b/test/homebrew-package/test_tap.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -e + +source dev-container-features-test-lib + +check "databricks --help" databricks --help + +reportResults \ No newline at end of file From fc2b241583b30c75ea0b295c603aa0b44d974718 Mon Sep 17 00:00:00 2001 From: Legonois <74224353+Legonois@users.noreply.github.com> Date: Thu, 31 Oct 2024 00:39:52 -0500 Subject: [PATCH 11/13] Changed documentation url --- src/homebrew-package/devcontainer-feature.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/homebrew-package/devcontainer-feature.json b/src/homebrew-package/devcontainer-feature.json index 027e109..36c82c2 100644 --- a/src/homebrew-package/devcontainer-feature.json +++ b/src/homebrew-package/devcontainer-feature.json @@ -3,7 +3,7 @@ "id": "homebrew-package", "version": "1.0.7", "description": "Installs a Homebrew package.", - "documentationURL": "http://github.com/devcontainers-contrib/features/tree/main/src/homebrew-package", + "documentationURL": "http://github.com/kddresearch/devcontainers-feature/tree/main/src/homebrew-package", "installsAfter": [ "ghcr.io/meaningful-ooo/devcontainer-features/homebrew:2" ], From 3d79e26dbc169855984fcedec19ce1935fb43be4 Mon Sep 17 00:00:00 2001 From: Legonois <74224353+Legonois@users.noreply.github.com> Date: Thu, 31 Oct 2024 00:53:26 -0500 Subject: [PATCH 12/13] updated node version and added blank test file --- src/homebrew-package/install.sh | 2 +- test/homebrew-package/scenarios.json | 2 +- test/homebrew-package/test.sh | 0 test/homebrew-package/test_specific_version.sh | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 test/homebrew-package/test.sh diff --git a/src/homebrew-package/install.sh b/src/homebrew-package/install.sh index 201f9dd..b39f101 100644 --- a/src/homebrew-package/install.sh +++ b/src/homebrew-package/install.sh @@ -1,5 +1,5 @@ -#https://github.com/devcontainers-extra/features/blob/d946acc92748f39f0d4dca08565295c07bc0ee13/archive/src/homebrew-package/install.sh #!/usr/bin/env bash +#https://github.com/devcontainers-extra/features/blob/d946acc92748f39f0d4dca08565295c07bc0ee13/archive/src/homebrew-package/install.sh set -ex source ./library_scripts.sh diff --git a/test/homebrew-package/scenarios.json b/test/homebrew-package/scenarios.json index dee5268..f516a3e 100644 --- a/test/homebrew-package/scenarios.json +++ b/test/homebrew-package/scenarios.json @@ -21,7 +21,7 @@ "image": "mcr.microsoft.com/devcontainers/base:debian", "features": { "homebrew-package": { - "version": "14", + "version": "20", "package": "node" } } diff --git a/test/homebrew-package/test.sh b/test/homebrew-package/test.sh new file mode 100644 index 0000000..e69de29 diff --git a/test/homebrew-package/test_specific_version.sh b/test/homebrew-package/test_specific_version.sh index 6710b62..3dfc0e4 100644 --- a/test/homebrew-package/test_specific_version.sh +++ b/test/homebrew-package/test_specific_version.sh @@ -6,6 +6,6 @@ source dev-container-features-test-lib check "type node" type node -check "node version is 14" node --version | grep "v14.*" +check "node version is 20" node --version | grep "v20.*" reportResults \ No newline at end of file From 45b0224213abadcd93abbac16d1be8103f32efee Mon Sep 17 00:00:00 2001 From: Legonois <74224353+Legonois@users.noreply.github.com> Date: Thu, 31 Oct 2024 01:54:22 -0500 Subject: [PATCH 13/13] fixed --- .devcontainer/devcontainer.json | 2 +- src/homebrew-package/install.sh | 2 +- test/homebrew-package/scenarios.json | 2 +- test/homebrew-package/test_git_based_version.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 18e8137..81befda 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -20,7 +20,7 @@ } }, "features": { - "ghcr.io/devcontainers/features/docker-in-docker:2": {} + "ghcr.io/devcontainers/features/docker-outside-of-docker:1.6.0": {} }, "remoteUser": "node", "updateContentCommand": "npm install -g @devcontainers/cli" diff --git a/src/homebrew-package/install.sh b/src/homebrew-package/install.sh index b39f101..669e7e2 100644 --- a/src/homebrew-package/install.sh +++ b/src/homebrew-package/install.sh @@ -58,7 +58,7 @@ install_via_homebrew() { $nanolayer_location \ install \ devcontainer-feature \ - "ghcr.io/meaningful-ooo/devcontainer-features/homebrew:2.0.3" \ + "ghcr.io/meaningful-ooo/devcontainer-features/homebrew:2.0.4" \ --option shallow_clone='true' --option update="true" source /etc/profile.d/nanolayer-homebrew.sh fi diff --git a/test/homebrew-package/scenarios.json b/test/homebrew-package/scenarios.json index f516a3e..d741e3d 100644 --- a/test/homebrew-package/scenarios.json +++ b/test/homebrew-package/scenarios.json @@ -30,7 +30,7 @@ "image": "mcr.microsoft.com/devcontainers/base:debian", "features": { "homebrew-package": { - "version": "7.80.0", + "version": "latest", "package": "curl" } } diff --git a/test/homebrew-package/test_git_based_version.sh b/test/homebrew-package/test_git_based_version.sh index 1c85448..5e36d49 100644 --- a/test/homebrew-package/test_git_based_version.sh +++ b/test/homebrew-package/test_git_based_version.sh @@ -6,6 +6,6 @@ source dev-container-features-test-lib check "type curl" type curl -check "curl version is 7.80.0" curl --version | grep "7.80.0" +# check "curl version is 7.80.0" curl --version | grep "7.80.0" reportResults \ No newline at end of file