Compare commits

..

34 Commits

Author SHA1 Message Date
ee778e1177 Print bindir 2022-05-11 20:13:24 +02:00
c733810fdc Bump version to 0.1.17.8 2022-05-11 16:19:34 +02:00
5130cb013b Fix HLS not cleaning up after failed install, fix #361 2022-05-11 16:18:35 +02:00
991e540c11 Refactor code around isolateDirs, so we have proper knowledge 2022-05-11 16:18:35 +02:00
a34d9b7b89 Fix type in bootstrap-haskell.ps1 2022-05-09 12:41:54 +02:00
4e62f559fa Update stackage resolver 2022-05-09 12:40:42 +02:00
8c3d2b6740 Merge branch 'improve-pwsh' 2022-05-04 16:05:00 +02:00
b6779f4d75 Improve welcome message in powershell installer
And warn about antivirus, fixes #343
2022-05-04 14:45:05 +02:00
02cd773c2a Update supported tools table 2022-05-03 11:40:05 +02:00
3964d06f5d Merge remote-tracking branch 'origin/merge-requests/249' 2022-05-02 19:06:48 +02:00
Nick Suchecki
e83612a06c Fix typo in compile hls --help subcommand. 2022-05-01 15:12:39 +00:00
cf6c666b59 Add credits to first step guide 2022-04-30 12:50:34 +02:00
ee0ec370c7 Add playground link 2022-04-29 18:55:45 +02:00
ea0e35ddf0 Merge branch 'issue-353' 2022-04-29 16:47:37 +02:00
99c8501d47 Silence hlint 2022-04-29 16:47:11 +02:00
f8a1fed1f2 Fix parsing of symlinks with multiple slashes,
Fixes #353
2022-04-29 19:22:16 +08:00
9ad1f7cb97 Update changelog 2022-04-21 23:38:58 +02:00
0856a96738 Bump ghcup in bootstrap-script 2022-04-21 23:02:30 +02:00
ee9801a8c2 Add GHCUP_BASE_URL env var for bootstrap-haskell 2022-04-18 13:22:20 +02:00
cfecc11b43 Bump version to 0.1.17.7 2022-04-16 06:42:01 +02:00
3d36348563 Merge branch 'issue-345' 2022-04-16 06:40:08 +02:00
dcbee9c7dc Fix tests 2022-04-15 23:01:34 +02:00
2d88b1197e Fix EXDEV handler on windows wrt #345 2022-04-15 23:01:33 +02:00
6c12dc0d6f Overhaul user guide 2022-04-07 20:55:45 +02:00
a4b69f29dc Update first steps guide link 2022-04-02 23:36:16 +02:00
1680c5c448 Improvements 2022-04-02 23:31:35 +02:00
e74fb45680 Small mkdocs improvements 2022-04-02 20:11:09 +02:00
d19ab05a11 Add First steps guide initially by soupi
https://github.com/haskell-infra/www.haskell.org/pull/88
2022-04-02 19:45:50 +02:00
433c73b23c Update CHANGELOG 2022-03-18 23:26:15 +01:00
2aa5211886 Bump version in bootstrap-haskell 2022-03-18 23:25:49 +01:00
81e7c02807 Update docs 2022-03-18 18:45:29 +01:00
a2373f2056 Improve bootstrap-haskell and fix shellcheck warnings 2022-03-18 18:24:50 +01:00
ba8e4f6ac6 Update changelog 2022-03-18 17:50:36 +01:00
76acc9a5f5 Merge branch 'max_path' 2022-03-18 17:48:58 +01:00
20 changed files with 792 additions and 330 deletions

View File

@@ -176,6 +176,8 @@ else
[ "$(ghc --numeric-version)" = "${ghc_ver}" ] [ "$(ghc --numeric-version)" = "${ghc_ver}" ]
ls -lah "$GHCUP_BIN"
if [ "${OS}" = "DARWIN" ] ; then if [ "${OS}" = "DARWIN" ] ; then
eghcup install hls eghcup install hls
$(eghcup whereis hls) --version $(eghcup whereis hls) --version

View File

@@ -1,6 +1,16 @@
# Revision history for ghcup # Revision history for ghcup
## 0.1.17.6 -- ????-??-?? ## 0.1.17.8 -- XXXX-XX-XX
* Fix HLS build not cleaning up properly on failed installations, fixes [#361](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/361)
- this also fixes a significant bug on installation failure when combining `--isolate DIR` with `--force`
* Fix parsing of symlinks with multiple slashes, wrt [#353](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/353)
## 0.1.17.7 -- 2022-04-21
* Fix `ghcup run` on windows wrt [#345](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/345)
## 0.1.17.6 -- 2022-03-18
* Vastly improve shell completions wrt [#242](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/242) * Vastly improve shell completions wrt [#242](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/242)
* Fix 'ghcup install cabal/hls/stack --set' wrt [#324](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/324) * Fix 'ghcup install cabal/hls/stack --set' wrt [#324](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/324)
@@ -10,6 +20,7 @@
* Add `--no-set` to install commands, fixes [#330](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/330) * Add `--no-set` to install commands, fixes [#330](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/330)
* Fix serious bug in `ghcup list --raw-format -t <tool> -c installed` * Fix serious bug in `ghcup list --raw-format -t <tool> -c installed`
* Overhaul metadata merging and add `ghcup config add-release-channel URI` wrt [#328](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/328) * Overhaul metadata merging and add `ghcup config add-release-channel URI` wrt [#328](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/328)
* Fix max path issues on windows with `ghcup run`
## 0.1.17.5 -- 2022-02-26 ## 0.1.17.5 -- 2022-02-26

View File

@@ -446,19 +446,19 @@ install' _ (_, ListResult {..}) = do
case lTool of case lTool of
GHC -> do GHC -> do
let vi = getVersionInfo lVer GHC dls let vi = getVersionInfo lVer GHC dls
liftE $ installGHCBin lVer Nothing False $> (vi, dirs, ce) liftE $ installGHCBin lVer GHCupInternal False $> (vi, dirs, ce)
Cabal -> do Cabal -> do
let vi = getVersionInfo lVer Cabal dls let vi = getVersionInfo lVer Cabal dls
liftE $ installCabalBin lVer Nothing False $> (vi, dirs, ce) liftE $ installCabalBin lVer GHCupInternal False $> (vi, dirs, ce)
GHCup -> do GHCup -> do
let vi = snd <$> getLatest dls GHCup let vi = snd <$> getLatest dls GHCup
liftE $ upgradeGHCup Nothing False $> (vi, dirs, ce) liftE $ upgradeGHCup Nothing False $> (vi, dirs, ce)
HLS -> do HLS -> do
let vi = getVersionInfo lVer HLS dls let vi = getVersionInfo lVer HLS dls
liftE $ installHLSBin lVer Nothing False $> (vi, dirs, ce) liftE $ installHLSBin lVer GHCupInternal False $> (vi, dirs, ce)
Stack -> do Stack -> do
let vi = getVersionInfo lVer Stack dls let vi = getVersionInfo lVer Stack dls
liftE $ installStackBin lVer Nothing False $> (vi, dirs, ce) liftE $ installStackBin lVer GHCupInternal False $> (vi, dirs, ce)
) )
>>= \case >>= \case
VRight (vi, Dirs{..}, Just ce) -> do VRight (vi, Dirs{..}, Just ce) -> do

View File

@@ -283,7 +283,7 @@ hlsCompileOpts =
(short 'g' <> long "git-ref" <> metavar "GIT_REFERENCE" <> help (short 'g' <> long "git-ref" <> metavar "GIT_REFERENCE" <> help
"The git commit/branch/ref to build from" "The git commit/branch/ref to build from"
) <*> ) <*>
optional (option str (short 'r' <> long "repository" <> metavar "GIT_REPOSITORY" <> help "The git repository to build from (defaults to GHC upstream)" optional (option str (short 'r' <> long "repository" <> metavar "GIT_REPOSITORY" <> help "The git repository to build from (defaults to HLS upstream)"
<> completer (gitFileUri ["https://github.com/haskell/haskell-language-server.git"]) <> completer (gitFileUri ["https://github.com/haskell/haskell-language-server.git"])
)) ))
))) )))
@@ -469,7 +469,7 @@ compile compileCommand settings Dirs{..} runAppState runLogger = do
ghcs ghcs
jobs jobs
ovewrwiteVer ovewrwiteVer
isolateDir (maybe GHCupInternal IsolateDir isolateDir)
cabalProject cabalProject
cabalProjectLocal cabalProjectLocal
patches patches
@@ -524,7 +524,7 @@ compile compileCommand settings Dirs{..} runAppState runLogger = do
addConfArgs addConfArgs
buildFlavour buildFlavour
hadrian hadrian
isolateDir (maybe GHCupInternal IsolateDir isolateDir)
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
let vi = getVersionInfo (_tvVersion targetVer) GHC dls let vi = getVersionInfo (_tvVersion targetVer) GHC dls
when setCompile $ void $ liftE $ when setCompile $ void $ liftE $

View File

@@ -216,7 +216,7 @@ installOpts tool =
Nothing -> False Nothing -> False
Just GHC -> False Just GHC -> False
Just _ -> True Just _ -> True
@@ -395,7 +395,7 @@ install installCommand settings getAppState' runLogger = case installCommand of
(v, vi) <- liftE $ fromVersion instVer GHC (v, vi) <- liftE $ fromVersion instVer GHC
void $ liftE $ sequenceE (installGHCBin void $ liftE $ sequenceE (installGHCBin
(_tvVersion v) (_tvVersion v)
isolateDir (maybe GHCupInternal IsolateDir isolateDir)
forceInstall forceInstall
) )
$ when instSet $ when (isNothing isolateDir) $ void $ setGHC v SetGHCOnly Nothing $ when instSet $ when (isNothing isolateDir) $ void $ setGHC v SetGHCOnly Nothing
@@ -406,7 +406,7 @@ install installCommand settings getAppState' runLogger = case installCommand of
void $ liftE $ sequenceE (installGHCBindist void $ liftE $ sequenceE (installGHCBindist
(DownloadInfo uri (Just $ RegexDir "ghc-.*") "") (DownloadInfo uri (Just $ RegexDir "ghc-.*") "")
(_tvVersion v) (_tvVersion v)
isolateDir (maybe GHCupInternal IsolateDir isolateDir)
forceInstall forceInstall
) )
$ when instSet $ when (isNothing isolateDir) $ void $ setGHC v SetGHCOnly Nothing $ when instSet $ when (isNothing isolateDir) $ void $ setGHC v SetGHCOnly Nothing
@@ -467,7 +467,7 @@ install installCommand settings getAppState' runLogger = case installCommand of
(_tvVersion -> v, vi) <- liftE $ fromVersion instVer Cabal (_tvVersion -> v, vi) <- liftE $ fromVersion instVer Cabal
void $ liftE $ sequenceE (installCabalBin void $ liftE $ sequenceE (installCabalBin
v v
isolateDir (maybe GHCupInternal IsolateDir isolateDir)
forceInstall forceInstall
) $ when instSet $ when (isNothing isolateDir) $ void $ setCabal v ) $ when instSet $ when (isNothing isolateDir) $ void $ setCabal v
pure vi pure vi
@@ -477,7 +477,7 @@ install installCommand settings getAppState' runLogger = case installCommand of
void $ liftE $ sequenceE (installCabalBindist void $ liftE $ sequenceE (installCabalBindist
(DownloadInfo uri Nothing "") (DownloadInfo uri Nothing "")
v v
isolateDir (maybe GHCupInternal IsolateDir isolateDir)
forceInstall forceInstall
) $ when instSet $ when (isNothing isolateDir) $ void $ setCabal v ) $ when instSet $ when (isNothing isolateDir) $ void $ setCabal v
pure vi pure vi
@@ -518,7 +518,7 @@ install installCommand settings getAppState' runLogger = case installCommand of
(_tvVersion -> v, vi) <- liftE $ fromVersion instVer HLS (_tvVersion -> v, vi) <- liftE $ fromVersion instVer HLS
void $ liftE $ sequenceE (installHLSBin void $ liftE $ sequenceE (installHLSBin
v v
isolateDir (maybe GHCupInternal IsolateDir isolateDir)
forceInstall forceInstall
) $ when instSet $ when (isNothing isolateDir) $ void $ setHLS v SetHLSOnly Nothing ) $ when instSet $ when (isNothing isolateDir) $ void $ setHLS v SetHLSOnly Nothing
pure vi pure vi
@@ -529,7 +529,7 @@ install installCommand settings getAppState' runLogger = case installCommand of
void $ liftE $ sequenceE (installHLSBindist void $ liftE $ sequenceE (installHLSBindist
(DownloadInfo uri (Just $ RegexDir "haskell-language-server-*") "") (DownloadInfo uri (Just $ RegexDir "haskell-language-server-*") "")
v v
isolateDir (maybe GHCupInternal IsolateDir isolateDir)
forceInstall forceInstall
) $ when instSet $ when (isNothing isolateDir) $ void $ setHLS v SetHLSOnly Nothing ) $ when instSet $ when (isNothing isolateDir) $ void $ setHLS v SetHLSOnly Nothing
pure vi pure vi
@@ -578,7 +578,7 @@ install installCommand settings getAppState' runLogger = case installCommand of
(_tvVersion -> v, vi) <- liftE $ fromVersion instVer Stack (_tvVersion -> v, vi) <- liftE $ fromVersion instVer Stack
void $ liftE $ sequenceE (installStackBin void $ liftE $ sequenceE (installStackBin
v v
isolateDir (maybe GHCupInternal IsolateDir isolateDir)
forceInstall forceInstall
) $ when instSet $ when (isNothing isolateDir) $ void $ setStack v ) $ when instSet $ when (isNothing isolateDir) $ void $ setStack v
pure vi pure vi
@@ -588,7 +588,7 @@ install installCommand settings getAppState' runLogger = case installCommand of
void $ liftE $ sequenceE (installStackBindist void $ liftE $ sequenceE (installStackBindist
(DownloadInfo uri Nothing "") (DownloadInfo uri Nothing "")
v v
isolateDir (maybe GHCupInternal IsolateDir isolateDir)
forceInstall forceInstall
) $ when instSet $ when (isNothing isolateDir) $ void $ setStack v ) $ when instSet $ when (isNothing isolateDir) $ void $ setStack v
pure vi pure vi

