From 302a34f24fbd9b21298f753eb85ad96d0fd0a7b4 Mon Sep 17 00:00:00 2001 From: Steven Liekens Date: Sat, 22 Jul 2023 01:42:24 +0200 Subject: [PATCH 01/38] Use dotnet-install.sh in .NET feature --- src/dotnet/devcontainer-feature.json | 30 +- src/dotnet/install.sh | 529 +++--------------- test/dotnet/install_additional_dotnet.sh | 17 - test/dotnet/install_dotnet_3.sh | 17 - test/dotnet/install_dotnet_6_bullseye.sh | 17 - test/dotnet/install_dotnet_6_focal.sh | 17 - test/dotnet/install_dotnet_6_jammy.sh | 17 - test/dotnet/install_dotnet_7_bullseye.sh | 17 - test/dotnet/install_dotnet_7_jammy.sh | 17 - test/dotnet/install_dotnet_exact_version.sh | 28 + test/dotnet/install_dotnet_latest.sh | 17 - test/dotnet/install_dotnet_lts.sh | 30 +- .../install_dotnet_multiple_versions.sh | 30 + .../dotnet/install_dotnet_specific_release.sh | 29 + ...otnet_specific_release_and_feature_band.sh | 29 + test/dotnet/install_wo_apt.sh | 17 - test/dotnet/projects/.gitignore | 2 + test/dotnet/projects/multitargeting/Class1.cs | 4 + .../multitargeting/example_classlib.csproj | 9 + test/dotnet/projects/net5.0/Program.cs | 32 ++ .../projects/net5.0/example_project.csproj | 13 + test/dotnet/projects/net6.0/Program.cs | 30 + .../projects/net6.0/example_project.csproj | 14 + test/dotnet/projects/net7.0/Program.cs | 30 + .../projects/net7.0/example_project.csproj | 14 + test/dotnet/projects/net8.0/Program.cs | 32 ++ .../projects/net8.0/example_project.csproj | 14 + test/dotnet/projects/netcoreapp3.1/Program.cs | 39 ++ .../netcoreapp3.1/example_project.csproj | 14 + test/dotnet/scenarios.json | 81 +-- test/dotnet/test.sh | 30 +- 31 files changed, 523 insertions(+), 693 deletions(-) delete mode 100644 test/dotnet/install_additional_dotnet.sh delete mode 100644 test/dotnet/install_dotnet_3.sh delete mode 100644 test/dotnet/install_dotnet_6_bullseye.sh delete mode 100644 test/dotnet/install_dotnet_6_focal.sh delete mode 100644 test/dotnet/install_dotnet_6_jammy.sh delete mode 100644 test/dotnet/install_dotnet_7_bullseye.sh delete mode 100644 test/dotnet/install_dotnet_7_jammy.sh create mode 100644 test/dotnet/install_dotnet_exact_version.sh delete mode 100644 test/dotnet/install_dotnet_latest.sh create mode 100644 test/dotnet/install_dotnet_multiple_versions.sh create mode 100644 test/dotnet/install_dotnet_specific_release.sh create mode 100644 test/dotnet/install_dotnet_specific_release_and_feature_band.sh delete mode 100644 test/dotnet/install_wo_apt.sh create mode 100644 test/dotnet/projects/.gitignore create mode 100644 test/dotnet/projects/multitargeting/Class1.cs create mode 100644 test/dotnet/projects/multitargeting/example_classlib.csproj create mode 100644 test/dotnet/projects/net5.0/Program.cs create mode 100644 test/dotnet/projects/net5.0/example_project.csproj create mode 100644 test/dotnet/projects/net6.0/Program.cs create mode 100644 test/dotnet/projects/net6.0/example_project.csproj create mode 100644 test/dotnet/projects/net7.0/Program.cs create mode 100644 test/dotnet/projects/net7.0/example_project.csproj create mode 100644 test/dotnet/projects/net8.0/Program.cs create mode 100644 test/dotnet/projects/net8.0/example_project.csproj create mode 100644 test/dotnet/projects/netcoreapp3.1/Program.cs create mode 100644 test/dotnet/projects/netcoreapp3.1/example_project.csproj mode change 100755 => 100644 test/dotnet/test.sh diff --git a/src/dotnet/devcontainer-feature.json b/src/dotnet/devcontainer-feature.json index 4f484ccba..4d76d1984 100644 --- a/src/dotnet/devcontainer-feature.json +++ b/src/dotnet/devcontainer-feature.json @@ -1,35 +1,31 @@ { "id": "dotnet", - "version": "1.1.4", + "version": "2.0.0", "name": "Dotnet CLI", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/dotnet", - "description": "Installs the .NET CLI. Provides option of installing sdk or runtime, and option of versions to install. Uses latest version of .NET sdk as defaults to install.", + "description": "Installs .NET and its CLI. Offers options to install multiple SDK versions.", "options": { "version": { "type": "string", "proposals": [ "latest", - "7", - "6", - "3.1" + "lts", + "8.0", + "7.0", + "6.0" ], "default": "latest", - "description": "Select or enter a dotnet CLI version. (Available versions may vary by Linux distribution.)" + "description": "Version of .NET SDK to install. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' for a specific release, or 'X.Y.Z' for a specific version." }, - "runtimeOnly": { - "type": "boolean", - "default": false, - "description": "Install just the dotnet runtime if true, and sdk if false." - }, - "installUsingApt": { - "type": "boolean", - "default": true, - "description": "If true, it installs using apt instead of the release URL" + "additionalVersions": { + "type": "string", + "default": "", + "description": "Comma-separated list of additional .NET SDK versions to install. Use 'latest' for the latest version, 'lts' for the latest LTS version, 'X.Y' for a specific release, or 'X.Y.Z' for a specific version." } }, "containerEnv": { - "DOTNET_ROOT": "/usr/local/dotnet/current", - "PATH": "/usr/local/dotnet/current:${PATH}" + "DOTNET_ROOT": "/usr/share/dotnet", + "PATH": "${DOTNET_ROOT}:${PATH}" }, "customizations": { "vscode": { diff --git a/src/dotnet/install.sh b/src/dotnet/install.sh index 178994d71..6839edbd6 100644 --- a/src/dotnet/install.sh +++ b/src/dotnet/install.sh @@ -4,121 +4,26 @@ # Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. #------------------------------------------------------------------------------------------------------------- # -# Docs: https://github.com/microsoft/vscode-dev-containers/blob/main/script-library/docs/dotnet.md +# Docs: https://github.com/devcontainers/features/tree/main/src/dotnet # Maintainer: The VS Code and Codespaces Teams - DOTNET_VERSION="${VERSION:-"latest"}" +DOTNET_ADDITIONAL_VERSIONS="${ADDITIONALVERSIONS:-""}" DOTNET_RUNTIME_ONLY="${RUNTIMEONLY:-"false"}" -OVERRIDE_DEFAULT_VERSION="${OVERRIDEDEFAULTVERSION:-"true"}" -INSTALL_USING_APT="${INSTALLUSINGAPT:-"true"}" - -DOTNET_LATEST="7" -DOTNET_LTS="6" - -USERNAME="${USERNAME:-"${_REMOTE_USER:-"automatic"}"}" -UPDATE_RC="${UPDATE_RC:-"true"}" -TARGET_DOTNET_ROOT="${TARGET_DOTNET_ROOT:-"/usr/local/dotnet"}" -ACCESS_GROUP="${ACCESS_GROUP:-"dotnet"}" - -MICROSOFT_GPG_KEYS_URI="https://packages.microsoft.com/keys/microsoft.asc" -DOTNET_ARCHIVE_ARCHITECTURES="amd64" -DOTNET_ARCHIVE_VERSION_CODENAMES="buster bullseye bionic focal hirsute jammy" -# Feed URI sourced from the official dotnet-install.sh -# https://github.com/dotnet/install-scripts/blob/1b98b94a6f6d81cc4845eb88e0195fac67caa0a6/src/dotnet-install.sh#L1342-L1343 -DOTNET_CDN_FEED_URI="https://dotnetcli.azureedge.net" -# Ubuntu 22.04 and on do not ship with libssl1.1, which is required for versions of .NET < 6.0 -DOTNET_VERSION_CODENAMES_REQUIRE_OLDER_LIBSSL_1="buster bullseye bionic focal hirsute" -# Comma-separated list of dotnet versions to be installed -# alongside DOTNET_VERSION, but not set as default. -ADDITIONAL_VERSIONS=${ADDITIONALVERSIONS:-""} - -APT_PREFERENCES_CONTENT="$(cat << 'EOF' -Package: * -Pin: origin "packages.microsoft.com" -Pin-Priority: 1001 -EOF -)" - -APT_PREFERENCES_FILE_ADDED="false" -APT_PREFERENCES_UPDATED="false" +DOTNET_INSTALL_SCRIPT_URL='https://dot.net/v1/dotnet-install.sh' +DOTNET_INSTALL_SCRIPT='/tmp/dotnet-install.sh' +DOTNET_INSTALL_DIR='/usr/share/dotnet' set -e -# Clean up -rm -rf /var/lib/apt/lists/* - -# Setup STDERR. -err() { - echo "(!) $*" >&2 -} - -# Ensure the appropriate root user is running the script. -if [ "$(id -u)" -ne 0 ]; then - err 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' - exit 1 -fi - -# Ensure that login shells get the correct path if the user updated the PATH using ENV. -rm -f /etc/profile.d/00-restore-env.sh -echo "export PATH=${PATH//$(sh -lc 'echo $PATH')/\$PATH}" > /etc/profile.d/00-restore-env.sh -chmod +x /etc/profile.d/00-restore-env.sh - -# Determine the 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 - -################### -# Helper Functions -################### - -# Cleanup temporary directory and associated files when exiting the script. -cleanup() { - EXIT_CODE=$? - set +e - if [[ -n "${TMP_DIR}" ]]; then - echo "Executing cleanup of tmp files" - rm -Rf "${TMP_DIR}" - fi - exit $EXIT_CODE -} -trap cleanup EXIT - -# Add dotnet directory to PATH in bashrc/zshrc files if OVERRIDE_DEFAULT_VERSION=true. -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() -{ +apt_get_update() { if [ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]; then echo "Running apt-get update..." apt-get update -y fi } -# Check if packages are installed and installs them if not. +# Checks if packages are installed and installs them if not check_packages() { if ! dpkg -s "$@" > /dev/null 2>&1; then apt_get_update @@ -126,367 +31,99 @@ check_packages() { fi } -# Get appropriate architecture name for .NET binaries for the target OS -get_architecture_name_for_target_os() { - local architecture - architecture="$(uname -m)" - case $architecture in - x86_64) architecture="x64";; - aarch64 | armv8*) architecture="arm64";; - *) err "Architecture ${architecture} unsupported"; exit 1 ;; - esac - - echo "${architecture}" -} - -# Soft version matching that resolves a version for a given package in the *current apt-cache* -# Return value is stored in first argument (the unprocessed version) -apt_cache_package_and_version_soft_match() { - # Version - local version_variable_name="$1" - local requested_version=${!version_variable_name} - # Package Name - local package_variable_name="$2" - local partial_package_name=${!package_variable_name} - local package_name - # Exit on no match? - local exit_on_no_match="${3:-true}" - local major_minor_version - - # Ensure we've exported useful variables - . /etc/os-release - local architecture="$(dpkg --print-architecture)" - - apt-get update -y - major_minor_version="$(echo "${requested_version}" | cut -d "." --field=1,2)" - package_name="$(apt-cache search "${partial_package_name}-[0-9].[0-9]$" | awk -F" - " '{print $1}' | grep -m 1 "${partial_package_name}-${major_minor_version}")" - dot_escaped="${requested_version//./\\.}" - dot_plus_escaped="${dot_escaped//+/\\+}" - # Regex needs to handle debian package version number format: https://www.systutorials.com/docs/linux/man/5-deb-version/ - version_regex="^(.+:)?${dot_plus_escaped}([\\.\\+ ~:-]|$)" - set +e # Don't exit if finding version fails - handle gracefully - fuzzy_version="$(apt-cache madison ${package_name} | awk -F"|" '{print $2}' | sed -e 's/^[ \t]*//' | grep -E -m 1 "${version_regex}")" - set -e - if [ -z "${fuzzy_version}" ]; then - echo "(!) No full or partial for package \"${partial_package_name}\" (resolved: \"${package_name}\") match found in apt-cache for \"${requested_version}\" on OS ${ID} ${VERSION_CODENAME} (${architecture})." - - if $exit_on_no_match; then - echo "Available versions:" - apt-cache madison ${package_name} | awk -F"|" '{print $2}' | grep -oP '^(.+:)?\K.+' - exit 1 # Fail entire script - else - echo "Continuing to fallback method if available" - return 1; - fi - fi - - # Globally assign fuzzy_version to this value - # Use this value as the return value of this function - declare -g ${version_variable_name}="=${fuzzy_version}" - echo "${version_variable_name} ${!version_variable_name}" - - # Globally assign package to this value - # Use this value as the return value of this function - declare -g ${package_variable_name}="${package_name}" - echo "${package_variable_name} ${!package_variable_name}" -} - -# Install .NET CLI using apt-get package installer -install_using_apt() { - local sdk_or_runtime="$1" - local target_dotnet_version="$2" - local use_msft_repo="$3" - - if [ "${use_msft_repo}" = "true" ]; then - # Install dependencies - check_packages apt-transport-https curl ca-certificates gnupg2 dirmngr - # Import key safely and import Microsoft apt repo - curl -sSL ${MICROSOFT_GPG_KEYS_URI} | gpg --dearmor > /usr/share/keyrings/microsoft-archive-keyring.gpg - echo "deb [arch=${architecture} signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/microsoft-${ID}-${VERSION_CODENAME}-prod ${VERSION_CODENAME} main" > /etc/apt/sources.list.d/microsoft.list - - [ ! -f /etc/apt/preferences ] && APT_PREFERENCES_FILE_ADDED="true" - APT_PREFERENCES_UPDATED="true" - - # See https://github.com/dotnet/core/issues/7699 - echo "${APT_PREFERENCES_CONTENT}" >> /etc/apt/preferences - apt-get update -y - fi - - # .NET 7 is not a LTS version, so handle latest and LTS versions differently - export APT_DOTNET_VERSION="$target_dotnet_version" - if [ "${APT_DOTNET_VERSION}" = "latest" ]; then - APT_DOTNET_VERSION="${DOTNET_LATEST}.0" - elif [ "${APT_DOTNET_VERSION}" = "lts" ]; then - APT_DOTNET_VERSION="${DOTNET_LTS}.0" - fi - - # Sets target_dotnet_version and dotnet_package if matches found. - local base_dotnet_package="dotnet-${sdk_or_runtime}" - export DOTNET_PACKAGE="${base_dotnet_package}" - apt_cache_package_and_version_soft_match APT_DOTNET_VERSION DOTNET_PACKAGE false - if [ "$?" != 0 ] || [ ${DOTNET_PACKAGE} == "${base_dotnet_package}" ]; then - echo "Failed to find requested version." - return 1 - fi - - if type dotnet > /dev/null 2>&1 && [[ "$(dotnet --version)" == *"${APT_DOTNET_VERSION}"* ]] ; then - echo "dotnet version ${APT_DOTNET_VERSION} is already installed" - return 1 - fi - - echo "Installing '${DOTNET_PACKAGE}${APT_DOTNET_VERSION}'..." - apt-get install -yq ${DOTNET_PACKAGE}${APT_DOTNET_VERSION} - if [ "$?" != 0 ]; then - echo "Failed to complete apt install of ${DOTNET_PACKAGE}${TARGET_DOTNET_VERSION}" - return 1 - fi - - # Add symlink for current - CURRENT_DIR="${TARGET_DOTNET_ROOT}/current" - if [[ -d "${CURRENT_DIR}" ]]; then - rm -rf "${CURRENT_DIR}" - fi - mkdir -p "${TARGET_DOTNET_ROOT}" - local dotnet_installed_version="$(dotnet --version)" - # See if its the distro version - if [[ "$(dotnet --info)" == *"Base Path: /usr/lib/dotnet/${DOTNET_SDK_OR_RUNTIME}/${dotnet_installed_version}"* ]]; then - ln -s "/usr/lib/dotnet" "${CURRENT_DIR}" - else - # Location used by MS repo versions - ln -s "/usr/share/dotnet" "${CURRENT_DIR}" - fi -} - -# Find and extract .NET binary download details based on user-requested version -# args: -# sdk_or_runtime $1 -# dotnet_version_to_download $2 -# exports: -# DOTNET_DOWNLOAD_URL -# DOTNET_DOWNLOAD_HASH -# DOTNET_DOWNLOAD_NAME -get_full_version_details() { - local sdk_or_runtime="$1" - local architecture - local dotnet_channel_version - local dotnet_releases_url - local dotnet_releases_json - local dotnet_latest_version - local dotnet_download_details - - export DOTNET_DOWNLOAD_VERSION="$2" - export DOTNET_DOWNLOAD_URL - export DOTNET_DOWNLOAD_HASH - export DOTNET_DOWNLOAD_NAME - - # Set architecture variable to current user's architecture (x64 or ARM64). - architecture="$(get_architecture_name_for_target_os)" - - # Set VERSION to empty string to ensure jq includes all .NET versions in reverse sort below - if [ "${DOTNET_DOWNLOAD_VERSION}" = "latest" ]; then - DOTNET_DOWNLOAD_VERSION="" - fi - - dotnet_patchless_version="$(echo "${DOTNET_DOWNLOAD_VERSION}" | cut -d "." --field=1,2)" - - set +e - dotnet_channel_version="$(curl -s "${DOTNET_CDN_FEED_URI}/dotnet/release-metadata/releases-index.json" | jq -r --arg channel_version "${dotnet_patchless_version}" '[."releases-index"[]] | sort_by(."channel-version") | reverse | map( select(."channel-version" | startswith($channel_version))) | first | ."channel-version"')" - set -e - - # Construct the releases URL using the official channel-version if one was found. Otherwise make a best-effort using the user input. - if [ -n "${dotnet_channel_version}" ] && [ "${dotnet_channel_version}" != "null" ]; then - dotnet_releases_url="${DOTNET_CDN_FEED_URI}/dotnet/release-metadata/${dotnet_channel_version}/releases.json" +# Installs a version of .NET using the DOTNET_INSTALLER_SCRIPT +install_version() { + local version="$1" + local channel="STS" + local runtime_arg="" + + echo "Installing version '$version'..." + + # Quick options reminder for dotnet-install.sh: + # + # --version: 'latest' (default) or an exact version in the form 'A.B.C' like '6.0.412' + # --channel: 'LTS' (default), 'STS', a two-part version in the form 'A.B' like '6.0' or three-part form 'A.B.Cxx' like '6.0.1xx' + # --quality: 'daily', 'signed', 'validated', 'preview' or 'GA' + # + # Valid examples + # + # dotnet-install.sh [--version latest] --channel LTS + # dotnet-install.sh [--version latest] --channel STS + # dotnet-install.sh [--version latest] --channel 6.0 [--quality GA] + # dotnet-install.sh [--version latest] --channel 6.0.4xx [--quality GA] + # dotnet-install.sh [--version latest] --channel 8.0 --quality preview + # dotnet-install.sh [--version latest] --channel 8.0 --quality daily + # dotnet-install.sh --version 6.0.412 + # + # The channel option is only used when version is 'latest' because an exact version overrides the channel option + # The quality option is only used when channel is 'A.B' or 'A.B.Cxx' because it can't be used with STS or LTS + # + # This script aims to reduce these combinations of options to a single 'version' input + # Currently this script does not make it possible to request a version in the form 'A.B' or 'A.B.Cxx' and a quality other than 'GA' + if [[ "$version" == "latest" ]]; then + # When user input is 'latest' + # Then version=latest, channel=STS + channel="STS" + elif [[ "$version" == "lts" ]]; then + # When user input is 'lts' + # Then version=latest, channel=LTS + channel="LTS" + version="latest" + elif [[ "$version" =~ ^[0-9]+\.[0-9]+$ ]]; then + # When user input is form 'A.B' like '3.1' + # Then version=latest, channel=3.1 + channel="$version" + version="latest" + elif [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]xx$ ]]; then + # When user input is form 'A.B.Cxx' like '6.0.4xx' + # Then version=latest, channel=6.0.4xx + channel="$version" + version="latest" else - dotnet_releases_url="${DOTNET_CDN_FEED_URI}/dotnet/release-metadata/${dotnet_patchless_version}/releases.json" - fi - - set +e - dotnet_releases_json="$(curl -s "${dotnet_releases_url}")" - set -e - - if [ -n "${dotnet_releases_json}" ] && [[ ! "${dotnet_releases_json}" = *"Error"* ]]; then - dotnet_latest_version="$(echo "${dotnet_releases_json}" | jq -r --arg sdk_or_runtime "${sdk_or_runtime}" '."latest-\($sdk_or_runtime)"')" - # If user-specified version has 2 or more dots, use it as is. Otherwise use latest version. - if [ "$(echo "${DOTNET_DOWNLOAD_VERSION}" | grep -o "\." | wc -l)" -lt "2" ]; then - DOTNET_DOWNLOAD_VERSION="${dotnet_latest_version}" - fi - - dotnet_download_details="$(echo "${dotnet_releases_json}" | jq -r --arg sdk_or_runtime "${sdk_or_runtime}" --arg dotnet_version "${DOTNET_DOWNLOAD_VERSION}" --arg arch "${architecture}" '.releases[]."\($sdk_or_runtime)" | select(.version==$dotnet_version) | .files[] | select(.name=="dotnet-\($sdk_or_runtime)-linux-\($arch).tar.gz")')" - if [ -n "${dotnet_download_details}" ]; then - echo "Found .NET binary version ${DOTNET_DOWNLOAD_VERSION}" - DOTNET_DOWNLOAD_URL="$(echo "${dotnet_download_details}" | jq -r '.url')" - DOTNET_DOWNLOAD_HASH="$(echo "${dotnet_download_details}" | jq -r '.hash')" - DOTNET_DOWNLOAD_NAME="$(echo "${dotnet_download_details}" | jq -r '.name')" - else - err "Unable to find .NET binary for version ${DOTNET_DOWNLOAD_VERSION}" - exit 1 - fi - else - err "Unable to find .NET release details for version ${DOTNET_DOWNLOAD_VERSION} at ${dotnet_releases_url}" - exit 1 - fi -} - -# Install .NET CLI using the .NET releases url -install_using_dotnet_releases_url() { - local sdk_or_runtime="$1" - local version="$2" - - # Check listed package dependencies and install them if they are not already installed. - # NOTE: icu-devtools is a small package with similar dependencies to .NET. - # It will install the appropriate dependencies based on the OS: - # - libgcc-s1 OR libgcc1 depending on OS - # - the latest libicuXX depending on OS (eg libicu57 for stretch) - # - also installs libc6 and libstdc++6 which are required by .NET - check_packages curl ca-certificates tar jq icu-devtools libgssapi-krb5-2 zlib1g - - # Starting with Ubuntu 22.04 (jammy), libssl1.1 does not ship with the OS anymore. - if [[ "${DOTNET_VERSION_CODENAMES_REQUIRE_OLDER_LIBSSL_1}" = *"${VERSION_CODENAME}"* ]]; then - check_packages libssl1.1 - else - check_packages libssl3 - fi - - get_full_version_details "${sdk_or_runtime}" "${version}" - - DOTNET_INSTALL_PATH="${TARGET_DOTNET_ROOT}/${DOTNET_DOWNLOAD_VERSION}" - if [ -d "${DOTNET_INSTALL_PATH}" ]; then - echo "(!) Dotnet version ${DOTNET_DOWNLOAD_VERSION} already exists." - exit 1 - fi - # exports DOTNET_DOWNLOAD_URL, DOTNET_DOWNLOAD_HASH, DOTNET_DOWNLOAD_NAME - echo "DOWNLOAD LINK: ${DOTNET_DOWNLOAD_URL}" - - # Setup the access group and add the user to it. - umask 0002 - if ! cat /etc/group | grep -e "^${ACCESS_GROUP}:" > /dev/null 2>&1; then - groupadd -r "${ACCESS_GROUP}" + # Assume version is an exact version string like '6.0.412' or '8.0.100-rc.1.23371.5'' + channel="superseded" fi - usermod -a -G "${ACCESS_GROUP}" "${USERNAME}" - - # Download the .NET binaries. - echo "DOWNLOADING BINARY..." - TMP_DIR="/tmp/dotnetinstall" - mkdir -p "${TMP_DIR}" - curl -sSL "${DOTNET_DOWNLOAD_URL}" -o "${TMP_DIR}/${DOTNET_DOWNLOAD_NAME}" - - # Get checksum from .NET CLI blob storage using the runtime version and - # run validation (sha512sum) of checksum against the expected checksum hash. - echo "VERIFY CHECKSUM" - cd "${TMP_DIR}" - echo "${DOTNET_DOWNLOAD_HASH} *${DOTNET_DOWNLOAD_NAME}" | sha512sum -c - - - # Extract binaries and add to path. - mkdir -p "${DOTNET_INSTALL_PATH}" - echo "Extract Binary to ${DOTNET_INSTALL_PATH}" - tar -xzf "${TMP_DIR}/${DOTNET_DOWNLOAD_NAME}" -C "${DOTNET_INSTALL_PATH}" --strip-components=1 - CURRENT_DIR="${TARGET_DOTNET_ROOT}/current" - if [[ ! -d "${CURRENT_DIR}" ]]; then - ln -s "${DOTNET_INSTALL_PATH}" "${CURRENT_DIR}" + if [ "$DOTNET_RUNTIME_ONLY" = 'true' ]; then + echo "Installing runtime only..." + runtime_arg='--runtime dotnet' fi - # Give write permissions to the user. - chown -R "${USERNAME}:${USERNAME}" "${CURRENT_DIR}" - chmod g+r+w+s "${CURRENT_DIR}" - chmod -R g+r+w "${CURRENT_DIR}" - - if [[ "${OVERRIDE_DEFAULT_VERSION}" = "true" ]]; then - if [[ $(ls -l ${CURRENT_DIR}) != *"-> ${DOTNET_INSTALL_PATH}"* ]] ; then - rm "${CURRENT_DIR}" - ln -s "${DOTNET_INSTALL_PATH}" "${CURRENT_DIR}" - fi - fi - - updaterc "if [[ \"\${PATH}\" != *\"${CURRENT_DIR}\"* ]]; then export PATH=${CURRENT_DIR}:\${PATH}; fi" + echo "Executing $DOTNET_INSTALL_SCRIPT --install-dir $DOTNET_INSTALL_DIR --version $version --channel $channel $runtime_arg" + "$DOTNET_INSTALL_SCRIPT" \ + --install-dir "$DOTNET_INSTALL_DIR" \ + --version "$version" \ + --channel "$channel" \ + $runtime_arg } -########################### -# Start .NET installation -########################### - -export DEBIAN_FRONTEND=noninteractive - -. /etc/os-release -architecture="$(dpkg --print-architecture)" - -# Dotnet 3.1 and 5 are not supported on Ubuntu 22.04 (jammy)+, -# due to lack of libssl3.0 support. -# See: https://github.com/microsoft/vscode-dev-containers/issues/1458#issuecomment-1135077775 -# NOTE: This will only guard against installation of the dotnet versions we propose via 'features'. -# The user can attempt to install any other version at their own risk. -if [[ "${DOTNET_VERSION}" = "3"* ]] || [[ "${DOTNET_VERSION}" = "5"* ]]; then - if [[ ! "${DOTNET_VERSION_CODENAMES_REQUIRE_OLDER_LIBSSL_1}" = *"${VERSION_CODENAME}"* ]]; then - err "Dotnet ${DOTNET_VERSION} is not supported on Ubuntu ${VERSION_CODENAME} due to a change in the 'libssl' dependency across distributions.\n Please upgrade your version of dotnet, or downgrade your OS version." - exit 1 - fi -fi - -# Determine if the user wants to download .NET Runtime only, or .NET SDK & Runtime -# and set the appropriate variables. -if [ "${DOTNET_RUNTIME_ONLY}" = "true" ]; then - DOTNET_SDK_OR_RUNTIME="runtime" -elif [ "${DOTNET_RUNTIME_ONLY}" = "false" ]; then - DOTNET_SDK_OR_RUNTIME="sdk" -else - err "Expected true for installing dotnet Runtime only or false for installing SDK and Runtime. Received ${DOTNET_RUNTIME_ONLY}." +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 -# Install the .NET CLI -echo "(*) Installing .NET CLI..." +# icu-devtools includes dependencies for .NET +check_packages wget ca-certificates icu-devtools -CHANGE_OWNERSHIP="false" -if [[ "${DOTNET_ARCHIVE_ARCHITECTURES}" = *"${architecture}"* ]] && [[ "${DOTNET_ARCHIVE_VERSION_CODENAMES}" = *"${VERSION_CODENAME}"* ]] && [[ "${INSTALL_USING_APT}" = "true" ]]; then - echo "Detected ${VERSION_CODENAME} on ${architecture}. Attempting to install dotnet from apt" +wget -O "$DOTNET_INSTALL_SCRIPT" "$DOTNET_INSTALL_SCRIPT_URL" +chmod +x "$DOTNET_INSTALL_SCRIPT" - install_using_apt "${DOTNET_SDK_OR_RUNTIME}" "${DOTNET_VERSION}" false || install_using_apt "${DOTNET_SDK_OR_RUNTIME}" "${DOTNET_VERSION}" true - if [ "$?" != 0 ]; then - echo "Could not install requested version from apt on current distribution." - exit 1 - fi -else - if [[ "${INSTALL_USING_APT}" = "false" ]]; then - echo "Installing dotnet from releases url" - else - echo "Attempting to install dotnet from releases url" - fi - install_using_dotnet_releases_url "${DOTNET_SDK_OR_RUNTIME}" "${DOTNET_VERSION}" - CHANGE_OWNERSHIP="true" -fi +# Install primary version +install_version "$DOTNET_VERSION" -# Additional dotnet versions to be installed but not be set as default. -if [ ! -z "${ADDITIONAL_VERSIONS}" ]; then - OLDIFS=$IFS +# Install additional versions +if [ -n "$DOTNET_ADDITIONAL_VERSIONS" ]; then + OLD_IFS=$IFS IFS="," - read -a additional_versions <<< "$ADDITIONAL_VERSIONS" + read -a additional_versions <<< "$DOTNET_ADDITIONAL_VERSIONS" for version in "${additional_versions[@]}"; do - OVERRIDE_DEFAULT_VERSION="false" - install_using_dotnet_releases_url "${DOTNET_SDK_OR_RUNTIME}" "${version}" + # Trim whitespace from version + version="$(echo -e "$version" | tr -d '[:space:]')" + install_version "$version" done - IFS=$OLDIFS -fi - -if [ "${CHANGE_OWNERSHIP}" = "true" ]; then - if ! cat /etc/group | grep -e "^dotnet:" > /dev/null 2>&1; then - groupadd -r dotnet - fi - usermod -a -G dotnet "${USERNAME}" - - chown -R "${USERNAME}:dotnet" "${TARGET_DOTNET_ROOT}" - chmod -R g+r+w "${TARGET_DOTNET_ROOT}" - find "${TARGET_DOTNET_ROOT}" -type d -print0 | xargs -n 1 -0 chmod g+s -fi - -# Clean up -if [ "${APT_PREFERENCES_UPDATED}" = "true" ]; then - if [ "${APT_PREFERENCES_FILE_ADDED}" = "true" ]; then - rm -f /etc/apt/preferences - else - head -n -3 /etc/apt/preferences > /tmp/preferences-temp && mv /tmp/preferences-temp /etc/apt/preferences - fi + IFS=$OLD_IFS fi -rm -rf /var/lib/apt/lists/* +rm "$DOTNET_INSTALL_SCRIPT" echo "Done!" diff --git a/test/dotnet/install_additional_dotnet.sh b/test/dotnet/install_additional_dotnet.sh deleted file mode 100644 index e69c7dce1..000000000 --- a/test/dotnet/install_additional_dotnet.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -e - -# Optional: Import test library -source dev-container-features-test-lib - -check "dotnet version 6.0.301 installed as default" bash -c "dotnet --version | grep 6.0.301" -check "dotnet version 5.0 installed" bash -c "ls -l /usr/local/dotnet | grep 5.0" -check "dotnet version 3.1.420 installed" bash -c "ls -l /usr/local/dotnet | grep 3.1.420" - -# Verify current symlink exists and works -check "current link dotnet" /usr/local/dotnet/current/dotnet --info -check "current link sdk" ls -l /usr/local/dotnet/current/sdk - -# Report result -reportResults diff --git a/test/dotnet/install_dotnet_3.sh b/test/dotnet/install_dotnet_3.sh deleted file mode 100644 index 51d871bcf..000000000 --- a/test/dotnet/install_dotnet_3.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -e - -# Optional: Import test library -source dev-container-features-test-lib - -check "dotnet sdks" dotnet --list-sdks -check "some major version of dotnet 3 is installed" bash -c "dotnet --list-sdks | grep '3\.[0-9]*\.[0-9]*'" -check "dotnet version 3 installed" bash -c "ls -l /usr/share/dotnet/sdk | grep '3\.[0-9]*\.[0-9]*'" - -# Verify current symlink exists and works -check "current link dotnet" /usr/local/dotnet/current/dotnet --info -check "current link sdk" ls -l /usr/local/dotnet/current/sdk - -# Report result -reportResults diff --git a/test/dotnet/install_dotnet_6_bullseye.sh b/test/dotnet/install_dotnet_6_bullseye.sh deleted file mode 100644 index 758f0402d..000000000 --- a/test/dotnet/install_dotnet_6_bullseye.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -e - -# Optional: Import test library -source dev-container-features-test-lib - -check "dotnet sdks" dotnet --list-sdks -check "some major version of dotnet 6 is installed" bash -c "dotnet --list-sdks | grep '6\.[0-9]*\.[0-9]*'" -check "dotnet version 6 installed" bash -c "ls -l /usr/share/dotnet/sdk | grep '6\.[0-9]*\.[0-9]*'" - -# Verify current symlink exists and works -check "current link dotnet" /usr/local/dotnet/current/dotnet --info -check "current link sdk" ls -l /usr/local/dotnet/current/sdk - -# Report result -reportResults diff --git a/test/dotnet/install_dotnet_6_focal.sh b/test/dotnet/install_dotnet_6_focal.sh deleted file mode 100644 index 758f0402d..000000000 --- a/test/dotnet/install_dotnet_6_focal.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -e - -# Optional: Import test library -source dev-container-features-test-lib - -check "dotnet sdks" dotnet --list-sdks -check "some major version of dotnet 6 is installed" bash -c "dotnet --list-sdks | grep '6\.[0-9]*\.[0-9]*'" -check "dotnet version 6 installed" bash -c "ls -l /usr/share/dotnet/sdk | grep '6\.[0-9]*\.[0-9]*'" - -# Verify current symlink exists and works -check "current link dotnet" /usr/local/dotnet/current/dotnet --info -check "current link sdk" ls -l /usr/local/dotnet/current/sdk - -# Report result -reportResults diff --git a/test/dotnet/install_dotnet_6_jammy.sh b/test/dotnet/install_dotnet_6_jammy.sh deleted file mode 100644 index fd1063473..000000000 --- a/test/dotnet/install_dotnet_6_jammy.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -e - -# Optional: Import test library -source dev-container-features-test-lib - -check "dotnet sdks" dotnet --list-sdks -check "some major version of dotnet 6 is installed" bash -c "dotnet --list-sdks | grep '6\.[0-9]*\.[0-9]*'" -check "dotnet version 6 installed" bash -c "ls -l /usr/lib/dotnet/sdk | grep '6\.[0-9]*\.[0-9]*'" - -# Verify current symlink exists and works -check "current link dotnet" /usr/local/dotnet/current/dotnet --info -check "current link sdk" ls -l /usr/local/dotnet/current/sdk - -# Report result -reportResults diff --git a/test/dotnet/install_dotnet_7_bullseye.sh b/test/dotnet/install_dotnet_7_bullseye.sh deleted file mode 100644 index 2c015fc0e..000000000 --- a/test/dotnet/install_dotnet_7_bullseye.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -e - -# Optional: Import test library -source dev-container-features-test-lib - -check "dotnet sdks" dotnet --list-sdks -check "some major version of dotnet 7 is installed" bash -c "dotnet --list-sdks | grep '7\.[0-9]*\.[0-9]*'" -check "dotnet version 7 installed" bash -c "ls -l /usr/share/dotnet/sdk | grep '7\.[0-9]*\.[0-9]*'" - -# Verify current symlink exists and works -check "current link dotnet" /usr/local/dotnet/current/dotnet --info -check "current link sdk" ls -l /usr/local/dotnet/current/sdk - -# Report result -reportResults diff --git a/test/dotnet/install_dotnet_7_jammy.sh b/test/dotnet/install_dotnet_7_jammy.sh deleted file mode 100644 index 139216885..000000000 --- a/test/dotnet/install_dotnet_7_jammy.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -e - -# Optional: Import test library -source dev-container-features-test-lib - -check "dotnet sdks" dotnet --list-sdks -check "some major version of dotnet 7 is installed" bash -c "dotnet --list-sdks | grep '7\.[0-9]*\.[0-9]*'" -check "dotnet version 7 installed" bash -c "ls -l /usr/lib/dotnet/sdk | grep '7\.[0-9]*\.[0-9]*'" - -# Verify current symlink exists and works -check "current link dotnet" /usr/local/dotnet/current/dotnet --info -check "current link sdk" ls -l /usr/local/dotnet/current/sdk - -# Report result -reportResults diff --git a/test/dotnet/install_dotnet_exact_version.sh b/test/dotnet/install_dotnet_exact_version.sh new file mode 100644 index 000000000..dd2a088d4 --- /dev/null +++ b/test/dotnet/install_dotnet_exact_version.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +set -e + +export DOTNET_NOLOGO=true +export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true +export DOTNET_GENERATE_ASPNET_CERTIFICATE=false + +# 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