Compare commits
73 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
c19dd5ee8b
|
|||
|
6ae3bfe395
|
|||
|
4f82e80dad
|
|||
|
8e8198546f
|
|||
|
9497e310ca
|
|||
|
02135bdbae
|
|||
|
041a341879
|
|||
|
15dd810d67
|
|||
|
7982f3aec0
|
|||
|
2fb07201c7
|
|||
|
b5ca01dc4f
|
|||
|
fa523d590e
|
|||
|
523f2f57e1
|
|||
|
d662682fb5
|
|||
|
ff2b06a5e8
|
|||
|
aece305003
|
|||
|
ef8da9bcec
|
|||
|
3cd55beab1
|
|||
|
6766501858
|
|||
|
d5b41683ca
|
|||
|
ff8dbe111d
|
|||
|
28d4071fac
|
|||
|
31a523755f
|
|||
|
3d1d8f1af7
|
|||
|
167f6d0683
|
|||
|
8580487b61
|
|||
|
a8b1c33280
|
|||
|
fca2a4134b
|
|||
|
f90741f4d3
|
|||
|
ba4b45f7fb
|
|||
|
4767f3db5b
|
|||
|
709658462c
|
|||
|
c431c0ae00
|
|||
|
6f61b5dbef
|
|||
|
c42c4b64f9
|
|||
|
d3a36c2c9a
|
|||
|
6799e9616e
|
|||
|
|
e8d962ac44 | ||
|
ac1e145028
|
|||
|
2fdf121167
|
|||
|
dcca8b0bf2
|
|||
|
b1f891b005
|
|||
|
648dcc7287
|
|||
|
2175f7dd3d
|
|||
|
aff90a52f1
|
|||
|
0f14dee72a
|
|||
|
ae2031174e
|
|||
|
c163278c64
|
|||
|
d10133f06f
|
|||
|
4377fc663e
|
|||
|
487e236882
|
|||
|
|
8fc128e89b | ||
|
|
737f72f90f | ||
|
|
c3aab65521 | ||
|
|
972474f79a | ||
| bc64d2ade0 | |||
|
|
eddda55fe6 | ||
|
|
13aca91231 | ||
|
|
6011242eae | ||
|
|
cadb5086e1 | ||
|
|
10a30bbf38 | ||
|
|
6ac7a75bab | ||
|
|
d60f58cf43 | ||
|
|
7a6a119829 | ||
|
|
f0fb019c70 | ||
|
|
0f98ec6b78 | ||
|
|
107fed6e60 | ||
|
|
59a9a770a5 | ||
|
|
20bcb26e3d | ||
|
|
be82565775 | ||
|
|
f8d0243146 | ||
|
|
d7f82d643c | ||
|
|
15560a06b1 |
@@ -49,6 +49,7 @@ variables:
|
|||||||
OS: "LINUX"
|
OS: "LINUX"
|
||||||
ARCH: "ARM"
|
ARCH: "ARM"
|
||||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||||
|
retry: 2
|
||||||
|
|
||||||
.linux:aarch64:
|
.linux:aarch64:
|
||||||
image: "registry.gitlab.haskell.org/ghc/ci-images/aarch64-linux-deb10:$DOCKER_REV"
|
image: "registry.gitlab.haskell.org/ghc/ci-images/aarch64-linux-deb10:$DOCKER_REV"
|
||||||
@@ -75,7 +76,7 @@ variables:
|
|||||||
ARCH: "ARM64"
|
ARCH: "ARM64"
|
||||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||||
|
|
||||||
.freebsd:
|
.freebsd13:
|
||||||
tags:
|
tags:
|
||||||
- x86_64-freebsd13
|
- x86_64-freebsd13
|
||||||
variables:
|
variables:
|
||||||
@@ -83,6 +84,14 @@ variables:
|
|||||||
ARCH: "64"
|
ARCH: "64"
|
||||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||||
|
|
||||||
|
.freebsd12:
|
||||||
|
tags:
|
||||||
|
- x86_64-freebsd12
|
||||||
|
variables:
|
||||||
|
OS: "FREEBSD"
|
||||||
|
ARCH: "64"
|
||||||
|
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||||
|
|
||||||
.windows:
|
.windows:
|
||||||
tags:
|
tags:
|
||||||
- new-x86_64-windows
|
- new-x86_64-windows
|
||||||
@@ -90,6 +99,7 @@ variables:
|
|||||||
OS: "WINDOWS"
|
OS: "WINDOWS"
|
||||||
ARCH: "64"
|
ARCH: "64"
|
||||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||||
|
retry: 2
|
||||||
|
|
||||||
.root_cleanup:
|
.root_cleanup:
|
||||||
after_script:
|
after_script:
|
||||||
@@ -99,7 +109,7 @@ variables:
|
|||||||
script:
|
script:
|
||||||
- bash ./.gitlab/script/ghcup_version.sh
|
- bash ./.gitlab/script/ghcup_version.sh
|
||||||
variables:
|
variables:
|
||||||
JSON_VERSION: "0.0.7"
|
JSON_VERSION: "0.0.6"
|
||||||
artifacts:
|
artifacts:
|
||||||
expire_in: 2 week
|
expire_in: 2 week
|
||||||
paths:
|
paths:
|
||||||
@@ -173,10 +183,18 @@ variables:
|
|||||||
runInNixShell ./.gitlab/before_script/darwin/install_deps.sh 2>&1
|
runInNixShell ./.gitlab/before_script/darwin/install_deps.sh 2>&1
|
||||||
runInNixShell ./.gitlab/script/ghcup_version.sh 2>&1
|
runInNixShell ./.gitlab/script/ghcup_version.sh 2>&1
|
||||||
|
|
||||||
.test_ghcup_version:freebsd:
|
.test_ghcup_version:freebsd12:
|
||||||
extends:
|
extends:
|
||||||
- .test_ghcup_version
|
- .test_ghcup_version
|
||||||
- .freebsd
|
- .freebsd12
|
||||||
|
- .root_cleanup
|
||||||
|
before_script:
|
||||||
|
- ./.gitlab/before_script/freebsd/install_deps.sh
|
||||||
|
|
||||||
|
.test_ghcup_version:freebsd13:
|
||||||
|
extends:
|
||||||
|
- .test_ghcup_version
|
||||||
|
- .freebsd13
|
||||||
- .root_cleanup
|
- .root_cleanup
|
||||||
before_script:
|
before_script:
|
||||||
- ./.gitlab/before_script/freebsd/install_deps.sh
|
- ./.gitlab/before_script/freebsd/install_deps.sh
|
||||||
@@ -207,7 +225,7 @@ variables:
|
|||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
||||||
variables:
|
variables:
|
||||||
JSON_VERSION: "0.0.7"
|
JSON_VERSION: "0.0.6"
|
||||||
|
|
||||||
######## stack test ########
|
######## stack test ########
|
||||||
|
|
||||||
@@ -263,6 +281,23 @@ test:linux:
|
|||||||
CABAL_VERSION: "3.4.0.0"
|
CABAL_VERSION: "3.4.0.0"
|
||||||
needs: []
|
needs: []
|
||||||
|
|
||||||
|
test:linux:hls:
|
||||||
|
stage: test
|
||||||
|
extends:
|
||||||
|
- .test_ghcup_version
|
||||||
|
- .debian
|
||||||
|
variables:
|
||||||
|
GHC_VERSION: "8.10.7"
|
||||||
|
HLS_TARGET_VERSION: "1.4.0"
|
||||||
|
CABAL_VERSION: "3.6.0.0"
|
||||||
|
needs: []
|
||||||
|
when: manual
|
||||||
|
allow_failure: true
|
||||||
|
before_script:
|
||||||
|
- ./.gitlab/before_script/linux/install_deps.sh
|
||||||
|
script:
|
||||||
|
- ./.gitlab/script/ghcup_hls.sh
|
||||||
|
|
||||||
test:linux:cross-armv7:
|
test:linux:cross-armv7:
|
||||||
stage: test
|
stage: test
|
||||||
extends:
|
extends:
|
||||||
@@ -355,9 +390,19 @@ test:mac:aarch64:
|
|||||||
|
|
||||||
######## freebsd test ########
|
######## freebsd test ########
|
||||||
|
|
||||||
test:freebsd:
|
test:freebsd12:
|
||||||
stage: test
|
stage: test
|
||||||
extends: .test_ghcup_version:freebsd
|
extends: .test_ghcup_version:freebsd12
|
||||||
|
variables:
|
||||||
|
GHC_VERSION: "8.10.4"
|
||||||
|
CABAL_VERSION: "3.4.0.0"
|
||||||
|
allow_failure: true # freebsd runners are unreliable
|
||||||
|
when: manual
|
||||||
|
needs: []
|
||||||
|
|
||||||
|
test:freebsd13:
|
||||||
|
stage: test
|
||||||
|
extends: .test_ghcup_version:freebsd13
|
||||||
variables:
|
variables:
|
||||||
GHC_VERSION: "8.10.4"
|
GHC_VERSION: "8.10.4"
|
||||||
CABAL_VERSION: "3.4.0.0"
|
CABAL_VERSION: "3.4.0.0"
|
||||||
@@ -491,11 +536,26 @@ release:darwin:aarch64:
|
|||||||
|
|
||||||
######## freebsd release ########
|
######## freebsd release ########
|
||||||
|
|
||||||
release:freebsd:
|
release:freebsd12:
|
||||||
stage: release
|
stage: release
|
||||||
needs: ["test:freebsd"]
|
needs: ["test:freebsd12"]
|
||||||
extends:
|
extends:
|
||||||
- .freebsd
|
- .freebsd12
|
||||||
|
- .release_ghcup
|
||||||
|
- .root_cleanup
|
||||||
|
before_script:
|
||||||
|
- ./.gitlab/before_script/freebsd/install_deps.sh
|
||||||
|
variables:
|
||||||
|
ARTIFACT: "x86_64-portbld-freebsd-ghcup"
|
||||||
|
GHC_VERSION: "8.10.6"
|
||||||
|
CABAL_VERSION: "3.4.0.0"
|
||||||
|
allow_failure: true
|
||||||
|
|
||||||
|
release:freebsd13:
|
||||||
|
stage: release
|
||||||
|
needs: ["test:freebsd13"]
|
||||||
|
extends:
|
||||||
|
- .freebsd13
|
||||||
- .release_ghcup
|
- .release_ghcup
|
||||||
- .root_cleanup
|
- .root_cleanup
|
||||||
before_script:
|
before_script:
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
if [ "${OS}" = "WINDOWS" ] ; then
|
if [ "${OS}" = "WINDOWS" ] ; then
|
||||||
export GHCUP_INSTALL_BASE_PREFIX="$CI_PROJECT_DIR"
|
export GHCUP_INSTALL_BASE_PREFIX="$CI_PROJECT_DIR"
|
||||||
export PATH="$GHCUP_INSTALL_BASE_PREFIX/ghcup/bin:$CI_PROJECT_DIR/.local/bin:$PATH"
|
export GHCUP_BIN="$CI_PROJECT_DIR/ghcup/bin"
|
||||||
|
export PATH="$GHCUP_BIN:$CI_PROJECT_DIR/.local/bin:$PATH"
|
||||||
export TMPDIR="$CI_PROJECT_DIR/tmp"
|
export TMPDIR="$CI_PROJECT_DIR/tmp"
|
||||||
else
|
else
|
||||||
export GHCUP_INSTALL_BASE_PREFIX="$CI_PROJECT_DIR"
|
export GHCUP_INSTALL_BASE_PREFIX="$CI_PROJECT_DIR"
|
||||||
export PATH="$CI_PROJECT_DIR/.ghcup/bin:$CI_PROJECT_DIR/.local/bin:/opt/llvm/bin:$PATH"
|
export GHCUP_BIN="$CI_PROJECT_DIR/.ghcup/bin"
|
||||||
|
export PATH="$GHCUP_BIN:$CI_PROJECT_DIR/.local/bin:/opt/llvm/bin:$PATH"
|
||||||
export TMPDIR="$CI_PROJECT_DIR/tmp"
|
export TMPDIR="$CI_PROJECT_DIR/tmp"
|
||||||
fi
|
fi
|
||||||
|
|||||||
51
.gitlab/script/ghcup_hls.sh
Executable file
51
.gitlab/script/ghcup_hls.sh
Executable file
@@ -0,0 +1,51 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -eux
|
||||||
|
|
||||||
|
. "$( cd "$(dirname "$0")" ; pwd -P )/../ghcup_env"
|
||||||
|
|
||||||
|
mkdir -p "$CI_PROJECT_DIR"/.local/bin
|
||||||
|
|
||||||
|
CI_PROJECT_DIR=$(pwd)
|
||||||
|
|
||||||
|
ecabal() {
|
||||||
|
cabal "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
eghcup() {
|
||||||
|
ghcup -v -c -s file://$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
git describe --always
|
||||||
|
|
||||||
|
### build
|
||||||
|
|
||||||
|
ecabal update
|
||||||
|
|
||||||
|
ecabal build -w ghc-${GHC_VERSION}
|
||||||
|
cp "$(ecabal new-exec -w ghc-${GHC_VERSION} --verbose=0 --offline sh -- -c 'command -v ghcup')" "$CI_PROJECT_DIR"/.local/bin/ghcup
|
||||||
|
|
||||||
|
### cleanup
|
||||||
|
|
||||||
|
rm -rf "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup
|
||||||
|
|
||||||
|
### manual cli based testing
|
||||||
|
|
||||||
|
eghcup --numeric-version
|
||||||
|
|
||||||
|
eghcup install ghc ${GHC_VERSION}
|
||||||
|
eghcup set ghc ${GHC_VERSION}
|
||||||
|
eghcup install cabal ${CABAL_VERSION}
|
||||||
|
|
||||||
|
cabal --version
|
||||||
|
|
||||||
|
eghcup debug-info
|
||||||
|
|
||||||
|
eghcup compile hls -j $(nproc) -v ${HLS_TARGET_VERSION} ${GHC_VERSION}
|
||||||
|
|
||||||
|
[ `$(eghcup whereis hls ${HLS_TARGET_VERSION}) --numeric-version` = "${HLS_TARGET_VERSION}" ] || [ `$(eghcup whereis hls ${HLS_TARGET_VERSION}) --numeric-version | sed 's/.0$//'` = "${HLS_TARGET_VERSION}" ]
|
||||||
|
|
||||||
|
# nuke
|
||||||
|
eghcup nuke
|
||||||
|
[ ! -e "${GHCUP_INSTALL_BASE_PREFIX}/.ghcup" ]
|
||||||
|
|
||||||
@@ -101,6 +101,10 @@ eghcup install ghc ${GHC_VERSION}
|
|||||||
eghcup set ghc ${GHC_VERSION}
|
eghcup set ghc ${GHC_VERSION}
|
||||||
eghcup install cabal ${CABAL_VERSION}
|
eghcup install cabal ${CABAL_VERSION}
|
||||||
[ `$(eghcup whereis cabal ${CABAL_VERSION}) --numeric-version` = "${CABAL_VERSION}" ]
|
[ `$(eghcup whereis cabal ${CABAL_VERSION}) --numeric-version` = "${CABAL_VERSION}" ]
|
||||||
|
eghcup unset cabal
|
||||||
|
"$GHCUP_BIN"/cabal --version && exit || echo yes
|
||||||
|
eghcup set cabal ${CABAL_VERSION}
|
||||||
|
[ `$(eghcup whereis cabal ${CABAL_VERSION}) --numeric-version` = "${CABAL_VERSION}" ]
|
||||||
|
|
||||||
cabal --version
|
cabal --version
|
||||||
|
|
||||||
@@ -151,9 +155,13 @@ else
|
|||||||
[ "$(ghc --numeric-version)" = "8.10.3" ]
|
[ "$(ghc --numeric-version)" = "8.10.3" ]
|
||||||
eghcup set ${GHC_VERSION}
|
eghcup set ${GHC_VERSION}
|
||||||
[ "$(ghc --numeric-version)" = "${ghc_ver}" ]
|
[ "$(ghc --numeric-version)" = "${ghc_ver}" ]
|
||||||
|
eghcup unset ghc
|
||||||
|
"$GHCUP_BIN"/ghc --numeric-version && exit || echo yes
|
||||||
|
eghcup set ${GHC_VERSION}
|
||||||
eghcup --offline rm 8.10.3
|
eghcup --offline rm 8.10.3
|
||||||
[ "$(ghc --numeric-version)" = "${ghc_ver}" ]
|
[ "$(ghc --numeric-version)" = "${ghc_ver}" ]
|
||||||
|
|
||||||
|
|
||||||
if [ "${OS}" = "DARWIN" ] ; then
|
if [ "${OS}" = "DARWIN" ] ; then
|
||||||
eghcup install hls
|
eghcup install hls
|
||||||
$(eghcup whereis hls) --version
|
$(eghcup whereis hls) --version
|
||||||
@@ -164,9 +172,13 @@ else
|
|||||||
if [ "${ARCH}" = "64" ] ; then
|
if [ "${ARCH}" = "64" ] ; then
|
||||||
eghcup install hls
|
eghcup install hls
|
||||||
haskell-language-server-wrapper --version
|
haskell-language-server-wrapper --version
|
||||||
|
eghcup unset hls
|
||||||
|
"$GHCUP_BIN"/haskell-language-server-wrapper --version && exit || echo yes
|
||||||
|
|
||||||
eghcup install stack
|
eghcup install stack
|
||||||
stack --version
|
stack --version
|
||||||
|
eghcup unset hls
|
||||||
|
"$GHCUP_BIN"/stack --version && exit || echo yes
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
87
README.md
87
README.md
@@ -10,13 +10,15 @@ Similar in scope to [rustup](https://github.com/rust-lang-nursery/rustup.rs), [p
|
|||||||
[](https://app.element.io/#/room/#haskell-tooling:matrix.org)
|
[](https://app.element.io/#/room/#haskell-tooling:matrix.org)
|
||||||
[](https://discord.gg/pKYf3zDQU7)
|
[](https://discord.gg/pKYf3zDQU7)
|
||||||
[](https://gitter.im/haskell/ghcup?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/haskell/ghcup?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
<a href="https://opencollective.com/ghcup#category-CONTRIBUTE"><img src="https://opencollective.com/webpack/donate/button@2x.png?color=blue" alt="Donate" width="150"></a>
|
||||||
|
|
||||||
* [Installation](#installation)
|
* [Installation](#installation)
|
||||||
* [Simple bootstrap](#simple-bootstrap)
|
* [Supported platforms](#supported-platforms)
|
||||||
* [Manual install](#manual-install)
|
* [Manual install](#manual-install)
|
||||||
* [Vim integration](#vim-integration)
|
* [Vim integration](#vim-integration)
|
||||||
* [Usage](#usage)
|
* [Usage](#usage)
|
||||||
* [Configuration](#configuration)
|
* [Configuration](#configuration)
|
||||||
|
* [GPG verification](#gpg-verification)
|
||||||
* [Manpages](#manpages)
|
* [Manpages](#manpages)
|
||||||
* [Shell-completion](#shell-completion)
|
* [Shell-completion](#shell-completion)
|
||||||
* [Compiling GHC from source](#compiling-ghc-from-source)
|
* [Compiling GHC from source](#compiling-ghc-from-source)
|
||||||
@@ -34,9 +36,59 @@ Similar in scope to [rustup](https://github.com/rust-lang-nursery/rustup.rs), [p
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Simple bootstrap
|
Most users should follow the instructions at [https://www.haskell.org/ghcup/](https://www.haskell.org/ghcup/).
|
||||||
|
Advanced users may want to perform a [manual installation](#manual-install).
|
||||||
|
|
||||||
Follow the instructions at [https://www.haskell.org/ghcup/](https://www.haskell.org/ghcup/)
|
### Supported platforms
|
||||||
|
|
||||||
|
This list may not be exhaustive and specifies support for bindists only.
|
||||||
|
|
||||||
|
| Platform | Architecture | ghcup | GHC | cabal | HLS | stack |
|
||||||
|
| ------ | ------ | ------ | ------ | ------ | ------ | ------ |
|
||||||
|
| Windows 7 | amd64 | ❔ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| Windows 10 | amd64 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| Windows Server 2016 | amd64 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| Windows Server 2019 | amd64 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| Windows Server 2022 | amd64 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| Windows WSL1 | amd64 | ❌ | ❔ | ❔ | ❔ | ❔ |
|
||||||
|
| Windows WSL2 | amd64 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| MacOS >=13 | amd64 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| MacOS <13 | amd64 | ❌ | ❔ | ❔ | ❔ | ❔ |
|
||||||
|
| MacOS | aarch64 | ✅ | ✅ | ✅ | ⚠️ | ❌ |
|
||||||
|
| FreeBSD | amd64 | ✅ | ⚠️ | ✅ | ⚠️ | ❌ |
|
||||||
|
| Linux generic | x86 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| Linux generic | amd64 | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| Linux generic | aarch64 | ✅ | ⚠️ | ✅ | ⚠️ | ❌ |
|
||||||
|
| Linux generic | armv7 | ✅ | ⚠️ | ✅ | ⚠️ | ❌ |
|
||||||
|
|
||||||
|
#### Windows 7
|
||||||
|
|
||||||
|
May or may not work, several issues:
|
||||||
|
|
||||||
|
* https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/140
|
||||||
|
* https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/197
|
||||||
|
|
||||||
|
#### WSL1
|
||||||
|
|
||||||
|
Unsupported. GHC may or may not work. Upgrade to WSL2.
|
||||||
|
|
||||||
|
#### MacOS <13
|
||||||
|
|
||||||
|
Not supported. Would require separate binaries, since >=13 binaries are incompatible.
|
||||||
|
Please upgrade.
|
||||||
|
|
||||||
|
#### MacOS aarch64
|
||||||
|
|
||||||
|
HLS bindists are still experimental. Stack is theoretically supported, but has no binaries yet.
|
||||||
|
|
||||||
|
#### FreeBSD
|
||||||
|
|
||||||
|
Lacks some upstream bindists and may need compat libs, since most bindists are built on FreeBSD-12.
|
||||||
|
HLS bindists are experimental.
|
||||||
|
|
||||||
|
#### Linux ARMv7/AARCH64
|
||||||
|
|
||||||
|
Lower availability of bindists. HLS only has experimental ones. Stack not supported currently.
|
||||||
|
|
||||||
### Manual install
|
### Manual install
|
||||||
|
|
||||||
@@ -95,6 +147,34 @@ explaining all possible configurations can be found in this repo: [config.yaml](
|
|||||||
|
|
||||||
Partial configuration is fine. Command line options always override the config file settings.
|
Partial configuration is fine. Command line options always override the config file settings.
|
||||||
|
|
||||||
|
### GPG verification
|
||||||
|
|
||||||
|
GHCup supports verifying the GPG signature of the metadata file. The metadata file then contains SHA256 hashes of all downloads, so
|
||||||
|
this is cryptographically secure.
|
||||||
|
|
||||||
|
First, obtain the gpg key:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
gpg --batch --keyserver keys.openpgp.org --recv-keys 7784930957807690A66EBDBE3786C5262ECB4A3F
|
||||||
|
```
|
||||||
|
|
||||||
|
Then verify the gpg key in one of these ways:
|
||||||
|
|
||||||
|
1. find out where I live and visit me to do offline key signing
|
||||||
|
2. figure out my mobile phone number and call me to verify the fingerprint
|
||||||
|
3. more boring: contact me on Libera IRC (`maerwald`) and verify the fingerprint
|
||||||
|
|
||||||
|
Once you've verified the key, you have to figure out if you trust me.
|
||||||
|
|
||||||
|
If you trust me, then you can configure gpg in `~/.ghcup/config.yaml`:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
gpg-setting: GPGLax # GPGStrict | GPGLax | GPGNone
|
||||||
|
```
|
||||||
|
|
||||||
|
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>`.
|
||||||
|
|
||||||
### 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.
|
||||||
@@ -155,6 +235,7 @@ This is the complete list of env variables that change GHCup behavior:
|
|||||||
* `GHCUP_INSTALL_BASE_PREFIX`: the base of ghcup (default: `$HOME`)
|
* `GHCUP_INSTALL_BASE_PREFIX`: the base of ghcup (default: `$HOME`)
|
||||||
* `GHCUP_CURL_OPTS`: additional options that can be passed to curl
|
* `GHCUP_CURL_OPTS`: additional options that can be passed to curl
|
||||||
* `GHCUP_WGET_OPTS`: additional options that can be passed to wget
|
* `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
|
* `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
|
* `CC`/`LD` etc.: full environment is passed to the build system when compiling GHC via GHCup
|
||||||
|
|
||||||
|
|||||||
@@ -11,21 +11,23 @@
|
|||||||
module Main where
|
module Main where
|
||||||
|
|
||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
import GHCup.Types.Optics
|
|
||||||
import GHCup.Errors
|
import GHCup.Errors
|
||||||
import GHCup.Platform
|
import GHCup.Platform
|
||||||
import GHCup.Utils.Dirs
|
import GHCup.Utils.Dirs
|
||||||
|
import GHCup.Utils.Logger
|
||||||
import GHCup.Types.JSON ( )
|
import GHCup.Types.JSON ( )
|
||||||
|
|
||||||
import Control.Monad.Trans.Reader ( runReaderT )
|
import Control.Monad.Trans.Reader ( runReaderT )
|
||||||
import Control.Monad.IO.Class
|
import Control.Monad.IO.Class
|
||||||
import Data.Char ( toLower )
|
import Data.Char ( toLower )
|
||||||
|
import Data.Maybe
|
||||||
#if !MIN_VERSION_base(4,13,0)
|
#if !MIN_VERSION_base(4,13,0)
|
||||||
import Data.Semigroup ( (<>) )
|
import Data.Semigroup ( (<>) )
|
||||||
#endif
|
#endif
|
||||||
import Options.Applicative hiding ( style )
|
import Options.Applicative hiding ( style )
|
||||||
import Haskus.Utils.Variant.Excepts
|
import Haskus.Utils.Variant.Excepts
|
||||||
import System.Console.Pretty
|
import System.Console.Pretty
|
||||||
|
import System.Environment
|
||||||
import System.Exit
|
import System.Exit
|
||||||
import System.IO ( stderr )
|
import System.IO ( stderr )
|
||||||
import Text.Regex.Posix
|
import Text.Regex.Posix
|
||||||
@@ -114,12 +116,14 @@ com = subparser
|
|||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
no_color <- isJust <$> lookupEnv "NO_COLOR"
|
||||||
let loggerConfig = LoggerConfig { lcPrintDebug = True
|
let loggerConfig = LoggerConfig { lcPrintDebug = True
|
||||||
, colorOutter = T.hPutStr stderr
|
, consoleOutter = T.hPutStr stderr
|
||||||
, rawOutter = \_ -> pure ()
|
, fileOutter = \_ -> pure ()
|
||||||
|
, fancyColors = not no_color
|
||||||
}
|
}
|
||||||
dirs <- liftIO getAllDirs
|
dirs <- liftIO getAllDirs
|
||||||
let leanAppstate = LeanAppState (Settings True False Never Curl True GHCupURL False) dirs defaultKeyBindings loggerConfig
|
let leanAppstate = LeanAppState (Settings True False Never Curl True GHCupURL False GPGNone False) dirs defaultKeyBindings loggerConfig
|
||||||
|
|
||||||
pfreq <- (
|
pfreq <- (
|
||||||
flip runReaderT leanAppstate . runE @'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound] $ platformRequest
|
flip runReaderT leanAppstate . runE @'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound] $ platformRequest
|
||||||
@@ -129,7 +133,7 @@ main = do
|
|||||||
flip runReaderT leanAppstate $ logError $ T.pack $ prettyShow e
|
flip runReaderT leanAppstate $ logError $ T.pack $ prettyShow e
|
||||||
liftIO $ exitWith (ExitFailure 2)
|
liftIO $ exitWith (ExitFailure 2)
|
||||||
|
|
||||||
let appstate = AppState (Settings True False Never Curl True GHCupURL False) dirs defaultKeyBindings (GHCupInfo mempty mempty mempty) pfreq loggerConfig
|
let appstate = AppState (Settings True False Never Curl True GHCupURL False GPGNone False) dirs defaultKeyBindings (GHCupInfo mempty mempty mempty) pfreq loggerConfig
|
||||||
|
|
||||||
_ <- customExecParser (prefs showHelpOnError) (info (opts <**> helper) idm)
|
_ <- customExecParser (prefs showHelpOnError) (info (opts <**> helper) idm)
|
||||||
>>= \Options {..} -> case optCommand of
|
>>= \Options {..} -> case optCommand of
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import GHCup.Errors
|
|||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
import GHCup.Types.Optics
|
import GHCup.Types.Optics
|
||||||
import GHCup.Utils
|
import GHCup.Utils
|
||||||
|
import GHCup.Utils.Logger
|
||||||
import GHCup.Utils.Version.QQ
|
import GHCup.Utils.Version.QQ
|
||||||
|
|
||||||
import Codec.Archive
|
import Codec.Archive
|
||||||
@@ -229,6 +230,7 @@ validateTarballs (TarballFilter etool versionRegex) dls gt = do
|
|||||||
downloadAll ref dli = do
|
downloadAll ref dli = do
|
||||||
r <- runResourceT
|
r <- runResourceT
|
||||||
. runE @'[DigestError
|
. runE @'[DigestError
|
||||||
|
, GPGError
|
||||||
, DownloadFailed
|
, DownloadFailed
|
||||||
, UnknownArchive
|
, UnknownArchive
|
||||||
, ArchiveResult
|
, ArchiveResult
|
||||||
@@ -237,7 +239,7 @@ validateTarballs (TarballFilter etool versionRegex) dls gt = do
|
|||||||
case etool of
|
case etool of
|
||||||
Right (Just GHCup) -> do
|
Right (Just GHCup) -> do
|
||||||
tmpUnpack <- lift mkGhcupTmpDir
|
tmpUnpack <- lift mkGhcupTmpDir
|
||||||
_ <- liftE $ download (_dlUri dli) (Just (_dlHash dli)) tmpUnpack Nothing False
|
_ <- liftE $ download (_dlUri dli) Nothing (Just (_dlHash dli)) tmpUnpack Nothing False
|
||||||
pure Nothing
|
pure Nothing
|
||||||
Right _ -> do
|
Right _ -> do
|
||||||
p <- liftE $ downloadCached dli Nothing
|
p <- liftE $ downloadCached dli Nothing
|
||||||
@@ -247,7 +249,7 @@ validateTarballs (TarballFilter etool versionRegex) dls gt = do
|
|||||||
$ p
|
$ p
|
||||||
Left ShimGen -> do
|
Left ShimGen -> do
|
||||||
tmpUnpack <- lift mkGhcupTmpDir
|
tmpUnpack <- lift mkGhcupTmpDir
|
||||||
_ <- liftE $ download (_dlUri dli) (Just (_dlHash dli)) tmpUnpack Nothing False
|
_ <- liftE $ download (_dlUri dli) Nothing (Just (_dlHash dli)) tmpUnpack Nothing False
|
||||||
pure Nothing
|
pure Nothing
|
||||||
case r of
|
case r of
|
||||||
VRight (Just basePath) -> do
|
VRight (Just basePath) -> do
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ module BrickMain where
|
|||||||
import GHCup
|
import GHCup
|
||||||
import GHCup.Download
|
import GHCup.Download
|
||||||
import GHCup.Errors
|
import GHCup.Errors
|
||||||
import GHCup.Types.Optics hiding ( getGHCupInfo )
|
|
||||||
import GHCup.Types hiding ( LeanAppState(..) )
|
import GHCup.Types hiding ( LeanAppState(..) )
|
||||||
import GHCup.Utils
|
import GHCup.Utils
|
||||||
|
import GHCup.Utils.Logger
|
||||||
import GHCup.Utils.Prelude ( decUTF8Safe )
|
import GHCup.Utils.Prelude ( decUTF8Safe )
|
||||||
import GHCup.Utils.File
|
import GHCup.Utils.File
|
||||||
|
|
||||||
@@ -43,7 +43,6 @@ import Data.Vector ( Vector
|
|||||||
import Data.Versions hiding ( str )
|
import Data.Versions hiding ( str )
|
||||||
import Haskus.Utils.Variant.Excepts
|
import Haskus.Utils.Variant.Excepts
|
||||||
import Prelude hiding ( appendFile )
|
import Prelude hiding ( appendFile )
|
||||||
import System.Environment
|
|
||||||
import System.Exit
|
import System.Exit
|
||||||
import System.IO.Unsafe
|
import System.IO.Unsafe
|
||||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||||
@@ -429,6 +428,7 @@ install' _ (_, ListResult {..}) = do
|
|||||||
, BuildFailed
|
, BuildFailed
|
||||||
, TagNotFound
|
, TagNotFound
|
||||||
, DigestError
|
, DigestError
|
||||||
|
, GPGError
|
||||||
, DownloadFailed
|
, DownloadFailed
|
||||||
, DirNotEmpty
|
, DirNotEmpty
|
||||||
, NoUpdate
|
, NoUpdate
|
||||||
@@ -440,19 +440,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 $> vi
|
liftE $ installGHCBin lVer Nothing False $> vi
|
||||||
Cabal -> do
|
Cabal -> do
|
||||||
let vi = getVersionInfo lVer Cabal dls
|
let vi = getVersionInfo lVer Cabal dls
|
||||||
liftE $ installCabalBin lVer Nothing $> vi
|
liftE $ installCabalBin lVer Nothing False $> vi
|
||||||
GHCup -> do
|
GHCup -> do
|
||||||
let vi = snd <$> getLatest dls GHCup
|
let vi = snd <$> getLatest dls GHCup
|
||||||
liftE $ upgradeGHCup Nothing False $> vi
|
liftE $ upgradeGHCup Nothing False $> vi
|
||||||
HLS -> do
|
HLS -> do
|
||||||
let vi = getVersionInfo lVer HLS dls
|
let vi = getVersionInfo lVer HLS dls
|
||||||
liftE $ installHLSBin lVer Nothing $> vi
|
liftE $ installHLSBin lVer Nothing False $> vi
|
||||||
Stack -> do
|
Stack -> do
|
||||||
let vi = getVersionInfo lVer Stack dls
|
let vi = getVersionInfo lVer Stack dls
|
||||||
liftE $ installStackBin lVer Nothing $> vi
|
liftE $ installStackBin lVer Nothing False $> vi
|
||||||
)
|
)
|
||||||
>>= \case
|
>>= \case
|
||||||
VRight vi -> do
|
VRight vi -> do
|
||||||
@@ -537,8 +537,9 @@ settings' :: IORef AppState
|
|||||||
settings' = unsafePerformIO $ do
|
settings' = unsafePerformIO $ do
|
||||||
dirs <- getAllDirs
|
dirs <- getAllDirs
|
||||||
let loggerConfig = LoggerConfig { lcPrintDebug = False
|
let loggerConfig = LoggerConfig { lcPrintDebug = False
|
||||||
, colorOutter = \_ -> pure ()
|
, consoleOutter = \_ -> pure ()
|
||||||
, rawOutter = \_ -> pure ()
|
, fileOutter = \_ -> pure ()
|
||||||
|
, fancyColors = True
|
||||||
}
|
}
|
||||||
newIORef $ AppState (Settings { cache = True
|
newIORef $ AppState (Settings { cache = True
|
||||||
, noVerify = False
|
, noVerify = False
|
||||||
@@ -547,6 +548,8 @@ settings' = unsafePerformIO $ do
|
|||||||
, verbose = False
|
, verbose = False
|
||||||
, urlSource = GHCupURL
|
, urlSource = GHCupURL
|
||||||
, noNetwork = False
|
, noNetwork = False
|
||||||
|
, gpgSetting = GPGNone
|
||||||
|
, noColor = False
|
||||||
, ..
|
, ..
|
||||||
})
|
})
|
||||||
dirs
|
dirs
|
||||||
@@ -562,13 +565,11 @@ brickMain :: AppState
|
|||||||
brickMain s = do
|
brickMain s = do
|
||||||
writeIORef settings' s
|
writeIORef settings' s
|
||||||
|
|
||||||
no_color <- isJust <$> lookupEnv "NO_COLOR"
|
|
||||||
|
|
||||||
eAppData <- getAppData (Just $ ghcupInfo s)
|
eAppData <- getAppData (Just $ ghcupInfo s)
|
||||||
case eAppData of
|
case eAppData of
|
||||||
Right ad ->
|
Right ad ->
|
||||||
defaultMain
|
defaultMain
|
||||||
(app (defaultAttributes no_color) (dimAttributes no_color))
|
(app (defaultAttributes (noColor $ settings s)) (dimAttributes (noColor $ settings s)))
|
||||||
(BrickState ad
|
(BrickState ad
|
||||||
defaultAppSettings
|
defaultAppSettings
|
||||||
(constructList ad defaultAppSettings Nothing)
|
(constructList ad defaultAppSettings Nothing)
|
||||||
@@ -591,7 +592,7 @@ getGHCupInfo = do
|
|||||||
|
|
||||||
r <-
|
r <-
|
||||||
flip runReaderT settings
|
flip runReaderT settings
|
||||||
. runE @'[JSONError , DownloadFailed , FileDoesNotExistError]
|
. runE @'[DigestError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError]
|
||||||
$ liftE
|
$ liftE
|
||||||
$ getDownloadsF
|
$ getDownloadsF
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ import Data.Char
|
|||||||
import Data.Either
|
import Data.Either
|
||||||
import Data.Functor
|
import Data.Functor
|
||||||
import Data.List ( intercalate, nub, sort, sortBy )
|
import Data.List ( intercalate, nub, sort, sortBy )
|
||||||
import Data.List.NonEmpty (NonEmpty ((:|)))
|
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.Text ( Text )
|
import Data.Text ( Text )
|
||||||
import Data.Versions hiding ( str )
|
import Data.Versions hiding ( str )
|
||||||
@@ -94,6 +93,7 @@ data Options = Options
|
|||||||
, optKeepDirs :: Maybe KeepDirs
|
, optKeepDirs :: Maybe KeepDirs
|
||||||
, optsDownloader :: Maybe Downloader
|
, optsDownloader :: Maybe Downloader
|
||||||
, optNoNetwork :: Maybe Bool
|
, optNoNetwork :: Maybe Bool
|
||||||
|
, optGpg :: Maybe GPGSetting
|
||||||
-- commands
|
-- commands
|
||||||
, optCommand :: Command
|
, optCommand :: Command
|
||||||
}
|
}
|
||||||
@@ -102,6 +102,7 @@ data Command
|
|||||||
= Install (Either InstallCommand InstallOptions)
|
= Install (Either InstallCommand InstallOptions)
|
||||||
| InstallCabalLegacy InstallOptions
|
| InstallCabalLegacy InstallOptions
|
||||||
| Set (Either SetCommand SetOptions)
|
| Set (Either SetCommand SetOptions)
|
||||||
|
| UnSet UnsetCommand
|
||||||
| List ListOptions
|
| List ListOptions
|
||||||
| Rm (Either RmCommand RmOptions)
|
| Rm (Either RmCommand RmOptions)
|
||||||
| DInfo
|
| DInfo
|
||||||
@@ -116,6 +117,7 @@ data Command
|
|||||||
| Interactive
|
| Interactive
|
||||||
#endif
|
#endif
|
||||||
| Prefetch PrefetchCommand
|
| Prefetch PrefetchCommand
|
||||||
|
| GC GCOptions
|
||||||
|
|
||||||
data ToolVersion = ToolVersion GHCTargetVersion -- target is ignored for cabal
|
data ToolVersion = ToolVersion GHCTargetVersion -- target is ignored for cabal
|
||||||
| ToolTag Tag
|
| ToolTag Tag
|
||||||
@@ -141,6 +143,16 @@ data InstallOptions = InstallOptions
|
|||||||
, instBindist :: Maybe URI
|
, instBindist :: Maybe URI
|
||||||
, instSet :: Bool
|
, instSet :: Bool
|
||||||
, isolateDir :: Maybe FilePath
|
, isolateDir :: Maybe FilePath
|
||||||
|
, forceInstall :: Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
data GCOptions = GCOptions
|
||||||
|
{ gcOldGHC :: Bool
|
||||||
|
, gcProfilingLibs :: Bool
|
||||||
|
, gcShareDir :: Bool
|
||||||
|
, gcHLSNoGHC :: Bool
|
||||||
|
, gcCache :: Bool
|
||||||
|
, gcTmp :: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
data SetCommand = SetGHC SetOptions
|
data SetCommand = SetGHC SetOptions
|
||||||
@@ -148,6 +160,11 @@ data SetCommand = SetGHC SetOptions
|
|||||||
| SetHLS SetOptions
|
| SetHLS SetOptions
|
||||||
| SetStack SetOptions
|
| SetStack SetOptions
|
||||||
|
|
||||||
|
data UnsetCommand = UnsetGHC UnsetOptions
|
||||||
|
| UnsetCabal UnsetOptions
|
||||||
|
| UnsetHLS UnsetOptions
|
||||||
|
| UnsetStack UnsetOptions
|
||||||
|
|
||||||
-- a superset of ToolVersion
|
-- a superset of ToolVersion
|
||||||
data SetToolVersion = SetToolVersion GHCTargetVersion
|
data SetToolVersion = SetToolVersion GHCTargetVersion
|
||||||
| SetToolTag Tag
|
| SetToolTag Tag
|
||||||
@@ -158,6 +175,10 @@ data SetOptions = SetOptions
|
|||||||
{ sToolVer :: SetToolVersion
|
{ sToolVer :: SetToolVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data UnsetOptions = UnsetOptions
|
||||||
|
{ sToolVer :: Maybe Text -- target platform triple
|
||||||
|
}
|
||||||
|
|
||||||
data ListOptions = ListOptions
|
data ListOptions = ListOptions
|
||||||
{ loTool :: Maybe Tool
|
{ loTool :: Maybe Tool
|
||||||
, lCriteria :: Maybe ListCriteria
|
, lCriteria :: Maybe ListCriteria
|
||||||
@@ -175,6 +196,7 @@ data RmOptions = RmOptions
|
|||||||
|
|
||||||
|
|
||||||
data CompileCommand = CompileGHC GHCCompileOptions
|
data CompileCommand = CompileGHC GHCCompileOptions
|
||||||
|
| CompileHLS HLSCompileOptions
|
||||||
|
|
||||||
data ConfigCommand = ShowConfig | SetConfig String String | InitConfig
|
data ConfigCommand = ShowConfig | SetConfig String String | InitConfig
|
||||||
|
|
||||||
@@ -193,6 +215,18 @@ data GHCCompileOptions = GHCCompileOptions
|
|||||||
, isolateDir :: Maybe FilePath
|
, isolateDir :: Maybe FilePath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data HLSCompileOptions = HLSCompileOptions
|
||||||
|
{ targetHLS :: Either Version GitBranch
|
||||||
|
, jobs :: Maybe Int
|
||||||
|
, setCompile :: Bool
|
||||||
|
, ovewrwiteVer :: Maybe Version
|
||||||
|
, isolateDir :: Maybe FilePath
|
||||||
|
, cabalProject :: Maybe FilePath
|
||||||
|
, cabalProjectLocal :: Maybe FilePath
|
||||||
|
, patchDir :: Maybe FilePath
|
||||||
|
, targetGHCs :: [ToolVersion]
|
||||||
|
}
|
||||||
|
|
||||||
data UpgradeOpts = UpgradeInplace
|
data UpgradeOpts = UpgradeInplace
|
||||||
| UpgradeAt FilePath
|
| UpgradeAt FilePath
|
||||||
| UpgradeGHCupDir
|
| UpgradeGHCupDir
|
||||||
@@ -309,6 +343,13 @@ opts =
|
|||||||
<> hidden
|
<> hidden
|
||||||
))
|
))
|
||||||
<*> invertableSwitch "offline" 'o' False (help "Don't do any network calls, trying cached assets and failing if missing.")
|
<*> invertableSwitch "offline" 'o' False (help "Don't do any network calls, trying cached assets and failing if missing.")
|
||||||
|
<*> optional (option
|
||||||
|
(eitherReader gpgParser)
|
||||||
|
( long "gpg"
|
||||||
|
<> metavar "<strict|lax|none>"
|
||||||
|
<> help
|
||||||
|
"GPG verification (default: none)"
|
||||||
|
))
|
||||||
<*> com
|
<*> com
|
||||||
where
|
where
|
||||||
parseUri s' =
|
parseUri s' =
|
||||||
@@ -348,6 +389,14 @@ com =
|
|||||||
<> footerDoc (Just $ text setFooter)
|
<> footerDoc (Just $ text setFooter)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
<> command
|
||||||
|
"unset"
|
||||||
|
(info
|
||||||
|
(UnSet <$> unsetParser <**> helper)
|
||||||
|
( progDesc "Unset currently active GHC/cabal version"
|
||||||
|
<> footerDoc (Just $ text unsetFooter)
|
||||||
|
)
|
||||||
|
)
|
||||||
<> command
|
<> command
|
||||||
"rm"
|
"rm"
|
||||||
(info
|
(info
|
||||||
@@ -399,6 +448,16 @@ com =
|
|||||||
(progDesc "Prefetch assets"
|
(progDesc "Prefetch assets"
|
||||||
<> footerDoc ( Just $ text prefetchFooter ))
|
<> footerDoc ( Just $ text prefetchFooter ))
|
||||||
)
|
)
|
||||||
|
<> command
|
||||||
|
"gc"
|
||||||
|
(info
|
||||||
|
( (GC
|
||||||
|
<$> gcP
|
||||||
|
) <**> helper
|
||||||
|
)
|
||||||
|
(progDesc "Garbage collection"
|
||||||
|
<> footerDoc ( Just $ text gcFooter ))
|
||||||
|
)
|
||||||
<> commandGroup "Main commands:"
|
<> commandGroup "Main commands:"
|
||||||
)
|
)
|
||||||
<|> subparser
|
<|> subparser
|
||||||
@@ -461,6 +520,10 @@ com =
|
|||||||
is given, sets GHC to 'recommended' version).
|
is given, sets GHC to 'recommended' version).
|
||||||
It is recommended to always specify a subcommand (ghc/cabal/hls/stack).|]
|
It is recommended to always specify a subcommand (ghc/cabal/hls/stack).|]
|
||||||
|
|
||||||
|
unsetFooter :: String
|
||||||
|
unsetFooter = [s|Discussion:
|
||||||
|
Unsets the currently active GHC or cabal version.|]
|
||||||
|
|
||||||
rmFooter :: String
|
rmFooter :: String
|
||||||
rmFooter = [s|Discussion:
|
rmFooter = [s|Discussion:
|
||||||
Remove the given GHC or cabal version. When no command is given,
|
Remove the given GHC or cabal version. When no command is given,
|
||||||
@@ -499,6 +562,10 @@ Examples:
|
|||||||
ghcup prefetch ghc 8.10.5
|
ghcup prefetch ghc 8.10.5
|
||||||
ghcup --offline install ghc 8.10.5|]
|
ghcup --offline install ghc 8.10.5|]
|
||||||
|
|
||||||
|
gcFooter :: String
|
||||||
|
gcFooter = [s|Discussion:
|
||||||
|
Performs garbage collection. If no switches are specified, does nothing.|]
|
||||||
|
|
||||||
configFooter :: String
|
configFooter :: String
|
||||||
configFooter = [s|Examples:
|
configFooter = [s|Examples:
|
||||||
|
|
||||||
@@ -602,7 +669,7 @@ Examples:
|
|||||||
|
|
||||||
installOpts :: Maybe Tool -> Parser InstallOptions
|
installOpts :: Maybe Tool -> Parser InstallOptions
|
||||||
installOpts tool =
|
installOpts tool =
|
||||||
(\p (u, v) b is -> InstallOptions v p u b is)
|
(\p (u, v) b is f -> InstallOptions v p u b is f)
|
||||||
<$> optional
|
<$> optional
|
||||||
(option
|
(option
|
||||||
(eitherReader platformParser)
|
(eitherReader platformParser)
|
||||||
@@ -640,6 +707,9 @@ installOpts tool =
|
|||||||
<> help "install in an isolated dir instead of the default one"
|
<> help "install in an isolated dir instead of the default one"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
<*> switch
|
||||||
|
(short 'f' <> long "force" <> help "Force install")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setParser :: Parser (Either SetCommand SetOptions)
|
setParser :: Parser (Either SetCommand SetOptions)
|
||||||
@@ -703,19 +773,81 @@ setParser =
|
|||||||
setHLSFooter = [s|Discussion:
|
setHLSFooter = [s|Discussion:
|
||||||
Sets the the current haskell-language-server version.|]
|
Sets the the current haskell-language-server version.|]
|
||||||
|
|
||||||
|
unsetParser :: Parser UnsetCommand
|
||||||
|
unsetParser =
|
||||||
|
(subparser
|
||||||
|
( command
|
||||||
|
"ghc"
|
||||||
|
( UnsetGHC
|
||||||
|
<$> info
|
||||||
|
(unsetOpts <**> helper)
|
||||||
|
( progDesc "Unset GHC version"
|
||||||
|
<> footerDoc (Just $ text unsetGHCFooter)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
<> command
|
||||||
|
"cabal"
|
||||||
|
( UnsetCabal
|
||||||
|
<$> info
|
||||||
|
(unsetOpts <**> helper)
|
||||||
|
( progDesc "Unset Cabal version"
|
||||||
|
<> footerDoc (Just $ text unsetCabalFooter)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
<> command
|
||||||
|
"hls"
|
||||||
|
( UnsetHLS
|
||||||
|
<$> info
|
||||||
|
(unsetOpts <**> helper)
|
||||||
|
( progDesc "Unset haskell-language-server version"
|
||||||
|
<> footerDoc (Just $ text unsetHLSFooter)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
<> command
|
||||||
|
"stack"
|
||||||
|
( UnsetStack
|
||||||
|
<$> info
|
||||||
|
(unsetOpts <**> helper)
|
||||||
|
( progDesc "Unset stack version"
|
||||||
|
<> footerDoc (Just $ text unsetStackFooter)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
where
|
||||||
|
unsetGHCFooter :: String
|
||||||
|
unsetGHCFooter = [s|Discussion:
|
||||||
|
Unsets the the current GHC version. That means there won't
|
||||||
|
be a ~/.ghcup/bin/ghc anymore.|]
|
||||||
|
|
||||||
|
unsetCabalFooter :: String
|
||||||
|
unsetCabalFooter = [s|Discussion:
|
||||||
|
Unsets the the current Cabal version.|]
|
||||||
|
|
||||||
|
unsetStackFooter :: String
|
||||||
|
unsetStackFooter = [s|Discussion:
|
||||||
|
Unsets the the current Stack version.|]
|
||||||
|
|
||||||
|
unsetHLSFooter :: String
|
||||||
|
unsetHLSFooter = [s|Discussion:
|
||||||
|
Unsets the the current haskell-language-server version.|]
|
||||||
|
|
||||||
|
|
||||||
setOpts :: Maybe Tool -> Parser SetOptions
|
setOpts :: Maybe Tool -> Parser SetOptions
|
||||||
setOpts tool = SetOptions <$>
|
setOpts tool = SetOptions <$>
|
||||||
(fromMaybe SetRecommended <$>
|
(fromMaybe SetRecommended <$>
|
||||||
optional (setVersionArgument (Just ListInstalled) tool))
|
optional (setVersionArgument (Just ListInstalled) tool))
|
||||||
|
|
||||||
|
unsetOpts :: Parser UnsetOptions
|
||||||
|
unsetOpts = UnsetOptions . fmap T.pack <$> optional (argument str (metavar "TRIPLE"))
|
||||||
|
|
||||||
listOpts :: Parser ListOptions
|
listOpts :: Parser ListOptions
|
||||||
listOpts =
|
listOpts =
|
||||||
ListOptions
|
ListOptions
|
||||||
<$> optional
|
<$> optional
|
||||||
(option
|
(option
|
||||||
(eitherReader toolParser)
|
(eitherReader toolParser)
|
||||||
(short 't' <> long "tool" <> metavar "<ghc|cabal>" <> help
|
(short 't' <> long "tool" <> metavar "<ghc|cabal|hls|stack>" <> help
|
||||||
"Tool to list versions for. Default is all"
|
"Tool to list versions for. Default is all"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -724,8 +856,8 @@ listOpts =
|
|||||||
(eitherReader criteriaParser)
|
(eitherReader criteriaParser)
|
||||||
( short 'c'
|
( short 'c'
|
||||||
<> long "show-criteria"
|
<> long "show-criteria"
|
||||||
<> metavar "<installed|set>"
|
<> metavar "<installed|set|available>"
|
||||||
<> help "Show only installed or set tool versions"
|
<> help "Show only installed/set/available tool versions"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
<*> switch
|
<*> switch
|
||||||
@@ -799,6 +931,15 @@ compileP = subparser
|
|||||||
<> footerDoc (Just $ text compileFooter)
|
<> footerDoc (Just $ text compileFooter)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
<> command
|
||||||
|
"hls"
|
||||||
|
( CompileHLS
|
||||||
|
<$> info
|
||||||
|
(hlsCompileOpts <**> helper)
|
||||||
|
( progDesc "Compile HLS from source"
|
||||||
|
<> footerDoc (Just $ text compileHLSFooter)
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
compileFooter = [s|Discussion:
|
compileFooter = [s|Discussion:
|
||||||
@@ -823,6 +964,14 @@ Examples:
|
|||||||
# build cross compiler
|
# build cross compiler
|
||||||
ghcup compile ghc -j 4 -v 8.4.2 -b 8.2.2 -x armv7-unknown-linux-gnueabihf --config $(pwd)/build.mk -- --enable-unregisterised|]
|
ghcup compile ghc -j 4 -v 8.4.2 -b 8.2.2 -x armv7-unknown-linux-gnueabihf --config $(pwd)/build.mk -- --enable-unregisterised|]
|
||||||
|
|
||||||
|
compileHLSFooter = [s|Discussion:
|
||||||
|
Compiles and installs the specified HLS version.
|
||||||
|
The last argument is a list of GHC versions to compile for.
|
||||||
|
These need to be available in PATH prior to compilation.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
ghcup compile hls -v 1.4.0 -j 12 8.10.5 8.10.7 9.0.1|]
|
||||||
|
|
||||||
configP :: Parser ConfigCommand
|
configP :: Parser ConfigCommand
|
||||||
configP = subparser
|
configP = subparser
|
||||||
( command "init" initP
|
( command "init" initP
|
||||||
@@ -997,6 +1146,28 @@ prefetchP = subparser
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
gcP :: Parser GCOptions
|
||||||
|
gcP =
|
||||||
|
GCOptions
|
||||||
|
<$>
|
||||||
|
switch
|
||||||
|
(short 'o' <> long "ghc-old" <> help "Remove GHC versions marked as 'old'")
|
||||||
|
<*>
|
||||||
|
switch
|
||||||
|
(short 'p' <> long "profiling-libs" <> help "Remove profiling libs of GHC versions")
|
||||||
|
<*>
|
||||||
|
switch
|
||||||
|
(short 's' <> long "share-dir" <> help "Remove GHC share directories (documentation)")
|
||||||
|
<*>
|
||||||
|
switch
|
||||||
|
(short 'h' <> long "hls-no-ghc" <> help "Remove HLS versions that don't have a corresponding installed GHC version")
|
||||||
|
<*>
|
||||||
|
switch
|
||||||
|
(short 'c' <> long "cache" <> help "GC the GHCup cache")
|
||||||
|
<*>
|
||||||
|
switch
|
||||||
|
(short 't' <> long "tmpdirs" <> help "Remove tmpdir leftovers")
|
||||||
|
|
||||||
|
|
||||||
ghcCompileOpts :: Parser GHCCompileOptions
|
ghcCompileOpts :: Parser GHCCompileOptions
|
||||||
ghcCompileOpts =
|
ghcCompileOpts =
|
||||||
@@ -1092,6 +1263,78 @@ ghcCompileOpts =
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
hlsCompileOpts :: Parser HLSCompileOptions
|
||||||
|
hlsCompileOpts =
|
||||||
|
HLSCompileOptions
|
||||||
|
<$> ((Left <$> option
|
||||||
|
(eitherReader
|
||||||
|
(first (const "Not a valid version") . version . T.pack)
|
||||||
|
)
|
||||||
|
(short 'v' <> long "version" <> metavar "VERSION" <> help
|
||||||
|
"The tool version to compile"
|
||||||
|
)
|
||||||
|
) <|>
|
||||||
|
(Right <$> (GitBranch <$> option
|
||||||
|
str
|
||||||
|
(short 'g' <> long "git-ref" <> metavar "GIT_REFERENCE" <> help
|
||||||
|
"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
|
||||||
|
(eitherReader (readEither @Int))
|
||||||
|
(short 'j' <> long "jobs" <> metavar "JOBS" <> help
|
||||||
|
"How many jobs to use for make"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
<*> flag
|
||||||
|
False
|
||||||
|
True
|
||||||
|
(long "set" <> help
|
||||||
|
"Set as active version after install"
|
||||||
|
)
|
||||||
|
<*> optional
|
||||||
|
(option
|
||||||
|
(eitherReader
|
||||||
|
(first (const "Not a valid version") . version . T.pack)
|
||||||
|
)
|
||||||
|
(short 'o' <> long "overwrite-version" <> metavar "OVERWRITE_VERSION" <> help
|
||||||
|
"Allows to overwrite the finally installed VERSION with a different one, e.g. when you build 8.10.4 with your own patches, you might want to set this to '8.10.4-p1'"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
<*> optional
|
||||||
|
(option
|
||||||
|
(eitherReader isolateParser)
|
||||||
|
( short 'i'
|
||||||
|
<> long "isolate"
|
||||||
|
<> metavar "DIR"
|
||||||
|
<> help "install in an isolated directory instead of the default one, no symlinks to this installation will be made"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
<*> optional
|
||||||
|
(option
|
||||||
|
str
|
||||||
|
(long "cabal-project" <> metavar "CABAL_PROJECT" <> help
|
||||||
|
"If relative, specifies the path to cabal.project inside the unpacked HLS tarball/checkout. If absolute, will copy the file over."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
<*> optional
|
||||||
|
(option
|
||||||
|
(eitherReader absolutePathParser)
|
||||||
|
(long "cabal-project-local" <> metavar "CABAL_PROJECT_LOCAL" <> help
|
||||||
|
"Absolute path to a cabal.project.local to be used for the build. Will be copied over."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
<*> optional
|
||||||
|
(option
|
||||||
|
(eitherReader absolutePathParser)
|
||||||
|
(short 'p' <> long "patchdir" <> metavar "PATCH_DIR" <> help
|
||||||
|
"Absolute path to patch directory (applies all .patch and .diff files in order using -p1)"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
<*> some (toolVersionArgument Nothing (Just GHC))
|
||||||
|
|
||||||
|
|
||||||
toolVersionParser :: Parser ToolVersion
|
toolVersionParser :: Parser ToolVersion
|
||||||
toolVersionParser = verP' <|> toolP
|
toolVersionParser = verP' <|> toolP
|
||||||
@@ -1107,9 +1350,13 @@ toolVersionParser = verP' <|> toolP
|
|||||||
toolVersionArgument :: Maybe ListCriteria -> Maybe Tool -> Parser ToolVersion
|
toolVersionArgument :: Maybe ListCriteria -> Maybe Tool -> Parser ToolVersion
|
||||||
toolVersionArgument criteria tool =
|
toolVersionArgument criteria tool =
|
||||||
argument (eitherReader toolVersionEither)
|
argument (eitherReader toolVersionEither)
|
||||||
(metavar "VERSION|TAG"
|
(metavar (mv tool)
|
||||||
<> completer (tagCompleter (fromMaybe GHC tool) [])
|
<> completer (tagCompleter (fromMaybe GHC tool) [])
|
||||||
<> foldMap (completer . versionCompleter criteria) tool)
|
<> foldMap (completer . versionCompleter criteria) tool)
|
||||||
|
where
|
||||||
|
mv (Just GHC) = "GHC_VERSION|TAG"
|
||||||
|
mv (Just HLS) = "HLS_VERSION|TAG"
|
||||||
|
mv _ = "VERSION|TAG"
|
||||||
|
|
||||||
|
|
||||||
setVersionArgument :: Maybe ListCriteria -> Maybe Tool -> Parser SetToolVersion
|
setVersionArgument :: Maybe ListCriteria -> Maybe Tool -> Parser SetToolVersion
|
||||||
@@ -1137,11 +1384,12 @@ tagCompleter tool add = listIOCompleter $ do
|
|||||||
dirs' <- liftIO getAllDirs
|
dirs' <- liftIO getAllDirs
|
||||||
let loggerConfig = LoggerConfig
|
let loggerConfig = LoggerConfig
|
||||||
{ lcPrintDebug = False
|
{ lcPrintDebug = False
|
||||||
, colorOutter = mempty
|
, consoleOutter = mempty
|
||||||
, rawOutter = mempty
|
, fileOutter = mempty
|
||||||
|
, fancyColors = False
|
||||||
}
|
}
|
||||||
let appState = LeanAppState
|
let appState = LeanAppState
|
||||||
(Settings True False Never Curl False GHCupURL True)
|
(Settings True False Never Curl False GHCupURL True GPGNone False)
|
||||||
dirs'
|
dirs'
|
||||||
defaultKeyBindings
|
defaultKeyBindings
|
||||||
loggerConfig
|
loggerConfig
|
||||||
@@ -1163,10 +1411,11 @@ versionCompleter criteria tool = listIOCompleter $ do
|
|||||||
dirs' <- liftIO getAllDirs
|
dirs' <- liftIO getAllDirs
|
||||||
let loggerConfig = LoggerConfig
|
let loggerConfig = LoggerConfig
|
||||||
{ lcPrintDebug = False
|
{ lcPrintDebug = False
|
||||||
, colorOutter = mempty
|
, consoleOutter = mempty
|
||||||
, rawOutter = mempty
|
, fileOutter = mempty
|
||||||
|
, fancyColors = False
|
||||||
}
|
}
|
||||||
let settings = Settings True False Never Curl False GHCupURL True
|
let settings = Settings True False Never Curl False GHCupURL True GPGNone False
|
||||||
let leanAppState = LeanAppState
|
let leanAppState = LeanAppState
|
||||||
settings
|
settings
|
||||||
dirs'
|
dirs'
|
||||||
@@ -1225,6 +1474,8 @@ toolVersionEither s' =
|
|||||||
toolParser :: String -> Either String Tool
|
toolParser :: String -> Either String Tool
|
||||||
toolParser s' | t == T.pack "ghc" = Right GHC
|
toolParser s' | t == T.pack "ghc" = Right GHC
|
||||||
| t == T.pack "cabal" = Right Cabal
|
| t == T.pack "cabal" = Right Cabal
|
||||||
|
| t == T.pack "hls" = Right HLS
|
||||||
|
| t == T.pack "stack" = Right Stack
|
||||||
| otherwise = Left ("Unknown tool: " <> s')
|
| otherwise = Left ("Unknown tool: " <> s')
|
||||||
where t = T.toLower (T.pack s')
|
where t = T.toLower (T.pack s')
|
||||||
|
|
||||||
@@ -1232,6 +1483,7 @@ toolParser s' | t == T.pack "ghc" = Right GHC
|
|||||||
criteriaParser :: String -> Either String ListCriteria
|
criteriaParser :: String -> Either String ListCriteria
|
||||||
criteriaParser s' | t == T.pack "installed" = Right ListInstalled
|
criteriaParser s' | t == T.pack "installed" = Right ListInstalled
|
||||||
| t == T.pack "set" = Right ListSet
|
| t == T.pack "set" = Right ListSet
|
||||||
|
| t == T.pack "available" = Right ListAvailable
|
||||||
| otherwise = Left ("Unknown criteria: " <> s')
|
| otherwise = Left ("Unknown criteria: " <> s')
|
||||||
where t = T.toLower (T.pack s')
|
where t = T.toLower (T.pack s')
|
||||||
|
|
||||||
@@ -1253,6 +1505,13 @@ downloaderParser s' | t == T.pack "curl" = Right Curl
|
|||||||
| otherwise = Left ("Unknown downloader value: " <> s')
|
| otherwise = Left ("Unknown downloader value: " <> s')
|
||||||
where t = T.toLower (T.pack s')
|
where t = T.toLower (T.pack s')
|
||||||
|
|
||||||
|
gpgParser :: String -> Either String GPGSetting
|
||||||
|
gpgParser s' | t == T.pack "strict" = Right GPGStrict
|
||||||
|
| t == T.pack "lax" = Right GPGLax
|
||||||
|
| t == T.pack "none" = Right GPGNone
|
||||||
|
| otherwise = Left ("Unknown gpg setting value: " <> s')
|
||||||
|
where t = T.toLower (T.pack s')
|
||||||
|
|
||||||
|
|
||||||
platformParser :: String -> Either String PlatformRequest
|
platformParser :: String -> Either String PlatformRequest
|
||||||
platformParser s' = case MP.parse (platformP <* MP.eof) "" (T.pack s') of
|
platformParser s' = case MP.parse (platformP <* MP.eof) "" (T.pack s') of
|
||||||
@@ -1311,8 +1570,14 @@ isolateParser f = case isValid f of
|
|||||||
True -> Right $ normalise f
|
True -> Right $ normalise f
|
||||||
False -> Left "Please enter a valid filepath for isolate dir."
|
False -> Left "Please enter a valid filepath for isolate dir."
|
||||||
|
|
||||||
|
absolutePathParser :: FilePath -> Either String FilePath
|
||||||
|
absolutePathParser f = case isValid f && isAbsolute f of
|
||||||
|
True -> Right $ normalise f
|
||||||
|
False -> Left "Please enter a valid absolute filepath."
|
||||||
|
|
||||||
toSettings :: Options -> IO (Settings, KeyBindings)
|
toSettings :: Options -> IO (Settings, KeyBindings)
|
||||||
toSettings options = do
|
toSettings options = do
|
||||||
|
noColor <- isJust <$> lookupEnv "NO_COLOR"
|
||||||
userConf <- runE @'[ JSONError ] ghcupConfigFile >>= \case
|
userConf <- runE @'[ JSONError ] ghcupConfigFile >>= \case
|
||||||
VRight r -> pure r
|
VRight r -> pure r
|
||||||
VLeft (V (JSONDecodeError e)) -> do
|
VLeft (V (JSONDecodeError e)) -> do
|
||||||
@@ -1320,10 +1585,10 @@ toSettings options = do
|
|||||||
pure defaultUserSettings
|
pure defaultUserSettings
|
||||||
_ -> do
|
_ -> do
|
||||||
die "Unexpected error!"
|
die "Unexpected error!"
|
||||||
pure $ mergeConf options userConf
|
pure $ mergeConf options userConf noColor
|
||||||
where
|
where
|
||||||
mergeConf :: Options -> UserSettings -> (Settings, KeyBindings)
|
mergeConf :: Options -> UserSettings -> Bool -> (Settings, KeyBindings)
|
||||||
mergeConf Options{..} UserSettings{..} =
|
mergeConf Options{..} UserSettings{..} noColor =
|
||||||
let cache = fromMaybe (fromMaybe False uCache) optCache
|
let cache = fromMaybe (fromMaybe False uCache) optCache
|
||||||
noVerify = fromMaybe (fromMaybe False uNoVerify) optNoVerify
|
noVerify = fromMaybe (fromMaybe False uNoVerify) optNoVerify
|
||||||
verbose = fromMaybe (fromMaybe False uVerbose) optVerbose
|
verbose = fromMaybe (fromMaybe False uVerbose) optVerbose
|
||||||
@@ -1332,6 +1597,7 @@ toSettings options = do
|
|||||||
keyBindings = maybe defaultKeyBindings mergeKeys uKeyBindings
|
keyBindings = maybe defaultKeyBindings mergeKeys uKeyBindings
|
||||||
urlSource = maybe (fromMaybe GHCupURL uUrlSource) OwnSource optUrlSource
|
urlSource = maybe (fromMaybe GHCupURL uUrlSource) OwnSource optUrlSource
|
||||||
noNetwork = fromMaybe (fromMaybe False uNoNetwork) optNoNetwork
|
noNetwork = fromMaybe (fromMaybe False uNoNetwork) optNoNetwork
|
||||||
|
gpgSetting = fromMaybe (fromMaybe GPGNone uGPGSetting) optGpg
|
||||||
in (Settings {..}, keyBindings)
|
in (Settings {..}, keyBindings)
|
||||||
#if defined(INTERNAL_DOWNLOADER)
|
#if defined(INTERNAL_DOWNLOADER)
|
||||||
defaultDownloader = Internal
|
defaultDownloader = Internal
|
||||||
@@ -1367,7 +1633,8 @@ updateSettings config settings = do
|
|||||||
verbose' = fromMaybe verbose uVerbose
|
verbose' = fromMaybe verbose uVerbose
|
||||||
urlSource' = fromMaybe urlSource uUrlSource
|
urlSource' = fromMaybe urlSource uUrlSource
|
||||||
noNetwork' = fromMaybe noNetwork uNoNetwork
|
noNetwork' = fromMaybe noNetwork uNoNetwork
|
||||||
in Settings cache' noVerify' keepDirs' downloader' verbose' urlSource' noNetwork'
|
gpgSetting' = fromMaybe gpgSetting uGPGSetting
|
||||||
|
in Settings cache' noVerify' keepDirs' downloader' verbose' urlSource' noNetwork' gpgSetting' noColor
|
||||||
|
|
||||||
upgradeOptsP :: Parser UpgradeOpts
|
upgradeOptsP :: Parser UpgradeOpts
|
||||||
upgradeOptsP =
|
upgradeOptsP =
|
||||||
@@ -1392,7 +1659,7 @@ describe_result = $( LitE . StringL <$>
|
|||||||
runIO (do
|
runIO (do
|
||||||
CapturedProcess{..} <- do
|
CapturedProcess{..} <- do
|
||||||
dirs <- liftIO getAllDirs
|
dirs <- liftIO getAllDirs
|
||||||
let settings = AppState (Settings True False Never Curl False GHCupURL False)
|
let settings = AppState (Settings True False Never Curl False GHCupURL False GPGNone False)
|
||||||
dirs
|
dirs
|
||||||
defaultKeyBindings
|
defaultKeyBindings
|
||||||
flip runReaderT settings $ executeOut "git" ["describe"] Nothing
|
flip runReaderT settings $ executeOut "git" ["describe"] Nothing
|
||||||
@@ -1472,17 +1739,19 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
|
|
||||||
-- logger interpreter
|
-- logger interpreter
|
||||||
logfile <- flip runReaderT dirs initGHCupFileLogging
|
logfile <- flip runReaderT dirs initGHCupFileLogging
|
||||||
|
no_color <- isJust <$> lookupEnv "NO_COLOR"
|
||||||
let loggerConfig = LoggerConfig
|
let loggerConfig = LoggerConfig
|
||||||
{ lcPrintDebug = verbose settings
|
{ lcPrintDebug = verbose settings
|
||||||
, colorOutter = T.hPutStr stderr
|
, consoleOutter = T.hPutStr stderr
|
||||||
, rawOutter =
|
, fileOutter =
|
||||||
case optCommand of
|
case optCommand of
|
||||||
Nuke -> \_ -> pure ()
|
Nuke -> \_ -> pure ()
|
||||||
_ -> T.appendFile logfile
|
_ -> T.appendFile logfile
|
||||||
|
, fancyColors = not no_color
|
||||||
}
|
}
|
||||||
let leanAppstate = LeanAppState settings dirs keybindings loggerConfig
|
let leanAppstate = LeanAppState settings dirs keybindings loggerConfig
|
||||||
let runLogger = flip runReaderT leanAppstate
|
let runLogger = flip runReaderT leanAppstate
|
||||||
let siletRunLogger = flip runReaderT (leanAppstate { loggerConfig = loggerConfig { colorOutter = \_ -> pure () } } :: LeanAppState)
|
let siletRunLogger = flip runReaderT (leanAppstate { loggerConfig = loggerConfig { consoleOutter = \_ -> pure () } } :: LeanAppState)
|
||||||
|
|
||||||
|
|
||||||
-------------------------
|
-------------------------
|
||||||
@@ -1502,7 +1771,7 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
|
|
||||||
ghcupInfo <-
|
ghcupInfo <-
|
||||||
( flip runReaderT leanAppstate
|
( flip runReaderT leanAppstate
|
||||||
. runE @'[JSONError , DownloadFailed, FileDoesNotExistError]
|
. runE @'[DigestError, GPGError, JSONError , DownloadFailed, FileDoesNotExistError]
|
||||||
$ liftE
|
$ liftE
|
||||||
$ getDownloadsF
|
$ getDownloadsF
|
||||||
)
|
)
|
||||||
@@ -1575,6 +1844,7 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
, BuildFailed
|
, BuildFailed
|
||||||
, TagNotFound
|
, TagNotFound
|
||||||
, DigestError
|
, DigestError
|
||||||
|
, GPGError
|
||||||
, DownloadFailed
|
, DownloadFailed
|
||||||
, TarDirDoesNotExist
|
, TarDirDoesNotExist
|
||||||
, NextVerNotFound
|
, NextVerNotFound
|
||||||
@@ -1607,6 +1877,11 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
, NoToolVersionSet
|
, NoToolVersionSet
|
||||||
]
|
]
|
||||||
|
|
||||||
|
runUnsetGHC =
|
||||||
|
runAppState
|
||||||
|
. runE
|
||||||
|
@'[ NotInstalled ]
|
||||||
|
|
||||||
let
|
let
|
||||||
runLeanSetCabal =
|
runLeanSetCabal =
|
||||||
runLeanAppState
|
runLeanAppState
|
||||||
@@ -1665,6 +1940,7 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
@'[ AlreadyInstalled
|
@'[ AlreadyInstalled
|
||||||
, BuildFailed
|
, BuildFailed
|
||||||
, DigestError
|
, DigestError
|
||||||
|
, GPGError
|
||||||
, DownloadFailed
|
, DownloadFailed
|
||||||
, GHCupSetError
|
, GHCupSetError
|
||||||
, NoDownload
|
, NoDownload
|
||||||
@@ -1677,6 +1953,29 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
, ArchiveResult
|
, ArchiveResult
|
||||||
]
|
]
|
||||||
|
|
||||||
|
let runCompileHLS =
|
||||||
|
runAppState
|
||||||
|
. runResourceT
|
||||||
|
. runE
|
||||||
|
@'[ AlreadyInstalled
|
||||||
|
, BuildFailed
|
||||||
|
, DigestError
|
||||||
|
, GPGError
|
||||||
|
, DownloadFailed
|
||||||
|
, GHCupSetError
|
||||||
|
, NoDownload
|
||||||
|
, NotFoundInPATH
|
||||||
|
, PatchFailed
|
||||||
|
, UnknownArchive
|
||||||
|
, TarDirDoesNotExist
|
||||||
|
, TagNotFound
|
||||||
|
, NextVerNotFound
|
||||||
|
, NoToolVersionSet
|
||||||
|
, NotInstalled
|
||||||
|
, DirNotEmpty
|
||||||
|
, ArchiveResult
|
||||||
|
]
|
||||||
|
|
||||||
let
|
let
|
||||||
runLeanWhereIs =
|
runLeanWhereIs =
|
||||||
-- Don't use runLeanAppState here, which is disabled on windows.
|
-- Don't use runLeanAppState here, which is disabled on windows.
|
||||||
@@ -1703,6 +2002,7 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
. runResourceT
|
. runResourceT
|
||||||
. runE
|
. runE
|
||||||
@'[ DigestError
|
@'[ DigestError
|
||||||
|
, GPGError
|
||||||
, NoDownload
|
, NoDownload
|
||||||
, NoUpdate
|
, NoUpdate
|
||||||
, FileDoesNotExistError
|
, FileDoesNotExistError
|
||||||
@@ -1719,11 +2019,19 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
, NoToolVersionSet
|
, NoToolVersionSet
|
||||||
, NoDownload
|
, NoDownload
|
||||||
, DigestError
|
, DigestError
|
||||||
|
, GPGError
|
||||||
, DownloadFailed
|
, DownloadFailed
|
||||||
, JSONError
|
, JSONError
|
||||||
, FileDoesNotExistError
|
, FileDoesNotExistError
|
||||||
]
|
]
|
||||||
|
|
||||||
|
let runGC =
|
||||||
|
runAppState
|
||||||
|
. runResourceT
|
||||||
|
. runE
|
||||||
|
@'[ NotInstalled
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
-- Command functions --
|
-- Command functions --
|
||||||
@@ -1733,7 +2041,10 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
(case instBindist of
|
(case instBindist of
|
||||||
Nothing -> runInstTool instPlatform $ do
|
Nothing -> runInstTool instPlatform $ do
|
||||||
(v, vi) <- liftE $ fromVersion instVer GHC
|
(v, vi) <- liftE $ fromVersion instVer GHC
|
||||||
liftE $ installGHCBin (_tvVersion v) isolateDir
|
liftE $ installGHCBin
|
||||||
|
(_tvVersion v)
|
||||||
|
isolateDir
|
||||||
|
forceInstall
|
||||||
when instSet $ void $ liftE $ setGHC v SetGHCOnly
|
when instSet $ void $ liftE $ setGHC v SetGHCOnly
|
||||||
pure vi
|
pure vi
|
||||||
Just uri -> do
|
Just uri -> do
|
||||||
@@ -1744,6 +2055,7 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
(DownloadInfo uri (Just $ RegexDir "ghc-.*") "")
|
(DownloadInfo uri (Just $ RegexDir "ghc-.*") "")
|
||||||
(_tvVersion v)
|
(_tvVersion v)
|
||||||
isolateDir
|
isolateDir
|
||||||
|
forceInstall
|
||||||
when instSet $ void $ liftE $ setGHC v SetGHCOnly
|
when instSet $ void $ liftE $ setGHC v SetGHCOnly
|
||||||
pure vi
|
pure vi
|
||||||
)
|
)
|
||||||
@@ -1755,8 +2067,12 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
pure ExitSuccess
|
pure ExitSuccess
|
||||||
VLeft (V (AlreadyInstalled _ v)) -> do
|
VLeft (V (AlreadyInstalled _ v)) -> do
|
||||||
runLogger $ logWarn $
|
runLogger $ logWarn $
|
||||||
"GHC ver " <> prettyVer v <> " already installed; if you really want to reinstall it, you may want to run 'ghcup rm ghc " <> prettyVer v <> "' first"
|
"GHC ver " <> prettyVer v <> " already installed; if you really want to reinstall it, you may want to run 'ghcup install ghc --force " <> prettyVer v <> "'"
|
||||||
pure ExitSuccess
|
pure ExitSuccess
|
||||||
|
VLeft (V (DirNotEmpty fp)) -> do
|
||||||
|
runLogger $ logWarn $
|
||||||
|
"Install directory " <> T.pack fp <> " is not empty. Use 'ghcup install ghc --isolate " <> T.pack fp <> " --force ..." <> "' to install regardless."
|
||||||
|
pure $ ExitFailure 3
|
||||||
VLeft err@(V (BuildFailed tmpdir _)) -> do
|
VLeft err@(V (BuildFailed tmpdir _)) -> do
|
||||||
case keepDirs settings of
|
case keepDirs settings of
|
||||||
Never -> runLogger $ (logError $ T.pack $ prettyShow err)
|
Never -> runLogger $ (logError $ T.pack $ prettyShow err)
|
||||||
@@ -1775,7 +2091,10 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
(case instBindist of
|
(case instBindist of
|
||||||
Nothing -> runInstTool instPlatform $ do
|
Nothing -> runInstTool instPlatform $ do
|
||||||
(v, vi) <- liftE $ fromVersion instVer Cabal
|
(v, vi) <- liftE $ fromVersion instVer Cabal
|
||||||
liftE $ installCabalBin (_tvVersion v) isolateDir
|
liftE $ installCabalBin
|
||||||
|
(_tvVersion v)
|
||||||
|
isolateDir
|
||||||
|
forceInstall
|
||||||
pure vi
|
pure vi
|
||||||
Just uri -> do
|
Just uri -> do
|
||||||
s' <- appState
|
s' <- appState
|
||||||
@@ -1785,6 +2104,7 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
(DownloadInfo uri Nothing "")
|
(DownloadInfo uri Nothing "")
|
||||||
(_tvVersion v)
|
(_tvVersion v)
|
||||||
isolateDir
|
isolateDir
|
||||||
|
forceInstall
|
||||||
pure vi
|
pure vi
|
||||||
)
|
)
|
||||||
>>= \case
|
>>= \case
|
||||||
@@ -1795,8 +2115,12 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
pure ExitSuccess
|
pure ExitSuccess
|
||||||
VLeft (V (AlreadyInstalled _ v)) -> do
|
VLeft (V (AlreadyInstalled _ v)) -> do
|
||||||
runLogger $ logWarn $
|
runLogger $ logWarn $
|
||||||
"Cabal ver " <> prettyVer v <> " already installed; if you really want to reinstall it, you may want to run 'ghcup rm cabal " <> prettyVer v <> "' first"
|
"Cabal ver " <> prettyVer v <> " already installed; if you really want to reinstall it, you may want to run 'ghcup install cabal --force " <> prettyVer v <> "'"
|
||||||
pure ExitSuccess
|
pure ExitSuccess
|
||||||
|
VLeft (V (FileAlreadyExistsError fp)) -> do
|
||||||
|
runLogger $ logWarn $
|
||||||
|
"File " <> T.pack fp <> " already exists. Use 'ghcup install cabal --isolate " <> T.pack fp <> " --force ..." <> "' if you want to overwrite."
|
||||||
|
pure $ ExitFailure 3
|
||||||
VLeft e -> do
|
VLeft e -> do
|
||||||
runLogger $ do
|
runLogger $ do
|
||||||
logError $ T.pack $ prettyShow e
|
logError $ T.pack $ prettyShow e
|
||||||
@@ -1807,7 +2131,10 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
(case instBindist of
|
(case instBindist of
|
||||||
Nothing -> runInstTool instPlatform $ do
|
Nothing -> runInstTool instPlatform $ do
|
||||||
(v, vi) <- liftE $ fromVersion instVer HLS
|
(v, vi) <- liftE $ fromVersion instVer HLS
|
||||||
liftE $ installHLSBin (_tvVersion v) isolateDir
|
liftE $ installHLSBin
|
||||||
|
(_tvVersion v)
|
||||||
|
isolateDir
|
||||||
|
forceInstall
|
||||||
pure vi
|
pure vi
|
||||||
Just uri -> do
|
Just uri -> do
|
||||||
s' <- appState
|
s' <- appState
|
||||||
@@ -1817,6 +2144,7 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
(DownloadInfo uri Nothing "")
|
(DownloadInfo uri Nothing "")
|
||||||
(_tvVersion v)
|
(_tvVersion v)
|
||||||
isolateDir
|
isolateDir
|
||||||
|
forceInstall
|
||||||
pure vi
|
pure vi
|
||||||
)
|
)
|
||||||
>>= \case
|
>>= \case
|
||||||
@@ -1829,10 +2157,14 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
runLogger $ logWarn $
|
runLogger $ logWarn $
|
||||||
"HLS ver "
|
"HLS ver "
|
||||||
<> prettyVer v
|
<> prettyVer v
|
||||||
<> " already installed; if you really want to reinstall it, you may want to run 'ghcup rm hls "
|
<> " already installed; if you really want to reinstall it, you may want to run 'ghcup install hls --force "
|
||||||
<> prettyVer v
|
<> prettyVer v
|
||||||
<> "' first"
|
<> "'"
|
||||||
pure ExitSuccess
|
pure ExitSuccess
|
||||||
|
VLeft (V (FileAlreadyExistsError fp)) -> do
|
||||||
|
runLogger $ logWarn $
|
||||||
|
"File " <> T.pack fp <> " already exists. Use 'ghcup install hls --isolate " <> T.pack fp <> " --force ..." <> "' if you want to overwrite."
|
||||||
|
pure $ ExitFailure 3
|
||||||
VLeft e -> do
|
VLeft e -> do
|
||||||
runLogger $ do
|
runLogger $ do
|
||||||
logError $ T.pack $ prettyShow e
|
logError $ T.pack $ prettyShow e
|
||||||
@@ -1843,7 +2175,10 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
(case instBindist of
|
(case instBindist of
|
||||||
Nothing -> runInstTool instPlatform $ do
|
Nothing -> runInstTool instPlatform $ do
|
||||||
(v, vi) <- liftE $ fromVersion instVer Stack
|
(v, vi) <- liftE $ fromVersion instVer Stack
|
||||||
liftE $ installStackBin (_tvVersion v) isolateDir
|
liftE $ installStackBin
|
||||||
|
(_tvVersion v)
|
||||||
|
isolateDir
|
||||||
|
forceInstall
|
||||||
pure vi
|
pure vi
|
||||||
Just uri -> do
|
Just uri -> do
|
||||||
s' <- appState
|
s' <- appState
|
||||||
@@ -1853,6 +2188,7 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
(DownloadInfo uri Nothing "")
|
(DownloadInfo uri Nothing "")
|
||||||
(_tvVersion v)
|
(_tvVersion v)
|
||||||
isolateDir
|
isolateDir
|
||||||
|
forceInstall
|
||||||
pure vi
|
pure vi
|
||||||
)
|
)
|
||||||
>>= \case
|
>>= \case
|
||||||
@@ -1863,8 +2199,12 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
pure ExitSuccess
|
pure ExitSuccess
|
||||||
VLeft (V (AlreadyInstalled _ v)) -> do
|
VLeft (V (AlreadyInstalled _ v)) -> do
|
||||||
runLogger $ logWarn $
|
runLogger $ logWarn $
|
||||||
"Stack ver " <> prettyVer v <> " already installed; if you really want to reinstall it, you may want to run 'ghcup rm stack " <> prettyVer v <> "' first"
|
"Stack ver " <> prettyVer v <> " already installed; if you really want to reinstall it, you may want to run 'ghcup install stack --force " <> prettyVer v <> "'"
|
||||||
pure ExitSuccess
|
pure ExitSuccess
|
||||||
|
VLeft (V (FileAlreadyExistsError fp)) -> do
|
||||||
|
runLogger $ logWarn $
|
||||||
|
"File " <> T.pack fp <> " already exists. Use 'ghcup install stack --isolate " <> T.pack fp <> " --force ..." <> "' if you want to overwrite."
|
||||||
|
pure $ ExitFailure 3
|
||||||
VLeft e -> do
|
VLeft e -> do
|
||||||
runLogger $ do
|
runLogger $ do
|
||||||
logError $ T.pack $ prettyShow e
|
logError $ T.pack $ prettyShow e
|
||||||
@@ -2032,10 +2372,31 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
Set (Left (SetHLS sopts)) -> setHLS' sopts
|
Set (Left (SetHLS sopts)) -> setHLS' sopts
|
||||||
Set (Left (SetStack sopts)) -> setStack' sopts
|
Set (Left (SetStack sopts)) -> setStack' sopts
|
||||||
|
|
||||||
|
UnSet (UnsetGHC (UnsetOptions triple)) -> runUnsetGHC (unsetGHC triple)
|
||||||
|
>>= \case
|
||||||
|
VRight _ -> do
|
||||||
|
runLogger $ logInfo "GHC successfully unset"
|
||||||
|
pure ExitSuccess
|
||||||
|
VLeft e -> do
|
||||||
|
runLogger $ logError $ T.pack $ prettyShow e
|
||||||
|
pure $ ExitFailure 14
|
||||||
|
UnSet (UnsetCabal (UnsetOptions _)) -> do
|
||||||
|
runAppState unsetCabal
|
||||||
|
runLogger $ logInfo "Cabal successfully unset"
|
||||||
|
pure ExitSuccess
|
||||||
|
UnSet (UnsetHLS (UnsetOptions _)) -> do
|
||||||
|
runAppState unsetHLS
|
||||||
|
runLogger $ logInfo "HLS successfully unset"
|
||||||
|
pure ExitSuccess
|
||||||
|
UnSet (UnsetStack (UnsetOptions _)) -> do
|
||||||
|
runAppState unsetStack
|
||||||
|
runLogger $ logInfo "Stack successfully unset"
|
||||||
|
pure ExitSuccess
|
||||||
|
|
||||||
List ListOptions {..} ->
|
List ListOptions {..} ->
|
||||||
runListGHC (do
|
runListGHC (do
|
||||||
l <- listVersions loTool lCriteria
|
l <- listVersions loTool lCriteria
|
||||||
liftIO $ printListResult lRawFormat l
|
liftIO $ printListResult no_color lRawFormat l
|
||||||
pure ExitSuccess
|
pure ExitSuccess
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2057,6 +2418,53 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
runLogger $ logError $ T.pack $ prettyShow e
|
runLogger $ logError $ T.pack $ prettyShow e
|
||||||
pure $ ExitFailure 8
|
pure $ ExitFailure 8
|
||||||
|
|
||||||
|
Compile (CompileHLS HLSCompileOptions { .. }) -> do
|
||||||
|
runCompileHLS (do
|
||||||
|
case targetHLS of
|
||||||
|
Left targetVer -> do
|
||||||
|
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||||
|
let vi = getVersionInfo targetVer HLS dls
|
||||||
|
forM_ (_viPreCompile =<< vi) $ \msg -> do
|
||||||
|
lift $ logInfo msg
|
||||||
|
lift $ logInfo
|
||||||
|
"...waiting for 5 seconds, you can still abort..."
|
||||||
|
liftIO $ threadDelay 5000000 -- for compilation, give the user a sec to intervene
|
||||||
|
Right _ -> pure ()
|
||||||
|
ghcs <- liftE $ forM targetGHCs (\ghc -> fmap (_tvVersion . fst) . fromVersion (Just ghc) $ GHC)
|
||||||
|
targetVer <- liftE $ compileHLS
|
||||||
|
targetHLS
|
||||||
|
ghcs
|
||||||
|
jobs
|
||||||
|
ovewrwiteVer
|
||||||
|
isolateDir
|
||||||
|
cabalProject
|
||||||
|
cabalProjectLocal
|
||||||
|
patchDir
|
||||||
|
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||||
|
let vi = getVersionInfo targetVer HLS dls
|
||||||
|
when setCompile $ void $ liftE $
|
||||||
|
setHLS targetVer
|
||||||
|
pure (vi, targetVer)
|
||||||
|
)
|
||||||
|
>>= \case
|
||||||
|
VRight (vi, tv) -> do
|
||||||
|
runLogger $ logInfo
|
||||||
|
"HLS successfully compiled and installed"
|
||||||
|
forM_ (_viPostInstall =<< vi) $ \msg ->
|
||||||
|
runLogger $ logInfo msg
|
||||||
|
putStr (T.unpack $ prettyVer tv)
|
||||||
|
pure ExitSuccess
|
||||||
|
VLeft err@(V (BuildFailed tmpdir _)) -> do
|
||||||
|
case keepDirs settings of
|
||||||
|
Never -> runLogger $ logError $ T.pack $ prettyShow err
|
||||||
|
_ -> runLogger $ (logError $ T.pack (prettyShow err) <> "\n" <>
|
||||||
|
"Check the logs at " <> T.pack logsDir <> " and the build directory "
|
||||||
|
<> T.pack tmpdir <> " for more clues." <> "\n" <>
|
||||||
|
"Make sure to clean up " <> T.pack tmpdir <> " afterwards.")
|
||||||
|
pure $ ExitFailure 9
|
||||||
|
VLeft e -> do
|
||||||
|
runLogger $ logError $ T.pack $ prettyShow e
|
||||||
|
pure $ ExitFailure 9
|
||||||
Compile (CompileGHC GHCCompileOptions { hadrian = True, crossTarget = Just _ }) -> do
|
Compile (CompileGHC GHCCompileOptions { hadrian = True, crossTarget = Just _ }) -> do
|
||||||
runLogger $ logError "Hadrian cross compile support is not yet implemented!"
|
runLogger $ logError "Hadrian cross compile support is not yet implemented!"
|
||||||
pure $ ExitFailure 9
|
pure $ ExitFailure 9
|
||||||
@@ -2099,8 +2507,12 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
pure ExitSuccess
|
pure ExitSuccess
|
||||||
VLeft (V (AlreadyInstalled _ v)) -> do
|
VLeft (V (AlreadyInstalled _ v)) -> do
|
||||||
runLogger $ logWarn $
|
runLogger $ logWarn $
|
||||||
"GHC ver " <> prettyVer v <> " already installed; if you really want to reinstall it, you may want to run 'ghcup rm ghc " <> prettyVer v <> "' first"
|
"GHC ver " <> prettyVer v <> " already installed; if you really want to reinstall it, you may want to run 'ghcup install ghc --force " <> prettyVer v <> "'"
|
||||||
pure ExitSuccess
|
pure ExitSuccess
|
||||||
|
VLeft (V (DirNotEmpty fp)) -> do
|
||||||
|
runLogger $ logWarn $
|
||||||
|
"Install directory " <> T.pack fp <> " is not empty. Use 'ghcup install ghc --isolate " <> T.pack fp <> " --force ..." <> "' to install regardless."
|
||||||
|
pure $ ExitFailure 3
|
||||||
VLeft err@(V (BuildFailed tmpdir _)) -> do
|
VLeft err@(V (BuildFailed tmpdir _)) -> do
|
||||||
case keepDirs settings of
|
case keepDirs settings of
|
||||||
Never -> runLogger $ logError $ T.pack $ prettyShow err
|
Never -> runLogger $ logError $ T.pack $ prettyShow err
|
||||||
@@ -2339,6 +2751,20 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
|
|||||||
VLeft e -> do
|
VLeft e -> do
|
||||||
runLogger $ logError $ T.pack $ prettyShow e
|
runLogger $ logError $ T.pack $ prettyShow e
|
||||||
pure $ ExitFailure 15
|
pure $ ExitFailure 15
|
||||||
|
GC GCOptions{..} ->
|
||||||
|
runGC (do
|
||||||
|
when gcOldGHC rmOldGHC
|
||||||
|
lift $ when gcProfilingLibs rmProfilingLibs
|
||||||
|
lift $ when gcShareDir rmShareDir
|
||||||
|
lift $ when gcHLSNoGHC rmHLSNoGHC
|
||||||
|
lift $ when gcCache rmCache
|
||||||
|
lift $ when gcTmp rmTmp
|
||||||
|
) >>= \case
|
||||||
|
VRight _ -> do
|
||||||
|
pure ExitSuccess
|
||||||
|
VLeft e -> do
|
||||||
|
runLogger $ logError $ T.pack $ prettyShow e
|
||||||
|
pure $ ExitFailure 27
|
||||||
|
|
||||||
|
|
||||||
case res of
|
case res of
|
||||||
@@ -2389,13 +2815,15 @@ fromVersion' SetRecommended tool = do
|
|||||||
fromVersion' (SetToolVersion v) tool = do
|
fromVersion' (SetToolVersion v) tool = do
|
||||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||||
let vi = getVersionInfo (_tvVersion v) tool dls
|
let vi = getVersionInfo (_tvVersion v) tool dls
|
||||||
case pvp $ prettyVer (_tvVersion v) of
|
case pvp $ prettyVer (_tvVersion v) of -- need to be strict here
|
||||||
Left _ -> pure (v, vi)
|
Left _ -> pure (v, vi)
|
||||||
Right (PVP (major' :|[minor'])) ->
|
Right pvpIn ->
|
||||||
case getLatestGHCFor (fromIntegral major') (fromIntegral minor') dls of
|
lift (getLatestToolFor tool pvpIn dls) >>= \case
|
||||||
Just (v', vi') -> pure (GHCTargetVersion (_tvTarget v) v', Just vi')
|
Just (pvp_, vi') -> do
|
||||||
|
v' <- lift $ pvpToVersion pvp_
|
||||||
|
when (v' /= (_tvVersion v)) $ lift $ logWarn ("Assuming you meant version " <> prettyVer v')
|
||||||
|
pure (GHCTargetVersion (_tvTarget v) v', Just vi')
|
||||||
Nothing -> pure (v, vi)
|
Nothing -> pure (v, vi)
|
||||||
Right _ -> pure (v, vi)
|
|
||||||
fromVersion' (SetToolTag Latest) tool = do
|
fromVersion' (SetToolTag Latest) tool = do
|
||||||
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
GHCupInfo { _ghcupDownloads = dls } <- lift getGHCupInfo
|
||||||
(\(x, y) -> (mkTVer x, Just y)) <$> getLatest dls tool ?? TagNotFound Latest tool
|
(\(x, y) -> (mkTVer x, Just y)) <$> getLatest dls tool ?? TagNotFound Latest tool
|
||||||
@@ -2455,9 +2883,8 @@ fromVersion' (SetToolTag t') tool =
|
|||||||
throwE $ TagNotFound t' tool
|
throwE $ TagNotFound t' tool
|
||||||
|
|
||||||
|
|
||||||
printListResult :: Bool -> [ListResult] -> IO ()
|
printListResult :: Bool -> Bool -> [ListResult] -> IO ()
|
||||||
printListResult raw lr = do
|
printListResult no_color raw lr = do
|
||||||
no_color <- isJust <$> lookupEnv "NO_COLOR"
|
|
||||||
|
|
||||||
let
|
let
|
||||||
color | raw || no_color = flip const
|
color | raw || no_color = flip const
|
||||||
|
|||||||
@@ -8,11 +8,6 @@ package ghcup
|
|||||||
tests: True
|
tests: True
|
||||||
flags: +tui
|
flags: +tui
|
||||||
|
|
||||||
source-repository-package
|
|
||||||
type: git
|
|
||||||
location: https://github.com/bgamari/terminal-size
|
|
||||||
tag: 34ea816bd63f75f800eedac12c6908c6f3736036
|
|
||||||
|
|
||||||
source-repository-package
|
source-repository-package
|
||||||
type: git
|
type: git
|
||||||
location: https://github.com/hasufell/libarchive
|
location: https://github.com/hasufell/libarchive
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ verbose: False
|
|||||||
keep-dirs: Errors # Always | Never | Errors
|
keep-dirs: Errors # Always | Never | Errors
|
||||||
# Which downloader to use
|
# Which downloader to use
|
||||||
downloader: Curl # Curl | Wget | Internal
|
downloader: Curl # Curl | Wget | Internal
|
||||||
|
# whether to run in offline mode
|
||||||
|
no-network: False
|
||||||
|
# whether/how to do gpg verification
|
||||||
|
gpg-setting: GPGNone # GPGStrict | GPGLax | GPGNone
|
||||||
|
|
||||||
# TUI key bindings,
|
# TUI key bindings,
|
||||||
# see https://hackage.haskell.org/package/vty-5.31/docs/Graphics-Vty-Input-Events.html#t:Key
|
# see https://hackage.haskell.org/package/vty-5.31/docs/Graphics-Vty-Input-Events.html#t:Key
|
||||||
|
|||||||
@@ -72,7 +72,6 @@ toolRequirements:
|
|||||||
'( >= 7 && < 8 )':
|
'( >= 7 && < 8 )':
|
||||||
distroPKGs:
|
distroPKGs:
|
||||||
- gcc
|
- gcc
|
||||||
- gcc-c++
|
|
||||||
- gmp
|
- gmp
|
||||||
- gmp-devel
|
- gmp-devel
|
||||||
- make
|
- make
|
||||||
@@ -83,7 +82,6 @@ toolRequirements:
|
|||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
distroPKGs:
|
distroPKGs:
|
||||||
- gcc
|
- gcc
|
||||||
- gcc-c++
|
|
||||||
- gmp
|
- gmp
|
||||||
- gmp-devel
|
- gmp-devel
|
||||||
- make
|
- make
|
||||||
@@ -96,7 +94,6 @@ toolRequirements:
|
|||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
distroPKGs:
|
distroPKGs:
|
||||||
- gcc
|
- gcc
|
||||||
- gcc-c++
|
|
||||||
- gmp
|
- gmp
|
||||||
- gmp-devel
|
- gmp-devel
|
||||||
- make
|
- make
|
||||||
@@ -111,14 +108,15 @@ toolRequirements:
|
|||||||
- binutils-gold
|
- binutils-gold
|
||||||
- curl
|
- curl
|
||||||
- gcc
|
- gcc
|
||||||
- g++
|
|
||||||
- gmp-dev
|
- gmp-dev
|
||||||
- ncurses-dev
|
- libc-dev
|
||||||
- libffi-dev
|
- libffi-dev
|
||||||
- make
|
- make
|
||||||
- xz
|
- musl-dev
|
||||||
- tar
|
- ncurses-dev
|
||||||
- perl
|
- perl
|
||||||
|
- tar
|
||||||
|
- xz
|
||||||
notes: ''
|
notes: ''
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
@@ -1598,6 +1596,11 @@ ghcupDownloads:
|
|||||||
dlHash: f10941f16e4fbd98580ab5241b9271bb0851304560c4d5ca127e3b0e20e3076f
|
dlHash: f10941f16e4fbd98580ab5241b9271bb0851304560c4d5ca127e3b0e20e3076f
|
||||||
viPostRemove: *ghc-post-remove
|
viPostRemove: *ghc-post-remove
|
||||||
viPreCompile: *ghc-pre-compile
|
viPreCompile: *ghc-pre-compile
|
||||||
|
viPostInstall: &ghc-8105-post-install |
|
||||||
|
GHC 8.10.5 and 8.10.6 have several issues on Darwin, e.g.
|
||||||
|
https://gitlab.haskell.org/ghc/ghc/-/issues/19950
|
||||||
|
Consider upgrading to 8.10.7 via
|
||||||
|
ghcup install ghc --set 8.10.7
|
||||||
viArch:
|
viArch:
|
||||||
A_64:
|
A_64:
|
||||||
Linux_Debian:
|
Linux_Debian:
|
||||||
@@ -1698,6 +1701,7 @@ ghcupDownloads:
|
|||||||
dlHash: 43afba72a533408b42c1492bd047b5e37e5f7204e41a5cedd3182cc841610ce9
|
dlHash: 43afba72a533408b42c1492bd047b5e37e5f7204e41a5cedd3182cc841610ce9
|
||||||
viPostRemove: *ghc-post-remove
|
viPostRemove: *ghc-post-remove
|
||||||
viPreCompile: *ghc-pre-compile
|
viPreCompile: *ghc-pre-compile
|
||||||
|
viPostInstall: *ghc-8105-post-install
|
||||||
viArch:
|
viArch:
|
||||||
A_64:
|
A_64:
|
||||||
Linux_Debian:
|
Linux_Debian:
|
||||||
@@ -2265,7 +2269,7 @@ ghcupDownloads:
|
|||||||
dlUri: https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal/3.6.0.0/cabal-install-3.6.0.0-armv7-linux.tar.xz
|
dlUri: https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal/3.6.0.0/cabal-install-3.6.0.0-armv7-linux.tar.xz
|
||||||
dlHash: 11b5ca042a8bf45971224f2127a3e9d6b803f09210042ca80a254bea06f01a2e
|
dlHash: 11b5ca042a8bf45971224f2127a3e9d6b803f09210042ca80a254bea06f01a2e
|
||||||
GHCup:
|
GHCup:
|
||||||
0.1.16.2:
|
0.1.17:
|
||||||
viTags:
|
viTags:
|
||||||
- Recommended
|
- Recommended
|
||||||
- Latest
|
- Latest
|
||||||
@@ -2275,46 +2279,47 @@ ghcupDownloads:
|
|||||||
A_64:
|
A_64:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning: &ghcup-64
|
unknown_versioning: &ghcup-64
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-linux-ghcup-0.1.16.2
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.17/x86_64-linux-ghcup-0.1.17
|
||||||
dlHash: d5e43b95ce1d42263376e414f7eb7c5dd440271c7c6cd9bad446fdeff3823893
|
dlHash: 1eaa33af4180f97edf02822d6d711ce618d9828fe9ebbf042d198fe6c1c9d153
|
||||||
Darwin:
|
Darwin:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-apple-darwin-ghcup-0.1.16.2
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.17/x86_64-apple-darwin-ghcup-0.1.17
|
||||||
dlHash: a334620ccce7705211b2142882dde544003e6030af4b91a44c890542a90f879f
|
dlHash: a3d4ed12f8631c0537d8d9531cc5518bc6f90edcee3326e5d4e0efb72c8dfc6f
|
||||||
FreeBSD:
|
FreeBSD:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-portbld-freebsd-ghcup-0.1.16.2
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.17/x86_64-portbld-freebsd-ghcup-0.1.17
|
||||||
dlHash: 92359592a5694375e53b22628920086bf4bbf0faff5be018a0ed3e745a6426a9
|
dlHash: 83012de837773f3aa26182c607c2da85ee6ff3b0092becb78907700f407a27fb
|
||||||
Windows:
|
Windows:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/x86_64-mingw64-ghcup-0.1.16.2.exe
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.17/x86_64-mingw64-ghcup-0.1.17.exe
|
||||||
dlHash: ec78872a84213968c490675127b9aad2285980b747c68207801ae824b98c7948
|
dlHash: 40bda6050c800fa69af51d2e668426ca73b4179214bfeef329b795484991d258
|
||||||
Linux_Alpine:
|
Linux_Alpine:
|
||||||
unknown_versioning: *ghcup-64
|
unknown_versioning: *ghcup-64
|
||||||
A_32:
|
A_32:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning: &ghcup-32
|
unknown_versioning: &ghcup-32
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/i386-linux-ghcup-0.1.16.2
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.17/i386-linux-ghcup-0.1.17
|
||||||
dlHash: 01968ca6decac7b6e8ba6e2c817870d3fa47289a6507e0c1ab563f7b6eec0e38
|
dlHash: d0f887b13a2c7a11477dc54cb90b446ef0ebe1d2a6bfbf60ccd4b37fc5de70cc
|
||||||
Linux_Alpine:
|
Linux_Alpine:
|
||||||
unknown_versioning: *ghcup-32
|
unknown_versioning: *ghcup-32
|
||||||
A_ARM64:
|
A_ARM64:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/aarch64-linux-ghcup-0.1.16.2
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.17/aarch64-linux-ghcup-0.1.17
|
||||||
dlHash: 0bdbfc724e0ddabb266156eea83c2c4e19c6ed79dd06db0c29b7d69df8d9fa8c
|
dlHash: be67cf8800ae305c5ba210b645f4fce8751763f3eac3db399f6efca145b7ab38
|
||||||
Darwin:
|
Darwin:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/aarch64-apple-darwin-ghcup-0.1.16.2
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.17/aarch64-apple-darwin-ghcup-0.1.17
|
||||||
dlHash: 8854e991a2ba1350abda59dab96ce50ae7729d1ce99399d67929ef31e90f1da5
|
dlHash: b1be8c55838bd0d972e42b02b71bdf47fbbf67be1456e0de2d7d346620538539
|
||||||
A_ARM:
|
A_ARM:
|
||||||
Linux_UnknownLinux:
|
Linux_UnknownLinux:
|
||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/0.1.16.2/armv7-linux-ghcup-0.1.16.2
|
dlUri: https://downloads.haskell.org/~ghcup/0.1.17/armv7-linux-ghcup-0.1.17
|
||||||
dlHash: 983ebb5b584bfa600704216a63f94b40d36a02573834e90ef1042c8472d9ad57
|
dlHash: fe54ded2fafff4f8d82e511229f257f4c3b87b14c796f9b5b0ea35c359c26cb0
|
||||||
HLS:
|
HLS:
|
||||||
1.1.0:
|
1.1.0:
|
||||||
viTags: []
|
viTags:
|
||||||
|
- old
|
||||||
viChangeLog: https://github.com/haskell/haskell-language-server/blob/master/ChangeLog.md#110
|
viChangeLog: https://github.com/haskell/haskell-language-server/blob/master/ChangeLog.md#110
|
||||||
viPostInstall: &hls-post-install |
|
viPostInstall: &hls-post-install |
|
||||||
This is just the server part of your LSP configuration. Consult the README on how to
|
This is just the server part of your LSP configuration. Consult the README on how to
|
||||||
@@ -2337,7 +2342,8 @@ ghcupDownloads:
|
|||||||
Linux_Alpine:
|
Linux_Alpine:
|
||||||
unknown_versioning: *hls-110-64
|
unknown_versioning: *hls-110-64
|
||||||
1.2.0:
|
1.2.0:
|
||||||
viTags: []
|
viTags:
|
||||||
|
- old
|
||||||
viChangeLog: https://github.com/haskell/haskell-language-server/blob/master/ChangeLog.md#120
|
viChangeLog: https://github.com/haskell/haskell-language-server/blob/master/ChangeLog.md#120
|
||||||
viPostInstall: *hls-post-install
|
viPostInstall: *hls-post-install
|
||||||
viArch:
|
viArch:
|
||||||
@@ -2357,9 +2363,7 @@ ghcupDownloads:
|
|||||||
Linux_Alpine:
|
Linux_Alpine:
|
||||||
unknown_versioning: *hls-120-64
|
unknown_versioning: *hls-120-64
|
||||||
1.3.0:
|
1.3.0:
|
||||||
viTags:
|
viTags: []
|
||||||
- Recommended
|
|
||||||
- Latest
|
|
||||||
viChangeLog: https://github.com/haskell/haskell-language-server/blob/master/ChangeLog.md#130
|
viChangeLog: https://github.com/haskell/haskell-language-server/blob/master/ChangeLog.md#130
|
||||||
viPostInstall: *hls-post-install
|
viPostInstall: *hls-post-install
|
||||||
viArch:
|
viArch:
|
||||||
@@ -2378,6 +2382,50 @@ ghcupDownloads:
|
|||||||
dlHash: 46aac7be888e29a9907cf56698c1ce1475c148b5e6cc099513e9ef74a0520dcf
|
dlHash: 46aac7be888e29a9907cf56698c1ce1475c148b5e6cc099513e9ef74a0520dcf
|
||||||
Linux_Alpine:
|
Linux_Alpine:
|
||||||
unknown_versioning: *hls-130-64
|
unknown_versioning: *hls-130-64
|
||||||
|
1.4.0:
|
||||||
|
viTags:
|
||||||
|
- Recommended
|
||||||
|
- Latest
|
||||||
|
viChangeLog: https://github.com/haskell/haskell-language-server/blob/master/ChangeLog.md#140
|
||||||
|
viPostInstall: *hls-post-install
|
||||||
|
viSourceDL:
|
||||||
|
dlUri: https://downloads.haskell.org/ghcup/src/haskell-language-server/1.4.0/haskell-language-server-1.4.0.tar.gz
|
||||||
|
dlSubdir: haskell-language-server-1.4.0
|
||||||
|
dlHash: c5d7dbf7fae9aa3ed2c1184b49e82d8ac623ca786494ef6602cfe11735d28db0
|
||||||
|
viArch:
|
||||||
|
A_64:
|
||||||
|
Linux_UnknownLinux:
|
||||||
|
unknown_versioning: &hls-140-64
|
||||||
|
dlUri: https://github.com/haskell/haskell-language-server/releases/download/1.4.0/haskell-language-server-Linux-1.4.0.tar.gz
|
||||||
|
dlHash: f93c114441911ccce55649702adc9553cb4c9f953c37878321d2806a3525fee8
|
||||||
|
Darwin:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://github.com/haskell/haskell-language-server/releases/download/1.4.0/haskell-language-server-macOS-1.4.0.tar.gz
|
||||||
|
dlHash: a7f0ac6be93ffb08cc239e5f5fead99b061061825f99566c1be33ee60cab62a4
|
||||||
|
FreeBSD:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/ghcup/unofficial-bindists/haskell-language-server/1.4.0/haskell-language-server-freebsd-1.4.0.tar.gz
|
||||||
|
dlHash: 6b2ad2398ed8c3964dea017e3d5e553b54c10ba1373d7653d2edd019854f4da2
|
||||||
|
Windows:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://github.com/haskell/haskell-language-server/releases/download/1.4.0/haskell-language-server-Windows-1.4.0.tar.gz
|
||||||
|
dlHash: 0ec77cee750037b7a0ede817b46a913a702821f4098c6a858bcb686cb30f7efd
|
||||||
|
Linux_Alpine:
|
||||||
|
unknown_versioning: *hls-140-64
|
||||||
|
A_ARM64:
|
||||||
|
Linux_UnknownLinux:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/ghcup/unofficial-bindists/haskell-language-server/1.4.0/haskell-language-server-linux-aarch64-1.4.0.tar.gz
|
||||||
|
dlHash: 8ad97e2bf1c538e637edec194e1cd9939019955bb749cb470f34bbe5a067b001
|
||||||
|
Darwin:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/ghcup/unofficial-bindists/haskell-language-server/1.4.0/haskell-language-server-macOS-aarch64-1.4.0.tar.gz
|
||||||
|
dlHash: 70c6fe38e987ba44c1e19173486c01f666ffb30a74cd5a7968296a5aba4c2dd0
|
||||||
|
A_ARM:
|
||||||
|
Linux_UnknownLinux:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/ghcup/unofficial-bindists/haskell-language-server/1.4.0/haskell-language-server-linux-armv7-1.4.0.tar.gz
|
||||||
|
dlHash: 4a921fbca06b02f3b1c0930cec5e65e9362b603e7715680ec7b150f18bd703d6
|
||||||
Stack:
|
Stack:
|
||||||
2.5.1:
|
2.5.1:
|
||||||
viTags:
|
viTags:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,32 +0,0 @@
|
|||||||
FROM alpine:3.14.2
|
|
||||||
|
|
||||||
# install deps needed by GHC
|
|
||||||
RUN apk add --no-cache \
|
|
||||||
curl \
|
|
||||||
gcc \
|
|
||||||
g++ \
|
|
||||||
binutils \
|
|
||||||
binutils-gold \
|
|
||||||
gmp \
|
|
||||||
ncurses \
|
|
||||||
libffi \
|
|
||||||
make \
|
|
||||||
xz \
|
|
||||||
tar \
|
|
||||||
perl
|
|
||||||
|
|
||||||
ARG GHCUP_VERSION
|
|
||||||
|
|
||||||
# install ghcup
|
|
||||||
RUN if [ -n "$GHCUP_VERSION" ] ; \
|
|
||||||
then curl -sSfL https://downloads.haskell.org/~ghcup/$GHCUP_VERSION/x86_64-linux-ghcup-$GHCUP_VERSION > /usr/bin/ghcup ; \
|
|
||||||
else curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-linux-ghcup > /usr/bin/ghcup ; \
|
|
||||||
fi && \
|
|
||||||
chmod +x /usr/bin/ghcup
|
|
||||||
|
|
||||||
ENV GHCUP_INSTALL_BASE_PREFIX=/usr/local
|
|
||||||
ENV PATH=/usr/local/.ghcup/bin:$PATH
|
|
||||||
|
|
||||||
RUN ghcup install ghc --set 8.10.7 && \
|
|
||||||
ghcup install cabal latest && \
|
|
||||||
ghcup install stack latest
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
FROM alpine:3.14.2
|
|
||||||
|
|
||||||
# install deps needed by GHC
|
|
||||||
RUN apk add --no-cache \
|
|
||||||
curl \
|
|
||||||
gcc \
|
|
||||||
g++ \
|
|
||||||
binutils \
|
|
||||||
binutils-gold \
|
|
||||||
gmp \
|
|
||||||
ncurses \
|
|
||||||
libffi \
|
|
||||||
make \
|
|
||||||
xz \
|
|
||||||
tar \
|
|
||||||
perl
|
|
||||||
|
|
||||||
ARG GHCUP_VERSION
|
|
||||||
|
|
||||||
# install ghcup
|
|
||||||
RUN if [ -n "$GHCUP_VERSION" ] ; \
|
|
||||||
then curl -sSfL https://downloads.haskell.org/~ghcup/$GHCUP_VERSION/x86_64-linux-ghcup-$GHCUP_VERSION > /usr/bin/ghcup ; \
|
|
||||||
else curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-linux-ghcup > /usr/bin/ghcup ; \
|
|
||||||
fi && \
|
|
||||||
chmod +x /usr/bin/ghcup
|
|
||||||
|
|
||||||
ENV GHCUP_INSTALL_BASE_PREFIX=/usr/local
|
|
||||||
ENV PATH=/usr/local/.ghcup/bin:$PATH
|
|
||||||
|
|
||||||
RUN ghcup prefetch metadata
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
FROM alpine:latest
|
|
||||||
|
|
||||||
# install deps needed by GHC
|
|
||||||
RUN apk add --no-cache \
|
|
||||||
curl \
|
|
||||||
gcc \
|
|
||||||
g++ \
|
|
||||||
binutils \
|
|
||||||
binutils-gold \
|
|
||||||
gmp \
|
|
||||||
ncurses \
|
|
||||||
libffi \
|
|
||||||
make \
|
|
||||||
xz \
|
|
||||||
tar \
|
|
||||||
perl
|
|
||||||
|
|
||||||
ARG GHCUP_VERSION
|
|
||||||
|
|
||||||
# install ghcup
|
|
||||||
RUN if [ -n "$GHCUP_VERSION" ] ; \
|
|
||||||
then curl -sSfL https://downloads.haskell.org/~ghcup/$GHCUP_VERSION/x86_64-linux-ghcup-$GHCUP_VERSION > /usr/bin/ghcup ; \
|
|
||||||
else curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-linux-ghcup > /usr/bin/ghcup ; \
|
|
||||||
fi && \
|
|
||||||
chmod +x /usr/bin/ghcup
|
|
||||||
|
|
||||||
ENV GHCUP_INSTALL_BASE_PREFIX=/usr/local
|
|
||||||
ENV PATH=/usr/local/.ghcup/bin:$PATH
|
|
||||||
|
|
||||||
RUN ghcup install ghc --set 8.10.7 && \
|
|
||||||
ghcup install cabal latest && \
|
|
||||||
ghcup install stack latest
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
FROM alpine:latest
|
|
||||||
|
|
||||||
# install deps needed by GHC
|
|
||||||
RUN apk add --no-cache \
|
|
||||||
curl \
|
|
||||||
gcc \
|
|
||||||
g++ \
|
|
||||||
binutils \
|
|
||||||
binutils-gold \
|
|
||||||
gmp \
|
|
||||||
ncurses \
|
|
||||||
libffi \
|
|
||||||
make \
|
|
||||||
xz \
|
|
||||||
tar \
|
|
||||||
perl
|
|
||||||
|
|
||||||
ARG GHCUP_VERSION
|
|
||||||
|
|
||||||
# install ghcup
|
|
||||||
RUN if [ -n "$GHCUP_VERSION" ] ; \
|
|
||||||
then curl -sSfL https://downloads.haskell.org/~ghcup/$GHCUP_VERSION/x86_64-linux-ghcup-$GHCUP_VERSION > /usr/bin/ghcup ; \
|
|
||||||
else curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-linux-ghcup > /usr/bin/ghcup ; \
|
|
||||||
fi && \
|
|
||||||
chmod +x /usr/bin/ghcup
|
|
||||||
|
|
||||||
ENV GHCUP_INSTALL_BASE_PREFIX=/usr/local
|
|
||||||
ENV PATH=/usr/local/.ghcup/bin:$PATH
|
|
||||||
|
|
||||||
RUN ghcup prefetch metadata
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
FROM ubuntu:20.04
|
|
||||||
|
|
||||||
# install deps needed by GHC
|
|
||||||
RUN export DEBIAN_FRONTEND=noninteractive && \
|
|
||||||
apt-get update -y && \
|
|
||||||
apt-get install -y --no-install-recommends libnuma-dev zlib1g-dev libgmp-dev libgmp10 libssl-dev liblzma-dev libbz2-dev git wget lsb-release software-properties-common gnupg2 apt-transport-https gcc autoconf automake build-essential curl && \
|
|
||||||
apt-get clean && \
|
|
||||||
rm -rf /var/cache/apt/archives && \
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
ARG GHCUP_VERSION
|
|
||||||
|
|
||||||
# install ghcup
|
|
||||||
RUN if [ -n "$GHCUP_VERSION" ] ; \
|
|
||||||
then curl -sSfL https://downloads.haskell.org/~ghcup/$GHCUP_VERSION/x86_64-linux-ghcup-$GHCUP_VERSION > /usr/bin/ghcup ; \
|
|
||||||
else curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-linux-ghcup > /usr/bin/ghcup ; \
|
|
||||||
fi && \
|
|
||||||
chmod +x /usr/bin/ghcup
|
|
||||||
|
|
||||||
ENV GHCUP_INSTALL_BASE_PREFIX=/usr/local
|
|
||||||
ENV PATH=/usr/local/.ghcup/bin:$PATH
|
|
||||||
|
|
||||||
RUN ghcup install ghc --set 8.10.7 && \
|
|
||||||
ghcup install cabal latest && \
|
|
||||||
ghcup install stack latest
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
FROM ubuntu:20.04
|
|
||||||
|
|
||||||
# install deps needed by GHC
|
|
||||||
RUN export DEBIAN_FRONTEND=noninteractive && \
|
|
||||||
apt-get update -y && \
|
|
||||||
apt-get install -y --no-install-recommends libnuma-dev zlib1g-dev libgmp-dev libgmp10 libssl-dev liblzma-dev libbz2-dev git wget lsb-release software-properties-common gnupg2 apt-transport-https gcc autoconf automake build-essential curl && \
|
|
||||||
apt-get clean && \
|
|
||||||
rm -rf /var/cache/apt/archives && \
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
ARG GHCUP_VERSION
|
|
||||||
|
|
||||||
# install ghcup
|
|
||||||
RUN if [ -n "$GHCUP_VERSION" ] ; \
|
|
||||||
then curl -sSfL https://downloads.haskell.org/~ghcup/$GHCUP_VERSION/x86_64-linux-ghcup-$GHCUP_VERSION > /usr/bin/ghcup ; \
|
|
||||||
else curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-linux-ghcup > /usr/bin/ghcup ; \
|
|
||||||
fi && \
|
|
||||||
chmod +x /usr/bin/ghcup
|
|
||||||
|
|
||||||
ENV GHCUP_INSTALL_BASE_PREFIX=/usr/local
|
|
||||||
ENV PATH=/usr/local/.ghcup/bin:$PATH
|
|
||||||
|
|
||||||
RUN ghcup prefetch metadata
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
FROM ubuntu:latest
|
|
||||||
|
|
||||||
# install deps needed by GHC
|
|
||||||
RUN export DEBIAN_FRONTEND=noninteractive && \
|
|
||||||
apt-get update -y && \
|
|
||||||
apt-get install -y --no-install-recommends libnuma-dev zlib1g-dev libgmp-dev libgmp10 libssl-dev liblzma-dev libbz2-dev git wget lsb-release software-properties-common gnupg2 apt-transport-https gcc autoconf automake build-essential curl && \
|
|
||||||
apt-get clean && \
|
|
||||||
rm -rf /var/cache/apt/archives && \
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
ARG GHCUP_VERSION
|
|
||||||
|
|
||||||
# install ghcup
|
|
||||||
RUN if [ -n "$GHCUP_VERSION" ] ; \
|
|
||||||
then curl -sSfL https://downloads.haskell.org/~ghcup/$GHCUP_VERSION/x86_64-linux-ghcup-$GHCUP_VERSION > /usr/bin/ghcup ; \
|
|
||||||
else curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-linux-ghcup > /usr/bin/ghcup ; \
|
|
||||||
fi && \
|
|
||||||
chmod +x /usr/bin/ghcup
|
|
||||||
|
|
||||||
ENV GHCUP_INSTALL_BASE_PREFIX=/usr/local
|
|
||||||
ENV PATH=/usr/local/.ghcup/bin:$PATH
|
|
||||||
|
|
||||||
RUN ghcup install ghc --set 8.10.7 && \
|
|
||||||
ghcup install cabal latest && \
|
|
||||||
ghcup install stack latest
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
FROM ubuntu:latest
|
|
||||||
|
|
||||||
# install deps needed by GHC
|
|
||||||
RUN export DEBIAN_FRONTEND=noninteractive && \
|
|
||||||
apt-get update -y && \
|
|
||||||
apt-get install -y --no-install-recommends libnuma-dev zlib1g-dev libgmp-dev libgmp10 libssl-dev liblzma-dev libbz2-dev git wget lsb-release software-properties-common gnupg2 apt-transport-https gcc autoconf automake build-essential curl && \
|
|
||||||
apt-get clean && \
|
|
||||||
rm -rf /var/cache/apt/archives && \
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
ARG GHCUP_VERSION
|
|
||||||
|
|
||||||
# install ghcup
|
|
||||||
RUN if [ -n "$GHCUP_VERSION" ] ; \
|
|
||||||
then curl -sSfL https://downloads.haskell.org/~ghcup/$GHCUP_VERSION/x86_64-linux-ghcup-$GHCUP_VERSION > /usr/bin/ghcup ; \
|
|
||||||
else curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-linux-ghcup > /usr/bin/ghcup ; \
|
|
||||||
fi && \
|
|
||||||
chmod +x /usr/bin/ghcup
|
|
||||||
|
|
||||||
ENV GHCUP_INSTALL_BASE_PREFIX=/usr/local
|
|
||||||
ENV PATH=/usr/local/.ghcup/bin:$PATH
|
|
||||||
|
|
||||||
RUN ghcup prefetch metadata
|
|
||||||
@@ -1,5 +1,19 @@
|
|||||||
# Revision history for ghcup
|
# Revision history for ghcup
|
||||||
|
|
||||||
|
## 0.1.17 -- 2021-09-20
|
||||||
|
|
||||||
|
* Add `--force` option to install/compile wrt [#210](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/210) by Arjun Kathuria
|
||||||
|
* Implement compiling HLS from source wrt [#201](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/201)
|
||||||
|
* Implement experimental GPG verification of the metadata file (see README) wrt [#263](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/236)
|
||||||
|
* Add `ghcup unset` command wrt [#145](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/145)
|
||||||
|
* Add `ghcup whereis bindir` etc wrt [#221](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/221)
|
||||||
|
* Greatly reduce dependency footprint wrt [#212](https://gitlab.haskell.org/haskell/ghcup-hs/-/issues/212)
|
||||||
|
* Add `ghcup --plan-json`
|
||||||
|
* Improve `--patchdir` option for GHC compilation wrt [#226](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/226)
|
||||||
|
* Try to improve logging and failure modes, especially during downloads
|
||||||
|
* Add descriptive warnings when HLS and GHC versions are incompatible
|
||||||
|
* Improve curl header parsing wrt [#213](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/213)
|
||||||
|
|
||||||
## 0.1.16.2 -- 2021-08-12
|
## 0.1.16.2 -- 2021-08-12
|
||||||
|
|
||||||
* Add isolated installations wrt [#141](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/141) by Arjun Kathuria
|
* Add isolated installations wrt [#141](https://gitlab.haskell.org/haskell/ghcup-hs/-/merge_requests/141) by Arjun Kathuria
|
||||||
|
|||||||
27
ghcup.cabal
27
ghcup.cabal
@@ -1,6 +1,6 @@
|
|||||||
cabal-version: 3.0
|
cabal-version: 3.0
|
||||||
name: ghcup
|
name: ghcup
|
||||||
version: 0.1.16.2
|
version: 0.1.17
|
||||||
license: LGPL-3.0-only
|
license: LGPL-3.0-only
|
||||||
license-file: LICENSE
|
license-file: LICENSE
|
||||||
copyright: Julian Ospald 2020
|
copyright: Julian Ospald 2020
|
||||||
@@ -16,19 +16,18 @@ description:
|
|||||||
category: System
|
category: System
|
||||||
build-type: Simple
|
build-type: Simple
|
||||||
extra-doc-files:
|
extra-doc-files:
|
||||||
README.md
|
|
||||||
docs/CHANGELOG.md
|
|
||||||
docs/HACKING.md
|
|
||||||
docs/RELEASING.md
|
|
||||||
data/config.yaml
|
data/config.yaml
|
||||||
data/metadata/ghcup-0.0.4.yaml
|
data/metadata/ghcup-0.0.4.yaml
|
||||||
data/metadata/ghcup-0.0.5.yaml
|
data/metadata/ghcup-0.0.5.yaml
|
||||||
data/metadata/ghcup-0.0.6.yaml
|
data/metadata/ghcup-0.0.6.yaml
|
||||||
data/metadata/ghcup-0.0.7.yaml
|
docs/CHANGELOG.md
|
||||||
|
docs/HACKING.md
|
||||||
|
docs/RELEASING.md
|
||||||
|
README.md
|
||||||
|
|
||||||
extra-source-files:
|
extra-source-files:
|
||||||
data/build_mk/default
|
|
||||||
data/build_mk/cross
|
data/build_mk/cross
|
||||||
|
data/build_mk/default
|
||||||
|
|
||||||
source-repository head
|
source-repository head
|
||||||
type: git
|
type: git
|
||||||
@@ -100,9 +99,9 @@ library
|
|||||||
, base16-bytestring >=0.1.1.6 && <1.1
|
, base16-bytestring >=0.1.1.6 && <1.1
|
||||||
, binary ^>=0.8.6.0
|
, binary ^>=0.8.6.0
|
||||||
, bytestring ^>=0.10
|
, bytestring ^>=0.10
|
||||||
|
, Cabal
|
||||||
, case-insensitive ^>=1.2.1.0
|
, case-insensitive ^>=1.2.1.0
|
||||||
, casing ^>=0.1.4.1
|
, casing ^>=0.1.4.1
|
||||||
, concurrent-output ^>=1.10.11
|
|
||||||
, containers ^>=0.6
|
, containers ^>=0.6
|
||||||
, cryptohash-sha256 ^>=0.11.101.0
|
, cryptohash-sha256 ^>=0.11.101.0
|
||||||
, deepseq ^>=1.4.4.0
|
, deepseq ^>=1.4.4.0
|
||||||
@@ -111,6 +110,7 @@ library
|
|||||||
, filepath ^>=1.4.2.1
|
, filepath ^>=1.4.2.1
|
||||||
, haskus-utils-types ^>=1.5
|
, haskus-utils-types ^>=1.5
|
||||||
, haskus-utils-variant >=3.0 && <3.2
|
, haskus-utils-variant >=3.0 && <3.2
|
||||||
|
, HsYAML-aeson ^>=0.2.0.0
|
||||||
, libarchive ^>=3.0.0.0
|
, libarchive ^>=3.0.0.0
|
||||||
, lzma-static ^>=5.2.5.3
|
, lzma-static ^>=5.2.5.3
|
||||||
, megaparsec >=8.0.0 && <9.1
|
, megaparsec >=8.0.0 && <9.1
|
||||||
@@ -136,7 +136,6 @@ library
|
|||||||
, vector ^>=0.12
|
, vector ^>=0.12
|
||||||
, versions >=4.0.1 && <5.1
|
, versions >=4.0.1 && <5.1
|
||||||
, word8 ^>=0.1.3
|
, word8 ^>=0.1.3
|
||||||
, HsYAML-aeson ^>=0.2.0.0
|
|
||||||
, zlib ^>=0.6.2.2
|
, zlib ^>=0.6.2.2
|
||||||
|
|
||||||
if (flag(internal-downloader) && !os(windows))
|
if (flag(internal-downloader) && !os(windows))
|
||||||
@@ -158,7 +157,11 @@ library
|
|||||||
, Win32 ^>=2.10
|
, Win32 ^>=2.10
|
||||||
|
|
||||||
else
|
else
|
||||||
other-modules: GHCup.Utils.File.Posix
|
other-modules:
|
||||||
|
GHCup.Utils.File.Posix
|
||||||
|
System.Console.Terminal.Common
|
||||||
|
System.Console.Terminal.Posix
|
||||||
|
|
||||||
build-depends:
|
build-depends:
|
||||||
, bz2 >=0.5.0.5 && <1.1
|
, bz2 >=0.5.0.5 && <1.1
|
||||||
, unix ^>=2.7
|
, unix ^>=2.7
|
||||||
@@ -198,6 +201,7 @@ executable ghcup
|
|||||||
, filepath ^>=1.4.2.1
|
, filepath ^>=1.4.2.1
|
||||||
, ghcup
|
, ghcup
|
||||||
, haskus-utils-variant >=3.0 && <3.2
|
, haskus-utils-variant >=3.0 && <3.2
|
||||||
|
, HsYAML-aeson ^>=0.2.0.0
|
||||||
, libarchive ^>=3.0.0.0
|
, libarchive ^>=3.0.0.0
|
||||||
, megaparsec >=8.0.0 && <9.1
|
, megaparsec >=8.0.0 && <9.1
|
||||||
, mtl ^>=2.2
|
, mtl ^>=2.2
|
||||||
@@ -212,7 +216,6 @@ executable ghcup
|
|||||||
, uri-bytestring ^>=0.3.2.2
|
, uri-bytestring ^>=0.3.2.2
|
||||||
, utf8-string ^>=1.0
|
, utf8-string ^>=1.0
|
||||||
, versions >=4.0.1 && <5.1
|
, versions >=4.0.1 && <5.1
|
||||||
, HsYAML-aeson ^>=0.2.0.0
|
|
||||||
|
|
||||||
if flag(internal-downloader)
|
if flag(internal-downloader)
|
||||||
cpp-options: -DINTERNAL_DOWNLOADER
|
cpp-options: -DINTERNAL_DOWNLOADER
|
||||||
@@ -260,6 +263,7 @@ executable ghcup-gen
|
|||||||
, filepath ^>=1.4.2.1
|
, filepath ^>=1.4.2.1
|
||||||
, ghcup
|
, ghcup
|
||||||
, haskus-utils-variant >=3.0 && <3.2
|
, haskus-utils-variant >=3.0 && <3.2
|
||||||
|
, HsYAML-aeson ^>=0.2.0.0
|
||||||
, libarchive ^>=3.0.0.0
|
, libarchive ^>=3.0.0.0
|
||||||
, mtl ^>=2.2
|
, mtl ^>=2.2
|
||||||
, optics ^>=0.4
|
, optics ^>=0.4
|
||||||
@@ -272,7 +276,6 @@ executable ghcup-gen
|
|||||||
, text ^>=1.2.4.0
|
, text ^>=1.2.4.0
|
||||||
, transformers ^>=0.5
|
, transformers ^>=0.5
|
||||||
, versions >=4.0.1 && <5.1
|
, versions >=4.0.1 && <5.1
|
||||||
, HsYAML-aeson ^>=0.2.0.0
|
|
||||||
|
|
||||||
test-suite ghcup-test
|
test-suite ghcup-test
|
||||||
type: exitcode-stdio-1.0
|
type: exitcode-stdio-1.0
|
||||||
|
|||||||
640
lib/GHCup.hs
640
lib/GHCup.hs
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,7 @@ import GHCup.Types.Optics
|
|||||||
import GHCup.Types.JSON ( )
|
import GHCup.Types.JSON ( )
|
||||||
import GHCup.Utils.Dirs
|
import GHCup.Utils.Dirs
|
||||||
import GHCup.Utils.File
|
import GHCup.Utils.File
|
||||||
|
import GHCup.Utils.Logger
|
||||||
import GHCup.Utils.Prelude
|
import GHCup.Utils.Prelude
|
||||||
import GHCup.Version
|
import GHCup.Version
|
||||||
|
|
||||||
@@ -114,7 +115,7 @@ getDownloadsF :: ( FromJSONKey Tool
|
|||||||
, MonadMask m
|
, MonadMask m
|
||||||
)
|
)
|
||||||
=> Excepts
|
=> Excepts
|
||||||
'[JSONError , DownloadFailed , FileDoesNotExistError]
|
'[DigestError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError]
|
||||||
m
|
m
|
||||||
GHCupInfo
|
GHCupInfo
|
||||||
getDownloadsF = do
|
getDownloadsF = do
|
||||||
@@ -165,7 +166,7 @@ getBase :: ( MonadReader env m
|
|||||||
, MonadMask m
|
, MonadMask m
|
||||||
)
|
)
|
||||||
=> URI
|
=> URI
|
||||||
-> Excepts '[JSONError, FileDoesNotExistError] m GHCupInfo
|
-> Excepts '[GPGError, DigestError, JSONError, FileDoesNotExistError] m GHCupInfo
|
||||||
getBase uri = do
|
getBase uri = do
|
||||||
Settings { noNetwork, downloader } <- lift getSettings
|
Settings { noNetwork, downloader } <- lift getSettings
|
||||||
|
|
||||||
@@ -176,7 +177,6 @@ getBase uri = do
|
|||||||
then pure Nothing
|
then pure Nothing
|
||||||
else handleIO (\e -> lift (warnCache (displayException e) downloader) >> pure Nothing)
|
else handleIO (\e -> lift (warnCache (displayException e) downloader) >> pure Nothing)
|
||||||
. catchE @_ @_ @'[] (\e@(DownloadFailed _) -> lift (warnCache (prettyShow e) downloader) >> pure Nothing)
|
. catchE @_ @_ @'[] (\e@(DownloadFailed _) -> lift (warnCache (prettyShow e) downloader) >> pure Nothing)
|
||||||
. reThrowAll @_ @_ @'[DownloadFailed] DownloadFailed
|
|
||||||
. fmap Just
|
. fmap Just
|
||||||
. smartDl
|
. smartDl
|
||||||
$ uri
|
$ uri
|
||||||
@@ -234,6 +234,7 @@ getBase uri = do
|
|||||||
-> Excepts
|
-> Excepts
|
||||||
'[ DownloadFailed
|
'[ DownloadFailed
|
||||||
, DigestError
|
, DigestError
|
||||||
|
, GPGError
|
||||||
]
|
]
|
||||||
m1
|
m1
|
||||||
FilePath
|
FilePath
|
||||||
@@ -245,7 +246,7 @@ getBase uri = do
|
|||||||
Dirs { cacheDir } <- lift getDirs
|
Dirs { cacheDir } <- lift getDirs
|
||||||
|
|
||||||
-- for local files, let's short-circuit and ignore access time
|
-- for local files, let's short-circuit and ignore access time
|
||||||
if | scheme == "file" -> liftE $ download uri' Nothing cacheDir Nothing True
|
if | scheme == "file" -> liftE $ download uri' Nothing Nothing cacheDir Nothing True
|
||||||
| e -> do
|
| e -> do
|
||||||
accessTime <- liftIO $ getAccessTime json_file
|
accessTime <- liftIO $ getAccessTime json_file
|
||||||
|
|
||||||
@@ -258,7 +259,7 @@ getBase uri = do
|
|||||||
where
|
where
|
||||||
dlWithMod modTime json_file = do
|
dlWithMod modTime json_file = do
|
||||||
let (dir, fn) = splitFileName json_file
|
let (dir, fn) = splitFileName json_file
|
||||||
f <- liftE $ download uri' Nothing dir (Just fn) True
|
f <- liftE $ download uri' (Just $ over pathL' (<> ".sig") uri') Nothing dir (Just fn) True
|
||||||
liftIO $ setModificationTime f modTime
|
liftIO $ setModificationTime f modTime
|
||||||
liftIO $ setAccessTime f modTime
|
liftIO $ setAccessTime f modTime
|
||||||
pure f
|
pure f
|
||||||
@@ -322,16 +323,17 @@ download :: ( MonadReader env m
|
|||||||
, MonadIO m
|
, MonadIO m
|
||||||
)
|
)
|
||||||
=> URI
|
=> URI
|
||||||
|
-> Maybe URI -- ^ URI for gpg sig
|
||||||
-> Maybe T.Text -- ^ expected hash
|
-> Maybe T.Text -- ^ expected hash
|
||||||
-> FilePath -- ^ destination dir (ignored for file:// scheme)
|
-> FilePath -- ^ destination dir (ignored for file:// scheme)
|
||||||
-> Maybe FilePath -- ^ optional filename
|
-> Maybe FilePath -- ^ optional filename
|
||||||
-> Bool -- ^ whether to read an write etags
|
-> Bool -- ^ whether to read an write etags
|
||||||
-> Excepts '[DigestError , DownloadFailed] m FilePath
|
-> Excepts '[DigestError , DownloadFailed, GPGError] m FilePath
|
||||||
download uri eDigest dest mfn etags
|
download uri gpgUri eDigest dest mfn etags
|
||||||
| scheme == "https" = dl
|
| scheme == "https" = dl
|
||||||
| scheme == "http" = dl
|
| scheme == "http" = dl
|
||||||
| scheme == "file" = do
|
| scheme == "file" = do
|
||||||
let destFile' = T.unpack . decUTF8Safe $ path
|
let destFile' = T.unpack . decUTF8Safe $ view pathL' uri
|
||||||
lift $ logDebug $ "using local file: " <> T.pack destFile'
|
lift $ logDebug $ "using local file: " <> T.pack destFile'
|
||||||
forM_ eDigest (liftE . flip checkDigest destFile')
|
forM_ eDigest (liftE . flip checkDigest destFile')
|
||||||
pure destFile'
|
pure destFile'
|
||||||
@@ -340,35 +342,89 @@ download uri eDigest dest mfn etags
|
|||||||
where
|
where
|
||||||
scheme = view (uriSchemeL' % schemeBSL') uri
|
scheme = view (uriSchemeL' % schemeBSL') uri
|
||||||
dl = do
|
dl = do
|
||||||
destFile <- liftE . reThrowAll @_ @_ @'[DownloadFailed] DownloadFailed $ getDestFile
|
baseDestFile <- liftE . reThrowAll @_ @_ @'[DownloadFailed] DownloadFailed $ getDestFile uri mfn
|
||||||
lift $ logInfo $ "downloading: " <> uri' <> " as file " <> T.pack destFile
|
lift $ logInfo $ "downloading: " <> (decUTF8Safe . serializeURIRef') uri <> " as file " <> T.pack baseDestFile
|
||||||
|
|
||||||
-- destination dir must exist
|
-- destination dir must exist
|
||||||
liftIO $ createDirRecursive' dest
|
liftIO $ createDirRecursive' dest
|
||||||
|
|
||||||
|
|
||||||
-- download
|
-- download
|
||||||
flip onException
|
flip onException
|
||||||
(lift $ hideError doesNotExistErrorType $ recycleFile destFile)
|
(lift $ hideError doesNotExistErrorType $ recycleFile (tmpFile baseDestFile))
|
||||||
$ catchAllE @_ @'[ProcessError, DownloadFailed, UnsupportedScheme]
|
$ catchAllE @_ @'[GPGError, ProcessError, DownloadFailed, UnsupportedScheme, DigestError] @'[DigestError, DownloadFailed, GPGError]
|
||||||
(\e ->
|
(\e' -> do
|
||||||
lift (hideError doesNotExistErrorType $ recycleFile destFile)
|
lift $ hideError doesNotExistErrorType $ recycleFile (tmpFile baseDestFile)
|
||||||
>> (throwE . DownloadFailed $ e)
|
case e' of
|
||||||
|
V e@GPGError {} -> throwE e
|
||||||
|
V e@DigestError {} -> throwE e
|
||||||
|
_ -> throwE (DownloadFailed e')
|
||||||
) $ do
|
) $ do
|
||||||
Settings{ downloader, noNetwork } <- lift getSettings
|
Settings{ downloader, noNetwork, gpgSetting } <- lift getSettings
|
||||||
when noNetwork $ throwE (DownloadFailed (V NoNetwork :: V '[NoNetwork]))
|
when noNetwork $ throwE (DownloadFailed (V NoNetwork :: V '[NoNetwork]))
|
||||||
case downloader of
|
downloadAction <- case downloader of
|
||||||
Curl -> do
|
Curl -> do
|
||||||
o' <- liftIO getCurlOpts
|
o' <- liftIO getCurlOpts
|
||||||
if etags
|
if etags
|
||||||
then do
|
then pure $ curlEtagsDL o'
|
||||||
|
else pure $ curlDL o'
|
||||||
|
Wget -> do
|
||||||
|
o' <- liftIO getWgetOpts
|
||||||
|
if etags
|
||||||
|
then pure $ wgetEtagsDL o'
|
||||||
|
else pure $ wgetDL o'
|
||||||
|
#if defined(INTERNAL_DOWNLOADER)
|
||||||
|
Internal -> do
|
||||||
|
if etags
|
||||||
|
then pure (\fp -> liftE . internalEtagsDL fp)
|
||||||
|
else pure (\fp -> liftE . internalDL fp)
|
||||||
|
#endif
|
||||||
|
liftE $ downloadAction baseDestFile uri
|
||||||
|
case (gpgUri, gpgSetting) of
|
||||||
|
(_, GPGNone) -> pure ()
|
||||||
|
(Just gpgUri', _) -> do
|
||||||
|
gpgDestFile <- liftE . reThrowAll @_ @_ @'[DownloadFailed] DownloadFailed $ getDestFile gpgUri' Nothing
|
||||||
|
liftE $ flip onException
|
||||||
|
(lift $ hideError doesNotExistErrorType $ recycleFile (tmpFile gpgDestFile))
|
||||||
|
$ catchAllE @_ @'[GPGError, ProcessError, UnsupportedScheme, DownloadFailed] @'[GPGError]
|
||||||
|
(\e -> if gpgSetting == GPGStrict then throwE (GPGError e) else lift $ logWarn $ T.pack (prettyShow (GPGError e))
|
||||||
|
) $ do
|
||||||
|
o' <- liftIO getGpgOpts
|
||||||
|
lift $ logDebug $ "downloading: " <> (decUTF8Safe . serializeURIRef') gpgUri' <> " as file " <> T.pack gpgDestFile
|
||||||
|
liftE $ downloadAction gpgDestFile gpgUri'
|
||||||
|
lift $ logInfo $ "verifying signature of: " <> T.pack baseDestFile
|
||||||
|
let args = o' ++ ["--batch", "--verify", "--quiet", "--no-tty", gpgDestFile, baseDestFile]
|
||||||
|
cp <- lift $ executeOut "gpg" args Nothing
|
||||||
|
case cp of
|
||||||
|
CapturedProcess { _exitCode = ExitFailure i, _stdErr } -> do
|
||||||
|
lift $ logDebug $ decUTF8Safe' _stdErr
|
||||||
|
throwE (GPGError @'[ProcessError] (V (NonZeroExit i "gpg" args)))
|
||||||
|
CapturedProcess { _stdErr } -> lift $ logDebug $ decUTF8Safe' _stdErr
|
||||||
|
_ -> pure ()
|
||||||
|
|
||||||
|
forM_ eDigest (liftE . flip checkDigest baseDestFile)
|
||||||
|
pure baseDestFile
|
||||||
|
|
||||||
|
curlDL :: (MonadCatch m, MonadMask m, MonadIO m) => [String] -> FilePath -> URI -> Excepts '[ProcessError, DownloadFailed, UnsupportedScheme] m ()
|
||||||
|
curlDL o' destFile (decUTF8Safe . serializeURIRef' -> uri') = do
|
||||||
|
let destFileTemp = tmpFile destFile
|
||||||
|
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
||||||
|
liftE $ lEM @_ @'[ProcessError] $ exec "curl"
|
||||||
|
(o' ++ ["-fL", "-o", destFileTemp, T.unpack uri']) Nothing Nothing
|
||||||
|
liftIO $ renameFile destFileTemp destFile
|
||||||
|
|
||||||
|
curlEtagsDL :: (MonadReader env m, HasLog env, MonadCatch m, MonadMask m, MonadIO m)
|
||||||
|
=> [String] -> FilePath -> URI -> Excepts '[ProcessError, DownloadFailed, UnsupportedScheme] m ()
|
||||||
|
curlEtagsDL o' destFile (decUTF8Safe . serializeURIRef' -> uri') = do
|
||||||
|
let destFileTemp = tmpFile destFile
|
||||||
dh <- liftIO $ emptySystemTempFile "curl-header"
|
dh <- liftIO $ emptySystemTempFile "curl-header"
|
||||||
flip finally (try @_ @SomeException $ rmFile dh) $
|
flip finally (try @_ @SomeException $ rmFile dh) $
|
||||||
flip finally (try @_ @SomeException $ rmFile (destFile <.> "tmp")) $ do
|
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
||||||
metag <- lift $ readETag destFile
|
metag <- lift $ readETag destFile
|
||||||
liftE $ lEM @_ @'[ProcessError] $ exec "curl"
|
liftE $ lEM @_ @'[ProcessError] $ exec "curl"
|
||||||
(o' ++ (if etags then ["--dump-header", dh] else [])
|
(o' ++ (if etags then ["--dump-header", dh] else [])
|
||||||
++ maybe [] (\t -> ["-H", "If-None-Match: " <> T.unpack t]) metag
|
++ maybe [] (\t -> ["-H", "If-None-Match: " <> T.unpack t]) metag
|
||||||
++ ["-fL", "-o", destFile <.> "tmp", T.unpack uri']) Nothing Nothing
|
++ ["-fL", "-o", destFileTemp, T.unpack uri']) Nothing Nothing
|
||||||
headers <- liftIO $ T.readFile dh
|
headers <- liftIO $ T.readFile dh
|
||||||
|
|
||||||
-- this nonsense is necessary, because some older versions of curl would overwrite
|
-- this nonsense is necessary, because some older versions of curl would overwrite
|
||||||
@@ -379,27 +435,33 @@ download uri eDigest dest mfn etags
|
|||||||
, T.pack "HTTP" `T.isPrefixOf` http' -> lift $ logDebug "Status code was 304, not overwriting"
|
, T.pack "HTTP" `T.isPrefixOf` http' -> lift $ logDebug "Status code was 304, not overwriting"
|
||||||
| T.pack "HTTP" `T.isPrefixOf` http' -> do
|
| T.pack "HTTP" `T.isPrefixOf` http' -> do
|
||||||
lift $ logDebug $ "Status code was " <> sc <> ", overwriting"
|
lift $ logDebug $ "Status code was " <> sc <> ", overwriting"
|
||||||
liftIO $ copyFile (destFile <.> "tmp") destFile
|
liftIO $ renameFile destFileTemp destFile
|
||||||
_ -> liftE $ throwE @_ @'[DownloadFailed] (DownloadFailed (toVariantAt @0 (MalformedHeaders headers)
|
_ -> liftE $ throwE @_ @'[DownloadFailed] (DownloadFailed (toVariantAt @0 (MalformedHeaders headers)
|
||||||
:: V '[MalformedHeaders]))
|
:: V '[MalformedHeaders]))
|
||||||
|
|
||||||
lift $ writeEtags destFile (parseEtags headers)
|
lift $ writeEtags destFile (parseEtags headers)
|
||||||
else
|
|
||||||
liftE $ lEM @_ @'[ProcessError] $ exec "curl"
|
wgetDL :: (MonadCatch m, MonadMask m, MonadIO m) => [String] -> FilePath -> URI -> Excepts '[ProcessError, DownloadFailed, UnsupportedScheme] m ()
|
||||||
(o' ++ ["-fL", "-o", destFile, T.unpack uri']) Nothing Nothing
|
wgetDL o' destFile (decUTF8Safe . serializeURIRef' -> uri') = do
|
||||||
Wget -> do
|
let destFileTemp = tmpFile destFile
|
||||||
destFileTemp <- liftIO $ emptySystemTempFile "wget-tmp"
|
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
||||||
|
let opts = o' ++ ["-O", destFileTemp , T.unpack uri']
|
||||||
|
liftE $ lEM @_ @'[ProcessError] $ exec "wget" opts Nothing Nothing
|
||||||
|
liftIO $ renameFile destFileTemp destFile
|
||||||
|
|
||||||
|
|
||||||
|
wgetEtagsDL :: (MonadReader env m, HasLog env, MonadCatch m, MonadMask m, MonadIO m)
|
||||||
|
=> [String] -> FilePath -> URI -> Excepts '[ProcessError, DownloadFailed, UnsupportedScheme] m ()
|
||||||
|
wgetEtagsDL o' destFile (decUTF8Safe . serializeURIRef' -> uri') = do
|
||||||
|
let destFileTemp = tmpFile destFile
|
||||||
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
||||||
o' <- liftIO getWgetOpts
|
|
||||||
if etags
|
|
||||||
then do
|
|
||||||
metag <- lift $ readETag destFile
|
metag <- lift $ readETag destFile
|
||||||
let opts = o' ++ maybe [] (\t -> ["--header", "If-None-Match: " <> T.unpack t]) metag
|
let opts = o' ++ maybe [] (\t -> ["--header", "If-None-Match: " <> T.unpack t]) metag
|
||||||
++ ["-q", "-S", "-O", destFileTemp , T.unpack uri']
|
++ ["-q", "-S", "-O", destFileTemp , T.unpack uri']
|
||||||
CapturedProcess {_exitCode, _stdErr} <- lift $ executeOut "wget" opts Nothing
|
CapturedProcess {_exitCode, _stdErr} <- lift $ executeOut "wget" opts Nothing
|
||||||
case _exitCode of
|
case _exitCode of
|
||||||
ExitSuccess -> do
|
ExitSuccess -> do
|
||||||
liftIO $ copyFile destFileTemp destFile
|
liftIO $ renameFile destFileTemp destFile
|
||||||
lift $ writeEtags destFile (parseEtags (decUTF8Safe' _stdErr))
|
lift $ writeEtags destFile (parseEtags (decUTF8Safe' _stdErr))
|
||||||
ExitFailure i'
|
ExitFailure i'
|
||||||
| i' == 8
|
| i' == 8
|
||||||
@@ -408,47 +470,51 @@ download uri eDigest dest mfn etags
|
|||||||
lift $ logDebug "Not modified, skipping download"
|
lift $ logDebug "Not modified, skipping download"
|
||||||
lift $ writeEtags destFile (parseEtags (decUTF8Safe' _stdErr))
|
lift $ writeEtags destFile (parseEtags (decUTF8Safe' _stdErr))
|
||||||
| otherwise -> throwE (NonZeroExit i' "wget" opts)
|
| otherwise -> throwE (NonZeroExit i' "wget" opts)
|
||||||
else do
|
|
||||||
let opts = o' ++ ["-O", destFileTemp , T.unpack uri']
|
|
||||||
liftE $ lEM @_ @'[ProcessError] $ exec "wget" opts Nothing Nothing
|
|
||||||
liftIO $ copyFile destFileTemp destFile
|
|
||||||
#if defined(INTERNAL_DOWNLOADER)
|
#if defined(INTERNAL_DOWNLOADER)
|
||||||
Internal -> do
|
internalDL :: (MonadCatch m, MonadMask m, MonadIO m)
|
||||||
(https, host, fullPath, port) <- liftE $ uriToQuadruple uri
|
=> FilePath -> URI -> Excepts '[DownloadFailed, UnsupportedScheme] m ()
|
||||||
if etags
|
internalDL destFile uri' = do
|
||||||
then do
|
let destFileTemp = tmpFile destFile
|
||||||
|
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
||||||
|
(https, host, fullPath, port) <- liftE $ uriToQuadruple uri'
|
||||||
|
void $ liftE $ catchE @HTTPNotModified
|
||||||
|
@'[DownloadFailed]
|
||||||
|
(\e@(HTTPNotModified _) ->
|
||||||
|
throwE @_ @'[DownloadFailed] (DownloadFailed (toVariantAt @0 e :: V '[HTTPNotModified])))
|
||||||
|
$ downloadToFile https host fullPath port destFileTemp mempty
|
||||||
|
liftIO $ renameFile destFileTemp destFile
|
||||||
|
|
||||||
|
|
||||||
|
internalEtagsDL :: (MonadReader env m, HasLog env, MonadCatch m, MonadMask m, MonadIO m)
|
||||||
|
=> FilePath -> URI -> Excepts '[DownloadFailed, UnsupportedScheme] m ()
|
||||||
|
internalEtagsDL destFile uri' = do
|
||||||
|
let destFileTemp = tmpFile destFile
|
||||||
|
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
||||||
|
(https, host, fullPath, port) <- liftE $ uriToQuadruple uri'
|
||||||
metag <- lift $ readETag destFile
|
metag <- lift $ readETag destFile
|
||||||
let addHeaders = maybe mempty (\etag -> M.fromList [ (mk . E.encodeUtf8 . T.pack $ "If-None-Match"
|
let addHeaders = maybe mempty (\etag -> M.fromList [ (mk . E.encodeUtf8 . T.pack $ "If-None-Match"
|
||||||
, E.encodeUtf8 etag)]) metag
|
, E.encodeUtf8 etag)]) metag
|
||||||
liftE
|
liftE
|
||||||
$ catchE @HTTPNotModified @'[DownloadFailed] @'[] (\(HTTPNotModified etag) -> lift $ writeEtags destFile (pure $ Just etag))
|
$ catchE @HTTPNotModified @'[DownloadFailed] @'[] (\(HTTPNotModified etag) -> lift $ writeEtags destFile (pure $ Just etag))
|
||||||
$ do
|
$ do
|
||||||
r <- downloadToFile https host fullPath port destFile addHeaders
|
r <- downloadToFile https host fullPath port destFileTemp addHeaders
|
||||||
|
liftIO $ renameFile destFileTemp destFile
|
||||||
lift $ writeEtags destFile (pure $ decUTF8Safe <$> getHeader r "etag")
|
lift $ writeEtags destFile (pure $ decUTF8Safe <$> getHeader r "etag")
|
||||||
else void $ liftE $ catchE @HTTPNotModified
|
|
||||||
@'[DownloadFailed]
|
|
||||||
(\e@(HTTPNotModified _) ->
|
|
||||||
throwE @_ @'[DownloadFailed] (DownloadFailed (toVariantAt @0 e :: V '[HTTPNotModified])))
|
|
||||||
$ downloadToFile https host fullPath port destFile mempty
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
forM_ eDigest (liftE . flip checkDigest destFile)
|
|
||||||
pure destFile
|
|
||||||
|
|
||||||
|
|
||||||
-- Manage to find a file we can write the body into.
|
-- Manage to find a file we can write the body into.
|
||||||
getDestFile :: Monad m => Excepts '[NoUrlBase] m FilePath
|
getDestFile :: Monad m => URI -> Maybe FilePath -> Excepts '[NoUrlBase] m FilePath
|
||||||
getDestFile =
|
getDestFile uri' mfn' =
|
||||||
case mfn of
|
let path = view pathL' uri'
|
||||||
|
in case mfn' of
|
||||||
Just fn -> pure (dest </> fn)
|
Just fn -> pure (dest </> fn)
|
||||||
Nothing
|
Nothing
|
||||||
| let urlBase = T.unpack (decUTF8Safe (urlBaseName path))
|
| let urlBase = T.unpack (decUTF8Safe (urlBaseName path))
|
||||||
, not (null urlBase) -> pure (dest </> urlBase)
|
, not (null urlBase) -> pure (dest </> urlBase)
|
||||||
-- TODO: remove this once we use hpath again
|
-- TODO: remove this once we use hpath again
|
||||||
| otherwise -> throwE $ NoUrlBase uri'
|
| otherwise -> throwE $ NoUrlBase (decUTF8Safe . serializeURIRef' $ uri')
|
||||||
|
|
||||||
path = view pathL' uri
|
|
||||||
uri' = decUTF8Safe (serializeURIRef' uri)
|
|
||||||
|
|
||||||
parseEtags :: (MonadReader env m, HasLog env, MonadIO m, MonadThrow m) => T.Text -> m (Maybe T.Text)
|
parseEtags :: (MonadReader env m, HasLog env, MonadIO m, MonadThrow m) => T.Text -> m (Maybe T.Text)
|
||||||
parseEtags stderr = do
|
parseEtags stderr = do
|
||||||
@@ -509,14 +575,14 @@ downloadCached :: ( MonadReader env m
|
|||||||
)
|
)
|
||||||
=> DownloadInfo
|
=> DownloadInfo
|
||||||
-> Maybe FilePath -- ^ optional filename
|
-> Maybe FilePath -- ^ optional filename
|
||||||
-> Excepts '[DigestError , DownloadFailed] m FilePath
|
-> Excepts '[DigestError , DownloadFailed, GPGError] m FilePath
|
||||||
downloadCached dli mfn = do
|
downloadCached dli mfn = do
|
||||||
Settings{ cache } <- lift getSettings
|
Settings{ cache } <- lift getSettings
|
||||||
case cache of
|
case cache of
|
||||||
True -> downloadCached' dli mfn Nothing
|
True -> downloadCached' dli mfn Nothing
|
||||||
False -> do
|
False -> do
|
||||||
tmp <- lift withGHCupTmpDir
|
tmp <- lift withGHCupTmpDir
|
||||||
liftE $ download (_dlUri dli) (Just (_dlHash dli)) tmp mfn False
|
liftE $ download (_dlUri dli) Nothing (Just (_dlHash dli)) tmp mfn False
|
||||||
|
|
||||||
|
|
||||||
downloadCached' :: ( MonadReader env m
|
downloadCached' :: ( MonadReader env m
|
||||||
@@ -531,7 +597,7 @@ downloadCached' :: ( MonadReader env m
|
|||||||
=> DownloadInfo
|
=> DownloadInfo
|
||||||
-> Maybe FilePath -- ^ optional filename
|
-> Maybe FilePath -- ^ optional filename
|
||||||
-> Maybe FilePath -- ^ optional destination dir (default: cacheDir)
|
-> Maybe FilePath -- ^ optional destination dir (default: cacheDir)
|
||||||
-> Excepts '[DigestError , DownloadFailed] m FilePath
|
-> Excepts '[DigestError , DownloadFailed, GPGError] m FilePath
|
||||||
downloadCached' dli mfn mDestDir = do
|
downloadCached' dli mfn mDestDir = do
|
||||||
Dirs { cacheDir } <- lift getDirs
|
Dirs { cacheDir } <- lift getDirs
|
||||||
let destDir = fromMaybe cacheDir mDestDir
|
let destDir = fromMaybe cacheDir mDestDir
|
||||||
@@ -542,7 +608,7 @@ downloadCached' dli mfn mDestDir = do
|
|||||||
| fileExists -> do
|
| fileExists -> do
|
||||||
liftE $ checkDigest (view dlHash dli) cachfile
|
liftE $ checkDigest (view dlHash dli) cachfile
|
||||||
pure cachfile
|
pure cachfile
|
||||||
| otherwise -> liftE $ download (_dlUri dli) (Just (_dlHash dli)) destDir mfn False
|
| otherwise -> liftE $ download (_dlUri dli) Nothing (Just (_dlHash dli)) destDir mfn False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -571,7 +637,7 @@ checkDigest eDigest file = do
|
|||||||
lift $ logInfo $ "verifying digest of: " <> T.pack p'
|
lift $ logInfo $ "verifying digest of: " <> T.pack p'
|
||||||
c <- liftIO $ L.readFile file
|
c <- liftIO $ L.readFile file
|
||||||
cDigest <- throwEither . E.decodeUtf8' . B16.encode . SHA256.hashlazy $ c
|
cDigest <- throwEither . E.decodeUtf8' . B16.encode . SHA256.hashlazy $ c
|
||||||
when ((cDigest /= eDigest) && verify) $ throwE (DigestError cDigest eDigest)
|
when ((cDigest /= eDigest) && verify) $ throwE (DigestError file cDigest eDigest)
|
||||||
|
|
||||||
|
|
||||||
-- | Get additional curl args from env. This is an undocumented option.
|
-- | Get additional curl args from env. This is an undocumented option.
|
||||||
@@ -589,6 +655,12 @@ getWgetOpts =
|
|||||||
Just r -> pure $ splitOn " " r
|
Just r -> pure $ splitOn " " r
|
||||||
Nothing -> pure []
|
Nothing -> pure []
|
||||||
|
|
||||||
|
-- | Get additional gpg args from env. This is an undocumented option.
|
||||||
|
getGpgOpts :: IO [String]
|
||||||
|
getGpgOpts =
|
||||||
|
lookupEnv "GHCUP_GPG_OPTS" >>= \case
|
||||||
|
Just r -> pure $ splitOn " " r
|
||||||
|
Nothing -> pure []
|
||||||
|
|
||||||
-- | Get the url base name.
|
-- | Get the url base name.
|
||||||
--
|
--
|
||||||
@@ -610,3 +682,7 @@ urlBaseName = snd . B.breakEnd (== _slash) . urlDecode False
|
|||||||
-- "HTTP/1.1 304 Not Modified\n"
|
-- "HTTP/1.1 304 Not Modified\n"
|
||||||
getLastHeader :: T.Text -> T.Text
|
getLastHeader :: T.Text -> T.Text
|
||||||
getLastHeader = T.unlines . lastDef [] . filter (\x -> not (null x)) . splitOn [""] . fmap T.stripEnd . T.lines
|
getLastHeader = T.unlines . lastDef [] . filter (\x -> not (null x)) . splitOn [""] . fmap T.stripEnd . T.lines
|
||||||
|
|
||||||
|
|
||||||
|
tmpFile :: FilePath -> FilePath
|
||||||
|
tmpFile = (<.> "tmp")
|
||||||
|
|||||||
@@ -188,12 +188,22 @@ instance Pretty TarDirDoesNotExist where
|
|||||||
text "Tar directory does not exist:" <+> pPrint dir
|
text "Tar directory does not exist:" <+> pPrint dir
|
||||||
|
|
||||||
-- | File digest verification failed.
|
-- | File digest verification failed.
|
||||||
data DigestError = DigestError Text Text
|
data DigestError = DigestError FilePath Text Text
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
instance Pretty DigestError where
|
instance Pretty DigestError where
|
||||||
pPrint (DigestError currentDigest expectedDigest) =
|
pPrint (DigestError fp currentDigest expectedDigest) =
|
||||||
text "Digest error: expected" <+> text (T.unpack expectedDigest) <+> text "but got" <+> pPrint currentDigest
|
text "Digest error for" <+> text (fp <> ": expected")
|
||||||
|
<+> text (T.unpack expectedDigest) <+> text "but got" <+> pPrint currentDigest <+> text
|
||||||
|
"\nConsider removing the file in case it's cached and try again."
|
||||||
|
|
||||||
|
-- | File digest verification failed.
|
||||||
|
data GPGError = forall xs . (ToVariantMaybe DownloadFailed xs, PopVariant DownloadFailed xs, Show (V xs), Pretty (V xs)) => GPGError (V xs)
|
||||||
|
|
||||||
|
deriving instance Show GPGError
|
||||||
|
|
||||||
|
instance Pretty GPGError where
|
||||||
|
pPrint (GPGError reason) = text "GPG verify failed:" <+> pPrint reason
|
||||||
|
|
||||||
-- | Unexpected HTTP status.
|
-- | Unexpected HTTP status.
|
||||||
data HTTPStatusError = HTTPStatusError Int (M.Map (CI ByteString) ByteString)
|
data HTTPStatusError = HTTPStatusError Int (M.Map (CI ByteString) ByteString)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import GHCup.Types
|
|||||||
import GHCup.Types.Optics
|
import GHCup.Types.Optics
|
||||||
import GHCup.Types.JSON ( )
|
import GHCup.Types.JSON ( )
|
||||||
import GHCup.Utils.File
|
import GHCup.Utils.File
|
||||||
|
import GHCup.Utils.Logger
|
||||||
import GHCup.Utils.Prelude
|
import GHCup.Utils.Prelude
|
||||||
import GHCup.Utils.String.QQ
|
import GHCup.Utils.String.QQ
|
||||||
|
|
||||||
@@ -138,7 +139,6 @@ getLinuxDistro = do
|
|||||||
| hasWord name ["exherbo"] -> Exherbo
|
| hasWord name ["exherbo"] -> Exherbo
|
||||||
| hasWord name ["gentoo"] -> Gentoo
|
| hasWord name ["gentoo"] -> Gentoo
|
||||||
| hasWord name ["amazonlinux", "Amazon Linux"] -> AmazonLinux
|
| hasWord name ["amazonlinux", "Amazon Linux"] -> AmazonLinux
|
||||||
| hasWord name ["solus"] -> Solus
|
|
||||||
| otherwise -> UnknownLinux
|
| otherwise -> UnknownLinux
|
||||||
pure (distro, parsedVer)
|
pure (distro, parsedVer)
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -60,8 +60,9 @@ getCommonRequirements pr tr =
|
|||||||
prettyRequirements :: Requirements -> T.Text
|
prettyRequirements :: Requirements -> T.Text
|
||||||
prettyRequirements Requirements {..} =
|
prettyRequirements Requirements {..} =
|
||||||
let d = if not . null $ _distroPKGs
|
let d = if not . null $ _distroPKGs
|
||||||
then
|
then "\n Please ensure the following distro packages "
|
||||||
"\n Please install the following distro packages: "
|
<> "are installed before continuing (you can exit ghcup "
|
||||||
|
<> "and return at any time): "
|
||||||
<> T.intercalate " " _distroPKGs
|
<> T.intercalate " " _distroPKGs
|
||||||
else ""
|
else ""
|
||||||
n = if not . T.null $ _notes then "\n Note: " <> _notes else ""
|
n = if not . T.null $ _notes then "\n Note: " <> _notes else ""
|
||||||
|
|||||||
@@ -223,7 +223,6 @@ data LinuxDistro = Debian
|
|||||||
| RedHat
|
| RedHat
|
||||||
| Alpine
|
| Alpine
|
||||||
| AmazonLinux
|
| AmazonLinux
|
||||||
| Solus
|
|
||||||
-- rolling
|
-- rolling
|
||||||
| Gentoo
|
| Gentoo
|
||||||
| Exherbo
|
| Exherbo
|
||||||
@@ -243,7 +242,6 @@ distroToString CentOS = "centos"
|
|||||||
distroToString RedHat = "redhat"
|
distroToString RedHat = "redhat"
|
||||||
distroToString Alpine = "alpine"
|
distroToString Alpine = "alpine"
|
||||||
distroToString AmazonLinux = "amazon"
|
distroToString AmazonLinux = "amazon"
|
||||||
distroToString Solus = "solus"
|
|
||||||
distroToString Gentoo = "gentoo"
|
distroToString Gentoo = "gentoo"
|
||||||
distroToString Exherbo = "exherbo"
|
distroToString Exherbo = "exherbo"
|
||||||
distroToString UnknownLinux = "unknown"
|
distroToString UnknownLinux = "unknown"
|
||||||
@@ -303,11 +301,12 @@ data UserSettings = UserSettings
|
|||||||
, uKeyBindings :: Maybe UserKeyBindings
|
, uKeyBindings :: Maybe UserKeyBindings
|
||||||
, uUrlSource :: Maybe URLSource
|
, uUrlSource :: Maybe URLSource
|
||||||
, uNoNetwork :: Maybe Bool
|
, uNoNetwork :: Maybe Bool
|
||||||
|
, uGPGSetting :: Maybe GPGSetting
|
||||||
}
|
}
|
||||||
deriving (Show, GHC.Generic)
|
deriving (Show, GHC.Generic)
|
||||||
|
|
||||||
defaultUserSettings :: UserSettings
|
defaultUserSettings :: UserSettings
|
||||||
defaultUserSettings = UserSettings Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
|
defaultUserSettings = UserSettings Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing
|
||||||
|
|
||||||
fromSettings :: Settings -> Maybe KeyBindings -> UserSettings
|
fromSettings :: Settings -> Maybe KeyBindings -> UserSettings
|
||||||
fromSettings Settings{..} Nothing =
|
fromSettings Settings{..} Nothing =
|
||||||
@@ -320,6 +319,7 @@ fromSettings Settings{..} Nothing =
|
|||||||
, uNoNetwork = Just noNetwork
|
, uNoNetwork = Just noNetwork
|
||||||
, uKeyBindings = Nothing
|
, uKeyBindings = Nothing
|
||||||
, uUrlSource = Just urlSource
|
, uUrlSource = Just urlSource
|
||||||
|
, uGPGSetting = Just gpgSetting
|
||||||
}
|
}
|
||||||
fromSettings Settings{..} (Just KeyBindings{..}) =
|
fromSettings Settings{..} (Just KeyBindings{..}) =
|
||||||
let ukb = UserKeyBindings
|
let ukb = UserKeyBindings
|
||||||
@@ -342,6 +342,7 @@ fromSettings Settings{..} (Just KeyBindings{..}) =
|
|||||||
, uNoNetwork = Just noNetwork
|
, uNoNetwork = Just noNetwork
|
||||||
, uKeyBindings = Just ukb
|
, uKeyBindings = Just ukb
|
||||||
, uUrlSource = Just urlSource
|
, uUrlSource = Just urlSource
|
||||||
|
, uGPGSetting = Just gpgSetting
|
||||||
}
|
}
|
||||||
|
|
||||||
data UserKeyBindings = UserKeyBindings
|
data UserKeyBindings = UserKeyBindings
|
||||||
@@ -415,6 +416,8 @@ data Settings = Settings
|
|||||||
, verbose :: Bool
|
, verbose :: Bool
|
||||||
, urlSource :: URLSource
|
, urlSource :: URLSource
|
||||||
, noNetwork :: Bool
|
, noNetwork :: Bool
|
||||||
|
, gpgSetting :: GPGSetting
|
||||||
|
, noColor :: Bool -- this also exists in LoggerConfig
|
||||||
}
|
}
|
||||||
deriving (Show, GHC.Generic)
|
deriving (Show, GHC.Generic)
|
||||||
|
|
||||||
@@ -448,6 +451,13 @@ data Downloader = Curl
|
|||||||
|
|
||||||
instance NFData Downloader
|
instance NFData Downloader
|
||||||
|
|
||||||
|
data GPGSetting = GPGStrict
|
||||||
|
| GPGLax
|
||||||
|
| GPGNone
|
||||||
|
deriving (Eq, Show, Ord, GHC.Generic)
|
||||||
|
|
||||||
|
instance NFData GPGSetting
|
||||||
|
|
||||||
data DebugInfo = DebugInfo
|
data DebugInfo = DebugInfo
|
||||||
{ diBaseDir :: FilePath
|
{ diBaseDir :: FilePath
|
||||||
, diBinDir :: FilePath
|
, diBinDir :: FilePath
|
||||||
@@ -568,10 +578,11 @@ data LogLevel = Warn
|
|||||||
|
|
||||||
data LoggerConfig = LoggerConfig
|
data LoggerConfig = LoggerConfig
|
||||||
{ lcPrintDebug :: Bool -- ^ whether to print debug in colorOutter
|
{ lcPrintDebug :: Bool -- ^ whether to print debug in colorOutter
|
||||||
, colorOutter :: T.Text -> IO () -- ^ how to write the color output
|
, consoleOutter :: T.Text -> IO () -- ^ how to write the console output
|
||||||
, rawOutter :: T.Text -> IO () -- ^ how to write the full raw output
|
, fileOutter :: T.Text -> IO () -- ^ how to write the file output
|
||||||
|
, fancyColors :: Bool
|
||||||
}
|
}
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
instance NFData LoggerConfig where
|
instance NFData LoggerConfig where
|
||||||
rnf (LoggerConfig !lcPrintDebug !_ !_) = rnf lcPrintDebug
|
rnf (LoggerConfig !lcPrintDebug !_ !_ !fancyColors) = rnf (lcPrintDebug, fancyColors)
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ module GHCup.Types.JSON where
|
|||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
import GHCup.Utils.MegaParsec
|
import GHCup.Utils.MegaParsec
|
||||||
import GHCup.Utils.Prelude
|
import GHCup.Utils.Prelude
|
||||||
|
import GHCup.Utils.Logger () -- TH is broken shite and needs GHCup.Utils.Logger for linking, although we don't depend on the file.
|
||||||
|
-- This is due to the boot file.
|
||||||
|
|
||||||
import Control.Applicative ( (<|>) )
|
import Control.Applicative ( (<|>) )
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
@@ -54,6 +56,7 @@ deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Tool
|
|||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''GlobalTool
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''GlobalTool
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''KeepDirs
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''KeepDirs
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Downloader
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Downloader
|
||||||
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''GPGSetting
|
||||||
|
|
||||||
instance ToJSON Tag where
|
instance ToJSON Tag where
|
||||||
toJSON Latest = String "Latest"
|
toJSON Latest = String "Latest"
|
||||||
|
|||||||
@@ -23,12 +23,9 @@ import GHCup.Types
|
|||||||
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Data.ByteString ( ByteString )
|
import Data.ByteString ( ByteString )
|
||||||
import Data.Text ( Text )
|
|
||||||
import Optics
|
import Optics
|
||||||
import URI.ByteString
|
import URI.ByteString
|
||||||
import System.Console.Pretty
|
|
||||||
|
|
||||||
import qualified Data.Text as T
|
|
||||||
|
|
||||||
makePrisms ''Tool
|
makePrisms ''Tool
|
||||||
makePrisms ''Architecture
|
makePrisms ''Architecture
|
||||||
@@ -117,80 +114,6 @@ getDirs :: ( MonadReader env m
|
|||||||
getDirs = gets @"dirs"
|
getDirs = gets @"dirs"
|
||||||
|
|
||||||
|
|
||||||
logInfo :: ( MonadReader env m
|
|
||||||
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
|
||||||
, MonadIO m
|
|
||||||
)
|
|
||||||
=> Text
|
|
||||||
-> m ()
|
|
||||||
logInfo = logInternal Info
|
|
||||||
|
|
||||||
logWarn :: ( MonadReader env m
|
|
||||||
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
|
||||||
, MonadIO m
|
|
||||||
)
|
|
||||||
=> Text
|
|
||||||
-> m ()
|
|
||||||
logWarn = logInternal Warn
|
|
||||||
|
|
||||||
logDebug :: ( MonadReader env m
|
|
||||||
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
|
||||||
, MonadIO m
|
|
||||||
)
|
|
||||||
=> Text
|
|
||||||
-> m ()
|
|
||||||
logDebug = logInternal Debug
|
|
||||||
|
|
||||||
logError :: ( MonadReader env m
|
|
||||||
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
|
||||||
, MonadIO m
|
|
||||||
)
|
|
||||||
=> Text
|
|
||||||
-> m ()
|
|
||||||
logError = logInternal Error
|
|
||||||
|
|
||||||
|
|
||||||
logInternal :: ( MonadReader env m
|
|
||||||
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
|
||||||
, MonadIO m
|
|
||||||
) => LogLevel
|
|
||||||
-> Text
|
|
||||||
-> m ()
|
|
||||||
logInternal logLevel msg = do
|
|
||||||
LoggerConfig {..} <- gets @"loggerConfig"
|
|
||||||
let style' = case logLevel of
|
|
||||||
Debug -> style Bold . color Blue
|
|
||||||
Info -> style Bold . color Green
|
|
||||||
Warn -> style Bold . color Yellow
|
|
||||||
Error -> style Bold . color Red
|
|
||||||
let l = case logLevel of
|
|
||||||
Debug -> style' "[ Debug ]"
|
|
||||||
Info -> style' "[ Info ]"
|
|
||||||
Warn -> style' "[ Warn ]"
|
|
||||||
Error -> style' "[ Error ]"
|
|
||||||
let strs = T.split (== '\n') msg
|
|
||||||
let out = case strs of
|
|
||||||
[] -> T.empty
|
|
||||||
(x:xs) ->
|
|
||||||
foldr (\a b -> a <> "\n" <> b) mempty
|
|
||||||
. ((l <> " " <> x) :)
|
|
||||||
. fmap (\line' -> style' "[ ... ] " <> line' )
|
|
||||||
$ xs
|
|
||||||
|
|
||||||
when (lcPrintDebug || (not lcPrintDebug && (logLevel /= Debug)))
|
|
||||||
$ liftIO $ colorOutter out
|
|
||||||
|
|
||||||
-- raw output
|
|
||||||
let lr = case logLevel of
|
|
||||||
Debug -> "Debug:"
|
|
||||||
Info -> "Info:"
|
|
||||||
Warn -> "Warn:"
|
|
||||||
Error -> "Error:"
|
|
||||||
let outr = lr <> " " <> msg <> "\n"
|
|
||||||
liftIO $ rawOutter outr
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
getLogCleanup :: ( MonadReader env m
|
getLogCleanup :: ( MonadReader env m
|
||||||
, LabelOptic' "logCleanup" A_Lens env (IO ())
|
, LabelOptic' "logCleanup" A_Lens env (IO ())
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import GHCup.Types.Optics
|
|||||||
import GHCup.Types.JSON ( )
|
import GHCup.Types.JSON ( )
|
||||||
import GHCup.Utils.Dirs
|
import GHCup.Utils.Dirs
|
||||||
import GHCup.Utils.File
|
import GHCup.Utils.File
|
||||||
|
import GHCup.Utils.Logger
|
||||||
import GHCup.Utils.MegaParsec
|
import GHCup.Utils.MegaParsec
|
||||||
import GHCup.Utils.Prelude
|
import GHCup.Utils.Prelude
|
||||||
import GHCup.Utils.String.QQ
|
import GHCup.Utils.String.QQ
|
||||||
@@ -85,8 +86,37 @@ import qualified Data.Map.Strict as Map
|
|||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Encoding as E
|
import qualified Data.Text.Encoding as E
|
||||||
import qualified Text.Megaparsec as MP
|
import qualified Text.Megaparsec as MP
|
||||||
|
import qualified Data.List.NonEmpty as NE
|
||||||
|
|
||||||
|
|
||||||
|
-- $setup
|
||||||
|
-- >>> :set -XOverloadedStrings
|
||||||
|
-- >>> :set -XDataKinds
|
||||||
|
-- >>> :set -XTypeApplications
|
||||||
|
-- >>> :set -XQuasiQuotes
|
||||||
|
-- >>> import System.Directory
|
||||||
|
-- >>> import URI.ByteString
|
||||||
|
-- >>> import qualified Data.Text as T
|
||||||
|
-- >>> import GHCup.Utils.Prelude
|
||||||
|
-- >>> import GHCup.Download
|
||||||
|
-- >>> import GHCup.Version
|
||||||
|
-- >>> import GHCup.Errors
|
||||||
|
-- >>> import GHCup.Types
|
||||||
|
-- >>> import GHCup.Types.Optics
|
||||||
|
-- >>> import Optics
|
||||||
|
-- >>> import GHCup.Utils.Version.QQ
|
||||||
|
-- >>> import qualified Data.Text.Encoding as E
|
||||||
|
-- >>> import Control.Monad.Reader
|
||||||
|
-- >>> import Haskus.Utils.Variant.Excepts
|
||||||
|
-- >>> import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||||
|
-- >>> let lc = LoggerConfig { lcPrintDebug = False, consoleOutter = mempty, fileOutter = mempty, fancyColors = False }
|
||||||
|
-- >>> dirs' <- getAllDirs
|
||||||
|
-- >>> let installedVersions = [ ([pver|8.10.7|], Nothing), ([pver|8.10.4|], Nothing), ([pver|8.8.4|], Nothing), ([pver|8.8.3|], Nothing) ]
|
||||||
|
-- >>> let settings = Settings True False Never Curl False GHCupURL True GPGNone False
|
||||||
|
-- >>> let leanAppState = LeanAppState settings dirs' defaultKeyBindings lc
|
||||||
|
-- >>> cwd <- getCurrentDirectory
|
||||||
|
-- >>> (Right ref) <- pure $ parseURI strictURIParserOptions $ "file://" <> E.encodeUtf8 (T.pack cwd) <> "/data/metadata/" <> (urlBaseName . view pathL' $ ghcupURL)
|
||||||
|
-- >>> (VRight r) <- (fmap . fmap) _ghcupDownloads $ flip runReaderT leanAppState . runE @'[DigestError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError] $ liftE $ getBase ref
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -250,7 +280,6 @@ getInstalledGHCs = do
|
|||||||
-- | Get all installed cabals, by matching on @~\/.ghcup\/bin/cabal-*@.
|
-- | Get all installed cabals, by matching on @~\/.ghcup\/bin/cabal-*@.
|
||||||
getInstalledCabals :: ( MonadReader env m
|
getInstalledCabals :: ( MonadReader env m
|
||||||
, HasDirs env
|
, HasDirs env
|
||||||
, HasLog env
|
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadCatch m
|
, MonadCatch m
|
||||||
)
|
)
|
||||||
@@ -268,7 +297,7 @@ getInstalledCabals = do
|
|||||||
|
|
||||||
|
|
||||||
-- | Whether the given cabal version is installed.
|
-- | Whether the given cabal version is installed.
|
||||||
cabalInstalled :: (HasLog env, MonadIO m, MonadReader env m, HasDirs env, MonadCatch m) => Version -> m Bool
|
cabalInstalled :: (MonadIO m, MonadReader env m, HasDirs env, MonadCatch m) => Version -> m Bool
|
||||||
cabalInstalled ver = do
|
cabalInstalled ver = do
|
||||||
vers <- fmap rights getInstalledCabals
|
vers <- fmap rights getInstalledCabals
|
||||||
pure $ elem ver vers
|
pure $ elem ver vers
|
||||||
@@ -464,9 +493,20 @@ hlsGHCVersions :: ( MonadReader env m
|
|||||||
=> m [Version]
|
=> m [Version]
|
||||||
hlsGHCVersions = do
|
hlsGHCVersions = do
|
||||||
h <- hlsSet
|
h <- hlsSet
|
||||||
vers <- forM h $ \h' -> do
|
fromMaybe [] <$> forM h hlsGHCVersions'
|
||||||
bins <- hlsServerBinaries h'
|
|
||||||
pure $ fmap
|
|
||||||
|
hlsGHCVersions' :: ( MonadReader env m
|
||||||
|
, HasDirs env
|
||||||
|
, MonadIO m
|
||||||
|
, MonadThrow m
|
||||||
|
, MonadCatch m
|
||||||
|
)
|
||||||
|
=> Version
|
||||||
|
-> m [Version]
|
||||||
|
hlsGHCVersions' v' = do
|
||||||
|
bins <- hlsServerBinaries v' Nothing
|
||||||
|
let vers = fmap
|
||||||
(version
|
(version
|
||||||
. T.pack
|
. T.pack
|
||||||
. fromJust
|
. fromJust
|
||||||
@@ -475,21 +515,27 @@ hlsGHCVersions = do
|
|||||||
. splitOn "~"
|
. splitOn "~"
|
||||||
)
|
)
|
||||||
bins
|
bins
|
||||||
pure . rights . concat . maybeToList $ vers
|
pure . sortBy (flip compare) . rights $ vers
|
||||||
|
|
||||||
|
|
||||||
-- | Get all server binaries for an hls version, if any.
|
-- | Get all server binaries for an hls version, if any.
|
||||||
hlsServerBinaries :: (MonadReader env m, HasDirs env, MonadIO m)
|
hlsServerBinaries :: (MonadReader env m, HasDirs env, MonadIO m)
|
||||||
=> Version
|
=> Version
|
||||||
|
-> Maybe Version -- ^ optional GHC version
|
||||||
-> m [FilePath]
|
-> m [FilePath]
|
||||||
hlsServerBinaries ver = do
|
hlsServerBinaries ver mghcVer = do
|
||||||
Dirs {..} <- getDirs
|
Dirs {..} <- getDirs
|
||||||
liftIO $ handleIO (\_ -> pure []) $ findFiles
|
liftIO $ handleIO (\_ -> pure []) $ findFiles
|
||||||
binDir
|
binDir
|
||||||
(makeRegexOpts
|
(makeRegexOpts
|
||||||
compExtended
|
compExtended
|
||||||
execBlank
|
execBlank
|
||||||
([s|^haskell-language-server-.*~|] <> escapeVerRex ver <> E.encodeUtf8 (T.pack exeExt) <> [s|$|] :: ByteString
|
([s|^haskell-language-server-|]
|
||||||
|
<> maybe [s|.*|] escapeVerRex mghcVer
|
||||||
|
<> [s|~|]
|
||||||
|
<> escapeVerRex ver
|
||||||
|
<> E.encodeUtf8 (T.pack exeExt)
|
||||||
|
<> [s|$|] :: ByteString
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -518,7 +564,7 @@ hlsWrapperBinary ver = do
|
|||||||
-- | Get all binaries for an hls version, if any.
|
-- | Get all binaries for an hls version, if any.
|
||||||
hlsAllBinaries :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m) => Version -> m [FilePath]
|
hlsAllBinaries :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m) => Version -> m [FilePath]
|
||||||
hlsAllBinaries ver = do
|
hlsAllBinaries ver = do
|
||||||
hls <- hlsServerBinaries ver
|
hls <- hlsServerBinaries ver Nothing
|
||||||
wrapper <- hlsWrapperBinary ver
|
wrapper <- hlsWrapperBinary ver
|
||||||
pure (maybeToList wrapper ++ hls)
|
pure (maybeToList wrapper ++ hls)
|
||||||
|
|
||||||
@@ -559,34 +605,83 @@ matchMajor v' major' minor' = case getMajorMinorV v' of
|
|||||||
Just (x, y) -> x == major' && y == minor'
|
Just (x, y) -> x == major' && y == minor'
|
||||||
Nothing -> False
|
Nothing -> False
|
||||||
|
|
||||||
|
-- | Match PVP prefix.
|
||||||
|
--
|
||||||
|
-- >>> matchPVPrefix [pver|8.8|] [pver|8.8.4|]
|
||||||
|
-- True
|
||||||
|
-- >>> matchPVPrefix [pver|8|] [pver|8.8.4|]
|
||||||
|
-- True
|
||||||
|
-- >>> matchPVPrefix [pver|8.10|] [pver|8.8.4|]
|
||||||
|
-- False
|
||||||
|
-- >>> matchPVPrefix [pver|8.10|] [pver|8.10.7|]
|
||||||
|
-- True
|
||||||
|
matchPVPrefix :: PVP -> PVP -> Bool
|
||||||
|
matchPVPrefix (toL -> prefix) (toL -> full) = and $ zipWith (==) prefix full
|
||||||
|
|
||||||
-- | Get the latest installed full GHC version that satisfies X.Y.
|
toL :: PVP -> [Int]
|
||||||
-- This reads `ghcupGHCBaseDir`.
|
toL (PVP inner) = fmap fromIntegral $ NE.toList inner
|
||||||
getGHCForMajor :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m)
|
|
||||||
=> Int -- ^ major version component
|
|
||||||
-> Int -- ^ minor version component
|
-- | Get the latest installed full GHC version that satisfies the given (possibly partial)
|
||||||
|
-- PVP version.
|
||||||
|
getGHCForPVP :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m)
|
||||||
|
=> PVP
|
||||||
-> Maybe Text -- ^ the target triple
|
-> Maybe Text -- ^ the target triple
|
||||||
-> m (Maybe GHCTargetVersion)
|
-> m (Maybe GHCTargetVersion)
|
||||||
getGHCForMajor major' minor' mt = do
|
getGHCForPVP pvpIn mt = do
|
||||||
ghcs <- rights <$> getInstalledGHCs
|
ghcs <- rights <$> getInstalledGHCs
|
||||||
|
-- we're permissive here... failed parse just means we have no match anyway
|
||||||
|
let ghcs' = catMaybes $ flip fmap ghcs $ \GHCTargetVersion{..} -> do
|
||||||
|
pvp_ <- versionToPVP _tvVersion
|
||||||
|
pure (pvp_, _tvTarget)
|
||||||
|
|
||||||
pure
|
getGHCForPVP' pvpIn ghcs' mt
|
||||||
. lastMay
|
|
||||||
. sortBy (\x y -> compare (_tvVersion x) (_tvVersion y))
|
-- | Like 'getGHCForPVP', except with explicit input parameter.
|
||||||
|
--
|
||||||
|
-- >>> fmap prettyShow $ getGHCForPVP' [pver|8|] installedVersions Nothing
|
||||||
|
-- "Just 8.10.7"
|
||||||
|
-- >>> fmap prettyShow $ getGHCForPVP' [pver|8.8|] installedVersions Nothing
|
||||||
|
-- "Just 8.8.4"
|
||||||
|
-- >>> fmap prettyShow $ getGHCForPVP' [pver|8.10.4|] installedVersions Nothing
|
||||||
|
-- "Just 8.10.4"
|
||||||
|
getGHCForPVP' :: MonadThrow m
|
||||||
|
=> PVP
|
||||||
|
-> [(PVP, Maybe Text)] -- ^ installed GHCs
|
||||||
|
-> Maybe Text -- ^ the target triple
|
||||||
|
-> m (Maybe GHCTargetVersion)
|
||||||
|
getGHCForPVP' pvpIn ghcs' mt = do
|
||||||
|
let mResult = lastMay
|
||||||
|
. sortBy (\(x, _) (y, _) -> compare x y)
|
||||||
. filter
|
. filter
|
||||||
(\GHCTargetVersion {..} ->
|
(\(pvp_, target) ->
|
||||||
_tvTarget == mt && matchMajor _tvVersion major' minor'
|
target == mt && matchPVPrefix pvp_ pvpIn
|
||||||
)
|
)
|
||||||
$ ghcs
|
$ ghcs'
|
||||||
|
forM mResult $ \(pvp_, target) -> do
|
||||||
|
ver' <- pvpToVersion pvp_
|
||||||
|
pure (GHCTargetVersion target ver')
|
||||||
|
|
||||||
|
|
||||||
-- | Get the latest available ghc for X.Y major version.
|
-- | Get the latest available ghc for the given PVP version, which
|
||||||
getLatestGHCFor :: Int -- ^ major version component
|
-- may only contain parts.
|
||||||
-> Int -- ^ minor version component
|
--
|
||||||
|
-- >>> (fmap . fmap) fst $ getLatestToolFor GHC [pver|8|] r
|
||||||
|
-- Just (PVP {_pComponents = 8 :| [10,7]})
|
||||||
|
-- >>> (fmap . fmap) fst $ getLatestToolFor GHC [pver|8.8|] r
|
||||||
|
-- Just (PVP {_pComponents = 8 :| [8,4]})
|
||||||
|
-- >>> (fmap . fmap) fst $ getLatestToolFor GHC [pver|8.8.4|] r
|
||||||
|
-- Just (PVP {_pComponents = 8 :| [8,4]})
|
||||||
|
getLatestToolFor :: MonadThrow m
|
||||||
|
=> Tool
|
||||||
|
-> PVP
|
||||||
-> GHCupDownloads
|
-> GHCupDownloads
|
||||||
-> Maybe (Version, VersionInfo)
|
-> m (Maybe (PVP, VersionInfo))
|
||||||
getLatestGHCFor major' minor' dls =
|
getLatestToolFor tool pvpIn dls = do
|
||||||
preview (ix GHC % to Map.toDescList) dls >>= lastMay . filter (\(v, _) -> matchMajor v major' minor')
|
let ls = fromMaybe [] $ preview (ix tool % to Map.toDescList) dls
|
||||||
|
let ps = catMaybes $ fmap (\(v, vi) -> (,vi) <$> versionToPVP v) ls
|
||||||
|
pure . headMay . filter (\(v, _) -> matchPVPrefix pvpIn v) $ ps
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -690,11 +785,10 @@ intoSubdir bdir tardir = case tardir of
|
|||||||
-- | Get the tool version that has this tag. If multiple have it,
|
-- | Get the tool version that has this tag. If multiple have it,
|
||||||
-- picks the greatest version.
|
-- picks the greatest version.
|
||||||
getTagged :: Tag
|
getTagged :: Tag
|
||||||
-> AffineFold (Map.Map Version VersionInfo) (Version, VersionInfo)
|
-> Fold (Map.Map Version VersionInfo) (Version, VersionInfo)
|
||||||
getTagged tag =
|
getTagged tag =
|
||||||
to (Map.filter (\VersionInfo {..} -> tag `elem` _viTags))
|
to (Map.toDescList . Map.filter (\VersionInfo {..} -> tag `elem` _viTags))
|
||||||
% to Map.toDescList
|
% folding id
|
||||||
% _head
|
|
||||||
|
|
||||||
getLatest :: GHCupDownloads -> Tool -> Maybe (Version, VersionInfo)
|
getLatest :: GHCupDownloads -> Tool -> Maybe (Version, VersionInfo)
|
||||||
getLatest av tool = headOf (ix tool % getTagged Latest) av
|
getLatest av tool = headOf (ix tool % getTagged Latest) av
|
||||||
@@ -825,7 +919,7 @@ getChangeLog :: GHCupDownloads -> Tool -> Either Version Tag -> Maybe URI
|
|||||||
getChangeLog dls tool (Left v') =
|
getChangeLog dls tool (Left v') =
|
||||||
preview (ix tool % ix v' % viChangeLog % _Just) dls
|
preview (ix tool % ix v' % viChangeLog % _Just) dls
|
||||||
getChangeLog dls tool (Right tag) =
|
getChangeLog dls tool (Right tag) =
|
||||||
preview (ix tool % getTagged tag % to snd % viChangeLog % _Just) dls
|
preview (ix tool % pre (getTagged tag) % to snd % viChangeLog % _Just) dls
|
||||||
|
|
||||||
|
|
||||||
-- | Execute a build action while potentially cleaning up:
|
-- | Execute a build action while potentially cleaning up:
|
||||||
@@ -843,6 +937,8 @@ runBuildAction :: ( Pretty (V e)
|
|||||||
, MonadMask m
|
, MonadMask m
|
||||||
, HasLog env
|
, HasLog env
|
||||||
, MonadUnliftIO m
|
, MonadUnliftIO m
|
||||||
|
, MonadFail m
|
||||||
|
, MonadCatch m
|
||||||
)
|
)
|
||||||
=> FilePath -- ^ build directory (cleaned up depending on Settings)
|
=> FilePath -- ^ build directory (cleaned up depending on Settings)
|
||||||
-> Maybe FilePath -- ^ dir to *always* clean up on exception
|
-> Maybe FilePath -- ^ dir to *always* clean up on exception
|
||||||
@@ -1032,7 +1128,7 @@ ensureGlobalTools :: ( MonadMask m
|
|||||||
, MonadUnliftIO m
|
, MonadUnliftIO m
|
||||||
, MonadFail m
|
, MonadFail m
|
||||||
)
|
)
|
||||||
=> Excepts '[DigestError , DownloadFailed, NoDownload] m ()
|
=> Excepts '[GPGError, DigestError , DownloadFailed, NoDownload] m ()
|
||||||
ensureGlobalTools = do
|
ensureGlobalTools = do
|
||||||
#if defined(IS_WINDOWS)
|
#if defined(IS_WINDOWS)
|
||||||
(GHCupInfo _ _ gTools) <- lift getGHCupInfo
|
(GHCupInfo _ _ gTools) <- lift getGHCupInfo
|
||||||
@@ -1040,12 +1136,12 @@ ensureGlobalTools = do
|
|||||||
shimDownload <- liftE $ lE @_ @'[NoDownload]
|
shimDownload <- liftE $ lE @_ @'[NoDownload]
|
||||||
$ maybe (Left NoDownload) Right $ Map.lookup ShimGen gTools
|
$ maybe (Left NoDownload) Right $ Map.lookup ShimGen gTools
|
||||||
let dl = downloadCached' shimDownload (Just "gs.exe") Nothing
|
let dl = downloadCached' shimDownload (Just "gs.exe") Nothing
|
||||||
void $ (\(DigestError _ _) -> do
|
void $ (\(DigestError _ _ _) -> do
|
||||||
lift $ logWarn "Digest doesn't match, redownloading gs.exe..."
|
lift $ logWarn "Digest doesn't match, redownloading gs.exe..."
|
||||||
lift $ logDebug ("rm -f " <> T.pack (cacheDir dirs </> "gs.exe"))
|
lift $ logDebug ("rm -f " <> T.pack (cacheDir dirs </> "gs.exe"))
|
||||||
lift $ hideError doesNotExistErrorType $ recycleFile (cacheDir dirs </> "gs.exe")
|
lift $ hideError doesNotExistErrorType $ recycleFile (cacheDir dirs </> "gs.exe")
|
||||||
liftE @'[DigestError , DownloadFailed] $ dl
|
liftE @'[GPGError, DigestError , DownloadFailed] $ dl
|
||||||
) `catchE` (liftE @'[DigestError , DownloadFailed] dl)
|
) `catchE` (liftE @'[GPGError, DigestError , DownloadFailed] dl)
|
||||||
pure ()
|
pure ()
|
||||||
#else
|
#else
|
||||||
pure ()
|
pure ()
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import GHCup.Types
|
|||||||
import GHCup.Types.JSON ( )
|
import GHCup.Types.JSON ( )
|
||||||
import GHCup.Types.Optics
|
import GHCup.Types.Optics
|
||||||
import GHCup.Utils.MegaParsec
|
import GHCup.Utils.MegaParsec
|
||||||
|
import GHCup.Utils.Logger
|
||||||
import GHCup.Utils.Prelude
|
import GHCup.Utils.Prelude
|
||||||
|
|
||||||
import Control.Exception.Safe
|
import Control.Exception.Safe
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import GHCup.Utils.Prelude
|
|||||||
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
import Data.Text ( Text )
|
||||||
|
import Data.Void
|
||||||
import GHC.IO.Exception
|
import GHC.IO.Exception
|
||||||
import Optics hiding ((<|), (|>))
|
import Optics hiding ((<|), (|>))
|
||||||
import System.Directory
|
import System.Directory
|
||||||
@@ -16,7 +18,9 @@ import System.FilePath
|
|||||||
import Text.PrettyPrint.HughesPJClass hiding ( (<>) )
|
import Text.PrettyPrint.HughesPJClass hiding ( (<>) )
|
||||||
import Text.Regex.Posix
|
import Text.Regex.Posix
|
||||||
|
|
||||||
|
import qualified Data.Text as T
|
||||||
import qualified Data.ByteString.Lazy as BL
|
import qualified Data.ByteString.Lazy as BL
|
||||||
|
import qualified Text.Megaparsec as MP
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -101,6 +105,16 @@ findFiles path regex = do
|
|||||||
contents <- listDirectory path
|
contents <- listDirectory path
|
||||||
pure $ filter (match regex) contents
|
pure $ filter (match regex) contents
|
||||||
|
|
||||||
|
findFilesDeep :: FilePath -> Regex -> IO [FilePath]
|
||||||
|
findFilesDeep path regex = do
|
||||||
|
contents <- getDirectoryContentsRecursive path
|
||||||
|
pure $ filter (match regex) contents
|
||||||
|
|
||||||
|
findFiles' :: FilePath -> MP.Parsec Void Text a -> IO [FilePath]
|
||||||
|
findFiles' path parser = do
|
||||||
|
contents <- listDirectory path
|
||||||
|
pure $ filter (\fp -> either (const False) (const True) $ MP.parse parser "" (T.pack fp)) contents
|
||||||
|
|
||||||
|
|
||||||
checkFileAlreadyExists :: (MonadIO m) => FilePath -> m Bool
|
checkFileAlreadyExists :: (MonadIO m) => FilePath -> m Bool
|
||||||
checkFileAlreadyExists fp = liftIO $ doesFileExist fp
|
checkFileAlreadyExists fp = liftIO $ doesFileExist fp
|
||||||
|
|||||||
5
lib/GHCup/Utils/File/Common.hs-boot
Normal file
5
lib/GHCup/Utils/File/Common.hs-boot
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module GHCup.Utils.File.Common where
|
||||||
|
|
||||||
|
import Text.Regex.Posix
|
||||||
|
|
||||||
|
findFiles :: FilePath -> Regex -> IO [FilePath]
|
||||||
@@ -17,6 +17,7 @@ module GHCup.Utils.File.Posix where
|
|||||||
|
|
||||||
import GHCup.Utils.File.Common
|
import GHCup.Utils.File.Common
|
||||||
import GHCup.Utils.Prelude
|
import GHCup.Utils.Prelude
|
||||||
|
import GHCup.Utils.Logger
|
||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
import GHCup.Types.Optics
|
import GHCup.Types.Optics
|
||||||
|
|
||||||
@@ -34,8 +35,7 @@ import Data.Sequence ( Seq, (|>) )
|
|||||||
import Data.List
|
import Data.List
|
||||||
import Data.Word8
|
import Data.Word8
|
||||||
import GHC.IO.Exception
|
import GHC.IO.Exception
|
||||||
import System.Console.Pretty hiding ( Pretty )
|
import System.Console.Terminal.Common
|
||||||
import System.Console.Regions
|
|
||||||
import System.IO.Error
|
import System.IO.Error
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
import System.Directory
|
import System.Directory
|
||||||
@@ -51,6 +51,7 @@ import qualified Data.Sequence as Sq
|
|||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Encoding as E
|
import qualified Data.Text.Encoding as E
|
||||||
import qualified System.Posix.Process as SPP
|
import qualified System.Posix.Process as SPP
|
||||||
|
import qualified System.Console.Terminal.Posix as TP
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import qualified Data.ByteString.Lazy as BL
|
import qualified Data.ByteString.Lazy as BL
|
||||||
import qualified "unix-bytestring" System.Posix.IO.ByteString
|
import qualified "unix-bytestring" System.Posix.IO.ByteString
|
||||||
@@ -87,9 +88,9 @@ execLogged exe args chdir lfile env = do
|
|||||||
let logfile = logsDir </> lfile <> ".log"
|
let logfile = logsDir </> lfile <> ".log"
|
||||||
liftIO $ bracket (openFd logfile WriteOnly (Just newFilePerms) defaultFileFlags{ append = True })
|
liftIO $ bracket (openFd logfile WriteOnly (Just newFilePerms) defaultFileFlags{ append = True })
|
||||||
closeFd
|
closeFd
|
||||||
(action verbose)
|
(action verbose noColor)
|
||||||
where
|
where
|
||||||
action verbose fd = do
|
action verbose no_color fd = do
|
||||||
actionWithPipes $ \(stdoutRead, stdoutWrite) -> do
|
actionWithPipes $ \(stdoutRead, stdoutWrite) -> do
|
||||||
-- start the thread that logs to stdout
|
-- start the thread that logs to stdout
|
||||||
pState <- newEmptyMVar
|
pState <- newEmptyMVar
|
||||||
@@ -100,7 +101,7 @@ execLogged exe args chdir lfile env = do
|
|||||||
$ EX.finally
|
$ EX.finally
|
||||||
(if verbose
|
(if verbose
|
||||||
then tee fd stdoutRead
|
then tee fd stdoutRead
|
||||||
else printToRegion fd stdoutRead 6 pState
|
else printToRegion fd stdoutRead 6 pState no_color
|
||||||
)
|
)
|
||||||
(putMVar done ())
|
(putMVar done ())
|
||||||
|
|
||||||
@@ -137,44 +138,55 @@ execLogged exe args chdir lfile env = do
|
|||||||
|
|
||||||
-- Reads fdIn and logs the output in a continous scrolling area
|
-- Reads fdIn and logs the output in a continous scrolling area
|
||||||
-- of 'size' terminal lines. Also writes to a log file.
|
-- of 'size' terminal lines. Also writes to a log file.
|
||||||
printToRegion :: Fd -> Fd -> Int -> MVar Bool -> IO ()
|
printToRegion :: Fd -> Fd -> Int -> MVar Bool -> Bool -> IO ()
|
||||||
printToRegion fileFd fdIn size pState = do
|
printToRegion fileFd fdIn size pState no_color = do
|
||||||
void $ displayConsoleRegions $ do
|
-- init region
|
||||||
rs <-
|
forM_ [1..size] $ \_ -> BS.putStr "\n"
|
||||||
liftIO
|
|
||||||
. fmap Sq.fromList
|
void $ flip runStateT mempty
|
||||||
. sequence
|
$ do
|
||||||
. replicate size
|
handle
|
||||||
. openConsoleRegion
|
|
||||||
$ Linear
|
|
||||||
flip runStateT mempty
|
|
||||||
$ handle
|
|
||||||
(\(ex :: SomeException) -> do
|
(\(ex :: SomeException) -> do
|
||||||
ps <- liftIO $ takeMVar pState
|
ps <- liftIO $ takeMVar pState
|
||||||
when ps (forM_ rs (liftIO . closeConsoleRegion))
|
when ps (liftIO $ BS.putStr (pos1 <> moveLineUp size <> clearScreen))
|
||||||
throw ex
|
throw ex
|
||||||
)
|
) $ readTilEOF lineAction fdIn
|
||||||
$ readTilEOF (lineAction rs) fdIn
|
|
||||||
|
|
||||||
where
|
where
|
||||||
|
clearScreen :: ByteString
|
||||||
|
clearScreen = "\x1b[0J"
|
||||||
|
clearLine :: ByteString
|
||||||
|
clearLine = "\x1b[2K"
|
||||||
|
moveLineUp :: Int -> ByteString
|
||||||
|
moveLineUp n = "\x1b[" <> E.encodeUtf8 (T.pack (show n)) <> "A"
|
||||||
|
moveLineDown :: Int -> ByteString
|
||||||
|
moveLineDown n = "\x1b[" <> E.encodeUtf8 (T.pack (show n)) <> "B"
|
||||||
|
pos1 :: ByteString
|
||||||
|
pos1 = "\r"
|
||||||
|
overwriteNthLine :: Int -> ByteString -> ByteString
|
||||||
|
overwriteNthLine n str = pos1 <> moveLineUp n <> clearLine <> str <> moveLineDown n <> pos1
|
||||||
|
|
||||||
|
blue :: ByteString -> ByteString
|
||||||
|
blue bs
|
||||||
|
| no_color = bs
|
||||||
|
| otherwise = "\x1b[0;34m" <> bs <> "\x1b[0m"
|
||||||
|
|
||||||
-- action to perform line by line
|
-- action to perform line by line
|
||||||
-- TODO: do this with vty for efficiency
|
|
||||||
lineAction :: (MonadMask m, MonadIO m)
|
lineAction :: (MonadMask m, MonadIO m)
|
||||||
=> Seq ConsoleRegion
|
=> ByteString
|
||||||
-> ByteString
|
|
||||||
-> StateT (Seq ByteString) m ()
|
-> StateT (Seq ByteString) m ()
|
||||||
lineAction rs = \bs' -> do
|
lineAction = \bs' -> do
|
||||||
void $ liftIO $ SPIB.fdWrite fileFd (bs' <> "\n")
|
void $ liftIO $ SPIB.fdWrite fileFd (bs' <> "\n")
|
||||||
modify (swapRegs bs')
|
modify (swapRegs bs')
|
||||||
|
liftIO TP.size >>= \case
|
||||||
|
Nothing -> pure ()
|
||||||
|
Just (Window _ w) -> do
|
||||||
regs <- get
|
regs <- get
|
||||||
liftIO $ forM_ (Sq.zip regs rs) $ \(bs, r) -> setConsoleRegion r $ do
|
liftIO $ forM_ (Sq.zip regs (Sq.fromList [0..(Sq.length regs - 1)])) $ \(bs, i) -> do
|
||||||
w <- consoleWidth
|
BS.putStr
|
||||||
return
|
. overwriteNthLine (size - i)
|
||||||
. T.pack
|
|
||||||
. color Blue
|
|
||||||
. T.unpack
|
|
||||||
. decUTF8Safe
|
|
||||||
. trim w
|
. trim w
|
||||||
|
. blue
|
||||||
. (\b -> "[ " <> E.encodeUtf8 (T.pack lfile) <> " ] " <> b)
|
. (\b -> "[ " <> E.encodeUtf8 (T.pack lfile) <> " ] " <> b)
|
||||||
$ bs
|
$ bs
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE QuasiQuotes #-}
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
Module : GHCup.Utils.Logger
|
Module : GHCup.Utils.Logger
|
||||||
@@ -16,21 +18,97 @@ module GHCup.Utils.Logger where
|
|||||||
|
|
||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
import GHCup.Types.Optics
|
import GHCup.Types.Optics
|
||||||
import GHCup.Utils.File
|
import {-# SOURCE #-} GHCup.Utils.File.Common
|
||||||
import GHCup.Utils.String.QQ
|
import GHCup.Utils.String.QQ
|
||||||
|
|
||||||
import Control.Exception.Safe
|
import Control.Exception.Safe
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.IO.Class
|
import Control.Monad.IO.Class
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
|
import Data.Text ( Text )
|
||||||
|
import Optics
|
||||||
import Prelude hiding ( appendFile )
|
import Prelude hiding ( appendFile )
|
||||||
|
import System.Console.Pretty
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
import System.IO.Error
|
import System.IO.Error
|
||||||
import Text.Regex.Posix
|
import Text.Regex.Posix
|
||||||
|
|
||||||
import qualified Data.ByteString as B
|
import qualified Data.ByteString as B
|
||||||
import GHCup.Utils.Prelude
|
import GHCup.Utils.Prelude
|
||||||
|
import qualified Data.Text as T
|
||||||
|
|
||||||
|
logInfo :: ( MonadReader env m
|
||||||
|
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
||||||
|
, MonadIO m
|
||||||
|
)
|
||||||
|
=> Text
|
||||||
|
-> m ()
|
||||||
|
logInfo = logInternal Info
|
||||||
|
|
||||||
|
logWarn :: ( MonadReader env m
|
||||||
|
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
||||||
|
, MonadIO m
|
||||||
|
)
|
||||||
|
=> Text
|
||||||
|
-> m ()
|
||||||
|
logWarn = logInternal Warn
|
||||||
|
|
||||||
|
logDebug :: ( MonadReader env m
|
||||||
|
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
||||||
|
, MonadIO m
|
||||||
|
)
|
||||||
|
=> Text
|
||||||
|
-> m ()
|
||||||
|
logDebug = logInternal Debug
|
||||||
|
|
||||||
|
logError :: ( MonadReader env m
|
||||||
|
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
||||||
|
, MonadIO m
|
||||||
|
)
|
||||||
|
=> Text
|
||||||
|
-> m ()
|
||||||
|
logError = logInternal Error
|
||||||
|
|
||||||
|
|
||||||
|
logInternal :: ( MonadReader env m
|
||||||
|
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
||||||
|
, MonadIO m
|
||||||
|
) => LogLevel
|
||||||
|
-> Text
|
||||||
|
-> m ()
|
||||||
|
logInternal logLevel msg = do
|
||||||
|
LoggerConfig {..} <- gets @"loggerConfig"
|
||||||
|
let color' c = if fancyColors then color c else id
|
||||||
|
let style' = case logLevel of
|
||||||
|
Debug -> style Bold . color' Blue
|
||||||
|
Info -> style Bold . color' Green
|
||||||
|
Warn -> style Bold . color' Yellow
|
||||||
|
Error -> style Bold . color' Red
|
||||||
|
let l = case logLevel of
|
||||||
|
Debug -> style' "[ Debug ]"
|
||||||
|
Info -> style' "[ Info ]"
|
||||||
|
Warn -> style' "[ Warn ]"
|
||||||
|
Error -> style' "[ Error ]"
|
||||||
|
let strs = T.split (== '\n') msg
|
||||||
|
let out = case strs of
|
||||||
|
[] -> T.empty
|
||||||
|
(x:xs) ->
|
||||||
|
foldr (\a b -> a <> "\n" <> b) mempty
|
||||||
|
. ((l <> " " <> x) :)
|
||||||
|
. fmap (\line' -> style' "[ ... ] " <> line' )
|
||||||
|
$ xs
|
||||||
|
|
||||||
|
when (lcPrintDebug || (not lcPrintDebug && (logLevel /= Debug)))
|
||||||
|
$ liftIO $ consoleOutter out
|
||||||
|
|
||||||
|
-- raw output
|
||||||
|
let lr = case logLevel of
|
||||||
|
Debug -> "Debug:"
|
||||||
|
Info -> "Info:"
|
||||||
|
Warn -> "Warn:"
|
||||||
|
Error -> "Error:"
|
||||||
|
let outr = lr <> " " <> msg <> "\n"
|
||||||
|
liftIO $ fileOutter outr
|
||||||
|
|
||||||
|
|
||||||
initGHCupFileLogging :: ( MonadReader env m
|
initGHCupFileLogging :: ( MonadReader env m
|
||||||
|
|||||||
21
lib/GHCup/Utils/Logger.hs-boot
Normal file
21
lib/GHCup/Utils/Logger.hs-boot
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
|
module GHCup.Utils.Logger where
|
||||||
|
|
||||||
|
import GHCup.Types
|
||||||
|
|
||||||
|
import Control.Monad.IO.Class
|
||||||
|
import Control.Monad.Reader
|
||||||
|
import Data.Text ( Text )
|
||||||
|
import Optics
|
||||||
|
|
||||||
|
logWarn :: ( MonadReader env m
|
||||||
|
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
||||||
|
, MonadIO m
|
||||||
|
)
|
||||||
|
=> Text
|
||||||
|
-> m ()
|
||||||
|
|
||||||
@@ -22,7 +22,9 @@ module GHCup.Utils.Prelude where
|
|||||||
#if defined(IS_WINDOWS)
|
#if defined(IS_WINDOWS)
|
||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
#endif
|
#endif
|
||||||
|
import GHCup.Errors
|
||||||
import GHCup.Types.Optics
|
import GHCup.Types.Optics
|
||||||
|
import {-# SOURCE #-} GHCup.Utils.Logger
|
||||||
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import Control.Exception.Safe
|
import Control.Exception.Safe
|
||||||
@@ -31,13 +33,14 @@ import Control.Monad.IO.Class
|
|||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Data.Bifunctor
|
import Data.Bifunctor
|
||||||
import Data.ByteString ( ByteString )
|
import Data.ByteString ( ByteString )
|
||||||
import Data.List ( nub, intercalate, stripPrefix, isPrefixOf )
|
import Data.List ( nub, intercalate, stripPrefix, isPrefixOf, dropWhileEnd )
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
|
import Data.List.NonEmpty ( NonEmpty( (:|) ))
|
||||||
import Data.String
|
import Data.String
|
||||||
import Data.Text ( Text )
|
import Data.Text ( Text )
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
import Data.Word8
|
import Data.Word8 hiding ( isDigit )
|
||||||
import Haskus.Utils.Types.List
|
import Haskus.Utils.Types.List
|
||||||
import Haskus.Utils.Variant.Excepts
|
import Haskus.Utils.Variant.Excepts
|
||||||
import Text.PrettyPrint.HughesPJClass ( prettyShow, Pretty )
|
import Text.PrettyPrint.HughesPJClass ( prettyShow, Pretty )
|
||||||
@@ -58,6 +61,7 @@ import qualified Data.ByteString as B
|
|||||||
import qualified Data.ByteString.Lazy as L
|
import qualified Data.ByteString.Lazy as L
|
||||||
import qualified Data.Strict.Maybe as S
|
import qualified Data.Strict.Maybe as S
|
||||||
import qualified Data.List.Split as Split
|
import qualified Data.List.Split as Split
|
||||||
|
import qualified Data.List.NonEmpty as NE
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Encoding as E
|
import qualified Data.Text.Encoding as E
|
||||||
import qualified Data.Text.Encoding.Error as E
|
import qualified Data.Text.Encoding.Error as E
|
||||||
@@ -295,12 +299,28 @@ removeLensFieldLabel str' =
|
|||||||
maybe str' T.unpack . T.stripPrefix (T.pack "_") . T.pack $ str'
|
maybe str' T.unpack . T.stripPrefix (T.pack "_") . T.pack $ str'
|
||||||
|
|
||||||
|
|
||||||
pvpToVersion :: PVP -> Version
|
pvpToVersion :: MonadThrow m => PVP -> m Version
|
||||||
pvpToVersion =
|
pvpToVersion =
|
||||||
either (\_ -> error "Couldn't convert PVP to Version") id
|
either (\_ -> throwM $ ParseError "Couldn't convert PVP to Version") pure . version . prettyPVP
|
||||||
. version
|
|
||||||
. prettyPVP
|
|
||||||
|
|
||||||
|
versionToPVP :: MonadThrow m => Version -> m PVP
|
||||||
|
versionToPVP v = either (\_ -> alternative v) pure . pvp . prettyVer $ v
|
||||||
|
where
|
||||||
|
alternative :: MonadThrow m => Version -> m PVP
|
||||||
|
alternative v' = case NE.takeWhile isDigit (_vChunks v') of
|
||||||
|
[] -> throwM $ ParseError "Couldn't convert Version to PVP"
|
||||||
|
xs -> pure $ pvpFromList (unsafeDigit <$> xs)
|
||||||
|
|
||||||
|
isDigit :: VChunk -> Bool
|
||||||
|
isDigit (Digits _ :| []) = True
|
||||||
|
isDigit _ = False
|
||||||
|
|
||||||
|
unsafeDigit :: VChunk -> Int
|
||||||
|
unsafeDigit (Digits x :| []) = fromIntegral x
|
||||||
|
unsafeDigit _ = error "unsafeDigit: wrong input"
|
||||||
|
|
||||||
|
pvpFromList :: [Int] -> PVP
|
||||||
|
pvpFromList = PVP . NE.fromList . fmap fromIntegral
|
||||||
|
|
||||||
-- | Safe 'decodeUtf8With'. Replaces an invalid input byte with
|
-- | Safe 'decodeUtf8With'. Replaces an invalid input byte with
|
||||||
-- the Unicode replacement character U+FFFD.
|
-- the Unicode replacement character U+FFFD.
|
||||||
@@ -508,6 +528,10 @@ recover action =
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
copyFileE :: (CopyError :< xs, MonadCatch m, MonadIO m) => FilePath -> FilePath -> Excepts xs m ()
|
||||||
|
copyFileE from = handleIO (throwE . CopyError . show) . liftIO . copyFile from
|
||||||
|
|
||||||
|
|
||||||
-- | Gathering monoidal values
|
-- | Gathering monoidal values
|
||||||
--
|
--
|
||||||
-- >>> traverseFold (pure . (:["0"])) ["1","2"]
|
-- >>> traverseFold (pure . (:["0"])) ["1","2"]
|
||||||
@@ -528,6 +552,8 @@ forFold = \t -> (`traverseFold` t)
|
|||||||
--
|
--
|
||||||
-- >>> stripNewline "foo\n\n\n"
|
-- >>> stripNewline "foo\n\n\n"
|
||||||
-- "foo"
|
-- "foo"
|
||||||
|
-- >>> stripNewline "foo\n\n\nfoo"
|
||||||
|
-- "foofoo"
|
||||||
-- >>> stripNewline "foo\r"
|
-- >>> stripNewline "foo\r"
|
||||||
-- "foo"
|
-- "foo"
|
||||||
-- >>> stripNewline "foo"
|
-- >>> stripNewline "foo"
|
||||||
@@ -539,10 +565,29 @@ stripNewline :: String -> String
|
|||||||
stripNewline = filter (`notElem` "\n\r")
|
stripNewline = filter (`notElem` "\n\r")
|
||||||
|
|
||||||
|
|
||||||
|
-- | Strip @\\r@ and @\\n@ from end of 'String'.
|
||||||
|
--
|
||||||
|
-- >>> stripNewlineEnd "foo\n\n\n"
|
||||||
|
-- "foo"
|
||||||
|
-- >>> stripNewlineEnd "foo\n\n\nfoo"
|
||||||
|
-- "foo\n\n\nfoo"
|
||||||
|
-- >>> stripNewlineEnd "foo\r"
|
||||||
|
-- "foo"
|
||||||
|
-- >>> stripNewlineEnd "foo"
|
||||||
|
-- "foo"
|
||||||
|
--
|
||||||
|
-- prop> \t -> stripNewlineEnd (t <> "\n") === stripNewlineEnd t
|
||||||
|
-- prop> \t -> not (any (isNewLine . c2w) t) ==> stripNewlineEnd t == t
|
||||||
|
stripNewlineEnd :: String -> String
|
||||||
|
stripNewlineEnd = dropWhileEnd (`elem` "\n\r")
|
||||||
|
|
||||||
|
|
||||||
-- | Strip @\\r@ and @\\n@ from 'Text's
|
-- | Strip @\\r@ and @\\n@ from 'Text's
|
||||||
--
|
--
|
||||||
-- >>> stripNewline' "foo\n\n\n"
|
-- >>> stripNewline' "foo\n\n\n"
|
||||||
-- "foo"
|
-- "foo"
|
||||||
|
-- >>> stripNewline' "foo\n\n\nfoo"
|
||||||
|
-- "foofoo"
|
||||||
-- >>> stripNewline' "foo\r"
|
-- >>> stripNewline' "foo\r"
|
||||||
-- "foo"
|
-- "foo"
|
||||||
-- >>> stripNewline' "foo"
|
-- >>> stripNewline' "foo"
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import qualified Data.Text as T
|
|||||||
-- Note that when updating this, CI requires that the file exsists AND the same file exists at
|
-- Note that when updating this, CI requires that the file exsists AND the same file exists at
|
||||||
-- 'https://www.haskell.org/ghcup/exp/ghcup-<ver>.yaml' with some newlines added.
|
-- 'https://www.haskell.org/ghcup/exp/ghcup-<ver>.yaml' with some newlines added.
|
||||||
ghcupURL :: URI
|
ghcupURL :: URI
|
||||||
ghcupURL = [uri|https://www.haskell.org/ghcup/data/ghcup-0.0.7.yaml|]
|
ghcupURL = [uri|https://www.haskell.org/ghcup/data/ghcup-0.0.6.yaml|]
|
||||||
|
|
||||||
-- | The current ghcup version.
|
-- | The current ghcup version.
|
||||||
ghcUpVer :: PVP
|
ghcUpVer :: PVP
|
||||||
|
|||||||
43
lib/System/Console/Terminal/Common.hs
Normal file
43
lib/System/Console/Terminal/Common.hs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{-# LANGUAGE CPP #-}
|
||||||
|
{-# LANGUAGE DeriveDataTypeable #-}
|
||||||
|
{-# LANGUAGE DeriveTraversable #-}
|
||||||
|
|
||||||
|
#if __GLASGOW_HASKELL__ >= 702
|
||||||
|
#define LANGUAGE_DeriveGeneric
|
||||||
|
{-# LANGUAGE DeriveGeneric #-}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
module System.Console.Terminal.Common
|
||||||
|
( Window(..)
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.Data (Typeable, Data)
|
||||||
|
|
||||||
|
#if __GLASGOW_HASKELL__ < 710
|
||||||
|
import Data.Foldable (Foldable)
|
||||||
|
import Data.Traversable (Traversable)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef LANGUAGE_DeriveGeneric
|
||||||
|
import GHC.Generics
|
||||||
|
( Generic
|
||||||
|
#if __GLASGOW_HASKELL__ >= 706
|
||||||
|
, Generic1
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-- | Terminal window width and height
|
||||||
|
data Window a = Window
|
||||||
|
{ height :: !a
|
||||||
|
, width :: !a
|
||||||
|
} deriving
|
||||||
|
( Show, Eq, Read, Data, Typeable
|
||||||
|
, Foldable, Functor, Traversable
|
||||||
|
#ifdef LANGUAGE_DeriveGeneric
|
||||||
|
, Generic
|
||||||
|
#if __GLASGOW_HASKELL__ >= 706
|
||||||
|
, Generic1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
)
|
||||||
65
lib/System/Console/Terminal/Posix.hsc
Normal file
65
lib/System/Console/Terminal/Posix.hsc
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
{-# LANGUAGE CApiFFI #-}
|
||||||
|
|
||||||
|
module System.Console.Terminal.Posix
|
||||||
|
( size, fdSize, hSize
|
||||||
|
) where
|
||||||
|
|
||||||
|
import System.Console.Terminal.Common
|
||||||
|
import Control.Exception (catch)
|
||||||
|
import Data.Typeable (cast)
|
||||||
|
import Foreign
|
||||||
|
import Foreign.C.Error
|
||||||
|
import Foreign.C.Types
|
||||||
|
import GHC.IO.FD (FD(FD, fdFD))
|
||||||
|
import GHC.IO.Handle.Internals (withHandle_)
|
||||||
|
import GHC.IO.Handle.Types (Handle, Handle__(Handle__, haDevice))
|
||||||
|
#if defined(__GLASGOW_HASKELL__) && (__GLASGOW_HASKELL__ < 706)
|
||||||
|
import Prelude hiding (catch)
|
||||||
|
#endif
|
||||||
|
import System.Posix.Types (Fd(Fd))
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
#let alignment t = "%lu", (unsigned long)offsetof(struct {char x__; t (y__); }, y__)
|
||||||
|
|
||||||
|
|
||||||
|
-- Interesting part of @struct winsize@
|
||||||
|
data CWin = CWin CUShort CUShort
|
||||||
|
|
||||||
|
instance Storable CWin where
|
||||||
|
sizeOf _ = (#size struct winsize)
|
||||||
|
alignment _ = (#alignment struct winsize)
|
||||||
|
peek ptr = do
|
||||||
|
row <- (#peek struct winsize, ws_row) ptr
|
||||||
|
col <- (#peek struct winsize, ws_col) ptr
|
||||||
|
return $ CWin row col
|
||||||
|
poke ptr (CWin row col) = do
|
||||||
|
(#poke struct winsize, ws_row) ptr row
|
||||||
|
(#poke struct winsize, ws_col) ptr col
|
||||||
|
|
||||||
|
|
||||||
|
fdSize :: Integral n => Fd -> IO (Maybe (Window n))
|
||||||
|
fdSize (Fd fd) = with (CWin 0 0) $ \ws -> do
|
||||||
|
_ <- throwErrnoIfMinus1 "ioctl" $
|
||||||
|
ioctl fd (#const TIOCGWINSZ) ws
|
||||||
|
CWin row col <- peek ws
|
||||||
|
return . Just $ Window (fromIntegral row) (fromIntegral col)
|
||||||
|
`catch`
|
||||||
|
handler
|
||||||
|
where
|
||||||
|
handler :: IOError -> IO (Maybe (Window h))
|
||||||
|
handler _ = return Nothing
|
||||||
|
|
||||||
|
foreign import capi "sys/ioctl.h ioctl"
|
||||||
|
ioctl :: CInt -> CULong -> Ptr CWin -> IO CInt
|
||||||
|
|
||||||
|
size :: Integral n => IO (Maybe (Window n))
|
||||||
|
size = fdSize (Fd (#const STDOUT_FILENO))
|
||||||
|
|
||||||
|
hSize :: Integral n => Handle -> IO (Maybe (Window n))
|
||||||
|
hSize h = withHandle_ "hSize" h $ \Handle__ { haDevice = dev } ->
|
||||||
|
case cast dev of
|
||||||
|
Nothing -> return Nothing
|
||||||
|
Just FD { fdFD = fd } -> fdSize (Fd fd)
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
plat="$(uname -s)"
|
plat="$(uname -s)"
|
||||||
arch=$(uname -m)
|
arch=$(uname -m)
|
||||||
ghver="0.1.16.2"
|
ghver="0.1.17"
|
||||||
base_url="https://downloads.haskell.org/~ghcup"
|
base_url="https://downloads.haskell.org/~ghcup"
|
||||||
|
|
||||||
export GHCUP_SKIP_UPDATE_CHECK=yes
|
export GHCUP_SKIP_UPDATE_CHECK=yes
|
||||||
@@ -52,11 +52,18 @@ esac
|
|||||||
|
|
||||||
|
|
||||||
die() {
|
die() {
|
||||||
|
if [ -n "${NO_COLOR}" ] ; then
|
||||||
|
(>&2 printf "%s\\n" "$1")
|
||||||
|
else
|
||||||
(>&2 printf "\\033[0;31m%s\\033[0m\\n" "$1")
|
(>&2 printf "\\033[0;31m%s\\033[0m\\n" "$1")
|
||||||
|
fi
|
||||||
exit 2
|
exit 2
|
||||||
}
|
}
|
||||||
|
|
||||||
warn() {
|
warn() {
|
||||||
|
if [ -n "${NO_COLOR}" ] ; then
|
||||||
|
printf "%s\\n" "$1"
|
||||||
|
else
|
||||||
case "${plat}" in
|
case "${plat}" in
|
||||||
MSYS*|MINGW*)
|
MSYS*|MINGW*)
|
||||||
echo -e "\\033[0;35m$1\\033[0m"
|
echo -e "\\033[0;35m$1\\033[0m"
|
||||||
@@ -65,9 +72,13 @@ warn() {
|
|||||||
printf "\\033[0;35m%s\\033[0m\\n" "$1"
|
printf "\\033[0;35m%s\\033[0m\\n" "$1"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
yellow() {
|
yellow() {
|
||||||
|
if [ -n "${NO_COLOR}" ] ; then
|
||||||
|
printf "%s\\n" "$1"
|
||||||
|
else
|
||||||
case "${plat}" in
|
case "${plat}" in
|
||||||
MSYS*|MINGW*)
|
MSYS*|MINGW*)
|
||||||
echo -e "\\033[0;33m$1\\033[0m"
|
echo -e "\\033[0;33m$1\\033[0m"
|
||||||
@@ -76,9 +87,13 @@ yellow() {
|
|||||||
printf "\\033[0;33m%s\\033[0m\\n" "$1"
|
printf "\\033[0;33m%s\\033[0m\\n" "$1"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
green() {
|
green() {
|
||||||
|
if [ -n "${NO_COLOR}" ] ; then
|
||||||
|
printf "%s\\n" "$1"
|
||||||
|
else
|
||||||
case "${plat}" in
|
case "${plat}" in
|
||||||
MSYS*|MINGW*)
|
MSYS*|MINGW*)
|
||||||
echo -e "\\033[0;32m$1\\033[0m"
|
echo -e "\\033[0;32m$1\\033[0m"
|
||||||
@@ -87,6 +102,7 @@ green() {
|
|||||||
printf "\\033[0;32m%s\\033[0m\\n" "$1"
|
printf "\\033[0;32m%s\\033[0m\\n" "$1"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
edo() {
|
edo() {
|
||||||
@@ -405,7 +421,7 @@ warn_path() {
|
|||||||
echo
|
echo
|
||||||
[ -n "$1" ] && warn "$1"
|
[ -n "$1" ] && warn "$1"
|
||||||
yellow "In order to run ghc and cabal, you need to adjust your PATH variable."
|
yellow "In order to run ghc and cabal, you need to adjust your PATH variable."
|
||||||
yellow "To do so, you may want run 'source $GHCUP_DIR/env' in your current terminal"
|
yellow "To do so, you may want to run 'source $GHCUP_DIR/env' in your current terminal"
|
||||||
yellow "session as well as your shell configuration (e.g. ~/.bashrc)."
|
yellow "session as well as your shell configuration (e.g. ~/.bashrc)."
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -677,4 +693,3 @@ _done
|
|||||||
)
|
)
|
||||||
|
|
||||||
# vim: tabstop=4 shiftwidth=4 expandtab
|
# vim: tabstop=4 shiftwidth=4 expandtab
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,6 @@ packages:
|
|||||||
- .
|
- .
|
||||||
|
|
||||||
extra-deps:
|
extra-deps:
|
||||||
- git: https://github.com/bgamari/terminal-size
|
|
||||||
commit: 34ea816bd63f75f800eedac12c6908c6f3736036
|
|
||||||
|
|
||||||
- git: https://github.com/hasufell/libarchive
|
- git: https://github.com/hasufell/libarchive
|
||||||
commit: 8587aab78dd515928024ecd82c8f215e06db85cd
|
commit: 8587aab78dd515928024ecd82c8f215e06db85cd
|
||||||
|
|
||||||
|
|||||||
@@ -174,7 +174,17 @@ span.code {
|
|||||||
line-height: 2rem;
|
line-height: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#help {
|
||||||
|
margin-bottom: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#collective {
|
||||||
|
margin-top: 1em !important;
|
||||||
|
margin-bottom: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
#about {
|
#about {
|
||||||
|
margin-top: 0.5em !important;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 2em;
|
line-height: 2em;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,9 +137,14 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>
|
<p id="help">
|
||||||
Need help? Ask on <a href="https://kiwiirc.com/nextclient/irc.libera.chat/?nick=Guest%7C?#haskell,#haskell-ghcup"><img src="irc.svg" height="18px" alt="" />IRC</a>, <a href="https://discord.gg/pKYf3zDQU7"><img src="Discord-Logo-Black.svg" height="18px" alt="" />Discord</a>, <a href="https://app.element.io/#/room/#haskell-tooling:matrix.org"><img src="Matrix_logo.svg" height="25px" alt="" style="top:5px;position:relative;" /></a> or <a href="https://gitlab.haskell.org/haskell/ghcup-hs/issues">report a bug <img src="Octicons-bug.svg" height="18px" alt="" /></a>.
|
Need help? Ask on <a href="https://kiwiirc.com/nextclient/irc.libera.chat/?nick=Guest%7C?#haskell,#haskell-ghcup"><img src="irc.svg" height="18px" alt="" />IRC</a>, <a href="https://discord.gg/pKYf3zDQU7"><img src="Discord-Logo-Black.svg" height="18px" alt="" />Discord</a>, <a href="https://app.element.io/#/room/#haskell-tooling:matrix.org"><img src="Matrix_logo.svg" height="25px" alt="" style="top:5px;position:relative;" /></a> or <a href="https://gitlab.haskell.org/haskell/ghcup-hs/issues">report a bug <img src="Octicons-bug.svg" height="18px" alt="" /></a>.
|
||||||
</p>
|
</p>
|
||||||
|
<p id="collective">
|
||||||
|
<a id="collective" href="https://opencollective.com/ghcup#category-CONTRIBUTE" target="_blank">
|
||||||
|
<img src="https://opencollective.com/webpack/donate/button@2x.png?color=blue" width=200 />
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
<p id="about">
|
<p id="about">
|
||||||
<img src="haskell-logo.svg" alt="" />
|
<img src="haskell-logo.svg" alt="" />
|
||||||
|
|||||||
Reference in New Issue
Block a user