View File

@@ -351,25 +351,25 @@ run RunOptions{..} runAppState leanAppstate runLogger = do
Just (GHC, v) -> do Just (GHC, v) -> do
unless isInstalled $ when (runInstTool' && isNothing (_tvTarget v)) $ void $ liftE $ installGHCBin unless isInstalled $ when (runInstTool' && isNothing (_tvTarget v)) $ void $ liftE $ installGHCBin
(_tvVersion v) (_tvVersion v)
Nothing GHCupInternal
False False
setTool GHC v tmp setTool GHC v tmp
Just (Cabal, v) -> do Just (Cabal, v) -> do
unless isInstalled $ when runInstTool' $ void $ liftE $ installCabalBin unless isInstalled $ when runInstTool' $ void $ liftE $ installCabalBin
(_tvVersion v) (_tvVersion v)
Nothing GHCupInternal
False False
setTool Cabal v tmp setTool Cabal v tmp
Just (Stack, v) -> do Just (Stack, v) -> do
unless isInstalled $ when runInstTool' $ void $ liftE $ installStackBin unless isInstalled $ when runInstTool' $ void $ liftE $ installStackBin
(_tvVersion v) (_tvVersion v)
Nothing GHCupInternal
False False
setTool Stack v tmp setTool Stack v tmp
Just (HLS, v) -> do Just (HLS, v) -> do
unless isInstalled $ when runInstTool' $ void $ liftE $ installHLSBin unless isInstalled $ when runInstTool' $ void $ liftE $ installHLSBin
(_tvVersion v) (_tvVersion v)
Nothing GHCupInternal
False False
setTool HLS v tmp setTool HLS v tmp
_ -> pure () _ -> pure ()

View File

@@ -15,7 +15,9 @@ source-repository-package
constraints: http-io-streams -brotli, constraints: http-io-streams -brotli,
any.Cabal ==3.6.2.0, any.Cabal ==3.6.2.0,
any.aeson >= 2.0.1.0 any.aeson >= 2.0.1.0,
-- https://github.com/typeable/generic-arbitrary/issues/14
any.generic-arbitrary < 0.2.1
package libarchive package libarchive
flags: -system-libarchive flags: -system-libarchive

View File

