1#!/usr/local/bin/bash 2 3if [ "$1" == "-fromScript" ]; then 4 otherScript=$2 5 shift 2 6 echo Executed from $otherScript with arguments: $* 7fi 8 9build=false 10ci=false 11configuration="Debug" 12help=false 13nolog=false 14pack=false 15prepareMachine=false 16rebuild=false 17norestore=false 18sign=false 19skipTests=false 20bootstrapOnly=false 21verbosity="minimal" 22hostType="core" 23properties="" 24dotnetBuildFromSource=false 25dotnetCoreSdkDir="" 26 27function Help() { 28 echo "Common settings:" 29 echo " -configuration <value> Build configuration Debug, Release" 30 echo " -host <value> core (default), mono" 31 echo " -verbosity <value> Msbuild verbosity (q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic])" 32 echo " -help Print help and exit" 33 echo "" 34 echo "Actions:" 35 echo " -norestore Don't automatically run restore" 36 echo " -build Build solution" 37 echo " -rebuild Rebuild solution" 38 echo " -skipTests Don't run tests" 39 echo " -bootstrapOnly Don't run build again with bootstrapped MSBuild" 40 echo " -sign Sign build outputs" 41 echo " -pack Package build outputs into NuGet packages and Willow components" 42 echo "" 43 echo "Advanced settings:" 44 echo " -ci Set when running on CI server" 45 echo " -nolog Disable logging" 46 echo " -prepareMachine Prepare machine for CI run" 47 echo " -useSystemMSBuild [mono] Use system msbuild instead of downloading a copy for use with mono" 48 echo "" 49 echo "Command line arguments not listed above are passed through to MSBuild." 50} 51 52while [[ $# -gt 0 ]]; do 53 lowerI="$(echo $1 | awk '{print tolower($0)}')" 54 case $lowerI in 55 build) 56 build=true 57 shift 1 58 ;; 59 -build) 60 build=true 61 shift 1 62 ;; 63 -ci) 64 ci=true 65 shift 1 66 ;; 67 -configuration) 68 configuration=$2 69 shift 2 70 ;; 71 -h | -help) 72 Help 73 exit 0 74 ;; 75 -host) 76 hostType=$2 77 shift 2 78 ;; 79 -nolog) 80 nolog=true 81 shift 1 82 ;; 83 -pack) 84 pack=true 85 shift 1 86 ;; 87 -preparemachine) 88 prepareMachine=true 89 shift 1 90 ;; 91 -rebuild) 92 rebuild=true 93 shift 1 94 ;; 95 -norestore) 96 norestore=true 97 shift 1 98 ;; 99 -sign) 100 sign=true 101 shift 1 102 ;; 103 -skiptests) 104 skipTests=true 105 shift 1 106 ;; 107 -bootstraponly) 108 bootstrapOnly=true 109 shift 1 110 ;; 111 -usesystemmsbuild) 112 useSystemMSBuild=true 113 shift 1 114 ;; 115 -verbosity) 116 verbosity=$2 117 shift 2 118 ;; 119 -dotnetbuildfromsource) 120 dotnetBuildFromSource=true 121 shift 1 122 ;; 123 -dotnetcoresdkdir) 124 dotnetCoreSdkDir=$2 125 shift 2 126 ;; 127 *) 128 properties="$properties $1" 129 shift 1 130 ;; 131 esac 132done 133 134if [ "$hostType" = "mono" ]; then 135 configuration="$configuration-MONO" 136fi 137 138function KillProcessWithName { 139 echo "Killing processes containing \"$1\"" 140 kill $(ps ax | grep -i "$1" | awk '{ print $1 }') 141} 142 143function StopProcesses { 144 echo "Killing running build processes..." 145 KillProcessWithName "dotnet" 146 KillProcessWithName "vbcscompiler" 147} 148 149function ExitIfError { 150 if [ $1 != 0 ] 151 then 152 echo "$2" 153 154 if [[ "$ci" != "true" && "$dotnetBuildFromSource" != "true" && "$hostType" != "mono" ]]; # kill command not permitted on CI machines or in source-build 155 then 156 StopProcesses 157 fi 158 159 exit $1 160 fi 161} 162 163function CreateDirectory { 164 if [ ! -d "$1" ] 165 then 166 mkdir -p "$1" 167 fi 168} 169 170function QQ { 171 echo '"'$*'"' 172} 173 174function GetLogCmd { 175 if $ci || $log 176 then 177 CreateDirectory $LogDir 178 179 local logCmd="/bl:$(QQ $LogDir/$1.binlog)" 180 181 # When running under CI, also create a text log, so it can be viewed in the Jenkins UI 182 if $ci 183 then 184 logCmd="$logCmd /fl /flp:Verbosity=diag\;LogFile=$(QQ $LogDir/$1.log)" 185 fi 186 else 187 logCmd="" 188 fi 189 190 echo $logCmd 191} 192 193function downloadMSBuildForMono { 194 if [[ -z $useSystemMSBuild && ! -e "$MONO_MSBUILD_DIR/MSBuild.dll" ]] 195 then 196 echo "** Downloading MSBUILD from $MSBUILD_DOWNLOAD_URL" 197 curl -sL -o "$MSBUILD_ZIP" "$MSBUILD_DOWNLOAD_URL" 198 199 unzip -q "$MSBUILD_ZIP" -d "$ArtifactsDir" 200 # rename just to make it obvious when reading logs! 201 mv $ArtifactsDir/msbuild $ArtifactsDir/mono-msbuild 202 chmod +x $ArtifactsDir/mono-msbuild/MSBuild.dll 203 rm "$MSBUILD_ZIP" 204 fi 205} 206 207function CallMSBuild { 208 local commandLine="" 209 210 if [ -z "$msbuildHost" ] 211 then 212 commandLine="$msbuildToUse $*" 213 else 214 commandLine="$msbuildHost $msbuildToUse $*" 215 fi 216 217 echo ============= MSBuild command ============= 218 echo "$commandLine" 219 echo =========================================== 220 221 eval $commandLine 222 223 ExitIfError $? "Failed to run MSBuild: $commandLine" 224} 225 226function GetVersionsPropsVersion { 227 echo "$( awk -F'[<>]' "/<$1>/{print \$3}" "$VersionsProps" )" 228} 229 230function DownloadDotnetCli { 231 DotNetCliVersion="$( GetVersionsPropsVersion DotNetCliVersion )" 232 DotNetInstallVerbosity="" 233 234 if [ -z "$DOTNET_INSTALL_DIR" ] 235 then 236 export DOTNET_INSTALL_DIR="$RepoRoot/artifacts/.dotnet/$DotNetCliVersion" 237 fi 238 239 DotNetRoot=$DOTNET_INSTALL_DIR 240 DotNetInstallScript="$DotNetRoot/dotnet-install.sh" 241 242 if [ ! -a "$DotNetInstallScript" ] 243 then 244 CreateDirectory "$DotNetRoot" 245 curl "https://dot.net/v1/dotnet-install.sh" -sSL -o "$DotNetInstallScript" 246 fi 247 248 if [[ "$(echo $verbosity | awk '{print tolower($0)}')" == "diagnostic" ]] 249 then 250 DotNetInstallVerbosity="--verbose" 251 fi 252 253 # Install a stage 0 254 SdkInstallDir="$DotNetRoot/sdk/$DotNetCliVersion" 255 256 if [ ! -d "$SdkInstallDir" ] 257 then 258 bash "$DotNetInstallScript" --version $DotNetCliVersion $DotNetInstallVerbosity 259 LASTEXITCODE=$? 260 261 if [ $LASTEXITCODE != 0 ] 262 then 263 echo "Failed to install stage0" 264 return $LASTEXITCODE 265 fi 266 fi 267} 268 269function InstallDotNetCli { 270 if [ "$dotnetCoreSdkDir" = "" ] 271 then 272 DownloadDotnetCli 273 else 274 export DOTNET_INSTALL_DIR=$dotnetCoreSdkDir 275 fi 276 277 # don't double quote this otherwise the csc tooltask will fail with double double-quotting 278 export DOTNET_HOST_PATH="$DOTNET_INSTALL_DIR/dotnet" 279 280 # Put the stage 0 on the path 281 export PATH="$DOTNET_INSTALL_DIR:$PATH" 282 283 # Disable first run since we want to control all package sources 284 export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 285 286 # Don't resolve runtime, shared framework, or SDK from other locations 287 export DOTNET_MULTILEVEL_LOOKUP=0 288} 289 290function InstallRepoToolset { 291 RepoToolsetVersion="$( GetVersionsPropsVersion RoslynToolsRepoToolsetVersion )" 292 RepoToolsetDir="$NuGetPackageRoot/roslyntools.repotoolset/$RepoToolsetVersion/tools" 293 RepoToolsetBuildProj="$RepoToolsetDir/Build.proj" 294 295 local logCmd=$(GetLogCmd Toolset) 296 297 if [ ! -d "$RepoToolsetBuildProj" ] 298 then 299 ToolsetProj="$ScriptRoot/Toolset.proj" 300 CallMSBuild $(QQ $ToolsetProj) /t:restore /m /clp:Summary /warnaserror /v:$verbosity $logCmd $properties 301 fi 302} 303 304function ErrorHostType { 305 echo "Unsupported hostType ($hostType)" 306 exit 1 307} 308 309function Build { 310 if [ "$host" = "core" ]; then 311 InstallDotNetCli 312 echo "Using dotnet from: $DOTNET_INSTALL_DIR" 313 else 314 CreateDirectory $ArtifactsDir 315 fi 316 317 if $prepareMachine 318 then 319 CreateDirectory "$NuGetPackageRoot" 320 eval "$(QQ $DOTNET_HOST_PATH) nuget locals all --clear" 321 322 ExitIfError $? "Failed to clear NuGet cache" 323 fi 324 325 if [ "$hostType" = "core" ] 326 then 327 msbuildHost=$(QQ $DOTNET_HOST_PATH) 328 elif [ "$hostType" = "mono" ] 329 then 330 if [ -z $useSystemMSBuild ]; then 331 downloadMSBuildForMono 332 msbuildHost="" 333 msbuildToUse="$MONO_MSBUILD_DIR/msbuild" 334 else 335 msbuildHost="" 336 msbuildToUse="msbuild" 337 fi 338 else 339 ErrorHostType 340 fi 341 342 InstallRepoToolset 343 344 local logCmd=$(GetLogCmd Build) 345 346 commonMSBuildArgs="/m /clp:Summary /v:$verbosity /p:Configuration=$configuration /p:SolutionPath=$(QQ $MSBuildSolution) /p:CIBuild=$ci /p:DisableNerdbankVersioning=true" 347 348 # Only enable warnaserror on CI runs. 349 if $ci 350 then 351 commonMSBuildArgs="$commonMSBuildArgs /warnaserror" 352 fi 353 354 # Only test using stage 0 MSBuild if -bootstrapOnly is specified 355 local testStage0=false 356 if $bootstrapOnly 357 then 358 testStage0=$test 359 fi 360 361 CallMSBuild $(QQ $RepoToolsetBuildProj) $commonMSBuildArgs $logCmd /p:Restore=$restore /p:Build=$build /p:Rebuild=$rebuild /p:Test=$testStage0 /p:Sign=$sign /p:Pack=$pack /p:CreateBootstrap=true $properties 362 363 if ! $bootstrapOnly 364 then 365 bootstrapRoot="$ArtifactsConfigurationDir/bootstrap" 366 367 if [ $hostType = "core" ] 368 then 369 msbuildToUse=$(QQ "$bootstrapRoot/netcoreapp2.1/MSBuild/MSBuild.dll") 370 elif [ "$hostType" = "mono" ] 371 then 372 msbuildToUse="$bootstrapRoot/net461/MSBuild/15.0/Bin/MSBuild.dll" 373 msbuildHost="mono" 374 375 properties="$properties /p:MSBuildExtensionsPath=$bootstrapRoot/net461/MSBuild/" 376 else 377 ErrorHostType 378 fi 379 380 # forcing the slashes here or they get normalized and lost later 381 export ArtifactsDir="$ArtifactsDir\\2\\" 382 383 local logCmd=$(GetLogCmd BuildWithBootstrap) 384 385 # When using bootstrapped MSBuild: 386 # - Turn off node reuse (so that bootstrapped MSBuild processes don't stay running and lock files) 387 # - Don't sign 388 # - Don't pack 389 # - Do run tests (if not skipped) 390 # - Don't try to create a bootstrap deployment 391 CallMSBuild $(QQ $RepoToolsetBuildProj) $commonMSBuildArgs /nr:false $logCmd /p:Restore=$restore /p:Build=$build /p:Rebuild=$rebuild /p:Test=$test /p:Sign=false /p:Pack=false /p:CreateBootstrap=false $properties 392 fi 393} 394 395function AssertNugetPackages { 396 packageCount=$(find $PackagesDir -type f | wc -l) 397 if $pack || $dotnetBuildFromSource 398 then 399 400 if [ $packageCount -ne 5 ] 401 then 402 ExitIfError 1 "Did not find 5 packages in $PackagesDir" 403 fi 404 405 echo "Ensured that 5 nuget packages were created" 406 fi 407} 408 409SOURCE="${BASH_SOURCE[0]}" 410while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink 411 ScriptRoot="$( cd -P "$( dirname "$SOURCE" )" && pwd )" 412 SOURCE="$(readlink "$SOURCE")" 413 [[ $SOURCE != /* ]] && SOURCE="$ScriptRoot/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located 414done 415ScriptRoot="$( cd -P "$( dirname "$SOURCE" )" && pwd )" 416 417RepoRoot="$ScriptRoot/.." 418ArtifactsDir="$RepoRoot/artifacts" 419ArtifactsConfigurationDir="$ArtifactsDir/$configuration" 420PackagesDir="$ArtifactsConfigurationDir/packages" 421LogDir="$ArtifactsConfigurationDir/log" 422VersionsProps="$ScriptRoot/Versions.props" 423 424MONO_MSBUILD_DIR="$ArtifactsDir/mono-msbuild" 425MSBUILD_DOWNLOAD_URL="https://github.com/mono/msbuild/releases/download/v0.05/mono_msbuild_port2-394a6b5e.zip" 426MSBUILD_ZIP="$ArtifactsDir/msbuild.zip" 427 428#https://github.com/dotnet/source-build 429if $dotnetBuildFromSource 430then 431 MSBuildSolution="$RepoRoot/MSBuild.SourceBuild.sln" 432else 433 MSBuildSolution="$RepoRoot/MSBuild.sln" 434fi 435 436msbuildToUse="msbuild" 437 438log=false 439if ! $nolog 440then 441 log=true 442fi 443 444restore=false 445if ! $norestore 446then 447 restore=true 448fi 449 450test=false 451if ! $skipTests 452then 453 test=true 454fi 455 456if [ "$hostType" != "core" -a "$hostType" != "mono" ]; then 457 ErrorHostType 458fi 459 460# HOME may not be defined in some scenarios, but it is required by NuGet 461if [ -z $HOME ] 462then 463 export HOME="$RepoRoot/artifacts/.home/" 464 CreateDirectory "$HOME" 465fi 466 467if $ci 468then 469 TempDir="$ArtifactsConfigurationDir/tmp" 470 CreateDirectory "$TempDir" 471 472 export TEMP="$TempDir" 473 export TMP="$TempDir" 474 export MSBUILDDEBUGPATH="$TempDir" 475fi 476 477if [ -z $NUGET_PACKAGES ] 478then 479 export NUGET_PACKAGES="$HOME/.nuget/packages" 480fi 481 482NuGetPackageRoot=$NUGET_PACKAGES 483 484Build 485 486ExitIfError $? "Build failed" 487 488AssertNugetPackages 489 490ExitIfError $? "AssertNugetPackages failed" 491