diff --git a/src/alpine/.devcontainer/devcontainer.json b/src/alpine/.devcontainer.json similarity index 78% rename from src/alpine/.devcontainer/devcontainer.json rename to src/alpine/.devcontainer.json index 5655f42..752e97e 100644 --- a/src/alpine/.devcontainer/devcontainer.json +++ b/src/alpine/.devcontainer.json @@ -1,10 +1,6 @@ { "name": "Alpine", - "build": { - "dockerfile": "Dockerfile", - // Update 'VARIANT' to pick an Alpine version: 3.13, 3.14, 3.15, 3.16 - "args": { "VARIANT": "3.16" } - }, + "image": "mcr.microsoft.com/devcontainers/base:0-alpine-${templateOption:imageVariant}", // Use 'forwardPorts' to make a list of ports inside the container available locally. // "forwardPorts": [], diff --git a/src/alpine/.devcontainer/Dockerfile b/src/alpine/.devcontainer/Dockerfile deleted file mode 100644 index b7abd3a..0000000 --- a/src/alpine/.devcontainer/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -# [Choice] Alpine version: 3.16, 3.15, 3.14, 3.13 -ARG VARIANT=3.16 -FROM mcr.microsoft.com/vscode/devcontainers/base:0-alpine-${VARIANT} - -# ** [Optional] Uncomment this section to install additional packages. ** -# RUN apk update \ -# && apk add --no-cache diff --git a/src/alpine/.devcontainer/library-scripts/common-alpine.sh b/src/alpine/.devcontainer/library-scripts/common-alpine.sh deleted file mode 100755 index ffb626d..0000000 --- a/src/alpine/.devcontainer/library-scripts/common-alpine.sh +++ /dev/null @@ -1,364 +0,0 @@ -#!/bin/ash -#------------------------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# 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/common.md -# Maintainer: The VS Code and Codespaces Teams -# -# Syntax: ./common-alpine.sh [install zsh flag] [username] [user UID] [user GID] [install Oh My Zsh! flag] - -set -e - -# Switch to bash right away -if [ -z "${BASH_SOURCE}" ] && [ "${SWITCHED_TO_BASH}" != "true" ]; then - apk add --no-cache bash - export SWITCHED_TO_BASH=true - exec /bin/bash "$0" "$@" - exit $? -fi - -INSTALL_ZSH=${1:-"true"} -USERNAME=${2:-"automatic"} -USER_UID=${3:-"automatic"} -USER_GID=${4:-"automatic"} -INSTALL_OH_MYS=${5:-"true"} -MARKER_FILE="/usr/local/etc/vscode-dev-containers/common" -SCRIPT_DIR="$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)" - -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 - -# 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 - -# If in automatic mode, determine if a user already exists, if not use vscode -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=vscode - fi -elif [ "${USERNAME}" = "none" ]; then - USERNAME=root - USER_UID=0 - USER_GID=0 -fi - -# Load markers to see which steps have already run -if [ -f "${MARKER_FILE}" ]; then - echo "Marker file found:" - cat "${MARKER_FILE}" - source "${MARKER_FILE}" -fi - -# Install git, bash, common dependencies -if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then - apk update - apk add --no-cache \ - openssh-client \ - gnupg \ - procps \ - lsof \ - htop \ - net-tools \ - psmisc \ - curl \ - wget \ - rsync \ - ca-certificates \ - unzip \ - zip \ - nano \ - vim \ - less \ - jq \ - libgcc \ - libstdc++ \ - krb5-libs \ - libintl \ - libssl1.1 \ - lttng-ust \ - tzdata \ - userspace-rcu \ - zlib \ - sudo \ - coreutils \ - sed \ - grep \ - which \ - ncdu \ - shadow \ - strace - - # Install man pages - package name varies between 3.12 and earlier versions - if apk info man > /dev/null 2>&1; then - apk add --no-cache man man-pages - else - apk add --no-cache mandoc man-pages - fi - - # Install git if not already installed (may be more recent than distro version) - if ! type git > /dev/null 2>&1; then - apk add --no-cache git - fi - - PACKAGES_ALREADY_INSTALLED="true" -fi - -# Create or update a non-root user to match UID/GID. -group_name="${USERNAME}" -if id -u ${USERNAME} > /dev/null 2>&1; then - # User exists, update if needed - if [ "${USER_GID}" != "automatic" ] && [ "$USER_GID" != "$(id -g $USERNAME)" ]; then - group_name="$(id -gn $USERNAME)" - groupmod --gid $USER_GID ${group_name} - usermod --gid $USER_GID $USERNAME - fi - if [ "${USER_UID}" != "automatic" ] && [ "$USER_UID" != "$(id -u $USERNAME)" ]; then - usermod --uid $USER_UID $USERNAME - fi -else - # Create user - if [ "${USER_GID}" = "automatic" ]; then - groupadd $USERNAME - else - groupadd --gid $USER_GID $USERNAME - fi - if [ "${USER_UID}" = "automatic" ]; then - useradd -s /bin/bash --gid $USERNAME -m $USERNAME - else - useradd -s /bin/bash -K MAIL_DIR=/dev/null --uid $USER_UID --gid $USERNAME -m $USERNAME - fi -fi - -# Add sudo support for non-root user -if [ "${USERNAME}" != "root" ] && [ "${EXISTING_NON_ROOT_USER}" != "${USERNAME}" ]; then - echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME - chmod 0440 /etc/sudoers.d/$USERNAME - EXISTING_NON_ROOT_USER="${USERNAME}" -fi - -# ** Shell customization section ** -if [ "${USERNAME}" = "root" ]; then - user_rc_path="/root" -else - user_rc_path="/home/${USERNAME}" -fi - -# .bashrc/.zshrc snippet -rc_snippet="$(cat << 'EOF' - -if [ -z "${USER}" ]; then export USER=$(whoami); fi -if [[ "${PATH}" != *"$HOME/.local/bin"* ]]; then export PATH="${PATH}:$HOME/.local/bin"; fi - -# Display optional first run image specific notice if configured and terminal is interactive -if [ -t 1 ] && [[ "${TERM_PROGRAM}" = "vscode" || "${TERM_PROGRAM}" = "codespaces" ]] && [ ! -f "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed" ]; then - if [ -f "/usr/local/etc/vscode-dev-containers/first-run-notice.txt" ]; then - cat "/usr/local/etc/vscode-dev-containers/first-run-notice.txt" - elif [ -f "/workspaces/.codespaces/shared/first-run-notice.txt" ]; then - cat "/workspaces/.codespaces/shared/first-run-notice.txt" - fi - mkdir -p "$HOME/.config/vscode-dev-containers" - # Mark first run notice as displayed after 10s to avoid problems with fast terminal refreshes hiding it - ((sleep 10s; touch "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed") &) -fi - -# Set the default git editor if not already set -if [ -z "$(git config --get core.editor)" ] && [ -z "${GIT_EDITOR}" ]; then - if [ "${TERM_PROGRAM}" = "vscode" ]; then - if [[ -n $(command -v code-insiders) && -z $(command -v code) ]]; then - export GIT_EDITOR="code-insiders --wait" - else - export GIT_EDITOR="code --wait" - fi - fi -fi - -EOF -)" - -# code shim, it fallbacks to code-insiders if code is not available -cat << 'EOF' > /usr/local/bin/code -#!/bin/sh - -get_in_path_except_current() { - which -a "$1" | grep -A1 "$0" | grep -v "$0" -} - -code="$(get_in_path_except_current code)" - -if [ -n "$code" ]; then - exec "$code" "$@" -elif [ "$(command -v code-insiders)" ]; then - exec code-insiders "$@" -else - echo "code or code-insiders is not installed" >&2 - exit 127 -fi -EOF -chmod +x /usr/local/bin/code - -# Codespaces bash and OMZ themes - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme -codespaces_bash="$(cat \ -<<'EOF' - -# Codespaces bash prompt theme -__bash_prompt() { - local userpart='`export XIT=$? \ - && [ ! -z "${GITHUB_USER}" ] && echo -n "\[\033[0;32m\]@${GITHUB_USER} " || echo -n "\[\033[0;32m\]\u " \ - && [ "$XIT" -ne "0" ] && echo -n "\[\033[1;31m\]➜" || echo -n "\[\033[0m\]➜"`' - local gitbranch='`\ - if [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \ - export BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || git rev-parse --short HEAD 2>/dev/null); \ - if [ "${BRANCH}" != "" ]; then \ - echo -n "\[\033[0;36m\](\[\033[1;31m\]${BRANCH}" \ - && if git ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \ - echo -n " \[\033[1;33m\]✗"; \ - fi \ - && echo -n "\[\033[0;36m\]) "; \ - fi; \ - fi`' - local lightblue='\[\033[1;34m\]' - local removecolor='\[\033[0m\]' - PS1="${userpart} ${lightblue}\w ${gitbranch}${removecolor}\$ " - unset -f __bash_prompt -} -__bash_prompt - -EOF -)" - -codespaces_zsh="$(cat \ -<<'EOF' -# Codespaces zsh prompt theme -__zsh_prompt() { - local prompt_username - if [ ! -z "${GITHUB_USER}" ]; then - prompt_username="@${GITHUB_USER}" - else - prompt_username="%n" - fi - PROMPT="%{$fg[green]%}${prompt_username} %(?:%{$reset_color%}➜ :%{$fg_bold[red]%}➜ )" # User/exit code arrow - PROMPT+='%{$fg_bold[blue]%}%(5~|%-1~/…/%3~|%4~)%{$reset_color%} ' # cwd - PROMPT+='$([ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ] && git_prompt_info)' # Git status - PROMPT+='%{$fg[white]%}$ %{$reset_color%}' - unset -f __zsh_prompt -} -ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_bold[cyan]%}(%{$fg_bold[red]%}" -ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%} " -ZSH_THEME_GIT_PROMPT_DIRTY=" %{$fg_bold[yellow]%}✗%{$fg_bold[cyan]%})" -ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg_bold[cyan]%})" -__zsh_prompt - -EOF -)" - -# Add RC snippet and custom bash prompt -if [ "${RC_SNIPPET_ALREADY_ADDED}" != "true" ]; then - echo -e "${rc_snippet}\n${codespaces_bash}" >> "${user_rc_path}/.bashrc" - if [ "${USERNAME}" != "root" ]; then - echo -e "${rc_snippet}\n${codespaces_bash}" >> "/root/.bashrc" - fi - chown ${USERNAME}:${group_name} "${user_rc_path}/.bashrc" - RC_SNIPPET_ALREADY_ADDED="true" -fi - -# Optionally install and configure zsh and Oh My Zsh! -if [ "${INSTALL_ZSH}" = "true" ]; then - if ! type zsh > /dev/null 2>&1; then - apk add zsh - fi - if [ "${ZSH_ALREADY_INSTALLED}" != "true" ]; then - echo "${rc_snippet}" >> /etc/zsh/zshrc - ZSH_ALREADY_INSTALLED="true" - fi - - # Adapted, simplified inline Oh My Zsh! install steps that adds, defaults to a codespaces theme. - # See https://github.com/ohmyzsh/ohmyzsh/blob/master/tools/install.sh for official script. - oh_my_install_dir="${user_rc_path}/.oh-my-zsh" - if [ ! -d "${oh_my_install_dir}" ] && [ "${INSTALL_OH_MYS}" = "true" ]; then - template_path="${oh_my_install_dir}/templates/zshrc.zsh-template" - user_rc_file="${user_rc_path}/.zshrc" - umask g-w,o-w - mkdir -p ${oh_my_install_dir} - git clone --depth=1 \ - -c core.eol=lf \ - -c core.autocrlf=false \ - -c fsck.zeroPaddedFilemode=ignore \ - -c fetch.fsck.zeroPaddedFilemode=ignore \ - -c receive.fsck.zeroPaddedFilemode=ignore \ - "https://github.com/ohmyzsh/ohmyzsh" "${oh_my_install_dir}" 2>&1 - echo -e "$(cat "${template_path}")\nDISABLE_AUTO_UPDATE=true\nDISABLE_UPDATE_PROMPT=true" > ${user_rc_file} - sed -i -e 's/ZSH_THEME=.*/ZSH_THEME="codespaces"/g' ${user_rc_file} - mkdir -p ${oh_my_install_dir}/custom/themes - echo "${codespaces_zsh}" > "${oh_my_install_dir}/custom/themes/codespaces.zsh-theme" - # Shrink git while still enabling updates - cd "${oh_my_install_dir}" - git repack -a -d -f --depth=1 --window=1 - # Copy to non-root user if one is specified - if [ "${USERNAME}" != "root" ]; then - cp -rf "${user_rc_file}" "${oh_my_install_dir}" /root - chown -R ${USERNAME}:${group_name} "${user_rc_path}" - fi - fi -fi - -# Persist image metadata info, script if meta.env found in same directory -meta_info_script="$(cat << 'EOF' -#!/bin/sh -. /usr/local/etc/vscode-dev-containers/meta.env - -# Minimal output -if [ "$1" = "version" ] || [ "$1" = "image-version" ]; then - echo "${VERSION}" - exit 0 -elif [ "$1" = "release" ]; then - echo "${GIT_REPOSITORY_RELEASE}" - exit 0 -elif [ "$1" = "content" ] || [ "$1" = "content-url" ] || [ "$1" = "contents" ] || [ "$1" = "contents-url" ]; then - echo "${CONTENTS_URL}" - exit 0 -fi - -#Full output -echo -echo "Development container image information" -echo -if [ ! -z "${VERSION}" ]; then echo "- Image version: ${VERSION}"; fi -if [ ! -z "${DEFINITION_ID}" ]; then echo "- Definition ID: ${DEFINITION_ID}"; fi -if [ ! -z "${VARIANT}" ]; then echo "- Variant: ${VARIANT}"; fi -if [ ! -z "${GIT_REPOSITORY}" ]; then echo "- Source code repository: ${GIT_REPOSITORY}"; fi -if [ ! -z "${GIT_REPOSITORY_RELEASE}" ]; then echo "- Source code release/branch: ${GIT_REPOSITORY_RELEASE}"; fi -if [ ! -z "${BUILD_TIMESTAMP}" ]; then echo "- Timestamp: ${BUILD_TIMESTAMP}"; fi -if [ ! -z "${CONTENTS_URL}" ]; then echo && echo "More info: ${CONTENTS_URL}"; fi -echo -EOF -)" -if [ -f "${SCRIPT_DIR}/meta.env" ]; then - mkdir -p /usr/local/etc/vscode-dev-containers/ - cp -f "${SCRIPT_DIR}/meta.env" /usr/local/etc/vscode-dev-containers/meta.env - echo "${meta_info_script}" > /usr/local/bin/devcontainer-info - chmod +x /usr/local/bin/devcontainer-info -fi - -# Write marker file -mkdir -p "$(dirname "${MARKER_FILE}")" -echo -e "\ - PACKAGES_ALREADY_INSTALLED=${PACKAGES_ALREADY_INSTALLED}\n\ - EXISTING_NON_ROOT_USER=${EXISTING_NON_ROOT_USER}\n\ - RC_SNIPPET_ALREADY_ADDED=${RC_SNIPPET_ALREADY_ADDED}\n\ - ZSH_ALREADY_INSTALLED=${ZSH_ALREADY_INSTALLED}" > "${MARKER_FILE}" - -echo "Done!" diff --git a/src/alpine/.devcontainer/library-scripts/meta.env b/src/alpine/.devcontainer/library-scripts/meta.env deleted file mode 100644 index 9e54336..0000000 --- a/src/alpine/.devcontainer/library-scripts/meta.env +++ /dev/null @@ -1 +0,0 @@ -VERSION='dev' diff --git a/src/alpine/devcontainer-template.json b/src/alpine/devcontainer-template.json new file mode 100644 index 0000000..c73d653 --- /dev/null +++ b/src/alpine/devcontainer-template.json @@ -0,0 +1,29 @@ +{ + "id": "alpine", + "version": "1.0.0", + "name": "Alpine", + "description": "Simple Alpine container with Git installed.", + "documentationURL": "https://github.com/devcontainers/templates/tree/main/src/alpine", + "publisher": "Dev Container Spec Maintainers", + "licenseURL": "https://github.com/devcontainers/templates/LICENSE", + "type": "image", + "options": { + "imageVariant": { + "type": "string", + "description": "Alpine version:", + "proposals": [ + "3.16", + "3.15", + "3.14", + "3.13" + ], + "default": "3.16", + "replaceIn": [ + ".devcontainer.json" + ] + } + }, + "platforms": [ + "Any" + ] +} diff --git a/src/cpp-mariadb/.devcontainer/Dockerfile b/src/cpp-mariadb/.devcontainer/Dockerfile index 95f53d9..ff72e51 100644 --- a/src/cpp-mariadb/.devcontainer/Dockerfile +++ b/src/cpp-mariadb/.devcontainer/Dockerfile @@ -1,6 +1,4 @@ -# [Choice] Debian / Ubuntu version (use Debian 11, Ubuntu 18.04/22.04 on local arm64/Apple Silicon): debian-11, debian-10, ubuntu-22.04, ubuntu-20.04, ubuntu-18.04 -ARG VARIANT=debian-11 -FROM mcr.microsoft.com/vscode/devcontainers/cpp:0-${VARIANT} +FROM mcr.microsoft.com/devcontainers/cpp:0-${templateOption:imageVariant} # Everything below this is needed for installing MariaDB # Instructions are copied and modified from: https://mariadb.com/docs/clients/mariadb-connectors/connector-cpp/install/ @@ -10,12 +8,11 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ COPY ./install-mariadb.sh /tmp/ RUN chmod +x /tmp/install-mariadb.sh && /tmp/install-mariadb.sh && rm -f /tmp/install-mariadb.sh -# [Optional] Install CMake version different from what base image has already installed. -# CMake reinstall choices: none, 3.21.5, 3.22.2, or versions from https://cmake.org/download/ -ARG REINSTALL_CMAKE_VERSION_FROM_SOURCE="none" +ARG REINSTALL_CMAKE_VERSION_FROM_SOURCE="${templateOption:reinstallCmakeVersionFromSource}" # Optionally install the cmake for vcpkg COPY ./reinstall-cmake.sh /tmp/ + RUN if [ "${REINSTALL_CMAKE_VERSION_FROM_SOURCE}" != "none" ]; then \ chmod +x /tmp/reinstall-cmake.sh && /tmp/reinstall-cmake.sh ${REINSTALL_CMAKE_VERSION_FROM_SOURCE}; \ fi \ @@ -26,4 +23,4 @@ RUN if [ "${REINSTALL_CMAKE_VERSION_FROM_SOURCE}" != "none" ]; then \ # [Optional] Uncomment this section to install additional packages. # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ -# && apt-get -y install --no-install-recommends \ No newline at end of file +# && apt-get -y install --no-install-recommends diff --git a/src/cpp-mariadb/.devcontainer/devcontainer.json b/src/cpp-mariadb/.devcontainer/devcontainer.json index c352034..c2e83d4 100644 --- a/src/cpp-mariadb/.devcontainer/devcontainer.json +++ b/src/cpp-mariadb/.devcontainer/devcontainer.json @@ -3,20 +3,7 @@ "dockerComposeFile": "docker-compose.yml", "service": "app", "workspaceFolder": "/workspace", - - // Configure tool-specific properties. - "customizations": { - // Configure properties specific to VS Code. - "vscode": { - // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "ms-vscode.cpptools", - "ms-vscode.cmake-tools", - "ms-vscode.cpptools-extension-pack" - ] - } - }, - + // Use 'forwardPorts' to make a list of ports inside the container available locally. // This is the recommended way to access the container from the host // "forwardPorts": [3306], diff --git a/src/cpp-mariadb/.devcontainer/docker-compose.yml b/src/cpp-mariadb/.devcontainer/docker-compose.yml index 959fca0..2d5b29a 100644 --- a/src/cpp-mariadb/.devcontainer/docker-compose.yml +++ b/src/cpp-mariadb/.devcontainer/docker-compose.yml @@ -8,10 +8,6 @@ services: build: context: . dockerfile: Dockerfile - args: - # Update 'VARIANT' to pick a version of CPP - # See the README for more information on available versions. - VARIANT: debian-11 env_file: - .env diff --git a/src/cpp-mariadb/.devcontainer/install-mariadb.sh b/src/cpp-mariadb/.devcontainer/install-mariadb.sh old mode 100755 new mode 100644 diff --git a/src/cpp-mariadb/.devcontainer/reinstall-cmake.sh b/src/cpp-mariadb/.devcontainer/reinstall-cmake.sh old mode 100755 new mode 100644 diff --git a/src/cpp-mariadb/.gitignore b/src/cpp-mariadb/.gitignore deleted file mode 100644 index e387d27..0000000 --- a/src/cpp-mariadb/.gitignore +++ /dev/null @@ -1,35 +0,0 @@ -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app - -# build dir -build/ \ No newline at end of file diff --git a/src/cpp-mariadb/devcontainer-template.json b/src/cpp-mariadb/devcontainer-template.json new file mode 100644 index 0000000..d4a43ac --- /dev/null +++ b/src/cpp-mariadb/devcontainer-template.json @@ -0,0 +1,43 @@ +{ + "id": "cpp-mariadb", + "version": "1.0.0", + "name": "C++ & MariaDB", + "description": "Develop C++ applications on Linux. Includes Debian C++ build tools.", + "documentationURL": "https://github.com/devcontainers/templates/tree/main/src/cpp-mariadb", + "publisher": "Dev Container Spec Maintainers", + "licenseURL": "https://github.com/devcontainers/templates/LICENSE", + "type": "dockerCompose", + "options": { + "imageVariant": { + "type": "string", + "description": "Debian / Ubuntu version (use Debian 11, Ubuntu 18.04/22.04 on local arm64/Apple Silicon):", + "proposals": [ + "debian-11", + "debian-10", + "ubuntu-22.04", + "ubuntu-20.04", + "ubuntu-18.04" + ], + "default": "debian-11", + "replaceIn": [ + ".devcontainer/Dockerfile" + ] + }, + "reinstallCmakeVersionFromSource": { + "type": "string", + "description": "Install CMake version different from what base image has already installed.", + "proposals": [ + "none", + "3.21.5", + "3.22.2" + ], + "default": "none", + "replaceIn": [ + ".devcontainer/Dockerfile" + ] + } + }, + "platforms": [ + "C++" + ] +} \ No newline at end of file diff --git a/src/cpp/.devcontainer/Dockerfile b/src/cpp/.devcontainer/Dockerfile index df1c9e1..03f4e53 100644 --- a/src/cpp/.devcontainer/Dockerfile +++ b/src/cpp/.devcontainer/Dockerfile @@ -1,13 +1,10 @@ -# [Choice] Debian / Ubuntu version (use Debian 11, Ubuntu 18.04/22.04 on local arm64/Apple Silicon): debian-11, debian-10, ubuntu-22.04, ubuntu-20.04, ubuntu-18.04 -ARG VARIANT=debian-11 -FROM mcr.microsoft.com/vscode/devcontainers/cpp:0-${VARIANT} +FROM mcr.microsoft.com/devcontainers/cpp:0-${templateOption:imageVariant} -# [Optional] Install CMake version different from what base image has already installed. -# CMake reinstall choices: none, 3.21.5, 3.22.2, or versions from https://cmake.org/download/ -ARG REINSTALL_CMAKE_VERSION_FROM_SOURCE="none" +ARG REINSTALL_CMAKE_VERSION_FROM_SOURCE="${templateOption:reinstallCmakeVersionFromSource}" # Optionally install the cmake for vcpkg COPY ./reinstall-cmake.sh /tmp/ + RUN if [ "${REINSTALL_CMAKE_VERSION_FROM_SOURCE}" != "none" ]; then \ chmod +x /tmp/reinstall-cmake.sh && /tmp/reinstall-cmake.sh ${REINSTALL_CMAKE_VERSION_FROM_SOURCE}; \ fi \ diff --git a/src/cpp/.devcontainer/base-scripts/install-vcpkg.sh b/src/cpp/.devcontainer/base-scripts/install-vcpkg.sh deleted file mode 100755 index 821e2b6..0000000 --- a/src/cpp/.devcontainer/base-scripts/install-vcpkg.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env bash -#------------------------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. -#------------------------------------------------------------------------------------------------------------- -# -set -e - -USERNAME=${1:-"vscode"} - -# bionic and stretch pkg repos install cmake version < 3.15 which is required to run bootstrap-vcpkg.sh on ARM64 -VCPKG_UNSUPPORTED_ARM64_VERSION_CODENAMES="stretch bionic" - -. /etc/os-release - -# Exit early if ARM64 OS does not have cmake version required to build Vcpkg -if [ "$(dpkg --print-architecture)" = "arm64" ] && [[ "${VCPKG_UNSUPPORTED_ARM64_VERSION_CODENAMES}" = *"${VERSION_CODENAME}"* ]]; then - echo "OS ${VERSION_CODENAME} ARM64 pkg repo installs cmake version < 3.15, which is required to build Vcpkg." - exit 0 -fi - -# Add to bashrc/zshrc files for all users. -updaterc() { - 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 -} - -# Run apt-get if needed. -apt_get_update_if_needed() { - if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then - echo "Running apt-get update..." - apt-get update - else - echo "Skipping apt-get update." - fi -} - -# Check if packages are installed and installs them if not. -check_packages() { - if ! dpkg -s "$@" > /dev/null 2>&1; then - apt_get_update_if_needed - apt-get -y install --no-install-recommends "$@" - fi -} - -export DEBIAN_FRONTEND=noninteractive - -# Install additional packages needed by vcpkg: https://github.com/microsoft/vcpkg/blob/master/README.md#installing-linux-developer-tools -check_packages build-essential tar curl zip unzip pkg-config bash-completion ninja-build git - -# Setup group and add user -umask 0002 -if ! cat /etc/group | grep -e "^vcpkg:" > /dev/null 2>&1; then - groupadd -r "vcpkg" -fi -usermod -a -G "vcpkg" "${USERNAME}" - -# Start Installation -# Clone repository with ports and installer -mkdir -p "${VCPKG_ROOT}" -mkdir -p "${VCPKG_DOWNLOADS}" -git clone --depth=1 \ - -c core.eol=lf \ - -c core.autocrlf=false \ - -c fsck.zeroPaddedFilemode=ignore \ - -c fetch.fsck.zeroPaddedFilemode=ignore \ - -c receive.fsck.zeroPaddedFilemode=ignore \ - https://github.com/microsoft/vcpkg "${VCPKG_ROOT}" - -## Run installer to get latest stable vcpkg binary -## https://github.com/microsoft/vcpkg/blob/7e7dad5fe20cdc085731343e0e197a7ae655555b/scripts/bootstrap.sh#L126-L144 -"${VCPKG_ROOT}"/bootstrap-vcpkg.sh - -# Add vcpkg to PATH -updaterc "$(cat << EOF -export VCPKG_ROOT="${VCPKG_ROOT}" -if [[ "\${PATH}" != *"\${VCPKG_ROOT}"* ]]; then export PATH="\${PATH}:\${VCPKG_ROOT}"; fi -EOF -)" - -# Give read/write permissions to the user group. -chown -R ":vcpkg" "${VCPKG_ROOT}" "${VCPKG_DOWNLOADS}" -chmod g+r+w+s "${VCPKG_ROOT}" "${VCPKG_DOWNLOADS}" -chmod -R g+r+w "${VCPKG_ROOT}" "${VCPKG_DOWNLOADS}" - -# Enable tab completion for bash and zsh -VCPKG_FORCE_SYSTEM_BINARIES=1 su "${USERNAME}" -c "${VCPKG_ROOT}/vcpkg integrate bash" -VCPKG_FORCE_SYSTEM_BINARIES=1 su "${USERNAME}" -c "${VCPKG_ROOT}/vcpkg integrate zsh" \ No newline at end of file diff --git a/src/cpp/.devcontainer/devcontainer.json b/src/cpp/.devcontainer/devcontainer.json index 25472b4..0683a6d 100644 --- a/src/cpp/.devcontainer/devcontainer.json +++ b/src/cpp/.devcontainer/devcontainer.json @@ -1,23 +1,7 @@ { "name": "C++", "build": { - "dockerfile": "Dockerfile", - // Update 'VARIANT' to pick an Debian / Ubuntu OS version: debian-11, debian-10, ubuntu-22.04, ubuntu-20.04, ubuntu-18.04 - // Use Debian 11, Ubuntu 18.04 or Ubuntu 22.04 on local arm64/Apple Silicon - "args": { "VARIANT": "debian-11" } - }, - "runArgs": ["--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"], - - // Configure tool-specific properties. - "customizations": { - // Configure properties specific to VS Code. - "vscode": { - // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "ms-vscode.cpptools", - "ms-vscode.cmake-tools" - ] - } + "dockerfile": "Dockerfile" }, // Use 'forwardPorts' to make a list of ports inside the container available locally. diff --git a/src/cpp/.devcontainer/library-scripts/meta.env b/src/cpp/.devcontainer/library-scripts/meta.env deleted file mode 100644 index 9e54336..0000000 --- a/src/cpp/.devcontainer/library-scripts/meta.env +++ /dev/null @@ -1 +0,0 @@ -VERSION='dev' diff --git a/src/cpp/.devcontainer/reinstall-cmake.sh b/src/cpp/.devcontainer/reinstall-cmake.sh old mode 100755 new mode 100644 diff --git a/src/cpp/devcontainer-template.json b/src/cpp/devcontainer-template.json new file mode 100644 index 0000000..e98a558 --- /dev/null +++ b/src/cpp/devcontainer-template.json @@ -0,0 +1,43 @@ +{ + "id": "cpp", + "version": "1.0.0", + "name": "C++", + "description": "Develop C++ applications on Linux. Includes Debian C++ build tools.", + "documentationURL": "https://github.com/devcontainers/templates/tree/main/src/cpp", + "publisher": "Dev Container Spec Maintainers", + "licenseURL": "https://github.com/devcontainers/templates/LICENSE", + "type": "dockerfile", + "options": { + "imageVariant": { + "type": "string", + "description": "Debian / Ubuntu version (use Debian 11, Ubuntu 18.04/22.04 on local arm64/Apple Silicon):", + "proposals": [ + "debian-11", + "debian-10", + "ubuntu-22.04", + "ubuntu-20.04", + "ubuntu-18.04" + ], + "default": "debian-11", + "replaceIn": [ + ".devcontainer/Dockerfile" + ] + }, + "reinstallCmakeVersionFromSource": { + "type": "string", + "description": "Install CMake version different from what base image has already installed.", + "proposals": [ + "none", + "3.21.5", + "3.22.2" + ], + "default": "none", + "replaceIn": [ + ".devcontainer/Dockerfile" + ] + } + }, + "platforms": [ + "C++" + ] +} diff --git a/src/cpp/manifest.json b/src/cpp/manifest.json deleted file mode 100644 index ff3921c..0000000 --- a/src/cpp/manifest.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "variants": ["bullseye", "buster", "jammy", "focal", "bionic"], - "definitionVersion": "0.205.2", - "build": { - "latest": "bullseye", - "parent": { - "bullseye": "debian", - "buster": "debian", - "jammy": "ubuntu", - "focal": "ubuntu", - "bionic": "ubuntu" - }, - "rootDistro": "debian", - "architectures": { - "bullseye": ["linux/amd64", "linux/arm64"], - "buster": ["linux/amd64"], - "jammy": ["linux/amd64", "linux/arm64"], - "focal": ["linux/amd64"], - "bionic": ["linux/amd64", "linux/arm64"] - }, - "tags": [ - "cpp:${VERSION}-${VARIANT}" - ], - "variantTags": { - "bullseye": [ - "cpp:${VERSION}-debian-11", - "cpp:${VERSION}-debian11", - "cpp:${VERSION}-debian", - "cpp:${VERSION}" - ], - "buster": [ - "cpp:${VERSION}-debian-10", - "cpp:${VERSION}-debian10" - ], - "stretch": [ - "cpp:${VERSION}-debian-9", - "cpp:${VERSION}-debian9" - ], - "jammy": [ - "cpp:${VERSION}-ubuntu-22.04", - "cpp:${VERSION}-ubuntu22.04" - ], - "hirsute": [ - "cpp:${VERSION}-ubuntu-21.04", - "cpp:${VERSION}-ubuntu21.04" - ], - "focal": [ - "cpp:${VERSION}-ubuntu-20.04", - "cpp:${VERSION}-ubuntu20.04", - "cpp:${VERSION}-ubuntu" - ], - "bionic": [ - "cpp:${VERSION}-ubuntu-18.04", - "cpp:${VERSION}-ubuntu18.04" - ] - } - }, - "dependencies": { - "image": "buildpack-deps:${VARIANT}-curl", - "imageLink": "https://hub.docker.com/_/buildpack-deps", - "apt": [ - "build-essential", - "cmake", - "cppcheck", - "valgrind", - "clang", - "lldb", - "llvm", - "gdb", - "tar", - "curl", - "zip", - "unzip", - "pkg-config", - "bash-completion", - "ninja-build" - ], - "git": { - "Oh My Zsh!": "/home/vscode/.oh-my-zsh", - "vcpkg": "/usr/local/vcpkg" - }, - "languages": { - "GCC": { - "cgIgnore": true - }, - "Clang": { - "cgIgnore": true - } - } - } -} diff --git a/src/dotnet/.devcontainer.json b/src/dotnet/.devcontainer.json new file mode 100644 index 0000000..b2e3dac --- /dev/null +++ b/src/dotnet/.devcontainer.json @@ -0,0 +1,9 @@ +{ + "name": "C# (.NET)", + "image": "mcr.microsoft.com/devcontainers/dotnet:0-${templateOption:imageVariant}", + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "${templateOption:nodeVersion}" + } + } +} diff --git a/src/dotnet/.devcontainer/Dockerfile b/src/dotnet/.devcontainer/Dockerfile deleted file mode 100644 index 691aeac..0000000 --- a/src/dotnet/.devcontainer/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -# [Choice] .NET version: 6.0, 3.1, 6.0-bullseye, 3.1-bullseye, 6.0-focal, 3.1-focal -ARG VARIANT=6.0-bullseye -FROM mcr.microsoft.com/vscode/devcontainers/dotnet:0-${VARIANT} - -# [Choice] Node.js version: none, lts/*, 18, 16, 14 -ARG NODE_VERSION="none" -RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi - -# [Optional] Uncomment this section to install additional OS packages. -# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ -# && apt-get -y install --no-install-recommends - -# [Optional] Uncomment this line to install global node packages. -# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g " 2>&1 \ No newline at end of file diff --git a/src/dotnet/.devcontainer/devcontainer.json b/src/dotnet/.devcontainer/devcontainer.json deleted file mode 100644 index c14de95..0000000 --- a/src/dotnet/.devcontainer/devcontainer.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "name": "C# (.NET)", - "build": { - "dockerfile": "Dockerfile", - "args": { - // Update 'VARIANT' to pick a .NET Core version: 3.1, 6.0 - // Append -bullseye or -focal to pin to an OS version. - "VARIANT": "6.0-bullseye", - // Options - "NODE_VERSION": "lts/*" - } - }, - - // Configure tool-specific properties. - "customizations": { - // Configure properties specific to VS Code. - "vscode": { - // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "ms-dotnettools.csharp" - ] - } - }, - - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [5000, 5001], - - // [Optional] To reuse of your local HTTPS dev cert: - // - // 1. Export it locally using this command: - // * Windows PowerShell: - // dotnet dev-certs https --trust; dotnet dev-certs https -ep "$env:USERPROFILE/.aspnet/https/aspnetapp.pfx" -p "SecurePwdGoesHere" - // * macOS/Linux terminal: - // dotnet dev-certs https --trust; dotnet dev-certs https -ep "${HOME}/.aspnet/https/aspnetapp.pfx" -p "SecurePwdGoesHere" - // - // 2. Uncomment these 'remoteEnv' lines: - // "remoteEnv": { - // "ASPNETCORE_Kestrel__Certificates__Default__Password": "SecurePwdGoesHere", - // "ASPNETCORE_Kestrel__Certificates__Default__Path": "/home/vscode/.aspnet/https/aspnetapp.pfx", - // }, - // - // 3. Do one of the following depending on your scenario: - // * When using GitHub Codespaces and/or Remote - Containers: - // 1. Start the container - // 2. Drag ~/.aspnet/https/aspnetapp.pfx into the root of the file explorer - // 3. Open a terminal in VS Code and run "mkdir -p /home/vscode/.aspnet/https && mv aspnetapp.pfx /home/vscode/.aspnet/https" - // - // * If only using Remote - Containers with a local container, uncomment this line instead: - // "mounts": [ "source=${env:HOME}${env:USERPROFILE}/.aspnet/https,target=/home/vscode/.aspnet/https,type=bind" ], - - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "dotnet restore", - - // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. - "remoteUser": "vscode" -} diff --git a/src/dotnet/.devcontainer/library-scripts/common-debian.sh b/src/dotnet/.devcontainer/library-scripts/common-debian.sh deleted file mode 100755 index 35f06f5..0000000 --- a/src/dotnet/.devcontainer/library-scripts/common-debian.sh +++ /dev/null @@ -1,454 +0,0 @@ -#!/usr/bin/env bash -#------------------------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# 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/common.md -# Maintainer: The VS Code and Codespaces Teams -# -# Syntax: ./common-debian.sh [install zsh flag] [username] [user UID] [user GID] [upgrade packages flag] [install Oh My Zsh! flag] [Add non-free packages] - -set -e - -INSTALL_ZSH=${1:-"true"} -USERNAME=${2:-"automatic"} -USER_UID=${3:-"automatic"} -USER_GID=${4:-"automatic"} -UPGRADE_PACKAGES=${5:-"true"} -INSTALL_OH_MYS=${6:-"true"} -ADD_NON_FREE_PACKAGES=${7:-"false"} -SCRIPT_DIR="$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)" -MARKER_FILE="/usr/local/etc/vscode-dev-containers/common" - -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 - -# 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 - -# If in automatic mode, determine if a user already exists, if not use vscode -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=vscode - fi -elif [ "${USERNAME}" = "none" ]; then - USERNAME=root - USER_UID=0 - USER_GID=0 -fi - -# Load markers to see which steps have already run -if [ -f "${MARKER_FILE}" ]; then - echo "Marker file found:" - cat "${MARKER_FILE}" - source "${MARKER_FILE}" -fi - -# Ensure apt is in non-interactive to avoid prompts -export DEBIAN_FRONTEND=noninteractive - -# Function to call apt-get if needed -apt_get_update_if_needed() -{ - if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then - echo "Running apt-get update..." - apt-get update - else - echo "Skipping apt-get update." - fi -} - -# Run install apt-utils to avoid debconf warning then verify presence of other common developer tools and dependencies -if [ "${PACKAGES_ALREADY_INSTALLED}" != "true" ]; then - - package_list="apt-utils \ - openssh-client \ - gnupg2 \ - dirmngr \ - iproute2 \ - procps \ - lsof \ - htop \ - net-tools \ - psmisc \ - curl \ - wget \ - rsync \ - ca-certificates \ - unzip \ - zip \ - nano \ - vim-tiny \ - less \ - jq \ - lsb-release \ - apt-transport-https \ - dialog \ - libc6 \ - libgcc1 \ - libkrb5-3 \ - libgssapi-krb5-2 \ - libicu[0-9][0-9] \ - liblttng-ust0 \ - libstdc++6 \ - zlib1g \ - locales \ - sudo \ - ncdu \ - man-db \ - strace \ - manpages \ - manpages-dev \ - init-system-helpers" - - # Needed for adding manpages-posix and manpages-posix-dev which are non-free packages in Debian - if [ "${ADD_NON_FREE_PACKAGES}" = "true" ]; then - # Bring in variables from /etc/os-release like VERSION_CODENAME - . /etc/os-release - sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list - sed -i -E "s/deb-src http:\/\/(deb|httredir)\.debian\.org\/debian ${VERSION_CODENAME} main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME} main contrib non-free/" /etc/apt/sources.list - sed -i -E "s/deb http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list - sed -i -E "s/deb-src http:\/\/(deb|httpredir)\.debian\.org\/debian ${VERSION_CODENAME}-updates main/deb http:\/\/\1\.debian\.org\/debian ${VERSION_CODENAME}-updates main contrib non-free/" /etc/apt/sources.list - sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list - sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}\/updates main contrib non-free/" /etc/apt/sources.list - sed -i "s/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list - sed -i "s/deb-src http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main/deb http:\/\/deb\.debian\.org\/debian ${VERSION_CODENAME}-backports main contrib non-free/" /etc/apt/sources.list - # Handle bullseye location for security https://www.debian.org/releases/bullseye/amd64/release-notes/ch-information.en.html - sed -i "s/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list - sed -i "s/deb-src http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main/deb http:\/\/security\.debian\.org\/debian-security ${VERSION_CODENAME}-security main contrib non-free/" /etc/apt/sources.list - echo "Running apt-get update..." - apt-get update - package_list="${package_list} manpages-posix manpages-posix-dev" - else - apt_get_update_if_needed - fi - - # Install libssl1.1 if available - if [[ ! -z $(apt-cache --names-only search ^libssl1.1$) ]]; then - package_list="${package_list} libssl1.1" - fi - - # Install appropriate version of libssl1.0.x if available - libssl_package=$(dpkg-query -f '${db:Status-Abbrev}\t${binary:Package}\n' -W 'libssl1\.0\.?' 2>&1 || echo '') - if [ "$(echo "$LIlibssl_packageBSSL" | grep -o 'libssl1\.0\.[0-9]:' | uniq | sort | wc -l)" -eq 0 ]; then - if [[ ! -z $(apt-cache --names-only search ^libssl1.0.2$) ]]; then - # Debian 9 - package_list="${package_list} libssl1.0.2" - elif [[ ! -z $(apt-cache --names-only search ^libssl1.0.0$) ]]; then - # Ubuntu 18.04, 16.04, earlier - package_list="${package_list} libssl1.0.0" - fi - fi - - echo "Packages to verify are installed: ${package_list}" - apt-get -y install --no-install-recommends ${package_list} 2> >( grep -v 'debconf: delaying package configuration, since apt-utils is not installed' >&2 ) - - # Install git if not already installed (may be more recent than distro version) - if ! type git > /dev/null 2>&1; then - apt-get -y install --no-install-recommends git - fi - - PACKAGES_ALREADY_INSTALLED="true" -fi - -# Get to latest versions of all packages -if [ "${UPGRADE_PACKAGES}" = "true" ]; then - apt_get_update_if_needed - apt-get -y upgrade --no-install-recommends - apt-get autoremove -y -fi - -# Ensure at least the en_US.UTF-8 UTF-8 locale is available. -# Common need for both applications and things like the agnoster ZSH theme. -if [ "${LOCALE_ALREADY_SET}" != "true" ] && ! grep -o -E '^\s*en_US.UTF-8\s+UTF-8' /etc/locale.gen > /dev/null; then - echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen - locale-gen - LOCALE_ALREADY_SET="true" -fi - -# Create or update a non-root user to match UID/GID. -group_name="${USERNAME}" -if id -u ${USERNAME} > /dev/null 2>&1; then - # User exists, update if needed - if [ "${USER_GID}" != "automatic" ] && [ "$USER_GID" != "$(id -g $USERNAME)" ]; then - group_name="$(id -gn $USERNAME)" - groupmod --gid $USER_GID ${group_name} - usermod --gid $USER_GID $USERNAME - fi - if [ "${USER_UID}" != "automatic" ] && [ "$USER_UID" != "$(id -u $USERNAME)" ]; then - usermod --uid $USER_UID $USERNAME - fi -else - # Create user - if [ "${USER_GID}" = "automatic" ]; then - groupadd $USERNAME - else - groupadd --gid $USER_GID $USERNAME - fi - if [ "${USER_UID}" = "automatic" ]; then - useradd -s /bin/bash --gid $USERNAME -m $USERNAME - else - useradd -s /bin/bash --uid $USER_UID --gid $USERNAME -m $USERNAME - fi -fi - -# Add sudo support for non-root user -if [ "${USERNAME}" != "root" ] && [ "${EXISTING_NON_ROOT_USER}" != "${USERNAME}" ]; then - echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME - chmod 0440 /etc/sudoers.d/$USERNAME - EXISTING_NON_ROOT_USER="${USERNAME}" -fi - -# ** Shell customization section ** -if [ "${USERNAME}" = "root" ]; then - user_rc_path="/root" -else - user_rc_path="/home/${USERNAME}" -fi - -# Restore user .bashrc defaults from skeleton file if it doesn't exist or is empty -if [ ! -f "${user_rc_path}/.bashrc" ] || [ ! -s "${user_rc_path}/.bashrc" ] ; then - cp /etc/skel/.bashrc "${user_rc_path}/.bashrc" -fi - -# Restore user .profile defaults from skeleton file if it doesn't exist or is empty -if [ ! -f "${user_rc_path}/.profile" ] || [ ! -s "${user_rc_path}/.profile" ] ; then - cp /etc/skel/.profile "${user_rc_path}/.profile" -fi - -# .bashrc/.zshrc snippet -rc_snippet="$(cat << 'EOF' - -if [ -z "${USER}" ]; then export USER=$(whoami); fi -if [[ "${PATH}" != *"$HOME/.local/bin"* ]]; then export PATH="${PATH}:$HOME/.local/bin"; fi - -# Display optional first run image specific notice if configured and terminal is interactive -if [ -t 1 ] && [[ "${TERM_PROGRAM}" = "vscode" || "${TERM_PROGRAM}" = "codespaces" ]] && [ ! -f "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed" ]; then - if [ -f "/usr/local/etc/vscode-dev-containers/first-run-notice.txt" ]; then - cat "/usr/local/etc/vscode-dev-containers/first-run-notice.txt" - elif [ -f "/workspaces/.codespaces/shared/first-run-notice.txt" ]; then - cat "/workspaces/.codespaces/shared/first-run-notice.txt" - fi - mkdir -p "$HOME/.config/vscode-dev-containers" - # Mark first run notice as displayed after 10s to avoid problems with fast terminal refreshes hiding it - ((sleep 10s; touch "$HOME/.config/vscode-dev-containers/first-run-notice-already-displayed") &) -fi - -# Set the default git editor if not already set -if [ -z "$(git config --get core.editor)" ] && [ -z "${GIT_EDITOR}" ]; then - if [ "${TERM_PROGRAM}" = "vscode" ]; then - if [[ -n $(command -v code-insiders) && -z $(command -v code) ]]; then - export GIT_EDITOR="code-insiders --wait" - else - export GIT_EDITOR="code --wait" - fi - fi -fi - -EOF -)" - -# code shim, it fallbacks to code-insiders if code is not available -cat << 'EOF' > /usr/local/bin/code -#!/bin/sh - -get_in_path_except_current() { - which -a "$1" | grep -A1 "$0" | grep -v "$0" -} - -code="$(get_in_path_except_current code)" - -if [ -n "$code" ]; then - exec "$code" "$@" -elif [ "$(command -v code-insiders)" ]; then - exec code-insiders "$@" -else - echo "code or code-insiders is not installed" >&2 - exit 127 -fi -EOF -chmod +x /usr/local/bin/code - -# systemctl shim - tells people to use 'service' if systemd is not running -cat << 'EOF' > /usr/local/bin/systemctl -#!/bin/sh -set -e -if [ -d "/run/systemd/system" ]; then - exec /bin/systemctl "$@" -else - echo '\n"systemd" is not running in this container due to its overhead.\nUse the "service" command to start services instead. e.g.: \n\nservice --status-all' -fi -EOF -chmod +x /usr/local/bin/systemctl - -# Codespaces bash and OMZ themes - partly inspired by https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/robbyrussell.zsh-theme -codespaces_bash="$(cat \ -<<'EOF' - -# Codespaces bash prompt theme -__bash_prompt() { - local userpart='`export XIT=$? \ - && [ ! -z "${GITHUB_USER}" ] && echo -n "\[\033[0;32m\]@${GITHUB_USER} " || echo -n "\[\033[0;32m\]\u " \ - && [ "$XIT" -ne "0" ] && echo -n "\[\033[1;31m\]➜" || echo -n "\[\033[0m\]➜"`' - local gitbranch='`\ - if [ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ]; then \ - export BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || git rev-parse --short HEAD 2>/dev/null); \ - if [ "${BRANCH}" != "" ]; then \ - echo -n "\[\033[0;36m\](\[\033[1;31m\]${BRANCH}" \ - && if git ls-files --error-unmatch -m --directory --no-empty-directory -o --exclude-standard ":/*" > /dev/null 2>&1; then \ - echo -n " \[\033[1;33m\]✗"; \ - fi \ - && echo -n "\[\033[0;36m\]) "; \ - fi; \ - fi`' - local lightblue='\[\033[1;34m\]' - local removecolor='\[\033[0m\]' - PS1="${userpart} ${lightblue}\w ${gitbranch}${removecolor}\$ " - unset -f __bash_prompt -} -__bash_prompt - -EOF -)" - -codespaces_zsh="$(cat \ -<<'EOF' -# Codespaces zsh prompt theme -__zsh_prompt() { - local prompt_username - if [ ! -z "${GITHUB_USER}" ]; then - prompt_username="@${GITHUB_USER}" - else - prompt_username="%n" - fi - PROMPT="%{$fg[green]%}${prompt_username} %(?:%{$reset_color%}➜ :%{$fg_bold[red]%}➜ )" # User/exit code arrow - PROMPT+='%{$fg_bold[blue]%}%(5~|%-1~/…/%3~|%4~)%{$reset_color%} ' # cwd - PROMPT+='$([ "$(git config --get codespaces-theme.hide-status 2>/dev/null)" != 1 ] && git_prompt_info)' # Git status - PROMPT+='%{$fg[white]%}$ %{$reset_color%}' - unset -f __zsh_prompt -} -ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_bold[cyan]%}(%{$fg_bold[red]%}" -ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%} " -ZSH_THEME_GIT_PROMPT_DIRTY=" %{$fg_bold[yellow]%}✗%{$fg_bold[cyan]%})" -ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg_bold[cyan]%})" -__zsh_prompt - -EOF -)" - -# Add RC snippet and custom bash prompt -if [ "${RC_SNIPPET_ALREADY_ADDED}" != "true" ]; then - echo "${rc_snippet}" >> /etc/bash.bashrc - echo "${codespaces_bash}" >> "${user_rc_path}/.bashrc" - echo 'export PROMPT_DIRTRIM=4' >> "${user_rc_path}/.bashrc" - if [ "${USERNAME}" != "root" ]; then - echo "${codespaces_bash}" >> "/root/.bashrc" - echo 'export PROMPT_DIRTRIM=4' >> "/root/.bashrc" - fi - chown ${USERNAME}:${group_name} "${user_rc_path}/.bashrc" - RC_SNIPPET_ALREADY_ADDED="true" -fi - -# Optionally install and configure zsh and Oh My Zsh! -if [ "${INSTALL_ZSH}" = "true" ]; then - if ! type zsh > /dev/null 2>&1; then - apt_get_update_if_needed - apt-get install -y zsh - fi - if [ "${ZSH_ALREADY_INSTALLED}" != "true" ]; then - echo "${rc_snippet}" >> /etc/zsh/zshrc - ZSH_ALREADY_INSTALLED="true" - fi - - # Adapted, simplified inline Oh My Zsh! install steps that adds, defaults to a codespaces theme. - # See https://github.com/ohmyzsh/ohmyzsh/blob/master/tools/install.sh for official script. - oh_my_install_dir="${user_rc_path}/.oh-my-zsh" - if [ ! -d "${oh_my_install_dir}" ] && [ "${INSTALL_OH_MYS}" = "true" ]; then - template_path="${oh_my_install_dir}/templates/zshrc.zsh-template" - user_rc_file="${user_rc_path}/.zshrc" - umask g-w,o-w - mkdir -p ${oh_my_install_dir} - git clone --depth=1 \ - -c core.eol=lf \ - -c core.autocrlf=false \ - -c fsck.zeroPaddedFilemode=ignore \ - -c fetch.fsck.zeroPaddedFilemode=ignore \ - -c receive.fsck.zeroPaddedFilemode=ignore \ - "https://github.com/ohmyzsh/ohmyzsh" "${oh_my_install_dir}" 2>&1 - echo -e "$(cat "${template_path}")\nDISABLE_AUTO_UPDATE=true\nDISABLE_UPDATE_PROMPT=true" > ${user_rc_file} - sed -i -e 's/ZSH_THEME=.*/ZSH_THEME="codespaces"/g' ${user_rc_file} - - mkdir -p ${oh_my_install_dir}/custom/themes - echo "${codespaces_zsh}" > "${oh_my_install_dir}/custom/themes/codespaces.zsh-theme" - # Shrink git while still enabling updates - cd "${oh_my_install_dir}" - git repack -a -d -f --depth=1 --window=1 - # Copy to non-root user if one is specified - if [ "${USERNAME}" != "root" ]; then - cp -rf "${user_rc_file}" "${oh_my_install_dir}" /root - chown -R ${USERNAME}:${group_name} "${user_rc_path}" - fi - fi -fi - -# Persist image metadata info, script if meta.env found in same directory -meta_info_script="$(cat << 'EOF' -#!/bin/sh -. /usr/local/etc/vscode-dev-containers/meta.env - -# Minimal output -if [ "$1" = "version" ] || [ "$1" = "image-version" ]; then - echo "${VERSION}" - exit 0 -elif [ "$1" = "release" ]; then - echo "${GIT_REPOSITORY_RELEASE}" - exit 0 -elif [ "$1" = "content" ] || [ "$1" = "content-url" ] || [ "$1" = "contents" ] || [ "$1" = "contents-url" ]; then - echo "${CONTENTS_URL}" - exit 0 -fi - -#Full output -echo -echo "Development container image information" -echo -if [ ! -z "${VERSION}" ]; then echo "- Image version: ${VERSION}"; fi -if [ ! -z "${DEFINITION_ID}" ]; then echo "- Definition ID: ${DEFINITION_ID}"; fi -if [ ! -z "${VARIANT}" ]; then echo "- Variant: ${VARIANT}"; fi -if [ ! -z "${GIT_REPOSITORY}" ]; then echo "- Source code repository: ${GIT_REPOSITORY}"; fi -if [ ! -z "${GIT_REPOSITORY_RELEASE}" ]; then echo "- Source code release/branch: ${GIT_REPOSITORY_RELEASE}"; fi -if [ ! -z "${BUILD_TIMESTAMP}" ]; then echo "- Timestamp: ${BUILD_TIMESTAMP}"; fi -if [ ! -z "${CONTENTS_URL}" ]; then echo && echo "More info: ${CONTENTS_URL}"; fi -echo -EOF -)" -if [ -f "${SCRIPT_DIR}/meta.env" ]; then - mkdir -p /usr/local/etc/vscode-dev-containers/ - cp -f "${SCRIPT_DIR}/meta.env" /usr/local/etc/vscode-dev-containers/meta.env - echo "${meta_info_script}" > /usr/local/bin/devcontainer-info - chmod +x /usr/local/bin/devcontainer-info -fi - -# Write marker file -mkdir -p "$(dirname "${MARKER_FILE}")" -echo -e "\ - PACKAGES_ALREADY_INSTALLED=${PACKAGES_ALREADY_INSTALLED}\n\ - LOCALE_ALREADY_SET=${LOCALE_ALREADY_SET}\n\ - EXISTING_NON_ROOT_USER=${EXISTING_NON_ROOT_USER}\n\ - RC_SNIPPET_ALREADY_ADDED=${RC_SNIPPET_ALREADY_ADDED}\n\ - ZSH_ALREADY_INSTALLED=${ZSH_ALREADY_INSTALLED}" > "${MARKER_FILE}" - -echo "Done!" diff --git a/src/dotnet/.devcontainer/library-scripts/meta.env b/src/dotnet/.devcontainer/library-scripts/meta.env deleted file mode 100644 index 9e54336..0000000 --- a/src/dotnet/.devcontainer/library-scripts/meta.env +++ /dev/null @@ -1 +0,0 @@ -VERSION='dev' diff --git a/src/dotnet/.devcontainer/library-scripts/node-debian.sh b/src/dotnet/.devcontainer/library-scripts/node-debian.sh deleted file mode 100755 index c355168..0000000 --- a/src/dotnet/.devcontainer/library-scripts/node-debian.sh +++ /dev/null @@ -1,169 +0,0 @@ -#!/bin/bash -#------------------------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# 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/node.md -# Maintainer: The VS Code and Codespaces Teams -# -# Syntax: ./node-debian.sh [directory to install nvm] [node version to install (use "none" to skip)] [non-root user] [Update rc files flag] [install node-gyp deps] - -export NVM_DIR=${1:-"/usr/local/share/nvm"} -export NODE_VERSION=${2:-"lts"} -USERNAME=${3:-"automatic"} -UPDATE_RC=${4:-"true"} -INSTALL_TOOLS_FOR_NODE_GYP="${5:-true}" -export NVM_VERSION="0.38.0" - -set -e - -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 - -# 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 - -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 -} - -# Function to run apt-get if needed -apt_get_update_if_needed() -{ - if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then - echo "Running apt-get update..." - apt-get update - else - echo "Skipping apt-get update." - fi -} - -# Checks if packages are installed and installs them if not -check_packages() { - if ! dpkg -s "$@" > /dev/null 2>&1; then - apt_get_update_if_needed - apt-get -y install --no-install-recommends "$@" - fi -} - -# Ensure apt is in non-interactive to avoid prompts -export DEBIAN_FRONTEND=noninteractive - -# Install dependencies -check_packages apt-transport-https curl ca-certificates tar gnupg2 dirmngr - -# Install yarn -if type yarn > /dev/null 2>&1; then - echo "Yarn already installed." -else - # Import key safely (new method rather than deprecated apt-key approach) and install - curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor > /usr/share/keyrings/yarn-archive-keyring.gpg - echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/yarn-archive-keyring.gpg] https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list - apt-get update - apt-get -y install --no-install-recommends yarn -fi - -# Adjust node version if required -if [ "${NODE_VERSION}" = "none" ]; then - export NODE_VERSION= -elif [ "${NODE_VERSION}" = "lts" ]; then - export NODE_VERSION="lts/*" -fi - -# Create a symlink to the installed version for use in Dockerfile PATH statements -export NVM_SYMLINK_CURRENT=true - -# Install the specified node version if NVM directory already exists, then exit -if [ -d "${NVM_DIR}" ]; then - echo "NVM already installed." - if [ "${NODE_VERSION}" != "" ]; then - su ${USERNAME} -c ". $NVM_DIR/nvm.sh && nvm install ${NODE_VERSION} && nvm clear-cache" - fi - exit 0 -fi - -# Create nvm group, nvm dir, and set sticky bit -if ! cat /etc/group | grep -e "^nvm:" > /dev/null 2>&1; then - groupadd -r nvm -fi -umask 0002 -usermod -a -G nvm ${USERNAME} -mkdir -p ${NVM_DIR} -chown :nvm ${NVM_DIR} -chmod g+s ${NVM_DIR} -su ${USERNAME} -c "$(cat << EOF - set -e - umask 0002 - # Do not update profile - we'll do this manually - export PROFILE=/dev/null - curl -so- https://raw.githubusercontent.com/nvm-sh/nvm/v${NVM_VERSION}/install.sh | bash - source ${NVM_DIR}/nvm.sh - if [ "${NODE_VERSION}" != "" ]; then - nvm alias default ${NODE_VERSION} - fi - nvm clear-cache -EOF -)" 2>&1 -# Update rc files -if [ "${UPDATE_RC}" = "true" ]; then -updaterc "$(cat < /dev/null 2>&1; then - to_install="${to_install} make" - fi - if ! type gcc > /dev/null 2>&1; then - to_install="${to_install} gcc" - fi - if ! type g++ > /dev/null 2>&1; then - to_install="${to_install} g++" - fi - if ! type python3 > /dev/null 2>&1; then - to_install="${to_install} python3-minimal" - fi - if [ ! -z "${to_install}" ]; then - apt_get_update_if_needed - apt-get -y install ${to_install} - fi -fi - -echo "Done!" diff --git a/src/dotnet/devcontainer-template.json b/src/dotnet/devcontainer-template.json new file mode 100644 index 0000000..744ca64 --- /dev/null +++ b/src/dotnet/devcontainer-template.json @@ -0,0 +1,49 @@ +{ + "id": "dotnet", + "version": "1.0.0", + "name": "C# (.NET)", + "description": "Develop C# and .NET based applications. Includes all needed SDKs, extensions, and dependencies.", + "documentationURL": "https://github.com/devcontainers/templates/tree/main/src/dotnet", + "publisher": "Dev Container Spec Maintainers", + "licenseURL": "https://github.com/devcontainers/templates/LICENSE", + "type": "image", + "options": { + "imageVariant": { + "type": "string", + "description": ".NET version:", + "proposals": [ + "6.0", + "3.1", + "6.0-bullseye", + "3.1-bullseye", + "6.0-focal", + "3.1-focal" + ], + "default": "6.0-bullseye", + "replaceIn": [ + ".devcontainer.json" + ] + }, + "nodeVersion": { + "type": "string", + "description": "Node.js version:", + "proposals": [ + "none", + "lts", + "latest", + "18", + "16", + "14" + ], + "default": "none", + "replaceIn": [ + ".devcontainer.json" + ] + } + }, + "platforms": [ + ".NET", + ".NET Core", + "C#" + ] +} \ No newline at end of file diff --git a/src/dotnet/manifest.json b/src/dotnet/manifest.json deleted file mode 100644 index 1d25481..0000000 --- a/src/dotnet/manifest.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "variants": ["6.0-bullseye-slim", "6.0-focal", "3.1-bullseye", "3.1-focal"], - "definitionVersion": "0.203.3", - "build": { - "latest": "6.0-bullseye-slim", - "rootDistro": "debian", - "tags": [ - "dotnet:${VERSION}-${VARIANT}" - ], - "architectures": { - "6.0-focal": ["linux/amd64"], - "6.0-bullseye-slim": ["linux/amd64", "linux/arm64"], - "3.1-focal": ["linux/amd64"], - "3.1-bullseye": ["linux/amd64", "linux/arm64"] - }, - "variantTags": { - "6.0-bullseye-slim": [ - "dotnet:${VERSION}-6.0", - "dotnet:${VERSION}-6.0-bullseye" - ], - "3.1-focal": [ - "dotnet:${VERSION}-3.1", - "dotnetcore:${VERSION}-3.1" - ], - "3.1-bullseye": [ - "dotnetcore:${VERSION}-3.1-bullseye" - ] - } - }, - "dependencies": { - "image": "mcr.microsoft.com/dotnet/sdk:${VARIANT}", - "imageLink": "https://hub.docker.com/_/microsoft-dotnet-sdk", - "apt": [{ - "cgIgnore": false, - "name":"yarn" - }], - "git": { - "Oh My Zsh!": "/home/vscode/.oh-my-zsh", - "nvm": "/usr/local/share/nvm" - }, - "languages": { - ".NET": { - "cgIgnore": true, - "versionCommand": "dotnet --version | grep -oE '[0-9]+\\.[0-9]+\\.[0-9]+' | tr -d '\\n' && echo \\\" (\\$(dotnet --info | grep -ozP 'Host.*:\\s*Version:\\s*\\K[0-9]\\.[0-9]\\.[0-9]' | tr '\\0' '\\n'))\\\"", - "path": "/usr", - "downloadUrl": "https://dotnet.microsoft.com/" - } - } - } -}