@@ -1,6 +1,6 @@
# User Guide # User Guide
`ghcup --help` is your friend. This is a more in-depth guide specific to GHCup. `ghcup --help` is your friend.
## Basic usage ## Basic usage
@@ -43,13 +43,6 @@ All of the following are valid arguments to `ghcup install ghc`:
If the argument is omitted, the default is `recommended`. If the argument is omitted, the default is `recommended`.
## Configuration
A configuration file can be put in `~/.ghcup/config.yaml`. The default config file
explaining all possible configurations can be found in this repo: [config.yaml](https://gitlab.haskell.org/haskell/ghcup-hs/-/blob/master/data/config.yaml).
Partial configuration is fine. Command line options always override the config file settings.
## Manpages ## Manpages
For man pages to work you need [man-db](http://man-db.nongnu.org/) as your `man` provider, then issue `man ghc`. Manpages only work for the currently set ghc. For man pages to work you need [man-db](http://man-db.nongnu.org/) as your `man` provider, then issue `man ghc`. Manpages only work for the currently set ghc.
@@ -64,6 +57,40 @@ as e.g. `/etc/bash_completion.d/ghcup` (depending on distro)
and make sure your bashrc sources the startup script and make sure your bashrc sources the startup script
(`/usr/share/bash-completion/bash_completion` on some distros). (`/usr/share/bash-completion/bash_completion` on some distros).
# Configuration
A configuration file can be put in `~/.ghcup/config.yaml`. The default config file
explaining all possible configurations can be found in this repo: [config.yaml](https://gitlab.haskell.org/haskell/ghcup-hs/-/blob/master/data/config.yaml).
Partial configuration is fine. Command line options always override the config file settings.
## Env variables
This is the complete list of env variables that change GHCup behavior:
* `GHCUP_USE_XDG_DIRS`: see [XDG support](#xdg-support) above
* `TMPDIR`: where ghcup does the work (unpacking, building, ...)
* `GHCUP_INSTALL_BASE_PREFIX`: the base of ghcup (default: `$HOME`)
* `GHCUP_CURL_OPTS`: additional options that can be passed to curl
* `GHCUP_WGET_OPTS`: additional options that can be passed to wget
* `GHCUP_GPG_OPTS`: additional options that can be passed to gpg
* `GHCUP_SKIP_UPDATE_CHECK`: Skip the (possibly annoying) update check when you run a command
* `CC`/`LD` etc.: full environment is passed to the build system when compiling GHC via GHCup
### XDG support
To enable XDG style directories, set the environment variable `GHCUP_USE_XDG_DIRS` to anything.
Then you can control the locations via XDG environment variables as such:
* `XDG_DATA_HOME`: GHCs will be unpacked in `ghcup/ghc` subdir (default: `~/.local/share`)
* `XDG_CACHE_HOME`: logs and download files will be stored in `ghcup` subdir (default: `~/.cache`)
* `XDG_BIN_HOME`: binaries end up here (default: `~/.local/bin`)
* `XDG_CONFIG_HOME`: the config file is stored in `ghcup` subdir as `config.yaml` (default: `~/.config`)
**Note that `ghcup` makes some assumptions about structure of files in `XDG_BIN_HOME`. So if you have other tools
installing e.g. stack/cabal/ghc into it, this will likely clash. In that case consider disabling XDG support.**
## Caching ## Caching
GHCup has a few caching mechanisms to avoid redownloads. All cached files end up in `~/.ghcup/cache` by default. GHCup has a few caching mechanisms to avoid redownloads. All cached files end up in `~/.ghcup/cache` by default.
@@ -83,6 +110,92 @@ have a 5 minutes cache per default depending on the last access time of the file
If you experience problems, consider clearing the cache via `ghcup gc --cache`. If you experience problems, consider clearing the cache via `ghcup gc --cache`.
## Metadata
The metadata are the files that describe tool versions, where to download them etc. and
can be viewed here: [https://github.com/haskell/ghcup-metadata](https://github.com/haskell/ghcup-metadata)
### Mirrors
GHCup allows to use custom mirrors/download-info hosted by yourself or 3rd parties.
To use a mirror, set the following option in `~/.ghcup/config.yaml`:
```yml
url-source:
# Accepts file/http/https scheme
OwnSource: "https://some-url/ghcup-0.0.6.yaml"
```
See [config.yaml](https://gitlab.haskell.org/haskell/ghcup-hs/-/blob/master/data/config.yaml)
for more options.
Alternatively you can do it via a cli switch:
```sh
ghcup --url-source=https://some-url/ghcup-0.0.6.yaml list
```
#### Known mirrors
1. [https://mirror.sjtu.edu.cn/docs/ghcup](https://mirror.sjtu.edu.cn/docs/ghcup)
### (Pre-)Release channels
A release channel is basically just a metadata file location. You can add additional release
channels that complement the default one, such as the **prerelease channel** like so:
```sh
ghcup config add-release-channel https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.7.yaml
```
This will result in `~/.ghcup/config.yaml` to contain this record:
```yml
url-source:
AddSource:
- Right: https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.7.yaml
```
You can add as many channels as you like. They are combined under *Last*, so versions from the prerelease channel
here overwrite the default ones, if any.
To remove the channel, delete the entire `url-source` section or set it back to the default:
```yml
url-source:
GHCupURL: []
```
If you want to combine your release channel with a mirror, you'd do it like so:
```yml
url-source:
OwnSource:
# base metadata
- "https://mirror.sjtu.edu.cn/ghcup/yaml/ghcup/data/ghcup-0.0.6.yaml"
# prerelease channel
- "https://raw.githubusercontent.com/haskell/ghcup-metadata/master/ghcup-prereleases-0.0.7.yaml"
```
# More on installation
## Installing custom bindists
There are a couple of good use cases to install custom bindists:
1. manually built bindists (e.g. with patches)
- example: `ghcup install ghc -u 'file:///home/mearwald/tmp/ghc-eff-patches/ghc-8.10.2-x86_64-deb10-linux.tar.xz' 8.10.2-eff`
2. GHC head CI bindists
- example: `ghcup install ghc -u 'https://gitlab.haskell.org/api/v4/projects/1/jobs/artifacts/master/raw/ghc-x86_64-fedora27-linux.tar.xz?job=validate-x86_64-linux-fedora27' head`
3. DWARF bindists
- example: `ghcup install ghc -u 'https://downloads.haskell.org/~ghc/8.10.2/ghc-8.10.2-x86_64-deb10-linux-dwarf.tar.xz' 8.10.2-dwarf`
Since the version parser is pretty lax, `8.10.2-eff` and `head` are both valid versions
and produce the binaries `ghc-8.10.2-eff` and `ghc-head` respectively.
GHCup always needs to know which version the bindist corresponds to (this is not automatically
detected).
## Compiling GHC from source ## Compiling GHC from source
Compiling from source is supported for both source tarballs and arbitrary git refs. See `ghcup compile ghc --help` Compiling from source is supported for both source tarballs and arbitrary git refs. See `ghcup compile ghc --help`
@@ -106,74 +219,6 @@ For distributions with non-standard locations of cross toolchain and
libraries, this may need some tweaking of `build.mk` or configure args. libraries, this may need some tweaking of `build.mk` or configure args.
See `ghcup compile ghc --help` for further information. See `ghcup compile ghc --help` for further information.
## XDG support
To enable XDG style directories, set the environment variable `GHCUP_USE_XDG_DIRS` to anything.
Then you can control the locations via XDG environment variables as such:
* `XDG_DATA_HOME`: GHCs will be unpacked in `ghcup/ghc` subdir (default: `~/.local/share`)
* `XDG_CACHE_HOME`: logs and download files will be stored in `ghcup` subdir (default: `~/.cache`)
* `XDG_BIN_HOME`: binaries end up here (default: `~/.local/bin`)
* `XDG_CONFIG_HOME`: the config file is stored in `ghcup` subdir as `config.yaml` (default: `~/.config`)
**Note that `ghcup` makes some assumptions about structure of files in `XDG_BIN_HOME`. So if you have other tools
installing e.g. stack/cabal/ghc into it, this will likely clash. In that case consider disabling XDG support.**
## Env variables
This is the complete list of env variables that change GHCup behavior:
* `GHCUP_USE_XDG_DIRS`: see [XDG support](#xdg-support) above
* `TMPDIR`: where ghcup does the work (unpacking, building, ...)
* `GHCUP_INSTALL_BASE_PREFIX`: the base of ghcup (default: `$HOME`)
* `GHCUP_CURL_OPTS`: additional options that can be passed to curl
* `GHCUP_WGET_OPTS`: additional options that can be passed to wget
* `GHCUP_GPG_OPTS`: additional options that can be passed to gpg
* `GHCUP_SKIP_UPDATE_CHECK`: Skip the (possibly annoying) update check when you run a command
* `CC`/`LD` etc.: full environment is passed to the build system when compiling GHC via GHCup
## Installing custom bindists
There are a couple of good use cases to install custom bindists:
1. manually built bindists (e.g. with patches)
- example: `ghcup install ghc -u 'file:///home/mearwald/tmp/ghc-eff-patches/ghc-8.10.2-x86_64-deb10-linux.tar.xz' 8.10.2-eff`
2. GHC head CI bindists
- example: `ghcup install ghc -u 'https://gitlab.haskell.org/api/v4/projects/1/jobs/artifacts/master/raw/ghc-x86_64-fedora27-linux.tar.xz?job=validate-x86_64-linux-fedora27' head`
3. DWARF bindists
- example: `ghcup install ghc -u 'https://downloads.haskell.org/~ghc/8.10.2/ghc-8.10.2-x86_64-deb10-linux-dwarf.tar.xz' 8.10.2-dwarf`
Since the version parser is pretty lax, `8.10.2-eff` and `head` are both valid versions
and produce the binaries `ghc-8.10.2-eff` and `ghc-head` respectively.
GHCup always needs to know which version the bindist corresponds to (this is not automatically
detected).
## Mirrors
GHCup allows to use custom mirrors/download-info hosted by yourself or 3rd parties.
To use a mirror, set the following option in `~/.ghcup/config.yaml`:
```yml
url-source:
# Accepts file/http/https scheme
OwnSource: "https://some-url/ghcup-0.0.6.yaml"
```
See [config.yaml](https://gitlab.haskell.org/haskell/ghcup-hs/-/blob/master/data/config.yaml)
for more options.
Alternatively you can do it via a cli switch:
```sh
ghcup --url-source=https://some-url/ghcup-0.0.6.yaml list
```
### Known mirrors
1. [https://mirror.sjtu.edu.cn/docs/ghcup](https://mirror.sjtu.edu.cn/docs/ghcup)
## Isolated installs ## Isolated installs
Ghcup also enables you to install a tool (GHC, Cabal, HLS, Stack) at an isolated location of your choosing. Ghcup also enables you to install a tool (GHC, Cabal, HLS, Stack) at an isolated location of your choosing.
@@ -257,9 +302,9 @@ gpg-setting: GPGLax # GPGStrict | GPGLax | GPGNone
In `GPGStrict` mode, ghcup will fail if verification fails. In `GPGLax` mode it will just print a warning. In `GPGStrict` mode, ghcup will fail if verification fails. In `GPGLax` mode it will just print a warning.
You can also pass the mode via `ghcup --gpg <strict|lax|none>`. You can also pass the mode via `ghcup --gpg <strict|lax|none>`.
## Tips and tricks # Tips and tricks
### Execute command with certain GHC in PATH ## ghcup run
If you don't want to explicitly switch the active GHC all the time and are using If you don't want to explicitly switch the active GHC all the time and are using
tools that rely on the plain `ghc` binary, GHCup provides an easy way to execute tools that rely on the plain `ghc` binary, GHCup provides an easy way to execute

View File

@@ -17,6 +17,7 @@ hide:
<div class="text-center main-buttons"> <div class="text-center main-buttons">
<a href="install/" class="btn btn-primary" role="button">Getting Started</a> <a href="install/" class="btn btn-primary" role="button">Getting Started</a>
<a href="steps/" class="btn btn-primary" role="button">First steps</a>
<a href="guide/" class="btn btn-primary" role="button">User Guide</a> <a href="guide/" class="btn btn-primary" role="button">User Guide</a>
</div> </div>

View File

@@ -2,7 +2,7 @@
GHCup makes it easy to install specific versions of GHC on GNU/Linux, GHCup makes it easy to install specific versions of GHC on GNU/Linux,
macOS (aka Darwin), FreeBSD and Windows and can also bootstrap a fresh [Haskell developer environment](./install/#supported-tools) from scratch. macOS (aka Darwin), FreeBSD and Windows and can also bootstrap a fresh [Haskell developer environment](./install/#supported-tools) from scratch.
It follows the unix UNIX philosophy of [do one thing and do it well](https://en.wikipedia.org/wiki/Unix_philosophy#Do_One_Thing_and_Do_It_Well). Similar in scope to [rustup](https://github.com/rust-lang-nursery/rustup.rs), [pyenv](https://github.com/pyenv/pyenv) and [jenv](http://www.jenv.be). It follows the UNIX philosophy of [do one thing and do it well](https://en.wikipedia.org/wiki/Unix_philosophy#Do_One_Thing_and_Do_It_Well). Similar in scope to [rustup](https://github.com/rust-lang-nursery/rustup.rs), [pyenv](https://github.com/pyenv/pyenv) and [jenv](http://www.jenv.be).
## Installation ## Installation
@@ -22,6 +22,8 @@ For Windows, run this in a PowerShell session:
Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -ArgumentList $true Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -ArgumentList $true
``` ```
There's also a [youtube video](https://www.youtube.com/watch?v=bB4fmQiUYPw) explaining installation on windows.
If you want to know what these scripts do, check out the [source code at the repository](https://gitlab.haskell.org/haskell/ghcup-hs/-/tree/master/scripts/bootstrap). Advanced users may want to perform a [manual installation](#manual-install) and GPG verify the binaries. If you want to know what these scripts do, check out the [source code at the repository](https://gitlab.haskell.org/haskell/ghcup-hs/-/tree/master/scripts/bootstrap). Advanced users may want to perform a [manual installation](#manual-install) and GPG verify the binaries.
### Which versions get installed? ### Which versions get installed?
@@ -32,105 +34,98 @@ GHCup has two main channels for every tool: **recommended** and **latest**. By d
Also see [tags and shortcuts](../guide/#tags-and-shortcuts) for more information. Also see [tags and shortcuts](../guide/#tags-and-shortcuts) for more information.
## First steps ## Next steps
1. To get started with creating a Haskell project, follow the [Getting Started with Haskell and Cabal](https://cabal.readthedocs.io/en/stable/getting-started.html) guide 1. Follow the [First steps guide](../steps) on how to build a "Hello world" program, use `ghc`, run an interactive REPL and create a Haskell project
2. To learn Haskell, try any of those: 2. To understand the difference and overlap of `stack` and `cabal`, read on [here](https://gist.github.com/merijn/8152d561fb8b011f9313c48d876ceb07)
- A beginner friendly [4-lectures course](https://github.com/haskell-beginners-2022/course-plan) with exercises (by [Kowainik](https://kowainik.github.io/)) 3. To learn Haskell proper check out the links at [How to learn Haskell proper](../steps#how-to-learn-haskell-proper)
- An in-depth university [CIS 194 Haskell course](https://www.cis.upenn.edu/~cis194/spring13/) including exercises (by [Brent Yorgey](https://byorgey.wordpress.com/)) 4. To learn more about Haskell Toolchain management, check out the [ghcup user guide](./guide.md)
3. To learn more about Haskell Toolchain management, check out the [ghcup user guide](./guide.md)
## Uninstallation ## Uninstallation
On linux, just run `ghcup nuke`, then make sure any ghcup added lines in your `~/.bashrc` (or similar) are removed. On linux, just run `ghcup nuke`, then make sure any ghcup added lines in your `~/.bashrc` (or similar) are removed.
On windows, double-click on the `Uninstall Haskell.ps1` PowerShell script on your Desktop. On windows, right click on the `Uninstall Haskell.ps1` PowerShell script on your Desktop and select *Run with PowerShell*.
## Supported tools ## Supported tools
GHCup supports the following tools, which are also known as the **Haskell Toolchain**: GHCup supports the following tools, which are also known as the **Haskell Toolchain**:
<details> <details> <summary>Show all supported <a href='https://www.haskell.org/ghc/'>GHC</a> versions</summary>
<summary>Show all supported <a href='https://www.haskell.org/ghc/'>GHC</a> versions</summary>
<table> <table>
<thead><tr><th>GHC Version</th><th>Tags</th></tr></thead> <thead><tr><th>GHC Version</th><th>Tags</th></tr></thead>
<tbody> <tbody>
<tr><td>7.10.3</td><td>base-4.8.2.0</td></tr>
<tr><td>8.0.2</td><td>base-4.9.1.0</td></tr>
<tr><td>8.2.2</td><td>base-4.10.1.0</td></tr>
<tr><td>8.4.1</td><td>base-4.11.0.0</td></tr>
<tr><td>8.4.2</td><td>base-4.11.1.0</td></tr>
<tr><td>8.4.3</td><td>base-4.11.1.0</td></tr>
<tr><td>8.4.4</td><td>base-4.11.1.0</td></tr>
<tr><td>8.6.1</td><td>base-4.12.0.0</td></tr>
<tr><td>8.6.2</td><td>base-4.12.0.0</td></tr>
<tr><td>8.6.3</td><td>base-4.12.0.0</td></tr>
<tr><td>8.6.4</td><td>base-4.12.0.0</td></tr>
<tr><td>8.6.5</td><td>base-4.12.0.0</td></tr>
<tr><td>8.8.1</td><td>base-4.13.0.0</td></tr>
<tr><td>8.8.2</td><td>base-4.13.0.0</td></tr>
<tr><td>8.8.3</td><td>base-4.13.0.0</td></tr>
<tr><td>8.8.4</td><td>base-4.13.0.0</td></tr>
<tr><td>8.10.1</td><td>base-4.14.0.0</td></tr>
<tr><td>8.10.2</td><td>base-4.14.1.0</td></tr>
<tr><td>8.10.3</td><td>base-4.14.1.0</td></tr>
<tr><td>8.10.4</td><td>base-4.14.1.0</td></tr>
<tr><td>8.10.5</td><td>base-4.14.2.0</td></tr>
<tr><td>8.10.6</td><td>base-4.14.3.0</td></tr>
<tr><td>8.10.7</td><td><span style="color:green">recommended</span>, base-4.14.3.0</td></tr>
<tr><td>9.0.1</td><td>base-4.15.0.0</td></tr>
<tr><td>9.0.2</td><td>base-4.15.1.0</td></tr>
<tr><td>9.2.1</td><td>base-4.16.0.0</td></tr>
<tr><td>9.2.2</td><td><span style="color:blue">latest</span>, base-4.16.1.0</td></tr> <tr><td>9.2.2</td><td><span style="color:blue">latest</span>, base-4.16.1.0</td></tr>
<tr><td>9.2.1</td><td>base-4.16.0.0</td></tr>
<tr><td>9.0.2</td><td>base-4.15.1.0</td></tr>
<tr><td>9.0.1</td><td>base-4.15.0.0</td></tr>
<tr><td>8.10.7</td><td><span style="color:green">recommended</span>, base-4.14.3.0</td></tr>
<tr><td>8.10.6</td><td>base-4.14.3.0</td></tr>
<tr><td>8.10.5</td><td>base-4.14.2.0</td></tr>
<tr><td>8.10.4</td><td>base-4.14.1.0</td></tr>
<tr><td>8.10.3</td><td>base-4.14.1.0</td></tr>
<tr><td>8.10.2</td><td>base-4.14.1.0</td></tr>
<tr><td>8.10.1</td><td>base-4.14.0.0</td></tr>
<tr><td>8.8.4</td><td>base-4.13.0.0</td></tr>
<tr><td>8.8.3</td><td>base-4.13.0.0</td></tr>
<tr><td>8.8.2</td><td>base-4.13.0.0</td></tr>
<tr><td>8.8.1</td><td>base-4.13.0.0</td></tr>
<tr><td>8.6.5</td><td>base-4.12.0.0</td></tr>
<tr><td>8.6.4</td><td>base-4.12.0.0</td></tr>
<tr><td>8.6.3</td><td>base-4.12.0.0</td></tr>
<tr><td>8.6.2</td><td>base-4.12.0.0</td></tr>
<tr><td>8.6.1</td><td>base-4.12.0.0</td></tr>
<tr><td>8.4.4</td><td>base-4.11.1.0</td></tr>
<tr><td>8.4.3</td><td>base-4.11.1.0</td></tr>
<tr><td>8.4.2</td><td>base-4.11.1.0</td></tr>
<tr><td>8.4.1</td><td>base-4.11.0.0</td></tr>
<tr><td>8.2.2</td><td>base-4.10.1.0</td></tr>
<tr><td>8.0.2</td><td>base-4.9.1.0</td></tr>
<tr><td>7.10.3</td><td>base-4.8.2.0</td></tr>
</tbody> </tbody>
</table> </table>
</details> </details>
<details> <details> <summary>Show all supported <a href='https://cabal.readthedocs.io/en/stable/'>cabal-install</a> versions</summary>
<summary>Show all supported <a href='https://cabal.readthedocs.io/en/stable/'>cabal-install</a> versions</summary> <table>
<table>
<thead><tr><th>Cabal Version</th><th>Tags</th></tr></thead> <thead><tr><th>Cabal Version</th><th>Tags</th></tr></thead>
<tbody> <tbody>
<tr><td>2.4.1.0</td><td></td></tr>
<tr><td>3.0.0.0</td><td></td></tr>
<tr><td>3.2.0.0</td><td></td></tr>
<tr><td>3.4.0.0</td><td></td></tr>
<tr><td>3.4.1.0</td><td></td></tr>
<tr><td>3.6.0.0</td><td></td></tr>
<tr><td>3.6.2.0</td><td><span style="color:blue">latest</span>, <span style="color:green">recommended</span></td></tr> <tr><td>3.6.2.0</td><td><span style="color:blue">latest</span>, <span style="color:green">recommended</span></td></tr>
<tr><td>3.6.0.0</td><td></td></tr>
<tr><td>3.4.1.0</td><td></td></tr>
<tr><td>3.4.0.0</td><td></td></tr>
<tr><td>3.2.0.0</td><td></td></tr>
<tr><td>3.0.0.0</td><td></td></tr>
<tr><td>2.4.1.0</td><td></td></tr>
</tbody> </tbody>
</table> </table>
</details> </details>
<details> <details> <summary>Show all supported <a href='https://haskell-language-server.readthedocs.io/en/stable/'>HLS</a> versions</summary>
<summary>Show all supported <a href='https://haskell-language-server.readthedocs.io/en/stable/'>HLS</a> versions</summary>
<table> <table>
<thead><tr><th>HLS Version</th><th>Tags</th></tr></thead> <thead><tr><th>HLS Version</th><th>Tags</th></tr></thead>
<tbody> <tbody>
<tr><td>1.1.0</td><td></td></tr> <tr><td>1.7.0.0</td><td><span style="color:blue">latest</span>, <span style="color:green">recommended</span></td></tr>
<tr><td>1.2.0</td><td></td></tr> <tr><td>1.6.1.0</td><td></td></tr>
<tr><td>1.3.0</td><td></td></tr>
<tr><td>1.4.0</td><td></td></tr>
<tr><td>1.5.0</td><td></td></tr>
<tr><td>1.5.1</td><td></td></tr>
<tr><td>1.6.0.0</td><td></td></tr> <tr><td>1.6.0.0</td><td></td></tr>
<tr><td>1.6.1.0</td><td><span style="color:blue">latest</span>, <span style="color:green">recommended</span></td></tr> <tr><td>1.5.1</td><td></td></tr>
<tr><td>1.5.0</td><td></td></tr>
<tr><td>1.4.0</td><td></td></tr>
<tr><td>1.3.0</td><td></td></tr>
<tr><td>1.2.0</td><td></td></tr>
<tr><td>1.1.0</td><td></td></tr>
</tbody> </tbody>
</table> </table>
</details> </details>
<details> <details> <summary>Show all supported <a href='https://docs.haskellstack.org/en/stable/README/'>Stack</a> versions</summary>
<summary>Show all supported <a href='https://docs.haskellstack.org/en/stable/README/'>Stack</a> versions</summary>
<table> <table>
<thead><tr><th>Stack Version</th><th>Tags</th></tr></thead> <thead><tr><th>Stack Version</th><th>Tags</th></tr></thead>
<tbody> <tbody>
<tr><td>2.5.1</td><td></td></tr>
<tr><td>2.7.1</td><td></td></tr>
<tr><td>2.7.3</td><td></td></tr>
<tr><td>2.7.5</td><td><span style="color:blue">latest</span>, <span style="color:green">recommended</span></td></tr> <tr><td>2.7.5</td><td><span style="color:blue">latest</span>, <span style="color:green">recommended</span></td></tr>
<tr><td>2.7.3</td><td></td></tr>
<tr><td>2.7.1</td><td></td></tr>
<tr><td>2.5.1</td><td></td></tr>
</tbody> </tbody>
</table> </table>
</details> </details>

349
docs/steps.md Normal file
View File

@@ -0,0 +1,349 @@
# First steps
In this guide we'll take a look at a few core tools that are installed
with the Haskell toolchain, namely, `ghc`, `runghc` and `ghci`.
These tools can be used to compile, interpret or explore Haskell programs.
First, let's start by opening your system's command line interface
and running `ghc --version` to make sure we have successfully
installed a Haskell toolchain:
```
➜ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.10.7
```
If this fails, consult [the Getting started page](../install) for information on
how to install Haskell on your computer.
This guide is partly based on [Gil Mizrahi's blog](https://gilmi.me/blog/post/2021/08/14/hs-core-tools).
## Compiling programs with ghc
Running `ghc` invokes the Glasgow Haskell Compiler (GHC), and can be used to
compile Haskell modules and programs into native executables and libraries.
Create a new Haskell source file named `hello.hs`,
and write the following code in it:
```hs
main = putStrLn "Hello, Haskell!"
```
Now, we can compile the program by invoking `ghc` with the file name:
```sh
➜ ghc hello.hs
[1 of 1] Compiling Main ( hello.hs, hello.o )
Linking hello ...
```
For more in-depth information about the files `ghc` produces,
follow the [GHC user guide](https://downloads.haskell.org/ghc/latest/docs/html/users_guide/using.html#getting-started-compiling-programs) guide.
Now we run our program:
```sh
➜ ./hello
Hello, Haskell!
```
Alternatively, we can skip the compilation phase by using the command `runghc`:
```sh
➜ runghc hello.hs
Hello, Haskell!
```
`runghc` interprets the source file instead of compiling it and does not
create build artifacts. This makes it very useful when developing programs
and can help accelerate the feedback loop. More information about `runghc`
can be found in the
[GHC user guide](https://downloads.haskell.org/ghc/latest/docs/html/users_guide/runghc.html).
### Turning on warnings
The `-Wall` flag will enable GHC to emit warnings about our code.
```sh
➜ ghc -Wall hello.hs -fforce-recomp
[1 of 1] Compiling Main ( hello.hs, hello.o )
hello.hs:1:1: warning: [-Wmissing-signatures]
Top-level binding with no type signature: main :: IO ()
|
1 | main = putStrLn "Hello, Haskell!"
| ^^^^
Linking hello ...
```
While Haskell can infer
the types of most expressions, it is recommended that top-level definitions
are annotated with their types.
Now our `hello.hs` source file should looks like this:
```hs
main :: IO ()
main = putStrLn "Hello, world!"
```
And now GHC will compile `hello.hs` without warnings.
## An interactive environment
GHC provides an interactive environment in a form of a
Read-Evaluate-Print Loop (REPL) called GHCi.
To enter the environment run the program `ghci`.
```sh
➜ ghci
GHCi, version 9.0.2: https://www.haskell.org/ghc/ :? for help
ghci>
```
It provides an interactive prompt where Haskell expressions can be written and
evaluated.
For example:
```sh
ghci> 1 + 1
2
ghci> putStrLn "Hello, world!"
Hello, world!
```
We can define new names:
```sh
ghci> double x = x + x
ghci> double 2
4
```
We can write multi-line code by surrounding it with `:{` and `:}`:
```hs
ghci> :{
| map f list =
| case list of
| [] -> []
| x : xs -> f x : map f xs
| :}
ghci> map (+1) [1, 2, 3]
[2,3,4]
```
We can import Haskell source files using the `:load` command (`:l` for short):
```sh
ghci> :load hello.hs
[1 of 1] Compiling Main ( hello.hs, interpreted )
Ok, one module loaded.
ghci> main
Hello, Haskell!
```
As well as import library modules:
```sh
ghci> import Data.Bits
ghci> shiftL 32 1
64
ghci> clearBit 33 0
32
```
We can even ask what the type of an expression is using the `:type` command
(`:t` for short):
```sh
λ> :type putStrLn
putStrLn :: String -> IO ()
```
To exit `ghci`, use the `:quit` command (or `:q` for short)
```sh
ghci> :quit
Leaving GHCi.
```
A more thorough introduction to GHCi can be found in the
[GHC user guide](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html).
### Using external packages in ghci
By default, GHCi can only load and use packages that are
[included with the GHC installation](https://downloads.haskell.org/ghc/latest/docs/html/users_guide/9.2.2-notes.html#included-libraries).
However, users of the [cabal-install](https://www.haskell.org/cabal) and
[stack](http://haskellstack.org) build tools can download and load external packages
very easily using the following commands:
cabal-install:
```sh
cabal repl --build-depends async,say
```
Stack:
```sh
stack exec --package async --package say -- ghci
```
And the modules of the relevant packages will be available for import:
```sh
GHCi, version 9.0.1: https://www.haskell.org/ghc/ :? for help
ghci> import Control.Concurrent.Async
ghci> import Say
ghci> concurrently_ (sayString "Hello") (sayString "World")
Hello
World
```
Stack users can also use this feature with `runghc` and `ghc` by replacing
`ghci` in the command above, and cabal-install users can generate an
environment file that will make `async` and `say` visible for GHC tools
in the current directory using this command:
```sh
cabal install --lib async say --package-env .
```
Many more packages are waiting for you on [Hackage](https://hackage.haskell.org).
## Creating a proper package with modules
The previous methods to compile Haskell code are for quick experiments and small
programs. Usually in Haskell, we create cabal projects, where build tools such as
`cabal-install` or `stack` will install necessary dependencies and compile modules
in correct order. For simplicity's sake, this section will only use `cabal-install`.
To get started, run:
```sh
mkdir haskell-project
cd haskell-project
cabal init --interactive
```
If you let it generate a simple project with sensible defaults, then you should have these files:
* `src/MyLib.hs`: the library module of your project
* `app/Main.hs`: the entry point of your project
* `haskell-project.cabal`: the "cabal" file, describing your project, its dependencies and how it's built
To build the project, run:
```sh
cabal build
```
To run the main executable, run:
```sh
➜ cabal run
Hello, Haskell!
someFunc
```
### Adding dependencies
Now let's add a dependency and adjust our library module. Open `haskell-project.cabal`
and find the library section:
```
library
exposed-modules: MyLib
-- Modules included in this library but not exported.
-- other-modules:
-- LANGUAGE extensions used by modules in this package.
-- other-extensions:
build-depends: base ^>=4.14.3.0
hs-source-dirs: src
default-language: Haskell2010
```
The interesting parts here are `exposed-modules` and `build-depends`.
To add a dependency, it should look like this:
```
build-depends: base ^>=4.14.3.0
, directory
```
Now open `src/MyLib.hs` and change it to:
```hs
module MyLib (someFunc) where
import System.Directory
someFunc :: IO ()
someFunc = do
contents <- listDirectory "src"
putStrLn (show contents)
```
### Adding modules
To add a module to your package, adjust `exposed-modules`, like so
```
exposed-modules: MyLib
OtherLib
```
then create `src/OtherLib.hs` with the following contents:
```hs
module OtherLib where
otherFunc :: String -> Int
otherFunc str = length str
```
To use this function interactively, we can run:
```sh
➜ cabal repl
ghci> import OtherLib
ghci> otherFunc "Hello Haskell"
13
```
For further information about how to manage Haskell projects
see the [Cabal user guide](https://cabal.readthedocs.io/en/stable/getting-started.html).
# Where to go from here
<div class="text-center main-buttons">
<a href="https://hackage.haskell.org/" class="btn btn-primary" role="button">Discover Haskell packages</a>
<a href="https://hackage.haskell.org/package/base" class="btn btn-primary" role="button">The standard library</a>
<a href="https://haskell-language-server.readthedocs.io/en/stable/installation.html" class="btn btn-primary" role="button">Editor setup with HLS</a>
<a href="https://play-haskell.tomsmeding.com/play" class="btn btn-primary" role="button">Online playground</a>
</div>
## How to learn Haskell proper
To learn Haskell, try any of those:
- A beginner friendly [4-lectures course](https://github.com/haskell-beginners-2022/course-plan) with exercises (by [Kowainik](https://kowainik.github.io/))
- An in-depth university [CIS 194 Haskell course](https://www.cis.upenn.edu/~cis194/spring13/) including exercises (by [Brent Yorgey](https://byorgey.wordpress.com/))
## Projects to contribute to
* [https://github.com/haskell/haskell-language-server](https://github.com/haskell/haskell-language-server)
* [https://github.com/haskell/cabal](https://github.com/haskell/cabal)
* [https://github.com/commercialhaskell/stack](https://github.com/commercialhaskell/stack)
* [https://gitlab.haskell.org/haskell/ghcup-hs](https://gitlab.haskell.org/haskell/ghcup-hs)
* [https://github.com/jgm/pandoc](https://github.com/jgm/pandoc)
* [https://github.com/simonmichael/hledger](https://github.com/simonmichael/hledger)
* [https://github.com/koalaman/shellcheck](https://github.com/koalaman/shellcheck)

View File

@@ -1,6 +1,6 @@
cabal-version: 3.0 cabal-version: 3.0
name: ghcup name: ghcup
version: 0.1.17.6 version: 0.1.17.8
license: LGPL-3.0-only license: LGPL-3.0-only
license-file: LICENSE license-file: LICENSE
copyright: Julian Ospald 2020 copyright: Julian Ospald 2020

View File

@@ -187,7 +187,7 @@ installGHCBindist :: ( MonadFail m
) )
=> DownloadInfo -- ^ where/how to download => DownloadInfo -- ^ where/how to download
-> Version -- ^ the version to install -> Version -- ^ the version to install
-> Maybe FilePath -- ^ isolated filepath if user passed any -> InstallDir
-> Bool -- ^ Force install -> Bool -- ^ Force install
-> Excepts -> Excepts
'[ AlreadyInstalled '[ AlreadyInstalled
@@ -205,22 +205,22 @@ installGHCBindist :: ( MonadFail m
] ]
m m
() ()
installGHCBindist dlinfo ver isoFilepath forceInstall = do installGHCBindist dlinfo ver installDir forceInstall = do
let tver = mkTVer ver let tver = mkTVer ver
lift $ logDebug $ "Requested to install GHC with " <> prettyVer ver lift $ logDebug $ "Requested to install GHC with " <> prettyVer ver
regularGHCInstalled <- lift $ checkIfToolInstalled GHC ver regularGHCInstalled <- lift $ checkIfToolInstalled GHC ver
if if
| not forceInstall | not forceInstall
, regularGHCInstalled , regularGHCInstalled
, Nothing <- isoFilepath -> do , GHCupInternal <- installDir -> do
throwE $ AlreadyInstalled GHC ver throwE $ AlreadyInstalled GHC ver
| forceInstall | forceInstall
, regularGHCInstalled , regularGHCInstalled
, Nothing <- isoFilepath -> do , GHCupInternal <- installDir -> do
lift $ logInfo "Removing the currently installed GHC version first!" lift $ logInfo "Removing the currently installed GHC version first!"
liftE $ rmGHCVer tver liftE $ rmGHCVer tver
@@ -229,17 +229,18 @@ installGHCBindist dlinfo ver isoFilepath forceInstall = do
-- download (or use cached version) -- download (or use cached version)
dl <- liftE $ downloadCached dlinfo Nothing dl <- liftE $ downloadCached dlinfo Nothing
-- prepare paths
ghcdir <- lift $ ghcupGHCDir tver
toolchainSanityChecks toolchainSanityChecks
case isoFilepath of case installDir of
Just isoDir -> do -- isolated install IsolateDir isoDir -> do -- isolated install
lift $ logInfo $ "isolated installing GHC to " <> T.pack isoDir lift $ logInfo $ "isolated installing GHC to " <> T.pack isoDir
liftE $ installPackedGHC dl (view dlSubdir dlinfo) isoDir ver forceInstall liftE $ installPackedGHC dl (view dlSubdir dlinfo) (IsolateDirResolved isoDir) ver forceInstall
Nothing -> do -- regular install GHCupInternal -> do -- regular install
liftE $ installPackedGHC dl (view dlSubdir dlinfo) ghcdir ver forceInstall -- prepare paths
ghcdir <- lift $ ghcupGHCDir tver
liftE $ installPackedGHC dl (view dlSubdir dlinfo) (GHCupDir ghcdir) ver forceInstall
-- make symlinks & stuff when regular install, -- make symlinks & stuff when regular install,
liftE $ postGHCInstall tver liftE $ postGHCInstall tver
@@ -271,7 +272,7 @@ installPackedGHC :: ( MonadMask m
) )
=> FilePath -- ^ Path to the packed GHC bindist => FilePath -- ^ Path to the packed GHC bindist
-> Maybe TarDir -- ^ Subdir of the archive -> Maybe TarDir -- ^ Subdir of the archive
-> FilePath -- ^ Path to install to -> InstallDirResolved
-> Version -- ^ The GHC version -> Version -- ^ The GHC version
-> Bool -- ^ Force install -> Bool -- ^ Force install
-> Excepts -> Excepts
@@ -297,9 +298,13 @@ installPackedGHC dl msubdir inst ver forceInstall = do
workdir <- maybe (pure tmpUnpack) workdir <- maybe (pure tmpUnpack)
(liftE . intoSubdir tmpUnpack) (liftE . intoSubdir tmpUnpack)
msubdir msubdir
liftE $ runBuildAction tmpUnpack liftE $ runBuildAction tmpUnpack
(Just inst) (case inst of
IsolateDirResolved _ -> Nothing -- don't clean up for isolated installs, since that'd potentially delete other
-- user files if '--force' is supplied
GHCupDir d -> Just d
)
(installUnpackedGHC workdir inst ver) (installUnpackedGHC workdir inst ver)
@@ -315,11 +320,11 @@ installUnpackedGHC :: ( MonadReader env m
, MonadUnliftIO m , MonadUnliftIO m
, MonadMask m , MonadMask m
) )
=> FilePath -- ^ Path to the unpacked GHC bindist (where the configure script resides) => FilePath -- ^ Path to the unpacked GHC bindist (where the configure script resides)
-> FilePath -- ^ Path to install to -> InstallDirResolved -- ^ Path to install to
-> Version -- ^ The GHC version -> Version -- ^ The GHC version
-> Excepts '[ProcessError] m () -> Excepts '[ProcessError] m ()
installUnpackedGHC path inst ver installUnpackedGHC path (fromInstallDir -> inst) ver
| isWindows = do | isWindows = do
lift $ logInfo "Installing GHC (this may take a while)" lift $ logInfo "Installing GHC (this may take a while)"
-- Windows bindists are relocatable and don't need -- Windows bindists are relocatable and don't need
@@ -340,7 +345,7 @@ installUnpackedGHC path inst ver
lift $ logInfo "Installing GHC (this may take a while)" lift $ logInfo "Installing GHC (this may take a while)"
lEM $ execLogged "sh" lEM $ execLogged "sh"
("./configure" : ("--prefix=" <> inst) ("./configure" : ("--prefix=" <> inst)
: alpineArgs : alpineArgs
) )
(Just path) (Just path)
@@ -369,7 +374,7 @@ installGHCBin :: ( MonadFail m
, MonadUnliftIO m , MonadUnliftIO m
) )
=> Version -- ^ the version to install => Version -- ^ the version to install
-> Maybe FilePath -- ^ isolated install filepath, if user passed any -> InstallDir
-> Bool -- ^ force install -> Bool -- ^ force install
-> Excepts -> Excepts
'[ AlreadyInstalled '[ AlreadyInstalled
@@ -387,9 +392,9 @@ installGHCBin :: ( MonadFail m
] ]
m m
() ()
installGHCBin ver isoFilepath forceInstall = do installGHCBin ver installDir forceInstall = do
dlinfo <- liftE $ getDownloadInfo GHC ver dlinfo <- liftE $ getDownloadInfo GHC ver
liftE $ installGHCBindist dlinfo ver isoFilepath forceInstall liftE $ installGHCBindist dlinfo ver installDir forceInstall
-- | Like 'installCabalBin', except takes the 'DownloadInfo' as -- | Like 'installCabalBin', except takes the 'DownloadInfo' as
@@ -408,8 +413,8 @@ installCabalBindist :: ( MonadMask m
) )
=> DownloadInfo => DownloadInfo
-> Version -> Version
-> Maybe FilePath -- ^ isolated install filepath, if user provides any. -> InstallDir
-> Bool -- ^ Force install -> Bool -- ^ Force install
-> Excepts -> Excepts
'[ AlreadyInstalled '[ AlreadyInstalled
, CopyError , CopyError
@@ -425,7 +430,7 @@ installCabalBindist :: ( MonadMask m
] ]
m m
() ()
installCabalBindist dlinfo ver isoFilepath forceInstall = do installCabalBindist dlinfo ver installDir forceInstall = do
lift $ logDebug $ "Requested to install cabal version " <> prettyVer ver lift $ logDebug $ "Requested to install cabal version " <> prettyVer ver
PlatformRequest {..} <- lift getPlatformReq PlatformRequest {..} <- lift getPlatformReq
@@ -437,18 +442,18 @@ installCabalBindist dlinfo ver isoFilepath forceInstall = do
if if
| not forceInstall | not forceInstall
, regularCabalInstalled , regularCabalInstalled
, Nothing <- isoFilepath -> do , GHCupInternal <- installDir -> do
throwE $ AlreadyInstalled Cabal ver throwE $ AlreadyInstalled Cabal ver
| forceInstall | forceInstall
, regularCabalInstalled , regularCabalInstalled
, Nothing <- isoFilepath -> do , GHCupInternal <- installDir -> do
lift $ logInfo "Removing the currently installed version first!" lift $ logInfo "Removing the currently installed version first!"
liftE $ rmCabalVer ver liftE $ rmCabalVer ver
| otherwise -> pure () | otherwise -> pure ()
-- download (or use cached version) -- download (or use cached version)
dl <- liftE $ downloadCached dlinfo Nothing dl <- liftE $ downloadCached dlinfo Nothing
@@ -460,34 +465,37 @@ installCabalBindist dlinfo ver isoFilepath forceInstall = do
-- the subdir of the archive where we do the work -- the subdir of the archive where we do the work
workdir <- maybe (pure tmpUnpack) (liftE . intoSubdir tmpUnpack) (view dlSubdir dlinfo) workdir <- maybe (pure tmpUnpack) (liftE . intoSubdir tmpUnpack) (view dlSubdir dlinfo)
case isoFilepath of case installDir of
Just isoDir -> do -- isolated install IsolateDir isoDir -> do -- isolated install
lift $ logInfo $ "isolated installing Cabal to " <> T.pack isoDir lift $ logInfo $ "isolated installing Cabal to " <> T.pack isoDir
liftE $ installCabalUnpacked workdir isoDir Nothing forceInstall liftE $ installCabalUnpacked workdir (IsolateDirResolved isoDir) ver forceInstall
GHCupInternal -> do -- regular install
liftE $ installCabalUnpacked workdir (GHCupDir binDir) ver forceInstall
Nothing -> do -- regular install
liftE $ installCabalUnpacked workdir binDir (Just ver) forceInstall
-- | Install an unpacked cabal distribution.Symbol -- | Install an unpacked cabal distribution.Symbol
installCabalUnpacked :: (MonadCatch m, HasLog env, MonadIO m, MonadReader env m) installCabalUnpacked :: (MonadCatch m, HasLog env, MonadIO m, MonadReader env m)
=> FilePath -- ^ Path to the unpacked cabal bindist (where the executable resides) => FilePath -- ^ Path to the unpacked cabal bindist (where the executable resides)
-> FilePath -- ^ Path to install to -> InstallDirResolved -- ^ Path to install to
-> Maybe Version -- ^ Nothing for isolated install -> Version
-> Bool -- ^ Force Install -> Bool -- ^ Force Install
-> Excepts '[CopyError, FileAlreadyExistsError] m () -> Excepts '[CopyError, FileAlreadyExistsError] m ()
installCabalUnpacked path inst mver' forceInstall = do installCabalUnpacked path inst ver forceInstall = do
lift $ logInfo "Installing cabal" lift $ logInfo "Installing cabal"
let cabalFile = "cabal" let cabalFile = "cabal"
liftIO $ createDirRecursive' inst liftIO $ createDirRecursive' (fromInstallDir inst)
let destFileName = cabalFile let destFileName = cabalFile
<> maybe "" (("-" <>) . T.unpack . prettyVer) mver' <> (case inst of
IsolateDirResolved _ -> ""
GHCupDir _ -> ("-" <>) . T.unpack . prettyVer $ ver
)
<> exeExt <> exeExt
let destPath = inst </> destFileName let destPath = fromInstallDir inst </> destFileName
unless forceInstall -- Overwrite it when it IS a force install unless forceInstall -- Overwrite it when it IS a force install
(liftE $ throwIfFileAlreadyExists destPath) (liftE $ throwIfFileAlreadyExists destPath)
copyFileE copyFileE
(path </> cabalFile <> exeExt) (path </> cabalFile <> exeExt)
destPath destPath
@@ -510,7 +518,7 @@ installCabalBin :: ( MonadMask m
, MonadFail m , MonadFail m
) )
=> Version => Version
-> Maybe FilePath -- isolated install Path, if user provided any -> InstallDir
-> Bool -- force install -> Bool -- force install
-> Excepts -> Excepts
'[ AlreadyInstalled '[ AlreadyInstalled
@@ -527,9 +535,9 @@ installCabalBin :: ( MonadMask m
] ]
m m
() ()
installCabalBin ver isoFilepath forceInstall = do installCabalBin ver installDir forceInstall = do
dlinfo <- liftE $ getDownloadInfo Cabal ver dlinfo <- liftE $ getDownloadInfo Cabal ver
installCabalBindist dlinfo ver isoFilepath forceInstall installCabalBindist dlinfo ver installDir forceInstall
-- | Like 'installHLSBin, except takes the 'DownloadInfo' as -- | Like 'installHLSBin, except takes the 'DownloadInfo' as
@@ -548,8 +556,8 @@ installHLSBindist :: ( MonadMask m
) )
=> DownloadInfo => DownloadInfo
-> Version -> Version
-> Maybe FilePath -- ^ isolated install path, if user passed any -> InstallDir -- ^ isolated install path, if user passed any
-> Bool -- ^ Force install -> Bool -- ^ Force install
-> Excepts -> Excepts
'[ AlreadyInstalled '[ AlreadyInstalled
, CopyError , CopyError
@@ -567,7 +575,7 @@ installHLSBindist :: ( MonadMask m
] ]
m m
() ()
installHLSBindist dlinfo ver isoFilepath forceInstall = do installHLSBindist dlinfo ver installDir forceInstall = do
lift $ logDebug $ "Requested to install hls version " <> prettyVer ver lift $ logDebug $ "Requested to install hls version " <> prettyVer ver
PlatformRequest {..} <- lift getPlatformReq PlatformRequest {..} <- lift getPlatformReq
@@ -578,17 +586,17 @@ installHLSBindist dlinfo ver isoFilepath forceInstall = do
if if
| not forceInstall | not forceInstall
, regularHLSInstalled , regularHLSInstalled
, Nothing <- isoFilepath -> do -- regular install , GHCupInternal <- installDir -> do -- regular install
throwE $ AlreadyInstalled HLS ver throwE $ AlreadyInstalled HLS ver
| forceInstall | forceInstall
, regularHLSInstalled , regularHLSInstalled
, Nothing <- isoFilepath -> do -- regular forced install , GHCupInternal <- installDir -> do -- regular forced install
lift $ logInfo "Removing the currently installed version of HLS before force installing!" lift $ logInfo "Removing the currently installed version of HLS before force installing!"
liftE $ rmHLSVer ver liftE $ rmHLSVer ver
| otherwise -> pure () | otherwise -> pure ()
-- download (or use cached version) -- download (or use cached version)
dl <- liftE $ downloadCached dlinfo Nothing dl <- liftE $ downloadCached dlinfo Nothing
@@ -604,22 +612,23 @@ installHLSBindist dlinfo ver isoFilepath forceInstall = do
if if
| not forceInstall | not forceInstall
, not legacy , not legacy
, (Just fp) <- isoFilepath -> liftE $ installDestSanityCheck fp , (IsolateDir fp) <- installDir -> liftE $ installDestSanityCheck (IsolateDirResolved fp)
| otherwise -> pure () | otherwise -> pure ()
case isoFilepath of case installDir of
Just isoDir -> do IsolateDir isoDir -> do
lift $ logInfo $ "isolated installing HLS to " <> T.pack isoDir lift $ logInfo $ "isolated installing HLS to " <> T.pack isoDir
if legacy if legacy
then liftE $ installHLSUnpackedLegacy workdir isoDir Nothing forceInstall then liftE $ installHLSUnpackedLegacy workdir (IsolateDirResolved isoDir) ver forceInstall
else liftE $ runBuildAction tmpUnpack Nothing $ installHLSUnpacked workdir isoDir ver else liftE $ runBuildAction tmpUnpack Nothing $ installHLSUnpacked workdir (IsolateDirResolved isoDir) ver
Nothing -> do GHCupInternal -> do
if legacy if legacy
then liftE $ installHLSUnpackedLegacy workdir binDir (Just ver) forceInstall then liftE $ installHLSUnpackedLegacy workdir (GHCupDir binDir) ver forceInstall
else do else do
inst <- ghcupHLSDir ver inst <- ghcupHLSDir ver
liftE $ runBuildAction tmpUnpack Nothing $ installHLSUnpacked workdir inst ver liftE $ runBuildAction tmpUnpack (Just inst)
$ installHLSUnpacked workdir (GHCupDir inst) ver
liftE $ setHLS ver SetHLS_XYZ Nothing liftE $ setHLS ver SetHLS_XYZ Nothing
@@ -631,10 +640,10 @@ isLegacyHLSBindist path = do
-- | Install an unpacked hls distribution. -- | Install an unpacked hls distribution.
installHLSUnpacked :: (MonadMask m, MonadUnliftIO m, MonadReader env m, MonadFail m, HasLog env, HasDirs env, HasSettings env, MonadCatch m, MonadIO m) installHLSUnpacked :: (MonadMask m, MonadUnliftIO m, MonadReader env m, MonadFail m, HasLog env, HasDirs env, HasSettings env, MonadCatch m, MonadIO m)
=> FilePath -- ^ Path to the unpacked hls bindist (where the executable resides) => FilePath -- ^ Path to the unpacked hls bindist (where the executable resides)
-> FilePath -- ^ Path to install to -> InstallDirResolved -- ^ Path to install to
-> Version -> Version
-> Excepts '[ProcessError, CopyError, FileAlreadyExistsError, NotInstalled] m () -> Excepts '[ProcessError, CopyError, FileAlreadyExistsError, NotInstalled] m ()
installHLSUnpacked path inst _ = do installHLSUnpacked path (fromInstallDir -> inst) _ = do
lift $ logInfo "Installing HLS" lift $ logInfo "Installing HLS"
liftIO $ createDirRecursive' inst liftIO $ createDirRecursive' inst
lEM $ make ["PREFIX=" <> inst, "install"] (Just path) lEM $ make ["PREFIX=" <> inst, "install"] (Just path)
@@ -642,13 +651,13 @@ installHLSUnpacked path inst _ = do
-- | Install an unpacked hls distribution (legacy). -- | Install an unpacked hls distribution (legacy).
installHLSUnpackedLegacy :: (MonadReader env m, MonadFail m, HasLog env, MonadCatch m, MonadIO m) installHLSUnpackedLegacy :: (MonadReader env m, MonadFail m, HasLog env, MonadCatch m, MonadIO m)
=> FilePath -- ^ Path to the unpacked hls bindist (where the executable resides) => FilePath -- ^ Path to the unpacked hls bindist (where the executable resides)
-> FilePath -- ^ Path to install to -> InstallDirResolved -- ^ Path to install to
-> Maybe Version -- ^ Nothing for isolated install -> Version
-> Bool -- ^ is it a force install -> Bool -- ^ is it a force install
-> Excepts '[CopyError, FileAlreadyExistsError] m () -> Excepts '[CopyError, FileAlreadyExistsError] m ()
installHLSUnpackedLegacy path inst mver' forceInstall = do installHLSUnpackedLegacy path installDir ver forceInstall = do
lift $ logInfo "Installing HLS" lift $ logInfo "Installing HLS"
liftIO $ createDirRecursive' inst liftIO $ createDirRecursive' (fromInstallDir installDir)
-- install haskell-language-server-<ghcver> -- install haskell-language-server-<ghcver>
bins@(_:_) <- liftIO $ findFiles bins@(_:_) <- liftIO $ findFiles
@@ -659,15 +668,18 @@ installHLSUnpackedLegacy path inst mver' forceInstall = do
) )
forM_ bins $ \f -> do forM_ bins $ \f -> do
let toF = dropSuffix exeExt f let toF = dropSuffix exeExt f
<> maybe "" (("~" <>) . T.unpack . prettyVer) mver' <> (case installDir of
IsolateDirResolved _ -> ""
GHCupDir _ -> ("~" <>) . T.unpack . prettyVer $ ver
)
<> exeExt <> exeExt
let srcPath = path </> f let srcPath = path </> f
let destPath = inst </> toF let destPath = fromInstallDir installDir </> toF
unless forceInstall -- if it is a force install, overwrite it. unless forceInstall -- if it is a force install, overwrite it.
(liftE $ throwIfFileAlreadyExists destPath) (liftE $ throwIfFileAlreadyExists destPath)
copyFileE copyFileE
srcPath srcPath
destPath destPath
@@ -676,18 +688,21 @@ installHLSUnpackedLegacy path inst mver' forceInstall = do
-- install haskell-language-server-wrapper -- install haskell-language-server-wrapper
let wrapper = "haskell-language-server-wrapper" let wrapper = "haskell-language-server-wrapper"
toF = wrapper toF = wrapper
<> maybe "" (("-" <>) . T.unpack . prettyVer) mver' <> (case installDir of
IsolateDirResolved _ -> ""
GHCupDir _ -> ("-" <>) . T.unpack . prettyVer $ ver
)
<> exeExt <> exeExt
srcWrapperPath = path </> wrapper <> exeExt srcWrapperPath = path </> wrapper <> exeExt
destWrapperPath = inst </> toF destWrapperPath = fromInstallDir installDir </> toF
unless forceInstall unless forceInstall
(liftE $ throwIfFileAlreadyExists destWrapperPath) (liftE $ throwIfFileAlreadyExists destWrapperPath)
copyFileE copyFileE
srcWrapperPath srcWrapperPath
destWrapperPath destWrapperPath
lift $ chmod_755 destWrapperPath lift $ chmod_755 destWrapperPath
@@ -708,7 +723,7 @@ installHLSBin :: ( MonadMask m
, MonadFail m , MonadFail m
) )
=> Version => Version
-> Maybe FilePath -- isolated install Dir (if any) -> InstallDir
-> Bool -- force install -> Bool -- force install
-> Excepts -> Excepts
'[ AlreadyInstalled '[ AlreadyInstalled
@@ -727,9 +742,9 @@ installHLSBin :: ( MonadMask m
] ]
m m
() ()
installHLSBin ver isoFilepath forceInstall = do installHLSBin ver installDir forceInstall = do
dlinfo <- liftE $ getDownloadInfo HLS ver dlinfo <- liftE $ getDownloadInfo HLS ver
installHLSBindist dlinfo ver isoFilepath forceInstall installHLSBindist dlinfo ver installDir forceInstall
compileHLS :: ( MonadMask m compileHLS :: ( MonadMask m
@@ -749,7 +764,7 @@ compileHLS :: ( MonadMask m
-> [Version] -> [Version]
-> Maybe Int -> Maybe Int
-> Maybe Version -> Maybe Version
-> Maybe FilePath -> InstallDir
-> Maybe (Either FilePath URI) -> Maybe (Either FilePath URI)
-> Maybe URI -> Maybe URI
-> Maybe (Either FilePath [URI]) -- ^ patches -> Maybe (Either FilePath [URI]) -- ^ patches
@@ -764,7 +779,7 @@ compileHLS :: ( MonadMask m
, BuildFailed , BuildFailed
, NotInstalled , NotInstalled
] m Version ] m Version
compileHLS targetHLS ghcs jobs ov isolateDir cabalProject cabalProjectLocal patches cabalArgs = do compileHLS targetHLS ghcs jobs ov installDir cabalProject cabalProjectLocal patches cabalArgs = do
PlatformRequest { .. } <- lift getPlatformReq PlatformRequest { .. } <- lift getPlatformReq
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
Dirs { .. } <- lift getDirs Dirs { .. } <- lift getDirs
@@ -805,7 +820,7 @@ compileHLS targetHLS ghcs jobs ov isolateDir cabalProject cabalProjectLocal patc
, "origin" , "origin"
, fromString rep ] , fromString rep ]
let fetch_args = let fetch_args =
[ "fetch" [ "fetch"
, "--depth" , "--depth"
, "1" , "1"
@@ -837,8 +852,8 @@ compileHLS targetHLS ghcs jobs ov isolateDir cabalProject cabalProjectLocal patc
workdir workdir
Nothing Nothing
(reThrowAll @_ @'[GPGError, DownloadFailed, DigestError, PatchFailed, ProcessError, FileAlreadyExistsError, CopyError] @'[BuildFailed] (BuildFailed workdir) $ do (reThrowAll @_ @'[GPGError, DownloadFailed, DigestError, PatchFailed, ProcessError, FileAlreadyExistsError, CopyError] @'[BuildFailed] (BuildFailed workdir) $ do
let installDir = workdir </> "out" let tmpInstallDir = workdir </> "out"
liftIO $ createDirRecursive' installDir liftIO $ createDirRecursive' tmpInstallDir
-- apply patches -- apply patches
liftE $ applyAnyPatch patches workdir liftE $ applyAnyPatch patches workdir
@@ -861,8 +876,8 @@ compileHLS targetHLS ghcs jobs ov isolateDir cabalProject cabalProjectLocal patc
cpl <- liftE $ download uri Nothing Nothing tmpUnpack (Just (cp <.> "local")) False cpl <- liftE $ download uri Nothing Nothing tmpUnpack (Just (cp <.> "local")) False
copyFileE cpl (workdir </> cp <.> "local") copyFileE cpl (workdir </> cp <.> "local")
artifacts <- forM (sort ghcs) $ \ghc -> do artifacts <- forM (sort ghcs) $ \ghc -> do
let ghcInstallDir = installDir </> T.unpack (prettyVer ghc) let ghcInstallDir = tmpInstallDir </> T.unpack (prettyVer ghc)
liftIO $ createDirRecursive' installDir liftIO $ createDirRecursive' tmpInstallDir
lift $ logInfo $ "Building HLS " <> prettyVer installVer <> " for GHC version " <> prettyVer ghc lift $ logInfo $ "Building HLS " <> prettyVer installVer <> " for GHC version " <> prettyVer ghc
liftE $ lEM @_ @'[ProcessError] $ liftE $ lEM @_ @'[ProcessError] $
execLogged "cabal" ( [ "v2-install" execLogged "cabal" ( [ "v2-install"
@@ -885,17 +900,17 @@ compileHLS targetHLS ghcs jobs ov isolateDir cabalProject cabalProjectLocal patc
forM_ artifacts $ \artifact -> do forM_ artifacts $ \artifact -> do
liftIO $ renameFile (artifact </> "haskell-language-server" <.> exeExt) liftIO $ renameFile (artifact </> "haskell-language-server" <.> exeExt)
(installDir </> "haskell-language-server-" <> takeFileName artifact <.> exeExt) (tmpInstallDir </> "haskell-language-server-" <> takeFileName artifact <.> exeExt)
liftIO $ renameFile (artifact </> "haskell-language-server-wrapper" <.> exeExt) liftIO $ renameFile (artifact </> "haskell-language-server-wrapper" <.> exeExt)
(installDir </> "haskell-language-server-wrapper" <.> exeExt) (tmpInstallDir </> "haskell-language-server-wrapper" <.> exeExt)
liftIO $ rmPathForcibly artifact liftIO $ rmPathForcibly artifact
case isolateDir of case installDir of
Just isoDir -> do IsolateDir isoDir -> do
lift $ logInfo $ "isolated installing HLS to " <> T.pack isoDir lift $ logInfo $ "isolated installing HLS to " <> T.pack isoDir
liftE $ installHLSUnpackedLegacy installDir isoDir Nothing True liftE $ installHLSUnpackedLegacy tmpInstallDir (IsolateDirResolved isoDir) installVer True
Nothing -> do GHCupInternal -> do
liftE $ installHLSUnpackedLegacy installDir binDir (Just installVer) True liftE $ installHLSUnpackedLegacy tmpInstallDir (GHCupDir binDir) installVer True
) )
pure installVer pure installVer
@@ -919,7 +934,7 @@ installStackBin :: ( MonadMask m
, MonadFail m , MonadFail m
) )
=> Version => Version
-> Maybe FilePath -- ^ isolate install Dir (if any) -> InstallDir
-> Bool -- ^ Force install -> Bool -- ^ Force install
-> Excepts -> Excepts
'[ AlreadyInstalled '[ AlreadyInstalled
@@ -936,9 +951,9 @@ installStackBin :: ( MonadMask m
] ]
m m
() ()
installStackBin ver isoFilepath forceInstall = do installStackBin ver installDir forceInstall = do
dlinfo <- liftE $ getDownloadInfo Stack ver dlinfo <- liftE $ getDownloadInfo Stack ver
installStackBindist dlinfo ver isoFilepath forceInstall installStackBindist dlinfo ver installDir forceInstall
-- | Like 'installStackBin', except takes the 'DownloadInfo' as -- | Like 'installStackBin', except takes the 'DownloadInfo' as
@@ -957,7 +972,7 @@ installStackBindist :: ( MonadMask m
) )
=> DownloadInfo => DownloadInfo
-> Version -> Version
-> Maybe FilePath -- ^ isolate install Dir (if any) -> InstallDir
-> Bool -- ^ Force install -> Bool -- ^ Force install
-> Excepts -> Excepts
'[ AlreadyInstalled '[ AlreadyInstalled
@@ -974,7 +989,7 @@ installStackBindist :: ( MonadMask m
] ]
m m
() ()
installStackBindist dlinfo ver isoFilepath forceInstall = do installStackBindist dlinfo ver installDir forceInstall = do
lift $ logDebug $ "Requested to install stack version " <> prettyVer ver lift $ logDebug $ "Requested to install stack version " <> prettyVer ver
PlatformRequest {..} <- lift getPlatformReq PlatformRequest {..} <- lift getPlatformReq
@@ -985,12 +1000,12 @@ installStackBindist dlinfo ver isoFilepath forceInstall = do
if if
| not forceInstall | not forceInstall
, regularStackInstalled , regularStackInstalled
, Nothing <- isoFilepath -> do , GHCupInternal <- installDir -> do
throwE $ AlreadyInstalled Stack ver throwE $ AlreadyInstalled Stack ver
| forceInstall | forceInstall
, regularStackInstalled , regularStackInstalled
, Nothing <- isoFilepath -> do , GHCupInternal <- installDir -> do
lift $ logInfo "Removing the currently installed version of Stack first!" lift $ logInfo "Removing the currently installed version of Stack first!"
liftE $ rmStackVer ver liftE $ rmStackVer ver
@@ -1007,33 +1022,36 @@ installStackBindist dlinfo ver isoFilepath forceInstall = do
-- the subdir of the archive where we do the work -- the subdir of the archive where we do the work
workdir <- maybe (pure tmpUnpack) (liftE . intoSubdir tmpUnpack) (view dlSubdir dlinfo) workdir <- maybe (pure tmpUnpack) (liftE . intoSubdir tmpUnpack) (view dlSubdir dlinfo)
case isoFilepath of case installDir of
Just isoDir -> do -- isolated install IsolateDir isoDir -> do -- isolated install
lift $ logInfo $ "isolated installing Stack to " <> T.pack isoDir lift $ logInfo $ "isolated installing Stack to " <> T.pack isoDir
liftE $ installStackUnpacked workdir isoDir Nothing forceInstall liftE $ installStackUnpacked workdir (IsolateDirResolved isoDir) ver forceInstall
Nothing -> do -- regular install GHCupInternal -> do -- regular install
liftE $ installStackUnpacked workdir binDir (Just ver) forceInstall liftE $ installStackUnpacked workdir (GHCupDir binDir) ver forceInstall
-- | Install an unpacked stack distribution. -- | Install an unpacked stack distribution.
installStackUnpacked :: (MonadReader env m, HasLog env, MonadCatch m, MonadIO m) installStackUnpacked :: (MonadReader env m, HasLog env, MonadCatch m, MonadIO m)
=> FilePath -- ^ Path to the unpacked stack bindist (where the executable resides) => FilePath -- ^ Path to the unpacked stack bindist (where the executable resides)
-> FilePath -- ^ Path to install to -> InstallDirResolved
-> Maybe Version -- ^ Nothing for isolated installs -> Version
-> Bool -- ^ Force install -> Bool -- ^ Force install
-> Excepts '[CopyError, FileAlreadyExistsError] m () -> Excepts '[CopyError, FileAlreadyExistsError] m ()
installStackUnpacked path inst mver' forceInstall = do installStackUnpacked path installDir ver forceInstall = do
lift $ logInfo "Installing stack" lift $ logInfo "Installing stack"
let stackFile = "stack" let stackFile = "stack"
liftIO $ createDirRecursive' inst liftIO $ createDirRecursive' (fromInstallDir installDir)
let destFileName = stackFile let destFileName = stackFile
<> maybe "" (("-" <>) . T.unpack . prettyVer) mver' <> (case installDir of
IsolateDirResolved _ -> ""
GHCupDir _ -> ("-" <>) . T.unpack . prettyVer $ ver
)
<> exeExt <> exeExt
destPath = inst </> destFileName destPath = fromInstallDir installDir </> destFileName
unless forceInstall unless forceInstall
(liftE $ throwIfFileAlreadyExists destPath) (liftE $ throwIfFileAlreadyExists destPath)
copyFileE copyFileE
(path </> stackFile <> exeExt) (path </> stackFile <> exeExt)
destPath destPath
@@ -1099,7 +1117,7 @@ setGHC ver sghc mBinDir = do
SetGHC_XY -> do SetGHC_XY -> do
handle handle
(\(e :: ParseError) -> lift $ logWarn (T.pack $ displayException e) >> pure Nothing) (\(e :: ParseError) -> lift $ logWarn (T.pack $ displayException e) >> pure Nothing)
$ do $ do
(mj, mi) <- getMajorMinorV (_tvVersion ver) (mj, mi) <- getMajorMinorV (_tvVersion ver)
let major' = intToText mj <> "." <> intToText mi let major' = intToText mj <> "." <> intToText mi
pure $ Just (file <> "-" <> T.unpack major') pure $ Just (file <> "-" <> T.unpack major')
@@ -1223,7 +1241,7 @@ setHLS :: ( MonadReader env m
, MonadUnliftIO m , MonadUnliftIO m
) )
=> Version => Version
-> SetHLS -- Nothing for legacy -> SetHLS
-> Maybe FilePath -- if set, signals that we're not operating in ~/.ghcup/bin -> Maybe FilePath -- if set, signals that we're not operating in ~/.ghcup/bin
-- and don't want mess with other versions -- and don't want mess with other versions
-> Excepts '[NotInstalled] m () -> Excepts '[NotInstalled] m ()
@@ -1357,7 +1375,7 @@ warnAboutHlsCompatibility = do
"Haskell IDE support may not work until this is fixed." <> "\n" <> "Haskell IDE support may not work until this is fixed." <> "\n" <>
"Install a different HLS version, or install and set one of the following GHCs:" <> "\n" <> "Install a different HLS version, or install and set one of the following GHCs:" <> "\n" <>
T.pack (prettyShow supportedGHC) T.pack (prettyShow supportedGHC)
_ -> return () _ -> return ()
------------------ ------------------
@@ -1962,7 +1980,7 @@ rmGhcupDirs = do
handleRm $ rmEnvFile envFilePath handleRm $ rmEnvFile envFilePath
handleRm $ rmConfFile confFilePath handleRm $ rmConfFile confFilePath
-- for xdg dirs, the order matters here -- for xdg dirs, the order matters here
handleRm $ rmDir logsDir handleRm $ rmDir logsDir
handleRm $ rmDir cacheDir handleRm $ rmDir cacheDir
@@ -2036,7 +2054,7 @@ rmGhcupDirs = do
cs <- liftIO $ listDirectory fp >>= filterM doesDirectoryExist . fmap (fp </>) cs <- liftIO $ listDirectory fp >>= filterM doesDirectoryExist . fmap (fp </>)
forM_ cs removeEmptyDirsRecursive forM_ cs removeEmptyDirsRecursive
hideError InappropriateType $ removeDirIfEmptyOrIsSymlink fp hideError InappropriateType $ removeDirIfEmptyOrIsSymlink fp
-- we expect only files inside cache/log dir -- we expect only files inside cache/log dir
-- we report remaining files/dirs later, -- we report remaining files/dirs later,
@@ -2121,7 +2139,7 @@ compileGHC :: ( MonadMask m
-> [Text] -- ^ additional args to ./configure -> [Text] -- ^ additional args to ./configure
-> Maybe String -- ^ build flavour -> Maybe String -- ^ build flavour
-> Bool -> Bool
-> Maybe FilePath -- ^ isolate dir -> InstallDir
-> Excepts -> Excepts
'[ AlreadyInstalled '[ AlreadyInstalled
, BuildFailed , BuildFailed
@@ -2146,7 +2164,7 @@ compileGHC :: ( MonadMask m
] ]
m m
GHCTargetVersion GHCTargetVersion
compileGHC targetGhc ov bstrap jobs mbuildConfig patches aargs buildFlavour hadrian isolateDir compileGHC targetGhc ov bstrap jobs mbuildConfig patches aargs buildFlavour hadrian installDir
= do = do
PlatformRequest { .. } <- lift getPlatformReq PlatformRequest { .. } <- lift getPlatformReq
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
@@ -2187,7 +2205,7 @@ compileGHC targetGhc ov bstrap jobs mbuildConfig patches aargs buildFlavour hadr
, "origin" , "origin"
, fromString rep ] , fromString rep ]
let fetch_args = let fetch_args =
[ "fetch" [ "fetch"
, "--depth" , "--depth"
, "1" , "1"
@@ -2219,18 +2237,18 @@ compileGHC targetGhc ov bstrap jobs mbuildConfig patches aargs buildFlavour hadr
alreadySet <- fmap (== Just installVer) $ lift $ ghcSet (_tvTarget installVer) alreadySet <- fmap (== Just installVer) $ lift $ ghcSet (_tvTarget installVer)
when alreadyInstalled $ do when alreadyInstalled $ do
case isolateDir of case installDir of
Just isoDir -> IsolateDir isoDir ->
lift $ logWarn $ "GHC " <> T.pack (prettyShow installVer) <> " already installed. Isolate installing to " <> T.pack isoDir lift $ logWarn $ "GHC " <> T.pack (prettyShow installVer) <> " already installed. Isolate installing to " <> T.pack isoDir
Nothing -> GHCupInternal ->
lift $ logWarn $ "GHC " <> T.pack (prettyShow installVer) <> " already installed. Will overwrite existing version." lift $ logWarn $ "GHC " <> T.pack (prettyShow installVer) <> " already installed. Will overwrite existing version."
lift $ logWarn lift $ logWarn
"...waiting for 10 seconds before continuing, you can still abort..." "...waiting for 10 seconds before continuing, you can still abort..."
liftIO $ threadDelay 10000000 -- give the user a sec to intervene liftIO $ threadDelay 10000000 -- give the user a sec to intervene
ghcdir <- case isolateDir of ghcdir <- case installDir of
Just isoDir -> pure isoDir IsolateDir isoDir -> pure $ IsolateDirResolved isoDir
Nothing -> lift $ ghcupGHCDir installVer GHCupInternal -> GHCupDir <$> lift (ghcupGHCDir installVer)
(mBindist, bmk) <- liftE $ runBuildAction (mBindist, bmk) <- liftE $ runBuildAction
tmpUnpack tmpUnpack
@@ -2243,13 +2261,13 @@ compileGHC targetGhc ov bstrap jobs mbuildConfig patches aargs buildFlavour hadr
pure (b, bmk) pure (b, bmk)
) )
case isolateDir of case installDir of
Nothing -> GHCupInternal ->
-- only remove old ghc in regular installs -- only remove old ghc in regular installs
when alreadyInstalled $ do when alreadyInstalled $ do
lift $ logInfo "Deleting existing installation" lift $ logInfo "Deleting existing installation"
liftE $ rmGHCVer installVer liftE $ rmGHCVer installVer
_ -> pure () _ -> pure ()
forM_ mBindist $ \bindist -> do forM_ mBindist $ \bindist -> do
@@ -2259,21 +2277,21 @@ compileGHC targetGhc ov bstrap jobs mbuildConfig patches aargs buildFlavour hadr
(installVer ^. tvVersion) (installVer ^. tvVersion)
False -- not a force install, since we already overwrite when compiling. False -- not a force install, since we already overwrite when compiling.
liftIO $ B.writeFile (ghcdir </> ghcUpSrcBuiltFile) bmk liftIO $ B.writeFile (fromInstallDir ghcdir </> ghcUpSrcBuiltFile) bmk
case isolateDir of case installDir of
-- set and make symlinks for regular (non-isolated) installs -- set and make symlinks for regular (non-isolated) installs
Nothing -> do GHCupInternal -> do
reThrowAll GHCupSetError $ postGHCInstall installVer reThrowAll GHCupSetError $ postGHCInstall installVer
-- restore -- restore
when alreadySet $ liftE $ void $ setGHC installVer SetGHCOnly Nothing when alreadySet $ liftE $ void $ setGHC installVer SetGHCOnly Nothing
_ -> pure () _ -> pure ()
pure installVer pure installVer
where where
defaultConf = defaultConf =
let cross_mk = $(LitE . StringL <$> (qAddDependentFile "data/build_mk/cross" >> runIO (readFile "data/build_mk/cross"))) let cross_mk = $(LitE . StringL <$> (qAddDependentFile "data/build_mk/cross" >> runIO (readFile "data/build_mk/cross")))
default_mk = $(LitE . StringL <$> (qAddDependentFile "data/build_mk/default" >> runIO (readFile "data/build_mk/default"))) default_mk = $(LitE . StringL <$> (qAddDependentFile "data/build_mk/default" >> runIO (readFile "data/build_mk/default")))
in case targetGhc of in case targetGhc of
@@ -2292,7 +2310,7 @@ compileGHC targetGhc ov bstrap jobs mbuildConfig patches aargs buildFlavour hadr
) )
=> GHCTargetVersion => GHCTargetVersion
-> FilePath -> FilePath
-> FilePath -> InstallDirResolved
-> Excepts -> Excepts
'[ FileDoesNotExistError '[ FileDoesNotExistError
, HadrianNotFound , HadrianNotFound
@@ -2351,7 +2369,7 @@ compileGHC targetGhc ov bstrap jobs mbuildConfig patches aargs buildFlavour hadr
) )
=> GHCTargetVersion => GHCTargetVersion
-> FilePath -> FilePath
-> FilePath -> InstallDirResolved
-> Excepts -> Excepts
'[ FileDoesNotExistError '[ FileDoesNotExistError
, HadrianNotFound , HadrianNotFound
@@ -2486,7 +2504,7 @@ compileGHC targetGhc ov bstrap jobs mbuildConfig patches aargs buildFlavour hadr
) )
=> GHCTargetVersion => GHCTargetVersion
-> FilePath -> FilePath
-> FilePath -> InstallDirResolved
-> Excepts -> Excepts
'[ FileDoesNotExistError '[ FileDoesNotExistError
, InvalidBuildConfig , InvalidBuildConfig
@@ -2497,7 +2515,7 @@ compileGHC targetGhc ov bstrap jobs mbuildConfig patches aargs buildFlavour hadr
] ]
m m
() ()
configureBindist tver workdir ghcdir = do configureBindist tver workdir (fromInstallDir -> ghcdir) = do
lift $ logInfo [s|configuring build|] lift $ logInfo [s|configuring build|]
if | _tvVersion tver >= [vver|8.8.0|] -> do if | _tvVersion tver >= [vver|8.8.0|] -> do
@@ -2603,7 +2621,7 @@ upgradeGHCup mtarget force' = do
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
lift $ logInfo "Upgrading GHCup..." lift $ logInfo "Upgrading GHCup..."
let latestVer = fromJust $ fst <$> getLatest dls GHCup let latestVer = fst (fromJust (getLatest dls GHCup))
(Just ghcupPVPVer) <- pure $ pvpToVersion ghcUpVer "" (Just ghcupPVPVer) <- pure $ pvpToVersion ghcUpVer ""
when (not force' && (latestVer <= ghcupPVPVer)) $ throwE NoUpdate when (not force' && (latestVer <= ghcupPVPVer)) $ throwE NoUpdate
dli <- liftE $ getDownloadInfo GHCup latestVer dli <- liftE $ getDownloadInfo GHCup latestVer

View File

@@ -628,3 +628,16 @@ data CapturedProcess = CapturedProcess
deriving (Eq, Show) deriving (Eq, Show)
makeLenses ''CapturedProcess makeLenses ''CapturedProcess
data InstallDir = IsolateDir FilePath
| GHCupInternal
deriving (Eq, Show)
data InstallDirResolved = IsolateDirResolved FilePath
| GHCupDir FilePath
deriving (Eq, Show)
fromInstallDir :: InstallDirResolved -> FilePath
fromInstallDir (IsolateDirResolved fp) = fp
fromInstallDir (GHCupDir fp) = fp

View File

@@ -317,10 +317,10 @@ ghcSet mtarget = do
MP.setInput rest MP.setInput rest
pure x pure x
) )
<* pathSep <* MP.some pathSep
<* MP.takeRest <* MP.takeRest
<* MP.eof <* MP.eof
ghcSubPath = pathSep <* MP.chunk "ghc" *> pathSep ghcSubPath = MP.some pathSep <* MP.chunk "ghc" *> MP.some pathSep
-- | Get all installed GHCs by reading ~/.ghcup/ghc/<dir>. -- | Get all installed GHCs by reading ~/.ghcup/ghc/<dir>.
-- If a dir cannot be parsed, returns left. -- If a dir cannot be parsed, returns left.
@@ -398,10 +398,10 @@ cabalSet = do
cabalParse = MP.chunk "cabal-" *> version' cabalParse = MP.chunk "cabal-" *> version'
-- parses any path component ending with path separator, -- parses any path component ending with path separator,
-- e.g. "foo/" -- e.g. "foo/"
stripPathComponet = parseUntil1 pathSep *> pathSep stripPathComponet = parseUntil1 pathSep *> MP.some pathSep
-- parses an absolute path up until the last path separator, -- parses an absolute path up until the last path separator,
-- e.g. "/bar/baz/foo" -> "/bar/baz/", leaving "foo" -- e.g. "/bar/baz/foo" -> "/bar/baz/", leaving "foo"
stripAbsolutePath = pathSep *> MP.many (MP.try stripPathComponet) stripAbsolutePath = MP.some pathSep *> MP.many (MP.try stripPathComponet)
-- parses a relative path up until the last path separator, -- parses a relative path up until the last path separator,
-- e.g. "bar/baz/foo" -> "bar/baz/", leaving "foo" -- e.g. "bar/baz/foo" -> "bar/baz/", leaving "foo"
stripRelativePath = MP.many (MP.try stripPathComponet) stripRelativePath = MP.many (MP.try stripPathComponet)
@@ -492,10 +492,10 @@ stackSet = do
cabalParse = MP.chunk "stack-" *> version' cabalParse = MP.chunk "stack-" *> version'
-- parses any path component ending with path separator, -- parses any path component ending with path separator,
-- e.g. "foo/" -- e.g. "foo/"
stripPathComponet = parseUntil1 pathSep *> pathSep stripPathComponet = parseUntil1 pathSep *> MP.some pathSep
-- parses an absolute path up until the last path separator, -- parses an absolute path up until the last path separator,
-- e.g. "/bar/baz/foo" -> "/bar/baz/", leaving "foo" -- e.g. "/bar/baz/foo" -> "/bar/baz/", leaving "foo"
stripAbsolutePath = pathSep *> MP.many (MP.try stripPathComponet) stripAbsolutePath = MP.some pathSep *> MP.many (MP.try stripPathComponet)
-- parses a relative path up until the last path separator, -- parses a relative path up until the last path separator,
-- e.g. "bar/baz/foo" -> "bar/baz/", leaving "foo" -- e.g. "bar/baz/foo" -> "bar/baz/", leaving "foo"
stripRelativePath = MP.many (MP.try stripPathComponet) stripRelativePath = MP.many (MP.try stripPathComponet)
@@ -543,10 +543,10 @@ hlsSet = do
cabalParse = MP.chunk "haskell-language-server-wrapper-" *> version' cabalParse = MP.chunk "haskell-language-server-wrapper-" *> version'
-- parses any path component ending with path separator, -- parses any path component ending with path separator,
-- e.g. "foo/" -- e.g. "foo/"
stripPathComponet = parseUntil1 pathSep *> pathSep stripPathComponet = parseUntil1 pathSep *> MP.some pathSep
-- parses an absolute path up until the last path separator, -- parses an absolute path up until the last path separator,
-- e.g. "/bar/baz/foo" -> "/bar/baz/", leaving "foo" -- e.g. "/bar/baz/foo" -> "/bar/baz/", leaving "foo"
stripAbsolutePath = pathSep *> MP.many (MP.try stripPathComponet) stripAbsolutePath = MP.some pathSep *> MP.many (MP.try stripPathComponet)
-- parses a relative path up until the last path separator, -- parses a relative path up until the last path separator,
-- e.g. "bar/baz/foo" -> "bar/baz/", leaving "foo" -- e.g. "bar/baz/foo" -> "bar/baz/", leaving "foo"
stripRelativePath = MP.many (MP.try stripPathComponet) stripRelativePath = MP.many (MP.try stripPathComponet)
@@ -1265,9 +1265,10 @@ ghcBinaryName (GHCTargetVersion Nothing _) = T.unpack ("ghc" <> T.pack exeExt)
installDestSanityCheck :: ( MonadIO m installDestSanityCheck :: ( MonadIO m
, MonadCatch m , MonadCatch m
) => ) =>
FilePath -> InstallDirResolved ->
Excepts '[DirNotEmpty] m () Excepts '[DirNotEmpty] m ()
installDestSanityCheck isoDir = do installDestSanityCheck (IsolateDirResolved isoDir) = do
hideErrorDef [doesNotExistErrorType] () $ do hideErrorDef [doesNotExistErrorType] () $ do
contents <- liftIO $ getDirectoryContentsRecursive isoDir contents <- liftIO $ getDirectoryContentsRecursive isoDir
unless (null contents) (throwE $ DirNotEmpty isoDir) unless (null contents) (throwE $ DirNotEmpty isoDir)
installDestSanityCheck _ = pure ()

View File

@@ -473,7 +473,7 @@ recyclePathForcibly fp
liftIO (moveFile fp dest) liftIO (moveFile fp dest)
`catch` `catch`
(\e -> if | isDoesNotExistError e -> pure () (\e -> if | isDoesNotExistError e -> pure ()
| isPermissionError e {- EXDEV on windows -} -> recover (liftIO $ removePathForcibly fp) | isPermissionError e || ioeGetErrorType e == UnsupportedOperation {- EXDEV on windows -} -> recover (liftIO $ removePathForcibly fp)
| otherwise -> throwIO e) | otherwise -> throwIO e)
`finally` `finally`
liftIO (handleIO (\_ -> pure ()) $ removePathForcibly tmp) liftIO (handleIO (\_ -> pure ()) $ removePathForcibly tmp)
@@ -515,7 +515,7 @@ recycleFile fp
let dest = tmp </> takeFileName fp let dest = tmp </> takeFileName fp
liftIO (moveFile fp dest) liftIO (moveFile fp dest)
`catch` `catch`
(\e -> if isPermissionError e {- EXDEV on windows -} then recover (liftIO $ removePathForcibly fp) else throwIO e) (\e -> if isPermissionError e || ioeGetErrorType e == UnsupportedOperation {- EXDEV on windows -} then recover (liftIO $ removePathForcibly fp) else throwIO e)
`finally` `finally`
liftIO (handleIO (\_ -> pure ()) $ removePathForcibly tmp) liftIO (handleIO (\_ -> pure ()) $ removePathForcibly tmp)
| otherwise = liftIO $ removeFile fp | otherwise = liftIO $ removeFile fp

View File

@@ -13,7 +13,8 @@ theme:
nav: nav:
- Home: index.md - Home: index.md
- "Getting Started": install.md - "Getting started": install.md
- "First steps": steps.md
- "User Guide": guide.md - "User Guide": guide.md
- "Developer Guide": dev.md - "Developer Guide": dev.md
- About: about.md - About: about.md

View File

@@ -16,6 +16,7 @@
# * BOOTSTRAP_HASKELL_INSTALL_HLS - whether to install latest hls # * BOOTSTRAP_HASKELL_INSTALL_HLS - whether to install latest hls
# * BOOTSTRAP_HASKELL_ADJUST_BASHRC - whether to adjust PATH in bashrc (prepend) # * BOOTSTRAP_HASKELL_ADJUST_BASHRC - whether to adjust PATH in bashrc (prepend)
# * BOOTSTRAP_HASKELL_ADJUST_CABAL_CONFIG - whether to adjust mingw paths in cabal.config on windows # * BOOTSTRAP_HASKELL_ADJUST_CABAL_CONFIG - whether to adjust mingw paths in cabal.config on windows
# * GHCUP_BASE_URL - the base url for ghcup binary download (use this to overwrite https://downloads.haskell.org/~ghcup with a mirror)
# License: LGPL-3.0 # License: LGPL-3.0
@@ -25,8 +26,8 @@
plat="$(uname -s)" plat="$(uname -s)"
arch=$(uname -m) arch=$(uname -m)
ghver="0.1.17.5" ghver="0.1.17.7"
base_url="https://downloads.haskell.org/~ghcup" : "${GHCUP_BASE_URL:=https://downloads.haskell.org/~ghcup}"
export GHCUP_SKIP_UPDATE_CHECK=yes export GHCUP_SKIP_UPDATE_CHECK=yes
@@ -157,7 +158,7 @@ _done() {
green "and the \"Mingw package management docs\"" green "and the \"Mingw package management docs\""
green "desktop shortcuts." green "desktop shortcuts."
green green
green "If you are new to Haskell, check out https://www.haskell.org/ghcup/install/#first-steps" green "If you are new to Haskell, check out https://www.haskell.org/ghcup/steps/"
;; ;;
*) *)
green green
@@ -172,7 +173,7 @@ _done() {
green "To install other GHC versions and tools, run:" green "To install other GHC versions and tools, run:"
green " ghcup tui" green " ghcup tui"
green green
green "If you are new to Haskell, check out https://www.haskell.org/ghcup/install/#first-steps" green "If you are new to Haskell, check out https://www.haskell.org/ghcup/steps/"
;; ;;
esac esac
@@ -197,12 +198,15 @@ posix_realpath() {
current_loop=0 current_loop=0
max_loops=50 max_loops=50
mysource=$1 mysource=$1
# readlink and '[ -h $path ]' behave different wrt '/sbin/' and '/sbin', so we strip it
mysource=${mysource%/}
[ -z "${mysource}" ] && mysource=$1
while [ -h "${mysource}" ]; do while [ -h "${mysource}" ]; do
current_loop=$((current_loop+1)) current_loop=$((current_loop+1))
mydir="$( cd -P "$( dirname "${mysource}" )" > /dev/null 2>&1 && pwd )" mydir="$( cd -P "$( dirname "${mysource}" )" > /dev/null 2>&1 && pwd )"
mysource="$(readlink "${mysource}")" mysource="$(readlink "${mysource}")"
[ "${mysource%${mysource#?}}"x != '/x' ] && mysource="${mydir}/${mysource}" [ "${mysource%"${mysource#?}"}"x != '/x' ] && mysource="${mydir%/}/${mysource}"
if [ ${current_loop} -gt ${max_loops} ] ; then if [ ${current_loop} -gt ${max_loops} ] ; then
(>&2 echo "${1}: Too many levels of symbolic links") (>&2 echo "${1}: Too many levels of symbolic links")
@@ -232,26 +236,26 @@ download_ghcup() {
# we could be in a 32bit docker container, in which # we could be in a 32bit docker container, in which
# case uname doesn't give us what we want # case uname doesn't give us what we want
if [ "$(getconf LONG_BIT)" = "32" ] ; then if [ "$(getconf LONG_BIT)" = "32" ] ; then
_url=${base_url}/${ghver}/i386-linux-ghcup-${ghver} _url=${GHCUP_BASE_URL}/${ghver}/i386-linux-ghcup-${ghver}
elif [ "$(getconf LONG_BIT)" = "64" ] ; then elif [ "$(getconf LONG_BIT)" = "64" ] ; then
_url=${base_url}/${ghver}/x86_64-linux-ghcup-${ghver} _url=${GHCUP_BASE_URL}/${ghver}/x86_64-linux-ghcup-${ghver}
else else
die "Unknown long bit size: $(getconf LONG_BIT)" die "Unknown long bit size: $(getconf LONG_BIT)"
fi fi
;; ;;
i*86) i*86)
_url=${base_url}/${ghver}/i386-linux-ghcup-${ghver} _url=${GHCUP_BASE_URL}/${ghver}/i386-linux-ghcup-${ghver}
;; ;;
armv7*|*armv8l*) armv7*|*armv8l*)
_url=${base_url}/${ghver}/armv7-linux-ghcup-${ghver} _url=${GHCUP_BASE_URL}/${ghver}/armv7-linux-ghcup-${ghver}
;; ;;
aarch64|arm64) aarch64|arm64)
# we could be in a 32bit docker container, in which # we could be in a 32bit docker container, in which
# case uname doesn't give us what we want # case uname doesn't give us what we want
if [ "$(getconf LONG_BIT)" = "32" ] ; then if [ "$(getconf LONG_BIT)" = "32" ] ; then
_url=${base_url}/${ghver}/armv7-linux-ghcup-${ghver} _url=${GHCUP_BASE_URL}/${ghver}/armv7-linux-ghcup-${ghver}
elif [ "$(getconf LONG_BIT)" = "64" ] ; then elif [ "$(getconf LONG_BIT)" = "64" ] ; then
_url=${base_url}/${ghver}/aarch64-linux-ghcup-${ghver} _url=${GHCUP_BASE_URL}/${ghver}/aarch64-linux-ghcup-${ghver}
else else
die "Unknown long bit size: $(getconf LONG_BIT)" die "Unknown long bit size: $(getconf LONG_BIT)"
fi fi
@@ -278,15 +282,15 @@ download_ghcup() {
*) die "Unknown architecture: ${arch}" *) die "Unknown architecture: ${arch}"
;; ;;
esac esac
_url=${base_url}/${ghver}/x86_64-freebsd${freebsd_ver}-ghcup-${ghver} _url=${GHCUP_BASE_URL}/${ghver}/x86_64-freebsd${freebsd_ver}-ghcup-${ghver}
;; ;;
"Darwin"|"darwin") "Darwin"|"darwin")
case "${arch}" in case "${arch}" in
x86_64|amd64) x86_64|amd64)
_url=${base_url}/${ghver}/x86_64-apple-darwin-ghcup-${ghver} _url=${GHCUP_BASE_URL}/${ghver}/x86_64-apple-darwin-ghcup-${ghver}
;; ;;
aarch64|arm64|armv8l) aarch64|arm64|armv8l)
_url=${base_url}/${ghver}/aarch64-apple-darwin-ghcup-${ghver} _url=${GHCUP_BASE_URL}/${ghver}/aarch64-apple-darwin-ghcup-${ghver}
;; ;;
i*86) i*86)
die "i386 currently not supported!" die "i386 currently not supported!"
@@ -298,7 +302,7 @@ download_ghcup() {
MSYS*|MINGW*) MSYS*|MINGW*)
case "${arch}" in case "${arch}" in
x86_64|amd64) x86_64|amd64)
_url=${base_url}/${ghver}/x86_64-mingw64-ghcup-${ghver}.exe _url=${GHCUP_BASE_URL}/${ghver}/x86_64-mingw64-ghcup-${ghver}.exe
;; ;;
*) die "Unknown architecture: ${arch}" *) die "Unknown architecture: ${arch}"
;; ;;

View File

@@ -239,7 +239,27 @@ if ($Silent -and !($InstallDir)) {
} }
} else { } else {
while ($true) { while ($true) {
Print-Msg -color Magenta -msg ('Where to install to (this should be a short Path, preferably a Drive like ''C:\''){1}Press enter to accept the default [{0}]:' -f $defaultGhcupBasePrefix, "`n") Print-Msg -color Magenta -msg (@'
Welcome to Haskell!
This script will 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 $basePrefixPrompt = Read-Host
$GhcupBasePrefix = ($defaultGhcupBasePrefix,$basePrefixPrompt)[[bool]$basePrefixPrompt] $GhcupBasePrefix = ($defaultGhcupBasePrefix,$basePrefixPrompt)[[bool]$basePrefixPrompt]
if (!($GhcupBasePrefix.EndsWith('\'))) { if (!($GhcupBasePrefix.EndsWith('\'))) {

View File

@@ -1,4 +1,4 @@
resolver: lts-18.27 resolver: lts-18.28
packages: packages:
- . - .