2015-11-16 11:21:57 -08:00
#
# 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.
#
2016-03-02 14:03:17 -08:00
<#
. 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
Channel is the way of reasoning about stability and quality of dotnet . This parameter takes one of the values :
- nightly - Possibly unstable , frequently changing
- preview - Pre-release stable with known issues and feature gaps
- production - Most stable releases
. PARAMETER Version
Represents a build version on specific channel . Possible values :
- 4 -part version in a format A . B . C . D - represents specific version of build
- latest - most latest build on specific channel
- lkg - last known good version on specific channel
. PARAMETER InstallDir
Path to where to install dotnet . Note that binaries will be placed directly in a given directory .
Defaults to % LocalAppData % \ Microsoft \ . dotnet
. PARAMETER Architecture
Architecture of dotnet binaries to be installed . Defaults to the OS architecture .
Possible values are : AMD64 and x86
. 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
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
This parameter should not be usually changed by user . It allows to change URL for the Azure feed used by this installer .
#>
2016-03-01 16:37:25 -08:00
[ cmdletbinding ( ) ]
2016-02-11 10:47:49 -08:00
param (
2016-03-01 16:37:25 -08:00
[ string ] $Channel = " nightly " ,
[ string ] $Version = " Latest " ,
[ string ] $InstallDir = " <usershare> " ,
[ string ] $Architecture = " auto " ,
2016-03-02 14:03:17 -08:00
[ switch ] $DebugSymbols , # TODO: Switch does not work yet. Symbols zip is not being uploaded yet.
2016-03-01 16:37:25 -08:00
[ switch ] $DryRun ,
2016-03-02 14:03:17 -08:00
[ switch ] $NoPath ,
[ string ] $AzureFeed = " https://dotnetcli.blob.core.windows.net/dotnet "
2016-02-11 10:47:49 -08:00
)
2016-01-20 18:49:47 -08:00
2016-03-01 16:37:25 -08:00
Set-StrictMode -Version Latest
2015-11-10 17:30:01 -08:00
$ErrorActionPreference = " Stop "
$ProgressPreference = " SilentlyContinue "
2016-03-01 16:37:25 -08:00
$LocalVersionFileRelativePath = " \.version "
$BinFolderRelativePath = " \bin "
function Say($str ) {
Write-Host " dotnet_install: $str "
2016-02-11 10:47:49 -08:00
}
2016-03-16 10:55:24 -07:00
2016-03-01 16:37:25 -08:00
function Say-Verbose($str ) {
Write-Verbose " dotnet_install: $str "
}
2015-11-10 17:30:01 -08:00
2016-03-01 16:37:25 -08:00
function Say-Invocation($Invocation ) {
$command = $Invocation . MyCommand ;
$args = ( ( $Invocation . BoundParameters . Keys | foreach { " - $_ `" $( $Invocation . BoundParameters [ $_ ] ) `" " } ) -join " " )
Say-Verbose " $command $args "
2015-11-10 17:30:01 -08:00
}
2016-03-01 16:37:25 -08:00
function Get-Machine-Architecture ( ) {
Say-Invocation $MyInvocation
# possible values: AMD64, IA64, x86
return $ENV:PROCESSOR_ARCHITECTURE
}
# TODO: Architecture and CLIArchitecture should be unified
function Get-CLIArchitecture-From-Architecture([string]$Architecture ) {
Say-Invocation $MyInvocation
switch ( $Architecture . ToLower ( ) ) {
{ $_ -eq " auto " } { return Get-CLIArchitecture -From -Architecture $ ( Get-Machine -Architecture ) }
2016-03-02 14:03:17 -08:00
{ ( $_ -eq " amd64 " ) -or ( $_ -eq " x64 " ) } { return " x64 " }
2016-03-01 16:37:25 -08:00
{ $_ -eq " x86 " } { return " x86 " }
default { throw " Architecture not supported. If you think this is a bug, please report it at https://github.com/dotnet/cli/issues " }
}
}
function Get-Version-Info-From-Version-Text([string]$VersionText ) {
Say-Invocation $MyInvocation
$Data = @ ( $VersionText . Split ( [ char[] ] @ ( ) , [ StringSplitOptions ] :: RemoveEmptyEntries ) ) ;
$VersionInfo = @ { }
$VersionInfo . CommitHash = $Data [ 0 ] . Trim ( )
$VersionInfo . Version = $Data [ 1 ] . Trim ( )
return $VersionInfo
}
function Get-Latest-Version-Info([string]$AzureFeed , [ string ] $AzureChannel , [ string ] $CLIArchitecture ) {
Say-Invocation $MyInvocation
$VersionFileUrl = " $AzureFeed / $AzureChannel /dnvm/latest.win. $CLIArchitecture .version "
$Response = Invoke-WebRequest -UseBasicParsing $VersionFileUrl
$VersionText = [ Text.Encoding ] :: UTF8 . GetString ( $Response . Content )
$VersionInfo = Get-Version -Info -From -Version -Text $VersionText
return $VersionInfo
}
# TODO: AzureChannel and Channel should be unified
function Get-Azure-Channel-From-Channel([string]$Channel ) {
Say-Invocation $MyInvocation
2016-03-02 14:03:17 -08:00
# For compatibility with build scripts accept also directly Azure channels names
2016-03-01 16:37:25 -08:00
switch ( $Channel . ToLower ( ) ) {
2016-03-02 14:03:17 -08:00
{ ( $_ -eq " nightly " ) -or ( $_ -eq " dev " ) } { return " dev " }
{ ( $_ -eq " preview " ) -or ( $_ -eq " beta " ) } { return " beta " }
2016-03-01 16:37:25 -08:00
{ $_ -eq " production " } { throw " Production channel does not exist yet " }
default { throw " `` $Channel `` is an invalid channel name. Use one of the following: `` nightly `` , `` preview `` , `` production `` " }
}
}
function Get-Specific-Version-From-Version([string]$AzureFeed , [ string ] $AzureChannel , [ string ] $CLIArchitecture , [ string ] $Version ) {
Say-Invocation $MyInvocation
switch ( $Version . ToLower ( ) ) {
{ $_ -eq " latest " } {
$LatestVersionInfo = Get-Latest -Version -Info -AzureFeed $AzureFeed -AzureChannel $AzureChannel -CLIArchitecture $CLIArchitecture
return $LatestVersionInfo . Version
2015-11-10 17:30:01 -08:00
}
2016-03-01 16:37:25 -08:00
{ $_ -eq " lkg " } { throw " `` -Version LKG `` not supported yet. " }
default { return $Version }
2015-11-10 17:30:01 -08:00
}
}
2016-03-01 16:37:25 -08:00
function Construct-Download-Link([string]$AzureFeed , [ string ] $AzureChannel , [ string ] $SpecificVersion , [ string ] $CLIArchitecture ) {
Say-Invocation $MyInvocation
$DownloadLink = " $AzureFeed / $AzureChannel /Binaries/ $SpecificVersion /dotnet-win- $CLIArchitecture . $SpecificVersion .zip "
Say-Verbose " Constructed Download link: $DownloadLink "
return $DownloadLink
2015-11-10 17:30:01 -08:00
}
2016-03-01 16:37:25 -08:00
function Get-User-Share-Path ( ) {
Say-Invocation $MyInvocation
2015-11-10 17:30:01 -08:00
2016-03-01 16:37:25 -08:00
$InstallRoot = $env:DOTNET_INSTALL_DIR
if ( ! $InstallRoot ) {
$InstallRoot = " $env:LocalAppData \Microsoft\.dotnet "
}
return $InstallRoot
}
2015-11-10 17:30:01 -08:00
2016-03-01 16:37:25 -08:00
function Resolve-Installation-Path([string]$InstallDir ) {
Say-Invocation $MyInvocation
2015-11-10 17:30:01 -08:00
2016-03-01 16:37:25 -08:00
if ( $InstallDir -eq " <usershare> " ) {
return Get-User -Share -Path
}
return $InstallDir
2015-11-10 17:30:01 -08:00
}
2016-03-01 16:37:25 -08:00
# TODO: check for global.json
function Get-Installed-Version-Info([string]$InstallRoot ) {
Say-Invocation $MyInvocation
2016-03-02 14:03:17 -08:00
$VersionFile = Join-Path -Path $InstallRoot -ChildPath $LocalVersionFileRelativePath
2016-03-01 16:37:25 -08:00
Say-Verbose " Local version file: $VersionFile "
if ( Test-Path $VersionFile ) {
$VersionText = cat $VersionFile
Say-Verbose " Local version file text: $VersionText "
return Get-Version -Info -From -Version -Text $VersionText
}
Say-Verbose " Local version file not found. "
2015-11-10 17:30:01 -08:00
2016-03-01 16:37:25 -08:00
return $null
2015-11-10 17:30:01 -08:00
}
2016-03-01 16:37:25 -08:00
function Get-Absolute-Path([string]$RelativeOrAbsolutePath ) {
# Too much spam
# Say-Invocation $MyInvocation
return $ExecutionContext . SessionState . Path . GetUnresolvedProviderPathFromPSPath ( $RelativeOrAbsolutePath )
}
function Extract-And-Override-Zip([string]$ZipPath , [ string ] $OutPath ) {
Say-Invocation $MyInvocation
Add-Type -Assembly System . IO . Compression . FileSystem | Out-Null
Set-Variable -Name Zip
try {
$Zip = [ System.IO.Compression.ZipFile ] :: OpenRead ( $ZipPath )
foreach ( $entry in $Zip . Entries ) {
$DestinationPath = Get-Absolute -Path $ ( Join-Path -Path $OutPath -ChildPath $entry . FullName )
$DestinationDir = Split-Path -Parent $DestinationPath
New-Item -ItemType Directory -Force -Path $DestinationDir | Out-Null
[ System.IO.Compression.ZipFileExtensions ] :: ExtractToFile ( $entry , $DestinationPath , $true )
}
}
finally {
if ( $Zip -ne $null ) {
$Zip . Dispose ( )
}
}
2015-11-10 17:30:01 -08:00
}
2016-03-01 16:37:25 -08:00
$AzureChannel = Get-Azure -Channel -From -Channel -Channel $Channel
$CLIArchitecture = Get-CLIArchitecture -From -Architecture $Architecture
$SpecificVersion = Get-Specific -Version -From -Version -AzureFeed $AzureFeed -AzureChannel $AzureChannel -CLIArchitecture $CLIArchitecture -Version $Version
$DownloadLink = Construct-Download -Link -AzureFeed $AzureFeed -AzureChannel $AzureChannel -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture
if ( $DryRun ) {
Say " Payload URL: $DownloadLink "
Say " Repeatable invocation: .\ $( $MyInvocation . MyCommand ) -Version $SpecificVersion -Channel $Channel -DebugSymbols `$ $DebugSymbols -Architecture $CLIArchitecture -InstallDir $InstallDir -NoPath `$ $NoPath "
return
}
$InstallRoot = Resolve-Installation -Path $InstallDir
Say-Verbose " InstallRoot: $InstallRoot "
$VersionInfo = Get-Installed -Version -Info $InstallRoot
$LocalVersionText = if ( $VersionInfo -ne $null ) { $VersionInfo . Version } else { " <No version installed> " }
Say-Verbose " Local CLI version is: $LocalVersionText "
if ( ( $VersionInfo -ne $null ) -and ( $SpecificVersion -eq $VersionInfo . Version ) ) {
Say " Your version of CLI is up-to-date. "
return
}
New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null
$ZipPath = [ System.IO.Path ] :: GetTempFileName ( )
Say " Downloading $DownloadLink "
$resp = Invoke-WebRequest -UseBasicParsing $DownloadLink -OutFile $ZipPath
Say " Extracting zip "
Extract-And -Override -Zip -ZipPath $ZipPath -OutPath $InstallRoot
Say " Removing installation artifacts "
Remove-Item $ZipPath
2016-03-02 14:03:17 -08:00
$BinPath = Get-Absolute -Path $ ( Join-Path -Path $InstallRoot -ChildPath $BinFolderRelativePath )
2016-03-01 16:37:25 -08:00
if ( -Not $NoPath ) {
2016-03-02 14:03:17 -08:00
Say " Adding to current process PATH: `" $BinPath `" . Note: This change will not be visible if PowerShell was run as a child process. "
2016-03-01 16:37:25 -08:00
$env:path + = " ; $BinPath "
}
2016-03-02 14:03:17 -08:00
else {
Say " Binaries of dotnet can be found in $BinPath "
}
2015-11-16 13:49:29 -08:00
2016-03-01 16:37:25 -08:00
Say " Installation finished "