diff --git a/src/Microsoft.VisualStudio.Services.Agent/Constants.cs b/src/Microsoft.VisualStudio.Services.Agent/Constants.cs index f988fed4a7..54d869f777 100644 --- a/src/Microsoft.VisualStudio.Services.Agent/Constants.cs +++ b/src/Microsoft.VisualStudio.Services.Agent/Constants.cs @@ -38,7 +38,7 @@ public enum OSPlatform public static class Agent { - public static readonly string Version = "2.117.1"; + public static readonly string Version = "2.117.2"; #if OS_LINUX public static readonly OSPlatform Platform = OSPlatform.Linux; diff --git a/src/Misc/dotnet-install.ps1 b/src/Misc/dotnet-install.ps1 index 38787b5c42..85404535cc 100644 --- a/src/Misc/dotnet-install.ps1 +++ b/src/Misc/dotnet-install.ps1 @@ -10,14 +10,22 @@ Installs dotnet cli. If dotnet installation already exists in the given directory it will update it only if the requested version differs from the one already installed. .PARAMETER Channel - Default: release/1.0.0 - Download from the Channel specified + Default: LTS + Download from the Channel specified. Possible values: + - Current - most current release + - LTS - most current supported release + - 2-part version in a format A.B - represents a specific release + examples: 2.0; 1.0 + - Branch name + examples: release/2.0.0; Master .PARAMETER Version Default: latest Represents a build version on specific channel. Possible values: - latest - most latest build on specific channel + - coherent - most latest coherent build on specific channel + coherent applies only to SDK downloads - 3-part version in a format A.B.C - represents specific version of build - examples: 2.0.0-preview2-006120; 1.1.0 + examples: 2.0.0-preview2-006120; 1.1.0 .PARAMETER InstallDir Default: %LocalAppData%\Microsoft\dotnet Path to where to install dotnet. Note that binaries will be placed directly in a given directory. @@ -28,8 +36,6 @@ .PARAMETER SharedRuntime Default: false Installs just the shared runtime bits, not the entire SDK -.PARAMETER DebugSymbols - If set the installer will include symbols in the installation. .PARAMETER DryRun If set it will not perform installation but instead display what command line to use to consistently install currently requested version of dotnet cli. In example if you specify version 'latest' it will display a link @@ -55,12 +61,11 @@ #> [cmdletbinding()] param( - [string]$Channel="release/1.0.0", + [string]$Channel="LTS", [string]$Version="Latest", [string]$InstallDir="", [string]$Architecture="", [switch]$SharedRuntime, - [switch]$DebugSymbols, # TODO: Switch does not work yet. Symbols zip is not being uploaded yet. [switch]$DryRun, [switch]$NoPath, [string]$AzureFeed="https://dotnetcli.azureedge.net/dotnet", @@ -80,7 +85,7 @@ $VersionRegEx="/\d+\.\d+[^/]+/" $OverrideNonVersionedFiles=$true function Say($str) { - Write-Host "dotnet-install: $str" + Write-Output "dotnet-install: $str" } function Say-Verbose($str) { @@ -93,6 +98,25 @@ function Say-Invocation($Invocation) { Say-Verbose "$command $args" } +function Invoke-With-Retry([ScriptBlock]$ScriptBlock, [int]$MaxAttempts = 3, [int]$SecondsBetweenAttempts = 1) { + $Attempts = 0 + + while ($true) { + try { + return $ScriptBlock.Invoke() + } + catch { + $Attempts++ + if ($Attempts -lt $MaxAttempts) { + Start-Sleep $SecondsBetweenAttempts + } + else { + throw + } + } + } +} + function Get-Machine-Architecture() { Say-Invocation $MyInvocation @@ -135,56 +159,60 @@ function Load-Assembly([string] $Assembly) { function GetHTTPResponse([Uri] $Uri) { - $HttpClient = $null + Invoke-With-Retry( + { - try { - # HttpClient is used vs Invoke-WebRequest in order to support Nano Server which doesn't support the Invoke-WebRequest cmdlet. - Load-Assembly -Assembly System.Net.Http - - if(-not $ProxyAddress) - { - # Despite no proxy being explicitly specified, we may still be behind a default proxy - $DefaultProxy = [System.Net.WebRequest]::DefaultWebProxy; - if($DefaultProxy -and (-not $DefaultProxy.IsBypassed($Uri))){ - $ProxyAddress = $DefaultProxy.GetProxy($Uri).OriginalString - $ProxyUseDefaultCredentials = $true + $HttpClient = $null + + try { + # HttpClient is used vs Invoke-WebRequest in order to support Nano Server which doesn't support the Invoke-WebRequest cmdlet. + Load-Assembly -Assembly System.Net.Http + + if(-not $ProxyAddress) + { + # Despite no proxy being explicitly specified, we may still be behind a default proxy + $DefaultProxy = [System.Net.WebRequest]::DefaultWebProxy; + if($DefaultProxy -and (-not $DefaultProxy.IsBypassed($Uri))){ + $ProxyAddress = $DefaultProxy.GetProxy($Uri).OriginalString + $ProxyUseDefaultCredentials = $true + } } - } - if($ProxyAddress){ - $HttpClientHandler = New-Object System.Net.Http.HttpClientHandler - $HttpClientHandler.Proxy = New-Object System.Net.WebProxy -Property @{Address=$ProxyAddress;UseDefaultCredentials=$ProxyUseDefaultCredentials} - $HttpClient = New-Object System.Net.Http.HttpClient -ArgumentList $HttpClientHandler - } - else { - $HttpClient = New-Object System.Net.Http.HttpClient - } - # Default timeout for HttpClient is 100s. For a 50 MB download this assumes 500 KB/s average, any less will time out - # 10 minutes allows it to work over much slower connections. - $HttpClient.Timeout = New-TimeSpan -Minutes 10 - $Response = $HttpClient.GetAsync($Uri).Result - if (($Response -eq $null) -or (-not ($Response.IsSuccessStatusCode))) - { - $ErrorMsg = "Failed to download $Uri." - if ($Response -ne $null) + if($ProxyAddress){ + $HttpClientHandler = New-Object System.Net.Http.HttpClientHandler + $HttpClientHandler.Proxy = New-Object System.Net.WebProxy -Property @{Address=$ProxyAddress;UseDefaultCredentials=$ProxyUseDefaultCredentials} + $HttpClient = New-Object System.Net.Http.HttpClient -ArgumentList $HttpClientHandler + } + else { + $HttpClient = New-Object System.Net.Http.HttpClient + } + # Default timeout for HttpClient is 100s. For a 50 MB download this assumes 500 KB/s average, any less will time out + # 10 minutes allows it to work over much slower connections. + $HttpClient.Timeout = New-TimeSpan -Minutes 10 + $Response = $HttpClient.GetAsync($Uri).Result + if (($Response -eq $null) -or (-not ($Response.IsSuccessStatusCode))) { - $ErrorMsg += " $Response" + $ErrorMsg = "Failed to download $Uri." + if ($Response -ne $null) + { + $ErrorMsg += " $Response" + } + + throw $ErrorMsg } - throw $ErrorMsg + return $Response } - - return $Response - } - finally { - if ($HttpClient -ne $null) { - $HttpClient.Dispose() + finally { + if ($HttpClient -ne $null) { + $HttpClient.Dispose() + } } - } + }) } -function Get-Latest-Version-Info([string]$AzureFeed, [string]$Channel) { +function Get-Latest-Version-Info([string]$AzureFeed, [string]$Channel, [bool]$Coherent) { Say-Invocation $MyInvocation $VersionFileUrl = $null @@ -192,7 +220,12 @@ function Get-Latest-Version-Info([string]$AzureFeed, [string]$Channel) { $VersionFileUrl = "$UncachedFeed/Runtime/$Channel/latest.version" } else { - $VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.version" + if ($Coherent) { + $VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.coherent.version" + } + else { + $VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.version" + } } $Response = GetHTTPResponse -Uri $VersionFileUrl @@ -216,17 +249,34 @@ function Get-Specific-Version-From-Version([string]$AzureFeed, [string]$Channel, switch ($Version.ToLower()) { { $_ -eq "latest" } { - $LatestVersionInfo = Get-Latest-Version-Info -AzureFeed $AzureFeed -Channel $Channel + $LatestVersionInfo = Get-Latest-Version-Info -AzureFeed $AzureFeed -Channel $Channel -Coherent $False + return $LatestVersionInfo.Version + } + { $_ -eq "coherent" } { + $LatestVersionInfo = Get-Latest-Version-Info -AzureFeed $AzureFeed -Channel $Channel -Coherent $True return $LatestVersionInfo.Version } default { return $Version } } } -function Get-Download-Links([string]$AzureFeed, [string]$Channel, [string]$SpecificVersion, [string]$CLIArchitecture) { +function Get-Download-Link([string]$AzureFeed, [string]$Channel, [string]$SpecificVersion, [string]$CLIArchitecture) { Say-Invocation $MyInvocation - $ret = @() + if ($SharedRuntime) { + $PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/dotnet-runtime-$SpecificVersion-win-$CLIArchitecture.zip" + } + else { + $PayloadURL = "$AzureFeed/Sdk/$SpecificVersion/dotnet-sdk-$SpecificVersion-win-$CLIArchitecture.zip" + } + + Say-Verbose "Constructed primary payload URL: $PayloadURL" + + return $PayloadURL +} + +function Get-LegacyDownload-Link([string]$AzureFeed, [string]$Channel, [string]$SpecificVersion, [string]$CLIArchitecture) { + Say-Invocation $MyInvocation if ($SharedRuntime) { $PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/dotnet-win-$CLIArchitecture.$SpecificVersion.zip" @@ -235,10 +285,9 @@ function Get-Download-Links([string]$AzureFeed, [string]$Channel, [string]$Speci $PayloadURL = "$AzureFeed/Sdk/$SpecificVersion/dotnet-dev-win-$CLIArchitecture.$SpecificVersion.zip" } - Say-Verbose "Constructed payload URL: $PayloadURL" - $ret += $PayloadURL + Say-Verbose "Constructed legacy payload URL: $PayloadURL" - return $ret + return $PayloadURL } function Get-User-Share-Path() { @@ -396,13 +445,13 @@ function Prepend-Sdk-InstallRoot-To-Path([string]$InstallRoot, [string]$BinFolde $CLIArchitecture = Get-CLIArchitecture-From-Architecture $Architecture $SpecificVersion = Get-Specific-Version-From-Version -AzureFeed $AzureFeed -Channel $Channel -Version $Version -$DownloadLinks = Get-Download-Links -AzureFeed $AzureFeed -Channel $Channel -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture +$DownloadLink = Get-Download-Link -AzureFeed $AzureFeed -Channel $Channel -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture +$LegacyDownloadLink = Get-LegacyDownload-Link -AzureFeed $AzureFeed -Channel $Channel -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture if ($DryRun) { Say "Payload URLs:" - foreach ($DownloadLink in $DownloadLinks) { - Say "- $DownloadLink" - } + Say "Primary - $DownloadLink" + Say "Legacy - $LegacyDownloadLink" Say "Repeatable invocation: .\$($MyInvocation.MyCommand) -Version $SpecificVersion -Channel $Channel -Architecture $CLIArchitecture -InstallDir $InstallDir" exit 0 } @@ -420,22 +469,33 @@ if ($IsSdkInstalled) { New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null -$free = Get-CimInstance -Class win32_logicaldisk | where Deviceid -eq "$((Get-Item $InstallRoot).PSDrive.Name):" -if ($free.Freespace / 1MB -le 250 ) { - Say "there is not enough disk space on drive c:" +$installDrive = $((Get-Item $InstallRoot).PSDrive.Name); +Write-Output "${installDrive}:"; +$free = Get-CimInstance -Class win32_logicaldisk | where Deviceid -eq "${installDrive}:" +if ($free.Freespace / 1MB -le 100 ) { + Say "There is not enough disk space on drive ${installDrive}:" exit 0 } -foreach ($DownloadLink in $DownloadLinks) { +$ZipPath = [System.IO.Path]::GetTempFileName() +Say-Verbose "Zip path: $ZipPath" +Say "Downloading link: $DownloadLink" +try { + DownloadFile -Uri $DownloadLink -OutPath $ZipPath +} +catch { + Say "Cannot download: $DownloadLink" + $DownloadLink = $LegacyDownloadLink $ZipPath = [System.IO.Path]::GetTempFileName() - Say "Downloading $DownloadLink" + Say-Verbose "Legacy zip path: $ZipPath" + Say "Downloading legacy link: $DownloadLink" DownloadFile -Uri $DownloadLink -OutPath $ZipPath +} - Say "Extracting zip from $DownloadLink" - Extract-Dotnet-Package -ZipPath $ZipPath -OutPath $InstallRoot +Say "Extracting zip from $DownloadLink" +Extract-Dotnet-Package -ZipPath $ZipPath -OutPath $InstallRoot - Remove-Item $ZipPath -} +Remove-Item $ZipPath Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath diff --git a/src/Misc/dotnet-install.sh b/src/Misc/dotnet-install.sh index b251bfa891..12cf880f94 100644 --- a/src/Misc/dotnet-install.sh +++ b/src/Misc/dotnet-install.sh @@ -147,7 +147,7 @@ get_distro_specific_os_name() { fi fi - say_err "OS name could not be detected: $ID.$VERSION_ID" + say_verbose "Distribution specific OS name and version could not be detected: $ID.$VERSION_ID" return 1 } @@ -339,12 +339,17 @@ get_latest_version_info() { local azure_feed=$1 local channel=$2 local normalized_architecture=$3 + local coherent=$4 local version_file_url=null if [ "$shared_runtime" = true ]; then version_file_url="$uncached_feed/Runtime/$channel/latest.version" else - version_file_url="$uncached_feed/Sdk/$channel/latest.version" + if [ "$coherent" = true ]; then + version_file_url="$uncached_feed/Sdk/$channel/latest.coherent.version" + else + version_file_url="$uncached_feed/Sdk/$channel/latest.version" + fi fi say_verbose "get_latest_version_info: latest url: $version_file_url" @@ -368,7 +373,14 @@ get_specific_version_from_version() { case $version in latest) local version_info - version_info="$(get_latest_version_info $azure_feed $channel $normalized_architecture)" || return 1 + version_info="$(get_latest_version_info $azure_feed $channel $normalized_architecture false)" || return 1 + say_verbose "get_specific_version_from_version: version_info=$version_info" + echo "$version_info" | get_version_from_version_info + return 0 + ;; + coherent) + local version_info + version_info="$(get_latest_version_info $azure_feed $channel $normalized_architecture true)" || return 1 say_verbose "get_specific_version_from_version: version_info=$version_info" echo "$version_info" | get_version_from_version_info return 0 @@ -398,9 +410,9 @@ construct_download_link() { local download_link=null if [ "$shared_runtime" = true ]; then - download_link="$azure_feed/Runtime/$specific_version/dotnet-$osname-$normalized_architecture.$specific_version.tar.gz" + download_link="$azure_feed/Runtime/$specific_version/dotnet-runtime-$specific_version-$osname-$normalized_architecture.tar.gz" else - download_link="$azure_feed/Sdk/$specific_version/dotnet-dev-$osname-$normalized_architecture.$specific_version.tar.gz" + download_link="$azure_feed/Sdk/$specific_version/dotnet-sdk-$specific_version-$osname-$normalized_architecture.tar.gz" fi echo "$download_link" @@ -412,25 +424,25 @@ construct_download_link() { # channel - $2 # normalized_architecture - $3 # specific_version - $4 -construct_alt_download_link() { +construct_legacy_download_link() { eval $invocation local azure_feed=$1 local channel=$2 local normalized_architecture=$3 local specific_version=${4//[$'\t\r\n']} - + local distro_specific_osname distro_specific_osname=$(get_distro_specific_os_name) || return 1 - local alt_download_link=null + local legacy_download_link=null if [ "$shared_runtime" = true ]; then - alt_download_link="$azure_feed/Runtime/$specific_version/dotnet-$distro_specific_osname-$normalized_architecture.$specific_version.tar.gz" + legacy_download_link="$azure_feed/Runtime/$specific_version/dotnet-$distro_specific_osname-$normalized_architecture.$specific_version.tar.gz" else - alt_download_link="$azure_feed/Sdk/$specific_version/dotnet-dev-$distro_specific_osname-$normalized_architecture.$specific_version.tar.gz" + legacy_download_link="$azure_feed/Sdk/$specific_version/dotnet-dev-$distro_specific_osname-$normalized_architecture.$specific_version.tar.gz" fi - - echo "$alt_download_link" + + echo "$legacy_download_link" return 0 } @@ -601,7 +613,8 @@ downloadwget() { calculate_vars() { eval $invocation - + valid_legacy_download_link=true + normalized_architecture=$(get_normalized_architecture_from_architecture "$architecture") say_verbose "normalized_architecture=$normalized_architecture" @@ -615,9 +628,12 @@ calculate_vars() { download_link=$(construct_download_link $azure_feed $channel $normalized_architecture $specific_version) say_verbose "download_link=$download_link" - if [ "$(uname)" = "Linux" ]; then - alt_download_link=$(construct_alt_download_link $azure_feed $channel $normalized_architecture $specific_version) - say_verbose "alt_download_link=$alt_download_link" + legacy_download_link=$(construct_legacy_download_link $azure_feed $channel $normalized_architecture $specific_version) || valid_legacy_download_link=false + + if [ "$valid_legacy_download_link" = true ]; then + say_verbose "legacy_download_link=$legacy_download_link" + else + say_verbose "Cound not construct a legacy_download_link; omitting..." fi install_root=$(resolve_installation_path $install_dir) @@ -640,16 +656,17 @@ install_dotnet() { say "Downloading link: $download_link" download "$download_link" $zip_path || download_failed=true - # if the download fails, download the alt_download_link [Linux only] - if [ "$(uname)" = "Linux" ] && [ "$download_failed" = true ]; then + # if the download fails, download the legacy_download_link + if [ "$download_failed" = true ] && [ "$valid_legacy_download_link" = true ]; then say "Cannot download: $download_link" + download_link=$legacy_download_link zip_path=$(mktemp $temporary_file_template) - say_verbose "Alternate zip path: $zip_path" - say "Downloading alternate link: $alt_download_link" - download "$alt_download_link" $zip_path + say_verbose "Legacy zip path: $zip_path" + say "Downloading legacy link: $download_link" + download "$download_link" $zip_path fi - say "Extracting zip" + say "Extracting zip from $download_link" extract_dotnet_package $zip_path $install_root return 0 @@ -659,11 +676,10 @@ local_version_file_relative_path="/.version" bin_folder_relative_path="" temporary_file_template="${TMPDIR:-/tmp}/dotnet.XXXXXXXXX" -channel="release/1.0.0" +channel="LTS" version="Latest" install_dir="" architecture="" -debug_symbols=false dry_run=false no_path=false azure_feed="https://dotnetcli.azureedge.net/dotnet" @@ -695,9 +711,6 @@ do --shared-runtime|-[Ss]hared[Rr]untime) shared_runtime=true ;; - --debug-symbols|-[Dd]ebug[Ss]ymbols) - debug_symbols=true - ;; --dry-run|-[Dd]ry[Rr]un) dry_run=true ;; @@ -728,17 +741,29 @@ do echo "$script_name is a simple command line interface for obtaining dotnet cli." echo "" echo "Options:" - echo " -c,--channel Download from the CHANNEL specified (default: $channel)." + echo " -c,--channel Download from the CHANNEL specified, Defaults to \`$channel\`." echo " -Channel" - echo " -v,--version Use specific version, or \`latest\`. Defaults to \`latest\`." + echo " Possible values:" + echo " - Current - most current release" + echo " - LTS - most current supported release" + echo " - 2-part version in a format A.B - represents a specific release" + echo " examples: 2.0; 1.0" + echo " - Branch name" + echo " examples: release/2.0.0; Master" + echo " -v,--version Use specific VERSION, Defaults to \`$version\`." echo " -Version" + echo " Possible values:" + echo " - latest - most latest build on specific channel" + echo " - coherent - most latest coherent build on specific channel" + echo " coherent applies only to SDK downloads" + echo " - 3-part version in a format A.B.C - represents specific version of build" + echo " examples: 2.0.0-preview2-006120; 1.1.0" echo " -i,--install-dir Install under specified location (see Install Location below)" echo " -InstallDir" echo " --architecture Architecture of .NET Tools. Currently only x64 is supported." echo " --arch,-Architecture,-Arch" echo " --shared-runtime Installs just the shared runtime bits, not the entire SDK." echo " -SharedRuntime" - echo " --debug-symbols,-DebugSymbols Specifies if symbols should be included in the installation." echo " --dry-run,-DryRun Do not perform installation. Display download link." echo " --no-path, -NoPath Do not set PATH for the current process." echo " --verbose,-Verbose Display diagnostics information." @@ -766,10 +791,11 @@ done check_min_reqs calculate_vars + if [ "$dry_run" = true ]; then say "Payload URL: $download_link" - if [ "$(uname)" = "Linux" ]; then - say "Alternate payload URL: $alt_download_link" + if [ "$valid_legacy_download_link" = true ]; then + say "Legacy payload URL: $legacy_download_link" fi say "Repeatable invocation: ./$(basename $0) --version $specific_version --channel $channel --install-dir $install_dir" exit 0