#!/usr/bin/env bash set -euo pipefail # # variables # RESET="\033[0m" RED="\033[0;31m" YELLOW="\033[0;33m" MAGENTA="\033[0;95m" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" verbose=false update=false reinstall=false repo_path="$DIR" lockfile_path="$DIR/korebuild-lock.txt" config_file="$DIR/korebuild.json" channel='master' tools_source='https://aspnetcore.blob.core.windows.net/buildtools' ci=false run_restore=true run_build=true run_pack=false run_tests=false build_all=false build_managed=false build_nodejs=false build_projects='' msbuild_args=() # # Functions # __usage() { echo "Usage: $(basename "${BASH_SOURCE[0]}") [options] [[--] ...] Arguments: ... Arguments passed to the command. Variable number of arguments allowed. Options: --[no-]restore Run restore. --[no-]build Compile projects --[no-]pack Produce packages. --[no-]test Run tests. --projects A list of projects to build. (Must be an absolute path.) Globbing patterns are supported, such as \"$(pwd)/**/*.csproj\". --all Build all project types. --managed Build managed projects (C#, F#, VB). --nodejs Build NodeJS projects (TypeScript, JS). --ci Apply CI specific settings and environment variables. --verbose Show verbose output. Description: This build script installs required tools and runs an MSBuild command on this repository This script can be used to invoke various targets, such as targets to produce packages build projects, run tests, and generate code. " if [[ "${1:-}" != '--no-exit' ]]; then exit 2 fi } get_korebuild() { local version if [ ! -f "$lockfile_path" ]; then __get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" "$lockfile_path" fi version="$(grep 'version:*' -m 1 "$lockfile_path")" if [[ "$version" == '' ]]; then __error "Failed to parse version from $lockfile_path. Expected a line that begins with 'version:'" return 1 fi version="$(echo "${version#version:}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version" { if [ ! -d "$korebuild_path" ]; then mkdir -p "$korebuild_path" local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip" tmpfile="$(mktemp)" echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}" if __get_remote_file "$remote_path" "$tmpfile"; then unzip -q -d "$korebuild_path" "$tmpfile" fi rm "$tmpfile" || true fi source "$korebuild_path/KoreBuild.sh" } || { if [ -d "$korebuild_path" ]; then echo "Cleaning up after failed installation" rm -rf "$korebuild_path" || true fi return 1 } } __error() { echo -e "${RED}error: $*${RESET}" 1>&2 } __warn() { echo -e "${YELLOW}warning: $*${RESET}" } __machine_has() { hash "$1" > /dev/null 2>&1 return $? } __get_remote_file() { local remote_path=$1 local local_path=$2 if [[ "$remote_path" != 'http'* ]]; then cp "$remote_path" "$local_path" return 0 fi local failed=false if __machine_has wget; then wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true else failed=true fi if [ "$failed" = true ] && __machine_has curl; then failed=false curl --retry 10 -sSL -f --create-dirs -o "$local_path" "$remote_path" || failed=true fi if [ "$failed" = true ]; then __error "Download failed: $remote_path" 1>&2 return 1 fi } # # main # while [[ $# -gt 0 ]]; do case $1 in -\?|-h|--help) __usage --no-exit exit 0 ;; --repo-root|-RepoRoot) shift __warn '--repo-root is obsolete and will be removed when we finish https://github.com/aspnet/AspNetCore/issues/4246' repo_path="${1:-}" [ -z "$repo_path" ] && __error "Missing value for parameter --repo-root" && __usage ;; --restore|-[Rr]estore) run_restore=true ;; --no-restore) run_restore=false ;; --build|-[Bb]build) run_build=true ;; --no-build) run_build=false ;; --pack|-[Pp]ack) run_pack=true ;; --no-pack) run_pack=false ;; --test|-[Tt]est) run_tests=true ;; --no-test) run_tests=false ;; --projects|-[Pp]rojects) shift build_projects="${1:-}" [ -z "$build_projects" ] && __error "Missing value for parameter --projects" && __usage ;; --all|-[Aa]ll) build_all=true ;; --managed|-[Mm]anaged) build_managed=true ;; --nodejs|-[Nn]ode[Jj][Ss]) build_nodejs=true ;; --native|-[Nn]ative) __warn 'The C++ projects in this repo only build on Windows. The --native flag will be ignored.' ;; --ci|-[Cc][Ii]) ci=true if [[ -z "${DOTNET_HOME:-}" ]]; then DOTNET_HOME="$DIR/.dotnet" fi ;; --verbose|-[Vv]erbose) verbose=true ;; *) msbuild_args[${#msbuild_args[*]}]="$1" ;; esac shift done if ! __machine_has unzip; then __error 'Missing required command: unzip' exit 1 fi if ! __machine_has curl && ! __machine_has wget; then __error 'Missing required command. Either wget or curl is required.' exit 1 fi if [ -f "$config_file" ]; then if __machine_has jq ; then if jq '.' "$config_file" >/dev/null ; then config_channel="$(jq -r 'select(.channel!=null) | .channel' "$config_file")" config_tools_source="$(jq -r 'select(.toolsSource!=null) | .toolsSource' "$config_file")" else __error "$config_file is invalid JSON. Its settings will be ignored." exit 1 fi elif __machine_has python ; then if python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'))" >/dev/null ; then config_channel="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['channel'] if 'channel' in obj else '')")" config_tools_source="$(python -c "import json,codecs;obj=json.load(codecs.open('$config_file', 'r', 'utf-8-sig'));print(obj['toolsSource'] if 'toolsSource' in obj else '')")" else __error "$config_file is invalid JSON. Its settings will be ignored." exit 1 fi else __error 'Missing required command: jq or python. Could not parse the JSON file. Its settings will be ignored.' exit 1 fi [ ! -z "${config_channel:-}" ] && channel="$config_channel" [ ! -z "${config_tools_source:-}" ] && tools_source="$config_tools_source" fi [ -z "${DOTNET_HOME:-}" ] && DOTNET_HOME="$HOME/.dotnet" export DOTNET_HOME="$DOTNET_HOME" get_korebuild if [ "$build_all" = true ]; then msbuild_args[${#msbuild_args[*]}]="-p:BuildAllProjects=true" elif [ ! -z "$build_projects" ]; then msbuild_args[${#msbuild_args[*]}]="-p:Projects=$build_projects" else # When adding new sub-group build flags, add them to this check if [ "$build_managed" = false ] && [ "$build_nodejs" = false ]; then # This goal of this is to pick a sensible default for `build.sh` with zero arguments. # We believe the most common thing our contributors will work on is C#, so if no other build group was picked, build the C# projects. __warn "No default group of projects was specified, so building the 'managed' subset of projects. Run ``build.sh -help`` for more details." build_managed=true fi msbuild_args[${#msbuild_args[*]}]="-p:BuildManaged=$build_managed" msbuild_args[${#msbuild_args[*]}]="-p:BuildNodeJS=$build_nodejs" fi msbuild_args[${#msbuild_args[*]}]="-p:_RunRestore=$run_restore" msbuild_args[${#msbuild_args[*]}]="-p:_RunBuild=$run_build" msbuild_args[${#msbuild_args[*]}]="-p:_RunPack=$run_pack" msbuild_args[${#msbuild_args[*]}]="-p:_RunTests=$run_tests" # Disable downloading ref assemblies as a tarball. Use netfx refs from the Microsoft.NETFramework.ReferenceAssemblies NuGet package instead. [ -z "${KOREBUILD_SKIP_INSTALL_NETFX:-}" ] && KOREBUILD_SKIP_INSTALL_NETFX=1 set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$repo_path" "$config_file" "$ci" # This incantation avoids unbound variable issues if msbuild_args is empty # https://stackoverflow.com/questions/7577052/bash-empty-array-expansion-with-set-u invoke_korebuild_command 'default-build' ${msbuild_args[@]+"${msbuild_args[@]}"}