aspnetcore/build.sh

336 строки
11 KiB
Bash
Executable File

#!/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
lockfile_path="$DIR/korebuild-lock.txt"
config_file="$DIR/korebuild.json"
channel='master'
tools_source='https://aspnetcore.blob.core.windows.net/buildtools'
target_os_name=''
ci=false
run_restore=''
run_build=true
run_pack=false
run_tests=false
build_all=false
build_deps=true
build_managed=''
build_native=''
build_nodejs=''
build_java=''
build_projects=''
target_arch='x64'
if [ "$(uname)" = "Darwin" ]; then
target_os_name='osx'
else
target_os_name='linux'
fi
msbuild_args=()
#
# Functions
#
__usage() {
echo "Usage: $(basename "${BASH_SOURCE[0]}") [options] [[--] <Arguments>...]
Arguments:
<Arguments>... Arguments passed to the command. Variable number of arguments allowed.
Options:
--arch The CPU architecture to build for (x64, arm, arm64). Default=$target_arch
--os-name The base runtime identifier to build for (linux, osx, linux-musl). Default=$target_os_name
--[no-]restore Run restore.
--[no-]build Compile projects. (Implies --no-restore)
--[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\".
--no-build-deps Do not build project-to-project references and only build the specified project.
--all Build all project types.
--[no-]build-native Build native projects (C, C++).
--[no-]build-managed Build managed projects (C#, F#, VB).
--[no-]build-nodejs Build NodeJS projects (TypeScript, JS).
--[no-]build-java Build Java projects.
--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
;;
--arch)
shift
target_arch="${1:-}"
[ -z "$target_arch" ] && __error "Missing value for parameter --arch" && __usage
;;
--os-name)
shift
target_os_name="${1:-}"
[ -z "$target_os_name" ] && __error "Missing value for parameter --os-name" && __usage
;;
--restore|-[Rr]estore)
run_restore=true
;;
--no-restore)
run_restore=false
;;
--build|-[Bb]build)
run_build=true
;;
--no-build)
run_build=false
# --no-build implies --no-restore
[ -z "$run_restore" ] && run_restore=false
;;
--no-build-deps)
build_deps=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
;;
--build-managed|-BuildManaged)
build_managed=true
;;
--no-build-managed|-NoBuildManaged)
build_managed=false
;;
--build-nodejs|-BuildNodeJs)
build_nodejs=true
;;
--no-build-nodejs|-NoBuildNodeJs)
build_nodejs=false
;;
--build-java|-BuildJava)
build_java=true
;;
--no-build-java|-NoBuildJava)
build_java=false
;;
--build-native|-BuildNative)
build_native=true
;;
--no-build-native|-NoBuildNative)
build_native=false
;;
--ci|-[Cc][Ii])
ci=true
;;
--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
export DOTNET_HOME="$DIR/.dotnet"
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"
elif [ -z "$build_managed" ] && [ -z "$build_nodejs" ] && [ -z "$build_java" ] && [ -z "$build_native" ]; 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
if [ "$build_deps" = false ]; then
msbuild_args[${#msbuild_args[*]}]="-p:BuildProjectReferences=false"
fi
# Only set these MSBuild properties if they were explicitly set by build parameters.
[ ! -z "$build_java" ] && msbuild_args[${#msbuild_args[*]}]="-p:BuildJava=$build_java"
[ ! -z "$build_native" ] && msbuild_args[${#msbuild_args[*]}]="-p:BuildNative=$build_native"
[ ! -z "$build_nodejs" ] && msbuild_args[${#msbuild_args[*]}]="-p:BuildNodeJS=$build_nodejs"
[ ! -z "$build_managed" ] && msbuild_args[${#msbuild_args[*]}]="-p:BuildManaged=$build_managed"
# Run restore by default unless --no-restore or --no-build was specified.
[ -z "$run_restore" ] && run_restore=true
[ "$run_restore" = true ] && msbuild_args[${#msbuild_args[*]}]="-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"
msbuild_args[${#msbuild_args[*]}]="-p:TargetArchitecture=$target_arch"
msbuild_args[${#msbuild_args[*]}]="-p:TargetOsName=$target_os_name"
# 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
export KOREBUILD_KEEPGLOBALJSON=1
set_korebuildsettings "$tools_source" "$DOTNET_HOME" "$DIR" "$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[@]}"}