diff --git a/README.md b/README.md index 51147d4..e6a88c5 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Install the modern shell utilities: ### [`kotlinc`](src/kotlinc/README.md) -Install _kotlinc_ and [_ktlint_](https://github.com/pinterest/ktlint). +Install _kotlinc_ and [_ktlint_](https://github.com/ktlint/ktlint). **NB.** requires Java to work. Either use a base image with Java or add feature `ghcr.io/devcontainers/features/java:1`. diff --git a/src/kotlinc/NOTES.md b/src/kotlinc/NOTES.md new file mode 100644 index 0000000..6daa740 --- /dev/null +++ b/src/kotlinc/NOTES.md @@ -0,0 +1 @@ +The compiler is available on `PATH` in interactive and noninteractive processes. diff --git a/src/kotlinc/README.md b/src/kotlinc/README.md index cd3f770..58c79ef 100644 --- a/src/kotlinc/README.md +++ b/src/kotlinc/README.md @@ -1,7 +1,9 @@ # kotlinc (kotlinc) -Kotlin compiler and linter (requires Java) +Kotlin compiler and ktlint (requires Java; Debian and Ubuntu) + +The compiler is available on `PATH` in interactive and noninteractive processes. ## Example Usage diff --git a/src/kotlinc/devcontainer-feature.json b/src/kotlinc/devcontainer-feature.json index cacaac7..c8c4dd8 100644 --- a/src/kotlinc/devcontainer-feature.json +++ b/src/kotlinc/devcontainer-feature.json @@ -1,8 +1,11 @@ { "name": "kotlinc", "id": "kotlinc", - "version": "1.1.0", - "description": "Kotlin compiler and linter (requires Java)", + "version": "1.2.0", + "description": "Kotlin compiler and ktlint (requires Java; Debian and Ubuntu)", + "containerEnv": { + "PATH": "/opt/kotlinc/bin:${PATH}" + }, "installsAfter": [ "ghcr.io/devcontainers/features/common-utils:2", "ghcr.io/devcontainers/features/java:1" diff --git a/src/kotlinc/install.sh b/src/kotlinc/install.sh index 1fc9cfc..95e0db4 100644 --- a/src/kotlinc/install.sh +++ b/src/kotlinc/install.sh @@ -1,97 +1,44 @@ #!/usr/bin/env bash -set -e +set -euo pipefail echo "Activating feature 'kotlinc'" -# Clean up -rm -rf /var/lib/apt/lists/* -echo "Step 1, check if user is root" +echo "Step 1, check for root privileges" 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.' + echo "This feature must be installed as root." >&2 exit 1 fi -echo "Step 2, determine 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 - -echo "Step 3, define helper functions" -updaterc() { - if [ "${UPDATE_RC}" = "true" ]; then - echo "Updating /etc/bash.bashrc and /etc/zsh/zshrc..." - if [[ "$(cat /etc/bash.bashrc)" != *"$1"* ]]; then - echo -e "$1" >> /etc/bash.bashrc - fi - if [ -f "/etc/zsh/zshrc" ] && [[ "$(cat /etc/zsh/zshrc)" != *"$1"* ]]; then - echo -e "$1" >> /etc/zsh/zshrc - fi - fi -} - -apt_get_update() -{ - if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then - echo "Running apt-get update..." - apt-get update -y - fi -} - -# Checks if packages are installed and installs them if not -check_packages() { - if ! dpkg -s "$@" > /dev/null 2>&1; then - apt_get_update - apt-get -y install --no-install-recommends "$@" - fi -} - -export DEBIAN_FRONTEND=noninteractive - - -echo "Step 4, check if architecture is supported" -architecture="$(uname -m)" -if [ "${architecture}" != "amd64" ] && [ "${architecture}" != "x86_64" ] && [ "${architecture}" != "arm64" ] && [ "${architecture}" != "aarch64" ]; then - echo "(!) Architecture $architecture unsupported" +. /etc/os-release +echo "Step 2, check the distribution" +if [[ "${ID}" != "debian" && "${ID}" != "ubuntu" ]]; then + echo "Unsupported distribution: ${PRETTY_NAME}. This feature requires Debian or Ubuntu." >&2 exit 1 fi +export DEBIAN_FRONTEND=noninteractive +echo "Step 3, install prerequisites" +rm -rf /var/lib/apt/lists/* +apt-get update -y +apt-get install -y --no-install-recommends ca-certificates curl unzip -echo "Step 5, install packages" - -# Install dependencies -check_packages ca-certificates curl unzip - -# renovate: datasource=github-releases depName=pinterest/ktlint +# renovate: datasource=github-releases depName=ktlint/ktlint KTLINT_VERSION=1.8.0 -curl -sSfLO https://github.com/pinterest/ktlint/releases/download/${KTLINT_VERSION}/ktlint \ - && chmod a+x ktlint \ - && mv ktlint /usr/local/bin - # renovate: datasource=github-releases depName=JetBrains/kotlin KOTLIN_VERSION=v2.4.20 -export KT_VERSION=$(echo $KOTLIN_VERSION | cut -c2-) \ - && curl -sSfLo kotlinc.zip https://github.com/JetBrains/kotlin/releases/download/${KOTLIN_VERSION}/kotlin-compiler-${KT_VERSION}.zip \ - && unzip kotlinc.zip -d /opt/ \ - && rm kotlinc.zip -UPDATE_RC=true -updaterc "export KOTLINC_BIN_DIR=\"/opt/kotlinc/bin\"" -updaterc "if [[ \"\${PATH}\" != *\"\${KOTLINC_BIN_DIR}\"* ]]; then export PATH=\"\${PATH}:\${KOTLINC_BIN_DIR}\"; fi" -UPDATE_RC=false +install_dir="$(mktemp -d)" +trap 'rm -rf "$install_dir"' EXIT -# Clean up -rm -rf /var/lib/apt/lists/* +echo "Step 4, install ktlint ${KTLINT_VERSION}" +curl -fsSL "https://github.com/ktlint/ktlint/releases/download/${KTLINT_VERSION}/ktlint" -o "${install_dir}/ktlint" +install -m 755 "${install_dir}/ktlint" /usr/local/bin/ktlint +echo "Step 5, install Kotlin ${KOTLIN_VERSION}" +kotlin_number="${KOTLIN_VERSION#v}" +curl -fsSL "https://github.com/JetBrains/kotlin/releases/download/${KOTLIN_VERSION}/kotlin-compiler-${kotlin_number}.zip" -o "${install_dir}/kotlinc.zip" +unzip -oq "${install_dir}/kotlinc.zip" -d /opt/ + +echo "Step 6, clean up" +rm -rf /var/lib/apt/lists/* echo "Done!" diff --git a/test/kotlinc/test.sh b/test/kotlinc/test.sh index 5ecf083..e28b9e4 100644 --- a/test/kotlinc/test.sh +++ b/test/kotlinc/test.sh @@ -43,6 +43,7 @@ echo $PATH # The 'check' command comes from the dev-container-features-test-lib. check "ktlint: 'ktlint --version'" ktlint --version check "kotlinc: 'kotlinc --version'" kotlinc -version +check "kotlinc on PATH for noninteractive shells" sh -c 'command -v kotlinc' # Report results # If any of the checks above exited with a non-zero exit code, the test will fail.