initial update install.ps1 according to spec

This commit is contained in:
Krzysztof Wicher 2016-03-01 16:37:25 -08:00
parent 7c8158746e
commit 8e3992660d

View file

@ -3,107 +3,219 @@
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
#
[cmdletbinding()]
param(
[string]$Channel="beta",
[string]$version="Latest",
[string]$Architecture="x64"
[string]$Channel="nightly",
[string]$Version="Latest",
[string]$InstallDir="<usershare>",
[string]$Architecture="auto",
[switch]$DryRun,
[bool]$DebugSymbols=$false, # TODO: There is no zip uploaded yet
[bool]$NoPath=$false
)
Set-StrictMode -Version Latest
$ErrorActionPreference="Stop"
$ProgressPreference="SilentlyContinue"
$fileVersion = $Version
if ($fileVersion -eq "Latest") {
$fileVersion = "latest"
}
$Feed="https://dotnetcli.blob.core.windows.net/dotnet"
$AzureFeed="https://dotnetcli.blob.core.windows.net/dotnet"
$LocalVersionFileRelativePath="\.version"
$BinFolderRelativePath="\bin"
$DotNetFileName="dotnet-dev-win-$Architecture.$fileVersion.zip"
$DotNetUrl="$Feed/$Channel/Binaries/$Version"
function say($str)
{
function Say($str) {
Write-Host "dotnet_install: $str"
}
$InstallDir = $env:DOTNET_INSTALL_DIR
if (!$InstallDir) {
$InstallDir = "$env:LocalAppData\Microsoft\dotnet"
function Say-Verbose($str) {
Write-Verbose "dotnet_install: $str"
}
say "Preparing to install .NET Tools to $InstallDir"
function Say-Invocation($Invocation) {
$command = $Invocation.MyCommand;
$args = (($Invocation.BoundParameters.Keys | foreach { "-$_ `"$($Invocation.BoundParameters[$_])`"" }) -join " ")
Say-Verbose "$command $args"
}
# Check if we need to bother
$LocalFile = "$InstallDir\cli\.version"
if (Test-Path $LocalFile)
{
$LocalData = @(cat $LocalFile)
$LocalHash = $LocalData[0].Trim()
$LocalVersion = $LocalData[1].Trim()
if ($LocalVersion -and $LocalHash)
{
if ($Version -eq "Latest")
{
$RemoteResponse = Invoke-WebRequest -UseBasicParsing "$Feed/$Channel/dnvm/latest.win.$Architecture.version"
$RemoteData = @([Text.Encoding]::UTF8.GetString($RemoteResponse.Content).Split([char[]]@(), [StringSplitOptions]::RemoveEmptyEntries));
$RemoteHash = $RemoteData[0].Trim()
$RemoteVersion = $RemoteData[1].Trim()
function Get-Machine-Architecture() {
Say-Invocation $MyInvocation
if (!$RemoteVersion -or !$RemoteHash) {
throw "Invalid response from feed"
}
# possible values: AMD64, IA64, x86
return $ENV:PROCESSOR_ARCHITECTURE
}
say "Latest version: $RemoteVersion"
say "Local Version: $LocalVersion"
# TODO: Architecture and CLIArchitecture should be unified
function Get-CLIArchitecture-From-Architecture([string]$Architecture) {
Say-Invocation $MyInvocation
if($LocalHash -eq $RemoteHash)
{
say "You already have the latest version"
exit 0
}
switch ($Architecture.ToLower()) {
{ $_ -eq "auto" } { return Get-CLIArchitecture-From-Architecture $(Get-Machine-Architecture) }
{ ($_ -eq "amd64") -Or ($_ -eq "x64") } { return "x64" }
{ $_ -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
switch ($Channel.ToLower()) {
{ $_ -eq "nightly" } { return "dev" }
{ $_ -eq "preview" } { return "beta" }
{ $_ -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
}
elseif ($LocalVersion -eq $Version)
{
say "$Version is already installed."
exit 0
{ $_ -eq "lkg" } { throw "``-Version LKG`` not supported yet." }
default { return $Version }
}
}
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
}
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 "<usershare>") {
return Get-User-Share-Path
}
return $InstallDir
}
# TODO: check for global.json
function Get-Installed-Version-Info([string]$InstallRoot) {
Say-Invocation $MyInvocation
$VersionFile = $InstallRoot + $LocalVersionFileRelativePath
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."
return $null
}
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()
}
}
}
# Set up the install location
if (!(Test-Path $InstallDir)) {
mkdir $InstallDir | Out-Null
$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
}
# De-powershell the path before passing to .NET APIs
$InstallDir = Convert-Path $InstallDir
$InstallRoot = Resolve-Installation-Path $InstallDir
Say-Verbose "InstallRoot: $InstallRoot"
say "Downloading $DotNetFileName from $DotNetUrl"
$resp = Invoke-WebRequest -UseBasicParsing "$DotNetUrl/$DotNetFileName" -OutFile "$InstallDir\$DotNetFileName"
say "Extracting zip"
# Create the destination
if (Test-Path "$InstallDir\cli_new") {
del -rec -for "$InstallDir\cli_new"
}
mkdir "$InstallDir\cli_new" | Out-Null
Add-Type -Assembly System.IO.Compression.FileSystem | Out-Null
[System.IO.Compression.ZipFile]::ExtractToDirectory("$InstallDir\$DotNetFileName", "$InstallDir\cli_new")
# Replace the old installation (if any)
if (Test-Path "$InstallDir\cli") {
del -rec -for "$InstallDir\cli"
}
mv "$InstallDir\cli_new" "$InstallDir\cli"
# Clean the zip
if (Test-Path "$InstallDir\$DotNetFileName") {
del -for "$InstallDir\$DotNetFileName"
$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
}
say "The .NET Tools have been installed to $InstallDir\cli!"
New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null
# New layout
say "Add '$InstallDir\cli' to your PATH to use dotnet"
$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
if (-Not $NoPath) {
$BinPath = Get-Absolute-Path $(Join-Path -Path $InstallRoot -ChildPath $BinFolderRelativePath)
Say "Adding to PATH: `"$BinPath`""
$env:path += ";$BinPath"
}
Say "Installation finished"