diff --git a/README.md b/README.md index 236a5ab..e02c0d1 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ | Feature | Description | Install method | Version | | ------- | ----------- | -------------- | ------- | +| [add-script](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/add-script) | Add a script from a URL or inline text to /usr/local/bin during devcontainer build | custom | 1.0.0 | | [alexpasmantier/television](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/alexpasmantier-television) | `tv` — fuzzy finder for files, text, and more | gh release | 1.0.1 | | [ankitpokhrel/jira-cli](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/ankitpokhrel-jira-cli) | `jira` — feature-rich interactive Jira command line client | gh release | 1.0.0 | | [apt-build-essential](https://github.com/devcontainer-community/devcontainer-features/tree/main/src/apt-build-essential) | `gcc`/`g++`/`make` — C/C++ compiler toolchain via the build-essential package | apt | 1.0.0 | diff --git a/src/add-script/NOTES.md b/src/add-script/NOTES.md new file mode 100644 index 0000000..2946e13 --- /dev/null +++ b/src/add-script/NOTES.md @@ -0,0 +1,19 @@ +# add-script + +## Project + +_No upstream project — this is a utility feature._ + +## Description + +A utility feature that adds a custom script to `/usr/local/bin` during devcontainer build. Accepts either a URL pointing to a script to download, or an inline script supplied directly as text. The script is placed at `/usr/local/bin/` and made executable, but is **not** executed during install. Exactly one of `url` or `script` must be provided along with a `name`. + +## Installation Method + +No binary is installed. The feature downloads (via `wget` or `curl`) or writes the provided script to `/usr/local/bin/` and sets its permissions to executable (`755`). If neither `wget` nor `curl` is available, `curl` is installed automatically via `apt`. + +## Other Notes + +- If both `url` and `script` are provided the feature fails with an error. +- If neither `url` nor `script` is provided, or if `name` is not provided, the feature exits successfully without doing anything. +- The script is **not** executed during the devcontainer build — it is only placed at the target path for later use. diff --git a/src/add-script/devcontainer-feature.json b/src/add-script/devcontainer-feature.json new file mode 100644 index 0000000..e9d330f --- /dev/null +++ b/src/add-script/devcontainer-feature.json @@ -0,0 +1,24 @@ +{ + "name": "add-script", + "id": "add-script", + "version": "1.0.0", + "description": "Add a script from a URL or inline text to /usr/local/bin during devcontainer build", + "documentationURL": "https://github.com/devcontainer-community/devcontainer-features/tree/main/src/add-script", + "options": { + "name": { + "type": "string", + "default": "", + "description": "Name for the script placed in /usr/local/bin." + }, + "url": { + "type": "string", + "default": "", + "description": "URL of a script to download." + }, + "script": { + "type": "string", + "default": "", + "description": "Inline script text to add." + } + } +} diff --git a/src/add-script/install.sh b/src/add-script/install.sh new file mode 100755 index 0000000..b01f1d9 --- /dev/null +++ b/src/add-script/install.sh @@ -0,0 +1,74 @@ +#!/bin/bash +set -o errexit +set -o pipefail +set -o noclobber +set -o nounset +set -o allexport +readonly name="add-script" + +apt_get_update() { + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update -y + fi +} + +apt_get_checkinstall() { + if ! dpkg -s "$@" >/dev/null 2>&1; then + apt_get_update + DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends --no-install-suggests --option 'Debug::pkgProblemResolver=true' --option 'Debug::pkgAcquire::Worker=1' "$@" + fi +} + +apt_get_cleanup() { + apt-get clean + rm -rf /var/lib/apt/lists/* +} + +echo_banner() { + local text="$1" + echo -e "\e[1m\e[97m\e[41m$text\e[0m" +} + +install() { + if [ -z "${NAME}" ]; then + echo "No script name provided. Nothing to do." + return 0 + fi + + if [ -n "${URL}" ] && [ -n "${SCRIPT}" ]; then + printf >&2 '=== [ERROR] Both "url" and "script" options are provided. Please provide only one.\n' + exit 1 + fi + + if [ -z "${URL}" ] && [ -z "${SCRIPT}" ]; then + echo "No script URL or inline script provided. Nothing to do." + return 0 + fi + + local scriptTargetPath="/usr/local/bin/${NAME}" + + if [ -n "${URL}" ]; then + echo "Downloading script from: ${URL}" + if command -v wget >/dev/null 2>&1; then + wget -qO "${scriptTargetPath}" "${URL}" + elif command -v curl >/dev/null 2>&1; then + curl -fsSL -o "${scriptTargetPath}" "${URL}" + else + apt_get_checkinstall curl ca-certificates + apt_get_cleanup + curl -fsSL -o "${scriptTargetPath}" "${URL}" + fi + else + echo "Writing inline script to /usr/local/bin/${NAME}..." + printf '%s' "${SCRIPT}" | tee "${scriptTargetPath}" >/dev/null + fi + + chmod 755 "${scriptTargetPath}" + echo "Script added at: ${scriptTargetPath}" +} + +echo_banner "devcontainer.community" +echo "Running $name..." +install "$@" +echo "(*) Done!" diff --git a/test/add-script/test.sh b/test/add-script/test.sh new file mode 100755 index 0000000..387fa53 --- /dev/null +++ b/test/add-script/test.sh @@ -0,0 +1,18 @@ +#!/bin/bash + + +set -e + +# Optional: Import test library bundled with the devcontainer CLI +# See https://github.com/devcontainers/cli/blob/HEAD/docs/features/test.md#dev-container-features-test-lib +# Provides the 'check' and 'reportResults' commands. +source dev-container-features-test-lib + +# Feature-specific tests +# The 'check' command comes from the dev-container-features-test-lib. Syntax is... +# check