dotnet-installer/eng/common/tools.sh

329 lines
9.1 KiB
Bash
Raw Normal View History

2018-12-19 20:55:42 +00:00
# Initialize variables if they aren't already defined.
# CI mode - set to true on CI server for PR validation build or official build.
2018-10-22 05:07:26 +00:00
ci=${ci:-false}
2018-12-19 20:55:42 +00:00
# Build configuration. Common values include 'Debug' and 'Release', but the repository may use other names.
2018-10-22 05:07:26 +00:00
configuration=${configuration:-'Debug'}
2018-12-19 20:55:42 +00:00
# Set to true to output binary log from msbuild. Note that emitting binary log slows down the build.
# Binary log must be enabled on CI.
binary_log=${binary_log:-$ci}
# Turns on machine preparation/clean up code that changes the machine state (e.g. kills build processes).
2018-10-22 05:07:26 +00:00
prepare_machine=${prepare_machine:-false}
2018-12-19 20:55:42 +00:00
# True to restore toolsets and dependencies.
2018-10-22 05:07:26 +00:00
restore=${restore:-true}
2018-12-19 20:55:42 +00:00
# Adjusts msbuild verbosity level.
2018-10-22 05:07:26 +00:00
verbosity=${verbosity:-'minimal'}
2018-12-19 20:55:42 +00:00
# Set to true to reuse msbuild nodes. Recommended to not reuse on CI.
if [[ "$ci" == true ]]; then
node_reuse=${node_reuse:-false}
else
node_reuse=${node_reuse:-true}
fi
2018-12-19 20:55:42 +00:00
# Configures warning treatment in msbuild.
warn_as_error=${warn_as_error:-true}
2018-10-22 05:07:26 +00:00
2018-12-19 20:55:42 +00:00
# True to attempt using .NET Core already that meets requirements specified in global.json
# installed on the machine instead of downloading one.
use_installed_dotnet_cli=${use_installed_dotnet_cli:-true}
# True to use global NuGet cache instead of restoring packages to repository-local directory.
if [[ "$ci" == true ]]; then
use_global_nuget_cache=${use_global_nuget_cache:-false}
else
use_global_nuget_cache=${use_global_nuget_cache:-true}
fi
2018-10-22 05:07:26 +00:00
2018-12-19 20:55:42 +00:00
# Resolve any symlinks in the given path.
2018-10-22 05:07:26 +00:00
function ResolvePath {
local path=$1
while [[ -h $path ]]; do
local dir="$( cd -P "$( dirname "$path" )" && pwd )"
path="$(readlink "$path")"
# if $path was a relative symlink, we need to resolve it relative to the path where the
# symlink file was located
[[ $path != /* ]] && path="$dir/$path"
done
# return value
_ResolvePath="$path"
}
# ReadVersionFromJson [json key]
function ReadGlobalVersion {
local key=$1
local line=`grep -m 1 "$key" "$global_json_file"`
local pattern="\"$key\" *: *\"(.*)\""
if [[ ! $line =~ $pattern ]]; then
echo "Error: Cannot find \"$key\" in $global_json_file" >&2
ExitWithExitCode 1
fi
# return value
_ReadGlobalVersion=${BASH_REMATCH[1]}
}
function InitializeDotNetCli {
2018-12-19 20:55:42 +00:00
if [[ -n "${_InitializeDotNetCli:-}" ]]; then
return
fi
2018-10-22 05:07:26 +00:00
local install=$1
# Don't resolve runtime, shared framework, or SDK from other locations to ensure build determinism
export DOTNET_MULTILEVEL_LOOKUP=0
# Disable first run since we want to control all package sources
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
2018-12-19 20:55:42 +00:00
# Disable telemetry on CI
if [[ $ci == true ]]; then
export DOTNET_CLI_TELEMETRY_OPTOUT=1
fi
# LTTNG is the logging infrastructure used by Core CLR. Need this variable set
# so it doesn't output warnings to the console.
export LTTNG_HOME="$HOME"
2018-10-22 05:07:26 +00:00
# Source Build uses DotNetCoreSdkDir variable
if [[ -n "${DotNetCoreSdkDir:-}" ]]; then
export DOTNET_INSTALL_DIR="$DotNetCoreSdkDir"
fi
# Find the first path on $PATH that contains the dotnet.exe
2018-12-19 20:55:42 +00:00
if [[ "$use_installed_dotnet_cli" == true && -z "${DOTNET_INSTALL_DIR:-}" ]]; then
2018-10-22 05:07:26 +00:00
local dotnet_path=`command -v dotnet`
if [[ -n "$dotnet_path" ]]; then
ResolvePath "$dotnet_path"
export DOTNET_INSTALL_DIR=`dirname "$_ResolvePath"`
fi
fi
ReadGlobalVersion "dotnet"
local dotnet_sdk_version=$_ReadGlobalVersion
local dotnet_root=""
# Use dotnet installation specified in DOTNET_INSTALL_DIR if it contains the required SDK version,
# otherwise install the dotnet CLI and SDK to repo local .dotnet directory to avoid potential permission issues.
if [[ -n "${DOTNET_INSTALL_DIR:-}" && -d "$DOTNET_INSTALL_DIR/sdk/$dotnet_sdk_version" ]]; then
dotnet_root="$DOTNET_INSTALL_DIR"
else
dotnet_root="$repo_root/.dotnet"
export DOTNET_INSTALL_DIR="$dotnet_root"
if [[ ! -d "$DOTNET_INSTALL_DIR/sdk/$dotnet_sdk_version" ]]; then
if [[ "$install" == true ]]; then
InstallDotNetSdk "$dotnet_root" "$dotnet_sdk_version"
else
echo "Unable to find dotnet with SDK version '$dotnet_sdk_version'" >&2
ExitWithExitCode 1
fi
fi
fi
2018-12-19 20:55:42 +00:00
# Add dotnet to PATH. This prevents any bare invocation of dotnet in custom
# build steps from using anything other than what we've downloaded.
export PATH="$dotnet_root:$PATH"
if [[ $ci == true ]]; then
# Make Sure that our bootstrapped dotnet cli is avaliable in future steps of the Azure Pipelines build
echo "##vso[task.prependpath]$dotnet_root"
echo "##vso[task.setvariable variable=DOTNET_MULTILEVEL_LOOKUP]0"
echo "##vso[task.setvariable variable=DOTNET_SKIP_FIRST_TIME_EXPERIENCE]1"
fi
2018-10-22 05:07:26 +00:00
# return value
_InitializeDotNetCli="$dotnet_root"
}
function InstallDotNetSdk {
local root=$1
local version=$2
GetDotNetInstallScript "$root"
local install_script=$_GetDotNetInstallScript
local arch_arg=""
if [[ $# == 3 ]]; then
arch_arg="--architecture $3"
fi
bash "$install_script" --version $version --install-dir "$root" $arch_arg || {
local exit_code=$?
echo "Failed to install dotnet SDK (exit code '$exit_code')." >&2
ExitWithExitCode $exit_code
}
2018-10-22 05:07:26 +00:00
}
function GetDotNetInstallScript {
local root=$1
local install_script="$root/dotnet-install.sh"
local install_script_url="https://dot.net/v1/dotnet-install.sh"
if [[ ! -a "$install_script" ]]; then
mkdir -p "$root"
echo "Downloading '$install_script_url'"
# Use curl if available, otherwise use wget
if command -v curl > /dev/null; then
curl "$install_script_url" -sSL --retry 10 --create-dirs -o "$install_script"
else
wget -q -O "$install_script" "$install_script_url"
fi
fi
# return value
_GetDotNetInstallScript="$install_script"
}
2018-12-19 20:55:42 +00:00
function InitializeBuildTool {
if [[ -n "${_InitializeBuildTool:-}" ]]; then
return
fi
InitializeDotNetCli $restore
# return values
2018-12-19 20:55:42 +00:00
_InitializeBuildTool="$_InitializeDotNetCli/dotnet"
_InitializeBuildToolCommand="msbuild"
2018-12-19 20:55:42 +00:00
}
function GetNuGetPackageCachePath {
if [[ -z ${NUGET_PACKAGES:-} ]]; then
if [[ "$use_global_nuget_cache" == true ]]; then
export NUGET_PACKAGES="$HOME/.nuget/packages"
else
export NUGET_PACKAGES="$repo_root/.packages"
fi
fi
# return value
_GetNuGetPackageCachePath=$NUGET_PACKAGES
}
2018-10-22 05:07:26 +00:00
function InitializeToolset {
2018-12-19 20:55:42 +00:00
if [[ -n "${_InitializeToolset:-}" ]]; then
return
fi
GetNuGetPackageCachePath
2018-10-22 05:07:26 +00:00
ReadGlobalVersion "Microsoft.DotNet.Arcade.Sdk"
local toolset_version=$_ReadGlobalVersion
local toolset_location_file="$toolset_dir/$toolset_version.txt"
if [[ -a "$toolset_location_file" ]]; then
local path=`cat "$toolset_location_file"`
if [[ -a "$path" ]]; then
2018-12-19 20:55:42 +00:00
# return value
_InitializeToolset="$path"
2018-10-22 05:07:26 +00:00
return
fi
fi
if [[ "$restore" != true ]]; then
echo "Toolset version $toolsetVersion has not been restored." >&2
ExitWithExitCode 2
fi
local proj="$toolset_dir/restore.proj"
local bl=""
if [[ "$binary_log" == true ]]; then
bl="/bl:$log_dir/ToolsetRestore.binlog"
fi
2018-10-22 05:07:26 +00:00
echo '<Project Sdk="Microsoft.DotNet.Arcade.Sdk"/>' > "$proj"
MSBuild "$proj" $bl /t:__WriteToolsetLocation /clp:ErrorsOnly\;NoSummary /p:__ToolsetLocationOutputFile="$toolset_location_file"
2018-10-22 05:07:26 +00:00
2018-12-19 20:55:42 +00:00
local toolset_build_proj=`cat "$toolset_location_file"`
2018-10-22 05:07:26 +00:00
if [[ ! -a "$toolset_build_proj" ]]; then
echo "Invalid toolset path: $toolset_build_proj" >&2
ExitWithExitCode 3
fi
2018-12-19 20:55:42 +00:00
# return value
_InitializeToolset="$toolset_build_proj"
2018-10-22 05:07:26 +00:00
}
function ExitWithExitCode {
if [[ "$ci" == true && "$prepare_machine" == true ]]; then
StopProcesses
fi
exit $1
}
function StopProcesses {
echo "Killing running build processes..."
pkill -9 "dotnet" || true
pkill -9 "vbcscompiler" || true
2018-10-22 05:07:26 +00:00
return 0
}
function MSBuild {
2018-12-19 20:55:42 +00:00
if [[ "$ci" == true ]]; then
if [[ "$binary_log" != true ]]; then
echo "Binary log must be enabled in CI build." >&2
ExitWithExitCode 1
fi
if [[ "$node_reuse" == true ]]; then
echo "Node reuse must be disabled in CI build." >&2
ExitWithExitCode 1
fi
fi
InitializeBuildTool
2018-10-22 05:07:26 +00:00
local warnaserror_switch=""
2018-12-19 20:55:42 +00:00
if [[ $warn_as_error == true ]]; then
2018-10-22 05:07:26 +00:00
warnaserror_switch="/warnaserror"
fi
"$_InitializeBuildTool" "$_InitializeBuildToolCommand" /m /nologo /clp:Summary /v:$verbosity /nr:$node_reuse $warnaserror_switch /p:TreatWarningsAsErrors=$warn_as_error "$@" || {
local exit_code=$?
echo "Build failed (exit code '$exit_code')." >&2
ExitWithExitCode $exit_code
}
2018-10-22 05:07:26 +00:00
}
2018-12-19 20:55:42 +00:00
ResolvePath "${BASH_SOURCE[0]}"
_script_dir=`dirname "$_ResolvePath"`
eng_root=`cd -P "$_script_dir/.." && pwd`
repo_root=`cd -P "$_script_dir/../.." && pwd`
artifacts_dir="$repo_root/artifacts"
toolset_dir="$artifacts_dir/toolset"
log_dir="$artifacts_dir/log/$configuration"
temp_dir="$artifacts_dir/tmp/$configuration"
global_json_file="$repo_root/global.json"
2018-10-22 05:07:26 +00:00
# HOME may not be defined in some scenarios, but it is required by NuGet
if [[ -z $HOME ]]; then
export HOME="$repo_root/artifacts/.home/"
mkdir -p "$HOME"
fi
mkdir -p "$toolset_dir"
2018-12-19 20:55:42 +00:00
mkdir -p "$temp_dir"
2018-10-22 05:07:26 +00:00
mkdir -p "$log_dir"
if [[ $ci == true ]]; then
export TEMP="$temp_dir"
export TMP="$temp_dir"
fi