diff --git a/build/kvm.ps1 b/build/kvm.ps1 index 3e2acb9134..dc3d21cdd4 100644 --- a/build/kvm.ps1 +++ b/build/kvm.ps1 @@ -3,6 +3,7 @@ param( [string] $command, [switch] $verbosity = $false, [alias("g")][switch] $global = $false, + [alias("p")][switch] $persistent = $false, [switch] $x86 = $false, [switch] $x64 = $false, [switch] $svr50 = $false, @@ -12,27 +13,37 @@ param( ) $userKrePath = $env:USERPROFILE + "\.kre" +$userKrePackages = $userKrePath + "\packages" $globalKrePath = $env:ProgramFiles + "\KRE" +$globalKrePackages = $globalKrePath + "\packages" $scriptPath = $myInvocation.MyCommand.Definition function Kvm-Help { @" -kvm - K Runtime Environment Version Manager +K Runtime Environment Version Manager - Build {{BUILD_NUMBER}} -kvm upgrade +USAGE: kvm [options] + +kvm upgrade [-x86][-x64] [-svr50][-svrc50] [-g|-global] install latest KRE from feed - set 'default' alias - add KRE bin to path of current command line + set 'default' alias to installed version + add KRE bin to user PATH environment variable persistently + -g|-global install to machine-wide location -kvm install | [-x86][-x64] [-svr50][-svrc50] [-g|-global] +kvm install || [-x86][-x64] [-svr50][-svrc50] [-g|-global] install requested KRE from feed - -kvm list [-g|-global] - list KRE versions installed - -kvm use | [-x86][-x64] [-svr50][-svrc50] [-g|-global] add KRE bin to path of current command line + -g|-global install to machine-wide location + +kvm use ||none [-x86][-x64] [-svr50][-svrc50] [-p|-persistent] [-g|-global] + | add KRE bin to path of current command line + none remove KRE bin from path of current command line + -p|-persistent add KRE bin to PATH environment variables persistently + -g|-global combined with -p to change machine PATH instead of user PATH + +kvm list + list KRE versions installed kvm alias list KRE aliases which have been defined @@ -46,14 +57,70 @@ kvm alias [-x86][-x64] [-svr50][-svrc50] "@ | Write-Host } +function Kvm-Global-Setup { + If (Needs-Elevation) + { + $arguments = "& '$scriptPath' setup $(Requested-Switches) -persistent" + Start-Process "$psHome\powershell.exe" -Verb runAs -ArgumentList $arguments -Wait + Write-Host "Setup complete" + Kvm-Help + break + } + + $scriptFolder = [System.IO.Path]::GetDirectoryName($scriptPath) + + $kvmBinPath = "$userKrePath\bin" + + Write-Host "Copying file $kvmBinPath\kvm.ps1" + md $kvmBinPath -Force | Out-Null + copy "$scriptFolder\kvm.ps1" "$kvmBinPath\kvm.ps1" + + Write-Host "Copying file $kvmBinPath\kvm.cmd" + copy "$scriptFolder\kvm.cmd" "$kvmBinPath\kvm.cmd" + + Write-Host "Adding $kvmBinPath to process PATH" + Set-Path (Change-Path $env:Path $kvmBinPath ($kvmBinPath)) + + Write-Host "Adding $kvmBinPath to user PATH" + $userPath = [Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User) + $userPath = Change-Path $userPath $kvmBinPath ($kvmBinPath) + [Environment]::SetEnvironmentVariable("Path", $userPath, [System.EnvironmentVariableTarget]::User) + + Write-Host "Adding $globalKrePath;%USERPROFILE%\.kre to process KRE_HOME" + $envKreHome = $env:KRE_HOME + $envKreHome = Change-Path $envKreHome "%USERPROFILE%\.kre" ("%USERPROFILE%\.kre") + $envKreHome = Change-Path $envKreHome $globalKrePath ($globalKrePath) + $env:KRE_HOME = $envKreHome + + Write-Host "Adding $globalKrePath;%USERPROFILE%\.kre to machine KRE_HOME" + $machineKreHome = [Environment]::GetEnvironmentVariable("KRE_HOME", [System.EnvironmentVariableTarget]::Machine) + $machineKreHome = Change-Path $machineKreHome "%USERPROFILE%\.kre" ("%USERPROFILE%\.kre") + $machineKreHome = Change-Path $machineKreHome $globalKrePath ($globalKrePath) + [Environment]::SetEnvironmentVariable("KRE_HOME", $machineKreHome, [System.EnvironmentVariableTarget]::Machine) + + Write-Host "Press any key to continue ..." + $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown,AllowCtrlC") +} + +function Kvm-Global-Upgrade { + $persistent = $true + If (Needs-Elevation) { + $arguments = "& '$scriptPath' upgrade -global $(Requested-Switches)" + Start-Process "$psHome\powershell.exe" -Verb runAs -ArgumentList $arguments -Wait + break + } + $version = Kvm-Find-Latest (Requested-Platform "svr50") (Requested-Architecture "x86") + Kvm-Global-Install $version + Kvm-Alias-Set "default" $version +} function Kvm-Upgrade { + $persistent = $true $version = Kvm-Find-Latest (Requested-Platform "svr50") (Requested-Architecture "x86") Kvm-Install $version Kvm-Alias-Set "default" $version } - function Kvm-Find-Latest { param( [string] $platform, @@ -87,7 +154,8 @@ param( $kreFile = "$kreFolder\$kreFullName.nupkg" If (Test-Path $kreFolder) { - Remove-Item $kreFolder -Force -Recurse + Write-Host "$kreFullName already installed." + return; } Write-Host "Downloading" $kreFullName "from https://www.myget.org/F/aspnetvnext/api/v2/" @@ -122,6 +190,23 @@ param( } } +function Kvm-Global-Install { +param( + [string] $versionOrAlias +) + If (Needs-Elevation) { + $arguments = "& '$scriptPath' install -global $versionOrAlias $(Requested-Switches)" + Start-Process "$psHome\powershell.exe" -Verb runAs -ArgumentList $arguments -Wait + Kvm-Global-Use $versionOrAlias + break + } + + $kreFullName = Requested-VersionOrAlias $versionOrAlias + $kreFolder = "$globalKrePackages\$kreFullName" + Do-Kvm-Download $kreFullName $kreFolder + Kvm-Use $versionOrAlias +} + function Kvm-Install { param( [string] $versionOrAlias @@ -129,103 +214,148 @@ param( if ($versionOrAlias.EndsWith(".nupkg")) { $kreFullName = [System.IO.Path]::GetFileNameWithoutExtension($versionOrAlias) - $kreFolder = "$userKrePath\packages\$kreFullName" + $kreFolder = "$userKrePackages\$kreFullName" $kreFile = "$kreFolder\$kreFullName.nupkg" - md $kreFolder -Force | Out-Null + if (Test-Path($kreFolder)) { + Write-Host "Target folder '$kreFolder' already exists" + } else { + md $kreFolder -Force | Out-Null + copy $versionOrAlias $kreFile + Do-Kvm-Unpack $kreFile $kreFolder + } - copy $versionOrAlias $kreFile - - Do-Kvm-Unpack $kreFile $kreFolder + $kreBin = "$kreFolder\bin" + Write-Host "Adding" $kreBin "to process PATH" + Set-Path (Change-Path $env:Path $kreBin ($globalKrePackages, $userKrePackages)) } else { $kreFullName = Requested-VersionOrAlias $versionOrAlias - $kreFolder = "$userKrePath\packages\$kreFullName" + $kreFolder = "$userKrePackages\$kreFullName" Do-Kvm-Download $kreFullName $kreFolder Kvm-Use $versionOrAlias } } -function Kvm-Global-Install { -param( - [string] $versionOrAlias -) - If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) - { - $arguments = "install -global $versionOrAlias" - if ($x86) {$arguments = "$arguments -x86"} - if ($x64) {$arguments = "$arguments -x64"} - if ($svr50) {$arguments = "$arguments -svr50"} - if ($svrc50) {$arguments = "$arguments -svrc50"} - - $arguments = "& '$scriptPath' $arguments" - Start-Process "$psHome\powershell.exe" -Verb runAs -ArgumentList $arguments - Kvm-Global-Use $versionOrAlias - break - } - - $kreFullName = Requested-VersionOrAlias $versionOrAlias - - $kreFolder = $globalKrePath + "\packages\$kreFullName" - - Do-Kvm-Download $kreFullName $kreFolder -} - function Kvm-List { - Get-ChildItem ($userKrePath + "\packages\") | Select Name -} - -function Kvm-Global-List { - Get-ChildItem ($globalKrePath + "\packages\") | Select Name -} - -function Kvm-Use { -param( - [string] $versionOrAlias -) - $kreFullName = Requested-VersionOrAlias $versionOrAlias - - $kreBin = $userKrePath + "\packages\" + $kreFullName + "\bin" - - Write-Host "Adding" $kreBin "to PATH" - - $newPath = $kreBin - foreach($portion in $env:Path.Split(';')) { - if (!$portion.StartsWith($userKrePath) -and !$portion.StartsWith($globalKrePath)) { - $newPath = $newPath + ";" + $portion - } + $kreHome = $env:KRE_HOME + if (!$kreHome) { + $kreHome = $env:ProgramFiles + "\KRE;%USERPROFILE%\.kre" + } + $items = @() + foreach($portion in $kreHome.Split(';')) { + $path = [System.Environment]::ExpandEnvironmentVariables($portion) + if (Test-Path("$path\packages")) { + $items += Get-ChildItem ("$path\packages\KRE-*") | List-Parts } + } + $items | Sort-Object Version, Runtime, Architecture | Format-Table -AutoSize -Property @{name="Active";expression={$_.Active};alignment="center"}, "Version", "Runtime", "Architecture", "Location" +} -@" -SET "KRE_VERSION=$version" -SET "PATH=$newPath" -"@ | Out-File ($userKrePath + "\run-once.cmd") ascii +filter List-Parts { + $hasBin = Test-Path($_.FullName+"\bin") + if (!$hasBin) { + return + } + $active = $false + foreach($portion in $env:Path.Split(';')) { + if ($portion.StartsWith($_.FullName)) { + $active = $true + } + } + $parts1 = $_.Name.Split('.', 2) + $parts2 = $parts1[0].Split('-', 3) + return New-Object PSObject -Property @{ + Active = if($active){"*"}else{""} + Version = $parts1[1] + Runtime = $parts2[1] + Architecture = $parts2[2] + Location = $_.Parent.FullName + } } function Kvm-Global-Use { param( [string] $versionOrAlias ) - $kreFullName = Requested-VersionOrAlias $versionOrAlias - - $kreBin = "$globalKrePath\packages\$kreFullName\bin" - - Write-Host "Adding" $kreBin "to PATH" - - $newPath = $kreBin - foreach($portion in $env:Path.Split(';')) { - if (!$portion.StartsWith($userKrePath) -and !$portion.StartsWith($globalKrePath)) { - $newPath = $newPath + ";" + $portion - } + If (Needs-Elevation) { + $arguments = "& '$scriptPath' use -global $versionOrAlias $(Requested-Switches)" + if ($persistent) { + $arguments = $arguments + " -persistent" + } + Start-Process "$psHome\powershell.exe" -Verb runAs -ArgumentList $arguments -Wait + break } -@" -SET "KRE_VERSION=$version" -SET "PATH=$newPath" -"@ | Out-File ($userKrePath + "\run-once.cmd") ascii + if ($versionOrAlias -eq "none") { + Write-Host "Removing KRE from process PATH" + Set-Path (Change-Path $env:Path "" ($globalKrePackages, $userKrePackages)) + + if ($persistent) { + Write-Host "Removing KRE from machine PATH" + $machinePath = [Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine) + $machinePath = Change-Path $machinePath "" ($globalKrePackages, $userKrePackages) + [Environment]::SetEnvironmentVariable("Path", $machinePath, [System.EnvironmentVariableTarget]::Machine) + } + return; + } + + $kreFullName = Requested-VersionOrAlias $versionOrAlias + + $kreBin = Locate-KreBinFromFullName $kreFullName + if ($kreBin -eq $null) { + Write-Host "Cannot find $kreFullName, do you need to run 'kvm install $versionOrAlias'?" + return + } + + Write-Host "Adding" $kreBin "to process PATH" + Set-Path (Change-Path $env:Path $kreBin ($globalKrePackages, $userKrePackages)) + + if ($persistent) { + Write-Host "Adding $kreBin to machine PATH" + $machinePath = [Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine) + $machinePath = Change-Path $machinePath $kreBin ($globalKrePackages, $userKrePackages) + [Environment]::SetEnvironmentVariable("Path", $machinePath, [System.EnvironmentVariableTarget]::Machine) + } +} + +function Kvm-Use { +param( + [string] $versionOrAlias +) + if ($versionOrAlias -eq "none") { + Write-Host "Removing KRE from process PATH" + Set-Path (Change-Path $env:Path "" ($globalKrePackages, $userKrePackages)) + + if ($persistent) { + Write-Host "Removing KRE from user PATH" + $userPath = [Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User) + $userPath = Change-Path $userPath "" ($globalKrePackages, $userKrePackages) + [Environment]::SetEnvironmentVariable("Path", $userPath, [System.EnvironmentVariableTarget]::User) + } + return; + } + + $kreFullName = Requested-VersionOrAlias $versionOrAlias + + $kreBin = Locate-KreBinFromFullName $kreFullName + if ($kreBin -eq $null) { + Write-Host "Cannot find $kreFullName, do you need to run 'kvm install $versionOrAlias'?" + return + } + + Write-Host "Adding" $kreBin "to process PATH" + Set-Path (Change-Path $env:Path $kreBin ($globalKrePackages, $userKrePackages)) + + if ($persistent) { + Write-Host "Adding $kreBin to user PATH" + $userPath = [Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User) + $userPath = Change-Path $userPath $kreBin ($globalKrePackages, $userKrePackages) + [Environment]::SetEnvironmentVariable("Path", $userPath, [System.EnvironmentVariableTarget]::User) + } } function Kvm-Alias-List { @@ -254,6 +384,24 @@ param( $kreFullName | Out-File ($userKrePath + "\alias\" + $name + ".txt") ascii } +function Locate-KreBinFromFullName() { +param( + [string] $kreFullName +) + $kreHome = $env:KRE_HOME + if (!$kreHome) { + $kreHome = $env:ProgramFiles + ";%USERPROFILE%\.kre" + } + foreach($portion in $kreHome.Split(';')) { + $path = [System.Environment]::ExpandEnvironmentVariables($portion) + $kreBin = "$path\packages\$kreFullName\bin" + if (Test-Path "$kreBin") { + return $kreBin + } + } + return $null +} + function Requested-VersionOrAlias() { param( [string] $versionOrAlias @@ -305,28 +453,77 @@ param( return $default } +function Change-Path() { +param( + [string] $existingPaths, + [string] $prependPath, + [string[]] $removePaths +) + $newPath = $prependPath + foreach($portion in $existingPaths.Split(';')) { + $skip = $portion -eq "" + foreach($removePath in $removePaths) { + if ($portion.StartsWith($removePath)) { + $skip = $true + } + } + if (!$skip) { + $newPath = $newPath + ";" + $portion + } + } + return $newPath +} + +function Set-Path() { +param( + [string] $newPath +) + md $userKrePath -Force | Out-Null + $env:Path = $newPath +@" +SET "PATH=$newPath" +"@ | Out-File ($userKrePath + "\run-once.cmd") ascii +} + +function Needs-Elevation() { + $user = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent() + $elevated = $user.IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") + return -NOT $elevated +} + +function Requested-Switches() { + $arguments = "" + if ($x86) {$arguments = "$arguments -x86"} + if ($x64) {$arguments = "$arguments -x64"} + if ($svr50) {$arguments = "$arguments -svr50"} + if ($svrc50) {$arguments = "$arguments -svrc50"} + return $arguments +} try { if ($global) { switch -wildcard ($command + " " + $args.Count) { -# "upgrade 0" {Kvm-Global-Upgrade} + "setup 0" {Kvm-Global-Setup} + "upgrade 0" {Kvm-Global-Upgrade} # "install 0" {Kvm-Global-Install-Latest} "install 1" {Kvm-Global-Install $args[0]} - "list 0" {Kvm-Global-List} +# "list 0" {Kvm-Global-List} "use 1" {Kvm-Global-Use $args[0]} default {Write-Host 'Unknown command, or global switch not supported'; Kvm-Help;} } } else { switch -wildcard ($command + " " + $args.Count) { + "setup 0" {Kvm-Global-Setup} "upgrade 0" {Kvm-Upgrade} - "install 0" {Kvm-Install-Latest} +# "install 0" {Kvm-Install-Latest} "install 1" {Kvm-Install $args[0]} "list 0" {Kvm-List} "use 1" {Kvm-Use $args[0]} "alias 0" {Kvm-Alias-List} "alias 1" {Kvm-Alias-Get $args[0]} "alias 2" {Kvm-Alias-Set $args[0] $args[1]} - "help" {Kvm-Help} + "help 0" {Kvm-Help} + " 0" {Kvm-Help} default {Write-Host 'Unknown command'; Kvm-Help;} } }