Compare commits
149 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
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 | ||
|
bbd11bfa26
|
|||
|
75548fa02d
|
|||
|
fb6956009f
|
|||
|
e029117c3e
|
|||
|
bc7c01de90
|
|||
|
cfcd8a4c20
|
|||
|
5e17eb7ca7
|
|||
|
|
756727ffe2 | ||
|
6bc602dead
|
|||
|
056c79e813
|
|||
|
68bbf31a86
|
|||
|
b58f380e75
|
|||
|
48c54bf374
|
|||
|
51da1578f4
|
|||
|
|
488f25aed6 | ||
|
|
d60f58cf43 | ||
|
|
7a6a119829 | ||
|
|
f0fb019c70 | ||
|
|
0f98ec6b78 | ||
|
|
107fed6e60 | ||
|
|
59a9a770a5 | ||
|
|
20bcb26e3d | ||
|
d355c46250
|
|||
|
787c927de6
|
|||
|
d15ff7bc67
|
|||
|
7c5c35f1b0
|
|||
|
001b090bc6
|
|||
|
db8207f8b9
|
|||
|
e5918de7af
|
|||
|
d2346a543a
|
|||
|
c057b4ae5c
|
|||
|
b962bf4af9
|
|||
|
c54dc05d92
|
|||
|
8c72bf697e
|
|||
|
cc8cf3d12a
|
|||
|
9bdf6bde17
|
|||
|
8363495843
|
|||
|
bc80b1048f
|
|||
|
d61981bc1b
|
|||
|
4ccdc5dd6c
|
|||
|
3240118226
|
|||
|
254989d63d
|
|||
|
283f2a6e46
|
|||
|
94637dfbab
|
|||
|
3e26d7057c
|
|||
|
3f710112f3
|
|||
|
34df41b44a
|
|||
|
3897434ef0
|
|||
|
375dba9dd1
|
|||
|
2edd1fb583
|
|||
|
11326060fb
|
|||
|
d343c01737
|
|||
|
3925f78721
|
|||
|
d98e54a743
|
|||
|
13143b8e4d
|
|||
|
3a7895e5ea
|
|||
|
2893b2e2d2
|
|||
|
987436fed2
|
|||
|
|
be82565775 | ||
|
|
f8d0243146 | ||
|
96ac66e909
|
|||
|
e5947f3490
|
|||
|
b35fe15703
|
|||
|
a269b60282
|
|||
|
fc6f7ffd73
|
|||
|
430dc2d20b
|
|||
|
77c464870f
|
|||
|
dda38ec52b
|
|||
|
|
f6b6b36eb7 | ||
|
|
3986677b06 | ||
|
1fb048777c
|
|||
|
e9c335eecc
|
|||
|
a7c7186aa4
|
|||
|
|
d7f82d643c | ||
|
|
15560a06b1 | ||
|
e38bd61066
|
|||
|
b086261c3c
|
|||
|
8c098d4e17
|
|||
|
e3a9c095c6
|
|||
|
678bdd7915
|
|||
|
14fc6b7281
|
|||
|
a2555cecc5
|
|||
|
9d6e469f79
|
|||
|
982c0a0fcf
|
|||
|
f8cfcd4038
|
|||
|
4d465efef1
|
|||
|
d667160027
|
|||
|
|
df55d972cf | ||
|
|
df758d828b | ||
|
7bc00c4e68
|
|||
|
|
8c486e8d46 |
@@ -14,7 +14,7 @@ variables:
|
|||||||
############################################################
|
############################################################
|
||||||
|
|
||||||
.debian:
|
.debian:
|
||||||
image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb9:$DOCKER_REV"
|
image: "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb10:$DOCKER_REV"
|
||||||
tags:
|
tags:
|
||||||
- x86_64-linux
|
- x86_64-linux
|
||||||
variables:
|
variables:
|
||||||
@@ -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,9 +76,17 @@ variables:
|
|||||||
ARCH: "ARM64"
|
ARCH: "ARM64"
|
||||||
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||||
|
|
||||||
.freebsd:
|
.freebsd13:
|
||||||
tags:
|
tags:
|
||||||
- x86_64-freebsd
|
- x86_64-freebsd13
|
||||||
|
variables:
|
||||||
|
OS: "FREEBSD"
|
||||||
|
ARCH: "64"
|
||||||
|
CABAL_DIR: "$CI_PROJECT_DIR/cabal"
|
||||||
|
|
||||||
|
.freebsd12:
|
||||||
|
tags:
|
||||||
|
- x86_64-freebsd12
|
||||||
variables:
|
variables:
|
||||||
OS: "FREEBSD"
|
OS: "FREEBSD"
|
||||||
ARCH: "64"
|
ARCH: "64"
|
||||||
@@ -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:
|
||||||
@@ -103,7 +113,7 @@ variables:
|
|||||||
artifacts:
|
artifacts:
|
||||||
expire_in: 2 week
|
expire_in: 2 week
|
||||||
paths:
|
paths:
|
||||||
- golden
|
- test/golden
|
||||||
- dist-newstyle/cache/
|
- dist-newstyle/cache/
|
||||||
when: on_failure
|
when: on_failure
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -240,7 +258,7 @@ test:linux:bootstrap_script:
|
|||||||
test:windows:bootstrap_powershell_script:
|
test:windows:bootstrap_powershell_script:
|
||||||
stage: test
|
stage: test
|
||||||
script:
|
script:
|
||||||
- ./bootstrap-haskell.ps1 -InstallDir $CI_PROJECT_DIR -BootstrapUrl $CI_PROJECT_DIR/bootstrap-haskell -InBash
|
- ./scripts/bootstrap/bootstrap-haskell.ps1 -InstallDir $CI_PROJECT_DIR -BootstrapUrl $CI_PROJECT_DIR/bootstrap-haskell -InBash
|
||||||
after_script:
|
after_script:
|
||||||
- "[Environment]::SetEnvironmentVariable('GHCUP_INSTALL_BASE_PREFIX', $null, [System.EnvironmentVariableTarget]::User)"
|
- "[Environment]::SetEnvironmentVariable('GHCUP_INSTALL_BASE_PREFIX', $null, [System.EnvironmentVariableTarget]::User)"
|
||||||
- "[Environment]::SetEnvironmentVariable('GHCUP_MSYS2', $null, [System.EnvironmentVariableTarget]::User)"
|
- "[Environment]::SetEnvironmentVariable('GHCUP_MSYS2', $null, [System.EnvironmentVariableTarget]::User)"
|
||||||
@@ -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:
|
||||||
@@ -527,15 +587,9 @@ release:windows:
|
|||||||
hlint:
|
hlint:
|
||||||
stage: hlint
|
stage: hlint
|
||||||
extends:
|
extends:
|
||||||
- .alpine:64bit
|
- .debian
|
||||||
before_script:
|
|
||||||
- ./.gitlab/before_script/linux/alpine/install_deps.sh
|
|
||||||
script:
|
script:
|
||||||
- ./.gitlab/script/hlint.sh
|
- curl -sSL https://raw.github.com/ndmitchell/hlint/master/misc/run.sh | sh -s -- -r lib/ test/
|
||||||
variables:
|
|
||||||
GHC_VERSION: "8.10.6"
|
|
||||||
CABAL_VERSION: "3.4.0.0"
|
|
||||||
JSON_VERSION: "0.0.4"
|
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
artifacts:
|
artifacts:
|
||||||
expire_in: 2 week
|
expire_in: 2 week
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ mkdir -p "${TMPDIR}"
|
|||||||
curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-portbld-freebsd-ghcup > ./ghcup-bin
|
curl -sSfL https://downloads.haskell.org/~ghcup/x86_64-portbld-freebsd-ghcup > ./ghcup-bin
|
||||||
chmod +x ghcup-bin
|
chmod +x ghcup-bin
|
||||||
|
|
||||||
./ghcup-bin upgrade -i -f
|
./ghcup-bin -v upgrade -i -f
|
||||||
./ghcup-bin install ${GHC_VERSION}
|
./ghcup-bin -v install ${GHC_VERSION}
|
||||||
./ghcup-bin set ${GHC_VERSION}
|
./ghcup-bin -v set ${GHC_VERSION}
|
||||||
./ghcup-bin install-cabal ${CABAL_VERSION}
|
./ghcup-bin -v install-cabal ${CABAL_VERSION}
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -52,3 +52,7 @@ apk add --no-cache \
|
|||||||
xz-dev \
|
xz-dev \
|
||||||
ncurses-static
|
ncurses-static
|
||||||
|
|
||||||
|
if [ "${ARCH}" = "32" ] ; then
|
||||||
|
apk add --no-cache \
|
||||||
|
bsd-compat-headers
|
||||||
|
fi
|
||||||
|
|||||||
@@ -7,67 +7,21 @@ set -eux
|
|||||||
mkdir -p "${TMPDIR}"
|
mkdir -p "${TMPDIR}"
|
||||||
|
|
||||||
sudo apt-get update -y
|
sudo apt-get update -y
|
||||||
sudo apt-get install -y libnuma-dev zlib1g-dev libgmp-dev libgmp10 libssl-dev liblzma-dev libbz2-dev git wget lsb-release software-properties-common gnupg2 apt-transport-https
|
sudo apt-get install -y 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
|
||||||
|
|
||||||
if [ "${CROSS}" = "arm-linux-gnueabihf" ] ; then
|
if [ "${CROSS}" = "arm-linux-gnueabihf" ] ; then
|
||||||
sudo apt-get install -y autoconf build-essential gcc-arm-linux-gnueabihf
|
sudo apt-get install -y gcc-arm-linux-gnueabihf
|
||||||
sudo dpkg --add-architecture armhf
|
sudo dpkg --add-architecture armhf
|
||||||
sudo apt-get update -y
|
sudo apt-get update -y
|
||||||
sudo apt-get install -y libncurses-dev:armhf
|
sudo apt-get install -y libncurses-dev:armhf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
case "${ARCH}" in
|
export BOOTSTRAP_HASKELL_NONINTERACTIVE=1
|
||||||
ARM*)
|
export BOOTSTRAP_HASKELL_GHC_VERSION=$GHC_VERSION
|
||||||
case "${ARCH}" in
|
export BOOTSTRAP_HASKELL_CABAL_VERSION=$CABAL_VERSION
|
||||||
"ARM")
|
export BOOTSTRAP_HASKELL_VERBOSE=1
|
||||||
ghc_url=https://downloads.haskell.org/~ghc/${GHC_VERSION}/ghc-${GHC_VERSION}-armv7-deb10-linux.tar.xz
|
|
||||||
cabal_url=home.smart-cactus.org/~ben/cabal-install-${CABAL_VERSION}-armv7-linux-bootstrapped.tar.xz
|
|
||||||
;;
|
|
||||||
"ARM64")
|
|
||||||
ghc_url=https://downloads.haskell.org/~ghc/${GHC_VERSION}/ghc-${GHC_VERSION}-aarch64-deb10-linux.tar.xz
|
|
||||||
cabal_url=https://downloads.haskell.org/~cabal/cabal-install-${CABAL_VERSION}/cabal-install-${CABAL_VERSION}-aarch64-ubuntu-18.04.tar.xz
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
exit 1 ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
mkdir -p "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin
|
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
|
||||||
|
|
||||||
curl -O "${ghc_url}"
|
rm "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin/ghcup
|
||||||
tar -xf ghc-*.tar.*
|
|
||||||
cd ghc-${GHC_VERSION}
|
|
||||||
./configure --prefix="${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/ghc/${GHC_VERSION}
|
|
||||||
make install
|
|
||||||
for i in "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/ghc/${GHC_VERSION}/bin/*-${GHC_VERSION} ; do
|
|
||||||
ln -s "${i}" "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin/${i##*/}
|
|
||||||
done
|
|
||||||
for x in "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin/*-${GHC_VERSION} ; do
|
|
||||||
ln -s ${x##*/} ${x%-${GHC_VERSION}}
|
|
||||||
done
|
|
||||||
cd ..
|
|
||||||
rm -rf ghc-${GHC_VERSION} ghc-*.tar.*
|
|
||||||
unset x i
|
|
||||||
|
|
||||||
mkdir cabal-install
|
|
||||||
cd cabal-install
|
|
||||||
curl -O "${cabal_url}"
|
|
||||||
tar -xf cabal-install-*
|
|
||||||
mv cabal "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin/cabal
|
|
||||||
cd ..
|
|
||||||
rm -rf cabal-install
|
|
||||||
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
url=https://downloads.haskell.org/~ghcup/x86_64-linux-ghcup
|
|
||||||
|
|
||||||
curl -sSfL "${url}" > ./ghcup-bin
|
|
||||||
chmod +x ghcup-bin
|
|
||||||
|
|
||||||
./ghcup-bin upgrade -i -f
|
|
||||||
./ghcup-bin install ghc ${GHC_VERSION}
|
|
||||||
./ghcup-bin set ghc ${GHC_VERSION}
|
|
||||||
./ghcup-bin install cabal ${CABAL_VERSION}
|
|
||||||
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export BOOTSTRAP_HASKELL_NONINTERACTIVE=yes
|
|||||||
export BOOTSTRAP_HASKELL_GHC_VERSION=$GHC_VERSION
|
export BOOTSTRAP_HASKELL_GHC_VERSION=$GHC_VERSION
|
||||||
export BOOTSTRAP_HASKELL_CABAL_VERSION=$CABAL_VERSION
|
export BOOTSTRAP_HASKELL_CABAL_VERSION=$CABAL_VERSION
|
||||||
|
|
||||||
./bootstrap-haskell
|
./scripts/bootstrap/bootstrap-haskell
|
||||||
|
|
||||||
[ "$(ghc --numeric-version)" = "${GHC_VERSION}" ]
|
[ "$(ghc --numeric-version)" = "${GHC_VERSION}" ]
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ ecabal() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
eghcup() {
|
eghcup() {
|
||||||
ghcup -v -c -s file://$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml "$@"
|
ghcup -v -c -s file://$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
git describe --always
|
git describe --always
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ ecabal() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
eghcup() {
|
eghcup() {
|
||||||
ghcup -v -c -s file://$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml "$@"
|
ghcup -v -c -s file://$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
git describe --always
|
git describe --always
|
||||||
|
|||||||
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" ]
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ ecabal update
|
|||||||
|
|
||||||
if [ "${OS}" = "LINUX" ] ; then
|
if [ "${OS}" = "LINUX" ] ; then
|
||||||
if [ "${ARCH}" = "32" ] ; then
|
if [ "${ARCH}" = "32" ] ; then
|
||||||
ecabal build -w ghc-${GHC_VERSION} --ghc-options='-split-sections -optl-static' -ftui -ftar
|
ecabal build -w ghc-${GHC_VERSION} --ghc-options='-split-sections -optl-static' -ftui
|
||||||
elif [ "${ARCH}" = "64" ] ; then
|
elif [ "${ARCH}" = "64" ] ; then
|
||||||
ecabal build -w ghc-${GHC_VERSION} --ghc-options='-split-sections -optl-static' -ftui
|
ecabal build -w ghc-${GHC_VERSION} --ghc-options='-split-sections -optl-static' -ftui
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ raw_eghcup() {
|
|||||||
|
|
||||||
eghcup() {
|
eghcup() {
|
||||||
if [ "${OS}" = "WINDOWS" ] ; then
|
if [ "${OS}" = "WINDOWS" ] ; then
|
||||||
ghcup -v -c -s file:/$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml "$@"
|
ghcup -v -c -s file:/$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml "$@"
|
||||||
else
|
else
|
||||||
ghcup -v -c -s file://$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml "$@"
|
ghcup -v -c -s file://$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,22 +42,25 @@ if [ "${OS}" = "DARWIN" ] ; then
|
|||||||
ecabal haddock -w ghc-${GHC_VERSION} -ftui
|
ecabal haddock -w ghc-${GHC_VERSION} -ftui
|
||||||
elif [ "${OS}" = "LINUX" ] ; then
|
elif [ "${OS}" = "LINUX" ] ; then
|
||||||
if [ "${ARCH}" = "32" ] ; then
|
if [ "${ARCH}" = "32" ] ; then
|
||||||
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui -ftar
|
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
||||||
ecabal test -w ghc-${GHC_VERSION} -finternal-downloader -ftui -ftar ghcup-test
|
ecabal test -w ghc-${GHC_VERSION} -finternal-downloader -ftui ghcup-test
|
||||||
ecabal haddock -w ghc-${GHC_VERSION} -finternal-downloader -ftui -ftar
|
ecabal haddock -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
||||||
else
|
else
|
||||||
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
||||||
ecabal test -w ghc-${GHC_VERSION} -finternal-downloader -ftui ghcup-test
|
ecabal test -w ghc-${GHC_VERSION} -finternal-downloader -ftui ghcup-test
|
||||||
ecabal haddock -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
ecabal haddock -w ghc-${GHC_VERSION} -finternal-downloader -ftui
|
||||||
|
|
||||||
# doctest
|
if [ "${ARCH}" = "64" ] ; then
|
||||||
curl -sL https://github.com/phadej/cabal-extras/releases/download/cabal-docspec-0.0.0.20210111/cabal-docspec-0.0.0.20210111.xz > cabal-docspec.xz
|
# doctest
|
||||||
echo '0829bd034fba901cbcfe491d98ed8b28fd54f9cb5c91fa8e1ac62dc4413c9562 cabal-docspec.xz' | sha256sum -c -
|
curl -sL https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal-docspec/cabal-docspec-0.0.0.20210228_p1.tar.bz2 > cabal-docspec.tar.bz2
|
||||||
xz -d < cabal-docspec.xz > "$CI_PROJECT_DIR"/.local/bin/cabal-docspec
|
echo '3a10f6fec16dbd18efdd331b1cef5d2d342082da42f5b520726d1fa6a3990d12 cabal-docspec.tar.bz2' | sha256sum -c -
|
||||||
rm -f cabal-docspec.xz
|
tar -xjf cabal-docspec.tar.bz2 cabal-docspec
|
||||||
chmod a+x "$CI_PROJECT_DIR"/.local/bin/cabal-docspec
|
mv cabal-docspec "$CI_PROJECT_DIR"/.local/bin/cabal-docspec
|
||||||
|
rm -f cabal-docspec.tar.bz2
|
||||||
|
chmod a+x "$CI_PROJECT_DIR"/.local/bin/cabal-docspec
|
||||||
|
|
||||||
cabal-docspec -XCPP -XTypeSynonymInstances -XOverloadedStrings -XPackageImports --check-properties
|
cabal-docspec -XCPP -XTypeSynonymInstances -XOverloadedStrings -XPackageImports --check-properties
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
elif [ "${OS}" = "FREEBSD" ] ; then
|
elif [ "${OS}" = "FREEBSD" ] ; then
|
||||||
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui --constraint="zip +disable-zstd"
|
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui --constraint="zip +disable-zstd"
|
||||||
@@ -89,7 +92,7 @@ rm -rf "${GHCUP_DIR}"
|
|||||||
### manual cli based testing
|
### manual cli based testing
|
||||||
|
|
||||||
|
|
||||||
ghcup-gen check -f ghcup-${JSON_VERSION}.yaml
|
ghcup-gen check -f data/metadata/ghcup-${JSON_VERSION}.yaml
|
||||||
|
|
||||||
eghcup --numeric-version
|
eghcup --numeric-version
|
||||||
|
|
||||||
@@ -98,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
|
||||||
|
|
||||||
@@ -148,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
|
||||||
@@ -161,18 +172,22 @@ 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
|
||||||
|
|
||||||
# check that lazy loading works for 'whereis'
|
# check that lazy loading works for 'whereis'
|
||||||
cp "$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml" "$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml.bak"
|
cp "$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml" "$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml.bak"
|
||||||
echo '**' > "$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml"
|
echo '**' > "$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml"
|
||||||
eghcup whereis ghc $(ghc --numeric-version)
|
eghcup whereis ghc $(ghc --numeric-version)
|
||||||
mv -f "$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml.bak" "$CI_PROJECT_DIR/ghcup-${JSON_VERSION}.yaml"
|
mv -f "$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml.bak" "$CI_PROJECT_DIR/data/metadata/ghcup-${JSON_VERSION}.yaml"
|
||||||
|
|
||||||
eghcup rm $(ghc --numeric-version)
|
eghcup rm $(ghc --numeric-version)
|
||||||
|
|
||||||
|
|||||||
194
README.md
194
README.md
@@ -10,20 +10,23 @@ 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)
|
||||||
* [Cross support](#cross-support)
|
* [Compiling GHC from source](#compiling-ghc-from-source)
|
||||||
* [XDG support](#xdg-support)
|
* [XDG support](#xdg-support)
|
||||||
* [Env variables](#env-variables)
|
* [Env variables](#env-variables)
|
||||||
* [Installing custom bindists](#installing-custom-bindists)
|
* [Installing custom bindists](#installing-custom-bindists)
|
||||||
* [Isolated Installs](#isolated-installs)
|
* [Isolated Installs](#isolated-installs)
|
||||||
|
* [CI](#ci)
|
||||||
* [Tips and tricks](#tips-and-tricks)
|
* [Tips and tricks](#tips-and-tricks)
|
||||||
* [Design goals](#design-goals)
|
* [Design goals](#design-goals)
|
||||||
* [How](#how)
|
* [How](#how)
|
||||||
@@ -33,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
|
||||||
|
|
||||||
@@ -90,10 +143,38 @@ handles your haskell packages and can demand that [a specific version](https://c
|
|||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
A configuration file can be put in `~/.ghcup/config.yaml`. The default config file
|
A configuration file can be put in `~/.ghcup/config.yaml`. The default config file
|
||||||
explaining all possible configurations can be found in this repo: [config.yaml](./config.yaml).
|
explaining all possible configurations can be found in this repo: [config.yaml](./data/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.
|
||||||
@@ -101,14 +182,26 @@ For man pages to work you need [man-db](http://man-db.nongnu.org/) as your `man`
|
|||||||
|
|
||||||
### Shell-completion
|
### Shell-completion
|
||||||
|
|
||||||
Shell completions are in `shell-completions`.
|
Shell completions are in [scripts/shell-completions](./scripts/shell-completions) directory of this repository.
|
||||||
|
|
||||||
For bash: install `shell-completions/bash`
|
For bash: install `shell-completions/bash`
|
||||||
as e.g. `/etc/bash_completion.d/ghcup` (depending on distro)
|
as e.g. `/etc/bash_completion.d/ghcup` (depending on distro)
|
||||||
and make sure your bashrc sources the startup script
|
and make sure your bashrc sources the startup script
|
||||||
(`/usr/share/bash-completion/bash_completion` on some distros).
|
(`/usr/share/bash-completion/bash_completion` on some distros).
|
||||||
|
|
||||||
### Cross support
|
### Compiling GHC from source
|
||||||
|
|
||||||
|
Compiling from source is supported for both source tarballs and arbitrary git refs. See `ghcup compile ghc --help`
|
||||||
|
for a list of all available options.
|
||||||
|
|
||||||
|
If you need to overwrite the existing `build.mk`, check the default files
|
||||||
|
in [data/build_mk](./data/build_mk), copy them somewhere, adjust them and
|
||||||
|
pass `--config path/to/build.mk` to `ghcup compile ghc`.
|
||||||
|
Common `build.mk` options are explained [here](https://gitlab.haskell.org/ghc/ghc/-/wikis/building/using#build-configuration).
|
||||||
|
|
||||||
|
Make sure your system meets all the [prerequisites](https://gitlab.haskell.org/ghc/ghc/-/wikis/building/preparation).
|
||||||
|
|
||||||
|
#### Cross support
|
||||||
|
|
||||||
ghcup can compile and install a cross GHC for any target. However, this
|
ghcup can compile and install a cross GHC for any target. However, this
|
||||||
requires that the build host has a complete cross toolchain and various
|
requires that the build host has a complete cross toolchain and various
|
||||||
@@ -142,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
|
||||||
|
|
||||||
@@ -190,6 +284,83 @@ Examples:-
|
|||||||
5. you can even compile ghc to an isolated location.
|
5. you can even compile ghc to an isolated location.
|
||||||
- `ghcup compile ghc -j 4 -v 9.0.1 -b 8.10.5 -i /home/username/my/dir/ghc`
|
- `ghcup compile ghc -j 4 -v 9.0.1 -b 8.10.5 -i /home/username/my/dir/ghc`
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### CI
|
||||||
|
|
||||||
|
On windows, ghcup can be installed automatically on a CI runner like so:
|
||||||
|
|
||||||
|
```ps
|
||||||
|
Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -ArgumentList $false,$true,$true,$false,$false,$false,$false,"C:\"
|
||||||
|
```
|
||||||
|
|
||||||
|
On linux/darwin/freebsd, run the following on your runner:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | BOOTSTRAP_HASKELL_NONINTERACTIVE=1 BOOTSTRAP_HASKELL_MINIMAL=1 sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This will just install `ghcup` and on windows additionally `msys2`.
|
||||||
|
|
||||||
|
#### Example github workflow
|
||||||
|
|
||||||
|
On github workflows you can use https://github.com/haskell/actions/
|
||||||
|
|
||||||
|
If you want to install ghcup manually though, here's an example config:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
name: Haskell CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-cabal:
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||||
|
ghc: ['8.10.7', '9.0.1']
|
||||||
|
cabal: ['3.4.0.0']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- if: matrix.os == 'windows-latest'
|
||||||
|
name: Install ghcup on windows
|
||||||
|
run: Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072;Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -ArgumentList $false,$true,$true,$false,$false,$false,$false,"C:\"
|
||||||
|
|
||||||
|
- if: matrix.os == 'windows-latest'
|
||||||
|
name: Add ghcup to PATH
|
||||||
|
run: echo "/c/ghcup/bin" >> $GITHUB_PATH
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- if: matrix.os != 'windows-latest'
|
||||||
|
name: Install ghcup on non-windows
|
||||||
|
run: curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | BOOTSTRAP_HASKELL_NONINTERACTIVE=1 BOOTSTRAP_HASKELL_MINIMAL=1 sh
|
||||||
|
|
||||||
|
- name: Install ghc/cabal
|
||||||
|
run: |
|
||||||
|
ghcup install ghc ${{ matrix.ghc }}
|
||||||
|
ghcup install cabal ${{ matrix.cabal }}
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Update cabal index
|
||||||
|
run: cabal update
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cabal build --enable-tests --enable-benchmarks
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: cabal test
|
||||||
|
shell: bash
|
||||||
|
```
|
||||||
|
|
||||||
### Tips and tricks
|
### Tips and tricks
|
||||||
|
|
||||||
@@ -266,8 +437,13 @@ In addition this script can also install `cabal-install`.
|
|||||||
|
|
||||||
## Known users
|
## Known users
|
||||||
|
|
||||||
* Github action [haskell/actions/setup](https://github.com/haskell/actions/tree/main/setup)
|
* Github actions:
|
||||||
* [vabal](https://github.com/Franciman/vabal)
|
- [actions/virtual-environments](https://github.com/actions/virtual-environments)
|
||||||
|
- [haskell/actions/setup](https://github.com/haskell/actions/tree/main/setup)
|
||||||
|
* mirrors:
|
||||||
|
- [sjtug](https://mirror.sjtu.edu.cn/docs/ghcup)
|
||||||
|
* tools:
|
||||||
|
- [vabal](https://github.com/Franciman/vabal)
|
||||||
|
|
||||||
## Known problems
|
## Known problems
|
||||||
|
|
||||||
|
|||||||
19
RELEASING.md
19
RELEASING.md
@@ -1,19 +0,0 @@
|
|||||||
# RELEASING
|
|
||||||
|
|
||||||
1. update `GHCup.Version` module. `ghcupURL` must only be updated if we change the `_toolRequirements` type or the YAML representation of it. The version of the YAML represents the change increments. `ghcUpVer` is the current application version.
|
|
||||||
|
|
||||||
2. Update version in ghcup.cabal
|
|
||||||
|
|
||||||
3. Add ChangeLog entry
|
|
||||||
|
|
||||||
4. Add/fix downloads in `ghcup-<ver>.yaml`, then verify with `ghcup-gen check -f ghcup-<ver>.yaml`
|
|
||||||
|
|
||||||
5. Commit and git push with tag. Wait for tests to succeed and release artifacts to build.
|
|
||||||
|
|
||||||
6. Download release artifacts and upload them `downloads.haskell.org/ghcup`
|
|
||||||
|
|
||||||
7. Add release artifacts to yaml file (see point 4.)
|
|
||||||
|
|
||||||
8. Upload the final `ghcup-<ver>.yaml` to `webhost.haskell.org/ghcup/data/`.
|
|
||||||
|
|
||||||
9. Update bootstrap-haskell and symlinks on `downloads.haskell.org/ghcup`
|
|
||||||
@@ -11,22 +11,33 @@
|
|||||||
module Main where
|
module Main where
|
||||||
|
|
||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
import GHCup.Types.JSON ( )
|
import GHCup.Errors
|
||||||
|
import GHCup.Platform
|
||||||
|
import GHCup.Utils.Dirs
|
||||||
import GHCup.Utils.Logger
|
import GHCup.Utils.Logger
|
||||||
|
import GHCup.Types.JSON ( )
|
||||||
|
|
||||||
|
import Control.Monad.Trans.Reader ( runReaderT )
|
||||||
|
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 System.Console.Pretty
|
import System.Console.Pretty
|
||||||
|
import System.Environment
|
||||||
import System.Exit
|
import System.Exit
|
||||||
import System.IO ( stdout )
|
import System.IO ( stderr )
|
||||||
import Text.Regex.Posix
|
import Text.Regex.Posix
|
||||||
import Validate
|
import Validate
|
||||||
|
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||||
|
|
||||||
|
import qualified Data.Text.IO as T
|
||||||
|
import qualified Data.Text as T
|
||||||
import qualified Data.ByteString as B
|
import qualified Data.ByteString as B
|
||||||
import qualified Data.Yaml as Y
|
import qualified Data.YAML.Aeson as Y
|
||||||
|
|
||||||
|
|
||||||
data Options = Options
|
data Options = Options
|
||||||
@@ -105,10 +116,29 @@ com = subparser
|
|||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
no_color <- isJust <$> lookupEnv "NO_COLOR"
|
||||||
|
let loggerConfig = LoggerConfig { lcPrintDebug = True
|
||||||
|
, consoleOutter = T.hPutStr stderr
|
||||||
|
, fileOutter = \_ -> pure ()
|
||||||
|
, fancyColors = not no_color
|
||||||
|
}
|
||||||
|
dirs <- liftIO getAllDirs
|
||||||
|
let leanAppstate = LeanAppState (Settings True False Never Curl True GHCupURL False GPGNone False) dirs defaultKeyBindings loggerConfig
|
||||||
|
|
||||||
|
pfreq <- (
|
||||||
|
flip runReaderT leanAppstate . runE @'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound] $ platformRequest
|
||||||
|
) >>= \case
|
||||||
|
VRight r -> pure r
|
||||||
|
VLeft e -> do
|
||||||
|
flip runReaderT leanAppstate $ logError $ T.pack $ prettyShow e
|
||||||
|
liftIO $ exitWith (ExitFailure 2)
|
||||||
|
|
||||||
|
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
|
||||||
ValidateYAML vopts -> withValidateYamlOpts vopts validate
|
ValidateYAML vopts -> withValidateYamlOpts vopts (\dl m -> flip runReaderT appstate $ validate dl m)
|
||||||
ValidateTarballs vopts tarballFilter -> withValidateYamlOpts vopts (validateTarballs tarballFilter)
|
ValidateTarballs vopts tarballFilter -> withValidateYamlOpts vopts (\dl m -> flip runReaderT appstate $ validateTarballs tarballFilter dl m)
|
||||||
pure ()
|
pure ()
|
||||||
|
|
||||||
where
|
where
|
||||||
@@ -120,8 +150,8 @@ main = do
|
|||||||
ValidateYAMLOpts { vInput = Just (FileInput file) } ->
|
ValidateYAMLOpts { vInput = Just (FileInput file) } ->
|
||||||
B.readFile file >>= valAndExit f
|
B.readFile file >>= valAndExit f
|
||||||
valAndExit f contents = do
|
valAndExit f contents = do
|
||||||
(GHCupInfo _ av gt) <- case Y.decodeEither' contents of
|
(GHCupInfo _ av gt) <- case Y.decode1Strict contents of
|
||||||
Right r -> pure r
|
Right r -> pure r
|
||||||
Left e -> die (color Red $ show e)
|
Left (_, e) -> die (color Red $ show e)
|
||||||
myLoggerT (LoggerConfig True (B.hPut stdout) (\_ -> pure ())) (f av gt)
|
f av gt
|
||||||
>>= exitWith
|
>>= exitWith
|
||||||
|
|||||||
@@ -5,29 +5,24 @@
|
|||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
{-# LANGUAGE TypeApplications #-}
|
{-# LANGUAGE TypeApplications #-}
|
||||||
{-# LANGUAGE ViewPatterns #-}
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
module Validate where
|
module Validate where
|
||||||
|
|
||||||
import GHCup
|
import GHCup
|
||||||
import GHCup.Download
|
import GHCup.Download
|
||||||
import GHCup.Errors
|
import GHCup.Errors
|
||||||
import GHCup.Platform
|
import GHCup.Types
|
||||||
import GHCup.Types hiding ( LeanAppState (..) )
|
|
||||||
import GHCup.Types.Optics
|
import GHCup.Types.Optics
|
||||||
import GHCup.Utils
|
import GHCup.Utils
|
||||||
import GHCup.Utils.Logger
|
import GHCup.Utils.Logger
|
||||||
import GHCup.Utils.Version.QQ
|
import GHCup.Utils.Version.QQ
|
||||||
|
|
||||||
#if defined(TAR)
|
|
||||||
import qualified Codec.Archive.Tar as Tar
|
|
||||||
#else
|
|
||||||
import Codec.Archive
|
import Codec.Archive
|
||||||
#endif
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
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.Logger
|
|
||||||
import Control.Monad.Reader.Class
|
import Control.Monad.Reader.Class
|
||||||
import Control.Monad.Trans.Class ( lift )
|
import Control.Monad.Trans.Class ( lift )
|
||||||
import Control.Monad.Trans.Reader ( runReaderT )
|
import Control.Monad.Trans.Reader ( runReaderT )
|
||||||
@@ -37,18 +32,15 @@ import Control.Monad.Trans.Resource ( runResourceT
|
|||||||
import Data.Containers.ListUtils ( nubOrd )
|
import Data.Containers.ListUtils ( nubOrd )
|
||||||
import Data.IORef
|
import Data.IORef
|
||||||
import Data.List
|
import Data.List
|
||||||
import Data.String.Interpolate
|
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
import Haskus.Utils.Variant.Excepts
|
import Haskus.Utils.Variant.Excepts
|
||||||
import Optics
|
import Optics
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
import System.Exit
|
import System.Exit
|
||||||
import System.IO
|
|
||||||
import Text.ParserCombinators.ReadP
|
import Text.ParserCombinators.ReadP
|
||||||
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
import Text.PrettyPrint.HughesPJClass ( prettyShow )
|
||||||
import Text.Regex.Posix
|
import Text.Regex.Posix
|
||||||
|
|
||||||
import qualified Data.ByteString as B
|
|
||||||
import qualified Data.Map.Strict as M
|
import qualified Data.Map.Strict as M
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Version as V
|
import qualified Data.Version as V
|
||||||
@@ -66,7 +58,7 @@ addError = do
|
|||||||
liftIO $ modifyIORef ref (+ 1)
|
liftIO $ modifyIORef ref (+ 1)
|
||||||
|
|
||||||
|
|
||||||
validate :: (Monad m, MonadLogger m, MonadThrow m, MonadIO m, MonadUnliftIO m)
|
validate :: (Monad m, MonadReader env m, HasLog env, MonadThrow m, MonadIO m, MonadUnliftIO m)
|
||||||
=> GHCupDownloads
|
=> GHCupDownloads
|
||||||
-> M.Map GlobalTool DownloadInfo
|
-> M.Map GlobalTool DownloadInfo
|
||||||
-> m ExitCode
|
-> m ExitCode
|
||||||
@@ -93,24 +85,23 @@ validate dls _ = do
|
|||||||
if e > 0
|
if e > 0
|
||||||
then pure $ ExitFailure e
|
then pure $ ExitFailure e
|
||||||
else do
|
else do
|
||||||
lift $ $(logInfo) [i|All good|]
|
lift $ logInfo "All good"
|
||||||
pure ExitSuccess
|
pure ExitSuccess
|
||||||
where
|
where
|
||||||
checkHasRequiredPlatforms t v tags arch pspecs = do
|
checkHasRequiredPlatforms t v tags arch pspecs = do
|
||||||
let v' = prettyVer v
|
let v' = prettyVer v
|
||||||
arch' = prettyShow arch
|
arch' = prettyShow arch
|
||||||
when (notElem (Linux UnknownLinux) pspecs) $ do
|
when (notElem (Linux UnknownLinux) pspecs) $ do
|
||||||
lift $ $(logError)
|
lift $ logError $
|
||||||
[i|Linux UnknownLinux missing for for #{t} #{v'} #{arch'}|]
|
"Linux UnknownLinux missing for for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack arch'
|
||||||
addError
|
addError
|
||||||
when ((notElem Darwin pspecs) && arch == A_64) $ do
|
when ((notElem Darwin pspecs) && arch == A_64) $ do
|
||||||
lift $ $(logError) [i|Darwin missing for #{t} #{v'} #{arch'}|]
|
lift $ logError $ "Darwin missing for for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack arch'
|
||||||
addError
|
addError
|
||||||
when ((notElem FreeBSD pspecs) && arch == A_64) $ lift $ $(logWarn)
|
when ((notElem FreeBSD pspecs) && arch == A_64) $ lift $ logWarn $
|
||||||
[i|FreeBSD missing for #{t} #{v'} #{arch'}|]
|
"FreeBSD missing for for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack arch'
|
||||||
when (notElem Windows pspecs && arch == A_64) $ do
|
when (notElem Windows pspecs && arch == A_64) $ do
|
||||||
lift $ $(logError)
|
lift $ logError $ "Windows missing for for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack arch'
|
||||||
[i|Windows missing for for #{t} #{v'} #{arch'}|]
|
|
||||||
addError
|
addError
|
||||||
|
|
||||||
-- alpine needs to be set explicitly, because
|
-- alpine needs to be set explicitly, because
|
||||||
@@ -118,12 +109,12 @@ validate dls _ = do
|
|||||||
-- (although it could be static)
|
-- (although it could be static)
|
||||||
when (notElem (Linux Alpine) pspecs) $
|
when (notElem (Linux Alpine) pspecs) $
|
||||||
case t of
|
case t of
|
||||||
GHCup | arch `elem` [A_64, A_32] -> lift ($(logError) [i|Linux Alpine missing for #{t} #{v'} #{arch}|]) >> addError
|
GHCup | arch `elem` [A_64, A_32] -> lift (logError $ "Linux Alpine missing for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack (prettyShow arch)) >> addError
|
||||||
Cabal | v > [vver|2.4.1.0|]
|
Cabal | v > [vver|2.4.1.0|]
|
||||||
, arch `elem` [A_64, A_32] -> lift ($(logError) [i|Linux Alpine missing for #{t} #{v'} #{arch'}|]) >> addError
|
, arch `elem` [A_64, A_32] -> lift (logError $ "Linux Alpine missing for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack (prettyShow arch)) >> addError
|
||||||
GHC | Latest `elem` tags || Recommended `elem` tags
|
GHC | Latest `elem` tags || Recommended `elem` tags
|
||||||
, arch `elem` [A_64, A_32] -> lift ($(logError) [i|Linux Alpine missing for #{t} #{v'} #{arch'}|])
|
, arch `elem` [A_64, A_32] -> lift (logError $ "Linux Alpine missing for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack (prettyShow arch))
|
||||||
_ -> lift $ $(logWarn) [i|Linux Alpine missing for #{t} #{v'} #{arch'}|]
|
_ -> lift $ logWarn $ "Linux Alpine missing for " <> T.pack (prettyShow t) <> " " <> v' <> " " <> T.pack (prettyShow arch)
|
||||||
|
|
||||||
checkUniqueTags tool = do
|
checkUniqueTags tool = do
|
||||||
let allTags = join $ fmap _viTags $ M.elems $ availableToolVersions dls tool
|
let allTags = join $ fmap _viTags $ M.elems $ availableToolVersions dls tool
|
||||||
@@ -143,7 +134,7 @@ validate dls _ = do
|
|||||||
case join nonUnique of
|
case join nonUnique of
|
||||||
[] -> pure ()
|
[] -> pure ()
|
||||||
xs -> do
|
xs -> do
|
||||||
lift $ $(logError) [i|Tags not unique for #{tool}: #{xs}|]
|
lift $ logError $ "Tags not unique for " <> T.pack (prettyShow tool) <> ": " <> T.pack (prettyShow xs)
|
||||||
addError
|
addError
|
||||||
where
|
where
|
||||||
isUniqueTag Latest = True
|
isUniqueTag Latest = True
|
||||||
@@ -159,7 +150,7 @@ validate dls _ = do
|
|||||||
case [ x | (x,"") <- readP_to_S V.parseVersion (T.unpack . prettyVer $ v) ] of
|
case [ x | (x,"") <- readP_to_S V.parseVersion (T.unpack . prettyVer $ v) ] of
|
||||||
[_] -> pure ()
|
[_] -> pure ()
|
||||||
_ -> do
|
_ -> do
|
||||||
lift $ $(logError) [i|GHC version #{v} is not valid |]
|
lift $ logError $ "GHC version " <> prettyVer v <> " is not valid"
|
||||||
addError
|
addError
|
||||||
|
|
||||||
-- a tool must have at least one of each mandatory tags
|
-- a tool must have at least one of each mandatory tags
|
||||||
@@ -167,7 +158,7 @@ validate dls _ = do
|
|||||||
let allTags = join $ fmap _viTags $ M.elems $ availableToolVersions dls tool
|
let allTags = join $ fmap _viTags $ M.elems $ availableToolVersions dls tool
|
||||||
forM_ [Latest, Recommended] $ \t -> case elem t allTags of
|
forM_ [Latest, Recommended] $ \t -> case elem t allTags of
|
||||||
False -> do
|
False -> do
|
||||||
lift $ $(logError) [i|Tag #{t} missing from #{tool}|]
|
lift $ logError $ "Tag " <> T.pack (prettyShow t) <> " missing from " <> T.pack (prettyShow tool)
|
||||||
addError
|
addError
|
||||||
True -> pure ()
|
True -> pure ()
|
||||||
|
|
||||||
@@ -176,7 +167,7 @@ validate dls _ = do
|
|||||||
let allTags = M.toList $ availableToolVersions dls GHC
|
let allTags = M.toList $ availableToolVersions dls GHC
|
||||||
forM allTags $ \(ver, _viTags -> tags) -> case any isBase tags of
|
forM allTags $ \(ver, _viTags -> tags) -> case any isBase tags of
|
||||||
False -> do
|
False -> do
|
||||||
lift $ $(logError) [i|Base tag missing from GHC ver #{ver}|]
|
lift $ logError $ "Base tag missing from GHC ver " <> prettyVer ver
|
||||||
addError
|
addError
|
||||||
True -> pure ()
|
True -> pure ()
|
||||||
|
|
||||||
@@ -189,7 +180,10 @@ data TarballFilter = TarballFilter
|
|||||||
}
|
}
|
||||||
|
|
||||||
validateTarballs :: ( Monad m
|
validateTarballs :: ( Monad m
|
||||||
, MonadLogger m
|
, MonadReader env m
|
||||||
|
, HasLog env
|
||||||
|
, HasDirs env
|
||||||
|
, HasSettings env
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadUnliftIO m
|
, MonadUnliftIO m
|
||||||
@@ -204,59 +198,48 @@ validateTarballs :: ( Monad m
|
|||||||
validateTarballs (TarballFilter etool versionRegex) dls gt = do
|
validateTarballs (TarballFilter etool versionRegex) dls gt = do
|
||||||
ref <- liftIO $ newIORef 0
|
ref <- liftIO $ newIORef 0
|
||||||
|
|
||||||
flip runReaderT ref $ do
|
-- download/verify all tarballs
|
||||||
-- download/verify all tarballs
|
let dlis = either (const []) (\tool -> nubOrd $ dls ^.. each %& indices (maybe (const True) (==) tool) %> each %& indices (matchTest versionRegex . T.unpack . prettyVer) % (viSourceDL % _Just `summing` viArch % each % each % each)) etool
|
||||||
let dlis = either (const []) (\tool -> nubOrd $ dls ^.. each %& indices (maybe (const True) (==) tool) %> each %& indices (matchTest versionRegex . T.unpack . prettyVer) % (viSourceDL % _Just `summing` viArch % each % each % each)) etool
|
let gdlis = nubOrd $ gt ^.. each
|
||||||
let gdlis = nubOrd $ gt ^.. each
|
let allDls = either (const gdlis) (const dlis) etool
|
||||||
let allDls = either (const gdlis) (const dlis) etool
|
when (null allDls) $ logError "no tarballs selected by filter" *> (flip runReaderT ref addError)
|
||||||
when (null allDls) $ $(logError) [i|no tarballs selected by filter|] *> addError
|
forM_ allDls (downloadAll ref)
|
||||||
forM_ allDls downloadAll
|
|
||||||
|
|
||||||
-- exit
|
-- exit
|
||||||
e <- liftIO $ readIORef ref
|
e <- liftIO $ readIORef ref
|
||||||
if e > 0
|
if e > 0
|
||||||
then pure $ ExitFailure e
|
then pure $ ExitFailure e
|
||||||
else do
|
else do
|
||||||
lift $ $(logInfo) [i|All good|]
|
logInfo "All good"
|
||||||
pure ExitSuccess
|
pure ExitSuccess
|
||||||
|
|
||||||
where
|
where
|
||||||
runLogger = myLoggerT LoggerConfig { lcPrintDebug = True
|
downloadAll :: ( MonadUnliftIO m
|
||||||
, colorOutter = B.hPut stderr
|
, MonadIO m
|
||||||
, rawOutter = \_ -> pure ()
|
, MonadReader env m
|
||||||
}
|
, HasLog env
|
||||||
downloadAll dli = do
|
, HasDirs env
|
||||||
dirs <- liftIO getAllDirs
|
, HasSettings env
|
||||||
|
, MonadCatch m
|
||||||
pfreq <- (
|
, MonadMask m
|
||||||
runLogger . runE @'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound] . liftE $ platformRequest
|
, MonadThrow m
|
||||||
) >>= \case
|
)
|
||||||
VRight r -> pure r
|
=> IORef Int
|
||||||
VLeft e -> do
|
-> DownloadInfo
|
||||||
lift $ runLogger
|
-> m ()
|
||||||
($(logError) $ T.pack $ prettyShow e)
|
downloadAll ref dli = do
|
||||||
liftIO $ exitWith (ExitFailure 2)
|
r <- runResourceT
|
||||||
|
|
||||||
let appstate = AppState (Settings True False Never Curl True GHCupURL False) dirs defaultKeyBindings (GHCupInfo mempty mempty mempty) pfreq
|
|
||||||
|
|
||||||
r <-
|
|
||||||
runLogger
|
|
||||||
. flip runReaderT appstate
|
|
||||||
. runResourceT
|
|
||||||
. runE @'[DigestError
|
. runE @'[DigestError
|
||||||
|
, GPGError
|
||||||
, DownloadFailed
|
, DownloadFailed
|
||||||
, UnknownArchive
|
, UnknownArchive
|
||||||
#if defined(TAR)
|
|
||||||
, Tar.FormatError
|
|
||||||
#else
|
|
||||||
, ArchiveResult
|
, ArchiveResult
|
||||||
#endif
|
|
||||||
]
|
]
|
||||||
$ do
|
$ 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
|
||||||
@@ -266,32 +249,32 @@ 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
|
||||||
case _dlSubdir dli of
|
case _dlSubdir dli of
|
||||||
Just (RealDir prel) -> do
|
Just (RealDir prel) -> do
|
||||||
lift $ $(logInfo)
|
logInfo
|
||||||
[i|verifying subdir: #{prel}|]
|
$ " verifying subdir: " <> T.pack prel
|
||||||
when (basePath /= prel) $ do
|
when (basePath /= prel) $ do
|
||||||
lift $ $(logError)
|
logError $
|
||||||
[i|Subdir doesn't match: expected "#{prel}", got "#{basePath}"|]
|
"Subdir doesn't match: expected " <> T.pack prel <> ", got " <> T.pack basePath
|
||||||
addError
|
(flip runReaderT ref addError)
|
||||||
Just (RegexDir regexString) -> do
|
Just (RegexDir regexString) -> do
|
||||||
lift $ $(logInfo)
|
logInfo $
|
||||||
[i|verifying subdir (regex): #{regexString}|]
|
"verifying subdir (regex): " <> T.pack regexString
|
||||||
let regex = makeRegexOpts
|
let regex = makeRegexOpts
|
||||||
compIgnoreCase
|
compIgnoreCase
|
||||||
execBlank
|
execBlank
|
||||||
regexString
|
regexString
|
||||||
when (not (match regex basePath)) $ do
|
when (not (match regex basePath)) $ do
|
||||||
lift $ $(logError)
|
logError $
|
||||||
[i|Subdir doesn't match: expected regex "#{regexString}", got "#{basePath}"|]
|
"Subdir doesn't match: expected regex " <> T.pack regexString <> ", got " <> T.pack basePath
|
||||||
addError
|
(flip runReaderT ref addError)
|
||||||
Nothing -> pure ()
|
Nothing -> pure ()
|
||||||
VRight Nothing -> pure ()
|
VRight Nothing -> pure ()
|
||||||
VLeft e -> do
|
VLeft e -> do
|
||||||
lift $ $(logError)
|
logError $
|
||||||
[i|Could not download (or verify hash) of #{dli}, Error was: #{prettyShow e}|]
|
"Could not download (or verify hash) of " <> T.pack (show dli) <> ", Error was: " <> T.pack (prettyShow e)
|
||||||
addError
|
(flip runReaderT ref addError)
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ import GHCup.Download
|
|||||||
import GHCup.Errors
|
import GHCup.Errors
|
||||||
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
|
||||||
import GHCup.Utils.Logger
|
|
||||||
|
|
||||||
import Brick
|
import Brick
|
||||||
import Brick.Widgets.Border
|
import Brick.Widgets.Border
|
||||||
@@ -27,11 +27,8 @@ import Brick.Widgets.List ( listSelectedFocusedAttr
|
|||||||
, listSelectedAttr
|
, listSelectedAttr
|
||||||
, listAttr
|
, listAttr
|
||||||
)
|
)
|
||||||
#if !defined(TAR)
|
|
||||||
import Codec.Archive
|
import Codec.Archive
|
||||||
#endif
|
|
||||||
import Control.Exception.Safe
|
import Control.Exception.Safe
|
||||||
import Control.Monad.Logger
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Control.Monad.Trans.Except
|
import Control.Monad.Trans.Except
|
||||||
import Control.Monad.Trans.Resource
|
import Control.Monad.Trans.Resource
|
||||||
@@ -40,14 +37,12 @@ import Data.Functor
|
|||||||
import Data.List
|
import Data.List
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.IORef
|
import Data.IORef
|
||||||
import Data.String.Interpolate
|
|
||||||
import Data.Vector ( Vector
|
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 )
|
||||||
@@ -420,17 +415,11 @@ install' :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, Monad
|
|||||||
install' _ (_, ListResult {..}) = do
|
install' _ (_, ListResult {..}) = do
|
||||||
AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
|
AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
|
||||||
|
|
||||||
l <- liftIO $ readIORef logger'
|
|
||||||
let runLogger = myLoggerT l
|
|
||||||
|
|
||||||
let run =
|
let run =
|
||||||
runLogger
|
runResourceT
|
||||||
. runResourceT
|
|
||||||
. runE
|
. runE
|
||||||
@'[ AlreadyInstalled
|
@'[ AlreadyInstalled
|
||||||
#if !defined(TAR)
|
|
||||||
, ArchiveResult
|
, ArchiveResult
|
||||||
#endif
|
|
||||||
, UnknownArchive
|
, UnknownArchive
|
||||||
, FileDoesNotExistError
|
, FileDoesNotExistError
|
||||||
, CopyError
|
, CopyError
|
||||||
@@ -439,6 +428,7 @@ install' _ (_, ListResult {..}) = do
|
|||||||
, BuildFailed
|
, BuildFailed
|
||||||
, TagNotFound
|
, TagNotFound
|
||||||
, DigestError
|
, DigestError
|
||||||
|
, GPGError
|
||||||
, DownloadFailed
|
, DownloadFailed
|
||||||
, DirNotEmpty
|
, DirNotEmpty
|
||||||
, NoUpdate
|
, NoUpdate
|
||||||
@@ -450,40 +440,37 @@ 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
|
||||||
forM_ (_viPostInstall =<< vi) $ \msg ->
|
forM_ (_viPostInstall =<< vi) $ \msg ->
|
||||||
myLoggerT l $ $(logInfo) msg
|
logInfo msg
|
||||||
pure $ Right ()
|
pure $ Right ()
|
||||||
VLeft (V (AlreadyInstalled _ _)) -> pure $ Right ()
|
VLeft (V (AlreadyInstalled _ _)) -> pure $ Right ()
|
||||||
VLeft (V NoUpdate) -> pure $ Right ()
|
VLeft (V NoUpdate) -> pure $ Right ()
|
||||||
VLeft e -> pure $ Left [i|#{prettyShow e}
|
VLeft e -> pure $ Left $ prettyShow e <> "\n"
|
||||||
Also check the logs in ~/.ghcup/logs|]
|
<> "Also check the logs in ~/.ghcup/logs"
|
||||||
|
|
||||||
|
|
||||||
set' :: BrickState -> (Int, ListResult) -> IO (Either String ())
|
set' :: BrickState -> (Int, ListResult) -> IO (Either String ())
|
||||||
set' _ (_, ListResult {..}) = do
|
set' _ (_, ListResult {..}) = do
|
||||||
settings <- readIORef settings'
|
settings <- readIORef settings'
|
||||||
l <- readIORef logger'
|
|
||||||
let runLogger = myLoggerT l
|
|
||||||
|
|
||||||
let run =
|
let run =
|
||||||
runLogger
|
flip runReaderT settings
|
||||||
. flip runReaderT settings
|
|
||||||
. runE @'[FileDoesNotExistError , NotInstalled , TagNotFound]
|
. runE @'[FileDoesNotExistError , NotInstalled , TagNotFound]
|
||||||
|
|
||||||
run (do
|
run (do
|
||||||
@@ -506,9 +493,7 @@ del' :: (MonadReader AppState m, MonadIO m, MonadFail m, MonadMask m, MonadUnlif
|
|||||||
del' _ (_, ListResult {..}) = do
|
del' _ (_, ListResult {..}) = do
|
||||||
AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
|
AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
|
||||||
|
|
||||||
l <- liftIO $ readIORef logger'
|
let run = runE @'[NotInstalled]
|
||||||
let runLogger = myLoggerT l
|
|
||||||
let run = myLoggerT l . runE @'[NotInstalled]
|
|
||||||
|
|
||||||
run (do
|
run (do
|
||||||
let vi = getVersionInfo lVer lTool dls
|
let vi = getVersionInfo lVer lTool dls
|
||||||
@@ -522,7 +507,7 @@ del' _ (_, ListResult {..}) = do
|
|||||||
>>= \case
|
>>= \case
|
||||||
VRight vi -> do
|
VRight vi -> do
|
||||||
forM_ (join $ fmap _viPostRemove vi) $ \msg ->
|
forM_ (join $ fmap _viPostRemove vi) $ \msg ->
|
||||||
runLogger $ $(logInfo) msg
|
logInfo msg
|
||||||
pure $ Right ()
|
pure $ Right ()
|
||||||
VLeft e -> pure $ Left (prettyShow e)
|
VLeft e -> pure $ Left (prettyShow e)
|
||||||
|
|
||||||
@@ -534,8 +519,8 @@ changelog' :: (MonadReader AppState m, MonadIO m)
|
|||||||
changelog' _ (_, ListResult {..}) = do
|
changelog' _ (_, ListResult {..}) = do
|
||||||
AppState { pfreq, ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
|
AppState { pfreq, ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
|
||||||
case getChangeLog dls lTool (Left lVer) of
|
case getChangeLog dls lTool (Left lVer) of
|
||||||
Nothing -> pure $ Left
|
Nothing -> pure $ Left $
|
||||||
[i|Could not find ChangeLog for #{lTool}, version #{prettyVer lVer}|]
|
"Could not find ChangeLog for " <> prettyShow lTool <> ", version " <> T.unpack (prettyVer lVer)
|
||||||
Just uri -> do
|
Just uri -> do
|
||||||
let cmd = case _rPlatform pfreq of
|
let cmd = case _rPlatform pfreq of
|
||||||
Darwin -> "open"
|
Darwin -> "open"
|
||||||
@@ -551,6 +536,11 @@ settings' :: IORef AppState
|
|||||||
{-# NOINLINE settings' #-}
|
{-# NOINLINE settings' #-}
|
||||||
settings' = unsafePerformIO $ do
|
settings' = unsafePerformIO $ do
|
||||||
dirs <- getAllDirs
|
dirs <- getAllDirs
|
||||||
|
let loggerConfig = LoggerConfig { lcPrintDebug = False
|
||||||
|
, consoleOutter = \_ -> pure ()
|
||||||
|
, fileOutter = \_ -> pure ()
|
||||||
|
, fancyColors = True
|
||||||
|
}
|
||||||
newIORef $ AppState (Settings { cache = True
|
newIORef $ AppState (Settings { cache = True
|
||||||
, noVerify = False
|
, noVerify = False
|
||||||
, keepDirs = Never
|
, keepDirs = Never
|
||||||
@@ -558,41 +548,28 @@ settings' = unsafePerformIO $ do
|
|||||||
, verbose = False
|
, verbose = False
|
||||||
, urlSource = GHCupURL
|
, urlSource = GHCupURL
|
||||||
, noNetwork = False
|
, noNetwork = False
|
||||||
|
, gpgSetting = GPGNone
|
||||||
|
, noColor = False
|
||||||
, ..
|
, ..
|
||||||
})
|
})
|
||||||
dirs
|
dirs
|
||||||
defaultKeyBindings
|
defaultKeyBindings
|
||||||
(GHCupInfo mempty mempty mempty)
|
(GHCupInfo mempty mempty mempty)
|
||||||
(PlatformRequest A_64 Darwin Nothing)
|
(PlatformRequest A_64 Darwin Nothing)
|
||||||
|
loggerConfig
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
logger' :: IORef LoggerConfig
|
|
||||||
{-# NOINLINE logger' #-}
|
|
||||||
logger' = unsafePerformIO
|
|
||||||
(newIORef $ LoggerConfig { lcPrintDebug = False
|
|
||||||
, colorOutter = \_ -> pure ()
|
|
||||||
, rawOutter = \_ -> pure ()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
brickMain :: AppState
|
brickMain :: AppState
|
||||||
-> LoggerConfig
|
|
||||||
-> IO ()
|
-> IO ()
|
||||||
brickMain s l = do
|
brickMain s = do
|
||||||
writeIORef settings' s
|
writeIORef settings' s
|
||||||
-- logger interpreter
|
|
||||||
writeIORef logger' l
|
|
||||||
let runLogger = myLoggerT l
|
|
||||||
|
|
||||||
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)
|
||||||
@@ -601,7 +578,7 @@ brickMain s l = do
|
|||||||
)
|
)
|
||||||
$> ()
|
$> ()
|
||||||
Left e -> do
|
Left e -> do
|
||||||
runLogger ($(logError) [i|Error building app state: #{show e}|])
|
flip runReaderT s $ logError $ "Error building app state: " <> T.pack (show e)
|
||||||
exitWith $ ExitFailure 2
|
exitWith $ ExitFailure 2
|
||||||
|
|
||||||
|
|
||||||
@@ -612,13 +589,10 @@ defaultAppSettings = BrickSettings { showAllVersions = False, showAllTools = Fal
|
|||||||
getGHCupInfo :: IO (Either String GHCupInfo)
|
getGHCupInfo :: IO (Either String GHCupInfo)
|
||||||
getGHCupInfo = do
|
getGHCupInfo = do
|
||||||
settings <- readIORef settings'
|
settings <- readIORef settings'
|
||||||
l <- readIORef logger'
|
|
||||||
let runLogger = myLoggerT l
|
|
||||||
|
|
||||||
r <-
|
r <-
|
||||||
runLogger
|
flip runReaderT settings
|
||||||
. flip runReaderT settings
|
. runE @'[DigestError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError]
|
||||||
. runE @'[JSONError , DownloadFailed , FileDoesNotExistError]
|
|
||||||
$ liftE
|
$ liftE
|
||||||
$ getDownloadsF
|
$ getDownloadsF
|
||||||
|
|
||||||
@@ -630,14 +604,11 @@ getGHCupInfo = do
|
|||||||
getAppData :: Maybe GHCupInfo
|
getAppData :: Maybe GHCupInfo
|
||||||
-> IO (Either String BrickData)
|
-> IO (Either String BrickData)
|
||||||
getAppData mgi = runExceptT $ do
|
getAppData mgi = runExceptT $ do
|
||||||
l <- liftIO $ readIORef logger'
|
|
||||||
let runLogger = myLoggerT l
|
|
||||||
|
|
||||||
r <- ExceptT $ maybe getGHCupInfo (pure . Right) mgi
|
r <- ExceptT $ maybe getGHCupInfo (pure . Right) mgi
|
||||||
liftIO $ modifyIORef settings' (\s -> s { ghcupInfo = r })
|
liftIO $ modifyIORef settings' (\s -> s { ghcupInfo = r })
|
||||||
settings <- liftIO $ readIORef settings'
|
settings <- liftIO $ readIORef settings'
|
||||||
|
|
||||||
runLogger . flip runReaderT settings $ do
|
flip runReaderT settings $ do
|
||||||
lV <- listVersions Nothing Nothing
|
lV <- listVersions Nothing Nothing
|
||||||
pure $ BrickData (reverse lV)
|
pure $ BrickData (reverse lV)
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -8,26 +8,27 @@ package ghcup
|
|||||||
tests: True
|
tests: True
|
||||||
flags: +tui
|
flags: +tui
|
||||||
|
|
||||||
source-repository-package
|
|
||||||
type: git
|
|
||||||
location: https://github.com/jtdaugherty/brick.git
|
|
||||||
tag: b3b96cfe66dfd398d338e3feb2b6855e66a35190
|
|
||||||
|
|
||||||
source-repository-package
|
|
||||||
type: git
|
|
||||||
location: https://github.com/Bodigrim/tar
|
|
||||||
tag: ac197ec7ea4838dc2b4e22b9b888b080cedf29cf
|
|
||||||
|
|
||||||
source-repository-package
|
source-repository-package
|
||||||
type: git
|
type: git
|
||||||
location: https://github.com/bgamari/terminal-size
|
location: https://github.com/bgamari/terminal-size
|
||||||
tag: 34ea816bd63f75f800eedac12c6908c6f3736036
|
tag: 34ea816bd63f75f800eedac12c6908c6f3736036
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/hasufell/libarchive
|
||||||
|
tag: 8587aab78dd515928024ecd82c8f215e06db85cd
|
||||||
|
|
||||||
constraints: http-io-streams -brotli
|
constraints: http-io-streams -brotli
|
||||||
|
|
||||||
package libarchive
|
package libarchive
|
||||||
flags: -system-libarchive
|
flags: -system-libarchive
|
||||||
|
|
||||||
|
package aeson-pretty
|
||||||
|
flags: +lib-only
|
||||||
|
|
||||||
|
package cabal-plan
|
||||||
|
flags: -exe
|
||||||
|
|
||||||
allow-newer: base, ghc-prim, template-haskell, language-c
|
allow-newer: base, ghc-prim, template-haskell, language-c
|
||||||
|
|
||||||
with-compiler: ghc-8.10.5
|
with-compiler: ghc-8.10.7
|
||||||
@@ -1,15 +1,18 @@
|
|||||||
active-repositories: hackage.haskell.org:merge
|
active-repositories: hackage.haskell.org:merge
|
||||||
constraints: any.Cabal ==3.2.1.0,
|
constraints: any.Cabal ==3.2.1.0,
|
||||||
any.HUnit ==1.6.2.0,
|
any.HUnit ==1.6.2.0,
|
||||||
any.HsOpenSSL ==0.11.7,
|
any.HsOpenSSL ==0.11.7.1,
|
||||||
HsOpenSSL -fast-bignum -homebrew-openssl -macports-openssl -use-pkg-config,
|
HsOpenSSL -fast-bignum -homebrew-openssl -macports-openssl -use-pkg-config,
|
||||||
|
any.HsYAML ==0.2.1.0,
|
||||||
|
HsYAML -exe,
|
||||||
|
any.HsYAML-aeson ==0.2.0.0,
|
||||||
any.QuickCheck ==2.14.2,
|
any.QuickCheck ==2.14.2,
|
||||||
QuickCheck -old-random +templatehaskell,
|
QuickCheck -old-random +templatehaskell,
|
||||||
any.StateVar ==1.2.2,
|
any.StateVar ==1.2.2,
|
||||||
any.aeson ==1.5.6.0,
|
any.aeson ==1.5.6.0,
|
||||||
aeson -bytestring-builder -cffi -developer -fast,
|
aeson -bytestring-builder -cffi -developer -fast,
|
||||||
any.aeson-pretty ==0.8.8,
|
any.aeson-pretty ==0.8.8,
|
||||||
aeson-pretty -lib-only,
|
aeson-pretty +lib-only,
|
||||||
any.alex ==3.2.6,
|
any.alex ==3.2.6,
|
||||||
alex +small_base,
|
alex +small_base,
|
||||||
any.ansi-terminal ==0.11,
|
any.ansi-terminal ==0.11,
|
||||||
@@ -22,8 +25,7 @@ constraints: any.Cabal ==3.2.1.0,
|
|||||||
async -bench,
|
async -bench,
|
||||||
any.attoparsec ==0.13.2.5,
|
any.attoparsec ==0.13.2.5,
|
||||||
attoparsec -developer,
|
attoparsec -developer,
|
||||||
any.auto-update ==0.1.6,
|
any.base ==4.14.3.0,
|
||||||
any.base ==4.14.2.0,
|
|
||||||
any.base-compat ==0.11.2,
|
any.base-compat ==0.11.2,
|
||||||
any.base-compat-batteries ==0.11.2,
|
any.base-compat-batteries ==0.11.2,
|
||||||
any.base-orphans ==0.8.4,
|
any.base-orphans ==0.8.4,
|
||||||
@@ -32,41 +34,34 @@ constraints: any.Cabal ==3.2.1.0,
|
|||||||
any.bifunctors ==5.5.11,
|
any.bifunctors ==5.5.11,
|
||||||
bifunctors +semigroups +tagged,
|
bifunctors +semigroups +tagged,
|
||||||
any.binary ==0.8.8.0,
|
any.binary ==0.8.8.0,
|
||||||
any.bindings-DSL ==1.0.25,
|
|
||||||
any.blaze-builder ==0.4.2.1,
|
any.blaze-builder ==0.4.2.1,
|
||||||
any.brick ==0.63,
|
any.brick ==0.64,
|
||||||
brick -demos,
|
brick -demos,
|
||||||
any.bytestring ==0.10.12.0,
|
any.bytestring ==0.10.12.0,
|
||||||
any.bz2 ==1.0.1.0,
|
any.bz2 ==1.0.1.0,
|
||||||
bz2 -cross +with-bzlib,
|
bz2 -cross +with-bzlib,
|
||||||
any.bzlib-conduit ==0.3.0.2,
|
|
||||||
any.c2hs ==0.28.8,
|
any.c2hs ==0.28.8,
|
||||||
c2hs +base3 -regression,
|
c2hs +base3 -regression,
|
||||||
|
any.cabal-plan ==0.7.2.0,
|
||||||
|
cabal-plan -_ -exe -license-report,
|
||||||
any.call-stack ==0.4.0,
|
any.call-stack ==0.4.0,
|
||||||
any.case-insensitive ==1.2.1.0,
|
any.case-insensitive ==1.2.1.0,
|
||||||
any.casing ==0.1.4.1,
|
any.casing ==0.1.4.1,
|
||||||
any.cereal ==0.5.8.1,
|
|
||||||
cereal -bytestring-builder,
|
|
||||||
any.chs-cabal ==0.1.1.0,
|
any.chs-cabal ==0.1.1.0,
|
||||||
any.chs-deps ==0.1.0.0,
|
any.chs-deps ==0.1.0.0,
|
||||||
chs-deps -cross,
|
chs-deps -cross,
|
||||||
any.clock ==0.8.2,
|
any.clock ==0.8.2,
|
||||||
clock -llvm,
|
clock -llvm,
|
||||||
any.cmdargs ==0.10.21,
|
|
||||||
cmdargs +quotation -testprog,
|
|
||||||
any.colour ==2.3.6,
|
any.colour ==2.3.6,
|
||||||
any.comonad ==5.0.8,
|
any.comonad ==5.0.8,
|
||||||
comonad +containers +distributive +indexed-traversable,
|
comonad +containers +distributive +indexed-traversable,
|
||||||
any.composition-prelude ==3.0.0.2,
|
any.composition-prelude ==3.0.0.2,
|
||||||
composition-prelude -development,
|
composition-prelude -development,
|
||||||
any.concurrent-output ==1.10.12,
|
any.concurrent-output ==1.10.12,
|
||||||
any.conduit ==1.3.4.1,
|
|
||||||
any.conduit-extra ==1.3.5,
|
|
||||||
any.conduit-zstd ==0.0.2.0,
|
|
||||||
any.config-ini ==0.2.4.0,
|
any.config-ini ==0.2.4.0,
|
||||||
config-ini -enable-doctests,
|
config-ini -enable-doctests,
|
||||||
any.containers ==0.6.4.1,
|
any.containers ==0.6.5.1,
|
||||||
any.contravariant ==1.5.4,
|
any.contravariant ==1.5.5,
|
||||||
contravariant +semigroups +statevar +tagged,
|
contravariant +semigroups +statevar +tagged,
|
||||||
any.cpphs ==1.20.9.1,
|
any.cpphs ==1.20.9.1,
|
||||||
cpphs -old-locale,
|
cpphs -old-locale,
|
||||||
@@ -74,44 +69,32 @@ constraints: any.Cabal ==3.2.1.0,
|
|||||||
any.cryptohash-sha256 ==0.11.102.0,
|
any.cryptohash-sha256 ==0.11.102.0,
|
||||||
cryptohash-sha256 -exe +use-cbits,
|
cryptohash-sha256 -exe +use-cbits,
|
||||||
any.data-clist ==0.1.2.3,
|
any.data-clist ==0.1.2.3,
|
||||||
any.data-default-class ==0.1.2.0,
|
any.data-fix ==0.3.2,
|
||||||
any.data-fix ==0.3.1,
|
|
||||||
any.deepseq ==1.4.4.0,
|
any.deepseq ==1.4.4.0,
|
||||||
any.digest ==0.0.1.3,
|
|
||||||
digest -bytestring-in-base,
|
|
||||||
any.directory ==1.3.6.0,
|
any.directory ==1.3.6.0,
|
||||||
any.disk-free-space ==0.1.0.1,
|
any.disk-free-space ==0.1.0.1,
|
||||||
any.distributive ==0.6.2.1,
|
any.distributive ==0.6.2.1,
|
||||||
distributive +semigroups +tagged,
|
distributive +semigroups +tagged,
|
||||||
any.dlist ==1.0,
|
any.dlist ==1.0,
|
||||||
dlist -werror,
|
dlist -werror,
|
||||||
any.easy-file ==0.2.2,
|
|
||||||
any.errors ==2.3.0,
|
|
||||||
any.exceptions ==0.10.4,
|
any.exceptions ==0.10.4,
|
||||||
any.extra ==1.7.9,
|
|
||||||
any.fast-logger ==3.0.5,
|
|
||||||
any.filepath ==1.4.2.1,
|
any.filepath ==1.4.2.1,
|
||||||
any.free ==5.1.7,
|
any.free ==5.1.7,
|
||||||
any.generic-arbitrary ==0.1.0,
|
any.generic-arbitrary ==0.1.0,
|
||||||
any.generics-sop ==0.5.1.1,
|
any.ghc-boot-th ==8.10.7,
|
||||||
any.ghc-boot-th ==8.10.5,
|
|
||||||
any.ghc-byteorder ==4.11.0.0.10,
|
any.ghc-byteorder ==4.11.0.0.10,
|
||||||
any.ghc-prim ==0.6.1,
|
any.ghc-prim ==0.6.1,
|
||||||
any.happy ==1.20.0,
|
any.happy ==1.20.0,
|
||||||
any.hashable ==1.3.2.0,
|
any.hashable ==1.3.3.0,
|
||||||
hashable +integer-gmp -random-initial-seed,
|
hashable +integer-gmp -random-initial-seed,
|
||||||
any.haskell-src-exts ==1.23.1,
|
|
||||||
any.haskell-src-meta ==0.8.7,
|
|
||||||
any.haskus-utils-data ==1.4,
|
any.haskus-utils-data ==1.4,
|
||||||
any.haskus-utils-types ==1.5.1,
|
any.haskus-utils-types ==1.5.1,
|
||||||
any.haskus-utils-variant ==3.1,
|
any.haskus-utils-variant ==3.1,
|
||||||
any.hpath-filepath ==0.10.4,
|
|
||||||
any.hpath-posix ==0.13.3,
|
|
||||||
any.hsc2hs ==0.68.7,
|
any.hsc2hs ==0.68.7,
|
||||||
hsc2hs -in-ghc-tree,
|
hsc2hs -in-ghc-tree,
|
||||||
any.hspec ==2.7.10,
|
any.hspec ==2.7.10,
|
||||||
any.hspec-core ==2.7.10,
|
any.hspec-core ==2.7.10,
|
||||||
any.hspec-discover ==2.7.10 || ==2.8.2,
|
any.hspec-discover ==2.7.10 || ==2.8.3,
|
||||||
any.hspec-expectations ==0.8.2,
|
any.hspec-expectations ==0.8.2,
|
||||||
any.hspec-golden-aeson ==0.9.0.0,
|
any.hspec-golden-aeson ==0.9.0.0,
|
||||||
any.http-io-streams ==0.1.6.0,
|
any.http-io-streams ==0.1.6.0,
|
||||||
@@ -128,34 +111,22 @@ constraints: any.Cabal ==3.2.1.0,
|
|||||||
language-c -allwarnings +iecfpextension +usebytestrings,
|
language-c -allwarnings +iecfpextension +usebytestrings,
|
||||||
any.libarchive ==3.0.2.2,
|
any.libarchive ==3.0.2.2,
|
||||||
libarchive -cross -low-memory -system-libarchive,
|
libarchive -cross -low-memory -system-libarchive,
|
||||||
any.libyaml ==0.1.2,
|
|
||||||
libyaml -no-unicode -system-libyaml,
|
|
||||||
any.lifted-base ==0.2.3.12,
|
|
||||||
any.lzma-static ==5.2.5.4,
|
any.lzma-static ==5.2.5.4,
|
||||||
any.megaparsec ==9.0.1,
|
any.megaparsec ==9.0.1,
|
||||||
megaparsec -dev,
|
megaparsec -dev,
|
||||||
any.microlens ==0.4.12.0,
|
any.microlens ==0.4.12.0,
|
||||||
any.microlens-mtl ==0.2.0.1,
|
any.microlens-mtl ==0.2.0.1,
|
||||||
any.microlens-th ==0.4.3.10,
|
any.microlens-th ==0.4.3.10,
|
||||||
any.monad-control ==1.0.3,
|
|
||||||
any.monad-logger ==0.3.36,
|
|
||||||
monad-logger +template_haskell,
|
|
||||||
any.monad-loops ==0.4.3,
|
|
||||||
monad-loops +base4,
|
|
||||||
any.mono-traversable ==1.0.15.1,
|
|
||||||
any.mtl ==2.2.2,
|
any.mtl ==2.2.2,
|
||||||
any.network ==3.1.2.2,
|
any.network ==3.1.2.2,
|
||||||
network -devel,
|
network -devel,
|
||||||
any.network-uri ==2.6.4.1,
|
any.network-uri ==2.6.4.1,
|
||||||
any.old-locale ==1.0.0.7,
|
|
||||||
any.old-time ==1.1.0.3,
|
|
||||||
any.openssl-streams ==1.2.3.0,
|
any.openssl-streams ==1.2.3.0,
|
||||||
any.optics ==0.4,
|
any.optics ==0.4,
|
||||||
any.optics-core ==0.4,
|
any.optics-core ==0.4,
|
||||||
optics-core -explicit-generic-labels,
|
optics-core -explicit-generic-labels,
|
||||||
any.optics-extra ==0.4,
|
any.optics-extra ==0.4,
|
||||||
any.optics-th ==0.4,
|
any.optics-th ==0.4,
|
||||||
any.optics-vl ==0.2.1,
|
|
||||||
any.optparse-applicative ==0.16.1.0,
|
any.optparse-applicative ==0.16.1.0,
|
||||||
optparse-applicative +process,
|
optparse-applicative +process,
|
||||||
any.os-release ==1.0.2,
|
any.os-release ==1.0.2,
|
||||||
@@ -167,8 +138,8 @@ constraints: any.Cabal ==3.2.1.0,
|
|||||||
any.polyparse ==1.13,
|
any.polyparse ==1.13,
|
||||||
any.pretty ==1.1.3.6,
|
any.pretty ==1.1.3.6,
|
||||||
any.pretty-terminal ==0.1.0.0,
|
any.pretty-terminal ==0.1.0.0,
|
||||||
any.primitive ==0.7.1.0,
|
any.primitive ==0.7.2.0,
|
||||||
any.process ==1.6.9.0,
|
any.process ==1.6.13.2,
|
||||||
any.profunctors ==5.6.2,
|
any.profunctors ==5.6.2,
|
||||||
any.quickcheck-arbitrary-adt ==0.3.1.0,
|
any.quickcheck-arbitrary-adt ==0.3.1.0,
|
||||||
any.quickcheck-io ==0.2.0,
|
any.quickcheck-io ==0.2.0,
|
||||||
@@ -178,7 +149,7 @@ constraints: any.Cabal ==3.2.1.0,
|
|||||||
any.regex-base ==0.94.0.1,
|
any.regex-base ==0.94.0.1,
|
||||||
any.regex-posix ==0.96.0.1,
|
any.regex-posix ==0.96.0.1,
|
||||||
regex-posix -_regex-posix-clib,
|
regex-posix -_regex-posix-clib,
|
||||||
any.resourcet ==1.2.4.2,
|
any.resourcet ==1.2.4.3,
|
||||||
any.rts ==1.0.1,
|
any.rts ==1.0.1,
|
||||||
any.safe ==0.3.19,
|
any.safe ==0.3.19,
|
||||||
any.safe-exceptions ==0.1.7.2,
|
any.safe-exceptions ==0.1.7.2,
|
||||||
@@ -187,55 +158,41 @@ constraints: any.Cabal ==3.2.1.0,
|
|||||||
any.semigroupoids ==5.3.5,
|
any.semigroupoids ==5.3.5,
|
||||||
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
|
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
|
||||||
any.setenv ==0.1.1.3,
|
any.setenv ==0.1.1.3,
|
||||||
any.sop-core ==0.5.0.1,
|
|
||||||
any.split ==0.2.3.4,
|
any.split ==0.2.3.4,
|
||||||
any.splitmix ==0.1.0.3,
|
any.splitmix ==0.1.0.3,
|
||||||
splitmix -optimised-mixer,
|
splitmix -optimised-mixer,
|
||||||
any.stm ==2.5.0.1,
|
any.stm ==2.5.0.1,
|
||||||
any.stm-chans ==3.0.0.4,
|
|
||||||
any.streaming-commons ==0.2.2.1,
|
|
||||||
streaming-commons -use-bytestring-builder,
|
|
||||||
any.strict ==0.4.0.1,
|
any.strict ==0.4.0.1,
|
||||||
strict +assoc,
|
strict +assoc,
|
||||||
any.strict-base ==0.4.0.0,
|
any.strict-base ==0.4.0.0,
|
||||||
any.string-interpolate ==0.3.1.1,
|
|
||||||
string-interpolate -bytestring-builder -extended-benchmarks -text-builder,
|
|
||||||
any.syb ==0.7.2.1,
|
|
||||||
any.tagged ==0.8.6.1,
|
any.tagged ==0.8.6.1,
|
||||||
tagged +deepseq +transformers,
|
tagged +deepseq +transformers,
|
||||||
any.tar ==0.6.0.0,
|
|
||||||
any.template-haskell ==2.16.0.0,
|
any.template-haskell ==2.16.0.0,
|
||||||
any.temporary ==1.3,
|
any.temporary ==1.3,
|
||||||
any.terminal-progress-bar ==0.4.1,
|
any.terminal-progress-bar ==0.4.1,
|
||||||
any.terminal-size ==0.3.2.1,
|
any.terminal-size ==0.3.2.1,
|
||||||
any.terminfo ==0.4.1.4,
|
any.terminfo ==0.4.1.4,
|
||||||
any.text ==1.2.4.1,
|
any.text ==1.2.4.1,
|
||||||
any.text-conversions ==0.3.1,
|
|
||||||
any.text-zipper ==0.11,
|
any.text-zipper ==0.11,
|
||||||
any.tf-random ==0.5,
|
any.tf-random ==0.5,
|
||||||
any.th-abstraction ==0.4.2.0,
|
any.th-abstraction ==0.4.2.0,
|
||||||
any.th-compat ==0.1.2,
|
any.th-compat ==0.1.2,
|
||||||
any.th-expand-syns ==0.4.8.0,
|
|
||||||
any.th-lift ==0.8.2,
|
any.th-lift ==0.8.2,
|
||||||
any.th-lift-instances ==0.1.18,
|
any.th-lift-instances ==0.1.18,
|
||||||
any.th-orphans ==0.13.11,
|
|
||||||
any.th-reify-many ==0.1.9,
|
|
||||||
any.these ==1.1.1.1,
|
any.these ==1.1.1.1,
|
||||||
these +assoc,
|
these +assoc,
|
||||||
any.time ==1.9.3,
|
any.time ==1.9.3,
|
||||||
any.time-compat ==1.9.6,
|
any.time-compat ==1.9.6,
|
||||||
time-compat -old-locale,
|
time-compat -old-locale,
|
||||||
any.transformers ==0.5.6.2,
|
any.transformers ==0.5.6.2,
|
||||||
any.transformers-base ==0.4.5.2,
|
any.transformers-base ==0.4.6,
|
||||||
transformers-base +orphaninstances,
|
transformers-base +orphaninstances,
|
||||||
any.transformers-compat ==0.7,
|
any.transformers-compat ==0.7,
|
||||||
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
||||||
any.typed-process ==0.2.6.0,
|
|
||||||
any.unix ==2.7.2.2,
|
any.unix ==2.7.2.2,
|
||||||
any.unix-bytestring ==0.3.7.3,
|
any.unix-bytestring ==0.3.7.3,
|
||||||
any.unix-compat ==0.5.3,
|
any.unix-compat ==0.5.3,
|
||||||
unix-compat -old-time,
|
unix-compat -old-time,
|
||||||
any.unix-time ==0.4.7,
|
|
||||||
any.unliftio-core ==0.2.0.1,
|
any.unliftio-core ==0.2.0.1,
|
||||||
any.unordered-containers ==0.2.14.0,
|
any.unordered-containers ==0.2.14.0,
|
||||||
unordered-containers -debug,
|
unordered-containers -debug,
|
||||||
@@ -245,20 +202,12 @@ constraints: any.Cabal ==3.2.1.0,
|
|||||||
any.uuid-types ==1.0.5,
|
any.uuid-types ==1.0.5,
|
||||||
any.vector ==0.12.3.0,
|
any.vector ==0.12.3.0,
|
||||||
vector +boundschecks -internalchecks -unsafechecks -wall,
|
vector +boundschecks -internalchecks -unsafechecks -wall,
|
||||||
any.vector-algorithms ==0.8.0.4,
|
|
||||||
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
|
|
||||||
any.versions ==5.0.0,
|
any.versions ==5.0.0,
|
||||||
any.vty ==5.33,
|
any.vty ==5.33,
|
||||||
any.word-wrap ==0.4.1,
|
any.word-wrap ==0.4.1,
|
||||||
any.word8 ==0.1.3,
|
any.word8 ==0.1.3,
|
||||||
any.xor ==0.0.1.0,
|
any.xor ==0.0.1.0,
|
||||||
any.yaml ==0.11.5.0,
|
|
||||||
yaml +no-examples +no-exe,
|
|
||||||
any.zip ==1.7.1,
|
|
||||||
zip -dev -disable-bzip2 -disable-zstd,
|
|
||||||
any.zlib ==0.6.2.3,
|
any.zlib ==0.6.2.3,
|
||||||
zlib -bundled-c-zlib -non-blocking-ffi -pkg-config,
|
zlib -bundled-c-zlib -non-blocking-ffi -pkg-config,
|
||||||
any.zlib-bindings ==0.1.1.5,
|
any.zlib-bindings ==0.1.1.5
|
||||||
any.zstd ==0.1.2.0,
|
index-state: hackage.haskell.org 2021-08-29T16:24:29Z
|
||||||
zstd +standalone
|
|
||||||
index-state: hackage.haskell.org 2021-07-27T07:59:57Z
|
|
||||||
@@ -8,26 +8,27 @@ package ghcup
|
|||||||
tests: True
|
tests: True
|
||||||
flags: +tui
|
flags: +tui
|
||||||
|
|
||||||
source-repository-package
|
|
||||||
type: git
|
|
||||||
location: https://github.com/jtdaugherty/brick.git
|
|
||||||
tag: b3b96cfe66dfd398d338e3feb2b6855e66a35190
|
|
||||||
|
|
||||||
source-repository-package
|
|
||||||
type: git
|
|
||||||
location: https://github.com/Bodigrim/tar
|
|
||||||
tag: ac197ec7ea4838dc2b4e22b9b888b080cedf29cf
|
|
||||||
|
|
||||||
source-repository-package
|
source-repository-package
|
||||||
type: git
|
type: git
|
||||||
location: https://github.com/bgamari/terminal-size
|
location: https://github.com/bgamari/terminal-size
|
||||||
tag: 34ea816bd63f75f800eedac12c6908c6f3736036
|
tag: 34ea816bd63f75f800eedac12c6908c6f3736036
|
||||||
|
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/hasufell/libarchive
|
||||||
|
tag: 8587aab78dd515928024ecd82c8f215e06db85cd
|
||||||
|
|
||||||
constraints: http-io-streams -brotli
|
constraints: http-io-streams -brotli
|
||||||
|
|
||||||
package libarchive
|
package libarchive
|
||||||
flags: -system-libarchive
|
flags: -system-libarchive
|
||||||
|
|
||||||
|
package aeson-pretty
|
||||||
|
flags: +lib-only
|
||||||
|
|
||||||
|
package cabal-plan
|
||||||
|
flags: -exe
|
||||||
|
|
||||||
allow-newer: base, ghc-prim, template-haskell, language-c
|
allow-newer: base, ghc-prim, template-haskell, language-c
|
||||||
|
|
||||||
with-compiler: ghc-9.0.1
|
with-compiler: ghc-9.0.1
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
active-repositories: hackage.haskell.org:merge
|
active-repositories: hackage.haskell.org:merge
|
||||||
constraints: any.Cabal ==3.4.0.0,
|
constraints: any.Cabal ==3.4.0.0,
|
||||||
any.HUnit ==1.6.2.0,
|
any.HUnit ==1.6.2.0,
|
||||||
any.HsOpenSSL ==0.11.7,
|
any.HsOpenSSL ==0.11.7.1,
|
||||||
HsOpenSSL -fast-bignum -homebrew-openssl -macports-openssl -use-pkg-config,
|
HsOpenSSL -fast-bignum -homebrew-openssl -macports-openssl -use-pkg-config,
|
||||||
|
any.HsYAML ==0.2.1.0,
|
||||||
|
HsYAML -exe,
|
||||||
|
any.HsYAML-aeson ==0.2.0.0,
|
||||||
any.QuickCheck ==2.14.2,
|
any.QuickCheck ==2.14.2,
|
||||||
QuickCheck -old-random +templatehaskell,
|
QuickCheck -old-random +templatehaskell,
|
||||||
any.StateVar ==1.2.2,
|
any.StateVar ==1.2.2,
|
||||||
any.aeson ==1.5.6.0,
|
any.aeson ==1.5.6.0,
|
||||||
aeson -bytestring-builder -cffi -developer -fast,
|
aeson -bytestring-builder -cffi -developer -fast,
|
||||||
any.aeson-pretty ==0.8.8,
|
any.aeson-pretty ==0.8.8,
|
||||||
aeson-pretty -lib-only,
|
aeson-pretty +lib-only,
|
||||||
any.alex ==3.2.6,
|
any.alex ==3.2.6,
|
||||||
alex +small_base,
|
alex +small_base,
|
||||||
any.ansi-terminal ==0.11,
|
any.ansi-terminal ==0.11,
|
||||||
@@ -22,7 +25,6 @@ constraints: any.Cabal ==3.4.0.0,
|
|||||||
async -bench,
|
async -bench,
|
||||||
any.attoparsec ==0.13.2.5,
|
any.attoparsec ==0.13.2.5,
|
||||||
attoparsec -developer,
|
attoparsec -developer,
|
||||||
any.auto-update ==0.1.6,
|
|
||||||
any.base ==4.15.0.0,
|
any.base ==4.15.0.0,
|
||||||
any.base-compat ==0.11.2,
|
any.base-compat ==0.11.2,
|
||||||
any.base-compat-batteries ==0.11.2,
|
any.base-compat-batteries ==0.11.2,
|
||||||
@@ -32,41 +34,34 @@ constraints: any.Cabal ==3.4.0.0,
|
|||||||
any.bifunctors ==5.5.11,
|
any.bifunctors ==5.5.11,
|
||||||
bifunctors +semigroups +tagged,
|
bifunctors +semigroups +tagged,
|
||||||
any.binary ==0.8.8.0,
|
any.binary ==0.8.8.0,
|
||||||
any.bindings-DSL ==1.0.25,
|
|
||||||
any.blaze-builder ==0.4.2.1,
|
any.blaze-builder ==0.4.2.1,
|
||||||
any.brick ==0.63,
|
any.brick ==0.64,
|
||||||
brick -demos,
|
brick -demos,
|
||||||
any.bytestring ==0.10.12.1,
|
any.bytestring ==0.10.12.1,
|
||||||
any.bz2 ==1.0.1.0,
|
any.bz2 ==1.0.1.0,
|
||||||
bz2 -cross +with-bzlib,
|
bz2 -cross +with-bzlib,
|
||||||
any.bzlib-conduit ==0.3.0.2,
|
|
||||||
any.c2hs ==0.28.8,
|
any.c2hs ==0.28.8,
|
||||||
c2hs +base3 -regression,
|
c2hs +base3 -regression,
|
||||||
|
any.cabal-plan ==0.7.2.0,
|
||||||
|
cabal-plan -_ -exe -license-report,
|
||||||
any.call-stack ==0.4.0,
|
any.call-stack ==0.4.0,
|
||||||
any.case-insensitive ==1.2.1.0,
|
any.case-insensitive ==1.2.1.0,
|
||||||
any.casing ==0.1.4.1,
|
any.casing ==0.1.4.1,
|
||||||
any.cereal ==0.5.8.1,
|
|
||||||
cereal -bytestring-builder,
|
|
||||||
any.chs-cabal ==0.1.1.0,
|
any.chs-cabal ==0.1.1.0,
|
||||||
any.chs-deps ==0.1.0.0,
|
any.chs-deps ==0.1.0.0,
|
||||||
chs-deps -cross,
|
chs-deps -cross,
|
||||||
any.clock ==0.8.2,
|
any.clock ==0.8.2,
|
||||||
clock -llvm,
|
clock -llvm,
|
||||||
any.cmdargs ==0.10.21,
|
|
||||||
cmdargs +quotation -testprog,
|
|
||||||
any.colour ==2.3.6,
|
any.colour ==2.3.6,
|
||||||
any.comonad ==5.0.8,
|
any.comonad ==5.0.8,
|
||||||
comonad +containers +distributive +indexed-traversable,
|
comonad +containers +distributive +indexed-traversable,
|
||||||
any.composition-prelude ==3.0.0.2,
|
any.composition-prelude ==3.0.0.2,
|
||||||
composition-prelude -development,
|
composition-prelude -development,
|
||||||
any.concurrent-output ==1.10.12,
|
any.concurrent-output ==1.10.12,
|
||||||
any.conduit ==1.3.4.1,
|
|
||||||
any.conduit-extra ==1.3.5,
|
|
||||||
any.conduit-zstd ==0.0.2.0,
|
|
||||||
any.config-ini ==0.2.4.0,
|
any.config-ini ==0.2.4.0,
|
||||||
config-ini -enable-doctests,
|
config-ini -enable-doctests,
|
||||||
any.containers ==0.6.4.1,
|
any.containers ==0.6.4.1,
|
||||||
any.contravariant ==1.5.4,
|
any.contravariant ==1.5.5,
|
||||||
contravariant +semigroups +statevar +tagged,
|
contravariant +semigroups +statevar +tagged,
|
||||||
any.cpphs ==1.20.9.1,
|
any.cpphs ==1.20.9.1,
|
||||||
cpphs -old-locale,
|
cpphs -old-locale,
|
||||||
@@ -74,45 +69,33 @@ constraints: any.Cabal ==3.4.0.0,
|
|||||||
any.cryptohash-sha256 ==0.11.102.0,
|
any.cryptohash-sha256 ==0.11.102.0,
|
||||||
cryptohash-sha256 -exe +use-cbits,
|
cryptohash-sha256 -exe +use-cbits,
|
||||||
any.data-clist ==0.1.2.3,
|
any.data-clist ==0.1.2.3,
|
||||||
any.data-default-class ==0.1.2.0,
|
any.data-fix ==0.3.2,
|
||||||
any.data-fix ==0.3.1,
|
|
||||||
any.deepseq ==1.4.5.0,
|
any.deepseq ==1.4.5.0,
|
||||||
any.digest ==0.0.1.3,
|
|
||||||
digest -bytestring-in-base,
|
|
||||||
any.directory ==1.3.6.1,
|
any.directory ==1.3.6.1,
|
||||||
any.disk-free-space ==0.1.0.1,
|
any.disk-free-space ==0.1.0.1,
|
||||||
any.distributive ==0.6.2.1,
|
any.distributive ==0.6.2.1,
|
||||||
distributive +semigroups +tagged,
|
distributive +semigroups +tagged,
|
||||||
any.dlist ==1.0,
|
any.dlist ==1.0,
|
||||||
dlist -werror,
|
dlist -werror,
|
||||||
any.easy-file ==0.2.2,
|
|
||||||
any.errors ==2.3.0,
|
|
||||||
any.exceptions ==0.10.4,
|
any.exceptions ==0.10.4,
|
||||||
any.extra ==1.7.9,
|
|
||||||
any.fast-logger ==3.0.5,
|
|
||||||
any.filepath ==1.4.2.1,
|
any.filepath ==1.4.2.1,
|
||||||
any.free ==5.1.7,
|
any.free ==5.1.7,
|
||||||
any.generic-arbitrary ==0.1.0,
|
any.generic-arbitrary ==0.1.0,
|
||||||
any.generics-sop ==0.5.1.1,
|
|
||||||
any.ghc-bignum ==1.0,
|
any.ghc-bignum ==1.0,
|
||||||
any.ghc-boot-th ==9.0.1,
|
any.ghc-boot-th ==9.0.1,
|
||||||
any.ghc-byteorder ==4.11.0.0.10,
|
any.ghc-byteorder ==4.11.0.0.10,
|
||||||
any.ghc-prim ==0.7.0,
|
any.ghc-prim ==0.7.0,
|
||||||
any.happy ==1.20.0,
|
any.happy ==1.20.0,
|
||||||
any.hashable ==1.3.2.0,
|
any.hashable ==1.3.3.0,
|
||||||
hashable +integer-gmp -random-initial-seed,
|
hashable +integer-gmp -random-initial-seed,
|
||||||
any.haskell-src-exts ==1.23.1,
|
|
||||||
any.haskell-src-meta ==0.8.7,
|
|
||||||
any.haskus-utils-data ==1.4,
|
any.haskus-utils-data ==1.4,
|
||||||
any.haskus-utils-types ==1.5.1,
|
any.haskus-utils-types ==1.5.1,
|
||||||
any.haskus-utils-variant ==3.1,
|
any.haskus-utils-variant ==3.1,
|
||||||
any.hpath-filepath ==0.10.4,
|
|
||||||
any.hpath-posix ==0.13.3,
|
|
||||||
any.hsc2hs ==0.68.7,
|
any.hsc2hs ==0.68.7,
|
||||||
hsc2hs -in-ghc-tree,
|
hsc2hs -in-ghc-tree,
|
||||||
any.hspec ==2.7.10,
|
any.hspec ==2.7.10,
|
||||||
any.hspec-core ==2.7.10,
|
any.hspec-core ==2.7.10,
|
||||||
any.hspec-discover ==2.7.10 || ==2.8.2,
|
any.hspec-discover ==2.7.10 || ==2.8.3,
|
||||||
any.hspec-expectations ==0.8.2,
|
any.hspec-expectations ==0.8.2,
|
||||||
any.hspec-golden-aeson ==0.9.0.0,
|
any.hspec-golden-aeson ==0.9.0.0,
|
||||||
any.http-io-streams ==0.1.6.0,
|
any.http-io-streams ==0.1.6.0,
|
||||||
@@ -128,34 +111,22 @@ constraints: any.Cabal ==3.4.0.0,
|
|||||||
language-c -allwarnings +iecfpextension +usebytestrings,
|
language-c -allwarnings +iecfpextension +usebytestrings,
|
||||||
any.libarchive ==3.0.2.2,
|
any.libarchive ==3.0.2.2,
|
||||||
libarchive -cross -low-memory -system-libarchive,
|
libarchive -cross -low-memory -system-libarchive,
|
||||||
any.libyaml ==0.1.2,
|
|
||||||
libyaml -no-unicode -system-libyaml,
|
|
||||||
any.lifted-base ==0.2.3.12,
|
|
||||||
any.lzma-static ==5.2.5.4,
|
any.lzma-static ==5.2.5.4,
|
||||||
any.megaparsec ==9.0.1,
|
any.megaparsec ==9.0.1,
|
||||||
megaparsec -dev,
|
megaparsec -dev,
|
||||||
any.microlens ==0.4.12.0,
|
any.microlens ==0.4.12.0,
|
||||||
any.microlens-mtl ==0.2.0.1,
|
any.microlens-mtl ==0.2.0.1,
|
||||||
any.microlens-th ==0.4.3.10,
|
any.microlens-th ==0.4.3.10,
|
||||||
any.monad-control ==1.0.3,
|
|
||||||
any.monad-logger ==0.3.36,
|
|
||||||
monad-logger +template_haskell,
|
|
||||||
any.monad-loops ==0.4.3,
|
|
||||||
monad-loops +base4,
|
|
||||||
any.mono-traversable ==1.0.15.1,
|
|
||||||
any.mtl ==2.2.2,
|
any.mtl ==2.2.2,
|
||||||
any.network ==3.1.2.2,
|
any.network ==3.1.2.2,
|
||||||
network -devel,
|
network -devel,
|
||||||
any.network-uri ==2.6.4.1,
|
any.network-uri ==2.6.4.1,
|
||||||
any.old-locale ==1.0.0.7,
|
|
||||||
any.old-time ==1.1.0.3,
|
|
||||||
any.openssl-streams ==1.2.3.0,
|
any.openssl-streams ==1.2.3.0,
|
||||||
any.optics ==0.4,
|
any.optics ==0.4,
|
||||||
any.optics-core ==0.4,
|
any.optics-core ==0.4,
|
||||||
optics-core -explicit-generic-labels,
|
optics-core -explicit-generic-labels,
|
||||||
any.optics-extra ==0.4,
|
any.optics-extra ==0.4,
|
||||||
any.optics-th ==0.4,
|
any.optics-th ==0.4,
|
||||||
any.optics-vl ==0.2.1,
|
|
||||||
any.optparse-applicative ==0.16.1.0,
|
any.optparse-applicative ==0.16.1.0,
|
||||||
optparse-applicative +process,
|
optparse-applicative +process,
|
||||||
any.os-release ==1.0.2,
|
any.os-release ==1.0.2,
|
||||||
@@ -167,7 +138,7 @@ constraints: any.Cabal ==3.4.0.0,
|
|||||||
any.polyparse ==1.13,
|
any.polyparse ==1.13,
|
||||||
any.pretty ==1.1.3.6,
|
any.pretty ==1.1.3.6,
|
||||||
any.pretty-terminal ==0.1.0.0,
|
any.pretty-terminal ==0.1.0.0,
|
||||||
any.primitive ==0.7.1.0,
|
any.primitive ==0.7.2.0,
|
||||||
any.process ==1.6.11.0,
|
any.process ==1.6.11.0,
|
||||||
any.profunctors ==5.6.2,
|
any.profunctors ==5.6.2,
|
||||||
any.quickcheck-arbitrary-adt ==0.3.1.0,
|
any.quickcheck-arbitrary-adt ==0.3.1.0,
|
||||||
@@ -178,7 +149,7 @@ constraints: any.Cabal ==3.4.0.0,
|
|||||||
any.regex-base ==0.94.0.1,
|
any.regex-base ==0.94.0.1,
|
||||||
any.regex-posix ==0.96.0.1,
|
any.regex-posix ==0.96.0.1,
|
||||||
regex-posix -_regex-posix-clib,
|
regex-posix -_regex-posix-clib,
|
||||||
any.resourcet ==1.2.4.2,
|
any.resourcet ==1.2.4.3,
|
||||||
any.rts ==1.0,
|
any.rts ==1.0,
|
||||||
any.safe ==0.3.19,
|
any.safe ==0.3.19,
|
||||||
any.safe-exceptions ==0.1.7.2,
|
any.safe-exceptions ==0.1.7.2,
|
||||||
@@ -187,55 +158,41 @@ constraints: any.Cabal ==3.4.0.0,
|
|||||||
any.semigroupoids ==5.3.5,
|
any.semigroupoids ==5.3.5,
|
||||||
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
|
semigroupoids +comonad +containers +contravariant +distributive +tagged +unordered-containers,
|
||||||
any.setenv ==0.1.1.3,
|
any.setenv ==0.1.1.3,
|
||||||
any.sop-core ==0.5.0.1,
|
|
||||||
any.split ==0.2.3.4,
|
any.split ==0.2.3.4,
|
||||||
any.splitmix ==0.1.0.3,
|
any.splitmix ==0.1.0.3,
|
||||||
splitmix -optimised-mixer,
|
splitmix -optimised-mixer,
|
||||||
any.stm ==2.5.0.0,
|
any.stm ==2.5.0.0,
|
||||||
any.stm-chans ==3.0.0.4,
|
|
||||||
any.streaming-commons ==0.2.2.1,
|
|
||||||
streaming-commons -use-bytestring-builder,
|
|
||||||
any.strict ==0.4.0.1,
|
any.strict ==0.4.0.1,
|
||||||
strict +assoc,
|
strict +assoc,
|
||||||
any.strict-base ==0.4.0.0,
|
any.strict-base ==0.4.0.0,
|
||||||
any.string-interpolate ==0.3.1.1,
|
|
||||||
string-interpolate -bytestring-builder -extended-benchmarks -text-builder,
|
|
||||||
any.syb ==0.7.2.1,
|
|
||||||
any.tagged ==0.8.6.1,
|
any.tagged ==0.8.6.1,
|
||||||
tagged +deepseq +transformers,
|
tagged +deepseq +transformers,
|
||||||
any.tar ==0.6.0.0,
|
|
||||||
any.template-haskell ==2.17.0.0,
|
any.template-haskell ==2.17.0.0,
|
||||||
any.temporary ==1.3,
|
any.temporary ==1.3,
|
||||||
any.terminal-progress-bar ==0.4.1,
|
any.terminal-progress-bar ==0.4.1,
|
||||||
any.terminal-size ==0.3.2.1,
|
any.terminal-size ==0.3.2.1,
|
||||||
any.terminfo ==0.4.1.4,
|
any.terminfo ==0.4.1.4,
|
||||||
any.text ==1.2.4.1,
|
any.text ==1.2.4.1,
|
||||||
any.text-conversions ==0.3.1,
|
|
||||||
any.text-zipper ==0.11,
|
any.text-zipper ==0.11,
|
||||||
any.tf-random ==0.5,
|
any.tf-random ==0.5,
|
||||||
any.th-abstraction ==0.4.2.0,
|
any.th-abstraction ==0.4.2.0,
|
||||||
any.th-compat ==0.1.2,
|
any.th-compat ==0.1.2,
|
||||||
any.th-expand-syns ==0.4.8.0,
|
|
||||||
any.th-lift ==0.8.2,
|
any.th-lift ==0.8.2,
|
||||||
any.th-lift-instances ==0.1.18,
|
any.th-lift-instances ==0.1.18,
|
||||||
any.th-orphans ==0.13.11,
|
|
||||||
any.th-reify-many ==0.1.9,
|
|
||||||
any.these ==1.1.1.1,
|
any.these ==1.1.1.1,
|
||||||
these +assoc,
|
these +assoc,
|
||||||
any.time ==1.9.3,
|
any.time ==1.9.3,
|
||||||
any.time-compat ==1.9.6,
|
any.time-compat ==1.9.6,
|
||||||
time-compat -old-locale,
|
time-compat -old-locale,
|
||||||
any.transformers ==0.5.6.2,
|
any.transformers ==0.5.6.2,
|
||||||
any.transformers-base ==0.4.5.2,
|
any.transformers-base ==0.4.6,
|
||||||
transformers-base +orphaninstances,
|
transformers-base +orphaninstances,
|
||||||
any.transformers-compat ==0.7,
|
any.transformers-compat ==0.7,
|
||||||
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
transformers-compat -five +five-three -four +generic-deriving +mtl -three -two,
|
||||||
any.typed-process ==0.2.6.0,
|
|
||||||
any.unix ==2.7.2.2,
|
any.unix ==2.7.2.2,
|
||||||
any.unix-bytestring ==0.3.7.3,
|
any.unix-bytestring ==0.3.7.3,
|
||||||
any.unix-compat ==0.5.3,
|
any.unix-compat ==0.5.3,
|
||||||
unix-compat -old-time,
|
unix-compat -old-time,
|
||||||
any.unix-time ==0.4.7,
|
|
||||||
any.unliftio-core ==0.2.0.1,
|
any.unliftio-core ==0.2.0.1,
|
||||||
any.unordered-containers ==0.2.14.0,
|
any.unordered-containers ==0.2.14.0,
|
||||||
unordered-containers -debug,
|
unordered-containers -debug,
|
||||||
@@ -245,20 +202,12 @@ constraints: any.Cabal ==3.4.0.0,
|
|||||||
any.uuid-types ==1.0.5,
|
any.uuid-types ==1.0.5,
|
||||||
any.vector ==0.12.3.0,
|
any.vector ==0.12.3.0,
|
||||||
vector +boundschecks -internalchecks -unsafechecks -wall,
|
vector +boundschecks -internalchecks -unsafechecks -wall,
|
||||||
any.vector-algorithms ==0.8.0.4,
|
|
||||||
vector-algorithms +bench +boundschecks -internalchecks -llvm +properties -unsafechecks,
|
|
||||||
any.versions ==5.0.0,
|
any.versions ==5.0.0,
|
||||||
any.vty ==5.33,
|
any.vty ==5.33,
|
||||||
any.word-wrap ==0.4.1,
|
any.word-wrap ==0.4.1,
|
||||||
any.word8 ==0.1.3,
|
any.word8 ==0.1.3,
|
||||||
any.xor ==0.0.1.0,
|
any.xor ==0.0.1.0,
|
||||||
any.yaml ==0.11.5.0,
|
|
||||||
yaml +no-examples +no-exe,
|
|
||||||
any.zip ==1.7.1,
|
|
||||||
zip -dev -disable-bzip2 -disable-zstd,
|
|
||||||
any.zlib ==0.6.2.3,
|
any.zlib ==0.6.2.3,
|
||||||
zlib -bundled-c-zlib -non-blocking-ffi -pkg-config,
|
zlib -bundled-c-zlib -non-blocking-ffi -pkg-config,
|
||||||
any.zlib-bindings ==0.1.1.5,
|
any.zlib-bindings ==0.1.1.5
|
||||||
any.zstd ==0.1.2.0,
|
index-state: hackage.haskell.org 2021-08-29T16:24:29Z
|
||||||
zstd +standalone
|
|
||||||
index-state: hackage.haskell.org 2021-07-27T07:59:57Z
|
|
||||||
|
|||||||
@@ -10,22 +10,18 @@ package ghcup
|
|||||||
|
|
||||||
source-repository-package
|
source-repository-package
|
||||||
type: git
|
type: git
|
||||||
location: https://github.com/jtdaugherty/brick.git
|
location: https://github.com/hasufell/libarchive
|
||||||
tag: b3b96cfe66dfd398d338e3feb2b6855e66a35190
|
tag: 8587aab78dd515928024ecd82c8f215e06db85cd
|
||||||
|
|
||||||
source-repository-package
|
|
||||||
type: git
|
|
||||||
location: https://github.com/Bodigrim/tar
|
|
||||||
tag: ac197ec7ea4838dc2b4e22b9b888b080cedf29cf
|
|
||||||
|
|
||||||
source-repository-package
|
|
||||||
type: git
|
|
||||||
location: https://github.com/bgamari/terminal-size
|
|
||||||
tag: 34ea816bd63f75f800eedac12c6908c6f3736036
|
|
||||||
|
|
||||||
constraints: http-io-streams -brotli
|
constraints: http-io-streams -brotli
|
||||||
|
|
||||||
package libarchive
|
package libarchive
|
||||||
flags: -system-libarchive
|
flags: -system-libarchive
|
||||||
|
|
||||||
|
package aeson-pretty
|
||||||
|
flags: +lib-only
|
||||||
|
|
||||||
|
package cabal-plan
|
||||||
|
flags: -exe
|
||||||
|
|
||||||
allow-newer: base, ghc-prim, template-haskell, language-c
|
allow-newer: base, ghc-prim, template-haskell, language-c
|
||||||
|
|||||||
9
data/build_mk/cross
Normal file
9
data/build_mk/cross
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
V=0
|
||||||
|
BUILD_MAN = NO
|
||||||
|
BUILD_SPHINX_HTML = NO
|
||||||
|
BUILD_SPHINX_PDF = NO
|
||||||
|
HADDOCK_DOCS = NO
|
||||||
|
ifneq "$(BuildFlavour)" ""
|
||||||
|
include mk/flavours/$(BuildFlavour).mk
|
||||||
|
endif
|
||||||
|
Stage1Only = YES
|
||||||
8
data/build_mk/default
Normal file
8
data/build_mk/default
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
V=0
|
||||||
|
BUILD_MAN = NO
|
||||||
|
BUILD_SPHINX_HTML = NO
|
||||||
|
BUILD_SPHINX_PDF = NO
|
||||||
|
HADDOCK_DOCS = YES
|
||||||
|
ifneq "$(BuildFlavour)" ""
|
||||||
|
include mk/flavours/$(BuildFlavour).mk
|
||||||
|
endif
|
||||||
@@ -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:
|
||||||
@@ -1690,7 +1693,6 @@ ghcupDownloads:
|
|||||||
dlHash: 56170d1a8450e18b7eb9c23c94723da352815b27ec250bb23742a62f16dcab6c
|
dlHash: 56170d1a8450e18b7eb9c23c94723da352815b27ec250bb23742a62f16dcab6c
|
||||||
8.10.6:
|
8.10.6:
|
||||||
viTags:
|
viTags:
|
||||||
- Recommended
|
|
||||||
- base-4.14.3.0
|
- base-4.14.3.0
|
||||||
viChangeLog: https://downloads.haskell.org/~ghc/8.10.6/docs/html/users_guide/8.10.6-notes.html
|
viChangeLog: https://downloads.haskell.org/~ghc/8.10.6/docs/html/users_guide/8.10.6-notes.html
|
||||||
viSourceDL:
|
viSourceDL:
|
||||||
@@ -1699,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:
|
||||||
@@ -1789,6 +1792,107 @@ ghcupDownloads:
|
|||||||
dlUri: https://downloads.haskell.org/~ghc/8.10.6/ghc-8.10.6-armv7-deb10-linux.tar.xz
|
dlUri: https://downloads.haskell.org/~ghc/8.10.6/ghc-8.10.6-armv7-deb10-linux.tar.xz
|
||||||
dlSubdir: ghc-8.10.6
|
dlSubdir: ghc-8.10.6
|
||||||
dlHash: d54de8306aa8b33afabf2ac94408e1f82c8e982a2a3346168c071b92bdb464c0
|
dlHash: d54de8306aa8b33afabf2ac94408e1f82c8e982a2a3346168c071b92bdb464c0
|
||||||
|
8.10.7:
|
||||||
|
viTags:
|
||||||
|
- Recommended
|
||||||
|
- base-4.14.3.0
|
||||||
|
viChangeLog: https://downloads.haskell.org/~ghc/8.10.7/docs/html/users_guide/8.10.7-notes.html
|
||||||
|
viSourceDL:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.7/ghc-8.10.7-src.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.7
|
||||||
|
dlHash: e3eef6229ce9908dfe1ea41436befb0455fefb1932559e860ad4c606b0d03c9d
|
||||||
|
viPostRemove: *ghc-post-remove
|
||||||
|
viPreCompile: *ghc-pre-compile
|
||||||
|
viArch:
|
||||||
|
A_64:
|
||||||
|
Linux_Debian:
|
||||||
|
'( >= 9 && < 10 )': &ghc-8107-64-deb9
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.7/ghc-8.10.7-x86_64-deb9-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.7
|
||||||
|
dlHash: ced9870ea351af64fb48274b81a664cdb6a9266775f1598a79cbb6fdd5770a23
|
||||||
|
'( >= 10 && < 11 )': &ghc-8107-64-deb10
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.7/ghc-8.10.7-x86_64-deb10-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.7
|
||||||
|
dlHash: a13719bca87a0d3ac0c7d4157a4e60887009a7f1a8dbe95c4759ec413e086d30
|
||||||
|
unknown_versioning: *ghc-8107-64-deb9
|
||||||
|
Linux_Ubuntu:
|
||||||
|
unknown_versioning: &ghc-8107-64-fedora
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.7/ghc-8.10.7-x86_64-fedora27-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.7
|
||||||
|
dlHash: b6ed67049a23054a8042e65c9976d5e196e5ee4e83b29b2ee35c8a22ab1e5b73
|
||||||
|
'( >= 16 && < 19 )': *ghc-8107-64-deb9
|
||||||
|
Linux_Mint:
|
||||||
|
unknown_versioning: *ghc-8107-64-deb10
|
||||||
|
Linux_Fedora:
|
||||||
|
'( >= 27 && < 28 )': *ghc-8107-64-fedora
|
||||||
|
unknown_versioning: *ghc-8107-64-fedora
|
||||||
|
Linux_CentOS:
|
||||||
|
'( >= 7 && < 8 )': &ghc-8107-64-centos
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.7/ghc-8.10.7-x86_64-centos7-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.7
|
||||||
|
dlHash: 262a50bfb5b7c8770e0d99f54d42e5876968da7bf93e2e4d6cfe397891a36d05
|
||||||
|
unknown_versioning: *ghc-8107-64-centos
|
||||||
|
Linux_RedHat:
|
||||||
|
unknown_versioning: *ghc-8107-64-centos
|
||||||
|
Linux_Alpine:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.7/ghc-8.10.7-x86_64-alpine3.10-linux-integer-simple.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.7-x86_64-unknown-linux
|
||||||
|
dlHash: 16903df850ef73d5246f2ff169cbf57ecab76c2ac5acfa9928934282cfad575c
|
||||||
|
Linux_AmazonLinux:
|
||||||
|
unknown_versioning: *ghc-8107-64-centos
|
||||||
|
Linux_UnknownLinux:
|
||||||
|
unknown_versioning: *ghc-8107-64-fedora
|
||||||
|
Darwin:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.7/ghc-8.10.7-x86_64-apple-darwin.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.7
|
||||||
|
dlHash: 287db0f9c338c9f53123bfa8731b0996803ee50f6ee847fe388092e5e5132047
|
||||||
|
FreeBSD:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.7/ghc-8.10.7-x86_64-unknown-freebsd.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.7
|
||||||
|
dlHash: 45e35d24bc700e1093efa39189e9fa01498069881aed2fa8779c011941a80da1
|
||||||
|
Windows:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.7/ghc-8.10.7-x86_64-unknown-mingw32.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.7
|
||||||
|
dlHash: b6515b0ea3f7a6e34d92e7fcd0c1fef50d6030fe8f46883000185289a4b8ea9a
|
||||||
|
A_32:
|
||||||
|
Linux_Debian:
|
||||||
|
'( >= 9 && < 10 )': &ghc-8107-32-deb9
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.7/ghc-8.10.7-i386-deb9-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.7
|
||||||
|
dlHash: fbfc1ef194f4e7a4c0da8c11cc69b17458a4b928b609b3622c97acc4acd5c5ab
|
||||||
|
unknown_versioning: *ghc-8107-32-deb9
|
||||||
|
Linux_Ubuntu:
|
||||||
|
unknown_versioning: *ghc-8107-32-deb9
|
||||||
|
Linux_Mint:
|
||||||
|
unknown_versioning: *ghc-8107-32-deb9
|
||||||
|
Linux_UnknownLinux:
|
||||||
|
unknown_versioning: *ghc-8107-32-deb9
|
||||||
|
Linux_Alpine:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghcup/unofficial-bindists/ghc/8.10.7/ghc-8.10.7-i386-alpine-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.7
|
||||||
|
dlHash: 3110e6ee029d9d8062158b54b06f71a21b0fac87bf0e085f9be5bbcf73f99e6d
|
||||||
|
A_ARM64:
|
||||||
|
Linux_UnknownLinux:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.7/ghc-8.10.7-aarch64-deb10-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.7
|
||||||
|
dlHash: fad2417f9b295233bf8ade79c0e6140896359e87be46cb61cd1d35863d9d0e55
|
||||||
|
Darwin:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.7/ghc-8.10.7-aarch64-apple-darwin.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.7
|
||||||
|
dlHash: dc469fc3c35fd2a33a5a575ffce87f13de7b98c2d349a41002e200a56d9bba1c
|
||||||
|
A_ARM:
|
||||||
|
Linux_UnknownLinux:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghc/8.10.7/ghc-8.10.7-armv7-deb10-linux.tar.xz
|
||||||
|
dlSubdir: ghc-8.10.7
|
||||||
|
dlHash: 3949c31bdf7d3b4afb765ea8246bca4ca9707c5d988d9961a244f0da100956a2
|
||||||
9.0.1:
|
9.0.1:
|
||||||
viTags:
|
viTags:
|
||||||
- Latest
|
- Latest
|
||||||
@@ -2072,7 +2176,6 @@ ghcupDownloads:
|
|||||||
3.4.0.0:
|
3.4.0.0:
|
||||||
viTags:
|
viTags:
|
||||||
- Recommended
|
- Recommended
|
||||||
- Latest
|
|
||||||
viChangeLog: https://github.com/haskell/cabal/blob/master/release-notes/cabal-install-3.4.0.0.md
|
viChangeLog: https://github.com/haskell/cabal/blob/master/release-notes/cabal-install-3.4.0.0.md
|
||||||
viArch:
|
viArch:
|
||||||
A_64:
|
A_64:
|
||||||
@@ -2121,8 +2224,52 @@ ghcupDownloads:
|
|||||||
unknown_versioning:
|
unknown_versioning:
|
||||||
dlUri: https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal/3.4.0.0/cabal-install-3.4.0.0-armv7-linux-bootstrapped.tar.xz
|
dlUri: https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal/3.4.0.0/cabal-install-3.4.0.0-armv7-linux-bootstrapped.tar.xz
|
||||||
dlHash: 16c0d1eaba24bed14f3e152970179a45d9f9bb5cc839b2c210ad06eb7d4826ed
|
dlHash: 16c0d1eaba24bed14f3e152970179a45d9f9bb5cc839b2c210ad06eb7d4826ed
|
||||||
|
3.6.0.0:
|
||||||
|
viTags:
|
||||||
|
- Latest
|
||||||
|
viChangeLog: https://github.com/haskell/cabal/blob/master/release-notes/cabal-install-3.6.0.0.md
|
||||||
|
viArch:
|
||||||
|
A_64:
|
||||||
|
Linux_UnknownLinux:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~cabal/cabal-install-3.6.0.0/cabal-install-3.6.0.0-x86_64-linux.tar.xz
|
||||||
|
dlHash: bfcb7350966dafe95051b5fc9fcb989c5708ab9e78191e71fc04647061668a11
|
||||||
|
Linux_Alpine:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~cabal/cabal-install-3.6.0.0/cabal-install-3.6.0.0-x86_64-linux-alpine.tar.xz
|
||||||
|
dlHash: 3203d71b7ee87fc9dce74b452ae07f420afe8817b5e6f84e54798442f4ccdda8
|
||||||
|
Darwin:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~cabal/cabal-install-3.6.0.0/cabal-install-3.6.0.0-x86_64-darwin.tar.xz
|
||||||
|
dlHash: 8e1367a4a1fc86ff0fd82ee057320a7b974595ba7999457b42035467ba06190c
|
||||||
|
FreeBSD:
|
||||||
|
'( >= 12 && < 13 )':
|
||||||
|
dlUri: https://downloads.haskell.org/~cabal/cabal-install-3.6.0.0/cabal-install-3.6.0.0-x86_64-freebsd.tar.xz
|
||||||
|
dlHash: 56b5b37396c16a29f164a6963f24bd88f09e1d37448542ed61a683325f0a868b
|
||||||
|
'( >= 13 )':
|
||||||
|
dlUri: https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal/3.6.0.0/cabal-install-3.6.0.0-x86_64-freebsd13.tar.xz
|
||||||
|
dlHash: a283aa498702a3e286aa08e004c2a389538cbb47ec7096a25682fb7d57f6bb7f
|
||||||
|
Windows:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~cabal/cabal-install-3.6.0.0/cabal-install-3.6.0.0-x86_64-windows.zip
|
||||||
|
dlSubdir:
|
||||||
|
dlHash: 8222b49b6eac3d06aaa390bc688f467e8f949a38943567f46246f8320fd72ded
|
||||||
|
A_ARM64:
|
||||||
|
Linux_UnknownLinux:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~cabal/cabal-install-3.6.0.0/cabal-install-3.6.0.0-aarch64-linux-deb10.tar.xz
|
||||||
|
dlHash: 534f71cd4e1d9758dc73066cc5733c5838874710aeb3aa88541de6c6d042d9ec
|
||||||
|
Darwin:
|
||||||
|
unknown_versioning:
|
||||||
|
dlUri: https://downloads.haskell.org/~ghcup/unofficial-bindists/cabal/3.6.0.0/cabal-install-3.6.0.0-aarch64-darwin-big-sur.tar.xz
|
||||||
|
dlHash: 7acf740946d996ede835edf68887e6b2f1e16d1b95e94054d266463f38d136d9
|
||||||
|
A_ARM:
|
||||||
|
Linux_UnknownLinux:
|
||||||
|
unknown_versioning:
|
||||||
|
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
|
||||||
GHCup:
|
GHCup:
|
||||||
0.1.16.2:
|
0.1.17:
|
||||||
viTags:
|
viTags:
|
||||||
- Recommended
|
- Recommended
|
||||||
- Latest
|
- Latest
|
||||||
@@ -2132,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
|
||||||
@@ -2194,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:
|
||||||
@@ -2214,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:
|
||||||
@@ -2235,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:
|
||||||
@@ -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
|
||||||
21
docs/RELEASING.md
Normal file
21
docs/RELEASING.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# RELEASING
|
||||||
|
|
||||||
|
1. Update version in `ghcup.cabal` and `boostrap-haskell` (`ghver` variable at the top of the script)
|
||||||
|
|
||||||
|
2. Update `GHCup.Version` module. `ghcupURL` must only be updated if we change the `GHCupInfo` type or the YAML representation of it. The version of the YAML represents the change increments. `ghcUpVer` is the current application version, read from `ghcup.cabal`.
|
||||||
|
|
||||||
|
3. Add ChangeLog entry
|
||||||
|
|
||||||
|
4. Add/fix downloads in `ghcup-<ver>.yaml` (under `data/metadata`), then verify with `ghcup-gen check -f ghcup-<ver>.yaml` and possibly (example only) `ghcup-gen check-tarballs -f ghcup-<ver>.yaml -u 'ghc-8.10.7'`. Generally, new GHC/cabal/stack/hls versions are only added to the latest yaml file. New GHCup versions are added to all (great care must be taken here to not break the parser... e.g. ARM platforms don't parse in all older formats).
|
||||||
|
|
||||||
|
5. Commit and git push with tag. Wait for tests to succeed and release artifacts to build.
|
||||||
|
|
||||||
|
6. Download release artifacts and upload them `downloads.haskell.org/ghcup` along with checksum files (`sha256sum --tag * > SHA256SUMS && gpg --detach-sign -u <your-email> SHA256SUMS`)
|
||||||
|
|
||||||
|
7. Add ghcup release artifacts to ALL yaml files (see point 4.)
|
||||||
|
|
||||||
|
8. Upload the final `ghcup-<ver>.yaml` to `webhost.haskell.org/ghcup/data/`.
|
||||||
|
|
||||||
|
9. Update `bootstrap-haskell` and `bootstrap-haskell.ps1` to `webhost.haskell.org/ghcup/sh/`
|
||||||
|
|
||||||
|
10. Update the ghcup symlinks at `downloads.haskell.org/ghcup`
|
||||||
106
ghcup.cabal
106
ghcup.cabal
@@ -1,29 +1,33 @@
|
|||||||
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
|
||||||
maintainer: hasufell@posteo.de
|
maintainer: hasufell@posteo.de
|
||||||
author: Julian Ospald
|
author: Julian Ospald
|
||||||
homepage: https://gitlab.haskell.org/haskell/ghcup-hs
|
homepage: https://gitlab.haskell.org/haskell/ghcup-hs
|
||||||
bug-reports: https://gitlab.haskell.org/haskell/ghcup-hs/issues
|
bug-reports: https://gitlab.haskell.org/haskell/ghcup-hs/issues
|
||||||
synopsis: ghc toolchain installer
|
synopsis: ghc toolchain installer
|
||||||
description:
|
description:
|
||||||
A rewrite of the shell script ghcup, for providing
|
A rewrite of the shell script ghcup, for providing
|
||||||
a more stable user experience and exposing an API.
|
a more stable user experience and exposing an API.
|
||||||
|
|
||||||
category: System
|
category: System
|
||||||
build-type: Simple
|
build-type: Simple
|
||||||
extra-doc-files:
|
extra-doc-files:
|
||||||
CHANGELOG.md
|
data/config.yaml
|
||||||
config.yaml
|
data/metadata/ghcup-0.0.4.yaml
|
||||||
ghcup-0.0.4.yaml
|
data/metadata/ghcup-0.0.5.yaml
|
||||||
ghcup-0.0.5.yaml
|
data/metadata/ghcup-0.0.6.yaml
|
||||||
ghcup-0.0.6.yaml
|
docs/CHANGELOG.md
|
||||||
HACKING.md
|
docs/HACKING.md
|
||||||
|
docs/RELEASING.md
|
||||||
README.md
|
README.md
|
||||||
RELEASING.md
|
|
||||||
|
extra-source-files:
|
||||||
|
data/build_mk/cross
|
||||||
|
data/build_mk/default
|
||||||
|
|
||||||
source-repository head
|
source-repository head
|
||||||
type: git
|
type: git
|
||||||
@@ -43,11 +47,6 @@ flag internal-downloader
|
|||||||
default: False
|
default: False
|
||||||
manual: True
|
manual: True
|
||||||
|
|
||||||
flag tar
|
|
||||||
description: Use tar-bytestring instead of libarchive.
|
|
||||||
default: False
|
|
||||||
manual: True
|
|
||||||
|
|
||||||
library
|
library
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
GHCup
|
GHCup
|
||||||
@@ -100,27 +99,24 @@ 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
|
||||||
, directory ^>=1.3.6.0
|
, directory ^>=1.3.6.0
|
||||||
, disk-free-space ^>=0.1.0.1
|
, disk-free-space ^>=0.1.0.1
|
||||||
, extra ^>=1.7.9
|
|
||||||
, filepath ^>=1.4.2.1
|
, filepath ^>=1.4.2.1
|
||||||
, generics-sop ^>=0.5
|
|
||||||
, 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
|
||||||
, lzma-static ^>=5.2.5.3
|
, lzma-static ^>=5.2.5.3
|
||||||
, megaparsec >=8.0.0 && <9.1
|
, megaparsec >=8.0.0 && <9.1
|
||||||
, monad-logger ^>=0.3.31
|
|
||||||
, mtl ^>=2.2
|
, mtl ^>=2.2
|
||||||
, optics ^>=0.4
|
, optics ^>=0.4
|
||||||
, optics-vl ^>=0.2
|
|
||||||
, os-release ^>=1.0.0
|
, os-release ^>=1.0.0
|
||||||
, parsec ^>=3.1
|
|
||||||
, pretty ^>=1.1.3.1
|
, pretty ^>=1.1.3.1
|
||||||
, pretty-terminal ^>=0.1.0.0
|
, pretty-terminal ^>=0.1.0.0
|
||||||
, regex-posix ^>=0.96
|
, regex-posix ^>=0.96
|
||||||
@@ -129,7 +125,6 @@ library
|
|||||||
, safe-exceptions ^>=0.1
|
, safe-exceptions ^>=0.1
|
||||||
, split ^>=0.2.3.4
|
, split ^>=0.2.3.4
|
||||||
, strict-base ^>=0.4
|
, strict-base ^>=0.4
|
||||||
, string-interpolate >=0.2.0.0 && <0.4
|
|
||||||
, template-haskell >=2.7 && <2.18
|
, template-haskell >=2.7 && <2.18
|
||||||
, temporary ^>=1.3
|
, temporary ^>=1.3
|
||||||
, text ^>=1.2.4.0
|
, text ^>=1.2.4.0
|
||||||
@@ -138,12 +133,9 @@ library
|
|||||||
, unliftio-core ^>=0.2.0.1
|
, unliftio-core ^>=0.2.0.1
|
||||||
, unordered-containers ^>=0.2.10.0
|
, unordered-containers ^>=0.2.10.0
|
||||||
, uri-bytestring ^>=0.3.2.2
|
, uri-bytestring ^>=0.3.2.2
|
||||||
, utf8-string ^>=1.0
|
|
||||||
, 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
|
||||||
, yaml ^>=0.11.4.0
|
|
||||||
, zip ^>=1.7.1
|
|
||||||
, zlib ^>=0.6.2.2
|
, zlib ^>=0.6.2.2
|
||||||
|
|
||||||
if (flag(internal-downloader) && !os(windows))
|
if (flag(internal-downloader) && !os(windows))
|
||||||
@@ -155,13 +147,6 @@ library
|
|||||||
, io-streams >=1.5.2.1
|
, io-streams >=1.5.2.1
|
||||||
, terminal-progress-bar >=0.4.1
|
, terminal-progress-bar >=0.4.1
|
||||||
|
|
||||||
if flag(tar)
|
|
||||||
cpp-options: -DTAR
|
|
||||||
build-depends: tar
|
|
||||||
|
|
||||||
else
|
|
||||||
build-depends: libarchive ^>=3.0.0.0
|
|
||||||
|
|
||||||
if os(windows)
|
if os(windows)
|
||||||
cpp-options: -DIS_WINDOWS
|
cpp-options: -DIS_WINDOWS
|
||||||
other-modules: GHCup.Utils.File.Windows
|
other-modules: GHCup.Utils.File.Windows
|
||||||
@@ -172,11 +157,13 @@ 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
|
||||||
, hpath-posix ^>=0.13.3
|
|
||||||
, process ^>=1.6.9
|
|
||||||
, unix ^>=2.7
|
, unix ^>=2.7
|
||||||
, unix-bytestring ^>=0.3.7.3
|
, unix-bytestring ^>=0.3.7.3
|
||||||
|
|
||||||
@@ -203,16 +190,20 @@ executable ghcup
|
|||||||
-fwarn-incomplete-record-updates -threaded
|
-fwarn-incomplete-record-updates -threaded
|
||||||
|
|
||||||
build-depends:
|
build-depends:
|
||||||
|
, aeson >=1.4 && <1.6
|
||||||
|
, aeson-pretty ^>=0.8.8
|
||||||
, async ^>=2.2.3
|
, async ^>=2.2.3
|
||||||
, base >=4.13 && <5
|
, base >=4.13 && <5
|
||||||
, bytestring ^>=0.10
|
, bytestring ^>=0.10
|
||||||
|
, cabal-plan ^>=0.7.2
|
||||||
, containers ^>=0.6
|
, containers ^>=0.6
|
||||||
, deepseq ^>=1.4
|
, deepseq ^>=1.4
|
||||||
, 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
|
||||||
, megaparsec >=8.0.0 && <9.1
|
, megaparsec >=8.0.0 && <9.1
|
||||||
, monad-logger ^>=0.3.31
|
|
||||||
, mtl ^>=2.2
|
, mtl ^>=2.2
|
||||||
, optparse-applicative >=0.15.1.0 && <0.17
|
, optparse-applicative >=0.15.1.0 && <0.17
|
||||||
, pretty ^>=1.1.3.1
|
, pretty ^>=1.1.3.1
|
||||||
@@ -220,13 +211,11 @@ executable ghcup
|
|||||||
, resourcet ^>=1.2.2
|
, resourcet ^>=1.2.2
|
||||||
, safe ^>=0.3.18
|
, safe ^>=0.3.18
|
||||||
, safe-exceptions ^>=0.1
|
, safe-exceptions ^>=0.1
|
||||||
, string-interpolate >=0.2.0.0 && <0.4
|
|
||||||
, template-haskell >=2.7 && <2.18
|
, template-haskell >=2.7 && <2.18
|
||||||
, text ^>=1.2.4.0
|
, text ^>=1.2.4.0
|
||||||
, 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
|
||||||
, yaml ^>=0.11.4.0
|
|
||||||
|
|
||||||
if flag(internal-downloader)
|
if flag(internal-downloader)
|
||||||
cpp-options: -DINTERNAL_DOWNLOADER
|
cpp-options: -DINTERNAL_DOWNLOADER
|
||||||
@@ -235,7 +224,7 @@ executable ghcup
|
|||||||
cpp-options: -DBRICK
|
cpp-options: -DBRICK
|
||||||
other-modules: BrickMain
|
other-modules: BrickMain
|
||||||
build-depends:
|
build-depends:
|
||||||
, brick >=0.5 && <0.64
|
, brick ^>=0.64
|
||||||
, transformers ^>=0.5
|
, transformers ^>=0.5
|
||||||
, vector ^>=0.12
|
, vector ^>=0.12
|
||||||
, vty >=5.28.2 && <5.34
|
, vty >=5.28.2 && <5.34
|
||||||
@@ -243,12 +232,6 @@ executable ghcup
|
|||||||
if os(windows)
|
if os(windows)
|
||||||
cpp-options: -DIS_WINDOWS
|
cpp-options: -DIS_WINDOWS
|
||||||
|
|
||||||
if flag(tar)
|
|
||||||
cpp-options: -DTAR
|
|
||||||
|
|
||||||
else
|
|
||||||
build-depends: libarchive ^>=3.0.0.0
|
|
||||||
|
|
||||||
executable ghcup-gen
|
executable ghcup-gen
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
hs-source-dirs: app/ghcup-gen
|
hs-source-dirs: app/ghcup-gen
|
||||||
@@ -280,7 +263,8 @@ 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
|
||||||
, monad-logger ^>=0.3.31
|
, HsYAML-aeson ^>=0.2.0.0
|
||||||
|
, libarchive ^>=3.0.0.0
|
||||||
, mtl ^>=2.2
|
, mtl ^>=2.2
|
||||||
, optics ^>=0.4
|
, optics ^>=0.4
|
||||||
, optparse-applicative >=0.15.1.0 && <0.17
|
, optparse-applicative >=0.15.1.0 && <0.17
|
||||||
@@ -289,19 +273,9 @@ executable ghcup-gen
|
|||||||
, regex-posix ^>=0.96
|
, regex-posix ^>=0.96
|
||||||
, resourcet ^>=1.2.2
|
, resourcet ^>=1.2.2
|
||||||
, safe-exceptions ^>=0.1
|
, safe-exceptions ^>=0.1
|
||||||
, string-interpolate >=0.2.0.0 && <0.4
|
|
||||||
, text ^>=1.2.4.0
|
, text ^>=1.2.4.0
|
||||||
, transformers ^>=0.5
|
, transformers ^>=0.5
|
||||||
, uri-bytestring ^>=0.3.2.2
|
|
||||||
, versions >=4.0.1 && <5.1
|
, versions >=4.0.1 && <5.1
|
||||||
, yaml ^>=0.11.4.0
|
|
||||||
|
|
||||||
if flag(tar)
|
|
||||||
cpp-options: -DTAR
|
|
||||||
build-depends: tar
|
|
||||||
|
|
||||||
else
|
|
||||||
build-depends: libarchive ^>=3.0.0.0
|
|
||||||
|
|
||||||
test-suite ghcup-test
|
test-suite ghcup-test
|
||||||
type: exitcode-stdio-1.0
|
type: exitcode-stdio-1.0
|
||||||
|
|||||||
843
lib/GHCup.hs
843
lib/GHCup.hs
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,7 @@
|
|||||||
{-# LANGUAGE CPP #-}
|
{-# LANGUAGE CPP #-}
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE DeriveGeneric #-}
|
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE QuasiQuotes #-}
|
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
|
||||||
{-# LANGUAGE TypeApplications #-}
|
{-# LANGUAGE TypeApplications #-}
|
||||||
{-# LANGUAGE TypeFamilies #-}
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
|
|
||||||
@@ -34,10 +31,11 @@ import GHCup.Download.Utils
|
|||||||
#endif
|
#endif
|
||||||
import GHCup.Errors
|
import GHCup.Errors
|
||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
import GHCup.Types.JSON ( )
|
|
||||||
import GHCup.Types.Optics
|
import GHCup.Types.Optics
|
||||||
|
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
|
||||||
|
|
||||||
@@ -47,7 +45,6 @@ import Control.Monad
|
|||||||
#if !MIN_VERSION_base(4,13,0)
|
#if !MIN_VERSION_base(4,13,0)
|
||||||
import Control.Monad.Fail ( MonadFail )
|
import Control.Monad.Fail ( MonadFail )
|
||||||
#endif
|
#endif
|
||||||
import Control.Monad.Logger
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Control.Monad.Trans.Resource
|
import Control.Monad.Trans.Resource
|
||||||
hiding ( throwM )
|
hiding ( throwM )
|
||||||
@@ -57,9 +54,8 @@ import Data.ByteString ( ByteString )
|
|||||||
#if defined(INTERNAL_DOWNLOADER)
|
#if defined(INTERNAL_DOWNLOADER)
|
||||||
import Data.CaseInsensitive ( mk )
|
import Data.CaseInsensitive ( mk )
|
||||||
#endif
|
#endif
|
||||||
import Data.List.Extra
|
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.String.Interpolate
|
import Data.List
|
||||||
import Data.Time.Clock
|
import Data.Time.Clock
|
||||||
import Data.Time.Clock.POSIX
|
import Data.Time.Clock.POSIX
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
@@ -73,6 +69,7 @@ import Prelude hiding ( abs
|
|||||||
, readFile
|
, readFile
|
||||||
, writeFile
|
, writeFile
|
||||||
)
|
)
|
||||||
|
import Safe
|
||||||
import System.Directory
|
import System.Directory
|
||||||
import System.Environment
|
import System.Environment
|
||||||
import System.Exit
|
import System.Exit
|
||||||
@@ -90,7 +87,7 @@ import qualified Data.Map.Strict as M
|
|||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.IO as T
|
import qualified Data.Text.IO as T
|
||||||
import qualified Data.Text.Encoding as E
|
import qualified Data.Text.Encoding as E
|
||||||
import qualified Data.Yaml as Y
|
import qualified Data.YAML.Aeson as Y
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -112,13 +109,13 @@ getDownloadsF :: ( FromJSONKey Tool
|
|||||||
, HasDirs env
|
, HasDirs env
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadCatch m
|
, MonadCatch m
|
||||||
, MonadLogger m
|
, HasLog env
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, MonadFail m
|
, MonadFail m
|
||||||
, MonadMask m
|
, MonadMask m
|
||||||
)
|
)
|
||||||
=> Excepts
|
=> Excepts
|
||||||
'[JSONError , DownloadFailed , FileDoesNotExistError]
|
'[DigestError, GPGError, JSONError , DownloadFailed , FileDoesNotExistError]
|
||||||
m
|
m
|
||||||
GHCupInfo
|
GHCupInfo
|
||||||
getDownloadsF = do
|
getDownloadsF = do
|
||||||
@@ -165,50 +162,58 @@ getBase :: ( MonadReader env m
|
|||||||
, MonadFail m
|
, MonadFail m
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadCatch m
|
, MonadCatch m
|
||||||
, MonadLogger m
|
, HasLog env
|
||||||
, MonadMask m
|
, MonadMask m
|
||||||
)
|
)
|
||||||
=> URI
|
=> URI
|
||||||
-> Excepts '[JSONError] m GHCupInfo
|
-> Excepts '[GPGError, DigestError, JSONError, FileDoesNotExistError] m GHCupInfo
|
||||||
getBase uri = do
|
getBase uri = do
|
||||||
Settings { noNetwork } <- lift getSettings
|
Settings { noNetwork, downloader } <- lift getSettings
|
||||||
|
|
||||||
-- try to download yaml... usually this writes it into cache dir,
|
-- try to download yaml... usually this writes it into cache dir,
|
||||||
-- but in some cases not (e.g. when using file://), so we honour
|
-- but in some cases not (e.g. when using file://), so we honour
|
||||||
-- the return filepath, if any
|
-- the return filepath, if any
|
||||||
mYaml <- if noNetwork && view (uriSchemeL' % schemeBSL') uri /= "file" -- for file://, let it fall through
|
mYaml <- if noNetwork && view (uriSchemeL' % schemeBSL') uri /= "file" -- for file://, let it fall through
|
||||||
then pure Nothing
|
then pure Nothing
|
||||||
else handleIO (\e -> warnCache (displayException e) >> pure Nothing)
|
else handleIO (\e -> lift (warnCache (displayException e) downloader) >> pure Nothing)
|
||||||
. catchE @_ @_ @'[] (\e@(DownloadFailed _) -> warnCache (prettyShow e) >> pure Nothing)
|
. catchE @_ @_ @'[] (\e@(DownloadFailed _) -> lift (warnCache (prettyShow e) downloader) >> pure Nothing)
|
||||||
. reThrowAll @_ @_ @'[DownloadFailed] DownloadFailed
|
|
||||||
. fmap Just
|
. fmap Just
|
||||||
. smartDl
|
. smartDl
|
||||||
$ uri
|
$ uri
|
||||||
|
|
||||||
-- if we didn't get a filepath from the download, use the cached yaml
|
-- if we didn't get a filepath from the download, use the cached yaml
|
||||||
actualYaml <- maybe (lift $ yamlFromCache uri) pure mYaml
|
actualYaml <- maybe (lift $ yamlFromCache uri) pure mYaml
|
||||||
lift $ $(logDebug) [i|Decoding yaml at: #{actualYaml}|]
|
yamlContents <- liftIOException doesNotExistErrorType (FileDoesNotExistError actualYaml) $ liftIO $ L.readFile actualYaml
|
||||||
|
lift $ logDebug $ "Decoding yaml at: " <> T.pack actualYaml
|
||||||
|
|
||||||
liftE
|
liftE
|
||||||
. onE_ (onError actualYaml)
|
. onE_ (onError actualYaml)
|
||||||
. lEM' @_ @_ @'[JSONError] JSONDecodeError
|
. lE' @_ @_ @'[JSONError] JSONDecodeError
|
||||||
. fmap (first (\e -> [i|#{displayException e}
|
. first (\(_, e) -> unlines [e, "Consider removing " <> actualYaml <> " manually."])
|
||||||
Consider removing "#{actualYaml}" manually.|]))
|
. Y.decode1
|
||||||
. liftIO
|
$ yamlContents
|
||||||
. Y.decodeFileEither
|
|
||||||
$ actualYaml
|
|
||||||
where
|
where
|
||||||
-- On error, remove the etags file and set access time to 0. This should ensure the next invocation
|
-- On error, remove the etags file and set access time to 0. This should ensure the next invocation
|
||||||
-- may re-download and succeed.
|
-- may re-download and succeed.
|
||||||
onError :: (MonadLogger m, MonadMask m, MonadCatch m, MonadIO m) => FilePath -> m ()
|
onError :: (MonadReader env m, HasLog env, MonadMask m, MonadCatch m, MonadIO m) => FilePath -> m ()
|
||||||
onError fp = do
|
onError fp = do
|
||||||
let efp = etagsFile fp
|
let efp = etagsFile fp
|
||||||
handleIO (\e -> $(logWarn) [i|Couldn't remove file #{efp}, error was: #{displayException e}|])
|
handleIO (\e -> logWarn $ "Couldn't remove file " <> T.pack efp <> ", error was: " <> T.pack (displayException e))
|
||||||
(hideError doesNotExistErrorType $ rmFile efp)
|
(hideError doesNotExistErrorType $ rmFile efp)
|
||||||
liftIO $ hideError doesNotExistErrorType $ setAccessTime fp (posixSecondsToUTCTime (fromIntegral @Int 0))
|
liftIO $ hideError doesNotExistErrorType $ setAccessTime fp (posixSecondsToUTCTime (fromIntegral @Int 0))
|
||||||
warnCache s = do
|
|
||||||
lift $ $(logWarn) [i|Could not get download info, trying cached version (this may not be recent!)|]
|
warnCache :: (MonadReader env m, HasLog env, MonadMask m, MonadCatch m, MonadIO m) => FilePath -> Downloader -> m ()
|
||||||
lift $ $(logDebug) [i|Error was: #{s}|]
|
warnCache s downloader' = do
|
||||||
|
let tryDownloder = case downloader' of
|
||||||
|
Curl -> "Wget"
|
||||||
|
Wget -> "Curl"
|
||||||
|
#if defined(INTERNAL_DOWNLOADER)
|
||||||
|
Internal -> "Curl"
|
||||||
|
#endif
|
||||||
|
logWarn $ "Could not get download info, trying cached version (this may not be recent!)" <> "\n" <>
|
||||||
|
"If this problem persists, consider switching downloader via: " <> "\n " <>
|
||||||
|
"ghcup config set downloader " <> tryDownloder
|
||||||
|
logDebug $ "Error was: " <> T.pack s
|
||||||
|
|
||||||
-- First check if the json file is in the ~/.ghcup/cache dir
|
-- First check if the json file is in the ~/.ghcup/cache dir
|
||||||
-- and check it's access time. If it has been accessed within the
|
-- and check it's access time. If it has been accessed within the
|
||||||
@@ -222,13 +227,14 @@ Consider removing "#{actualYaml}" manually.|]))
|
|||||||
, MonadCatch m1
|
, MonadCatch m1
|
||||||
, MonadIO m1
|
, MonadIO m1
|
||||||
, MonadFail m1
|
, MonadFail m1
|
||||||
, MonadLogger m1
|
, HasLog env1
|
||||||
, MonadMask m1
|
, MonadMask m1
|
||||||
)
|
)
|
||||||
=> URI
|
=> URI
|
||||||
-> Excepts
|
-> Excepts
|
||||||
'[ DownloadFailed
|
'[ DownloadFailed
|
||||||
, DigestError
|
, DigestError
|
||||||
|
, GPGError
|
||||||
]
|
]
|
||||||
m1
|
m1
|
||||||
FilePath
|
FilePath
|
||||||
@@ -240,7 +246,7 @@ Consider removing "#{actualYaml}" manually.|]))
|
|||||||
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
|
||||||
|
|
||||||
@@ -253,7 +259,7 @@ Consider removing "#{actualYaml}" manually.|]))
|
|||||||
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
|
||||||
@@ -313,21 +319,22 @@ download :: ( MonadReader env m
|
|||||||
, HasDirs env
|
, HasDirs env
|
||||||
, MonadMask m
|
, MonadMask m
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, MonadLogger m
|
, HasLog env
|
||||||
, 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) [i|using local file: #{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'
|
||||||
| otherwise = throwE $ DownloadFailed (variantFromValue UnsupportedScheme)
|
| otherwise = throwE $ DownloadFailed (variantFromValue UnsupportedScheme)
|
||||||
@@ -335,143 +342,207 @@ 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) [i|downloading: #{uri'} as file #{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'
|
||||||
dh <- liftIO $ emptySystemTempFile "curl-header"
|
else pure $ curlDL o'
|
||||||
flip finally (try @_ @SomeException $ rmFile dh) $
|
Wget -> do
|
||||||
flip finally (try @_ @SomeException $ rmFile (destFile <.> "tmp")) $ do
|
o' <- liftIO getWgetOpts
|
||||||
metag <- readETag destFile
|
if etags
|
||||||
liftE $ lEM @_ @'[ProcessError] $ exec "curl"
|
then pure $ wgetEtagsDL o'
|
||||||
(o' ++ (if etags then ["--dump-header", dh] else [])
|
else pure $ wgetDL o'
|
||||||
++ maybe [] (\t -> ["-H", [i|If-None-Match: #{t}|]]) metag
|
|
||||||
++ ["-fL", "-o", destFile <.> "tmp", T.unpack uri']) Nothing Nothing
|
|
||||||
headers <- liftIO $ T.readFile dh
|
|
||||||
|
|
||||||
-- this nonsense is necessary, because some older versions of curl would overwrite
|
|
||||||
-- the destination file when 304 is returned
|
|
||||||
case fmap T.words . listToMaybe . fmap T.strip . T.lines . getLastHeader $ headers of
|
|
||||||
Just (http':sc:_)
|
|
||||||
| sc == "304"
|
|
||||||
, T.pack "HTTP" `T.isPrefixOf` http' -> $logDebug [i|Status code was 304, not overwriting|]
|
|
||||||
| T.pack "HTTP" `T.isPrefixOf` http' -> do
|
|
||||||
$logDebug [i|Status code was #{sc}, overwriting|]
|
|
||||||
liftIO $ copyFile (destFile <.> "tmp") destFile
|
|
||||||
_ -> liftE $ throwE @_ @'[DownloadFailed] (DownloadFailed (toVariantAt @0 (MalformedHeaders headers)
|
|
||||||
:: V '[MalformedHeaders]))
|
|
||||||
|
|
||||||
writeEtags destFile (parseEtags headers)
|
|
||||||
else
|
|
||||||
liftE $ lEM @_ @'[ProcessError] $ exec "curl"
|
|
||||||
(o' ++ ["-fL", "-o", destFile, T.unpack uri']) Nothing Nothing
|
|
||||||
Wget -> do
|
|
||||||
destFileTemp <- liftIO $ emptySystemTempFile "wget-tmp"
|
|
||||||
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
|
||||||
o' <- liftIO getWgetOpts
|
|
||||||
if etags
|
|
||||||
then do
|
|
||||||
metag <- readETag destFile
|
|
||||||
let opts = o' ++ maybe [] (\t -> ["--header", [i|If-None-Match: #{t}|]]) metag
|
|
||||||
++ ["-q", "-S", "-O", destFileTemp , T.unpack uri']
|
|
||||||
CapturedProcess {_exitCode, _stdErr} <- lift $ executeOut "wget" opts Nothing
|
|
||||||
case _exitCode of
|
|
||||||
ExitSuccess -> do
|
|
||||||
liftIO $ copyFile destFileTemp destFile
|
|
||||||
writeEtags destFile (parseEtags (decUTF8Safe' _stdErr))
|
|
||||||
ExitFailure i'
|
|
||||||
| i' == 8
|
|
||||||
, Just _ <- find (T.pack "304 Not Modified" `T.isInfixOf`) . T.lines . decUTF8Safe' $ _stdErr
|
|
||||||
-> do
|
|
||||||
$logDebug "Not modified, skipping download"
|
|
||||||
writeEtags destFile (parseEtags (decUTF8Safe' _stdErr))
|
|
||||||
| 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
|
Internal -> do
|
||||||
(https, host, fullPath, port) <- liftE $ uriToQuadruple uri
|
if etags
|
||||||
if etags
|
then pure (\fp -> liftE . internalEtagsDL fp)
|
||||||
then do
|
else pure (\fp -> liftE . internalDL fp)
|
||||||
metag <- readETag destFile
|
|
||||||
let addHeaders = maybe mempty (\etag -> M.fromList [ (mk . E.encodeUtf8 . T.pack $ "If-None-Match"
|
|
||||||
, E.encodeUtf8 etag)]) metag
|
|
||||||
liftE
|
|
||||||
$ catchE @HTTPNotModified @'[DownloadFailed] @'[] (\(HTTPNotModified etag) -> lift $ writeEtags destFile (pure $ Just etag))
|
|
||||||
$ do
|
|
||||||
r <- downloadToFile https host fullPath port destFile addHeaders
|
|
||||||
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
|
||||||
|
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 destFile)
|
forM_ eDigest (liftE . flip checkDigest baseDestFile)
|
||||||
pure destFile
|
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"
|
||||||
|
flip finally (try @_ @SomeException $ rmFile dh) $
|
||||||
|
flip finally (try @_ @SomeException $ rmFile destFileTemp) $ do
|
||||||
|
metag <- lift $ readETag destFile
|
||||||
|
liftE $ lEM @_ @'[ProcessError] $ exec "curl"
|
||||||
|
(o' ++ (if etags then ["--dump-header", dh] else [])
|
||||||
|
++ maybe [] (\t -> ["-H", "If-None-Match: " <> T.unpack t]) metag
|
||||||
|
++ ["-fL", "-o", destFileTemp, T.unpack uri']) Nothing Nothing
|
||||||
|
headers <- liftIO $ T.readFile dh
|
||||||
|
|
||||||
|
-- this nonsense is necessary, because some older versions of curl would overwrite
|
||||||
|
-- the destination file when 304 is returned
|
||||||
|
case fmap T.words . listToMaybe . fmap T.strip . T.lines . getLastHeader $ headers of
|
||||||
|
Just (http':sc:_)
|
||||||
|
| sc == "304"
|
||||||
|
, T.pack "HTTP" `T.isPrefixOf` http' -> lift $ logDebug "Status code was 304, not overwriting"
|
||||||
|
| T.pack "HTTP" `T.isPrefixOf` http' -> do
|
||||||
|
lift $ logDebug $ "Status code was " <> sc <> ", overwriting"
|
||||||
|
liftIO $ renameFile destFileTemp destFile
|
||||||
|
_ -> liftE $ throwE @_ @'[DownloadFailed] (DownloadFailed (toVariantAt @0 (MalformedHeaders headers)
|
||||||
|
:: V '[MalformedHeaders]))
|
||||||
|
|
||||||
|
lift $ writeEtags destFile (parseEtags headers)
|
||||||
|
|
||||||
|
wgetDL :: (MonadCatch m, MonadMask m, MonadIO m) => [String] -> FilePath -> URI -> Excepts '[ProcessError, DownloadFailed, UnsupportedScheme] m ()
|
||||||
|
wgetDL o' destFile (decUTF8Safe . serializeURIRef' -> uri') = do
|
||||||
|
let destFileTemp = tmpFile destFile
|
||||||
|
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
|
||||||
|
metag <- lift $ readETag destFile
|
||||||
|
let opts = o' ++ maybe [] (\t -> ["--header", "If-None-Match: " <> T.unpack t]) metag
|
||||||
|
++ ["-q", "-S", "-O", destFileTemp , T.unpack uri']
|
||||||
|
CapturedProcess {_exitCode, _stdErr} <- lift $ executeOut "wget" opts Nothing
|
||||||
|
case _exitCode of
|
||||||
|
ExitSuccess -> do
|
||||||
|
liftIO $ renameFile destFileTemp destFile
|
||||||
|
lift $ writeEtags destFile (parseEtags (decUTF8Safe' _stdErr))
|
||||||
|
ExitFailure i'
|
||||||
|
| i' == 8
|
||||||
|
, Just _ <- find (T.pack "304 Not Modified" `T.isInfixOf`) . T.lines . decUTF8Safe' $ _stdErr
|
||||||
|
-> do
|
||||||
|
lift $ logDebug "Not modified, skipping download"
|
||||||
|
lift $ writeEtags destFile (parseEtags (decUTF8Safe' _stdErr))
|
||||||
|
| otherwise -> throwE (NonZeroExit i' "wget" opts)
|
||||||
|
|
||||||
|
#if defined(INTERNAL_DOWNLOADER)
|
||||||
|
internalDL :: (MonadCatch m, MonadMask m, MonadIO m)
|
||||||
|
=> FilePath -> URI -> Excepts '[DownloadFailed, UnsupportedScheme] m ()
|
||||||
|
internalDL destFile uri' = 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
|
||||||
|
let addHeaders = maybe mempty (\etag -> M.fromList [ (mk . E.encodeUtf8 . T.pack $ "If-None-Match"
|
||||||
|
, E.encodeUtf8 etag)]) metag
|
||||||
|
liftE
|
||||||
|
$ catchE @HTTPNotModified @'[DownloadFailed] @'[] (\(HTTPNotModified etag) -> lift $ writeEtags destFile (pure $ Just etag))
|
||||||
|
$ do
|
||||||
|
r <- downloadToFile https host fullPath port destFileTemp addHeaders
|
||||||
|
liftIO $ renameFile destFileTemp destFile
|
||||||
|
lift $ writeEtags destFile (pure $ decUTF8Safe <$> getHeader r "etag")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
-- 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
|
parseEtags :: (MonadReader env m, HasLog env, MonadIO m, MonadThrow m) => T.Text -> m (Maybe T.Text)
|
||||||
uri' = decUTF8Safe (serializeURIRef' uri)
|
|
||||||
|
|
||||||
parseEtags :: (MonadLogger m, MonadIO m, MonadThrow m) => T.Text -> m (Maybe T.Text)
|
|
||||||
parseEtags stderr = do
|
parseEtags stderr = do
|
||||||
let mEtag = find (\line -> T.pack "etag:" `T.isPrefixOf` T.toLower line) . fmap T.strip . T.lines . getLastHeader $ stderr
|
let mEtag = find (\line -> T.pack "etag:" `T.isPrefixOf` T.toLower line) . fmap T.strip . T.lines . getLastHeader $ stderr
|
||||||
case T.words <$> mEtag of
|
case T.words <$> mEtag of
|
||||||
(Just []) -> do
|
(Just []) -> do
|
||||||
$logDebug "Couldn't parse etags, no input: "
|
logDebug "Couldn't parse etags, no input: "
|
||||||
pure Nothing
|
pure Nothing
|
||||||
(Just [_, etag']) -> do
|
(Just [_, etag']) -> do
|
||||||
$logDebug [i|Parsed etag: #{etag'}|]
|
logDebug $ "Parsed etag: " <> etag'
|
||||||
pure (Just etag')
|
pure (Just etag')
|
||||||
(Just xs) -> do
|
(Just xs) -> do
|
||||||
$logDebug ("Couldn't parse etags, unexpected input: " <> T.unwords xs)
|
logDebug ("Couldn't parse etags, unexpected input: " <> T.unwords xs)
|
||||||
pure Nothing
|
pure Nothing
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
$logDebug "No etags header found"
|
logDebug "No etags header found"
|
||||||
pure Nothing
|
pure Nothing
|
||||||
|
|
||||||
writeEtags :: (MonadLogger m, MonadIO m, MonadThrow m) => FilePath -> m (Maybe T.Text) -> m ()
|
writeEtags :: (MonadReader env m, HasLog env, MonadIO m, MonadThrow m) => FilePath -> m (Maybe T.Text) -> m ()
|
||||||
writeEtags destFile getTags = do
|
writeEtags destFile getTags = do
|
||||||
getTags >>= \case
|
getTags >>= \case
|
||||||
Just t -> do
|
Just t -> do
|
||||||
$logDebug [i|Writing etagsFile #{(etagsFile destFile)}|]
|
logDebug $ "Writing etagsFile " <> T.pack (etagsFile destFile)
|
||||||
liftIO $ T.writeFile (etagsFile destFile) t
|
liftIO $ T.writeFile (etagsFile destFile) t
|
||||||
Nothing ->
|
Nothing ->
|
||||||
$logDebug [i|No etags files written|]
|
logDebug "No etags files written"
|
||||||
|
|
||||||
readETag :: (MonadLogger m, MonadCatch m, MonadIO m) => FilePath -> m (Maybe T.Text)
|
readETag :: (MonadReader env m, HasLog env, MonadCatch m, MonadIO m) => FilePath -> m (Maybe T.Text)
|
||||||
readETag fp = do
|
readETag fp = do
|
||||||
e <- liftIO $ doesFileExist fp
|
e <- liftIO $ doesFileExist fp
|
||||||
if e
|
if e
|
||||||
@@ -479,13 +550,13 @@ download uri eDigest dest mfn etags
|
|||||||
rE <- try @_ @SomeException $ liftIO $ fmap stripNewline' $ T.readFile (etagsFile fp)
|
rE <- try @_ @SomeException $ liftIO $ fmap stripNewline' $ T.readFile (etagsFile fp)
|
||||||
case rE of
|
case rE of
|
||||||
(Right et) -> do
|
(Right et) -> do
|
||||||
$logDebug [i|Read etag: #{et}|]
|
logDebug $ "Read etag: " <> et
|
||||||
pure (Just et)
|
pure (Just et)
|
||||||
(Left _) -> do
|
(Left _) -> do
|
||||||
$logDebug [i|Etag file doesn't exist (yet)|]
|
logDebug "Etag file doesn't exist (yet)"
|
||||||
pure Nothing
|
pure Nothing
|
||||||
else do
|
else do
|
||||||
$logDebug [i|Skipping and deleting etags file because destination file #{fp} doesn't exist|]
|
logDebug $ "Skipping and deleting etags file because destination file " <> T.pack fp <> " doesn't exist"
|
||||||
liftIO $ hideError doesNotExistErrorType $ rmFile (etagsFile fp)
|
liftIO $ hideError doesNotExistErrorType $ rmFile (etagsFile fp)
|
||||||
pure Nothing
|
pure Nothing
|
||||||
|
|
||||||
@@ -498,20 +569,20 @@ downloadCached :: ( MonadReader env m
|
|||||||
, MonadMask m
|
, MonadMask m
|
||||||
, MonadResource m
|
, MonadResource m
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, MonadLogger m
|
, HasLog env
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadUnliftIO m
|
, MonadUnliftIO 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
|
||||||
@@ -519,14 +590,14 @@ downloadCached' :: ( MonadReader env m
|
|||||||
, HasSettings env
|
, HasSettings env
|
||||||
, MonadMask m
|
, MonadMask m
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, MonadLogger m
|
, HasLog env
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadUnliftIO m
|
, MonadUnliftIO 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
|
||||||
@@ -537,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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -553,7 +624,7 @@ checkDigest :: ( MonadReader env m
|
|||||||
, HasSettings env
|
, HasSettings env
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, MonadLogger m
|
, HasLog env
|
||||||
)
|
)
|
||||||
=> T.Text -- ^ the hash
|
=> T.Text -- ^ the hash
|
||||||
-> FilePath
|
-> FilePath
|
||||||
@@ -563,10 +634,10 @@ checkDigest eDigest file = do
|
|||||||
let verify = not noVerify
|
let verify = not noVerify
|
||||||
when verify $ do
|
when verify $ do
|
||||||
let p' = takeFileName file
|
let p' = takeFileName file
|
||||||
lift $ $(logInfo) [i|verifying digest of: #{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.
|
||||||
@@ -584,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.
|
||||||
--
|
--
|
||||||
@@ -605,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")
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
{-# LANGUAGE ExistentialQuantification #-}
|
{-# LANGUAGE ExistentialQuantification #-}
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE StandaloneDeriving #-}
|
{-# LANGUAGE StandaloneDeriving #-}
|
||||||
{-# LANGUAGE QuasiQuotes #-}
|
|
||||||
{-# LANGUAGE TypeOperators #-}
|
{-# LANGUAGE TypeOperators #-}
|
||||||
{-# LANGUAGE FlexibleInstances #-}
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
|
|
||||||
@@ -21,15 +20,10 @@ module GHCup.Errors where
|
|||||||
|
|
||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
|
|
||||||
#if !defined(TAR)
|
|
||||||
import Codec.Archive
|
import Codec.Archive
|
||||||
#else
|
|
||||||
import qualified Codec.Archive.Tar as Tar
|
|
||||||
#endif
|
|
||||||
import Control.Exception.Safe
|
import Control.Exception.Safe
|
||||||
import Data.ByteString ( ByteString )
|
import Data.ByteString ( ByteString )
|
||||||
import Data.CaseInsensitive ( CI )
|
import Data.CaseInsensitive ( CI )
|
||||||
import Data.String.Interpolate
|
|
||||||
import Data.Text ( Text )
|
import Data.Text ( Text )
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
import Haskus.Utils.Variant
|
import Haskus.Utils.Variant
|
||||||
@@ -38,6 +32,7 @@ import Text.PrettyPrint.HughesPJClass hiding ( (<>) )
|
|||||||
import URI.ByteString
|
import URI.ByteString
|
||||||
|
|
||||||
import qualified Data.Map.Strict as M
|
import qualified Data.Map.Strict as M
|
||||||
|
import qualified Data.Text as T
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -55,7 +50,7 @@ instance Pretty NoCompatiblePlatform where
|
|||||||
pPrint (NoCompatiblePlatform str') =
|
pPrint (NoCompatiblePlatform str') =
|
||||||
text ("Could not find a compatible platform. Got: " ++ str')
|
text ("Could not find a compatible platform. Got: " ++ str')
|
||||||
|
|
||||||
-- | Unable to find a download for the requested versio/distro.
|
-- | Unable to find a download for the requested version/distro.
|
||||||
data NoDownload = NoDownload
|
data NoDownload = NoDownload
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
@@ -92,7 +87,7 @@ data UnknownArchive = UnknownArchive FilePath
|
|||||||
|
|
||||||
instance Pretty UnknownArchive where
|
instance Pretty UnknownArchive where
|
||||||
pPrint (UnknownArchive file) =
|
pPrint (UnknownArchive file) =
|
||||||
text [i|The archive format is unknown. We don't know how to extract the file "#{file}"|]
|
text $ "The archive format is unknown. We don't know how to extract the file " <> file
|
||||||
|
|
||||||
-- | The scheme is not supported (such as ftp).
|
-- | The scheme is not supported (such as ftp).
|
||||||
data UnsupportedScheme = UnsupportedScheme
|
data UnsupportedScheme = UnsupportedScheme
|
||||||
@@ -115,7 +110,7 @@ data TagNotFound = TagNotFound Tag Tool
|
|||||||
|
|
||||||
instance Pretty TagNotFound where
|
instance Pretty TagNotFound where
|
||||||
pPrint (TagNotFound tag tool) =
|
pPrint (TagNotFound tag tool) =
|
||||||
text "Unable to find tag" <+> pPrint tag <+> text [i|of tool "#{tool}"|]
|
text "Unable to find tag" <+> pPrint tag <+> text "of tool" <+> pPrint tool
|
||||||
|
|
||||||
-- | Unable to find the next version of a tool (the one after the currently
|
-- | Unable to find the next version of a tool (the one after the currently
|
||||||
-- set one).
|
-- set one).
|
||||||
@@ -124,7 +119,7 @@ data NextVerNotFound = NextVerNotFound Tool
|
|||||||
|
|
||||||
instance Pretty NextVerNotFound where
|
instance Pretty NextVerNotFound where
|
||||||
pPrint (NextVerNotFound tool) =
|
pPrint (NextVerNotFound tool) =
|
||||||
text [i|Unable to find next (the one after the currently set one) version of tool "#{tool}"|]
|
text "Unable to find next (the one after the currently set one) version of tool" <+> pPrint tool
|
||||||
|
|
||||||
-- | The tool (such as GHC) is already installed with that version.
|
-- | The tool (such as GHC) is already installed with that version.
|
||||||
data AlreadyInstalled = AlreadyInstalled Tool Version
|
data AlreadyInstalled = AlreadyInstalled Tool Version
|
||||||
@@ -132,14 +127,14 @@ data AlreadyInstalled = AlreadyInstalled Tool Version
|
|||||||
|
|
||||||
instance Pretty AlreadyInstalled where
|
instance Pretty AlreadyInstalled where
|
||||||
pPrint (AlreadyInstalled tool ver') =
|
pPrint (AlreadyInstalled tool ver') =
|
||||||
text [i|#{tool}-#{prettyShow ver'} is already installed|]
|
pPrint tool <+> text "-" <+> pPrint ver' <+> text "is already installed"
|
||||||
|
|
||||||
-- | The Directory is supposed to be empty, but wasn't.
|
-- | The Directory is supposed to be empty, but wasn't.
|
||||||
data DirNotEmpty = DirNotEmpty {path :: FilePath}
|
data DirNotEmpty = DirNotEmpty {path :: FilePath}
|
||||||
|
|
||||||
instance Pretty DirNotEmpty where
|
instance Pretty DirNotEmpty where
|
||||||
pPrint (DirNotEmpty path) = do
|
pPrint (DirNotEmpty path) = do
|
||||||
text [i|The directory was expected to be empty, but isn't: #{path}|]
|
text $ "The directory was expected to be empty, but isn't: " <> path
|
||||||
|
|
||||||
-- | The tool is not installed. Some operations rely on a tool
|
-- | The tool is not installed. Some operations rely on a tool
|
||||||
-- to be installed (such as setting the current GHC version).
|
-- to be installed (such as setting the current GHC version).
|
||||||
@@ -148,7 +143,7 @@ data NotInstalled = NotInstalled Tool GHCTargetVersion
|
|||||||
|
|
||||||
instance Pretty NotInstalled where
|
instance Pretty NotInstalled where
|
||||||
pPrint (NotInstalled tool ver) =
|
pPrint (NotInstalled tool ver) =
|
||||||
text [i|The version "#{prettyShow ver}" of the tool "#{tool}" is not installed.|]
|
text "The version" <+> pPrint ver <+> text "of the tool" <+> pPrint tool <+> text "is not installed."
|
||||||
|
|
||||||
-- | An executable was expected to be in PATH, but was not found.
|
-- | An executable was expected to be in PATH, but was not found.
|
||||||
data NotFoundInPATH = NotFoundInPATH FilePath
|
data NotFoundInPATH = NotFoundInPATH FilePath
|
||||||
@@ -156,7 +151,7 @@ data NotFoundInPATH = NotFoundInPATH FilePath
|
|||||||
|
|
||||||
instance Pretty NotFoundInPATH where
|
instance Pretty NotFoundInPATH where
|
||||||
pPrint (NotFoundInPATH exe) =
|
pPrint (NotFoundInPATH exe) =
|
||||||
text [i|The exe "#{exe}" was not found in PATH.|]
|
text $ "The exe " <> exe <> " was not found in PATH."
|
||||||
|
|
||||||
-- | JSON decoding failed.
|
-- | JSON decoding failed.
|
||||||
data JSONError = JSONDecodeError String
|
data JSONError = JSONDecodeError String
|
||||||
@@ -164,7 +159,7 @@ data JSONError = JSONDecodeError String
|
|||||||
|
|
||||||
instance Pretty JSONError where
|
instance Pretty JSONError where
|
||||||
pPrint (JSONDecodeError err) =
|
pPrint (JSONDecodeError err) =
|
||||||
text [i|JSON decoding failed with: #{err}|]
|
text $ "JSON decoding failed with: " <> err
|
||||||
|
|
||||||
-- | A file that is supposed to exist does not exist
|
-- | A file that is supposed to exist does not exist
|
||||||
-- (e.g. when we use file scheme to "download" something).
|
-- (e.g. when we use file scheme to "download" something).
|
||||||
@@ -173,7 +168,7 @@ data FileDoesNotExistError = FileDoesNotExistError FilePath
|
|||||||
|
|
||||||
instance Pretty FileDoesNotExistError where
|
instance Pretty FileDoesNotExistError where
|
||||||
pPrint (FileDoesNotExistError file) =
|
pPrint (FileDoesNotExistError file) =
|
||||||
text [i|File "#{file}" does not exist.|]
|
text $ "File " <> file <> " does not exist."
|
||||||
|
|
||||||
-- | The file already exists
|
-- | The file already exists
|
||||||
-- (e.g. when we use isolated installs with the same path).
|
-- (e.g. when we use isolated installs with the same path).
|
||||||
@@ -183,7 +178,7 @@ data FileAlreadyExistsError = FileAlreadyExistsError FilePath
|
|||||||
|
|
||||||
instance Pretty FileAlreadyExistsError where
|
instance Pretty FileAlreadyExistsError where
|
||||||
pPrint (FileAlreadyExistsError file) =
|
pPrint (FileAlreadyExistsError file) =
|
||||||
text [i|File "#{file}" Already exists.|]
|
text $ "File " <> file <> " Already exists."
|
||||||
|
|
||||||
data TarDirDoesNotExist = TarDirDoesNotExist TarDir
|
data TarDirDoesNotExist = TarDirDoesNotExist TarDir
|
||||||
deriving Show
|
deriving Show
|
||||||
@@ -193,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 [i|Digest error: expected "#{expectedDigest}", but got "#{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)
|
||||||
@@ -206,7 +211,7 @@ data HTTPStatusError = HTTPStatusError Int (M.Map (CI ByteString) ByteString)
|
|||||||
|
|
||||||
instance Pretty HTTPStatusError where
|
instance Pretty HTTPStatusError where
|
||||||
pPrint (HTTPStatusError status _) =
|
pPrint (HTTPStatusError status _) =
|
||||||
text [i|Unexpected HTTP status: #{status}|]
|
text "Unexpected HTTP status:" <+> pPrint status
|
||||||
|
|
||||||
-- | Malformed headers.
|
-- | Malformed headers.
|
||||||
data MalformedHeaders = MalformedHeaders Text
|
data MalformedHeaders = MalformedHeaders Text
|
||||||
@@ -214,7 +219,7 @@ data MalformedHeaders = MalformedHeaders Text
|
|||||||
|
|
||||||
instance Pretty MalformedHeaders where
|
instance Pretty MalformedHeaders where
|
||||||
pPrint (MalformedHeaders h) =
|
pPrint (MalformedHeaders h) =
|
||||||
text [i|Headers are malformed: #{h}|]
|
text "Headers are malformed: " <+> pPrint h
|
||||||
|
|
||||||
-- | Unexpected HTTP status.
|
-- | Unexpected HTTP status.
|
||||||
data HTTPNotModified = HTTPNotModified Text
|
data HTTPNotModified = HTTPNotModified Text
|
||||||
@@ -222,7 +227,7 @@ data HTTPNotModified = HTTPNotModified Text
|
|||||||
|
|
||||||
instance Pretty HTTPNotModified where
|
instance Pretty HTTPNotModified where
|
||||||
pPrint (HTTPNotModified etag) =
|
pPrint (HTTPNotModified etag) =
|
||||||
text [i|Remote resource not modifed, etag was: #{etag}|]
|
text "Remote resource not modifed, etag was:" <+> pPrint etag
|
||||||
|
|
||||||
-- | The 'Location' header was expected during a 3xx redirect, but not found.
|
-- | The 'Location' header was expected during a 3xx redirect, but not found.
|
||||||
data NoLocationHeader = NoLocationHeader
|
data NoLocationHeader = NoLocationHeader
|
||||||
@@ -230,7 +235,7 @@ data NoLocationHeader = NoLocationHeader
|
|||||||
|
|
||||||
instance Pretty NoLocationHeader where
|
instance Pretty NoLocationHeader where
|
||||||
pPrint NoLocationHeader =
|
pPrint NoLocationHeader =
|
||||||
text [i|The 'Location' header was expected during a 3xx redirect, but not found.|]
|
text "The 'Location' header was expected during a 3xx redirect, but not found."
|
||||||
|
|
||||||
-- | Too many redirects.
|
-- | Too many redirects.
|
||||||
data TooManyRedirs = TooManyRedirs
|
data TooManyRedirs = TooManyRedirs
|
||||||
@@ -238,7 +243,7 @@ data TooManyRedirs = TooManyRedirs
|
|||||||
|
|
||||||
instance Pretty TooManyRedirs where
|
instance Pretty TooManyRedirs where
|
||||||
pPrint TooManyRedirs =
|
pPrint TooManyRedirs =
|
||||||
text [i|Too many redirections.|]
|
text "Too many redirections."
|
||||||
|
|
||||||
-- | A patch could not be applied.
|
-- | A patch could not be applied.
|
||||||
data PatchFailed = PatchFailed
|
data PatchFailed = PatchFailed
|
||||||
@@ -246,7 +251,7 @@ data PatchFailed = PatchFailed
|
|||||||
|
|
||||||
instance Pretty PatchFailed where
|
instance Pretty PatchFailed where
|
||||||
pPrint PatchFailed =
|
pPrint PatchFailed =
|
||||||
text [i|A patch could not be applied.|]
|
text "A patch could not be applied."
|
||||||
|
|
||||||
-- | The tool requirements could not be found.
|
-- | The tool requirements could not be found.
|
||||||
data NoToolRequirements = NoToolRequirements
|
data NoToolRequirements = NoToolRequirements
|
||||||
@@ -254,35 +259,35 @@ data NoToolRequirements = NoToolRequirements
|
|||||||
|
|
||||||
instance Pretty NoToolRequirements where
|
instance Pretty NoToolRequirements where
|
||||||
pPrint NoToolRequirements =
|
pPrint NoToolRequirements =
|
||||||
text [i|The Tool requirements could not be found.|]
|
text "The Tool requirements could not be found."
|
||||||
|
|
||||||
data InvalidBuildConfig = InvalidBuildConfig Text
|
data InvalidBuildConfig = InvalidBuildConfig Text
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
instance Pretty InvalidBuildConfig where
|
instance Pretty InvalidBuildConfig where
|
||||||
pPrint (InvalidBuildConfig reason) =
|
pPrint (InvalidBuildConfig reason) =
|
||||||
text [i|The build config is invalid. Reason was: #{reason}|]
|
text "The build config is invalid. Reason was:" <+> pPrint reason
|
||||||
|
|
||||||
data NoToolVersionSet = NoToolVersionSet Tool
|
data NoToolVersionSet = NoToolVersionSet Tool
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
instance Pretty NoToolVersionSet where
|
instance Pretty NoToolVersionSet where
|
||||||
pPrint (NoToolVersionSet tool) =
|
pPrint (NoToolVersionSet tool) =
|
||||||
text [i|No version is set for tool "#{tool}".|]
|
text "No version is set for tool" <+> pPrint tool <+> text "."
|
||||||
|
|
||||||
data NoNetwork = NoNetwork
|
data NoNetwork = NoNetwork
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
instance Pretty NoNetwork where
|
instance Pretty NoNetwork where
|
||||||
pPrint NoNetwork =
|
pPrint NoNetwork =
|
||||||
text [i|A download was required or requested, but '--offline' was specified.|]
|
text "A download was required or requested, but '--offline' was specified."
|
||||||
|
|
||||||
data HadrianNotFound = HadrianNotFound
|
data HadrianNotFound = HadrianNotFound
|
||||||
deriving Show
|
deriving Show
|
||||||
|
|
||||||
instance Pretty HadrianNotFound where
|
instance Pretty HadrianNotFound where
|
||||||
pPrint HadrianNotFound =
|
pPrint HadrianNotFound =
|
||||||
text [i|Could not find Hadrian build files. Does this GHC version support Hadrian builds?|]
|
text "Could not find Hadrian build files. Does this GHC version support Hadrian builds?"
|
||||||
|
|
||||||
|
|
||||||
-------------------------
|
-------------------------
|
||||||
@@ -290,31 +295,37 @@ instance Pretty HadrianNotFound where
|
|||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
-- | A download failed. The underlying error is encapsulated.
|
-- | A download failed. The underlying error is encapsulated.
|
||||||
data DownloadFailed = forall x xs . (Show x, Show (V xs), Pretty x, Pretty (V xs)) => DownloadFailed (V (x ': xs))
|
data DownloadFailed = forall xs . (ToVariantMaybe DownloadFailed xs, PopVariant DownloadFailed xs, Show (V xs), Pretty (V xs)) => DownloadFailed (V xs)
|
||||||
|
|
||||||
instance Pretty DownloadFailed where
|
instance Pretty DownloadFailed where
|
||||||
pPrint (DownloadFailed reason) =
|
pPrint (DownloadFailed reason) =
|
||||||
text "Download failed:" <+> pPrint reason
|
case reason of
|
||||||
|
VMaybe (_ :: DownloadFailed) -> pPrint reason
|
||||||
|
_ -> text "Download failed:" <+> pPrint reason
|
||||||
|
|
||||||
deriving instance Show DownloadFailed
|
deriving instance Show DownloadFailed
|
||||||
|
|
||||||
|
|
||||||
-- | A build failed.
|
-- | A build failed.
|
||||||
data BuildFailed = forall es . (Pretty (V es), Show (V es)) => BuildFailed FilePath (V es)
|
data BuildFailed = forall es . (ToVariantMaybe BuildFailed es, PopVariant BuildFailed es, Pretty (V es), Show (V es)) => BuildFailed FilePath (V es)
|
||||||
|
|
||||||
instance Pretty BuildFailed where
|
instance Pretty BuildFailed where
|
||||||
pPrint (BuildFailed path reason) =
|
pPrint (BuildFailed path reason) =
|
||||||
text [i|BuildFailed failed in dir "#{path}": |] <> pPrint reason
|
case reason of
|
||||||
|
VMaybe (_ :: BuildFailed) -> pPrint reason
|
||||||
|
_ -> text "BuildFailed failed in dir" <+> text (path <> ":") <+> pPrint reason
|
||||||
|
|
||||||
deriving instance Show BuildFailed
|
deriving instance Show BuildFailed
|
||||||
|
|
||||||
|
|
||||||
-- | Setting the current GHC version failed.
|
-- | Setting the current GHC version failed.
|
||||||
data GHCupSetError = forall es . Show (V es) => GHCupSetError (V es)
|
data GHCupSetError = forall es . (ToVariantMaybe GHCupSetError es, PopVariant GHCupSetError es, Show (V es), Pretty (V es)) => GHCupSetError (V es)
|
||||||
|
|
||||||
instance Pretty GHCupSetError where
|
instance Pretty GHCupSetError where
|
||||||
pPrint (GHCupSetError reason) =
|
pPrint (GHCupSetError reason) =
|
||||||
text [i|Setting the current GHC version failed: #{reason}|]
|
case reason of
|
||||||
|
VMaybe (_ :: GHCupSetError) -> pPrint reason
|
||||||
|
_ -> text "Setting the current GHC version failed:" <+> pPrint reason
|
||||||
|
|
||||||
deriving instance Show GHCupSetError
|
deriving instance Show GHCupSetError
|
||||||
|
|
||||||
@@ -330,7 +341,7 @@ data ParseError = ParseError String
|
|||||||
|
|
||||||
instance Pretty ParseError where
|
instance Pretty ParseError where
|
||||||
pPrint (ParseError reason) =
|
pPrint (ParseError reason) =
|
||||||
text [i|Parsing failed: #{reason}|]
|
text "Parsing failed:" <+> pPrint reason
|
||||||
|
|
||||||
instance Exception ParseError
|
instance Exception ParseError
|
||||||
|
|
||||||
@@ -340,7 +351,7 @@ data UnexpectedListLength = UnexpectedListLength String
|
|||||||
|
|
||||||
instance Pretty UnexpectedListLength where
|
instance Pretty UnexpectedListLength where
|
||||||
pPrint (UnexpectedListLength reason) =
|
pPrint (UnexpectedListLength reason) =
|
||||||
text [i|List length unexpected: #{reason}|]
|
text "List length unexpected:" <+> pPrint reason
|
||||||
|
|
||||||
instance Exception UnexpectedListLength
|
instance Exception UnexpectedListLength
|
||||||
|
|
||||||
@@ -349,7 +360,7 @@ data NoUrlBase = NoUrlBase Text
|
|||||||
|
|
||||||
instance Pretty NoUrlBase where
|
instance Pretty NoUrlBase where
|
||||||
pPrint (NoUrlBase url) =
|
pPrint (NoUrlBase url) =
|
||||||
text [i|Couldn't get a base filename from url #{url}|]
|
text "Couldn't get a base filename from url" <+> pPrint url
|
||||||
|
|
||||||
instance Exception NoUrlBase
|
instance Exception NoUrlBase
|
||||||
|
|
||||||
@@ -374,23 +385,22 @@ instance
|
|||||||
|
|
||||||
instance Pretty URIParseError where
|
instance Pretty URIParseError where
|
||||||
pPrint (MalformedScheme reason) =
|
pPrint (MalformedScheme reason) =
|
||||||
text [i|Failed to parse URI. Malformed scheme: #{reason}|]
|
text "Failed to parse URI. Malformed scheme:" <+> text (show reason)
|
||||||
pPrint MalformedUserInfo =
|
pPrint MalformedUserInfo =
|
||||||
text [i|Failed to parse URI. Malformed user info.|]
|
text "Failed to parse URI. Malformed user info."
|
||||||
pPrint MalformedQuery =
|
pPrint MalformedQuery =
|
||||||
text [i|Failed to parse URI. Malformed query.|]
|
text "Failed to parse URI. Malformed query."
|
||||||
pPrint MalformedFragment =
|
pPrint MalformedFragment =
|
||||||
text [i|Failed to parse URI. Malformed fragment.|]
|
text "Failed to parse URI. Malformed fragment."
|
||||||
pPrint MalformedHost =
|
pPrint MalformedHost =
|
||||||
text [i|Failed to parse URI. Malformed host.|]
|
text "Failed to parse URI. Malformed host."
|
||||||
pPrint MalformedPort =
|
pPrint MalformedPort =
|
||||||
text [i|Failed to parse URI. Malformed port.|]
|
text "Failed to parse URI. Malformed port."
|
||||||
pPrint MalformedPath =
|
pPrint MalformedPath =
|
||||||
text [i|Failed to parse URI. Malformed path.|]
|
text "Failed to parse URI. Malformed path."
|
||||||
pPrint (OtherError err) =
|
pPrint (OtherError err) =
|
||||||
text [i|Failed to parse URI: #{err}|]
|
text "Failed to parse URI:" <+> pPrint err
|
||||||
|
|
||||||
#if !defined(TAR)
|
|
||||||
instance Pretty ArchiveResult where
|
instance Pretty ArchiveResult where
|
||||||
pPrint ArchiveFatal = text "Archive result: fatal"
|
pPrint ArchiveFatal = text "Archive result: fatal"
|
||||||
pPrint ArchiveFailed = text "Archive result: failed"
|
pPrint ArchiveFailed = text "Archive result: failed"
|
||||||
@@ -398,14 +408,6 @@ instance Pretty ArchiveResult where
|
|||||||
pPrint ArchiveRetry = text "Archive result: retry"
|
pPrint ArchiveRetry = text "Archive result: retry"
|
||||||
pPrint ArchiveOk = text "Archive result: Ok"
|
pPrint ArchiveOk = text "Archive result: Ok"
|
||||||
pPrint ArchiveEOF = text "Archive result: EOF"
|
pPrint ArchiveEOF = text "Archive result: EOF"
|
||||||
#else
|
|
||||||
instance Pretty Tar.FormatError where
|
instance Pretty T.Text where
|
||||||
pPrint Tar.TruncatedArchive = text "Truncated archive"
|
pPrint = text . T.unpack
|
||||||
pPrint Tar.ShortTrailer = text "Short trailer"
|
|
||||||
pPrint Tar.BadTrailer = text "Bad trailer"
|
|
||||||
pPrint Tar.TrailingJunk = text "Trailing junk"
|
|
||||||
pPrint Tar.ChecksumIncorrect = text "Checksum incorrect"
|
|
||||||
pPrint Tar.NotTarFormat = text "Not a tar format"
|
|
||||||
pPrint Tar.UnrecognisedTarFormat = text "Unrecognised tar format"
|
|
||||||
pPrint Tar.HeaderBadNumericEncoding = text "Header has bad numeric encoding"
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -20,20 +20,20 @@ module GHCup.Platform where
|
|||||||
|
|
||||||
import GHCup.Errors
|
import GHCup.Errors
|
||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
|
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
|
||||||
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import Control.Exception.Safe
|
import Control.Exception.Safe
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.Logger
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Data.ByteString ( ByteString )
|
import Data.ByteString ( ByteString )
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.String.Interpolate
|
|
||||||
import Data.Text ( Text )
|
import Data.Text ( Text )
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
import Haskus.Utils.Variant.Excepts
|
import Haskus.Utils.Variant.Excepts
|
||||||
@@ -58,7 +58,7 @@ import qualified Data.Text.IO as T
|
|||||||
|
|
||||||
|
|
||||||
-- | Get the full platform request, consisting of architecture, distro, ...
|
-- | Get the full platform request, consisting of architecture, distro, ...
|
||||||
platformRequest :: (Alternative m, MonadFail m, MonadLogger m, MonadCatch m, MonadIO m)
|
platformRequest :: (MonadReader env m, Alternative m, MonadFail m, HasLog env, MonadCatch m, MonadIO m)
|
||||||
=> Excepts
|
=> Excepts
|
||||||
'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound]
|
'[NoCompatiblePlatform, NoCompatibleArch, DistroNotFound]
|
||||||
m
|
m
|
||||||
@@ -83,7 +83,7 @@ getArchitecture = case arch of
|
|||||||
what -> Left (NoCompatibleArch what)
|
what -> Left (NoCompatibleArch what)
|
||||||
|
|
||||||
|
|
||||||
getPlatform :: (Alternative m, MonadLogger m, MonadCatch m, MonadIO m, MonadFail m)
|
getPlatform :: (Alternative m, MonadReader env m, HasLog env, MonadCatch m, MonadIO m, MonadFail m)
|
||||||
=> Excepts
|
=> Excepts
|
||||||
'[NoCompatiblePlatform, DistroNotFound]
|
'[NoCompatiblePlatform, DistroNotFound]
|
||||||
m
|
m
|
||||||
@@ -108,7 +108,7 @@ getPlatform = do
|
|||||||
pure $ PlatformResult { _platform = FreeBSD, _distroVersion = ver }
|
pure $ PlatformResult { _platform = FreeBSD, _distroVersion = ver }
|
||||||
"mingw32" -> pure PlatformResult { _platform = Windows, _distroVersion = Nothing }
|
"mingw32" -> pure PlatformResult { _platform = Windows, _distroVersion = Nothing }
|
||||||
what -> throwE $ NoCompatiblePlatform what
|
what -> throwE $ NoCompatiblePlatform what
|
||||||
lift $ $(logDebug) [i|Identified Platform as: #{prettyShow pfr}|]
|
lift $ logDebug $ "Identified Platform as: " <> T.pack (prettyShow pfr)
|
||||||
pure pfr
|
pure pfr
|
||||||
where
|
where
|
||||||
getFreeBSDVersion = lift $ fmap _stdOut $ executeOut "freebsd-version" [] Nothing
|
getFreeBSDVersion = lift $ fmap _stdOut $ executeOut "freebsd-version" [] Nothing
|
||||||
@@ -142,9 +142,7 @@ getLinuxDistro = do
|
|||||||
| otherwise -> UnknownLinux
|
| otherwise -> UnknownLinux
|
||||||
pure (distro, parsedVer)
|
pure (distro, parsedVer)
|
||||||
where
|
where
|
||||||
hasWord t matches = foldr (\x y -> match (regex x) (T.unpack t) || y)
|
hasWord t = any (\x -> match (regex x) (T.unpack t))
|
||||||
False
|
|
||||||
matches
|
|
||||||
where
|
where
|
||||||
regex x = makeRegexOpts compIgnoreCase execBlank ([s|\<|] ++ x ++ [s|\>|])
|
regex x = makeRegexOpts compIgnoreCase execBlank ([s|\<|] ++ x ++ [s|\>|])
|
||||||
|
|
||||||
|
|||||||
@@ -60,9 +60,10 @@ 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 "
|
||||||
<> T.intercalate " " _distroPKGs
|
<> "and return at any time): "
|
||||||
|
<> 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 ""
|
||||||
in "System requirements " <> d <> n
|
in "System requirements " <> d <> n
|
||||||
|
|||||||
@@ -25,21 +25,17 @@ module GHCup.Types
|
|||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Control.Applicative
|
|
||||||
import Control.DeepSeq ( NFData, rnf )
|
import Control.DeepSeq ( NFData, rnf )
|
||||||
import Control.Monad.Logger
|
|
||||||
import Data.Map.Strict ( Map )
|
import Data.Map.Strict ( Map )
|
||||||
import Data.List.NonEmpty ( NonEmpty (..) )
|
import Data.List.NonEmpty ( NonEmpty (..) )
|
||||||
import Data.Text ( Text )
|
import Data.Text ( Text )
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
import Haskus.Utils.Variant.Excepts
|
|
||||||
import Text.PrettyPrint.HughesPJClass (Pretty, pPrint, text)
|
import Text.PrettyPrint.HughesPJClass (Pretty, pPrint, text)
|
||||||
import URI.ByteString
|
import URI.ByteString
|
||||||
#if defined(BRICK)
|
#if defined(BRICK)
|
||||||
import Graphics.Vty ( Key(..) )
|
import Graphics.Vty ( Key(..) )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
import qualified Control.Monad.Trans.Class as Trans
|
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified GHC.Generics as GHC
|
import qualified GHC.Generics as GHC
|
||||||
|
|
||||||
@@ -115,6 +111,13 @@ data Tool = GHC
|
|||||||
| Stack
|
| Stack
|
||||||
deriving (Eq, GHC.Generic, Ord, Show, Enum, Bounded)
|
deriving (Eq, GHC.Generic, Ord, Show, Enum, Bounded)
|
||||||
|
|
||||||
|
instance Pretty Tool where
|
||||||
|
pPrint GHC = text "ghc"
|
||||||
|
pPrint Cabal = text "cabal"
|
||||||
|
pPrint GHCup = text "ghcup"
|
||||||
|
pPrint HLS = text "hls"
|
||||||
|
pPrint Stack = text "stack"
|
||||||
|
|
||||||
instance NFData Tool
|
instance NFData Tool
|
||||||
|
|
||||||
data GlobalTool = ShimGen
|
data GlobalTool = ShimGen
|
||||||
@@ -145,7 +148,7 @@ data Tag = Latest
|
|||||||
| Recommended
|
| Recommended
|
||||||
| Prerelease
|
| Prerelease
|
||||||
| Base PVP
|
| Base PVP
|
||||||
| Old -- ^ old version are hidden by default in TUI
|
| Old -- ^ old versions are hidden by default in TUI
|
||||||
| UnknownTag String -- ^ used for upwardscompat
|
| UnknownTag String -- ^ used for upwardscompat
|
||||||
deriving (Ord, Eq, GHC.Generic, Show) -- FIXME: manual JSON instance
|
deriving (Ord, Eq, GHC.Generic, Show) -- FIXME: manual JSON instance
|
||||||
|
|
||||||
@@ -233,7 +236,7 @@ instance NFData LinuxDistro
|
|||||||
distroToString :: LinuxDistro -> String
|
distroToString :: LinuxDistro -> String
|
||||||
distroToString Debian = "debian"
|
distroToString Debian = "debian"
|
||||||
distroToString Ubuntu = "ubuntu"
|
distroToString Ubuntu = "ubuntu"
|
||||||
distroToString Mint= "mint"
|
distroToString Mint = "mint"
|
||||||
distroToString Fedora = "fedora"
|
distroToString Fedora = "fedora"
|
||||||
distroToString CentOS = "centos"
|
distroToString CentOS = "centos"
|
||||||
distroToString RedHat = "redhat"
|
distroToString RedHat = "redhat"
|
||||||
@@ -298,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 =
|
||||||
@@ -315,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
|
||||||
@@ -337,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
|
||||||
@@ -387,6 +393,7 @@ data AppState = AppState
|
|||||||
, keyBindings :: KeyBindings
|
, keyBindings :: KeyBindings
|
||||||
, ghcupInfo :: GHCupInfo
|
, ghcupInfo :: GHCupInfo
|
||||||
, pfreq :: PlatformRequest
|
, pfreq :: PlatformRequest
|
||||||
|
, loggerConfig :: LoggerConfig
|
||||||
} deriving (Show, GHC.Generic)
|
} deriving (Show, GHC.Generic)
|
||||||
|
|
||||||
instance NFData AppState
|
instance NFData AppState
|
||||||
@@ -395,6 +402,7 @@ data LeanAppState = LeanAppState
|
|||||||
{ settings :: Settings
|
{ settings :: Settings
|
||||||
, dirs :: Dirs
|
, dirs :: Dirs
|
||||||
, keyBindings :: KeyBindings
|
, keyBindings :: KeyBindings
|
||||||
|
, loggerConfig :: LoggerConfig
|
||||||
} deriving (Show, GHC.Generic)
|
} deriving (Show, GHC.Generic)
|
||||||
|
|
||||||
instance NFData LeanAppState
|
instance NFData LeanAppState
|
||||||
@@ -408,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)
|
||||||
|
|
||||||
@@ -441,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
|
||||||
@@ -546,14 +563,26 @@ instance Pretty Versioning where
|
|||||||
instance Pretty Version where
|
instance Pretty Version where
|
||||||
pPrint = text . T.unpack . prettyVer
|
pPrint = text . T.unpack . prettyVer
|
||||||
|
|
||||||
|
instance Show (a -> b) where
|
||||||
|
show _ = "<function>"
|
||||||
|
|
||||||
instance (Monad m, Alternative m) => Alternative (LoggingT m) where
|
instance Show (IO ()) where
|
||||||
empty = Trans.lift empty
|
show _ = "<io>"
|
||||||
{-# INLINE empty #-}
|
|
||||||
m <|> n = LoggingT $ \ r -> runLoggingT m r <|> runLoggingT n r
|
|
||||||
{-# INLINE (<|>) #-}
|
|
||||||
|
|
||||||
|
|
||||||
instance MonadLogger m => MonadLogger (Excepts e m) where
|
data LogLevel = Warn
|
||||||
monadLoggerLog a b c d = Trans.lift $ monadLoggerLog a b c d
|
| Info
|
||||||
|
| Debug
|
||||||
|
| Error
|
||||||
|
deriving (Eq, Ord, Show)
|
||||||
|
|
||||||
|
data LoggerConfig = LoggerConfig
|
||||||
|
{ lcPrintDebug :: Bool -- ^ whether to print debug in colorOutter
|
||||||
|
, consoleOutter :: T.Text -> IO () -- ^ how to write the console output
|
||||||
|
, fileOutter :: T.Text -> IO () -- ^ how to write the file output
|
||||||
|
, fancyColors :: Bool
|
||||||
|
}
|
||||||
|
deriving Show
|
||||||
|
|
||||||
|
instance NFData LoggerConfig where
|
||||||
|
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
|
||||||
@@ -42,7 +44,7 @@ import qualified Text.Megaparsec as MP
|
|||||||
import qualified Text.Megaparsec.Char as MPC
|
import qualified Text.Megaparsec.Char as MPC
|
||||||
|
|
||||||
|
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } { fieldLabelModifier = removeLensFieldLabel } ''Architecture
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''Architecture
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''LinuxDistro
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''LinuxDistro
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VSep
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VSep
|
||||||
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VUnit
|
deriveJSON defaultOptions { fieldLabelModifier = removeLensFieldLabel } ''VUnit
|
||||||
@@ -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"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE AllowAmbiguousTypes #-}
|
{-# LANGUAGE AllowAmbiguousTypes #-}
|
||||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
Module : GHCup.Types.Optics
|
Module : GHCup.Types.Optics
|
||||||
@@ -21,10 +22,11 @@ module GHCup.Types.Optics where
|
|||||||
import GHCup.Types
|
import GHCup.Types
|
||||||
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Data.ByteString ( ByteString )
|
import Data.ByteString ( ByteString )
|
||||||
import Optics
|
import Optics
|
||||||
import URI.ByteString
|
import URI.ByteString
|
||||||
|
|
||||||
|
|
||||||
makePrisms ''Tool
|
makePrisms ''Tool
|
||||||
makePrisms ''Architecture
|
makePrisms ''Architecture
|
||||||
makePrisms ''LinuxDistro
|
makePrisms ''LinuxDistro
|
||||||
@@ -87,13 +89,15 @@ getLeanAppState :: ( MonadReader env m
|
|||||||
, LabelOptic' "settings" A_Lens env Settings
|
, LabelOptic' "settings" A_Lens env Settings
|
||||||
, LabelOptic' "dirs" A_Lens env Dirs
|
, LabelOptic' "dirs" A_Lens env Dirs
|
||||||
, LabelOptic' "keyBindings" A_Lens env KeyBindings
|
, LabelOptic' "keyBindings" A_Lens env KeyBindings
|
||||||
|
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
||||||
)
|
)
|
||||||
=> m LeanAppState
|
=> m LeanAppState
|
||||||
getLeanAppState = do
|
getLeanAppState = do
|
||||||
s <- gets @"settings"
|
s <- gets @"settings"
|
||||||
d <- gets @"dirs"
|
d <- gets @"dirs"
|
||||||
k <- gets @"keyBindings"
|
k <- gets @"keyBindings"
|
||||||
pure (LeanAppState s d k)
|
l <- gets @"loggerConfig"
|
||||||
|
pure (LeanAppState s d k l)
|
||||||
|
|
||||||
|
|
||||||
getSettings :: ( MonadReader env m
|
getSettings :: ( MonadReader env m
|
||||||
@@ -110,6 +114,13 @@ getDirs :: ( MonadReader env m
|
|||||||
getDirs = gets @"dirs"
|
getDirs = gets @"dirs"
|
||||||
|
|
||||||
|
|
||||||
|
getLogCleanup :: ( MonadReader env m
|
||||||
|
, LabelOptic' "logCleanup" A_Lens env (IO ())
|
||||||
|
)
|
||||||
|
=> m (IO ())
|
||||||
|
getLogCleanup = gets @"logCleanup"
|
||||||
|
|
||||||
|
|
||||||
getKeyBindings :: ( MonadReader env m
|
getKeyBindings :: ( MonadReader env m
|
||||||
, LabelOptic' "keyBindings" A_Lens env KeyBindings
|
, LabelOptic' "keyBindings" A_Lens env KeyBindings
|
||||||
)
|
)
|
||||||
@@ -136,6 +147,7 @@ type HasDirs env = (LabelOptic' "dirs" A_Lens env Dirs)
|
|||||||
type HasKeyBindings env = (LabelOptic' "keyBindings" A_Lens env KeyBindings)
|
type HasKeyBindings env = (LabelOptic' "keyBindings" A_Lens env KeyBindings)
|
||||||
type HasGHCupInfo env = (LabelOptic' "ghcupInfo" A_Lens env GHCupInfo)
|
type HasGHCupInfo env = (LabelOptic' "ghcupInfo" A_Lens env GHCupInfo)
|
||||||
type HasPlatformReq env = (LabelOptic' "pfreq" A_Lens env PlatformRequest)
|
type HasPlatformReq env = (LabelOptic' "pfreq" A_Lens env PlatformRequest)
|
||||||
|
type HasLog env = (LabelOptic' "loggerConfig" A_Lens env LoggerConfig)
|
||||||
|
|
||||||
|
|
||||||
getCache :: (MonadReader env m, HasSettings env) => m Bool
|
getCache :: (MonadReader env m, HasSettings env) => m Bool
|
||||||
|
|||||||
@@ -35,21 +35,18 @@ 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
|
||||||
|
|
||||||
#if !defined(TAR)
|
|
||||||
import Codec.Archive hiding ( Directory )
|
import Codec.Archive hiding ( Directory )
|
||||||
#endif
|
|
||||||
import Codec.Archive.Zip
|
|
||||||
import Control.Applicative
|
import Control.Applicative
|
||||||
import Control.Exception.Safe
|
import Control.Exception.Safe
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
#if !MIN_VERSION_base(4,13,0)
|
#if !MIN_VERSION_base(4,13,0)
|
||||||
import Control.Monad.Fail ( MonadFail )
|
import Control.Monad.Fail ( MonadFail )
|
||||||
#endif
|
#endif
|
||||||
import Control.Monad.Logger
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Control.Monad.Trans.Resource
|
import Control.Monad.Trans.Resource
|
||||||
hiding ( throwM )
|
hiding ( throwM )
|
||||||
@@ -61,10 +58,8 @@ import Data.ByteString ( ByteString )
|
|||||||
import Data.Either
|
import Data.Either
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
import Data.List
|
import Data.List
|
||||||
import Data.List.Extra
|
|
||||||
import Data.List.NonEmpty ( NonEmpty( (:|) ))
|
import Data.List.NonEmpty ( NonEmpty( (:|) ))
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.String.Interpolate
|
|
||||||
import Data.Text ( Text )
|
import Data.Text ( Text )
|
||||||
import Data.Versions
|
import Data.Versions
|
||||||
import GHC.IO.Exception
|
import GHC.IO.Exception
|
||||||
@@ -83,9 +78,6 @@ import Text.PrettyPrint.HughesPJClass hiding ( (<>) )
|
|||||||
import Text.Regex.Posix
|
import Text.Regex.Posix
|
||||||
import URI.ByteString
|
import URI.ByteString
|
||||||
|
|
||||||
#if defined(TAR)
|
|
||||||
import qualified Codec.Archive.Tar as Tar
|
|
||||||
#endif
|
|
||||||
import qualified Codec.Compression.BZip as BZip
|
import qualified Codec.Compression.BZip as BZip
|
||||||
import qualified Codec.Compression.GZip as GZip
|
import qualified Codec.Compression.GZip as GZip
|
||||||
import qualified Codec.Compression.Lzma as Lzma
|
import qualified Codec.Compression.Lzma as Lzma
|
||||||
@@ -94,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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -121,7 +142,7 @@ ghcLinkDestination tool ver = do
|
|||||||
rmMinorSymlinks :: ( MonadReader env m
|
rmMinorSymlinks :: ( MonadReader env m
|
||||||
, HasDirs env
|
, HasDirs env
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadLogger m
|
, HasLog env
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, MonadFail m
|
, MonadFail m
|
||||||
, MonadMask m
|
, MonadMask m
|
||||||
@@ -135,14 +156,14 @@ rmMinorSymlinks tv@GHCTargetVersion{..} = do
|
|||||||
forM_ files $ \f -> do
|
forM_ files $ \f -> do
|
||||||
let f_xyz = f <> "-" <> T.unpack (prettyVer _tvVersion) <> exeExt
|
let f_xyz = f <> "-" <> T.unpack (prettyVer _tvVersion) <> exeExt
|
||||||
let fullF = binDir </> f_xyz
|
let fullF = binDir </> f_xyz
|
||||||
lift $ $(logDebug) [i|rm -f #{fullF}|]
|
lift $ logDebug ("rm -f " <> T.pack fullF)
|
||||||
lift $ hideError doesNotExistErrorType $ rmLink fullF
|
lift $ hideError doesNotExistErrorType $ rmLink fullF
|
||||||
|
|
||||||
|
|
||||||
-- | Removes the set ghc version for the given target, if any.
|
-- | Removes the set ghc version for the given target, if any.
|
||||||
rmPlain :: ( MonadReader env m
|
rmPlain :: ( MonadReader env m
|
||||||
, HasDirs env
|
, HasDirs env
|
||||||
, MonadLogger m
|
, HasLog env
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, MonadFail m
|
, MonadFail m
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
@@ -157,11 +178,11 @@ rmPlain target = do
|
|||||||
files <- liftE $ ghcToolFiles tv
|
files <- liftE $ ghcToolFiles tv
|
||||||
forM_ files $ \f -> do
|
forM_ files $ \f -> do
|
||||||
let fullF = binDir </> f <> exeExt
|
let fullF = binDir </> f <> exeExt
|
||||||
lift $ $(logDebug) [i|rm -f #{fullF}|]
|
lift $ logDebug ("rm -f " <> T.pack fullF)
|
||||||
lift $ hideError doesNotExistErrorType $ rmLink fullF
|
lift $ hideError doesNotExistErrorType $ rmLink fullF
|
||||||
-- old ghcup
|
-- old ghcup
|
||||||
let hdc_file = binDir </> "haddock-ghc" <> exeExt
|
let hdc_file = binDir </> "haddock-ghc" <> exeExt
|
||||||
lift $ $(logDebug) [i|rm -f #{hdc_file}|]
|
lift $ logDebug ("rm -f " <> T.pack hdc_file)
|
||||||
lift $ hideError doesNotExistErrorType $ rmLink hdc_file
|
lift $ hideError doesNotExistErrorType $ rmLink hdc_file
|
||||||
|
|
||||||
|
|
||||||
@@ -169,7 +190,7 @@ rmPlain target = do
|
|||||||
rmMajorSymlinks :: ( MonadReader env m
|
rmMajorSymlinks :: ( MonadReader env m
|
||||||
, HasDirs env
|
, HasDirs env
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadLogger m
|
, HasLog env
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, MonadFail m
|
, MonadFail m
|
||||||
, MonadMask m
|
, MonadMask m
|
||||||
@@ -185,7 +206,7 @@ rmMajorSymlinks tv@GHCTargetVersion{..} = do
|
|||||||
forM_ files $ \f -> do
|
forM_ files $ \f -> do
|
||||||
let f_xy = f <> "-" <> T.unpack v' <> exeExt
|
let f_xy = f <> "-" <> T.unpack v' <> exeExt
|
||||||
let fullF = binDir </> f_xy
|
let fullF = binDir </> f_xy
|
||||||
lift $ $(logDebug) [i|rm -f #{fullF}|]
|
lift $ logDebug ("rm -f " <> T.pack fullF)
|
||||||
lift $ hideError doesNotExistErrorType $ rmLink fullF
|
lift $ hideError doesNotExistErrorType $ rmLink fullF
|
||||||
|
|
||||||
|
|
||||||
@@ -257,8 +278,7 @@ getInstalledGHCs = do
|
|||||||
|
|
||||||
|
|
||||||
-- | Get all installed cabals, by matching on @~\/.ghcup\/bin/cabal-*@.
|
-- | Get all installed cabals, by matching on @~\/.ghcup\/bin/cabal-*@.
|
||||||
getInstalledCabals :: ( MonadLogger m
|
getInstalledCabals :: ( MonadReader env m
|
||||||
, MonadReader env m
|
|
||||||
, HasDirs env
|
, HasDirs env
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadCatch m
|
, MonadCatch m
|
||||||
@@ -277,14 +297,14 @@ getInstalledCabals = do
|
|||||||
|
|
||||||
|
|
||||||
-- | Whether the given cabal version is installed.
|
-- | Whether the given cabal version is installed.
|
||||||
cabalInstalled :: (MonadLogger m, 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
|
||||||
|
|
||||||
|
|
||||||
-- Return the currently set cabal version, if any.
|
-- Return the currently set cabal version, if any.
|
||||||
cabalSet :: (MonadLogger m, MonadReader env m, HasDirs env, MonadIO m, MonadThrow m, MonadCatch m) => m (Maybe Version)
|
cabalSet :: (HasLog env, MonadReader env m, HasDirs env, MonadIO m, MonadThrow m, MonadCatch m) => m (Maybe Version)
|
||||||
cabalSet = do
|
cabalSet = do
|
||||||
Dirs {..} <- getDirs
|
Dirs {..} <- getDirs
|
||||||
let cabalbin = binDir </> "cabal" <> exeExt
|
let cabalbin = binDir </> "cabal" <> exeExt
|
||||||
@@ -301,7 +321,11 @@ cabalSet = do
|
|||||||
case linkVersion =<< link of
|
case linkVersion =<< link of
|
||||||
Right v -> pure $ Just v
|
Right v -> pure $ Just v
|
||||||
Left err -> do
|
Left err -> do
|
||||||
$(logWarn) [i|Failed to parse cabal symlink target with: "#{err}". The symlink #{cabalbin} needs to point to valid cabal binary, such as 'cabal-3.4.0.0'.|]
|
logWarn $ "Failed to parse cabal symlink target with: "
|
||||||
|
<> T.pack (displayException err)
|
||||||
|
<> ". The symlink "
|
||||||
|
<> T.pack cabalbin
|
||||||
|
<> " needs to point to valid cabal binary, such as 'cabal-3.4.0.0'."
|
||||||
pure Nothing
|
pure Nothing
|
||||||
where
|
where
|
||||||
-- We try to be extra permissive with link destination parsing,
|
-- We try to be extra permissive with link destination parsing,
|
||||||
@@ -368,7 +392,7 @@ getInstalledStacks = do
|
|||||||
|
|
||||||
-- Return the currently set stack version, if any.
|
-- Return the currently set stack version, if any.
|
||||||
-- TODO: there's a lot of code duplication here :>
|
-- TODO: there's a lot of code duplication here :>
|
||||||
stackSet :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m, MonadCatch m, MonadLogger m) => m (Maybe Version)
|
stackSet :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m, MonadCatch m, HasLog env) => m (Maybe Version)
|
||||||
stackSet = do
|
stackSet = do
|
||||||
Dirs {..} <- getDirs
|
Dirs {..} <- getDirs
|
||||||
let stackBin = binDir </> "stack" <> exeExt
|
let stackBin = binDir </> "stack" <> exeExt
|
||||||
@@ -385,7 +409,11 @@ stackSet = do
|
|||||||
case linkVersion =<< link of
|
case linkVersion =<< link of
|
||||||
Right v -> pure $ Just v
|
Right v -> pure $ Just v
|
||||||
Left err -> do
|
Left err -> do
|
||||||
$(logWarn) [i|Failed to parse stack symlink target with: "#{err}". The symlink #{stackBin} needs to point to valid stack binary, such as 'stack-2.7.1'.|]
|
logWarn $ "Failed to parse stack symlink target with: "
|
||||||
|
<> T.pack (displayException err)
|
||||||
|
<> ". The symlink "
|
||||||
|
<> T.pack stackBin
|
||||||
|
<> " needs to point to valid stack binary, such as 'stack-2.7.1'."
|
||||||
pure Nothing
|
pure Nothing
|
||||||
where
|
where
|
||||||
linkVersion :: MonadThrow m => FilePath -> m Version
|
linkVersion :: MonadThrow m => FilePath -> m Version
|
||||||
@@ -476,7 +504,7 @@ hlsGHCVersions = do
|
|||||||
. splitOn "~"
|
. splitOn "~"
|
||||||
)
|
)
|
||||||
bins
|
bins
|
||||||
pure . rights . concat . maybeToList $ vers
|
pure . sortBy (flip compare) . rights . concat . maybeToList $ vers
|
||||||
|
|
||||||
|
|
||||||
-- | Get all server binaries for an hls version, if any.
|
-- | Get all server binaries for an hls version, if any.
|
||||||
@@ -560,34 +588,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)
|
||||||
-> Maybe Text -- ^ the target triple
|
-- PVP version.
|
||||||
-> m (Maybe GHCTargetVersion)
|
getGHCForPVP :: (MonadReader env m, HasDirs env, MonadIO m, MonadThrow m)
|
||||||
getGHCForMajor major' minor' mt = do
|
=> PVP
|
||||||
|
-> Maybe Text -- ^ the target triple
|
||||||
|
-> m (Maybe GHCTargetVersion)
|
||||||
|
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.
|
||||||
. filter
|
--
|
||||||
(\GHCTargetVersion {..} ->
|
-- >>> fmap prettyShow $ getGHCForPVP' [pver|8|] installedVersions Nothing
|
||||||
_tvTarget == mt && matchMajor _tvVersion major' minor'
|
-- "Just 8.10.7"
|
||||||
)
|
-- >>> fmap prettyShow $ getGHCForPVP' [pver|8.8|] installedVersions Nothing
|
||||||
$ ghcs
|
-- "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
|
||||||
|
(\(pvp_, target) ->
|
||||||
|
target == mt && matchPVPrefix pvp_ pvpIn
|
||||||
|
)
|
||||||
|
$ 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
|
--
|
||||||
-> GHCupDownloads
|
-- >>> (fmap . fmap) fst $ getLatestToolFor GHC [pver|8|] r
|
||||||
-> Maybe (Version, VersionInfo)
|
-- Just (PVP {_pComponents = 8 :| [10,7]})
|
||||||
getLatestGHCFor major' minor' dls =
|
-- >>> (fmap . fmap) fst $ getLatestToolFor GHC [pver|8.8|] r
|
||||||
preview (ix GHC % to Map.toDescList) dls >>= lastMay . filter (\(v, _) -> matchMajor v major' minor')
|
-- 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
|
||||||
|
-> m (Maybe (PVP, VersionInfo))
|
||||||
|
getLatestToolFor tool pvpIn dls = do
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -599,31 +676,21 @@ getLatestGHCFor major' minor' dls =
|
|||||||
|
|
||||||
|
|
||||||
-- | Unpack an archive to a temporary directory and return that path.
|
-- | Unpack an archive to a temporary directory and return that path.
|
||||||
unpackToDir :: (MonadLogger m, MonadIO m, MonadThrow m)
|
unpackToDir :: (MonadReader env m, HasLog env, MonadIO m, MonadThrow m)
|
||||||
=> FilePath -- ^ destination dir
|
=> FilePath -- ^ destination dir
|
||||||
-> FilePath -- ^ archive path
|
-> FilePath -- ^ archive path
|
||||||
-> Excepts '[UnknownArchive
|
-> Excepts '[UnknownArchive
|
||||||
#if !defined(TAR)
|
|
||||||
, ArchiveResult
|
, ArchiveResult
|
||||||
#endif
|
|
||||||
] m ()
|
] m ()
|
||||||
unpackToDir dfp av = do
|
unpackToDir dfp av = do
|
||||||
let fn = takeFileName av
|
let fn = takeFileName av
|
||||||
lift $ $(logInfo) [i|Unpacking: #{fn} to #{dfp}|]
|
lift $ logInfo $ "Unpacking: " <> T.pack fn <> " to " <> T.pack dfp
|
||||||
|
|
||||||
#if defined(TAR)
|
|
||||||
let untar :: MonadIO m => BL.ByteString -> Excepts '[] m ()
|
|
||||||
untar = liftIO . Tar.unpack dfp . Tar.read
|
|
||||||
|
|
||||||
rf :: MonadIO m => FilePath -> Excepts '[] m BL.ByteString
|
|
||||||
rf = liftIO . BL.readFile
|
|
||||||
#else
|
|
||||||
let untar :: MonadIO m => BL.ByteString -> Excepts '[ArchiveResult] m ()
|
let untar :: MonadIO m => BL.ByteString -> Excepts '[ArchiveResult] m ()
|
||||||
untar = lEM . liftIO . runArchiveM . unpackToDirLazy dfp
|
untar = lEM . liftIO . runArchiveM . unpackToDirLazy dfp
|
||||||
|
|
||||||
rf :: MonadIO m => FilePath -> Excepts '[ArchiveResult] m BL.ByteString
|
rf :: MonadIO m => FilePath -> Excepts '[ArchiveResult] m BL.ByteString
|
||||||
rf = liftIO . BL.readFile
|
rf = liftIO . BL.readFile
|
||||||
#endif
|
|
||||||
|
|
||||||
-- extract, depending on file extension
|
-- extract, depending on file extension
|
||||||
if
|
if
|
||||||
@@ -636,42 +703,23 @@ unpackToDir dfp av = do
|
|||||||
| ".tar.bz2" `isSuffixOf` fn ->
|
| ".tar.bz2" `isSuffixOf` fn ->
|
||||||
liftE (untar . BZip.decompress =<< rf av)
|
liftE (untar . BZip.decompress =<< rf av)
|
||||||
| ".tar" `isSuffixOf` fn -> liftE (untar =<< rf av)
|
| ".tar" `isSuffixOf` fn -> liftE (untar =<< rf av)
|
||||||
| ".zip" `isSuffixOf` fn ->
|
| ".zip" `isSuffixOf` fn -> liftE (untar =<< rf av)
|
||||||
withArchive av (unpackInto dfp)
|
|
||||||
| otherwise -> throwE $ UnknownArchive fn
|
| otherwise -> throwE $ UnknownArchive fn
|
||||||
|
|
||||||
|
|
||||||
getArchiveFiles :: (MonadLogger m, MonadIO m, MonadThrow m)
|
getArchiveFiles :: (MonadReader env m, HasLog env, MonadIO m, MonadThrow m)
|
||||||
=> FilePath -- ^ archive path
|
=> FilePath -- ^ archive path
|
||||||
-> Excepts '[UnknownArchive
|
-> Excepts '[UnknownArchive
|
||||||
#if defined(TAR)
|
|
||||||
, Tar.FormatError
|
|
||||||
#else
|
|
||||||
, ArchiveResult
|
, ArchiveResult
|
||||||
#endif
|
|
||||||
] m [FilePath]
|
] m [FilePath]
|
||||||
getArchiveFiles av = do
|
getArchiveFiles av = do
|
||||||
let fn = takeFileName av
|
let fn = takeFileName av
|
||||||
|
|
||||||
#if defined(TAR)
|
|
||||||
let entries :: Monad m => BL.ByteString -> Excepts '[Tar.FormatError] m [FilePath]
|
|
||||||
entries =
|
|
||||||
lE @Tar.FormatError
|
|
||||||
. Tar.foldEntries
|
|
||||||
(\e x -> fmap (Tar.entryPath e :) x)
|
|
||||||
(Right [])
|
|
||||||
(\e -> Left e)
|
|
||||||
. Tar.read
|
|
||||||
|
|
||||||
rf :: MonadIO m => FilePath -> Excepts '[Tar.FormatError] m BL.ByteString
|
|
||||||
rf = liftIO . BL.readFile
|
|
||||||
#else
|
|
||||||
let entries :: Monad m => BL.ByteString -> Excepts '[ArchiveResult] m [FilePath]
|
let entries :: Monad m => BL.ByteString -> Excepts '[ArchiveResult] m [FilePath]
|
||||||
entries = (fmap . fmap) filepath . lE . readArchiveBSL
|
entries = (fmap . fmap) filepath . lE . readArchiveBSL
|
||||||
|
|
||||||
rf :: MonadIO m => FilePath -> Excepts '[ArchiveResult] m BL.ByteString
|
rf :: MonadIO m => FilePath -> Excepts '[ArchiveResult] m BL.ByteString
|
||||||
rf = liftIO . BL.readFile
|
rf = liftIO . BL.readFile
|
||||||
#endif
|
|
||||||
|
|
||||||
-- extract, depending on file extension
|
-- extract, depending on file extension
|
||||||
if
|
if
|
||||||
@@ -684,14 +732,11 @@ getArchiveFiles av = do
|
|||||||
| ".tar.bz2" `isSuffixOf` fn ->
|
| ".tar.bz2" `isSuffixOf` fn ->
|
||||||
liftE (entries . BZip.decompress =<< rf av)
|
liftE (entries . BZip.decompress =<< rf av)
|
||||||
| ".tar" `isSuffixOf` fn -> liftE (entries =<< rf av)
|
| ".tar" `isSuffixOf` fn -> liftE (entries =<< rf av)
|
||||||
| ".zip" `isSuffixOf` fn ->
|
| ".zip" `isSuffixOf` fn -> liftE (entries =<< rf av)
|
||||||
withArchive av $ do
|
|
||||||
entries' <- getEntries
|
|
||||||
pure $ fmap unEntrySelector $ Map.keys entries'
|
|
||||||
| otherwise -> throwE $ UnknownArchive fn
|
| otherwise -> throwE $ UnknownArchive fn
|
||||||
|
|
||||||
|
|
||||||
intoSubdir :: (MonadLogger m, MonadIO m, MonadThrow m, MonadCatch m)
|
intoSubdir :: (MonadReader env m, HasLog env, MonadIO m, MonadThrow m, MonadCatch m)
|
||||||
=> FilePath -- ^ unpacked tar dir
|
=> FilePath -- ^ unpacked tar dir
|
||||||
-> TarDir -- ^ how to descend
|
-> TarDir -- ^ how to descend
|
||||||
-> Excepts '[TarDirDoesNotExist] m FilePath
|
-> Excepts '[TarDirDoesNotExist] m FilePath
|
||||||
@@ -819,14 +864,19 @@ makeOut args workdir = do
|
|||||||
|
|
||||||
-- | Try to apply patches in order. Fails with 'PatchFailed'
|
-- | Try to apply patches in order. Fails with 'PatchFailed'
|
||||||
-- on first failure.
|
-- on first failure.
|
||||||
applyPatches :: (MonadReader env m, HasDirs env, MonadLogger m, MonadIO m)
|
applyPatches :: (MonadReader env m, HasDirs env, HasLog env, MonadIO m)
|
||||||
=> FilePath -- ^ dir containing patches
|
=> FilePath -- ^ dir containing patches
|
||||||
-> FilePath -- ^ dir to apply patches in
|
-> FilePath -- ^ dir to apply patches in
|
||||||
-> Excepts '[PatchFailed] m ()
|
-> Excepts '[PatchFailed] m ()
|
||||||
applyPatches pdir ddir = do
|
applyPatches pdir ddir = do
|
||||||
patches <- (fmap . fmap) (pdir </>) $ liftIO $ listDirectory pdir
|
patches <- (fmap . fmap) (pdir </>) $ liftIO $ findFiles
|
||||||
|
pdir
|
||||||
|
(makeRegexOpts compExtended
|
||||||
|
execBlank
|
||||||
|
([s|.+\.(patch|diff)$|] :: ByteString)
|
||||||
|
)
|
||||||
forM_ (sort patches) $ \patch' -> do
|
forM_ (sort patches) $ \patch' -> do
|
||||||
lift $ $(logInfo) [i|Applying patch #{patch'}|]
|
lift $ logInfo $ "Applying patch " <> T.pack patch'
|
||||||
fmap (either (const Nothing) Just)
|
fmap (either (const Nothing) Just)
|
||||||
(exec
|
(exec
|
||||||
"patch"
|
"patch"
|
||||||
@@ -862,13 +912,17 @@ getChangeLog dls tool (Right tag) =
|
|||||||
-- 2. the install destination, depending on whether the build failed
|
-- 2. the install destination, depending on whether the build failed
|
||||||
runBuildAction :: ( Pretty (V e)
|
runBuildAction :: ( Pretty (V e)
|
||||||
, Show (V e)
|
, Show (V e)
|
||||||
|
, PopVariant BuildFailed e
|
||||||
|
, ToVariantMaybe BuildFailed e
|
||||||
, MonadReader env m
|
, MonadReader env m
|
||||||
, HasDirs env
|
, HasDirs env
|
||||||
, HasSettings env
|
, HasSettings env
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadMask m
|
, MonadMask m
|
||||||
, MonadLogger m
|
, 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
|
||||||
@@ -895,10 +949,10 @@ runBuildAction bdir instdir action = do
|
|||||||
|
|
||||||
-- | Remove a build directory, ignoring if it doesn't exist and gracefully
|
-- | Remove a build directory, ignoring if it doesn't exist and gracefully
|
||||||
-- printing other errors without crashing.
|
-- printing other errors without crashing.
|
||||||
rmBDir :: (MonadLogger m, MonadUnliftIO m, MonadIO m) => FilePath -> m ()
|
rmBDir :: (MonadReader env m, HasLog env, MonadUnliftIO m, MonadIO m) => FilePath -> m ()
|
||||||
rmBDir dir = withRunInIO (\run -> run $
|
rmBDir dir = withRunInIO (\run -> run $
|
||||||
liftIO $ handleIO (\e -> run $ $(logWarn)
|
liftIO $ handleIO (\e -> run $ logWarn $
|
||||||
[i|Couldn't remove build dir #{dir}, error was: #{displayException e}|])
|
"Couldn't remove build dir " <> T.pack dir <> ", error was: " <> T.pack (displayException e))
|
||||||
$ hideError doesNotExistErrorType
|
$ hideError doesNotExistErrorType
|
||||||
$ rmPathForcibly dir)
|
$ rmPathForcibly dir)
|
||||||
|
|
||||||
@@ -1010,7 +1064,7 @@ rmLink = hideError doesNotExistErrorType . recycleFile
|
|||||||
-- On windows, this requires that 'ensureGlobalTools' was run beforehand.
|
-- On windows, this requires that 'ensureGlobalTools' was run beforehand.
|
||||||
createLink :: ( MonadMask m
|
createLink :: ( MonadMask m
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, MonadLogger m
|
, HasLog env
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadReader env m
|
, MonadReader env m
|
||||||
, HasDirs env
|
, HasDirs env
|
||||||
@@ -1032,24 +1086,24 @@ createLink link exe = do
|
|||||||
fullLink = takeDirectory exe </> link
|
fullLink = takeDirectory exe </> link
|
||||||
shimContents = "path = " <> fullLink
|
shimContents = "path = " <> fullLink
|
||||||
|
|
||||||
$(logDebug) [i|rm -f #{exe}|]
|
logDebug $ "rm -f " <> T.pack exe
|
||||||
rmLink exe
|
rmLink exe
|
||||||
|
|
||||||
$(logDebug) [i|ln -s #{fullLink} #{exe}|]
|
logDebug $ "ln -s " <> T.pack fullLink <> " " <> T.pack exe
|
||||||
liftIO $ copyFile shimGen exe
|
liftIO $ copyFile shimGen exe
|
||||||
liftIO $ writeFile shim shimContents
|
liftIO $ writeFile shim shimContents
|
||||||
#else
|
#else
|
||||||
$(logDebug) [i|rm -f #{exe}|]
|
logDebug $ "rm -f " <> T.pack exe
|
||||||
hideError doesNotExistErrorType $ recycleFile exe
|
hideError doesNotExistErrorType $ recycleFile exe
|
||||||
|
|
||||||
$(logDebug) [i|ln -s #{link} #{exe}|]
|
logDebug $ "ln -s " <> T.pack link <> " " <> T.pack exe
|
||||||
liftIO $ createFileLink link exe
|
liftIO $ createFileLink link exe
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
ensureGlobalTools :: ( MonadMask m
|
ensureGlobalTools :: ( MonadMask m
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, MonadLogger m
|
, HasLog env
|
||||||
, MonadIO m
|
, MonadIO m
|
||||||
, MonadReader env m
|
, MonadReader env m
|
||||||
, HasDirs env
|
, HasDirs env
|
||||||
@@ -1058,7 +1112,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
|
||||||
@@ -1066,12 +1120,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) [i|Digest doesn't match, redownloading gs.exe...|]
|
lift $ logWarn "Digest doesn't match, redownloading gs.exe..."
|
||||||
lift $ $(logDebug) [i|rm -f #{shimDownload}|]
|
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 ()
|
||||||
|
|||||||
@@ -2,9 +2,7 @@
|
|||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE QuasiQuotes #-}
|
|
||||||
{-# LANGUAGE ViewPatterns #-}
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
Module : GHCup.Utils.Dirs
|
Module : GHCup.Utils.Dirs
|
||||||
@@ -40,17 +38,16 @@ 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
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.IO.Unlift
|
import Control.Monad.IO.Unlift
|
||||||
import Control.Monad.Logger
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Control.Monad.Trans.Resource hiding (throwM)
|
import Control.Monad.Trans.Resource hiding (throwM)
|
||||||
import Data.Bifunctor
|
import Data.Bifunctor
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.String.Interpolate
|
|
||||||
import GHC.IO.Exception ( IOErrorType(NoSuchThing) )
|
import GHC.IO.Exception ( IOErrorType(NoSuchThing) )
|
||||||
import Haskus.Utils.Variant.Excepts
|
import Haskus.Utils.Variant.Excepts
|
||||||
import Optics
|
import Optics
|
||||||
@@ -62,7 +59,7 @@ import System.IO.Temp
|
|||||||
|
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Yaml as Y
|
import qualified Data.YAML.Aeson as Y
|
||||||
import qualified Text.Megaparsec as MP
|
import qualified Text.Megaparsec as MP
|
||||||
import Control.Concurrent (threadDelay)
|
import Control.Concurrent (threadDelay)
|
||||||
|
|
||||||
@@ -225,7 +222,7 @@ ghcupConfigFile = do
|
|||||||
contents <- liftIO $ handleIO' NoSuchThing (\_ -> pure Nothing) $ Just <$> BS.readFile filepath
|
contents <- liftIO $ handleIO' NoSuchThing (\_ -> pure Nothing) $ Just <$> BS.readFile filepath
|
||||||
case contents of
|
case contents of
|
||||||
Nothing -> pure defaultUserSettings
|
Nothing -> pure defaultUserSettings
|
||||||
Just contents' -> lE' JSONDecodeError . first show . Y.decodeEither' $ contents'
|
Just contents' -> lE' JSONDecodeError . first snd . Y.decode1Strict $ contents'
|
||||||
|
|
||||||
|
|
||||||
-------------------------
|
-------------------------
|
||||||
@@ -262,7 +259,7 @@ parseGHCupGHCDir (T.pack -> fp) =
|
|||||||
mkGhcupTmpDir :: ( MonadReader env m
|
mkGhcupTmpDir :: ( MonadReader env m
|
||||||
, HasDirs env
|
, HasDirs env
|
||||||
, MonadUnliftIO m
|
, MonadUnliftIO m
|
||||||
, MonadLogger m
|
, HasLog env
|
||||||
, MonadCatch m
|
, MonadCatch m
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
, MonadMask m
|
, MonadMask m
|
||||||
@@ -274,15 +271,21 @@ mkGhcupTmpDir = do
|
|||||||
let minSpace = 5000 -- a rough guess, aight?
|
let minSpace = 5000 -- a rough guess, aight?
|
||||||
space <- handleIO (\_ -> pure Nothing) $ fmap Just $ liftIO $ getAvailSpace tmpdir
|
space <- handleIO (\_ -> pure Nothing) $ fmap Just $ liftIO $ getAvailSpace tmpdir
|
||||||
when (maybe False (toBytes minSpace >) space) $ do
|
when (maybe False (toBytes minSpace >) space) $ do
|
||||||
$(logWarn) [i|Possibly insufficient disk space on #{tmpdir}. At least #{minSpace} MB are recommended, but only #{toMB (fromJust space)} are free. Consider freeing up disk space or setting TMPDIR env variable.|]
|
logWarn ("Possibly insufficient disk space on "
|
||||||
$(logWarn)
|
<> T.pack tmpdir
|
||||||
|
<> ". At least "
|
||||||
|
<> T.pack (show minSpace)
|
||||||
|
<> " MB are recommended, but only "
|
||||||
|
<> toMB (fromJust space)
|
||||||
|
<> " are free. Consider freeing up disk space or setting TMPDIR env variable.")
|
||||||
|
logWarn
|
||||||
"...waiting for 10 seconds before continuing anyway, you can still abort..."
|
"...waiting for 10 seconds before continuing anyway, you can still abort..."
|
||||||
liftIO $ threadDelay 10000000 -- give the user a sec to intervene
|
liftIO $ threadDelay 10000000 -- give the user a sec to intervene
|
||||||
|
|
||||||
liftIO $ createTempDirectory tmpdir "ghcup"
|
liftIO $ createTempDirectory tmpdir "ghcup"
|
||||||
where
|
where
|
||||||
toBytes mb = mb * 1024 * 1024
|
toBytes mb = mb * 1024 * 1024
|
||||||
toMB b = show (truncate' (fromIntegral b / (1024 * 1024) :: Double) 2)
|
toMB b = T.pack $ show (truncate' (fromIntegral b / (1024 * 1024) :: Double) 2)
|
||||||
truncate' :: Double -> Int -> Double
|
truncate' :: Double -> Int -> Double
|
||||||
truncate' x n = fromIntegral (floor (x * t) :: Integer) / t
|
truncate' x n = fromIntegral (floor (x * t) :: Integer) / t
|
||||||
where t = 10^n
|
where t = 10^n
|
||||||
@@ -290,8 +293,9 @@ mkGhcupTmpDir = do
|
|||||||
|
|
||||||
withGHCupTmpDir :: ( MonadReader env m
|
withGHCupTmpDir :: ( MonadReader env m
|
||||||
, HasDirs env
|
, HasDirs env
|
||||||
|
, HasLog env
|
||||||
|
, HasSettings env
|
||||||
, MonadUnliftIO m
|
, MonadUnliftIO m
|
||||||
, MonadLogger m
|
|
||||||
, MonadCatch m
|
, MonadCatch m
|
||||||
, MonadResource m
|
, MonadResource m
|
||||||
, MonadThrow m
|
, MonadThrow m
|
||||||
@@ -304,7 +308,7 @@ withGHCupTmpDir = snd <$> withRunInIO (\run ->
|
|||||||
(run mkGhcupTmpDir)
|
(run mkGhcupTmpDir)
|
||||||
(\fp ->
|
(\fp ->
|
||||||
handleIO (\e -> run
|
handleIO (\e -> run
|
||||||
$ $(logDebug) [i|Resource cleanup failed for "#{fp}", error was: #{displayException e}|])
|
$ logDebug ("Resource cleanup failed for " <> T.pack fp <> ", error was: " <> T.pack (displayException e)))
|
||||||
. rmPathForcibly
|
. rmPathForcibly
|
||||||
$ fp))
|
$ fp))
|
||||||
|
|
||||||
@@ -336,9 +340,10 @@ relativeSymlink p1 p2 =
|
|||||||
|
|
||||||
cleanupTrash :: ( MonadIO m
|
cleanupTrash :: ( MonadIO m
|
||||||
, MonadMask m
|
, MonadMask m
|
||||||
, MonadLogger m
|
|
||||||
, MonadReader env m
|
, MonadReader env m
|
||||||
|
, HasLog env
|
||||||
, HasDirs env
|
, HasDirs env
|
||||||
|
, HasSettings env
|
||||||
)
|
)
|
||||||
=> m ()
|
=> m ()
|
||||||
cleanupTrash = do
|
cleanupTrash = do
|
||||||
@@ -347,8 +352,8 @@ cleanupTrash = do
|
|||||||
if null contents
|
if null contents
|
||||||
then pure ()
|
then pure ()
|
||||||
else do
|
else do
|
||||||
$(logWarn) [i|Removing leftover files in #{recycleDir}|]
|
logWarn ("Removing leftover files in " <> T.pack recycleDir)
|
||||||
forM_ contents (\fp -> handleIO (\e ->
|
forM_ contents (\fp -> handleIO (\e ->
|
||||||
$(logDebug) [i|Resource cleanup failed for "#{fp}", error was: #{displayException e}|]
|
logDebug ("Resource cleanup failed for " <> T.pack fp <> ", error was: " <> T.pack (displayException e))
|
||||||
) $ liftIO $ removePathForcibly (recycleDir </> fp))
|
) $ liftIO $ removePathForcibly (recycleDir </> fp))
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
{-# LANGUAGE QuasiQuotes #-}
|
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
@@ -8,10 +7,10 @@ module GHCup.Utils.File.Common where
|
|||||||
|
|
||||||
import GHCup.Utils.Prelude
|
import GHCup.Utils.Prelude
|
||||||
|
|
||||||
import Control.Monad.Extra
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.String.Interpolate
|
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
|
||||||
@@ -19,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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -31,13 +32,13 @@ data ProcessError = NonZeroExit Int FilePath [String]
|
|||||||
|
|
||||||
instance Pretty ProcessError where
|
instance Pretty ProcessError where
|
||||||
pPrint (NonZeroExit e exe args) =
|
pPrint (NonZeroExit e exe args) =
|
||||||
text [i|Process "#{exe}" with arguments #{args} failed with exit code #{e}.|]
|
text "Process" <+> pPrint exe <+> text "with arguments" <+> pPrint args <+> text "failed with exit code" <+> text (show e <> ".")
|
||||||
pPrint (PTerminated exe args) =
|
pPrint (PTerminated exe args) =
|
||||||
text [i|Process "#{exe}" with arguments #{args} terminated.|]
|
text "Process" <+> pPrint exe <+> text "with arguments" <+> pPrint args <+> text "terminated."
|
||||||
pPrint (PStopped exe args) =
|
pPrint (PStopped exe args) =
|
||||||
text [i|Process "#{exe}" with arguments #{args} stopped.|]
|
text "Process" <+> pPrint exe <+> text "with arguments" <+> pPrint args <+> text "stopped."
|
||||||
pPrint (NoSuchPid exe args) =
|
pPrint (NoSuchPid exe args) =
|
||||||
text [i|Could not find PID for process running "#{exe}" with arguments #{args}.|]
|
text "Could not find PID for process running " <+> pPrint exe <+> text " with arguments " <+> text (show args) <+> text "."
|
||||||
|
|
||||||
data CapturedProcess = CapturedProcess
|
data CapturedProcess = CapturedProcess
|
||||||
{ _exitCode :: ExitCode
|
{ _exitCode :: ExitCode
|
||||||
@@ -104,3 +105,11 @@ findFiles path regex = do
|
|||||||
contents <- listDirectory path
|
contents <- listDirectory path
|
||||||
pure $ filter (match regex) contents
|
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 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]
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
{-# LANGUAGE QuasiQuotes #-}
|
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
|
||||||
{-# LANGUAGE ViewPatterns #-}
|
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
Module : GHCup.Utils.File.Posix
|
Module : GHCup.Utils.File.Posix
|
||||||
@@ -20,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
|
||||||
|
|
||||||
@@ -28,19 +26,16 @@ import Control.Concurrent.Async
|
|||||||
import Control.Exception ( evaluate )
|
import Control.Exception ( evaluate )
|
||||||
import Control.Exception.Safe
|
import Control.Exception.Safe
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.Logger
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Control.Monad.Trans.State.Strict
|
import Control.Monad.Trans.State.Strict
|
||||||
import Data.ByteString ( ByteString )
|
import Data.ByteString ( ByteString )
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
import Data.IORef
|
import Data.IORef
|
||||||
import Data.Sequence ( Seq, (|>) )
|
import Data.Sequence ( Seq, (|>) )
|
||||||
import Data.String.Interpolate
|
|
||||||
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
|
||||||
@@ -56,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
|
||||||
@@ -92,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
|
||||||
@@ -105,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 ())
|
||||||
|
|
||||||
@@ -132,7 +128,7 @@ execLogged exe args chdir lfile env = do
|
|||||||
pure e
|
pure e
|
||||||
|
|
||||||
tee :: Fd -> Fd -> IO ()
|
tee :: Fd -> Fd -> IO ()
|
||||||
tee fileFd fdIn = readTilEOF lineAction fdIn
|
tee fileFd = readTilEOF lineAction
|
||||||
|
|
||||||
where
|
where
|
||||||
lineAction :: ByteString -> IO ()
|
lineAction :: ByteString -> IO ()
|
||||||
@@ -142,46 +138,57 @@ 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
|
(\(ex :: SomeException) -> do
|
||||||
$ Linear
|
ps <- liftIO $ takeMVar pState
|
||||||
flip runStateT mempty
|
when ps (liftIO $ BS.putStr (pos1 <> moveLineUp size <> clearScreen))
|
||||||
$ handle
|
throw ex
|
||||||
(\(ex :: SomeException) -> do
|
) $ readTilEOF lineAction fdIn
|
||||||
ps <- liftIO $ takeMVar pState
|
|
||||||
when ps (forM_ rs (liftIO . closeConsoleRegion))
|
|
||||||
throw ex
|
|
||||||
)
|
|
||||||
$ 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')
|
||||||
regs <- get
|
liftIO TP.size >>= \case
|
||||||
liftIO $ forM_ (Sq.zip regs rs) $ \(bs, r) -> setConsoleRegion r $ do
|
Nothing -> pure ()
|
||||||
w <- consoleWidth
|
Just (Window _ w) -> do
|
||||||
return
|
regs <- get
|
||||||
. T.pack
|
liftIO $ forM_ (Sq.zip regs (Sq.fromList [0..(Sq.length regs - 1)])) $ \(bs, i) -> do
|
||||||
. color Blue
|
BS.putStr
|
||||||
. T.unpack
|
. overwriteNthLine (size - i)
|
||||||
. decUTF8Safe
|
. trim w
|
||||||
. trim w
|
. blue
|
||||||
. (\b -> "[ " <> E.encodeUtf8 (T.pack lfile) <> " ] " <> b)
|
. (\b -> "[ " <> E.encodeUtf8 (T.pack lfile) <> " ] " <> b)
|
||||||
$ bs
|
$ bs
|
||||||
|
|
||||||
swapRegs :: a -> Seq a -> Seq a
|
swapRegs :: a -> Seq a -> Seq a
|
||||||
swapRegs bs = \regs -> if
|
swapRegs bs = \regs -> if
|
||||||
@@ -351,7 +358,7 @@ toProcessError exe args mps = case mps of
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
chmod_755 :: (MonadLogger m, MonadIO m) => FilePath -> m ()
|
chmod_755 :: (MonadReader env m, HasLog env, MonadIO m) => FilePath -> m ()
|
||||||
chmod_755 fp = do
|
chmod_755 fp = do
|
||||||
let exe_mode =
|
let exe_mode =
|
||||||
nullFileMode
|
nullFileMode
|
||||||
@@ -362,7 +369,7 @@ chmod_755 fp = do
|
|||||||
`unionFileModes` groupReadMode
|
`unionFileModes` groupReadMode
|
||||||
`unionFileModes` otherExecuteMode
|
`unionFileModes` otherExecuteMode
|
||||||
`unionFileModes` otherReadMode
|
`unionFileModes` otherReadMode
|
||||||
$(logDebug) [i|chmod 755 #{fp}|]
|
logDebug ("chmod 755 " <> T.pack fp)
|
||||||
liftIO $ setFileMode fp exe_mode
|
liftIO $ setFileMode fp exe_mode
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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,15 +18,15 @@ 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.Logger
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Data.Char ( ord )
|
import Data.Text ( Text )
|
||||||
|
import Optics
|
||||||
import Prelude hiding ( appendFile )
|
import Prelude hiding ( appendFile )
|
||||||
import System.Console.Pretty
|
import System.Console.Pretty
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
@@ -33,54 +35,80 @@ 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
|
||||||
|
|
||||||
|
|
||||||
data LoggerConfig = LoggerConfig
|
logInternal :: ( MonadReader env m
|
||||||
{ lcPrintDebug :: Bool -- ^ whether to print debug in colorOutter
|
, LabelOptic' "loggerConfig" A_Lens env LoggerConfig
|
||||||
, colorOutter :: B.ByteString -> IO () -- ^ how to write the color output
|
, MonadIO m
|
||||||
, rawOutter :: B.ByteString -> IO () -- ^ how to write the full raw output
|
) => 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
|
||||||
|
|
||||||
myLoggerT :: LoggerConfig -> LoggingT m a -> m a
|
-- raw output
|
||||||
myLoggerT LoggerConfig {..} loggingt = runLoggingT loggingt mylogger
|
let lr = case logLevel of
|
||||||
where
|
Debug -> "Debug:"
|
||||||
mylogger :: Loc -> LogSource -> LogLevel -> LogStr -> IO ()
|
Info -> "Info:"
|
||||||
mylogger _ _ level str' = do
|
Warn -> "Warn:"
|
||||||
-- color output
|
Error -> "Error:"
|
||||||
let style' = case level of
|
let outr = lr <> " " <> msg <> "\n"
|
||||||
LevelDebug -> style Bold . color Blue
|
liftIO $ fileOutter outr
|
||||||
LevelInfo -> style Bold . color Green
|
|
||||||
LevelWarn -> style Bold . color Yellow
|
|
||||||
LevelError -> style Bold . color Red
|
|
||||||
LevelOther _ -> id
|
|
||||||
let l = case level of
|
|
||||||
LevelDebug -> toLogStr (style' "[ Debug ]")
|
|
||||||
LevelInfo -> toLogStr (style' "[ Info ]")
|
|
||||||
LevelWarn -> toLogStr (style' "[ Warn ]")
|
|
||||||
LevelError -> toLogStr (style' "[ Error ]")
|
|
||||||
LevelOther t -> toLogStr "[ " <> toLogStr t <> toLogStr " ]"
|
|
||||||
let strs = fmap toLogStr . B.split (fromIntegral $ ord '\n') . fromLogStr $ str'
|
|
||||||
let out = case strs of
|
|
||||||
[] -> B.empty
|
|
||||||
(x:xs) -> fromLogStr
|
|
||||||
. foldr (\a b -> a <> toLogStr "\n" <> b) mempty
|
|
||||||
. ((l <> toLogStr " " <> x) :)
|
|
||||||
. fmap (\line' -> toLogStr (style' "[ ... ] ") <> line' )
|
|
||||||
$ xs
|
|
||||||
|
|
||||||
when (lcPrintDebug || (not lcPrintDebug && (level /= LevelDebug)))
|
|
||||||
$ colorOutter out
|
|
||||||
|
|
||||||
-- raw output
|
|
||||||
let lr = case level of
|
|
||||||
LevelDebug -> toLogStr "Debug:"
|
|
||||||
LevelInfo -> toLogStr "Info:"
|
|
||||||
LevelWarn -> toLogStr "Warn:"
|
|
||||||
LevelError -> toLogStr "Error:"
|
|
||||||
LevelOther t -> toLogStr t <> toLogStr ":"
|
|
||||||
let outr = fromLogStr (lr <> toLogStr " " <> str' <> toLogStr "\n")
|
|
||||||
rawOutter 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 ()
|
||||||
|
|
||||||
@@ -5,7 +5,6 @@
|
|||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
{-# LANGUAGE TypeFamilies #-}
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
{-# LANGUAGE TypeOperators #-}
|
{-# LANGUAGE TypeOperators #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
Module : GHCup.Utils.Prelude
|
Module : GHCup.Utils.Prelude
|
||||||
@@ -23,22 +22,25 @@ 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
|
||||||
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 Control.Monad.Logger
|
|
||||||
import Data.Bifunctor
|
import Data.Bifunctor
|
||||||
import Data.ByteString ( ByteString )
|
import Data.ByteString ( ByteString )
|
||||||
import Data.List ( nub, intercalate )
|
import Data.List ( nub, intercalate, stripPrefix, isPrefixOf )
|
||||||
|
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 )
|
||||||
@@ -59,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
|
||||||
@@ -75,8 +78,9 @@ import qualified System.Win32.File as Win32
|
|||||||
-- >>> import Data.ByteString.Internal (c2w, w2c)
|
-- >>> import Data.ByteString.Internal (c2w, w2c)
|
||||||
-- >>> import Test.QuickCheck
|
-- >>> import Test.QuickCheck
|
||||||
-- >>> import Data.Word8
|
-- >>> import Data.Word8
|
||||||
-- >>> import Data.Word8
|
|
||||||
-- >>> import qualified Data.Text as T
|
-- >>> import qualified Data.Text as T
|
||||||
|
-- >>> import qualified Data.Char as C
|
||||||
|
-- >>> import Data.List
|
||||||
-- >>> instance Arbitrary T.Text where arbitrary = T.pack <$> arbitrary
|
-- >>> instance Arbitrary T.Text where arbitrary = T.pack <$> arbitrary
|
||||||
|
|
||||||
|
|
||||||
@@ -174,8 +178,12 @@ lEM' :: forall e' e es a m
|
|||||||
lEM' f em = lift em >>= lE . first f
|
lEM' f em = lift em >>= lE . first f
|
||||||
|
|
||||||
-- for some obscure reason... this won't type-check if we move it to a different module
|
-- for some obscure reason... this won't type-check if we move it to a different module
|
||||||
catchWarn :: forall es m . (Pretty (V es), MonadLogger m, Monad m) => Excepts es m () -> Excepts '[] m ()
|
catchWarn :: forall es m env . ( Pretty (V es)
|
||||||
catchWarn = catchAllE @_ @es (\v -> lift $ $(logWarn) (T.pack . prettyShow $ v))
|
, MonadReader env m
|
||||||
|
, HasLog env
|
||||||
|
, MonadIO m
|
||||||
|
, Monad m) => Excepts es m () -> Excepts '[] m ()
|
||||||
|
catchWarn = catchAllE @_ @es (\v -> lift $ logWarn (T.pack . prettyShow $ v))
|
||||||
|
|
||||||
fromEither :: Either a b -> VEither '[a] b
|
fromEither :: Either a b -> VEither '[a] b
|
||||||
fromEither = either (VLeft . V) VRight
|
fromEither = either (VLeft . V) VRight
|
||||||
@@ -291,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.
|
||||||
@@ -520,7 +544,7 @@ forFold :: (Foldable t, Applicative m, Monoid b) => t a -> (a -> m b) -> m b
|
|||||||
forFold = \t -> (`traverseFold` t)
|
forFold = \t -> (`traverseFold` t)
|
||||||
|
|
||||||
|
|
||||||
-- | Strip @\\r@ and @\\n@ from 'ByteString's
|
-- | Strip @\\r@ and @\\n@ from 'String's
|
||||||
--
|
--
|
||||||
-- >>> stripNewline "foo\n\n\n"
|
-- >>> stripNewline "foo\n\n\n"
|
||||||
-- "foo"
|
-- "foo"
|
||||||
@@ -532,13 +556,10 @@ forFold = \t -> (`traverseFold` t)
|
|||||||
-- prop> \t -> stripNewline (t <> "\n") === stripNewline t
|
-- prop> \t -> stripNewline (t <> "\n") === stripNewline t
|
||||||
-- prop> \t -> not (any (isNewLine . c2w) t) ==> stripNewline t == t
|
-- prop> \t -> not (any (isNewLine . c2w) t) ==> stripNewline t == t
|
||||||
stripNewline :: String -> String
|
stripNewline :: String -> String
|
||||||
stripNewline s
|
stripNewline = filter (`notElem` "\n\r")
|
||||||
| null s = []
|
|
||||||
| head s `elem` "\n\r" = stripNewline (tail s)
|
|
||||||
| otherwise = head s : stripNewline (tail s)
|
|
||||||
|
|
||||||
|
|
||||||
-- | Strip @\\r@ and @\\n@ from 'ByteString's
|
-- | Strip @\\r@ and @\\n@ from 'Text's
|
||||||
--
|
--
|
||||||
-- >>> stripNewline' "foo\n\n\n"
|
-- >>> stripNewline' "foo\n\n\n"
|
||||||
-- "foo"
|
-- "foo"
|
||||||
@@ -550,10 +571,7 @@ stripNewline s
|
|||||||
-- prop> \t -> stripNewline' (t <> "\n") === stripNewline' t
|
-- prop> \t -> stripNewline' (t <> "\n") === stripNewline' t
|
||||||
-- prop> \t -> not (T.any (isNewLine . c2w) t) ==> stripNewline' t == t
|
-- prop> \t -> not (T.any (isNewLine . c2w) t) ==> stripNewline' t == t
|
||||||
stripNewline' :: T.Text -> T.Text
|
stripNewline' :: T.Text -> T.Text
|
||||||
stripNewline' s
|
stripNewline' = T.filter (`notElem` "\n\r")
|
||||||
| T.null s = mempty
|
|
||||||
| T.head s `elem` "\n\r" = stripNewline' (T.tail s)
|
|
||||||
| otherwise = T.singleton (T.head s) <> stripNewline' (T.tail s)
|
|
||||||
|
|
||||||
|
|
||||||
-- | Is the word8 a newline?
|
-- | Is the word8 a newline?
|
||||||
@@ -587,3 +605,117 @@ splitOnPVP c s = case Split.splitOn c s of
|
|||||||
| otherwise -> def
|
| otherwise -> def
|
||||||
where
|
where
|
||||||
def = (s, "")
|
def = (s, "")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- | Like 'find', but where the test can be monadic.
|
||||||
|
--
|
||||||
|
-- >>> findM (Just . C.isUpper) "teST"
|
||||||
|
-- Just (Just 'S')
|
||||||
|
-- >>> findM (Just . C.isUpper) "test"
|
||||||
|
-- Just Nothing
|
||||||
|
-- >>> findM (Just . const True) ["x",undefined]
|
||||||
|
-- Just (Just "x")
|
||||||
|
findM :: Monad m => (a -> m Bool) -> [a] -> m (Maybe a)
|
||||||
|
findM ~p = foldr (\x -> ifM (p x) (pure $ Just x)) (pure Nothing)
|
||||||
|
|
||||||
|
|
||||||
|
-- | Drops the given suffix from a list.
|
||||||
|
-- It returns the original sequence if the sequence doesn't end with the given suffix.
|
||||||
|
--
|
||||||
|
-- >>> dropSuffix "!" "Hello World!"
|
||||||
|
-- "Hello World"
|
||||||
|
-- >>> dropSuffix "!" "Hello World!!"
|
||||||
|
-- "Hello World!"
|
||||||
|
-- >>> dropSuffix "!" "Hello World."
|
||||||
|
-- "Hello World."
|
||||||
|
dropSuffix :: Eq a => [a] -> [a] -> [a]
|
||||||
|
dropSuffix a b = fromMaybe b $ stripSuffix a b
|
||||||
|
|
||||||
|
-- | Return the prefix of the second list if its suffix
|
||||||
|
-- matches the entire first list.
|
||||||
|
--
|
||||||
|
-- >>> stripSuffix "bar" "foobar"
|
||||||
|
-- Just "foo"
|
||||||
|
-- >>> stripSuffix "" "baz"
|
||||||
|
-- Just "baz"
|
||||||
|
-- >>> stripSuffix "foo" "quux"
|
||||||
|
-- Nothing
|
||||||
|
stripSuffix :: Eq a => [a] -> [a] -> Maybe [a]
|
||||||
|
stripSuffix a b = reverse <$> stripPrefix (reverse a) (reverse b)
|
||||||
|
|
||||||
|
|
||||||
|
-- | Drops the given prefix from a list.
|
||||||
|
-- It returns the original sequence if the sequence doesn't start with the given prefix.
|
||||||
|
--
|
||||||
|
-- >>> dropPrefix "Mr. " "Mr. Men"
|
||||||
|
-- "Men"
|
||||||
|
-- >>> dropPrefix "Mr. " "Dr. Men"
|
||||||
|
-- "Dr. Men"
|
||||||
|
dropPrefix :: Eq a => [a] -> [a] -> [a]
|
||||||
|
dropPrefix a b = fromMaybe b $ stripPrefix a b
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- | Break a list into pieces separated by the first
|
||||||
|
-- list argument, consuming the delimiter. An empty delimiter is
|
||||||
|
-- invalid, and will cause an error to be raised.
|
||||||
|
--
|
||||||
|
-- >>> splitOn "\r\n" "a\r\nb\r\nd\r\ne"
|
||||||
|
-- ["a","b","d","e"]
|
||||||
|
-- >>> splitOn "aaa" "aaaXaaaXaaaXaaa"
|
||||||
|
-- ["","X","X","X",""]
|
||||||
|
-- >>> splitOn "x" "x"
|
||||||
|
-- ["",""]
|
||||||
|
-- >>> splitOn "x" ""
|
||||||
|
-- [""]
|
||||||
|
--
|
||||||
|
-- prop> \s x -> s /= "" ==> intercalate s (splitOn s x) == x
|
||||||
|
-- prop> \c x -> splitOn [c] x == split (==c) x
|
||||||
|
splitOn :: Eq a => [a] -> [a] -> [[a]]
|
||||||
|
splitOn [] _ = error "splitOn, needle may not be empty"
|
||||||
|
splitOn _ [] = [[]]
|
||||||
|
splitOn needle haystack = a : if null b then [] else splitOn needle $ drop (length needle) b
|
||||||
|
where (a,b) = breakOn needle haystack
|
||||||
|
|
||||||
|
|
||||||
|
-- | Splits a list into components delimited by separators,
|
||||||
|
-- where the predicate returns True for a separator element. The
|
||||||
|
-- resulting components do not contain the separators. Two adjacent
|
||||||
|
-- separators result in an empty component in the output.
|
||||||
|
--
|
||||||
|
-- >>> split (== 'a') "aabbaca"
|
||||||
|
-- ["","","bb","c",""]
|
||||||
|
-- >>> split (== 'a') ""
|
||||||
|
-- [""]
|
||||||
|
-- >>> split (== ':') "::xyz:abc::123::"
|
||||||
|
-- ["","","xyz","abc","","123","",""]
|
||||||
|
-- >>> split (== ',') "my,list,here"
|
||||||
|
-- ["my","list","here"]
|
||||||
|
split :: (a -> Bool) -> [a] -> [[a]]
|
||||||
|
split _ [] = [[]]
|
||||||
|
split f (x:xs)
|
||||||
|
| f x = [] : split f xs
|
||||||
|
| y:ys <- split f xs = (x:y) : ys
|
||||||
|
| otherwise = [[]]
|
||||||
|
|
||||||
|
|
||||||
|
-- | Find the first instance of @needle@ in @haystack@.
|
||||||
|
-- The first element of the returned tuple
|
||||||
|
-- is the prefix of @haystack@ before @needle@ is matched. The second
|
||||||
|
-- is the remainder of @haystack@, starting with the match.
|
||||||
|
-- If you want the remainder /without/ the match, use 'stripInfix'.
|
||||||
|
--
|
||||||
|
-- >>> breakOn "::" "a::b::c"
|
||||||
|
-- ("a","::b::c")
|
||||||
|
-- >>> breakOn "/" "foobar"
|
||||||
|
-- ("foobar","")
|
||||||
|
--
|
||||||
|
-- prop> \needle haystack -> let (prefix,match) = breakOn needle haystack in prefix ++ match == haystack
|
||||||
|
breakOn :: Eq a => [a] -> [a] -> ([a], [a])
|
||||||
|
breakOn needle haystack | needle `isPrefixOf` haystack = ([], haystack)
|
||||||
|
breakOn _ [] = ([], [])
|
||||||
|
breakOn needle (x:xs) = first (x:) $ breakOn needle xs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -44,15 +44,14 @@ import Language.Haskell.TH.Quote
|
|||||||
-- The pattern portion is undefined.
|
-- The pattern portion is undefined.
|
||||||
s :: QuasiQuoter
|
s :: QuasiQuoter
|
||||||
s = QuasiQuoter
|
s = QuasiQuoter
|
||||||
(\s' -> case and $ fmap isAscii s' of
|
(\s' -> case all isAscii s' of
|
||||||
True -> (\a -> [|fromString a|]) . trimLeadingNewline . removeCRs $ s'
|
True -> (\a -> [|fromString a|]) . trimLeadingNewline . removeCRs $ s'
|
||||||
False -> fail "Not ascii"
|
False -> fail "Not ascii"
|
||||||
)
|
)
|
||||||
(error "Cannot use q as a pattern")
|
(error "Cannot use s as a pattern")
|
||||||
(error "Cannot use q as a type")
|
(error "Cannot use s as a type")
|
||||||
(error "Cannot use q as a dec")
|
(error "Cannot use s as a dec")
|
||||||
where
|
where
|
||||||
removeCRs = filter (/= '\r')
|
removeCRs = filter (/= '\r')
|
||||||
trimLeadingNewline ('\n' : xs) = xs
|
trimLeadingNewline ('\n' : xs) = xs
|
||||||
trimLeadingNewline xs = xs
|
trimLeadingNewline xs = xs
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ import qualified Data.List.NonEmpty as NE
|
|||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
|
||||||
-- | This reflects the API version of the YAML.
|
-- | This reflects the API version of the YAML.
|
||||||
|
--
|
||||||
|
-- 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.
|
||||||
ghcupURL :: URI
|
ghcupURL :: URI
|
||||||
ghcupURL = [uri|https://www.haskell.org/ghcup/data/ghcup-0.0.6.yaml|]
|
ghcupURL = [uri|https://www.haskell.org/ghcup/data/ghcup-0.0.6.yaml|]
|
||||||
|
|
||||||
|
|||||||
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)
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
# Main settings:
|
# Main settings:
|
||||||
# * BOOTSTRAP_HASKELL_NONINTERACTIVE - any nonzero value for noninteractive installation
|
# * BOOTSTRAP_HASKELL_NONINTERACTIVE - any nonzero value for noninteractive installation
|
||||||
# * BOOTSTRAP_HASKELL_NO_UPGRADE - any nonzero value to not trigger the upgrade
|
# * BOOTSTRAP_HASKELL_NO_UPGRADE - any nonzero value to not trigger the upgrade
|
||||||
|
# * BOOTSTRAP_HASKELL_MINIMAL - any nonzero value to only install ghcup
|
||||||
# * GHCUP_USE_XDG_DIRS - any nonzero value to respect The XDG Base Directory Specification
|
# * GHCUP_USE_XDG_DIRS - any nonzero value to respect The XDG Base Directory Specification
|
||||||
# * BOOTSTRAP_HASKELL_VERBOSE - any nonzero value for more verbose installation
|
# * BOOTSTRAP_HASKELL_VERBOSE - any nonzero value for more verbose installation
|
||||||
# * BOOTSTRAP_HASKELL_GHC_VERSION - the ghc version to install
|
# * BOOTSTRAP_HASKELL_GHC_VERSION - the ghc version to install
|
||||||
@@ -20,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
|
||||||
@@ -51,41 +52,57 @@ esac
|
|||||||
|
|
||||||
|
|
||||||
die() {
|
die() {
|
||||||
(>&2 printf "\\033[0;31m%s\\033[0m\\n" "$1")
|
if [ -n "${NO_COLOR}" ] ; then
|
||||||
|
(>&2 printf "%s\\n" "$1")
|
||||||
|
else
|
||||||
|
(>&2 printf "\\033[0;31m%s\\033[0m\\n" "$1")
|
||||||
|
fi
|
||||||
exit 2
|
exit 2
|
||||||
}
|
}
|
||||||
|
|
||||||
warn() {
|
warn() {
|
||||||
case "${plat}" in
|
if [ -n "${NO_COLOR}" ] ; then
|
||||||
MSYS*|MINGW*)
|
printf "%s\\n" "$1"
|
||||||
echo -e "\\033[0;35m$1\\033[0m"
|
else
|
||||||
;;
|
case "${plat}" in
|
||||||
*)
|
MSYS*|MINGW*)
|
||||||
printf "\\033[0;35m%s\\033[0m\\n" "$1"
|
echo -e "\\033[0;35m$1\\033[0m"
|
||||||
;;
|
;;
|
||||||
esac
|
*)
|
||||||
|
printf "\\033[0;35m%s\\033[0m\\n" "$1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
yellow() {
|
yellow() {
|
||||||
case "${plat}" in
|
if [ -n "${NO_COLOR}" ] ; then
|
||||||
MSYS*|MINGW*)
|
printf "%s\\n" "$1"
|
||||||
echo -e "\\033[0;33m$1\\033[0m"
|
else
|
||||||
;;
|
case "${plat}" in
|
||||||
*)
|
MSYS*|MINGW*)
|
||||||
printf "\\033[0;33m%s\\033[0m\\n" "$1"
|
echo -e "\\033[0;33m$1\\033[0m"
|
||||||
;;
|
;;
|
||||||
esac
|
*)
|
||||||
|
printf "\\033[0;33m%s\\033[0m\\n" "$1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
green() {
|
green() {
|
||||||
case "${plat}" in
|
if [ -n "${NO_COLOR}" ] ; then
|
||||||
MSYS*|MINGW*)
|
printf "%s\\n" "$1"
|
||||||
echo -e "\\033[0;32m$1\\033[0m"
|
else
|
||||||
;;
|
case "${plat}" in
|
||||||
*)
|
MSYS*|MINGW*)
|
||||||
printf "\\033[0;32m%s\\033[0m\\n" "$1"
|
echo -e "\\033[0;32m$1\\033[0m"
|
||||||
;;
|
;;
|
||||||
esac
|
*)
|
||||||
|
printf "\\033[0;32m%s\\033[0m\\n" "$1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
edo() {
|
edo() {
|
||||||
@@ -99,7 +116,7 @@ eghcup() {
|
|||||||
_eghcup() {
|
_eghcup() {
|
||||||
if [ -n "${BOOTSTRAP_HASKELL_YAML}" ] ; then
|
if [ -n "${BOOTSTRAP_HASKELL_YAML}" ] ; then
|
||||||
args="-s ${BOOTSTRAP_HASKELL_YAML}"
|
args="-s ${BOOTSTRAP_HASKELL_YAML}"
|
||||||
fi
|
fi
|
||||||
if [ -z "${BOOTSTRAP_HASKELL_VERBOSE}" ] ; then
|
if [ -z "${BOOTSTRAP_HASKELL_VERBOSE}" ] ; then
|
||||||
"${GHCUP_BIN}/ghcup" ${args} "$@"
|
"${GHCUP_BIN}/ghcup" ${args} "$@"
|
||||||
else
|
else
|
||||||
@@ -175,7 +192,15 @@ download_ghcup() {
|
|||||||
_url=${base_url}/${ghver}/armv7-linux-ghcup-${ghver}
|
_url=${base_url}/${ghver}/armv7-linux-ghcup-${ghver}
|
||||||
;;
|
;;
|
||||||
aarch64|arm64|armv8l)
|
aarch64|arm64|armv8l)
|
||||||
_url=${base_url}/${ghver}/aarch64-linux-ghcup-${ghver}
|
# we could be in a 32bit docker container, in which
|
||||||
|
# case uname doesn't give us what we want
|
||||||
|
if [ "$(getconf LONG_BIT)" = "32" ] ; then
|
||||||
|
_url=${base_url}/${ghver}/armv7-linux-ghcup-${ghver}
|
||||||
|
elif [ "$(getconf LONG_BIT)" = "64" ] ; then
|
||||||
|
_url=${base_url}/${ghver}/aarch64-linux-ghcup-${ghver}
|
||||||
|
else
|
||||||
|
die "Unknown long bit size: $(getconf LONG_BIT)"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
*) die "Unknown architecture: ${arch}"
|
*) die "Unknown architecture: ${arch}"
|
||||||
;;
|
;;
|
||||||
@@ -292,16 +317,7 @@ ask_bashrc() {
|
|||||||
|
|
||||||
read -r bashrc_answer </dev/tty
|
read -r bashrc_answer </dev/tty
|
||||||
else
|
else
|
||||||
# On windows .bashrc isn't an important user config, so we adjust it
|
return 0
|
||||||
# always. On other platforms, let's be a bit more conservative.
|
|
||||||
case "${plat}" in
|
|
||||||
MSYS*|MINGW*)
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
fi
|
||||||
case $bashrc_answer in
|
case $bashrc_answer in
|
||||||
[Pp]* | "")
|
[Pp]* | "")
|
||||||
@@ -371,6 +387,13 @@ adjust_bashrc() {
|
|||||||
echo "[[ -f ~/.bashrc ]] && source ~/.bashrc # ghcup-env" >> "${HOME}/.bash_profile"
|
echo "[[ -f ~/.bashrc ]] && source ~/.bashrc # ghcup-env" >> "${HOME}/.bash_profile"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
MSYS*|MINGW*)
|
||||||
|
if [ ! -e "${HOME}/.bash_profile" ] ; then
|
||||||
|
echo '# generated by ghcup' > "${HOME}/.bash_profile"
|
||||||
|
echo 'test -f ~/.profile && . ~/.profile' >> "${HOME}/.bash_profile"
|
||||||
|
echo 'test -f ~/.bashrc && . ~/.bashrc' >> "${HOME}/.bash_profile"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
break ;;
|
break ;;
|
||||||
|
|
||||||
@@ -398,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)."
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -591,10 +614,12 @@ ask_bashrc
|
|||||||
ask_bashrc_answer=$?
|
ask_bashrc_answer=$?
|
||||||
ask_cabal_config_init
|
ask_cabal_config_init
|
||||||
ask_cabal_config_init_answer=$?
|
ask_cabal_config_init_answer=$?
|
||||||
ask_hls
|
if [ -z "${BOOTSTRAP_HASKELL_MINIMAL}" ] ; then
|
||||||
ask_hls_answer=$?
|
ask_hls
|
||||||
ask_stack
|
ask_hls_answer=$?
|
||||||
ask_stack_answer=$?
|
ask_stack
|
||||||
|
ask_stack_answer=$?
|
||||||
|
fi
|
||||||
|
|
||||||
edo mkdir -p "${GHCUP_BIN}"
|
edo mkdir -p "${GHCUP_BIN}"
|
||||||
|
|
||||||
@@ -620,14 +645,30 @@ if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
|||||||
read -r answer </dev/tty
|
read -r answer </dev/tty
|
||||||
fi
|
fi
|
||||||
|
|
||||||
eghcup --cache install ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
if [ -z "${BOOTSTRAP_HASKELL_MINIMAL}" ] ; then
|
||||||
|
eghcup --cache install ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
||||||
|
|
||||||
eghcup set ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
eghcup set ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
||||||
eghcup --cache install cabal "${BOOTSTRAP_HASKELL_CABAL_VERSION}"
|
eghcup --cache install cabal "${BOOTSTRAP_HASKELL_CABAL_VERSION}"
|
||||||
|
|
||||||
do_cabal_config_init $ask_cabal_config_init_answer
|
do_cabal_config_init $ask_cabal_config_init_answer
|
||||||
|
|
||||||
edo cabal new-update
|
edo cabal new-update
|
||||||
|
else # don't install ghc and cabal
|
||||||
|
case "${plat}" in
|
||||||
|
MSYS*|MINGW*)
|
||||||
|
# need to bootstrap cabal to initialize config on windows
|
||||||
|
# we'll remove it afterwards
|
||||||
|
tmp_dir="$(mktemp -d)"
|
||||||
|
eghcup --cache install cabal -i "${tmp_dir}" "${BOOTSTRAP_HASKELL_CABAL_VERSION}"
|
||||||
|
PATH="${tmp_dir}:$PATH" do_cabal_config_init $ask_cabal_config_init_answer
|
||||||
|
rm "${tmp_dir}/cabal"
|
||||||
|
unset tmp_dir
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
case $ask_hls_answer in
|
case $ask_hls_answer in
|
||||||
1)
|
1)
|
||||||
@@ -652,4 +693,3 @@ _done
|
|||||||
)
|
)
|
||||||
|
|
||||||
# vim: tabstop=4 shiftwidth=4 expandtab
|
# vim: tabstop=4 shiftwidth=4 expandtab
|
||||||
|
|
||||||
@@ -15,24 +15,26 @@
|
|||||||
param (
|
param (
|
||||||
# Run an interactive installation
|
# Run an interactive installation
|
||||||
[switch]$Interactive,
|
[switch]$Interactive,
|
||||||
# Specify the install root (default: 'C:\')
|
# Do minimal installation of ghcup and msys2 only
|
||||||
[string]$InstallDir,
|
[switch]$Minimal,
|
||||||
# Instead of installing a new MSys2, use an existing installation
|
|
||||||
[string]$ExistingMsys2Dir,
|
|
||||||
# Specify the cabal root directory (default: '$InstallDir\cabal')
|
|
||||||
[string]$CabalDir,
|
|
||||||
# Overwrite (or rather backup) a previous install
|
|
||||||
[switch]$Overwrite,
|
|
||||||
# Specify the bootstrap url (default: 'https://www.haskell.org/ghcup/sh/bootstrap-haskell')
|
|
||||||
[string]$BootstrapUrl,
|
|
||||||
# Run the final bootstrap script via 'bash' instead of a full newly spawned msys2 shell
|
# Run the final bootstrap script via 'bash' instead of a full newly spawned msys2 shell
|
||||||
[switch]$InBash,
|
[switch]$InBash,
|
||||||
|
# Overwrite (or rather backup) a previous install
|
||||||
|
[switch]$Overwrite,
|
||||||
|
# Skip adjusting cabal.config with mingw paths
|
||||||
|
[switch]$NoAdjustCabalConfig,
|
||||||
# Whether to install stack as well
|
# Whether to install stack as well
|
||||||
[switch]$InstallStack,
|
[switch]$InstallStack,
|
||||||
# Whether to install hls as well
|
# Whether to install hls as well
|
||||||
[switch]$InstallHLS,
|
[switch]$InstallHLS,
|
||||||
# Skip adjusting cabal.config with mingw paths
|
# Specify the bootstrap url (default: 'https://www.haskell.org/ghcup/sh/bootstrap-haskell')
|
||||||
[switch]$NoAdjustCabalConfig
|
[string]$InstallDir,
|
||||||
|
# Instead of installing a new MSys2, use an existing installation
|
||||||
|
[string]$BootstrapUrl,
|
||||||
|
# Specify the install root (default: 'C:\')
|
||||||
|
[string]$ExistingMsys2Dir,
|
||||||
|
# Specify the cabal root directory (default: '$InstallDir\cabal')
|
||||||
|
[string]$CabalDir
|
||||||
)
|
)
|
||||||
|
|
||||||
$Silent = !$Interactive
|
$Silent = !$Interactive
|
||||||
@@ -180,7 +182,7 @@ elevated command prompt:
|
|||||||
|
|
||||||
if ($GhcupBasePrefixEnv) {
|
if ($GhcupBasePrefixEnv) {
|
||||||
$defaultGhcupBasePrefix = $GhcupBasePrefixEnv
|
$defaultGhcupBasePrefix = $GhcupBasePrefixEnv
|
||||||
} else {
|
} elseif (!($InstallDir)) {
|
||||||
$partitions = Get-CimInstance win32_logicaldisk
|
$partitions = Get-CimInstance win32_logicaldisk
|
||||||
$defaultGhcupBasePrefix = $null
|
$defaultGhcupBasePrefix = $null
|
||||||
foreach ($p in $partitions){
|
foreach ($p in $partitions){
|
||||||
@@ -209,10 +211,10 @@ if ($Silent -and !($InstallDir)) {
|
|||||||
$GhcupBasePrefix = $defaultGhcupBasePrefix
|
$GhcupBasePrefix = $defaultGhcupBasePrefix
|
||||||
} elseif ($InstallDir) {
|
} elseif ($InstallDir) {
|
||||||
if (!(Test-Path -LiteralPath ('{0}' -f $InstallDir) -IsValid)) {
|
if (!(Test-Path -LiteralPath ('{0}' -f $InstallDir) -IsValid)) {
|
||||||
Print-Msg -color Red -msg "Not a valid directory!"
|
Print-Msg -color Red -msg "Not a valid directory! (InstallDir)"
|
||||||
Exit 1
|
Exit 1
|
||||||
} elseif (!(Split-Path -IsAbsolute -Path "$InstallDir")) {
|
} elseif (!(Split-Path -IsAbsolute -Path "$InstallDir")) {
|
||||||
Print-Msg -color Red -msg "Non-absolute Path specified!"
|
Print-Msg -color Red -msg "Non-absolute Path specified! (InstallDir)"
|
||||||
Exit 1
|
Exit 1
|
||||||
} else {
|
} else {
|
||||||
$GhcupBasePrefix = $InstallDir
|
$GhcupBasePrefix = $InstallDir
|
||||||
@@ -243,7 +245,20 @@ $null = [Environment]::SetEnvironmentVariable("GHCUP_INSTALL_BASE_PREFIX", $Ghcu
|
|||||||
|
|
||||||
|
|
||||||
$GhcupDir = ('{0}\ghcup' -f $GhcupBasePrefix)
|
$GhcupDir = ('{0}\ghcup' -f $GhcupBasePrefix)
|
||||||
$MsysDir = ('{0}\msys64' -f $GhcupDir)
|
if ($ExistingMsys2Dir) {
|
||||||
|
if (!(Test-Path -LiteralPath ('{0}' -f $ExistingMsys2Dir) -IsValid)) {
|
||||||
|
Print-Msg -color Red -msg "Not a valid directory! (ExistingMsys2Dir)"
|
||||||
|
Exit 1
|
||||||
|
} elseif (!(Split-Path -IsAbsolute -Path "$ExistingMsys2Dir")) {
|
||||||
|
Print-Msg -color Red -msg "Non-absolute Path specified! (ExistingMsys2Dir)"
|
||||||
|
Exit 1
|
||||||
|
} else {
|
||||||
|
$MsysDir = $ExistingMsys2Dir
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$MsysDir = ('{0}\msys64' -f $GhcupDir)
|
||||||
|
}
|
||||||
|
|
||||||
$Bash = ('{0}\usr\bin\bash' -f $MsysDir)
|
$Bash = ('{0}\usr\bin\bash' -f $MsysDir)
|
||||||
if (!($BootstrapUrl)) {
|
if (!($BootstrapUrl)) {
|
||||||
$BootstrapUrl = 'https://www.haskell.org/ghcup/sh/bootstrap-haskell'
|
$BootstrapUrl = 'https://www.haskell.org/ghcup/sh/bootstrap-haskell'
|
||||||
@@ -398,6 +413,7 @@ if (!(Test-Path -Path ('{0}' -f $MsysDir))) {
|
|||||||
|
|
||||||
Print-Msg -msg 'Setting default home directory...'
|
Print-Msg -msg 'Setting default home directory...'
|
||||||
Exec "$Bash" '-lc' "sed -i -e 's/db_home:.*$/db_home: windows/' /etc/nsswitch.conf"
|
Exec "$Bash" '-lc' "sed -i -e 's/db_home:.*$/db_home: windows/' /etc/nsswitch.conf"
|
||||||
|
|
||||||
} elseif ($msys2Decision -eq 1) {
|
} elseif ($msys2Decision -eq 1) {
|
||||||
Print-Msg -color Yellow -msg 'Skipping MSys2 installation.'
|
Print-Msg -color Yellow -msg 'Skipping MSys2 installation.'
|
||||||
while ($true) {
|
while ($true) {
|
||||||
@@ -529,10 +545,14 @@ if (!($NoAdjustCabalConfig)) {
|
|||||||
$AdjustCabalConfigExport = 'export BOOTSTRAP_HASKELL_ADJUST_CABAL_CONFIG=1 ;'
|
$AdjustCabalConfigExport = 'export BOOTSTRAP_HASKELL_ADJUST_CABAL_CONFIG=1 ;'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($Minimal) {
|
||||||
|
$MinimalExport = 'export BOOTSTRAP_HASKELL_MINIMAL=1 ;'
|
||||||
|
}
|
||||||
|
|
||||||
if ((Get-Process -ID $PID).ProcessName.StartsWith("bootstrap-haskell") -Or $InBash) {
|
if ((Get-Process -ID $PID).ProcessName.StartsWith("bootstrap-haskell") -Or $InBash) {
|
||||||
Exec "$Bash" '-lc' ('{4} {6} {7} {8} [ -n ''{1}'' ] && export GHCUP_MSYS2=$(cygpath -m ''{1}'') ; [ -n ''{2}'' ] && export GHCUP_INSTALL_BASE_PREFIX=$(cygpath -m ''{2}/'') ; export PATH=$(cygpath -u ''{3}/bin''):$PATH ; export CABAL_DIR=''{5}'' ; [[ ''{0}'' = https* ]] && curl --proto ''=https'' --tlsv1.2 -sSf {0} | bash || cat $(cygpath -m ''{0}'') | bash' -f $BootstrapUrl, $MsysDir, $GhcupBasePrefix, $GhcupDir, $SilentExport, $CabalDirFull, $StackInstallExport, $HLSInstallExport, $AdjustCabalConfigExport)
|
Exec "$Bash" '-lc' ('{4} {6} {7} {8} {9} [ -n ''{1}'' ] && export GHCUP_MSYS2=$(cygpath -m ''{1}'') ; [ -n ''{2}'' ] && export GHCUP_INSTALL_BASE_PREFIX=$(cygpath -m ''{2}/'') ; export PATH=$(cygpath -u ''{3}/bin''):$PATH ; export CABAL_DIR=''{5}'' ; [[ ''{0}'' = https* ]] && curl --proto ''=https'' --tlsv1.2 -sSf {0} | bash || cat $(cygpath -m ''{0}'') | bash' -f $BootstrapUrl, $MsysDir, $GhcupBasePrefix, $GhcupDir, $SilentExport, $CabalDirFull, $StackInstallExport, $HLSInstallExport, $AdjustCabalConfigExport, $MinimalExport)
|
||||||
} else {
|
} else {
|
||||||
Exec "$Msys2Shell" '-mingw64' '-mintty' '-c' ('{4} {6} {7} {8} [ -n ''{1}'' ] && export GHCUP_MSYS2=$(cygpath -m ''{1}'') ; [ -n ''{2}'' ] && export GHCUP_INSTALL_BASE_PREFIX=$(cygpath -m ''{2}/'') ; export PATH=$(cygpath -u ''{3}/bin''):$PATH ; export CABAL_DIR=''{5}'' ; trap ''echo Press any key to exit && read -n 1 && exit'' 2 ; [[ ''{0}'' = https* ]] && curl --proto ''=https'' --tlsv1.2 -sSf {0} | bash || cat $(cygpath -m ''{0}'') | bash ; echo ''Press any key to exit'' && read -n 1' -f $BootstrapUrl, $MsysDir, $GhcupBasePrefix, $GhcupDir, $SilentExport, $CabalDirFull, $StackInstallExport, $HLSInstallExport, $AdjustCabalConfigExport)
|
Exec "$Msys2Shell" '-mingw64' '-mintty' '-c' ('{4} {6} {7} {8} {9} [ -n ''{1}'' ] && export GHCUP_MSYS2=$(cygpath -m ''{1}'') ; [ -n ''{2}'' ] && export GHCUP_INSTALL_BASE_PREFIX=$(cygpath -m ''{2}/'') ; export PATH=$(cygpath -u ''{3}/bin''):$PATH ; export CABAL_DIR=''{5}'' ; trap ''echo Press any key to exit && read -n 1 && exit'' 2 ; [[ ''{0}'' = https* ]] && curl --proto ''=https'' --tlsv1.2 -sSf {0} | bash || cat $(cygpath -m ''{0}'') | bash ; echo ''Press any key to exit'' && read -n 1' -f $BootstrapUrl, $MsysDir, $GhcupBasePrefix, $GhcupDir, $SilentExport, $CabalDirFull, $StackInstallExport, $HLSInstallExport, $AdjustCabalConfigExport, $MinimalExport)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
33
stack.yaml
33
stack.yaml
@@ -4,26 +4,21 @@ packages:
|
|||||||
- .
|
- .
|
||||||
|
|
||||||
extra-deps:
|
extra-deps:
|
||||||
- git: https://github.com/hasufell/text-conversions.git
|
- git: https://github.com/hasufell/libarchive
|
||||||
commit: 9abf0e5e5664a3178367597c32db19880477a53c
|
commit: 8587aab78dd515928024ecd82c8f215e06db85cd
|
||||||
|
|
||||||
- git: https://github.com/Bodigrim/tar
|
|
||||||
commit: ac197ec7ea4838dc2b4e22b9b888b080cedf29cf
|
|
||||||
|
|
||||||
- git: https://github.com/jtdaugherty/brick.git
|
|
||||||
commit: b3b96cfe66dfd398d338e3feb2b6855e66a35190
|
|
||||||
|
|
||||||
- IfElse-0.85@sha256:6939b94acc6a55f545f63a168a349dd2fbe4b9a7cca73bf60282db5cc6aa47d2,445
|
- IfElse-0.85@sha256:6939b94acc6a55f545f63a168a349dd2fbe4b9a7cca73bf60282db5cc6aa47d2,445
|
||||||
- ascii-string-1.0.1.4@sha256:fa34f1d9ba57e8e89c0d4c9cef5e01ba32cb2d4373d13f92dcc0b531a6c6749b,2582
|
- ascii-string-1.0.1.4@sha256:fa34f1d9ba57e8e89c0d4c9cef5e01ba32cb2d4373d13f92dcc0b531a6c6749b,2582
|
||||||
- base16-bytestring-0.1.1.7@sha256:0021256a9628971c08da95cb8f4d0d72192f3bb8a7b30b55c080562d17c43dd3,2231
|
- base16-bytestring-0.1.1.7@sha256:0021256a9628971c08da95cb8f4d0d72192f3bb8a7b30b55c080562d17c43dd3,2231
|
||||||
|
- brick-0.64@sha256:f03fa14607c22cf48af99e24c44f79a0fb073f7ec229f15e969fed9ff73c93f6,16530
|
||||||
- brotli-0.0.0.0@sha256:2bf383a4cd308745740986be0b18381c5a0784393fe69b91456aacb2d603de46,2964
|
- brotli-0.0.0.0@sha256:2bf383a4cd308745740986be0b18381c5a0784393fe69b91456aacb2d603de46,2964
|
||||||
- brotli-streams-0.0.0.0@sha256:1af1e22f67b8bfd6ad0d05e61825e7a178d738f689ebbb21c1aab5f1bbcae176,2331
|
- brotli-streams-0.0.0.0@sha256:1af1e22f67b8bfd6ad0d05e61825e7a178d738f689ebbb21c1aab5f1bbcae176,2331
|
||||||
- chs-cabal-0.1.1.0@sha256:20ec6a9fb5ab6991f1a4adf157c537bd5d3b98d08d3c09c387c954c7c50bd011,1153
|
- chs-cabal-0.1.1.0@sha256:20ec6a9fb5ab6991f1a4adf157c537bd5d3b98d08d3c09c387c954c7c50bd011,1153
|
||||||
- chs-deps-0.1.0.0@sha256:0cdada6d2c682c41b20331b8c63c2ecfc7e806928585195fd544c9d41f3074fd,2496
|
- chs-deps-0.1.0.0@sha256:0cdada6d2c682c41b20331b8c63c2ecfc7e806928585195fd544c9d41f3074fd,2496
|
||||||
- composition-prelude-3.0.0.2@sha256:1ffed216bd28d810fce0b5be83a661e2a892696d73b3f8de5c0f5edb9b5f0090,1216
|
- composition-prelude-3.0.0.2@sha256:1ffed216bd28d810fce0b5be83a661e2a892696d73b3f8de5c0f5edb9b5f0090,1216
|
||||||
- haskus-utils-data-1.3@sha256:f62c4e49021b463185d043f7b69c727b63af641a71d7edd582d9f4f98e80e500,1466
|
- haskus-utils-data-1.4@sha256:bfa94363b94b14779edd6834fbd59dbb847c3d7b8f48e3844f456ffdc077da4a,1466
|
||||||
- haskus-utils-types-1.5.1@sha256:991c472f4e751e2f0d7aab6ad4220ef151d6160876dcf0511bbf876bbd432020,1298
|
- haskus-utils-types-1.5.1@sha256:991c472f4e751e2f0d7aab6ad4220ef151d6160876dcf0511bbf876bbd432020,1298
|
||||||
- haskus-utils-variant-3.0@sha256:8d51e45d3b664e61ccc25a58b37c0ccc4ee7537138b9fee21cd15c356906dd34,2159
|
- haskus-utils-variant-3.1@sha256:e602dd23e068c98d03c1027af20503addef8df6368577622453f44ccabea2a5b,2159
|
||||||
- hpath-filepath-0.10.4@sha256:e9e44fb5fdbade7f30b5b5451257dbee15b6ef1aae4060034d73008bb3b5d878,1269
|
- hpath-filepath-0.10.4@sha256:e9e44fb5fdbade7f30b5b5451257dbee15b6ef1aae4060034d73008bb3b5d878,1269
|
||||||
- hpath-posix-0.13.3@sha256:abe472cf16bccd3a8b8814865ed3551a728fde0f3a2baea2acc03023bec6c565,1615
|
- hpath-posix-0.13.3@sha256:abe472cf16bccd3a8b8814865ed3551a728fde0f3a2baea2acc03023bec6c565,1615
|
||||||
- hspec-2.7.10@sha256:c9e82c90086acebac576552a06f3cabd249bba048edd1667c7fae0b1313d5bce,1712
|
- hspec-2.7.10@sha256:c9e82c90086acebac576552a06f3cabd249bba048edd1667c7fae0b1313d5bce,1712
|
||||||
@@ -31,13 +26,12 @@ extra-deps:
|
|||||||
- hspec-discover-2.7.10@sha256:d08bf5dd785629f589571477d9beb7cd91529471bd89f39517c1cb4b9b38160f,2184
|
- hspec-discover-2.7.10@sha256:d08bf5dd785629f589571477d9beb7cd91529471bd89f39517c1cb4b9b38160f,2184
|
||||||
- hspec-golden-aeson-0.9.0.0@sha256:aa17274114026661ba4dfc9c60c230673c8f408bd86482fd611d2d5cb6aff996,2179
|
- hspec-golden-aeson-0.9.0.0@sha256:aa17274114026661ba4dfc9c60c230673c8f408bd86482fd611d2d5cb6aff996,2179
|
||||||
- http-io-streams-0.1.6.0@sha256:53f5bab177efb52cd65ec396fd04ed59b93e5f919fb3700cd7dacd6cfce6f06d,3582
|
- http-io-streams-0.1.6.0@sha256:53f5bab177efb52cd65ec396fd04ed59b93e5f919fb3700cd7dacd6cfce6f06d,3582
|
||||||
- libarchive-3.0.2.1@sha256:40ebf2a278e585802427bc58826867208bb33822f63d56107a1fcc3ca04d691d,10990
|
|
||||||
- lzma-static-5.2.5.3@sha256:2758ee58c35992fcf7db78e98684c357a16a82fa2a4e7c352a6c210c08c555d8,7308
|
- lzma-static-5.2.5.3@sha256:2758ee58c35992fcf7db78e98684c357a16a82fa2a4e7c352a6c210c08c555d8,7308
|
||||||
- os-release-1.0.1@sha256:1281c62081f438fc3f0874d3bae6a4887d5964ac25261ba06e29d368ab173467,2716
|
|
||||||
- optics-0.4@sha256:9fb69bf0195b8d8f1f8cd0098000946868b8a3c3ffb51e5b64f79fc600c3eb4c,6568
|
- optics-0.4@sha256:9fb69bf0195b8d8f1f8cd0098000946868b8a3c3ffb51e5b64f79fc600c3eb4c,6568
|
||||||
- optics-core-0.4@sha256:59e04aebca536bd011ae50c781937f45af4c1456af1eb9fb578f9a69eee293cd,4995
|
- optics-core-0.4@sha256:59e04aebca536bd011ae50c781937f45af4c1456af1eb9fb578f9a69eee293cd,4995
|
||||||
- optics-extra-0.4@sha256:b9914f38aa7d5c92f231060d9168447f9f5a367c07df9bf47a003e3e786d5e05,3432
|
- optics-extra-0.4@sha256:b9914f38aa7d5c92f231060d9168447f9f5a367c07df9bf47a003e3e786d5e05,3432
|
||||||
- optics-th-0.4@sha256:7c838b5b1d6998133bf8f0641c36197ed6cb468dc69515e1952f33f0bbe8e11d,2009
|
- optics-th-0.4@sha256:7c838b5b1d6998133bf8f0641c36197ed6cb468dc69515e1952f33f0bbe8e11d,2009
|
||||||
|
- os-release-1.0.1@sha256:1281c62081f438fc3f0874d3bae6a4887d5964ac25261ba06e29d368ab173467,2716
|
||||||
- primitive-0.7.1.0@sha256:29de6bfd0cf8ba023ceb806203dfbec0e51e3524e75ffe41056f70b4229c6f0f,2728
|
- primitive-0.7.1.0@sha256:29de6bfd0cf8ba023ceb806203dfbec0e51e3524e75ffe41056f70b4229c6f0f,2728
|
||||||
- regex-posix-clib-2.7
|
- regex-posix-clib-2.7
|
||||||
- streamly-0.7.3@sha256:ad2a488fe802692ed47cab9fd0416c2904aac9e51cf2d8aafd1c3a40064c42f5,27421
|
- streamly-0.7.3@sha256:ad2a488fe802692ed47cab9fd0416c2904aac9e51cf2d8aafd1c3a40064c42f5,27421
|
||||||
@@ -45,7 +39,6 @@ extra-deps:
|
|||||||
- streamly-posix-0.1.0.1@sha256:5d89b806281035d34020387ed99dde1ddab282c7ed66df3b7cd010b38fd3517b,2138
|
- streamly-posix-0.1.0.1@sha256:5d89b806281035d34020387ed99dde1ddab282c7ed66df3b7cd010b38fd3517b,2138
|
||||||
- strict-base-0.4.0.0@sha256:2ff4e43cb95eedf2995558d7fc34d19362846413dd39e6aa6a5b3ea8228fef9f,1248
|
- strict-base-0.4.0.0@sha256:2ff4e43cb95eedf2995558d7fc34d19362846413dd39e6aa6a5b3ea8228fef9f,1248
|
||||||
- xor-0.0.1.0@sha256:f8362b4a68562b9afbcd727ff64c1a303970df3a032e0033d2f4c094c3501df3,2243
|
- xor-0.0.1.0@sha256:f8362b4a68562b9afbcd727ff64c1a303970df3a032e0033d2f4c094c3501df3,2243
|
||||||
- zip-1.7.1@sha256:0ce03d0fbffba47c1ab6fbb9166f8ba5373d828d78587df21b7e9d7bb150f929,3918
|
|
||||||
|
|
||||||
flags:
|
flags:
|
||||||
http-io-streams:
|
http-io-streams:
|
||||||
@@ -57,7 +50,21 @@ flags:
|
|||||||
regex-posix:
|
regex-posix:
|
||||||
_regex-posix-clib: true
|
_regex-posix-clib: true
|
||||||
|
|
||||||
|
aeson-pretty:
|
||||||
|
lib-only: true
|
||||||
|
|
||||||
|
cabal-plan:
|
||||||
|
exe: false
|
||||||
|
|
||||||
ghc-options:
|
ghc-options:
|
||||||
"$locals": -O2
|
"$locals": -O2
|
||||||
streamly: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
streamly: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
||||||
ghcup: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
ghcup: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
|
||||||
|
|
||||||
|
build:
|
||||||
|
test: true
|
||||||
|
test-arguments:
|
||||||
|
no-run-tests: true
|
||||||
|
bench: true
|
||||||
|
benchmark-opts:
|
||||||
|
no-run-benchmarks: true
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ instance Arbitrary ByteString where
|
|||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
instance Arbitrary Scheme where
|
instance Arbitrary Scheme where
|
||||||
arbitrary = oneof [ pure (Scheme "http"), pure (Scheme "https") ]
|
arbitrary = elements [ Scheme "http", Scheme "https" ]
|
||||||
|
|
||||||
instance Arbitrary Host where
|
instance Arbitrary Host where
|
||||||
arbitrary = genericArbitrary
|
arbitrary = genericArbitrary
|
||||||
|
|||||||
@@ -13,4 +13,5 @@ import Test.Hspec
|
|||||||
|
|
||||||
spec :: Spec
|
spec :: Spec
|
||||||
spec = do
|
spec = do
|
||||||
roundtripAndGoldenSpecs (Proxy @GHCupInfo)
|
roundtripAndGoldenSpecsWithSettings (defaultSettings { goldenDirectoryOption = CustomDirectoryName "test/golden" }) (Proxy @GHCupInfo)
|
||||||
|
|
||||||
|
|||||||
@@ -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