committed by
GitHub
9 changed files with 52 additions and 1992 deletions
@ -1,774 +0,0 @@ |
|||||
# |
|
||||
# Copyright (c) .NET Foundation and contributors. All rights reserved. |
|
||||
# Licensed under the MIT license. See LICENSE file in the project root for full license information. |
|
||||
# |
|
||||
|
|
||||
# Copied from https://dot.net/v1/dotnet-install.ps1 on 8/26/2020 |
|
||||
|
|
||||
<# |
|
||||
.SYNOPSIS |
|
||||
Installs dotnet cli |
|
||||
.DESCRIPTION |
|
||||
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: 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 |
|
||||
Note: The version parameter overrides the channel parameter. |
|
||||
.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 |
|
||||
.PARAMETER InstallDir |
|
||||
Default: %LocalAppData%\Microsoft\dotnet |
|
||||
Path to where to install dotnet. Note that binaries will be placed directly in a given directory. |
|
||||
.PARAMETER Architecture |
|
||||
Default: <auto> - this value represents currently running OS architecture |
|
||||
Architecture of dotnet binaries to be installed. |
|
||||
Possible values are: <auto>, amd64, x64, x86, arm64, arm |
|
||||
.PARAMETER SharedRuntime |
|
||||
This parameter is obsolete and may be removed in a future version of this script. |
|
||||
The recommended alternative is '-Runtime dotnet'. |
|
||||
Installs just the shared runtime bits, not the entire SDK. |
|
||||
.PARAMETER Runtime |
|
||||
Installs just a shared runtime, not the entire SDK. |
|
||||
Possible values: |
|
||||
- dotnet - the Microsoft.NETCore.App shared runtime |
|
||||
- aspnetcore - the Microsoft.AspNetCore.App shared runtime |
|
||||
- windowsdesktop - the Microsoft.WindowsDesktop.App shared runtime |
|
||||
.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 |
|
||||
with specific version so that this command can be used deterministicly in a build script. |
|
||||
It also displays binaries location if you prefer to install or download it yourself. |
|
||||
.PARAMETER NoPath |
|
||||
By default this script will set environment variable PATH for the current process to the binaries folder inside installation folder. |
|
||||
If set it will display binaries location but not set any environment variable. |
|
||||
.PARAMETER Verbose |
|
||||
Displays diagnostics information. |
|
||||
.PARAMETER AzureFeed |
|
||||
Default: https://dotnetcli.azureedge.net/dotnet |
|
||||
This parameter typically is not changed by the user. |
|
||||
It allows changing the URL for the Azure feed used by this installer. |
|
||||
.PARAMETER UncachedFeed |
|
||||
This parameter typically is not changed by the user. |
|
||||
It allows changing the URL for the Uncached feed used by this installer. |
|
||||
.PARAMETER FeedCredential |
|
||||
Used as a query string to append to the Azure feed. |
|
||||
It allows changing the URL to use non-public blob storage accounts. |
|
||||
.PARAMETER ProxyAddress |
|
||||
If set, the installer will use the proxy when making web requests |
|
||||
.PARAMETER ProxyUseDefaultCredentials |
|
||||
Default: false |
|
||||
Use default credentials, when using proxy address. |
|
||||
.PARAMETER ProxyBypassList |
|
||||
If set with ProxyAddress, will provide the list of comma separated urls that will bypass the proxy |
|
||||
.PARAMETER SkipNonVersionedFiles |
|
||||
Default: false |
|
||||
Skips installing non-versioned files if they already exist, such as dotnet.exe. |
|
||||
.PARAMETER NoCdn |
|
||||
Disable downloading from the Azure CDN, and use the uncached feed directly. |
|
||||
.PARAMETER JSonFile |
|
||||
Determines the SDK version from a user specified global.json file |
|
||||
Note: global.json must have a value for 'SDK:Version' |
|
||||
#> |
|
||||
[cmdletbinding()] |
|
||||
param( |
|
||||
[string]$Channel="LTS", |
|
||||
[string]$Version="Latest", |
|
||||
[string]$JSonFile, |
|
||||
[string]$InstallDir="<auto>", |
|
||||
[string]$Architecture="<auto>", |
|
||||
[ValidateSet("dotnet", "aspnetcore", "windowsdesktop", IgnoreCase = $false)] |
|
||||
[string]$Runtime, |
|
||||
[Obsolete("This parameter may be removed in a future version of this script. The recommended alternative is '-Runtime dotnet'.")] |
|
||||
[switch]$SharedRuntime, |
|
||||
[switch]$DryRun, |
|
||||
[switch]$NoPath, |
|
||||
[string]$AzureFeed="https://dotnetcli.azureedge.net/dotnet", |
|
||||
[string]$UncachedFeed="https://dotnetcli.blob.core.windows.net/dotnet", |
|
||||
[string]$FeedCredential, |
|
||||
[string]$ProxyAddress, |
|
||||
[switch]$ProxyUseDefaultCredentials, |
|
||||
[string[]]$ProxyBypassList=@(), |
|
||||
[switch]$SkipNonVersionedFiles, |
|
||||
[switch]$NoCdn |
|
||||
) |
|
||||
|
|
||||
Set-StrictMode -Version Latest |
|
||||
$ErrorActionPreference="Stop" |
|
||||
$ProgressPreference="SilentlyContinue" |
|
||||
|
|
||||
if ($NoCdn) { |
|
||||
$AzureFeed = $UncachedFeed |
|
||||
} |
|
||||
|
|
||||
$BinFolderRelativePath="" |
|
||||
|
|
||||
if ($SharedRuntime -and (-not $Runtime)) { |
|
||||
$Runtime = "dotnet" |
|
||||
} |
|
||||
|
|
||||
# example path with regex: shared/1.0.0-beta-12345/somepath |
|
||||
$VersionRegEx="/\d+\.\d+[^/]+/" |
|
||||
$OverrideNonVersionedFiles = !$SkipNonVersionedFiles |
|
||||
|
|
||||
function Say($str) { |
|
||||
try |
|
||||
{ |
|
||||
Write-Host "dotnet-install: $str" |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
# Some platforms cannot utilize Write-Host (Azure Functions, for instance). Fall back to Write-Output |
|
||||
Write-Output "dotnet-install: $str" |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function Say-Verbose($str) { |
|
||||
try |
|
||||
{ |
|
||||
Write-Verbose "dotnet-install: $str" |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
# Some platforms cannot utilize Write-Verbose (Azure Functions, for instance). Fall back to Write-Output |
|
||||
Write-Output "dotnet-install: $str" |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function Say-Invocation($Invocation) { |
|
||||
$command = $Invocation.MyCommand; |
|
||||
$args = (($Invocation.BoundParameters.Keys | foreach { "-$_ `"$($Invocation.BoundParameters[$_])`"" }) -join " ") |
|
||||
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 |
|
||||
|
|
||||
# On PS x86, PROCESSOR_ARCHITECTURE reports x86 even on x64 systems. |
|
||||
# To get the correct architecture, we need to use PROCESSOR_ARCHITEW6432. |
|
||||
# PS x64 doesn't define this, so we fall back to PROCESSOR_ARCHITECTURE. |
|
||||
# Possible values: amd64, x64, x86, arm64, arm |
|
||||
|
|
||||
if( $ENV:PROCESSOR_ARCHITEW6432 -ne $null ) |
|
||||
{ |
|
||||
return $ENV:PROCESSOR_ARCHITEW6432 |
|
||||
} |
|
||||
|
|
||||
return $ENV:PROCESSOR_ARCHITECTURE |
|
||||
} |
|
||||
|
|
||||
function Get-CLIArchitecture-From-Architecture([string]$Architecture) { |
|
||||
Say-Invocation $MyInvocation |
|
||||
|
|
||||
switch ($Architecture.ToLower()) { |
|
||||
{ $_ -eq "<auto>" } { return Get-CLIArchitecture-From-Architecture $(Get-Machine-Architecture) } |
|
||||
{ ($_ -eq "amd64") -or ($_ -eq "x64") } { return "x64" } |
|
||||
{ $_ -eq "x86" } { return "x86" } |
|
||||
{ $_ -eq "arm" } { return "arm" } |
|
||||
{ $_ -eq "arm64" } { return "arm64" } |
|
||||
default { throw "Architecture not supported. If you think this is a bug, report it at https://github.com/dotnet/sdk/issues" } |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
# The version text returned from the feeds is a 1-line or 2-line string: |
|
||||
# For the SDK and the dotnet runtime (2 lines): |
|
||||
# Line 1: # commit_hash |
|
||||
# Line 2: # 4-part version |
|
||||
# For the aspnetcore runtime (1 line): |
|
||||
# Line 1: # 4-part version |
|
||||
function Get-Version-Info-From-Version-Text([string]$VersionText) { |
|
||||
Say-Invocation $MyInvocation |
|
||||
|
|
||||
$Data = -split $VersionText |
|
||||
|
|
||||
$VersionInfo = @{ |
|
||||
CommitHash = $(if ($Data.Count -gt 1) { $Data[0] }) |
|
||||
Version = $Data[-1] # last line is always the version number. |
|
||||
} |
|
||||
return $VersionInfo |
|
||||
} |
|
||||
|
|
||||
function Load-Assembly([string] $Assembly) { |
|
||||
try { |
|
||||
Add-Type -Assembly $Assembly | Out-Null |
|
||||
} |
|
||||
catch { |
|
||||
# On Nano Server, Powershell Core Edition is used. Add-Type is unable to resolve base class assemblies because they are not GAC'd. |
|
||||
# Loading the base class assemblies is not unnecessary as the types will automatically get resolved. |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function GetHTTPResponse([Uri] $Uri) |
|
||||
{ |
|
||||
Invoke-With-Retry( |
|
||||
{ |
|
||||
|
|
||||
$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) { |
|
||||
try { |
|
||||
# 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 |
|
||||
} |
|
||||
} catch { |
|
||||
# Eat the exception and move forward as the above code is an attempt |
|
||||
# at resolving the DefaultProxy that may not have been a problem. |
|
||||
$ProxyAddress = $null |
|
||||
Say-Verbose("Exception ignored: $_.Exception.Message - moving forward...") |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if($ProxyAddress) { |
|
||||
$HttpClientHandler = New-Object System.Net.Http.HttpClientHandler |
|
||||
$HttpClientHandler.Proxy = New-Object System.Net.WebProxy -Property @{ |
|
||||
Address=$ProxyAddress; |
|
||||
UseDefaultCredentials=$ProxyUseDefaultCredentials; |
|
||||
BypassList = $ProxyBypassList; |
|
||||
} |
|
||||
$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 |
|
||||
# 20 minutes allows it to work over much slower connections. |
|
||||
$HttpClient.Timeout = New-TimeSpan -Minutes 20 |
|
||||
$Response = $HttpClient.GetAsync("${Uri}${FeedCredential}").Result |
|
||||
if (($Response -eq $null) -or (-not ($Response.IsSuccessStatusCode))) { |
|
||||
# The feed credential is potentially sensitive info. Do not log FeedCredential to console output. |
|
||||
$ErrorMsg = "Failed to download $Uri." |
|
||||
if ($Response -ne $null) { |
|
||||
$ErrorMsg += " $Response" |
|
||||
} |
|
||||
|
|
||||
throw $ErrorMsg |
|
||||
} |
|
||||
|
|
||||
return $Response |
|
||||
} |
|
||||
finally { |
|
||||
if ($HttpClient -ne $null) { |
|
||||
$HttpClient.Dispose() |
|
||||
} |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
function Get-Latest-Version-Info([string]$AzureFeed, [string]$Channel, [bool]$Coherent) { |
|
||||
Say-Invocation $MyInvocation |
|
||||
|
|
||||
$VersionFileUrl = $null |
|
||||
if ($Runtime -eq "dotnet") { |
|
||||
$VersionFileUrl = "$UncachedFeed/Runtime/$Channel/latest.version" |
|
||||
} |
|
||||
elseif ($Runtime -eq "aspnetcore") { |
|
||||
$VersionFileUrl = "$UncachedFeed/aspnetcore/Runtime/$Channel/latest.version" |
|
||||
} |
|
||||
# Currently, the WindowsDesktop runtime is manufactured with the .Net core runtime |
|
||||
elseif ($Runtime -eq "windowsdesktop") { |
|
||||
$VersionFileUrl = "$UncachedFeed/Runtime/$Channel/latest.version" |
|
||||
} |
|
||||
elseif (-not $Runtime) { |
|
||||
if ($Coherent) { |
|
||||
$VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.coherent.version" |
|
||||
} |
|
||||
else { |
|
||||
$VersionFileUrl = "$UncachedFeed/Sdk/$Channel/latest.version" |
|
||||
} |
|
||||
} |
|
||||
else { |
|
||||
throw "Invalid value for `$Runtime" |
|
||||
} |
|
||||
try { |
|
||||
$Response = GetHTTPResponse -Uri $VersionFileUrl |
|
||||
} |
|
||||
catch { |
|
||||
throw "Could not resolve version information." |
|
||||
} |
|
||||
$StringContent = $Response.Content.ReadAsStringAsync().Result |
|
||||
|
|
||||
switch ($Response.Content.Headers.ContentType) { |
|
||||
{ ($_ -eq "application/octet-stream") } { $VersionText = $StringContent } |
|
||||
{ ($_ -eq "text/plain") } { $VersionText = $StringContent } |
|
||||
{ ($_ -eq "text/plain; charset=UTF-8") } { $VersionText = $StringContent } |
|
||||
default { throw "``$Response.Content.Headers.ContentType`` is an unknown .version file content type." } |
|
||||
} |
|
||||
|
|
||||
$VersionInfo = Get-Version-Info-From-Version-Text $VersionText |
|
||||
|
|
||||
return $VersionInfo |
|
||||
} |
|
||||
|
|
||||
function Parse-Jsonfile-For-Version([string]$JSonFile) { |
|
||||
Say-Invocation $MyInvocation |
|
||||
|
|
||||
If (-Not (Test-Path $JSonFile)) { |
|
||||
throw "Unable to find '$JSonFile'" |
|
||||
} |
|
||||
try { |
|
||||
$JSonContent = Get-Content($JSonFile) -Raw | ConvertFrom-Json | Select-Object -expand "sdk" -ErrorAction SilentlyContinue |
|
||||
} |
|
||||
catch { |
|
||||
throw "Json file unreadable: '$JSonFile'" |
|
||||
} |
|
||||
if ($JSonContent) { |
|
||||
try { |
|
||||
$JSonContent.PSObject.Properties | ForEach-Object { |
|
||||
$PropertyName = $_.Name |
|
||||
if ($PropertyName -eq "version") { |
|
||||
$Version = $_.Value |
|
||||
Say-Verbose "Version = $Version" |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
catch { |
|
||||
throw "Unable to parse the SDK node in '$JSonFile'" |
|
||||
} |
|
||||
} |
|
||||
else { |
|
||||
throw "Unable to find the SDK node in '$JSonFile'" |
|
||||
} |
|
||||
If ($Version -eq $null) { |
|
||||
throw "Unable to find the SDK:version node in '$JSonFile'" |
|
||||
} |
|
||||
return $Version |
|
||||
} |
|
||||
|
|
||||
function Get-Specific-Version-From-Version([string]$AzureFeed, [string]$Channel, [string]$Version, [string]$JSonFile) { |
|
||||
Say-Invocation $MyInvocation |
|
||||
|
|
||||
if (-not $JSonFile) { |
|
||||
switch ($Version.ToLower()) { |
|
||||
{ $_ -eq "latest" } { |
|
||||
$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 } |
|
||||
} |
|
||||
} |
|
||||
else { |
|
||||
return Parse-Jsonfile-For-Version $JSonFile |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function Get-Download-Link([string]$AzureFeed, [string]$SpecificVersion, [string]$CLIArchitecture) { |
|
||||
Say-Invocation $MyInvocation |
|
||||
|
|
||||
# If anything fails in this lookup it will default to $SpecificVersion |
|
||||
$SpecificProductVersion = Get-Product-Version -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion |
|
||||
|
|
||||
if ($Runtime -eq "dotnet") { |
|
||||
$PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/dotnet-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip" |
|
||||
} |
|
||||
elseif ($Runtime -eq "aspnetcore") { |
|
||||
$PayloadURL = "$AzureFeed/aspnetcore/Runtime/$SpecificVersion/aspnetcore-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip" |
|
||||
} |
|
||||
elseif ($Runtime -eq "windowsdesktop") { |
|
||||
$PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/windowsdesktop-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip" |
|
||||
} |
|
||||
elseif (-not $Runtime) { |
|
||||
$PayloadURL = "$AzureFeed/Sdk/$SpecificVersion/dotnet-sdk-$SpecificProductVersion-win-$CLIArchitecture.zip" |
|
||||
} |
|
||||
else { |
|
||||
throw "Invalid value for `$Runtime" |
|
||||
} |
|
||||
|
|
||||
Say-Verbose "Constructed primary named payload URL: $PayloadURL" |
|
||||
|
|
||||
return $PayloadURL, $SpecificProductVersion |
|
||||
} |
|
||||
|
|
||||
function Get-LegacyDownload-Link([string]$AzureFeed, [string]$SpecificVersion, [string]$CLIArchitecture) { |
|
||||
Say-Invocation $MyInvocation |
|
||||
|
|
||||
if (-not $Runtime) { |
|
||||
$PayloadURL = "$AzureFeed/Sdk/$SpecificVersion/dotnet-dev-win-$CLIArchitecture.$SpecificVersion.zip" |
|
||||
} |
|
||||
elseif ($Runtime -eq "dotnet") { |
|
||||
$PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/dotnet-win-$CLIArchitecture.$SpecificVersion.zip" |
|
||||
} |
|
||||
else { |
|
||||
return $null |
|
||||
} |
|
||||
|
|
||||
Say-Verbose "Constructed legacy named payload URL: $PayloadURL" |
|
||||
|
|
||||
return $PayloadURL |
|
||||
} |
|
||||
|
|
||||
function Get-Product-Version([string]$AzureFeed, [string]$SpecificVersion) { |
|
||||
Say-Invocation $MyInvocation |
|
||||
|
|
||||
if ($Runtime -eq "dotnet") { |
|
||||
$ProductVersionTxtURL = "$AzureFeed/Runtime/$SpecificVersion/productVersion.txt" |
|
||||
} |
|
||||
elseif ($Runtime -eq "aspnetcore") { |
|
||||
$ProductVersionTxtURL = "$AzureFeed/aspnetcore/Runtime/$SpecificVersion/productVersion.txt" |
|
||||
} |
|
||||
elseif ($Runtime -eq "windowsdesktop") { |
|
||||
$ProductVersionTxtURL = "$AzureFeed/Runtime/$SpecificVersion/productVersion.txt" |
|
||||
} |
|
||||
elseif (-not $Runtime) { |
|
||||
$ProductVersionTxtURL = "$AzureFeed/Sdk/$SpecificVersion/productVersion.txt" |
|
||||
} |
|
||||
else { |
|
||||
throw "Invalid value specified for `$Runtime" |
|
||||
} |
|
||||
|
|
||||
Say-Verbose "Checking for existence of $ProductVersionTxtURL" |
|
||||
|
|
||||
try { |
|
||||
$productVersionResponse = GetHTTPResponse($productVersionTxtUrl) |
|
||||
|
|
||||
if ($productVersionResponse.StatusCode -eq 200) { |
|
||||
$productVersion = $productVersionResponse.Content.ReadAsStringAsync().Result.Trim() |
|
||||
if ($productVersion -ne $SpecificVersion) |
|
||||
{ |
|
||||
Say "Using alternate version $productVersion found in $ProductVersionTxtURL" |
|
||||
} |
|
||||
|
|
||||
return $productVersion |
|
||||
} |
|
||||
else { |
|
||||
Say-Verbose "Got StatusCode $($productVersionResponse.StatusCode) trying to get productVersion.txt at $productVersionTxtUrl, so using default value of $SpecificVersion" |
|
||||
$productVersion = $SpecificVersion |
|
||||
} |
|
||||
} catch { |
|
||||
Say-Verbose "Could not read productVersion.txt at $productVersionTxtUrl, so using default value of $SpecificVersion" |
|
||||
$productVersion = $SpecificVersion |
|
||||
} |
|
||||
|
|
||||
return $productVersion |
|
||||
} |
|
||||
|
|
||||
function Get-User-Share-Path() { |
|
||||
Say-Invocation $MyInvocation |
|
||||
|
|
||||
$InstallRoot = $env:DOTNET_INSTALL_DIR |
|
||||
if (!$InstallRoot) { |
|
||||
$InstallRoot = "$env:LocalAppData\Microsoft\dotnet" |
|
||||
} |
|
||||
return $InstallRoot |
|
||||
} |
|
||||
|
|
||||
function Resolve-Installation-Path([string]$InstallDir) { |
|
||||
Say-Invocation $MyInvocation |
|
||||
|
|
||||
if ($InstallDir -eq "<auto>") { |
|
||||
return Get-User-Share-Path |
|
||||
} |
|
||||
return $InstallDir |
|
||||
} |
|
||||
|
|
||||
function Is-Dotnet-Package-Installed([string]$InstallRoot, [string]$RelativePathToPackage, [string]$SpecificVersion) { |
|
||||
Say-Invocation $MyInvocation |
|
||||
|
|
||||
$DotnetPackagePath = Join-Path -Path $InstallRoot -ChildPath $RelativePathToPackage | Join-Path -ChildPath $SpecificVersion |
|
||||
Say-Verbose "Is-Dotnet-Package-Installed: DotnetPackagePath=$DotnetPackagePath" |
|
||||
return Test-Path $DotnetPackagePath -PathType Container |
|
||||
} |
|
||||
|
|
||||
function Get-Absolute-Path([string]$RelativeOrAbsolutePath) { |
|
||||
# Too much spam |
|
||||
# Say-Invocation $MyInvocation |
|
||||
|
|
||||
return $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($RelativeOrAbsolutePath) |
|
||||
} |
|
||||
|
|
||||
function Get-Path-Prefix-With-Version($path) { |
|
||||
$match = [regex]::match($path, $VersionRegEx) |
|
||||
if ($match.Success) { |
|
||||
return $entry.FullName.Substring(0, $match.Index + $match.Length) |
|
||||
} |
|
||||
|
|
||||
return $null |
|
||||
} |
|
||||
|
|
||||
function Get-List-Of-Directories-And-Versions-To-Unpack-From-Dotnet-Package([System.IO.Compression.ZipArchive]$Zip, [string]$OutPath) { |
|
||||
Say-Invocation $MyInvocation |
|
||||
|
|
||||
$ret = @() |
|
||||
foreach ($entry in $Zip.Entries) { |
|
||||
$dir = Get-Path-Prefix-With-Version $entry.FullName |
|
||||
if ($dir -ne $null) { |
|
||||
$path = Get-Absolute-Path $(Join-Path -Path $OutPath -ChildPath $dir) |
|
||||
if (-Not (Test-Path $path -PathType Container)) { |
|
||||
$ret += $dir |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
$ret = $ret | Sort-Object | Get-Unique |
|
||||
|
|
||||
$values = ($ret | foreach { "$_" }) -join ";" |
|
||||
Say-Verbose "Directories to unpack: $values" |
|
||||
|
|
||||
return $ret |
|
||||
} |
|
||||
|
|
||||
# Example zip content and extraction algorithm: |
|
||||
# Rule: files if extracted are always being extracted to the same relative path locally |
|
||||
# .\ |
|
||||
# a.exe # file does not exist locally, extract |
|
||||
# b.dll # file exists locally, override only if $OverrideFiles set |
|
||||
# aaa\ # same rules as for files |
|
||||
# ... |
|
||||
# abc\1.0.0\ # directory contains version and exists locally |
|
||||
# ... # do not extract content under versioned part |
|
||||
# abc\asd\ # same rules as for files |
|
||||
# ... |
|
||||
# def\ghi\1.0.1\ # directory contains version and does not exist locally |
|
||||
# ... # extract content |
|
||||
function Extract-Dotnet-Package([string]$ZipPath, [string]$OutPath) { |
|
||||
Say-Invocation $MyInvocation |
|
||||
|
|
||||
Load-Assembly -Assembly System.IO.Compression.FileSystem |
|
||||
Set-Variable -Name Zip |
|
||||
try { |
|
||||
$Zip = [System.IO.Compression.ZipFile]::OpenRead($ZipPath) |
|
||||
|
|
||||
$DirectoriesToUnpack = Get-List-Of-Directories-And-Versions-To-Unpack-From-Dotnet-Package -Zip $Zip -OutPath $OutPath |
|
||||
|
|
||||
foreach ($entry in $Zip.Entries) { |
|
||||
$PathWithVersion = Get-Path-Prefix-With-Version $entry.FullName |
|
||||
if (($PathWithVersion -eq $null) -Or ($DirectoriesToUnpack -contains $PathWithVersion)) { |
|
||||
$DestinationPath = Get-Absolute-Path $(Join-Path -Path $OutPath -ChildPath $entry.FullName) |
|
||||
$DestinationDir = Split-Path -Parent $DestinationPath |
|
||||
$OverrideFiles=$OverrideNonVersionedFiles -Or (-Not (Test-Path $DestinationPath)) |
|
||||
if ((-Not $DestinationPath.EndsWith("\")) -And $OverrideFiles) { |
|
||||
New-Item -ItemType Directory -Force -Path $DestinationDir | Out-Null |
|
||||
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $DestinationPath, $OverrideNonVersionedFiles) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
finally { |
|
||||
if ($Zip -ne $null) { |
|
||||
$Zip.Dispose() |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function DownloadFile($Source, [string]$OutPath) { |
|
||||
if ($Source -notlike "http*") { |
|
||||
# Using System.IO.Path.GetFullPath to get the current directory |
|
||||
# does not work in this context - $pwd gives the current directory |
|
||||
if (![System.IO.Path]::IsPathRooted($Source)) { |
|
||||
$Source = $(Join-Path -Path $pwd -ChildPath $Source) |
|
||||
} |
|
||||
$Source = Get-Absolute-Path $Source |
|
||||
Say "Copying file from $Source to $OutPath" |
|
||||
Copy-Item $Source $OutPath |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
$Stream = $null |
|
||||
|
|
||||
try { |
|
||||
$Response = GetHTTPResponse -Uri $Source |
|
||||
$Stream = $Response.Content.ReadAsStreamAsync().Result |
|
||||
$File = [System.IO.File]::Create($OutPath) |
|
||||
$Stream.CopyTo($File) |
|
||||
$File.Close() |
|
||||
} |
|
||||
finally { |
|
||||
if ($Stream -ne $null) { |
|
||||
$Stream.Dispose() |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function Prepend-Sdk-InstallRoot-To-Path([string]$InstallRoot, [string]$BinFolderRelativePath) { |
|
||||
$BinPath = Get-Absolute-Path $(Join-Path -Path $InstallRoot -ChildPath $BinFolderRelativePath) |
|
||||
if (-Not $NoPath) { |
|
||||
$SuffixedBinPath = "$BinPath;" |
|
||||
if (-Not $env:path.Contains($SuffixedBinPath)) { |
|
||||
Say "Adding to current process PATH: `"$BinPath`". Note: This change will not be visible if PowerShell was run as a child process." |
|
||||
$env:path = $SuffixedBinPath + $env:path |
|
||||
} else { |
|
||||
Say-Verbose "Current process PATH already contains `"$BinPath`"" |
|
||||
} |
|
||||
} |
|
||||
else { |
|
||||
Say "Binaries of dotnet can be found in $BinPath" |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
$CLIArchitecture = Get-CLIArchitecture-From-Architecture $Architecture |
|
||||
$SpecificVersion = Get-Specific-Version-From-Version -AzureFeed $AzureFeed -Channel $Channel -Version $Version -JSonFile $JSonFile |
|
||||
$DownloadLink, $EffectiveVersion = Get-Download-Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture |
|
||||
$LegacyDownloadLink = Get-LegacyDownload-Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture |
|
||||
|
|
||||
$InstallRoot = Resolve-Installation-Path $InstallDir |
|
||||
Say-Verbose "InstallRoot: $InstallRoot" |
|
||||
$ScriptName = $MyInvocation.MyCommand.Name |
|
||||
|
|
||||
if ($DryRun) { |
|
||||
Say "Payload URLs:" |
|
||||
Say "Primary named payload URL: $DownloadLink" |
|
||||
if ($LegacyDownloadLink) { |
|
||||
Say "Legacy named payload URL: $LegacyDownloadLink" |
|
||||
} |
|
||||
$RepeatableCommand = ".\$ScriptName -Version `"$SpecificVersion`" -InstallDir `"$InstallRoot`" -Architecture `"$CLIArchitecture`"" |
|
||||
if ($Runtime -eq "dotnet") { |
|
||||
$RepeatableCommand+=" -Runtime `"dotnet`"" |
|
||||
} |
|
||||
elseif ($Runtime -eq "aspnetcore") { |
|
||||
$RepeatableCommand+=" -Runtime `"aspnetcore`"" |
|
||||
} |
|
||||
foreach ($key in $MyInvocation.BoundParameters.Keys) { |
|
||||
if (-not (@("Architecture","Channel","DryRun","InstallDir","Runtime","SharedRuntime","Version") -contains $key)) { |
|
||||
$RepeatableCommand+=" -$key `"$($MyInvocation.BoundParameters[$key])`"" |
|
||||
} |
|
||||
} |
|
||||
Say "Repeatable invocation: $RepeatableCommand" |
|
||||
exit 0 |
|
||||
} |
|
||||
|
|
||||
if ($Runtime -eq "dotnet") { |
|
||||
$assetName = ".NET Core Runtime" |
|
||||
$dotnetPackageRelativePath = "shared\Microsoft.NETCore.App" |
|
||||
} |
|
||||
elseif ($Runtime -eq "aspnetcore") { |
|
||||
$assetName = "ASP.NET Core Runtime" |
|
||||
$dotnetPackageRelativePath = "shared\Microsoft.AspNetCore.App" |
|
||||
} |
|
||||
elseif ($Runtime -eq "windowsdesktop") { |
|
||||
$assetName = ".NET Core Windows Desktop Runtime" |
|
||||
$dotnetPackageRelativePath = "shared\Microsoft.WindowsDesktop.App" |
|
||||
} |
|
||||
elseif (-not $Runtime) { |
|
||||
$assetName = ".NET Core SDK" |
|
||||
$dotnetPackageRelativePath = "sdk" |
|
||||
} |
|
||||
else { |
|
||||
throw "Invalid value for `$Runtime" |
|
||||
} |
|
||||
|
|
||||
if ($SpecificVersion -ne $EffectiveVersion) |
|
||||
{ |
|
||||
Say "Performing installation checks for effective version: $EffectiveVersion" |
|
||||
$SpecificVersion = $EffectiveVersion |
|
||||
} |
|
||||
|
|
||||
# Check if the SDK version is already installed. |
|
||||
$isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $SpecificVersion |
|
||||
if ($isAssetInstalled) { |
|
||||
Say "$assetName version $SpecificVersion is already installed." |
|
||||
Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath |
|
||||
exit 0 |
|
||||
} |
|
||||
|
|
||||
New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null |
|
||||
|
|
||||
$installDrive = $((Get-Item $InstallRoot).PSDrive.Name); |
|
||||
$diskInfo = Get-PSDrive -Name $installDrive |
|
||||
if ($diskInfo.Free / 1MB -le 100) { |
|
||||
Say "There is not enough disk space on drive ${installDrive}:" |
|
||||
exit 0 |
|
||||
} |
|
||||
|
|
||||
$ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName()) |
|
||||
Say-Verbose "Zip path: $ZipPath" |
|
||||
|
|
||||
$DownloadFailed = $false |
|
||||
Say "Downloading link: $DownloadLink" |
|
||||
try { |
|
||||
DownloadFile -Source $DownloadLink -OutPath $ZipPath |
|
||||
} |
|
||||
catch { |
|
||||
Say "Cannot download: $DownloadLink" |
|
||||
if ($LegacyDownloadLink) { |
|
||||
$DownloadLink = $LegacyDownloadLink |
|
||||
$ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName()) |
|
||||
Say-Verbose "Legacy zip path: $ZipPath" |
|
||||
Say "Downloading legacy link: $DownloadLink" |
|
||||
try { |
|
||||
DownloadFile -Source $DownloadLink -OutPath $ZipPath |
|
||||
} |
|
||||
catch { |
|
||||
Say "Cannot download: $DownloadLink" |
|
||||
$DownloadFailed = $true |
|
||||
} |
|
||||
} |
|
||||
else { |
|
||||
$DownloadFailed = $true |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if ($DownloadFailed) { |
|
||||
throw "Could not find/download: `"$assetName`" with version = $SpecificVersion`nRefer to: https://aka.ms/dotnet-os-lifecycle for information on .NET Core support" |
|
||||
} |
|
||||
|
|
||||
Say "Extracting zip from $DownloadLink" |
|
||||
Extract-Dotnet-Package -ZipPath $ZipPath -OutPath $InstallRoot |
|
||||
|
|
||||
# Check if the SDK version is installed; if not, fail the installation. |
|
||||
$isAssetInstalled = $false |
|
||||
|
|
||||
# if the version contains "RTM" or "servicing"; check if a 'release-type' SDK version is installed. |
|
||||
if ($SpecificVersion -Match "rtm" -or $SpecificVersion -Match "servicing") { |
|
||||
$ReleaseVersion = $SpecificVersion.Split("-")[0] |
|
||||
Say-Verbose "Checking installation: version = $ReleaseVersion" |
|
||||
$isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $ReleaseVersion |
|
||||
} |
|
||||
|
|
||||
# Check if the SDK version is installed. |
|
||||
if (!$isAssetInstalled) { |
|
||||
Say-Verbose "Checking installation: version = $SpecificVersion" |
|
||||
$isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $SpecificVersion |
|
||||
} |
|
||||
|
|
||||
if (!$isAssetInstalled) { |
|
||||
throw "`"$assetName`" with version = $SpecificVersion failed to install with an unknown error." |
|
||||
} |
|
||||
|
|
||||
Remove-Item $ZipPath |
|
||||
|
|
||||
Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath |
|
||||
|
|
||||
Say "Installation finished" |
|
||||
exit 0 |
|
||||
File diff suppressed because it is too large
Loading…
Reference in new issue