diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bc9d869..475b0ad 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,8 +13,7 @@ jobs: strategy: matrix: features: - # - color - # - hello + - dart baseImage: - debian:latest - ubuntu:latest @@ -34,8 +33,7 @@ jobs: strategy: matrix: features: - # - color - # - hello + - dart steps: - uses: actions/checkout@v3 diff --git a/src/dart/NOTES.md b/src/dart/NOTES.md new file mode 100644 index 0000000..7608082 --- /dev/null +++ b/src/dart/NOTES.md @@ -0,0 +1,45 @@ + + +
+ +[![Dart website](https://thum.io/get/width/800/crop/600/noanimate/https://dart.dev/)](https://dart.dev/) + +
+ +> Dart is a client-optimized language for fast apps on any platform + +— [Dart programming language | Dart] + +This feature installs the Dart SDK. + +🆘 If you're having trouble with this feature, [open a Discussion] or [open an +Issue]! We'd be happy to fix bugs! 🐛 + +## Supported platforms + +`linux/amd64` and `linux/arm64` platforms `debian` and `ubuntu`. + +## How to specify extensions? + +This feature installs any version with the `version` option and `channel` option. +Check [Dart SDK archive] for channel details. + +```json +"features": { + "ghcr.io/devcontainers-community/features/dart:1": { + "version": "3", + "channel": "beta" + } +} +``` + +Note that the beta and dev channels use suffix-based version matching, +so only versions ending with channel name (e.g. `3.1.0-63.1.beta`) can be installed. + + +[Dart programming language | Dart]: https://dart.dev/ +[Dart SDK archive]: https://dart.dev/get-dart/archive +[Flutter]: https://flutter.dev/ +[open a Discussion]: https://github.com/devcontainers-community/features/discussions/new?category=q-a +[open an Issue]: https://github.com/devcontainers-community/features/issues/new + diff --git a/src/dart/_common.sh b/src/dart/_common.sh new file mode 100644 index 0000000..a87e86a --- /dev/null +++ b/src/dart/_common.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +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 +} + +check_git() { + if [ ! -x "$(command -v git)" ]; then + check_packages git + fi +} diff --git a/src/dart/devcontainer-feature.json b/src/dart/devcontainer-feature.json new file mode 100644 index 0000000..749a5b0 --- /dev/null +++ b/src/dart/devcontainer-feature.json @@ -0,0 +1,28 @@ +{ + "id": "dart", + "name": "Dart", + "description": "Installs the Dart SDK", + "version": "1.0.0", + "options": { + "version": { + "description": "Select version of Dart SDK", + "type": "string", + "default": "latest", + "proposals": ["latest", "3"] + }, + "channel": { + "description": "Select build channel of Dart SDK", + "type": "string", + "default": "stable", + "enum": ["stable", "beta", "dev", "main"] + } + }, + "containerEnv": { + "PATH": "/usr/lib/dart/bin:${PATH}" + }, + "customizations": { + "vscode": { + "extensions": ["dart-code.dart-code"] + } + } +} diff --git a/src/dart/install.sh b/src/dart/install.sh new file mode 100644 index 0000000..11339a6 --- /dev/null +++ b/src/dart/install.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash + +VERSION=${VERSION:-"latest"} +CHANNEL=${CHANNEL:-"stable"} + +DART_SDK="/usr/lib/dart" + +set -e +source _common.sh + +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 + +architecture="$(dpkg --print-architecture)" +if [ "${architecture}" != "amd64" ] && [ "${architecture}" != "arm64" ]; then + echo "(!) Architecture $architecture unsupported" + exit 1 +fi + +# Clean up +rm -rf /var/lib/apt/lists/* + +find_version_from_git_tags() { + local variable_name=$1 + local requested_version=${!variable_name} + if [ "${requested_version}" = "none" ]; then return; fi + local repository=$2 + local prefix=${3:-"tags/v"} + local separator=${4:-"."} + local last_part_optional=${5:-""} + if [ "$(echo "${requested_version}" | grep -o "." | wc -l)" != "2" ]; then + local escaped_separator=${separator//./\\.} + local last_part + if [ -n "${last_part_optional}" ]; then + last_part=".*${last_part_optional}" + else + last_part="" + fi + local regex="${prefix}\\K[0-9]+${escaped_separator}[0-9]+${escaped_separator}[0-9]+${last_part}$" + local version_list + check_git + check_packages ca-certificates + version_list="$(git ls-remote --tags "${repository}" | grep -oP "${regex}" | tr -d ' ' | tr "${separator}" "." | sort -rV)" + if [ "${requested_version}" = "latest" ] || [ "${requested_version}" = "current" ] || [ "${requested_version}" = "lts" ]; then + declare -g "${variable_name}"="$(echo "${version_list}" | head -n 1)" + else + set +e + declare -g "${variable_name}"="$(echo "${version_list}" | grep -E -m 1 "^${requested_version//./\\.}([\\.\\s]|$)")" + set -e + fi + fi + if [ -z "${!variable_name}" ] || ! echo "${version_list}" | grep "^${!variable_name//./\\.}$" >/dev/null 2>&1; then + echo -e "Invalid ${variable_name} value: ${requested_version}\nValid values:\n${version_list}" >&2 + exit 1 + fi + echo "${variable_name}=${!variable_name}" +} + +export DEBIAN_FRONTEND=noninteractive + +check_packages curl ca-certificates unzip + +case "$architecture" in +amd64) + SDK_ARCH="x64" + ;; +arm64) + SDK_ARCH="arm64" + ;; +esac + +if [ "${CHANNEL}" = "main" ]; then + URL="https://storage.googleapis.com/dart-archive/channels/be/raw/latest/sdk/dartsdk-linux-${SDK_ARCH}-release.zip" +else + if [ "${CHANNEL}" = "stable" ]; then + LAST_PART="" + elif [ "${CHANNEL}" = "beta" ]; then + LAST_PART="beta" + elif [ "${CHANNEL}" = "dev" ]; then + LAST_PART="dev" + else + echo "(!) Channel ${CHANNEL} unsupported" + exit 1 + fi + # Soft version matching + find_version_from_git_tags VERSION "https://github.com/dart-lang/sdk" "tags/" "." "${LAST_PART}" + + URL="https://storage.googleapis.com/dart-archive/channels/${CHANNEL}/release/${VERSION}/sdk/dartsdk-linux-${SDK_ARCH}-release.zip" +fi + +echo "Downloading Dart..." + +mkdir "${DART_SDK}" + +# Working directory +mkdir /tmp/dvcf-dart +pushd /tmp/dvcf-dart + +curl -sL "${URL}" -o dart.zip +unzip -q dart.zip +mv dart-sdk/* "${DART_SDK}"/. + +chmod 755 "${DART_SDK}" "${DART_SDK}/bin" + +popd +rm -rf /tmp/dvcf-dart + +# Clean up +rm -rf /var/lib/apt/lists/* + +echo "Done!" diff --git a/test/dart/channel-beta.sh b/test/dart/channel-beta.sh new file mode 100644 index 0000000..2c16de8 --- /dev/null +++ b/test/dart/channel-beta.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -e +source dev-container-features-test-lib + +LATEST_VERSION="$(git ls-remote --tags https://github.com/dart-lang/sdk | grep -oP "(?<=refs/tags/)[0-9]+\\.[0-9]+\\.[0-9]+.*beta$" | sort -V | tail -n 1)" + +check 'dart' bash -c "dart --version | grep ${LATEST_VERSION}" + +reportResults diff --git a/test/dart/channel-main.sh b/test/dart/channel-main.sh new file mode 100644 index 0000000..c9e76e8 --- /dev/null +++ b/test/dart/channel-main.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e +source dev-container-features-test-lib + +check 'dart' bash -c "dart --version" + +reportResults diff --git a/test/dart/scenarios.json b/test/dart/scenarios.json new file mode 100644 index 0000000..1b2f9e2 --- /dev/null +++ b/test/dart/scenarios.json @@ -0,0 +1,26 @@ +{ + "version-3": { + "image": "mcr.microsoft.com/devcontainers/base:debian", + "features": { + "dart": { + "version": "3" + } + } + }, + "channel-beta": { + "image": "mcr.microsoft.com/devcontainers/base:debian", + "features": { + "dart": { + "channel": "beta" + } + } + }, + "channel-main": { + "image": "mcr.microsoft.com/devcontainers/base:debian", + "features": { + "dart": { + "channel": "main" + } + } + } +} diff --git a/test/dart/test.sh b/test/dart/test.sh new file mode 100644 index 0000000..4f4be27 --- /dev/null +++ b/test/dart/test.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +set -e +source dev-container-features-test-lib + +# Clean up +rm -rf /var/lib/apt/lists/* + +apt_get_update() { + if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then + echo "Running apt-get update..." + apt-get update -y + fi +} + +check_packages() { + if ! dpkg -s "$@" >/dev/null 2>&1; then + apt_get_update + apt-get -y install --no-install-recommends "$@" + fi +} + +check_packages git +LATEST_VERSION="$(git ls-remote --tags https://github.com/dart-lang/sdk | grep -oP "(?<=refs/tags/)[0-9]+\\.[0-9]+\\.[0-9]+$" | sort -V | tail -n 1)" + +check 'dart' bash -c "dart --version | grep ${LATEST_VERSION}" + +reportResults diff --git a/test/dart/version-3.sh b/test/dart/version-3.sh new file mode 100644 index 0000000..efae003 --- /dev/null +++ b/test/dart/version-3.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -e +source dev-container-features-test-lib + +LATEST_VERSION="$(git ls-remote --tags https://github.com/dart-lang/sdk | grep -oP "(?<=refs/tags/)3\\.[0-9]+\\.[0-9]+$" | sort -V | tail -n 1)" + +check 'dart' bash -c "dart --version | grep ${LATEST_VERSION}" + +reportResults