From e96c8631207bdc9b3cfdc2ead4f882fc7802393e Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Sat, 3 Jul 2021 21:11:33 +0200 Subject: [PATCH 1/2] Speed up installation wrt #151 --- bootstrap-haskell.ps1 | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/bootstrap-haskell.ps1 b/bootstrap-haskell.ps1 index 5d9859e..2d1bac4 100644 --- a/bootstrap-haskell.ps1 +++ b/bootstrap-haskell.ps1 @@ -21,8 +21,6 @@ param ( [string]$ExistingMsys2Dir, # Specify the cabal root directory (default: '$InstallDir\cabal') [string]$CabalDir, - # Perform a quick installation, omitting some expensive operations (you may have to install dependencies yourself later) - [bool]$Quick, # Overwrite (or rather backup) a previous install [bool]$Overwrite ) @@ -268,20 +266,8 @@ if (!(Test-Path -Path ('{0}' -f $MsysDir))) { Print-Msg -msg 'Upgrading full system twice...' Exec "$Bash" '-lc' 'pacman --noconfirm -Syuu' - if ($Quick) { - $ghcBuildDeps = $Quick - } elseif (!($Silent)) { - $ghcBuildDeps = $Host.UI.PromptForChoice('Install Dependencies' - , 'Install a standard set of mingw64 packages to be able to build various haskell packages requiring unix libraries? (recommended, however this might take a while... if you skip this, you might have to do it manually later)' - , [System.Management.Automation.Host.ChoiceDescription[]] @('&Yes' - '&No'), 0) - } else { - $ghcBuildDeps = 0 - } - if ($ghcBuildDeps -eq 0) { - Print-Msg -msg 'Installing Dependencies...' - Exec "$Bash" '-lc' 'pacman --noconfirm -S --needed git tar curl wget base-devel gettext binutils autoconf make libtool automake pkgconf python p7zip patch unzip' - } + Print-Msg -msg 'Installing Dependencies...' + Exec "$Bash" '-lc' 'pacman --noconfirm -S --needed curl mingw-w64-x86_64-pkgconf' Print-Msg -msg 'Updating SSL root certificate authorities...' Exec "$Bash" '-lc' 'pacman --noconfirm -S ca-certificates' @@ -320,6 +306,8 @@ if (!(Test-Path -Path ('{0}' -f $MsysDir))) { Print-Msg -msg 'Creating shortcuts...' $DesktopDir = [Environment]::GetFolderPath("Desktop") +$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 ('{0}\Install GHC dev dependencies.lnk' -f $DesktopDir) Create-Shortcut -SourceExe ('{0}\msys2_shell.cmd' -f $MsysDir) -ArgumentsToSourceExe '-mingw64' -DestinationPath ('{0}\Mingw haskell shell.lnk' -f $DesktopDir) Create-Shortcut -SourceExe 'https://www.msys2.org/docs/package-management' -ArgumentsToSourceExe '' -DestinationPath ('{0}\Mingw package management docs.url' -f $DesktopDir) @@ -400,3 +388,5 @@ if ((Get-Process -ID $PID).ProcessName.StartsWith("bootstrap-haskell")) { # E5VhEwLBnwzWrvLKtdEclhgUCo5Tq87QMXVdgX4aRmunl4ZE+Q== # SIG # End signature block + + From 19e46dac1831848b5fa88514e5aaeca54cb3ae53 Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Sun, 4 Jul 2021 19:12:37 +0200 Subject: [PATCH 2/2] Avoid too many questions --- .gitlab-ci.yml | 17 ++++ bootstrap-haskell | 178 +++++++++++++++++++++++------------------- bootstrap-haskell.ps1 | 46 +++++++++-- 3 files changed, 154 insertions(+), 87 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a62f686..afa2ab0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -221,6 +221,23 @@ test:linux:bootstrap_script: CABAL_VERSION: "3.4.0.0" extends: - .debian + - .root_cleanup + needs: [] + +test:windows:bootstrap_powershell_script: + stage: test + script: + - ./bootstrap-haskell.ps1 -InstallDir $CI_PROJECT_DIR -BootstrapUrl $CI_PROJECT_DIR/bootstrap-haskell -InBash + after_script: + - "[Environment]::SetEnvironmentVariable('GHCUP_INSTALL_BASE_PREFIX', $null, [System.EnvironmentVariableTarget]::User)" + - "[Environment]::SetEnvironmentVariable('GHCUP_MSYS2', $null, [System.EnvironmentVariableTarget]::User)" + - "[Environment]::SetEnvironmentVariable('CABAL_DIR', $null, [System.EnvironmentVariableTarget]::User)" + - bash ./.gitlab/after_script.sh + variables: + GHC_VERSION: "8.10.5" + CABAL_VERSION: "3.4.0.0" + extends: + - .windows needs: [] ######## linux test ######## diff --git a/bootstrap-haskell b/bootstrap-haskell index b8d0e0a..bd02859 100755 --- a/bootstrap-haskell +++ b/bootstrap-haskell @@ -210,6 +210,90 @@ download_ghcup() { eghcup upgrade } +adjust_bashrc() { + case $SHELL in + */zsh) # login shell is zsh + GHCUP_PROFILE_FILE="$HOME/.zshrc" + MY_SHELL="zsh" ;; + */bash) # login shell is bash + GHCUP_PROFILE_FILE="$HOME/.bashrc" + MY_SHELL="bash" ;; + */sh) # login shell is sh, but might be a symlink to bash or zsh + if [ -n "${BASH}" ] ; then + GHCUP_PROFILE_FILE="$HOME/.bashrc" + MY_SHELL="bash" + elif [ -n "${ZSH_VERSION}" ] ; then + GHCUP_PROFILE_FILE="$HOME/.zshrc" + MY_SHELL="zsh" + else + return + fi + ;; + */fish) # login shell is fish + GHCUP_PROFILE_FILE="$HOME/.config/fish/config.fish" + MY_SHELL="fish" ;; + *) return ;; + esac + + + warn "" + warn "Detected ${MY_SHELL} shell on your system..." + warn "If you want ghcup to automatically add the required PATH variable to \"${GHCUP_PROFILE_FILE}\"" + warn "" + warn "[Y] Yes [N] No [?] Help (default is \"Y\")." + warn "" + + while true; do + if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then + read -r next_answer > "${GHCUP_PROFILE_FILE}" + break ;; + bash) + sed -i -e '/# ghcup-env$/ s/^#*/#/' "${GHCUP_PROFILE_FILE}" + echo "[ -f \"${GHCUP_DIR}/env\" ] && source \"${GHCUP_DIR}/env\" # ghcup-env" >> "${GHCUP_PROFILE_FILE}" + case "${plat}" in + "Darwin"|"darwin") + if ! grep -q "ghcup-env" "${HOME}/.bash_profile" ; then + echo "[[ -f ~/.bashrc ]] && source ~/.bashrc # ghcup-env" >> "${HOME}/.bash_profile" + fi + ;; + esac + break ;; + + zsh) + sed -i -e '/# ghcup-env$/ s/^#*/#/' "${GHCUP_PROFILE_FILE}" + echo "[ -f \"${GHCUP_DIR}/env\" ] && source \"${GHCUP_DIR}/env\" # ghcup-env" >> "${GHCUP_PROFILE_FILE}" + break ;; + esac + warn "OK! ${GHCUP_PROFILE_FILE} has been modified. Restart your terminal for the changes to take effect," + warn "or type \"source ${GHCUP_DIR}/env\" to apply them in your current terminal session." + return + ;; + *) + echo "Possible choices are:" + echo + echo "Y - Yes, update my \"${GHCUP_PROFILE_FILE}\" (default)" + echo "N - No, don't mess with my configuration" + echo + echo "Please make your choice and press ENTER." + ;; + esac + done +} + echo echo "Welcome to Haskell!" @@ -317,6 +401,7 @@ esac edo cabal new-update + if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then warn "Do you want to install haskell-language-server (HLS) now?" warn "HLS is a language-server that provides IDE-like functionality" @@ -372,89 +457,24 @@ if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then ;; esac done +fi - echo "In order to run ghc and cabal, you need to adjust your PATH variable." - echo "You may want to source '$GHCUP_DIR/env' in your shell" - echo "configuration to do so (e.g. ~/.bashrc)." +# short-circuit script based on platform +case "${plat}" in + MSYS*|MINGW*) + # For windows we always adjust bashrc, since it's inside msys2 + adjust_bashrc + ;; + *) + if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then + echo "In order to run ghc and cabal, you need to adjust your PATH variable." + echo "You may want to source '$GHCUP_DIR/env' in your shell" + echo "configuration to do so (e.g. ~/.bashrc)." - case $SHELL in - */zsh) # login shell is zsh - GHCUP_PROFILE_FILE="$HOME/.zshrc" - MY_SHELL="zsh" ;; - */bash) # login shell is bash - GHCUP_PROFILE_FILE="$HOME/.bashrc" - MY_SHELL="bash" ;; - */sh) # login shell is sh, but might be a symlink to bash or zsh - if [ -n "${BASH}" ] ; then - GHCUP_PROFILE_FILE="$HOME/.bashrc" - MY_SHELL="bash" - elif [ -n "${ZSH_VERSION}" ] ; then - GHCUP_PROFILE_FILE="$HOME/.zshrc" - MY_SHELL="zsh" - else - _done + adjust_bashrc fi ;; - */fish) # login shell is fish - GHCUP_PROFILE_FILE="$HOME/.config/fish/config.fish" - MY_SHELL="fish" ;; - *) _done ;; - esac - - - warn "" - warn "Detected ${MY_SHELL} shell on your system..." - warn "If you want ghcup to automatically add the required PATH variable to \"${GHCUP_PROFILE_FILE}\"" - warn "" - warn "[Y] Yes [N] No [?] Help (default is \"Y\")." - warn "" - - while true; do - read -r next_answer > "${GHCUP_PROFILE_FILE}" - break ;; - bash) - sed -i -e '/# ghcup-env$/ s/^#*/#/' "${GHCUP_PROFILE_FILE}" - echo "[ -f \"${GHCUP_DIR}/env\" ] && source \"${GHCUP_DIR}/env\" # ghcup-env" >> "${GHCUP_PROFILE_FILE}" - case "${plat}" in - "Darwin"|"darwin") - if ! grep -q "ghcup-env" "${HOME}/.bash_profile" ; then - echo "[[ -f ~/.bashrc ]] && source ~/.bashrc # ghcup-env" >> "${HOME}/.bash_profile" - fi - ;; - esac - break ;; - - zsh) - sed -i -e '/# ghcup-env$/ s/^#*/#/' "${GHCUP_PROFILE_FILE}" - echo "[ -f \"${GHCUP_DIR}/env\" ] && source \"${GHCUP_DIR}/env\" # ghcup-env" >> "${GHCUP_PROFILE_FILE}" - break ;; - esac - warn "OK! ${GHCUP_PROFILE_FILE} has been modified. Restart your terminal for the changes to take effect," - warn "or type \"source ${GHCUP_DIR}/env\" to apply them in your current terminal session." - _done - ;; - *) - echo "Possible choices are:" - echo - echo "Y - Yes, update my \"${GHCUP_PROFILE_FILE}\" (default)" - echo "N - No, don't mess with my configuration" - echo - echo "Please make your choice and press ENTER." - ;; - esac - done -fi +esac _done diff --git a/bootstrap-haskell.ps1 b/bootstrap-haskell.ps1 index 2d1bac4..7a7cbce 100644 --- a/bootstrap-haskell.ps1 +++ b/bootstrap-haskell.ps1 @@ -13,8 +13,8 @@ * hls - (optional) A language server for developers to integrate with their editor/IDE" #> param ( - # Run a non-interactive installation - [switch]$Silent, + # Run an interactive installation + [switch]$Interactive, # Specify the install root (default: 'C:\') [string]$InstallDir, # Instead of installing a new MSys2, use an existing installation @@ -22,9 +22,15 @@ param ( # Specify the cabal root directory (default: '$InstallDir\cabal') [string]$CabalDir, # Overwrite (or rather backup) a previous install - [bool]$Overwrite + [switch]$Overwrite, + # Specify the bootstrap url (default: 'https://www.haskell.org/ghcup/sh/bootstrap-haskell') + [string]$BootstrapUrl, + # Run the final bootstrap script via 'bash' instead of a full newly spawned msys2 shell + [switch]$InBash ) +$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 @@ -149,7 +155,27 @@ $GhcupBasePrefixEnv = [System.Environment]::GetEnvironmentVariable('GHCUP_INSTAL if ($GhcupBasePrefixEnv) { $defaultGhcupBasePrefix = $GhcupBasePrefixEnv } else { - $defaultGhcupBasePrefix = 'C:\' + $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 + } } if ($Silent -and !($InstallDir)) { @@ -192,7 +218,9 @@ $null = [Environment]::SetEnvironmentVariable("GHCUP_INSTALL_BASE_PREFIX", $Ghcu $GhcupDir = ('{0}\ghcup' -f $GhcupBasePrefix) $MsysDir = ('{0}\msys64' -f $GhcupDir) $Bash = ('{0}\usr\bin\bash' -f $MsysDir) -$BootstrapUrl = 'https://www.haskell.org/ghcup/sh/bootstrap-haskell' +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...' @@ -357,10 +385,10 @@ if ($Silent) { $SilentExport = '' } -if ((Get-Process -ID $PID).ProcessName.StartsWith("bootstrap-haskell")) { - Exec "$Bash" '-lc' ('{4} [ -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}'' ; curl --proto ''=https'' --tlsv1.2 -sSf {0} | bash' -f $BootstrapUrl, $MsysDir, $GhcupBasePrefix, $GhcupDir, $SilentExport, $CabalDirFull) +if ((Get-Process -ID $PID).ProcessName.StartsWith("bootstrap-haskell") -Or $InBash) { + Exec "$Bash" '-lc' ('{4} [ -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) } else { - Exec "$Msys2Shell" '-mingw64' '-mintty' '-c' ('{4} [ -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 ; curl --proto =https --tlsv1.2 -sSf -k {0} | bash ; echo ''Press any key to exit'' && read -n 1' -f $BootstrapUrl, $MsysDir, $GhcupBasePrefix, $GhcupDir, $SilentExport, $CabalDirFull) + Exec "$Msys2Shell" '-mingw64' '-mintty' '-c' ('{4} [ -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) } @@ -390,3 +418,5 @@ if ((Get-Process -ID $PID).ProcessName.StartsWith("bootstrap-haskell")) { + +