2021-06-08 21:46:20 +00:00
<#
. 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 "
2021-09-29 09:37:16 +00:00
By default , the installation is non-interactive , unless you run it with 'Interactive $true' .
2021-06-08 21:46:20 +00:00
#>
param (
2021-07-04 17:12:37 +00:00
# Run an interactive installation
[ switch ] $Interactive ,
2021-08-30 11:47:08 +00:00
# Do minimal installation of ghcup and msys2 only
[ switch ] $Minimal ,
2021-07-04 17:12:37 +00:00
# Run the final bootstrap script via 'bash' instead of a full newly spawned msys2 shell
2021-07-12 18:48:05 +00:00
[ switch ] $InBash ,
2021-08-30 11:49:48 +00:00
# Overwrite (or rather backup) a previous install
[ switch ] $Overwrite ,
# Skip adjusting cabal.config with mingw paths
[ switch ] $NoAdjustCabalConfig ,
2021-07-12 18:48:05 +00:00
# Whether to install stack as well
[ switch ] $InstallStack ,
# Whether to install hls as well
[ switch ] $InstallHLS ,
2021-12-06 19:00:17 +00:00
# Specify the install root (default: 'C:\')
2021-08-30 11:49:48 +00:00
[ string ] $InstallDir ,
2021-12-06 19:00:17 +00:00
# Specify the bootstrap url (default: 'https://www.haskell.org/ghcup/sh/bootstrap-haskell')
2021-08-30 11:59:30 +00:00
[ string ] $BootstrapUrl ,
2021-12-06 19:00:17 +00:00
# Instead of installing a new MSys2, use an existing installation
2021-08-30 11:49:48 +00:00
[ string ] $ExistingMsys2Dir ,
# Specify the cabal root directory (default: '$InstallDir\cabal')
2022-07-10 18:51:27 +00:00
[ string ] $CabalDir ,
# Whether to disable use of curl.exe
2022-12-20 12:45:15 +00:00
[ switch ] $DisableCurl ,
# The Msys2 version to download (e.g. 20221216)
2023-07-18 02:02:28 +00:00
[ string ] $Msys2Version ,
# The Msys2 sha256sum hash
[ string ] $Msys2Hash
2021-06-08 21:46:20 +00:00
)
2022-12-20 12:45:15 +00:00
$DefaultMsys2Version = " 20221216 "
2023-07-18 02:02:28 +00:00
$DefaultMsys2Hash = " 18370d32b0264915c97e3d7c618f7b32d48ad80858923883fde5145acd32ca0f "
2022-12-20 12:45:15 +00:00
2021-07-04 17:12:37 +00:00
$Silent = ! $Interactive
2021-05-14 21:09:45 +00:00
function Print-Msg {
2021-06-07 15:06:44 +00:00
param ( [ Parameter ( Mandatory = $true , HelpMessage = 'String to output' ) ] [ string ] $msg , [ string ] $color = " Green " )
Write-Host ( '{0}' -f $msg ) -ForegroundColor $color
2021-05-14 21:09:45 +00:00
}
function Create-Shortcut {
2021-10-13 16:56:59 +00:00
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 )
2021-05-14 21:09:45 +00:00
$WshShell = New-Object -comObject WScript . Shell
2021-10-13 16:56:59 +00:00
$Shortcut = $WshShell . CreateShortcut ( $TmpFile )
2021-05-14 21:09:45 +00:00
$Shortcut . TargetPath = $SourceExe
if ( $ArgumentsToSourceExe ) {
$Shortcut . Arguments = $ArgumentsToSourceExe
}
$Shortcut . Save ( )
2021-10-13 16:56:59 +00:00
if ( ( Test-Path -Path ( '{0}' -f $FinalDest ) ) ) {
Remove-Item -LiteralPath $FinalDest -Force
}
Move-Item -LiteralPath $TmpFile -Destination $FinalDest
2021-05-14 21:09:45 +00:00
}
function Add-EnvPath {
2021-06-08 21:46:20 +00:00
param (
[ Parameter ( Mandatory = $true , HelpMessage = 'The Path to add to Users environment' ) ]
[ string ] $Path ,
2021-05-14 21:09:45 +00:00
2021-06-08 21:46:20 +00:00
[ ValidateSet ( 'Machine' , 'User' , 'Session' ) ]
[ string ] $Container = 'Session'
)
2021-05-14 21:09:45 +00:00
2021-06-08 21:46:20 +00:00
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' }
2021-05-14 21:09:45 +00:00
}
2021-06-08 21:46:20 +00:00
$hiveKey = $envKey = $null
try {
2021-06-11 12:36:52 +00:00
$hiveKey = [ Microsoft.Win32.RegistryKey ] :: OpenRemoteBaseKey ( $hive , '' )
2021-06-08 21:46:20 +00:00
$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 {
2021-06-11 12:36:52 +00:00
if ( $envKey ) { $envKey . Close ( ) }
if ( $hiveKey ) { $hiveKey . Close ( ) }
2021-06-08 21:46:20 +00:00
}
}
2021-05-14 21:09:45 +00:00
}
2021-06-08 21:46:20 +00:00
2021-05-14 21:09:45 +00:00
filter Get-FileSize {
'{0:N2} {1}' -f $ (
if ( $_ -lt 1 kb ) { $_ , 'Bytes' }
elseif ( $_ -lt 1 mb ) { ( $_ / 1 kb ) , 'KB' }
elseif ( $_ -lt 1 gb ) { ( $_ / 1 mb ) , 'MB' }
elseif ( $_ -lt 1 tb ) { ( $_ / 1 gb ) , 'GB' }
elseif ( $_ -lt 1 pb ) { ( $_ / 1 tb ) , 'TB' }
else { ( $_ / 1 pb ) , '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
}
2021-06-08 11:57:01 +00:00
function Test-AbsolutePath {
Param (
[ Parameter ( Mandatory = $True ) ]
[ ValidateScript ( { [ System.IO.Path ] :: IsPathRooted ( $_ ) } ) ]
[ String ] $Path
)
}
2021-06-09 12:43:36 +00:00
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 )
}
}
}
2021-05-14 21:09:45 +00:00
$ErrorActionPreference = 'Stop'
2021-06-08 21:46:20 +00:00
$GhcupBasePrefixEnv = [ System.Environment ] :: GetEnvironmentVariable ( 'GHCUP_INSTALL_BASE_PREFIX' , 'user' )
2021-06-08 11:57:01 +00:00
2021-08-14 12:44:00 +00:00
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
}
}
}
2021-06-08 21:46:20 +00:00
if ( $GhcupBasePrefixEnv ) {
$defaultGhcupBasePrefix = $GhcupBasePrefixEnv
2021-08-31 16:57:38 +00:00
} elseif ( ! ( $InstallDir ) ) {
2021-07-04 17:12:37 +00:00
$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
}
2021-06-08 11:57:01 +00:00
}
2021-07-12 18:48:05 +00:00
# ask for base install prefix
2021-06-08 21:46:20 +00:00
if ( $Silent -and ! ( $InstallDir ) ) {
$GhcupBasePrefix = $defaultGhcupBasePrefix
} elseif ( $InstallDir ) {
if ( ! ( Test-Path -LiteralPath ( '{0}' -f $InstallDir ) -IsValid ) ) {
2021-08-31 16:57:38 +00:00
Print-Msg -color Red -msg " Not a valid directory! (InstallDir) "
2021-06-08 21:46:20 +00:00
Exit 1
} elseif ( ! ( Split-Path -IsAbsolute -Path " $InstallDir " ) ) {
2021-08-31 16:57:38 +00:00
Print-Msg -color Red -msg " Non-absolute Path specified! (InstallDir) "
2021-06-08 21:46:20 +00:00
Exit 1
2021-06-08 11:57:01 +00:00
} else {
2021-06-08 21:46:20 +00:00
$GhcupBasePrefix = $InstallDir
}
} else {
while ( $true ) {
2022-05-04 12:41:39 +00:00
Print-Msg -color Magenta -msg ( @ '
Welcome to Haskell !
2022-06-11 05:06:54 +00:00
This script can download and install the following programs :
2022-05-04 12:41:39 +00:00
* 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
2022-05-09 10:41:54 +00:00
Please note that ANTIVIRUS may interfere with the installation . If you experience problems , consider
2022-05-04 12:41:39 +00:00
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 )
2021-06-08 21:46:20 +00:00
$basePrefixPrompt = Read-Host
$GhcupBasePrefix = ( $defaultGhcupBasePrefix , $basePrefixPrompt ) [ [bool ] $basePrefixPrompt ]
if ( ! ( $GhcupBasePrefix . EndsWith ( '\' ) ) ) {
$GhcupBasePrefix = ( '{0}\' -f $GhcupBasePrefix )
}
2021-11-13 19:35:50 +00:00
$GhcupBasePrefix = $GhcupBasePrefix . TrimEnd ( ) . TrimStart ( )
2021-06-08 21:46:20 +00:00
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
}
2021-06-08 11:57:01 +00:00
}
}
2021-06-08 21:46:20 +00:00
2021-06-08 11:57:01 +00:00
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 )
2021-08-31 16:57:38 +00:00
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 )
}
2021-05-14 21:09:45 +00:00
$Bash = ( '{0}\usr\bin\bash' -f $MsysDir )
2021-07-04 17:12:37 +00:00
if ( ! ( $BootstrapUrl ) ) {
$BootstrapUrl = 'https://www.haskell.org/ghcup/sh/bootstrap-haskell'
}
2021-06-07 15:06:44 +00:00
$GhcupMsys2 = [ System.Environment ] :: GetEnvironmentVariable ( 'GHCUP_MSYS2' , 'user' )
2021-05-14 21:09:45 +00:00
Print-Msg -msg 'Preparing for GHCup installation...'
2021-07-12 18:48:05 +00:00
# ask what to do in case ghcup is already installed
2021-06-08 11:57:01 +00:00
if ( Test-Path -LiteralPath ( '{0}' -f $GhcupDir ) ) {
2021-06-08 21:46:20 +00:00
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?'
2021-06-09 12:43:48 +00:00
, [ System.Management.Automation.Host.ChoiceDescription[] ] @ ( '&Reinstall'
2021-06-08 21:46:20 +00:00
'&Continue'
'&Abort' ) , 1 )
} else {
$decision = 1
}
2021-05-14 21:09:45 +00:00
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 ) {
2021-06-08 21:46:20 +00:00
Exit 0
2021-05-14 21:09:45 +00:00
}
}
$null = New-Item -Path ( '{0}' -f $GhcupDir ) -ItemType 'directory' -ErrorAction SilentlyContinue
$null = New-Item -Path ( '{0}' -f $GhcupDir ) -Name 'bin' -ItemType 'directory' -ErrorAction SilentlyContinue
2021-07-12 18:48:05 +00:00
# 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 )
2021-07-26 16:14:07 +00:00
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 " )
2021-07-12 18:48:05 +00:00
$CabalDirPrompt = Read-Host
$CabDirEnv = ( $defaultCabalDir , $CabalDirPrompt ) [ [bool ] $CabalDirPrompt ]
2021-05-14 21:09:45 +00:00
2021-11-13 19:35:50 +00:00
$CabDirEnv = $CabDirEnv . TrimEnd ( ) . TrimStart ( )
2021-07-12 18:48:05 +00:00
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...'
2021-06-08 11:57:01 +00:00
if ( ! ( Test-Path -Path ( '{0}' -f $MsysDir ) ) ) {
2021-06-08 21:46:20 +00:00
if ( $Silent ) {
$msys2Decision = 0
} else {
$msys2Decision = $Host . UI . PromptForChoice ( 'Install MSys2'
, 'Do you want GHCup to install a default MSys2 toolchain (recommended)?'
2021-06-09 12:43:48 +00:00
, [ System.Management.Automation.Host.ChoiceDescription[] ] @ ( '&Yes'
2021-06-08 21:46:20 +00:00
'&No' ) , 0 )
}
2021-06-07 15:06:44 +00:00
if ( $msys2Decision -eq 0 ) {
2021-07-13 12:50:22 +00:00
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
2021-05-14 21:09:45 +00:00
# Download the archive
2022-12-20 12:45:15 +00:00
if ( ! ( $Msys2Version ) ) {
$Msys2Version = $DefaultMsys2Version
}
2023-07-18 02:02:28 +00:00
if ( ! ( $Msys2Hash ) ) {
$Msys2Hash = $DefaultMsys2Hash
}
2022-12-20 12:45:15 +00:00
Print-Msg -msg ( 'Downloading Msys2 archive {0}...' -f $Msys2Version )
$archive = ( 'msys2-base-x86_64-{0}.sfx.exe' -f $Msys2Version )
2023-07-18 02:02:28 +00:00
$msysUrl = ( 'https://downloads.haskell.org/ghcup/msys2/{0}' -f " $archive " )
2022-02-13 20:11:48 +00:00
$archivePath = ( '{0}\{1}' -f ( [ IO.Path ] :: GetTempPath ( ) ) , " $archive " )
2022-12-20 12:45:15 +00:00
2022-07-10 18:51:27 +00:00
if ( ( Get-Command -Name 'curl.exe' -ErrorAction SilentlyContinue ) -and ! ( $DisableCurl ) ) {
2023-01-21 09:58:26 +00:00
Exec " curl.exe " '-o' " $archivePath " " $msysUrl "
2021-05-14 21:09:45 +00:00
} else {
2023-01-21 09:58:26 +00:00
Get-FileWCSynchronous -url " $msysUrl " -destinationFolder ( [ IO.Path ] :: GetTempPath ( ) ) -includeStats
2021-05-14 21:09:45 +00:00
}
2023-07-18 02:02:28 +00:00
$Msys2HashChecked = Get-FileHash -Algorithm SHA256 " ${archivePath} "
if ( ! ( $Msys2HashChecked . Hash -eq $Msys2Hash ) ) {
Print-Msg -color Red -msg ( " Hashes don't match, got {0}, but expected {1} " -f $Msys2HashChecked , $Msys2Hash )
Exit 1
}
2021-05-14 21:09:45 +00:00
Print-Msg -msg 'Extracting Msys2 archive...'
2022-02-13 20:11:48 +00:00
$null = & " $archivePath " '-y' ( '-o{0}' -f $GhcupDir ) # Extract
Remove-Item -Path " $archivePath "
2021-05-14 21:09:45 +00:00
Print-Msg -msg 'Processing MSYS2 bash for first time use...'
2021-06-09 12:43:36 +00:00
Exec " $Bash " '-lc' 'exit'
2021-05-14 21:09:45 +00:00
2023-07-22 21:41:00 +00:00
Exec " $env:windir \system32\taskkill.exe " / F / FI " MODULES eq msys-2.0.dll "
2021-05-14 21:09:45 +00:00
Print-Msg -msg 'Upgrading full system...'
2021-06-09 12:43:36 +00:00
Exec " $Bash " '-lc' 'pacman --noconfirm -Syuu'
2021-05-14 21:09:45 +00:00
Print-Msg -msg 'Upgrading full system twice...'
2021-06-09 12:43:36 +00:00
Exec " $Bash " '-lc' 'pacman --noconfirm -Syuu'
2021-05-14 21:09:45 +00:00
2021-07-03 19:11:33 +00:00
Print-Msg -msg 'Installing Dependencies...'
2021-08-10 14:58:37 +00:00
Exec " $Bash " '-lc' 'pacman --noconfirm -S --needed curl autoconf mingw-w64-x86_64-pkgconf'
2021-05-14 21:09:45 +00:00
Print-Msg -msg 'Updating SSL root certificate authorities...'
2021-06-09 12:43:36 +00:00
Exec " $Bash " '-lc' 'pacman --noconfirm -S ca-certificates'
2021-05-14 21:09:45 +00:00
Print-Msg -msg 'Setting default home directory...'
2021-06-09 12:43:36 +00:00
Exec " $Bash " '-lc' " sed -i -e 's/db_home:.* $ /db_home: windows/' /etc/nsswitch.conf "
2021-08-31 20:53:39 +00:00
2021-06-07 15:06:44 +00:00
} elseif ( $msys2Decision -eq 1 ) {
2021-06-08 11:57:01 +00:00
Print-Msg -color Yellow -msg 'Skipping MSys2 installation.'
while ( $true ) {
if ( $GhcupMsys2 ) {
$defaultMsys2Dir = $GhcupMsys2
2021-07-26 16:14:07 +00:00
Print-Msg -color Magenta -msg ( 'Input existing MSys2 toolchain directory.{1}Press enter to accept the default [{0}]:' -f $defaultMsys2Dir , " `n " )
2021-06-08 11:57:01 +00:00
$MsysDirPrompt = Read-Host
$MsysDir = ( $defaultMsys2Dir , $MsysDirPrompt ) [ [bool ] $MsysDirPrompt ]
} else {
Print-Msg -color Magenta -msg 'Input existing MSys2 toolchain directory:'
$MsysDir = Read-Host
}
2021-11-13 19:35:50 +00:00
$MsysDir = $MsysDir . TrimEnd ( ) . TrimStart ( )
2021-06-08 11:57:01 +00:00
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
}
2021-06-07 15:06:44 +00:00
}
2021-06-08 11:57:01 +00:00
Print-Msg -msg ( 'Setting GHCUP_MSYS2 env var to ''{0}''' -f $MsysDir )
2021-06-07 15:06:44 +00:00
$null = [ Environment ] :: SetEnvironmentVariable ( " GHCUP_MSYS2 " , $MsysDir , [ System.EnvironmentVariableTarget ] :: User )
$Bash = ( '{0}\usr\bin\bash' -f $MsysDir )
}
2021-05-14 21:09:45 +00:00
} else {
Print-Msg -msg ( '...Msys2 found in {0} ...skipping Msys2 installation.' -f $MsysDir )
2021-07-13 12:50:22 +00:00
Print-Msg -msg 'Starting installation in 5 seconds, this may take a while...'
Start-Sleep -s 5
2021-05-14 21:09:45 +00:00
}
Print-Msg -msg 'Creating shortcuts...'
2021-07-07 21:14:26 +00:00
$uninstallShortCut = @ '
2021-07-26 16:14:07 +00:00
$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
}
2021-07-07 21:14:26 +00:00
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
}
' @
2021-07-03 19:11:33 +00:00
$GhcInstArgs = '-mingw64 -mintty -c "pacman --noconfirm -S --needed base-devel gettext autoconf make libtool automake python p7zip patch unzip"'
2021-10-13 16:56:59 +00:00
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 " )
2021-07-07 21:14:26 +00:00
$null = New-Item -Path $DesktopDir -Name " Uninstall Haskell.ps1 " -ItemType " file " -Force -Value $uninstallShortCut
2021-05-14 21:09:45 +00:00
Print-Msg -msg ( 'Adding {0}\bin to Users Path...' -f $GhcupDir )
2021-06-08 21:46:20 +00:00
Add-EnvPath -Path ( '{0}\bin' -f ( [ System.IO.Path ] :: GetFullPath ( " $GhcupDir " ) ) ) -Container 'User'
2021-05-14 21:09:45 +00:00
2021-06-10 08:58:24 +00:00
$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 )
2021-05-14 21:09:45 +00:00
Print-Msg -msg 'Starting GHCup installer...'
2021-06-07 12:48:06 +00:00
2021-06-07 15:06:44 +00:00
$Msys2Shell = ( '{0}\msys2_shell.cmd' -f $MsysDir )
2021-07-12 18:48:05 +00:00
# The bootstrap script is always silent, since we ask relevant questions here
$SilentExport = 'export BOOTSTRAP_HASKELL_NONINTERACTIVE=1 ;'
2022-11-10 14:38:30 +00:00
if ( ! ( $InstallStack ) ) {
$StackInstallExport = 'export BOOTSTRAP_HASKELL_INSTALL_NO_STACK=1 ;'
2021-07-12 18:48:05 +00:00
}
if ( $InstallHLS ) {
$HLSInstallExport = 'export BOOTSTRAP_HASKELL_INSTALL_HLS=1 ;'
}
if ( ! ( $NoAdjustCabalConfig ) ) {
$AdjustCabalConfigExport = 'export BOOTSTRAP_HASKELL_ADJUST_CABAL_CONFIG=1 ;'
2021-06-08 21:46:20 +00:00
}
2021-08-30 09:18:11 +00:00
if ( $Minimal ) {
$MinimalExport = 'export BOOTSTRAP_HASKELL_MINIMAL=1 ;'
}
2022-07-10 18:51:27 +00:00
if ( $DisableCurl ) {
$BootstrapDownloader = 'export BOOTSTRAP_HASKELL_DOWNLOADER=wget ;'
$DownloadScript = 'wget -O /dev/stdout'
} else {
$DownloadScript = 'curl --proto ''=https'' --tlsv1.2 -sSf'
}
2021-07-04 17:12:37 +00:00
if ( ( Get-Process -ID $PID ) . ProcessName . StartsWith ( " bootstrap-haskell " ) -Or $InBash ) {
2022-07-10 18:51:27 +00:00
Exec " $Bash " '-lc' ( '{4} {6} {7} {8} {9} {10} [ -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* ]] && {11} {0} | bash || cat $(cygpath -m ''{0}'') | bash' -f $BootstrapUrl , $MsysDir , $GhcupBasePrefix , $GhcupDir , $SilentExport , $CabalDirFull , $StackInstallExport , $HLSInstallExport , $AdjustCabalConfigExport , $MinimalExport , $BootstrapDownloader , $DownloadScript )
2021-06-07 12:48:06 +00:00
} else {
2022-12-20 14:46:33 +00:00
Exec " $Msys2Shell " '-mingw64' '-mintty' '-shell' 'bash' '-c' ( '{4} {6} {7} {8} {9} {10} [ -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* ]] && {11} {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 , $BootstrapDownloader , $DownloadScript )
2021-06-07 12:48:06 +00:00
}
2021-05-14 21:09:45 +00:00
# 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
2021-06-11 20:12:23 +00:00
2021-07-03 19:11:33 +00:00
2021-07-04 17:12:37 +00:00
2021-07-12 18:48:05 +00:00