diff --git a/src/webi-packages/README.md b/src/webi-packages/README.md new file mode 100644 index 000000000..085d41a23 --- /dev/null +++ b/src/webi-packages/README.md @@ -0,0 +1,18 @@ + +# webi packages (webi-packages) + +Install webi and use it to install specified packages + +## Example Usage + +```json +"features": { + "ghcr.io/devcontainers-extra/features/webi-packages:1": {} +} +``` + +## Options + +| Options Id | Description | Type | Default Value | +|-----|-----|-----|-----| +| packages | List of packages to install, comma-separated (e.g., 'node@lts', 'deno'). | string | - | diff --git a/src/webi-packages/devcontainer-feature.json b/src/webi-packages/devcontainer-feature.json new file mode 100644 index 000000000..135b3d954 --- /dev/null +++ b/src/webi-packages/devcontainer-feature.json @@ -0,0 +1,17 @@ +{ + "id": "webi-packages", + "version": "1.0.0", + "name": "webi packages", + "documentationURL": "http://github.com/devcontainers-extra/features/tree/main/src/webi-packages", + "description": "Install webi and use it to install specified packages", + "options": { + "packages": { + "type": "string", + "description": "List of packages to install, comma-separated (e.g., 'node@lts', 'deno')", + "default": "" + } + }, + "installsAfter": [ + "ghcr.io/devcontainers/features/common-utils" + ] +} \ No newline at end of file diff --git a/src/webi-packages/install.sh b/src/webi-packages/install.sh new file mode 100755 index 000000000..f7f8873c5 --- /dev/null +++ b/src/webi-packages/install.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -e + +USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}" +PACKAGES="${PACKAGES:-""}" + +if [ "$(id -u)" -ne 0 ]; then + echo "Script must be run as root. Use sudo, su, or add \"USER root\" to your Dockerfile before running this script." + exit 1 +fi + +. ./utils.sh + +install_webi "$(determine_user "$USERNAME")" "$PACKAGES" + +clean diff --git a/src/webi-packages/utils.sh b/src/webi-packages/utils.sh new file mode 100644 index 000000000..e5ac74c41 --- /dev/null +++ b/src/webi-packages/utils.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash + +install_webi() { + local USERNAME="$1" + local PACKAGES="$2" + + check_command curl + + su - "${USERNAME}" </dev/null; then + echo "Installing webinstall.dev for user ${USERNAME}..." + curl -sS https://webi.sh/webi | sh + source ~/.config/envman/PATH.env + echo "Webinstall.dev installation completed for user ${USERNAME}" + fi + + if [ -n "$PACKAGES" ]; then + echo "Installing specified packages: ${PACKAGES}" + webi $(echo "$PACKAGES" | tr ',' ' ') + fi +EOF +} + +determine_user() { + local USERNAME="${1:-"auto"}" + if [ "${USERNAME}" = "auto" ] || [ "${USERNAME}" = "automatic" ]; then + USERNAME="" + check_command awk >/dev/null 2>&1 + USERNAME_UID_1000="$(awk -v val=1000 -F ":" '$3==val{print $1}' /etc/passwd)" + POSSIBLE_USERS=("vscode" "node" "codespace" "${USERNAME_UID_1000}") + 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 + + echo "${USERNAME}" +} + +check_command() { + local cmd=$1 + + if command -v "$cmd" &>/dev/null; then + echo "$cmd is already installed" + return 0 + fi + + echo "$cmd not found, attempting to install..." + + if command -v apt &>/dev/null; then + echo "Installing using apt..." + apt update + apt -y install --no-install-recommends "$cmd" + return $? + fi + + if command -v apk &>/dev/null; then + echo "Installing using apk..." + apk update + apk add --no-cache "$cmd" + return $? + fi + + echo "Error: No supported package manager found (apt/apk)" + return 1 +} + +clean() { + if command -v apt &>/dev/null; then + apt clean + rm -rf /var/lib/apt/lists/* + fi +} diff --git a/test/webi-packages/scenarios.json b/test/webi-packages/scenarios.json new file mode 100644 index 000000000..0db483f8f --- /dev/null +++ b/test/webi-packages/scenarios.json @@ -0,0 +1,18 @@ +{ + "test": { + "image": "mcr.microsoft.com/devcontainers/base:debian", + "features": { + "webi-packages": { + "packages": "node@18,deno" + } + } + }, + "test_alpine": { + "image": "mcr.microsoft.com/devcontainers/base:alpine", + "features": { + "webi-packages": { + "packages": "node@18" + } + } + } +} \ No newline at end of file diff --git a/test/webi-packages/test.sh b/test/webi-packages/test.sh new file mode 100755 index 000000000..e3f1dd062 --- /dev/null +++ b/test/webi-packages/test.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -e + +source dev-container-features-test-lib + +check "node version is equal to 18.*.*" sh -c "node --version | grep '18.*.*'" + +check "deno --version" deno --version + +reportResults diff --git a/test/webi-packages/test_alpine.sh b/test/webi-packages/test_alpine.sh new file mode 100755 index 000000000..28665a051 --- /dev/null +++ b/test/webi-packages/test_alpine.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -e + +source dev-container-features-test-lib + +source ~/.config/envman/PATH.env + +check "node version is equal to 18.*.*" sh -c "node --version | grep '18.*.*'" + +reportResults