29da21f5dc
A one word tweak to weaken the language in the initial explanation to make it "less scary": in general ghcup does not always download all of ghcup, ghc, cabal, stack, and hls (unless requested or they are not already installed, etc), but "will download" sounds like the user is has no choice here except to always download everything, which might give them second thoughts about trying this script and hence adopting ghcup. Perhaps the wording could be made further more precise, but at least "can" gives one less anxiety.
631 lines
25 KiB
PowerShell
631 lines
25 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Script to bootstrap a Haskell environment
|
|
|
|
.DESCRIPTION
|
|
This is the windows GHCup installer, installing:
|
|
|
|
* ghcup - The Haskell toolchain installer"
|
|
* ghc - The Glasgow Haskell Compiler"
|
|
* msys2 - Unix-style toolchain needed for dependencies and tools
|
|
* cabal - The Cabal build tool for managing Haskell software"
|
|
* stack - (optional) A cross-platform program for developing Haskell projects"
|
|
* hls - (optional) A language server for developers to integrate with their editor/IDE"
|
|
|
|
By default, the installation is non-interactive, unless you run it with 'Interactive $true'.
|
|
#>
|
|
param (
|
|
# Run an interactive installation
|
|
[switch]$Interactive,
|
|
# Do minimal installation of ghcup and msys2 only
|
|
[switch]$Minimal,
|
|
# Run the final bootstrap script via 'bash' instead of a full newly spawned msys2 shell
|
|
[switch]$InBash,
|
|
# Overwrite (or rather backup) a previous install
|
|
[switch]$Overwrite,
|
|
# Skip adjusting cabal.config with mingw paths
|
|
[switch]$NoAdjustCabalConfig,
|
|
# Whether to install stack as well
|
|
[switch]$InstallStack,
|
|
# Whether to install hls as well
|
|
[switch]$InstallHLS,
|
|
# Specify the install root (default: 'C:\')
|
|
[string]$InstallDir,
|
|
# Specify the bootstrap url (default: 'https://www.haskell.org/ghcup/sh/bootstrap-haskell')
|
|
[string]$BootstrapUrl,
|
|
# Instead of installing a new MSys2, use an existing installation
|
|
[string]$ExistingMsys2Dir,
|
|
# Specify the cabal root directory (default: '$InstallDir\cabal')
|
|
[string]$CabalDir
|
|
)
|
|
|
|
$Silent = !$Interactive
|
|
|
|
function Print-Msg {
|
|
param ( [Parameter(Mandatory=$true, HelpMessage='String to output')][string]$msg, [string]$color = "Green" )
|
|
Write-Host ('{0}' -f $msg) -ForegroundColor $color
|
|
}
|
|
|
|
function Create-Shortcut {
|
|
param ( [Parameter(Mandatory=$true,HelpMessage='Target path')][string]$SourceExe
|
|
, [Parameter(Mandatory=$true,HelpMessage='Arguments to the path/exe')][AllowEmptyString()]$ArgumentsToSourceExe
|
|
, [Parameter(Mandatory=$true,HelpMessage='The destination of the desktop link')][string]$DestinationPath
|
|
, [Parameter(Mandatory=$true,HelpMessage='Temporary path to create the link at')][string]$TempPath
|
|
)
|
|
# we save to a temp dir first due to
|
|
# https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/267
|
|
$DesktopDir = [Environment]::GetFolderPath("Desktop")
|
|
if (!(Test-Path -Path ('{0}' -f $TempPath))) {
|
|
New-Item -Path $TempPath -ItemType "directory"
|
|
}
|
|
$TmpFile = ('{0}\{1}' -f $TempPath, $DestinationPath)
|
|
$FinalDest = ('{0}\{1}' -f $DesktopDir, $DestinationPath)
|
|
$WshShell = New-Object -comObject WScript.Shell
|
|
$Shortcut = $WshShell.CreateShortcut($TmpFile)
|
|
$Shortcut.TargetPath = $SourceExe
|
|
if($ArgumentsToSourceExe) {
|
|
$Shortcut.Arguments = $ArgumentsToSourceExe
|
|
}
|
|
$Shortcut.Save()
|
|
if ((Test-Path -Path ('{0}' -f $FinalDest))) {
|
|
Remove-Item -LiteralPath $FinalDest -Force
|
|
}
|
|
Move-Item -LiteralPath $TmpFile -Destination $FinalDest
|
|
}
|
|
|
|
function Add-EnvPath {
|
|
param(
|
|
[Parameter(Mandatory=$true,HelpMessage='The Path to add to Users environment')]
|
|
[string] $Path,
|
|
|
|
[ValidateSet('Machine', 'User', 'Session')]
|
|
[string] $Container = 'Session'
|
|
)
|
|
|
|
if ($Container -eq 'Session') {
|
|
$envPaths = [Collections.Generic.List[String]]($env:Path -split ([IO.Path]::PathSeparator))
|
|
if ($envPaths -notcontains $Path) {
|
|
$envPaths.Add($Path)
|
|
$env:PATH = $envPaths -join ([IO.Path]::PathSeparator)
|
|
}
|
|
}
|
|
else {
|
|
[Microsoft.Win32.RegistryHive]$hive, $keyPath = switch ($Container) {
|
|
'Machine' { 'LocalMachine', 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment' }
|
|
'User' { 'CurrentUser', 'Environment' }
|
|
}
|
|
|
|
$hiveKey = $envKey = $null
|
|
try {
|
|
$hiveKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($hive, '')
|
|
$envKey = $hiveKey.OpenSubKey($keyPath, $true)
|
|
$rawPath = $envKey.GetValue('PATH', '', 'DoNotExpandEnvironmentNames')
|
|
|
|
$envPaths = [Collections.Generic.List[String]]($rawPath -split ([IO.Path]::PathSeparator))
|
|
if ($envPaths -notcontains $Path) {
|
|
$envPaths.Add($Path)
|
|
$envKey.SetValue('PATH', ($envPaths -join ([IO.Path]::PathSeparator)), 'ExpandString')
|
|
}
|
|
}
|
|
finally {
|
|
if ($envKey) { $envKey.Close() }
|
|
if ($hiveKey) { $hiveKey.Close() }
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
filter Get-FileSize {
|
|
'{0:N2} {1}' -f $(
|
|
if ($_ -lt 1kb) { $_, 'Bytes' }
|
|
elseif ($_ -lt 1mb) { ($_/1kb), 'KB' }
|
|
elseif ($_ -lt 1gb) { ($_/1mb), 'MB' }
|
|
elseif ($_ -lt 1tb) { ($_/1gb), 'GB' }
|
|
elseif ($_ -lt 1pb) { ($_/1tb), 'TB' }
|
|
else { ($_/1pb), 'PB' }
|
|
)
|
|
}
|
|
|
|
function Get-FileWCSynchronous{
|
|
param(
|
|
[Parameter(Mandatory=$true)]
|
|
[string]$url,
|
|
[string]$destinationFolder="$env:USERPROFILE\Downloads",
|
|
[switch]$includeStats
|
|
)
|
|
$wc = New-Object -TypeName Net.WebClient
|
|
$wc.UseDefaultCredentials = $true
|
|
$destination = Join-Path -Path $destinationFolder -ChildPath ($url | Split-Path -Leaf)
|
|
$start = Get-Date
|
|
$wc.DownloadFile($url, $destination)
|
|
$elapsed = ((Get-Date) - $start).ToString('hh\:mm\:ss')
|
|
$totalSize = (Get-Item -Path $destination).Length | Get-FileSize
|
|
if ($includeStats.IsPresent){
|
|
[PSCustomObject]@{Name=$MyInvocation.MyCommand;TotalSize=$totalSize;Time=$elapsed}
|
|
}
|
|
Get-Item -Path $destination | Unblock-File
|
|
}
|
|
|
|
function Test-AbsolutePath {
|
|
Param (
|
|
[Parameter(Mandatory=$True)]
|
|
[ValidateScript({[System.IO.Path]::IsPathRooted($_)})]
|
|
[String]$Path
|
|
)
|
|
}
|
|
|
|
function Exec
|
|
{
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Position = 0, Mandatory = 1)][string]$cmd,
|
|
[Parameter()][string]$errorMessage,
|
|
[parameter(ValueFromRemainingArguments = $true)]
|
|
[string[]]$Passthrough
|
|
)
|
|
& $cmd @Passthrough
|
|
if ($lastexitcode -ne 0) {
|
|
if (!($errorMessage)) {
|
|
throw ('Exec: Error executing command {0} with arguments ''{1}''' -f $cmd, "$Passthrough")
|
|
} else {
|
|
throw ('Exec: ' + $errorMessage)
|
|
}
|
|
}
|
|
}
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$GhcupBasePrefixEnv = [System.Environment]::GetEnvironmentVariable('GHCUP_INSTALL_BASE_PREFIX', 'user')
|
|
|
|
if (Get-Command -Name 'chocolatey.exe' -ErrorAction SilentlyContinue) {
|
|
if (!($Silent)) {
|
|
Print-Msg -color Magenta -msg (@'
|
|
Chocolatey was detected on your system. It is capable of installing the Haskell toolchain as well.
|
|
If you want to rather use that instead of ghcup, abort the installation and run the following at an
|
|
elevated command prompt:
|
|
choco install haskell-dev
|
|
refreshenv
|
|
|
|
'@)
|
|
$decision = $Host.UI.PromptForChoice(''
|
|
, 'Continue with GHCup installation?'
|
|
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Continue'
|
|
'&Abort'), 0)
|
|
if ($decision -eq 1) {
|
|
Exit 0
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($GhcupBasePrefixEnv) {
|
|
$defaultGhcupBasePrefix = $GhcupBasePrefixEnv
|
|
} elseif (!($InstallDir)) {
|
|
$partitions = Get-CimInstance win32_logicaldisk
|
|
$defaultGhcupBasePrefix = $null
|
|
foreach ($p in $partitions){
|
|
try {
|
|
if ($p."FreeSpace" -lt 5368709120) { # at least 5 GB are needed
|
|
throw ("Not enough free space on {0}" -f $p."DeviceId")
|
|
}
|
|
$null = New-Item -Path ('{0}\' -f $p."DeviceId") -Name "ghcup.test" -ItemType "directory" -Force
|
|
$defaultGhcupBasePrefix = ('{0}\' -f $p."DeviceId")
|
|
Remove-Item -LiteralPath ('{0}\ghcup.test' -f $p."DeviceId")
|
|
break
|
|
} catch {
|
|
Print-Msg -color Yellow -msg ("{0} not writable or not enough disk space, trying next device" -f $p."DeviceId")
|
|
}
|
|
}
|
|
if ($defaultGhcupBasePrefix) {
|
|
Print-Msg -color Green -msg ("Picked {0} as default Install prefix!" -f $defaultGhcupBasePrefix)
|
|
} else {
|
|
Print-Msg -color Red -msg "Couldn't find a writable partition with at least 5GB free disk space!"
|
|
Exit 1
|
|
}
|
|
}
|
|
|
|
# ask for base install prefix
|
|
if ($Silent -and !($InstallDir)) {
|
|
$GhcupBasePrefix = $defaultGhcupBasePrefix
|
|
} elseif ($InstallDir) {
|
|
if (!(Test-Path -LiteralPath ('{0}' -f $InstallDir) -IsValid)) {
|
|
Print-Msg -color Red -msg "Not a valid directory! (InstallDir)"
|
|
Exit 1
|
|
} elseif (!(Split-Path -IsAbsolute -Path "$InstallDir")) {
|
|
Print-Msg -color Red -msg "Non-absolute Path specified! (InstallDir)"
|
|
Exit 1
|
|
} else {
|
|
$GhcupBasePrefix = $InstallDir
|
|
}
|
|
} else {
|
|
while ($true) {
|
|
Print-Msg -color Magenta -msg (@'
|
|
Welcome to Haskell!
|
|
|
|
This script can download and install the following programs:
|
|
* ghcup - The Haskell toolchain installer
|
|
* ghc - The Glasgow Haskell Compiler
|
|
* msys2 - A linux-style toolchain environment required for many operations
|
|
* cabal - The Cabal build tool for managing Haskell software
|
|
* stack - (optional) A cross-platform program for developing Haskell projects
|
|
* hls - (optional) A language server for developers to integrate with their editor/IDE
|
|
|
|
Please note that ANTIVIRUS may interfere with the installation. If you experience problems, consider
|
|
disabling it temporarily.
|
|
|
|
Where to install to (this should be a short Path, preferably a Drive like 'C:\')?
|
|
If you accept this path, binaries will be installed into '{0}ghcup\bin' and msys2 into '{0}ghcup\msys64'.
|
|
Press enter to accept the default [{0}]:
|
|
|
|
'@ -f $defaultGhcupBasePrefix)
|
|
|
|
|
|
$basePrefixPrompt = Read-Host
|
|
$GhcupBasePrefix = ($defaultGhcupBasePrefix,$basePrefixPrompt)[[bool]$basePrefixPrompt]
|
|
if (!($GhcupBasePrefix.EndsWith('\'))) {
|
|
$GhcupBasePrefix = ('{0}\' -f $GhcupBasePrefix)
|
|
}
|
|
|
|
$GhcupBasePrefix = $GhcupBasePrefix.TrimEnd().TrimStart()
|
|
if (!($GhcupBasePrefix)) {
|
|
Print-Msg -color Red -msg "No directory specified!"
|
|
} elseif (!(Test-Path -LiteralPath ('{0}' -f $GhcupBasePrefix))) {
|
|
Print-Msg -color Red -msg "Directory does not exist, need to specify an existing Drive/Directory"
|
|
} elseif (!(Split-Path -IsAbsolute -Path "$GhcupBasePrefix")) {
|
|
Print-Msg -color Red -msg "Invalid/Non-absolute Path specified"
|
|
} else {
|
|
Break
|
|
}
|
|
}
|
|
}
|
|
|
|
Print-Msg -msg ('Setting env variable GHCUP_INSTALL_BASE_PREFIX to ''{0}''' -f $GhcupBasePrefix)
|
|
$null = [Environment]::SetEnvironmentVariable("GHCUP_INSTALL_BASE_PREFIX", $GhcupBasePrefix, [System.EnvironmentVariableTarget]::User)
|
|
|
|
|
|
$GhcupDir = ('{0}\ghcup' -f $GhcupBasePrefix)
|
|
if ($ExistingMsys2Dir) {
|
|
if (!(Test-Path -LiteralPath ('{0}' -f $ExistingMsys2Dir) -IsValid)) {
|
|
Print-Msg -color Red -msg "Not a valid directory! (ExistingMsys2Dir)"
|
|
Exit 1
|
|
} elseif (!(Split-Path -IsAbsolute -Path "$ExistingMsys2Dir")) {
|
|
Print-Msg -color Red -msg "Non-absolute Path specified! (ExistingMsys2Dir)"
|
|
Exit 1
|
|
} else {
|
|
$MsysDir = $ExistingMsys2Dir
|
|
}
|
|
} else {
|
|
$MsysDir = ('{0}\msys64' -f $GhcupDir)
|
|
}
|
|
|
|
$Bash = ('{0}\usr\bin\bash' -f $MsysDir)
|
|
if (!($BootstrapUrl)) {
|
|
$BootstrapUrl = 'https://www.haskell.org/ghcup/sh/bootstrap-haskell'
|
|
}
|
|
$GhcupMsys2 = [System.Environment]::GetEnvironmentVariable('GHCUP_MSYS2', 'user')
|
|
|
|
Print-Msg -msg 'Preparing for GHCup installation...'
|
|
|
|
# ask what to do in case ghcup is already installed
|
|
if (Test-Path -LiteralPath ('{0}' -f $GhcupDir)) {
|
|
Print-Msg -msg ('GHCup already installed at ''{0}''...' -f $GhcupDir)
|
|
if ($Overwrite) {
|
|
$decision = 0
|
|
} elseif (!($Silent)) {
|
|
$decision = $Host.UI.PromptForChoice('Install GHCup'
|
|
, 'GHCup is already installed, what do you want to do?'
|
|
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Reinstall'
|
|
'&Continue'
|
|
'&Abort'), 1)
|
|
} else {
|
|
$decision = 1
|
|
}
|
|
|
|
if ($decision -eq 0) {
|
|
$suffix = [IO.Path]::GetRandomFileName()
|
|
Print-Msg -msg ('Backing up {0} to {0}-{1} ...' -f $GhcupDir, $suffix)
|
|
Rename-Item -Path ('{0}' -f $GhcupDir) -NewName ('{0}-{1}' -f $GhcupDir, $suffix)
|
|
} elseif ($decision -eq 1) {
|
|
Print-Msg -msg 'Continuing installation...'
|
|
} elseif ($decision -eq 2) {
|
|
Exit 0
|
|
}
|
|
}
|
|
|
|
|
|
$null = New-Item -Path ('{0}' -f $GhcupDir) -ItemType 'directory' -ErrorAction SilentlyContinue
|
|
$null = New-Item -Path ('{0}' -f $GhcupDir) -Name 'bin' -ItemType 'directory' -ErrorAction SilentlyContinue
|
|
|
|
# ask for cabal dir destination
|
|
if ($CabalDir) {
|
|
$CabDirEnv = $CabalDir
|
|
if (!($CabDirEnv)) {
|
|
Print-Msg -color Red -msg "No directory specified!"
|
|
Exit 1
|
|
} elseif (!(Split-Path -IsAbsolute -Path "$CabDirEnv")) {
|
|
Print-Msg -color Red -msg "Invalid/Non-absolute Path specified"
|
|
Exit 1
|
|
}
|
|
} elseif (!($Silent)) {
|
|
while ($true) {
|
|
|
|
$defaultCabalDir = ('{0}\cabal' -f $GhcupBasePrefix)
|
|
Print-Msg -color Magenta -msg ('Specify Cabal directory (this is where haskell packages end up){1}Press enter to accept the default [{0}]:' -f $defaultCabalDir, "`n")
|
|
$CabalDirPrompt = Read-Host
|
|
$CabDirEnv = ($defaultCabalDir,$CabalDirPrompt)[[bool]$CabalDirPrompt]
|
|
|
|
$CabDirEnv = $CabDirEnv.TrimEnd().TrimStart()
|
|
if (!($CabDirEnv)) {
|
|
Print-Msg -color Red -msg "No directory specified!"
|
|
} elseif (!(Split-Path -IsAbsolute -Path "$CabDirEnv")) {
|
|
Print-Msg -color Red -msg "Invalid/Non-absolute Path specified"
|
|
} else {
|
|
Break
|
|
}
|
|
}
|
|
} else {
|
|
$CabDirEnv = ('{0}\cabal' -f $GhcupBasePrefix)
|
|
}
|
|
|
|
# ask whether to install HLS
|
|
if (!($InstallHLS)) {
|
|
if (!($Silent)) {
|
|
$HLSdecision = $Host.UI.PromptForChoice('Install HLS'
|
|
, 'Do you want to install the haskell-language-server (HLS) for development purposes as well?'
|
|
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Yes'
|
|
'&No'
|
|
'&Abort'), 1)
|
|
|
|
if ($HLSdecision -eq 0) {
|
|
$InstallHLS = $true
|
|
} elseif ($HLSdecision -eq 2) {
|
|
Exit 0
|
|
}
|
|
}
|
|
}
|
|
|
|
# ask whether to install stack
|
|
if (!($InstallStack)) {
|
|
if (!($Silent)) {
|
|
$StackDecision = $Host.UI.PromptForChoice('Install stack'
|
|
, 'Do you want to install stack as well?'
|
|
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Yes'
|
|
'&No'
|
|
'&Abort'), 1)
|
|
|
|
if ($StackDecision -eq 0) {
|
|
$InstallStack = $true
|
|
} elseif ($StackDecision -eq 2) {
|
|
Exit 0
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
# mingw foo
|
|
Print-Msg -msg 'First checking for Msys2...'
|
|
if (!(Test-Path -Path ('{0}' -f $MsysDir))) {
|
|
if ($Silent) {
|
|
$msys2Decision = 0
|
|
} else {
|
|
$msys2Decision = $Host.UI.PromptForChoice('Install MSys2'
|
|
, 'Do you want GHCup to install a default MSys2 toolchain (recommended)?'
|
|
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Yes'
|
|
'&No'), 0)
|
|
}
|
|
|
|
if ($msys2Decision -eq 0) {
|
|
Print-Msg -msg ('...Msys2 doesn''t exist, installing into {0}' -f $MsysDir)
|
|
|
|
Print-Msg -msg 'Starting installation in 5 seconds, this may take a while...'
|
|
Start-Sleep -s 5
|
|
|
|
# Download the archive
|
|
Print-Msg -msg 'Downloading Msys2 archive...'
|
|
$archive = 'msys2-x86_64-latest.sfx.exe'
|
|
$archivePath = ('{0}\{1}' -f ([IO.Path]::GetTempPath()), "$archive")
|
|
|
|
if (Get-Command -Name 'curl.exe' -ErrorAction SilentlyContinue) {
|
|
Exec "curl.exe" '-o' "$archivePath" ('https://repo.msys2.org/distrib/{0}' -f "$archive")
|
|
} else {
|
|
Get-FileWCSynchronous -url ('https://repo.msys2.org/distrib/{0}' -f $archive) -destinationFolder ([IO.Path]::GetTempPath()) -includeStats
|
|
}
|
|
|
|
Print-Msg -msg 'Extracting Msys2 archive...'
|
|
$null = & "$archivePath" '-y' ('-o{0}' -f $GhcupDir) # Extract
|
|
Remove-Item -Path "$archivePath"
|
|
|
|
Print-Msg -msg 'Processing MSYS2 bash for first time use...'
|
|
Exec "$Bash" '-lc' 'exit'
|
|
|
|
Exec "$env:windir\system32\taskkill.exe" /F /FI `"MODULES eq msys-2.0.dll`"
|
|
|
|
Print-Msg -msg 'Upgrading full system...'
|
|
Exec "$Bash" '-lc' 'pacman --noconfirm -Syuu'
|
|
|
|
Print-Msg -msg 'Upgrading full system twice...'
|
|
Exec "$Bash" '-lc' 'pacman --noconfirm -Syuu'
|
|
|
|
Print-Msg -msg 'Installing Dependencies...'
|
|
Exec "$Bash" '-lc' 'pacman --noconfirm -S --needed curl autoconf mingw-w64-x86_64-pkgconf'
|
|
|
|
Print-Msg -msg 'Updating SSL root certificate authorities...'
|
|
Exec "$Bash" '-lc' 'pacman --noconfirm -S ca-certificates'
|
|
|
|
Print-Msg -msg 'Setting default home directory...'
|
|
Exec "$Bash" '-lc' "sed -i -e 's/db_home:.*$/db_home: windows/' /etc/nsswitch.conf"
|
|
|
|
} elseif ($msys2Decision -eq 1) {
|
|
Print-Msg -color Yellow -msg 'Skipping MSys2 installation.'
|
|
while ($true) {
|
|
if ($GhcupMsys2) {
|
|
$defaultMsys2Dir = $GhcupMsys2
|
|
Print-Msg -color Magenta -msg ('Input existing MSys2 toolchain directory.{1}Press enter to accept the default [{0}]:' -f $defaultMsys2Dir, "`n")
|
|
$MsysDirPrompt = Read-Host
|
|
$MsysDir = ($defaultMsys2Dir,$MsysDirPrompt)[[bool]$MsysDirPrompt]
|
|
} else {
|
|
Print-Msg -color Magenta -msg 'Input existing MSys2 toolchain directory:'
|
|
$MsysDir = Read-Host
|
|
}
|
|
$MsysDir = $MsysDir.TrimEnd().TrimStart()
|
|
if (!($MsysDir)) {
|
|
Print-Msg -color Red -msg "No directory specified!"
|
|
} elseif (!(Test-Path -LiteralPath ('{0}' -f $MsysDir))) {
|
|
Print-Msg -color Red -msg ('MSys2 installation at ''{0}'' could not be found!' -f $MsysDir)
|
|
} elseif (!(Split-Path -IsAbsolute -Path "$MsysDir")) {
|
|
Print-Msg -color Red -msg "Invalid/Non-absolute Path specified"
|
|
} else {
|
|
Break
|
|
}
|
|
}
|
|
Print-Msg -msg ('Setting GHCUP_MSYS2 env var to ''{0}''' -f $MsysDir)
|
|
$null = [Environment]::SetEnvironmentVariable("GHCUP_MSYS2", $MsysDir, [System.EnvironmentVariableTarget]::User)
|
|
$Bash = ('{0}\usr\bin\bash' -f $MsysDir)
|
|
}
|
|
} else {
|
|
Print-Msg -msg ('...Msys2 found in {0} ...skipping Msys2 installation.' -f $MsysDir)
|
|
|
|
Print-Msg -msg 'Starting installation in 5 seconds, this may take a while...'
|
|
Start-Sleep -s 5
|
|
}
|
|
|
|
Print-Msg -msg 'Creating shortcuts...'
|
|
$uninstallShortCut = @'
|
|
$decision = $Host.UI.PromptForChoice('Uninstall Haskell'
|
|
, 'Do you want to uninstall all of the haskell toolchain, including GHC, Cabal, Stack and GHCup itself?'
|
|
, [System.Management.Automation.Host.ChoiceDescription[]] @('&Uninstall'
|
|
'&Abort'), 0)
|
|
|
|
if ($decision -eq 1) {
|
|
Exit 0
|
|
}
|
|
|
|
Write-Host 'Removing ghcup toolchain' -ForegroundColor Green
|
|
ghcup nuke
|
|
|
|
Write-Host 'Unsetting GHCUP_INSTALL_BASE_PREFIX' -ForegroundColor Green
|
|
[Environment]::SetEnvironmentVariable('GHCUP_INSTALL_BASE_PREFIX', $null, [System.EnvironmentVariableTarget]::User)
|
|
|
|
$ghcupMsys2 = [System.Environment]::GetEnvironmentVariable('GHCUP_MSYS2', 'user')
|
|
$GhcupBasePrefixEnv = [System.Environment]::GetEnvironmentVariable('GHCUP_INSTALL_BASE_PREFIX', 'user')
|
|
|
|
if ($ghcupMsys2) {
|
|
$msys2Dir = [IO.Path]::GetFullPath($ghcupMsys2)
|
|
$baseDir = [IO.Path]::GetFullPath('{0}\ghcup' -f $GhcupBasePrefixEnv)
|
|
|
|
if ($msys2Dir.StartsWith($baseDir)) {
|
|
Write-Host 'Unsetting GHCUP_MSYS2' -ForegroundColor Green
|
|
[Environment]::SetEnvironmentVariable('GHCUP_MSYS2', $null, [System.EnvironmentVariableTarget]::User)
|
|
} else {
|
|
Write-Host ('GHCUP_MSYS2 env variable is set to a non-standard location {0}. Environment variable not unset. Uninstall manually.' -f $msys2Dir) -ForegroundColor Magenta
|
|
}
|
|
} else {
|
|
Write-Host 'Unsetting GHCUP_MSYS2' -ForegroundColor Green
|
|
[Environment]::SetEnvironmentVariable('GHCUP_MSYS2', $null, [System.EnvironmentVariableTarget]::User)
|
|
}
|
|
|
|
Write-Host 'Removing ghcup from PATH env var' -ForegroundColor Green
|
|
$path = [System.Environment]::GetEnvironmentVariable(
|
|
'PATH',
|
|
'user'
|
|
)
|
|
$path = ($path.Split(';') | Where-Object { $_ -ne ('{0}\bin' -f $baseDir) }) -join ';'
|
|
[System.Environment]::SetEnvironmentVariable(
|
|
'PATH',
|
|
$path,
|
|
'user'
|
|
)
|
|
|
|
Write-Host 'Removing desktop files' -ForegroundColor Green
|
|
$DesktopDir = [Environment]::GetFolderPath("Desktop")
|
|
Remove-Item -LiteralPath ('{0}\Install GHC dev dependencies.lnk' -f $DesktopDir) -Force
|
|
Remove-Item -LiteralPath ('{0}\Mingw haskell shell.lnk' -f $DesktopDir) -Force
|
|
Remove-Item -LiteralPath ('{0}\Mingw package management docs.url' -f $DesktopDir) -Force
|
|
|
|
Write-Host ('CABAL_DIR env variable is still set to {0} and will be used by cabal regardless of ghcup. You may want to uninstall this manually.' -f [System.Environment]::GetEnvironmentVariable('CABAL_DIR', 'user')) -ForegroundColor Magenta
|
|
Write-Host 'You may remove this script now.' -ForegroundColor Magenta
|
|
|
|
if ($Host.Name -eq "ConsoleHost")
|
|
{
|
|
Write-Host "Press any key to continue..."
|
|
$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null
|
|
}
|
|
'@
|
|
|
|
$GhcInstArgs = '-mingw64 -mintty -c "pacman --noconfirm -S --needed base-devel gettext autoconf make libtool automake python p7zip patch unzip"'
|
|
Create-Shortcut -SourceExe ('{0}\msys2_shell.cmd' -f $MsysDir) -ArgumentsToSourceExe $GhcInstArgs -DestinationPath 'Install GHC dev dependencies.lnk' -TempPath $GhcupDir
|
|
Create-Shortcut -SourceExe ('{0}\msys2_shell.cmd' -f $MsysDir) -ArgumentsToSourceExe '-mingw64' -DestinationPath 'Mingw haskell shell.lnk' -TempPath $GhcupDir
|
|
Create-Shortcut -SourceExe 'https://www.msys2.org/docs/package-management' -ArgumentsToSourceExe '' -DestinationPath 'Mingw package management docs.url' -TempPath $GhcupDir
|
|
$DesktopDir = [Environment]::GetFolderPath("Desktop")
|
|
$null = New-Item -Path $DesktopDir -Name "Uninstall Haskell.ps1" -ItemType "file" -Force -Value $uninstallShortCut
|
|
|
|
Print-Msg -msg ('Adding {0}\bin to Users Path...' -f $GhcupDir)
|
|
Add-EnvPath -Path ('{0}\bin' -f ([System.IO.Path]::GetFullPath("$GhcupDir"))) -Container 'User'
|
|
|
|
|
|
|
|
$CabalDirFull = [System.IO.Path]::GetFullPath("$CabDirEnv")
|
|
Print-Msg -msg ('Setting CABAL_DIR to ''{0}''' -f $CabalDirFull)
|
|
$null = [Environment]::SetEnvironmentVariable("CABAL_DIR", $CabalDirFull, [System.EnvironmentVariableTarget]::User)
|
|
|
|
Print-Msg -msg 'Starting GHCup installer...'
|
|
|
|
$Msys2Shell = ('{0}\msys2_shell.cmd' -f $MsysDir)
|
|
|
|
# The bootstrap script is always silent, since we ask relevant questions here
|
|
$SilentExport = 'export BOOTSTRAP_HASKELL_NONINTERACTIVE=1 ;'
|
|
|
|
if ($InstallStack) {
|
|
$StackInstallExport = 'export BOOTSTRAP_HASKELL_INSTALL_STACK=1 ;'
|
|
}
|
|
|
|
if ($InstallHLS) {
|
|
$HLSInstallExport = 'export BOOTSTRAP_HASKELL_INSTALL_HLS=1 ;'
|
|
}
|
|
|
|
if (!($NoAdjustCabalConfig)) {
|
|
$AdjustCabalConfigExport = 'export BOOTSTRAP_HASKELL_ADJUST_CABAL_CONFIG=1 ;'
|
|
}
|
|
|
|
if ($Minimal) {
|
|
$MinimalExport = 'export BOOTSTRAP_HASKELL_MINIMAL=1 ;'
|
|
}
|
|
|
|
if ((Get-Process -ID $PID).ProcessName.StartsWith("bootstrap-haskell") -Or $InBash) {
|
|
Exec "$Bash" '-lc' ('{4} {6} {7} {8} {9} [ -n ''{1}'' ] && export GHCUP_MSYS2=$(cygpath -m ''{1}'') ; [ -n ''{2}'' ] && export GHCUP_INSTALL_BASE_PREFIX=$(cygpath -m ''{2}/'') ; export PATH=$(cygpath -u ''{3}/bin''):$PATH ; export CABAL_DIR=''{5}'' ; [[ ''{0}'' = https* ]] && curl --proto ''=https'' --tlsv1.2 -sSf {0} | bash || cat $(cygpath -m ''{0}'') | bash' -f $BootstrapUrl, $MsysDir, $GhcupBasePrefix, $GhcupDir, $SilentExport, $CabalDirFull, $StackInstallExport, $HLSInstallExport, $AdjustCabalConfigExport, $MinimalExport)
|
|
} else {
|
|
Exec "$Msys2Shell" '-mingw64' '-mintty' '-c' ('{4} {6} {7} {8} {9} [ -n ''{1}'' ] && export GHCUP_MSYS2=$(cygpath -m ''{1}'') ; [ -n ''{2}'' ] && export GHCUP_INSTALL_BASE_PREFIX=$(cygpath -m ''{2}/'') ; export PATH=$(cygpath -u ''{3}/bin''):$PATH ; export CABAL_DIR=''{5}'' ; trap ''echo Press any key to exit && read -n 1 && exit'' 2 ; [[ ''{0}'' = https* ]] && curl --proto ''=https'' --tlsv1.2 -sSf {0} | bash || cat $(cygpath -m ''{0}'') | bash ; echo ''Press any key to exit'' && read -n 1' -f $BootstrapUrl, $MsysDir, $GhcupBasePrefix, $GhcupDir, $SilentExport, $CabalDirFull, $StackInstallExport, $HLSInstallExport, $AdjustCabalConfigExport, $MinimalExport)
|
|
}
|
|
|
|
|
|
# SIG # Begin signature block
|
|
# MIID4QYJKoZIhvcNAQcCoIID0jCCA84CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
|
|
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
|
|
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUVqKek181kF/Jx/P7z176herc
|
|
# ZyCgggH/MIIB+zCCAWSgAwIBAgIQGOezhGS1A5tHh9VubW0liDANBgkqhkiG9w0B
|
|
# AQUFADAYMRYwFAYDVQQDDA1KdWxpYW4gT3NwYWxkMB4XDTIxMDUzMDE4Mzk1OVoX
|
|
# DTI1MDUzMDAwMDAwMFowGDEWMBQGA1UEAwwNSnVsaWFuIE9zcGFsZDCBnzANBgkq
|
|
# hkiG9w0BAQEFAAOBjQAwgYkCgYEAs76XCXYPM14buR1RkVKhOB8pyM4Df6kPaz75
|
|
# nkbA0nq1VmMhBfCYFWyYHd7jniqTH0LoAKGGquN1bniREaCP9j2pFWpMIgLpQH3H
|
|
# +jpsfmxV2BTG8q+Jok88gTXS1FlAk72E85zO/Jhr6Fja1aFYAdibBRsRxcVMTVh7
|
|
# 4AGLNGUCAwEAAaNGMEQwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHQYDVR0OBBYEFC+R
|
|
# hdhPo0Ty5HnzHyo1pN35IfZQMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQUF
|
|
# AAOBgQAl3IdBVIwbJJDp7BksMYPeM4ivB3UyNvlw8aVxGwAzNgdSaezYIdMFtKXV
|
|
# CSv5bd4VnFRAPDJW9dhW0h3SkeJUoklUxMjKXhR3qygQhSxPDjIatAuOCffGACba
|
|
# ZZ7Om40b+pKXc6i/HnlApk9DGbXJ59bFcLGGcZ9QjoUae6Ex1DGCAUwwggFIAgEB
|
|
# MCwwGDEWMBQGA1UEAwwNSnVsaWFuIE9zcGFsZAIQGOezhGS1A5tHh9VubW0liDAJ
|
|
# BgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0B
|
|
# CQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAj
|
|
# BgkqhkiG9w0BCQQxFgQUosm9nN1JgajqSBa1cUwxxhLrAsYwDQYJKoZIhvcNAQEB
|
|
# BQAEgYCnKzfsH1aDjS6xkC/uymjaBowHSnh6nFu2AkjcKu8RgcBZzP5SLBXgU9wm
|
|
# aED5Ujwyq3Qre+TGVRUqwkEauDhQiX2A008G00fRO6+di6yJRCRn5eaRAbdU3Xww
|
|
# E5VhEwLBnwzWrvLKtdEclhgUCo5Tq87QMXVdgX4aRmunl4ZE+Q==
|
|
# SIG # End signature block
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|