Compare commits
21 Commits
ghc-8.10.1
...
vhttp-clie
| Author | SHA1 | Date | |
|---|---|---|---|
| dd72f1eeaf | |||
| f46c8bdd6f | |||
| 4c4266dd8c | |||
| e8336bbc8a | |||
| 0f69c73e0e | |||
| e348de8dc4 | |||
| 55a3ba9be2 | |||
| 51b29b81b0 | |||
| 3c2e0334b7 | |||
| 0679626514 | |||
| 5035051135 | |||
| 63c70ee74b | |||
| 2e0bbca2e0 | |||
| b52fa23ca2 | |||
| ba03b78f23 | |||
| 04ef472c15 | |||
| 75cd8f2341 | |||
| f2e26c1800 | |||
| 0f7dd597d2 | |||
| fb0eba9201 | |||
| 3c80929c38 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -5,3 +5,10 @@ dist-newstyle/
|
||||
cabal.project.local
|
||||
.stack-work/
|
||||
bin/
|
||||
/*.prof
|
||||
/*.ps
|
||||
/*.hp
|
||||
tags
|
||||
TAGS
|
||||
/tmp/
|
||||
.entangled
|
||||
|
||||
@@ -150,7 +150,7 @@ release:linux:64bit:
|
||||
- ./.gitlab/before_script/linux/alpine/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "x86_64-linux-ghcup"
|
||||
GHC_VERSION: "8.10.1"
|
||||
GHC_VERSION: "8.8.3"
|
||||
CABAL_VERSION: "3.2.0.0"
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ release:linux:32bit:
|
||||
- ./.gitlab/before_script/linux/alpine/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "i386-linux-ghcup"
|
||||
GHC_VERSION: "8.10.1"
|
||||
GHC_VERSION: "8.8.3"
|
||||
CABAL_VERSION: "3.2.0.0"
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ release:darwin:
|
||||
- ./.gitlab/before_script/darwin/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "x86_64-apple-darwin-ghcup"
|
||||
GHC_VERSION: "8.10.1"
|
||||
GHC_VERSION: "8.8.3"
|
||||
CABAL_VERSION: "3.2.0.0"
|
||||
MACOSX_DEPLOYMENT_TARGET: "10.7"
|
||||
|
||||
@@ -193,5 +193,6 @@ release:freebsd:
|
||||
- ./.gitlab/before_script/freebsd/install_deps.sh
|
||||
variables:
|
||||
ARTIFACT: "x86_64-portbld-freebsd-ghcup"
|
||||
GHC_VERSION: "8.10.1"
|
||||
GHC_VERSION: "8.8.3"
|
||||
CABAL_VERSION: "3.2.0.0"
|
||||
|
||||
|
||||
@@ -23,26 +23,13 @@ ln -sf libncursesw.so.6 /usr/lib/libtinfow.so.6
|
||||
ln -sf libtinfow.so.6 /usr/lib/libtinfow.so
|
||||
|
||||
if [ "${BIT}" = "32" ] ; then
|
||||
curl -sSfL https://downloads.haskell.org/~ghcup/0.1.5/i386-linux-ghcup-0.1.5 > ./ghcup-bin
|
||||
curl -sSfL https://downloads.haskell.org/ghcup/i386-linux-ghcup > ./ghcup-bin
|
||||
else
|
||||
curl -sSfL https://downloads.haskell.org/~ghcup/0.1.5/x86_64-linux-ghcup-0.1.5 > ./ghcup-bin
|
||||
curl -sSfL https://downloads.haskell.org/ghcup/x86_64-linux-ghcup > ./ghcup-bin
|
||||
fi
|
||||
chmod +x ghcup-bin
|
||||
./ghcup-bin upgrade
|
||||
./ghcup-bin install ${GHC_VERSION}
|
||||
# ./ghcup-bin install-cabal ${CABAL_VERSION}
|
||||
# install cabal-3.2.0.0
|
||||
if [ "${BIT}" = "32" ] ; then
|
||||
curl -sSfL -o cabal-install-3.2.0.0-i386-alpine-linux-musl.tar.xz 'https://hasufell.de/d/d3e215db133e4fcaa61e/files/?p=/cabal-install-3.2.0.0-i386-alpine-linux-musl.tar.xz&dl=1'
|
||||
tar xf cabal-install-3.2.0.0-i386-alpine-linux-musl.tar.xz
|
||||
cp cabal-install-3.2.0.0-i386-alpine-linux-musl "${GHCUP_INSTALL_BASE_PREFIX}/.ghcup/bin/cabal"
|
||||
else
|
||||
curl -sSfL -o cabal-install-3.2.0.0-x86_64-alpine-linux-musl.tar.xz 'https://hasufell.de/d/d3e215db133e4fcaa61e/files/?p=/cabal-install-3.2.0.0-x86_64-alpine-linux-musl.tar.xz&dl=1'
|
||||
tar xf cabal-install-3.2.0.0-x86_64-alpine-linux-musl.tar.xz
|
||||
cp cabal-install-3.2.0.0-x86_64-alpine-linux-musl "${GHCUP_INSTALL_BASE_PREFIX}/.ghcup/bin/cabal"
|
||||
fi
|
||||
chmod +x "${GHCUP_INSTALL_BASE_PREFIX}/.ghcup/bin/cabal"
|
||||
|
||||
./ghcup-bin install-cabal ${CABAL_VERSION}
|
||||
|
||||
# utils
|
||||
apk add --no-cache \
|
||||
|
||||
@@ -19,10 +19,10 @@ if [ "${OS}" = "LINUX" ] ; then
|
||||
if [ "${BIT}" = "32" ] ; then
|
||||
ecabal build -w ghc-${GHC_VERSION} --ghc-options='-split-sections -optl-static' -ftui -ftar
|
||||
else
|
||||
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 -finternal-downloader
|
||||
fi
|
||||
elif [ "${OS}" = "FREEBSD" ] ; then
|
||||
ecabal build -w ghc-${GHC_VERSION} --ghc-options='-split-sections' --constraint="zlib static"
|
||||
ecabal build -w ghc-${GHC_VERSION} --ghc-options='-split-sections' --constraint="zlib static" -ftui
|
||||
else
|
||||
ecabal build -w ghc-${GHC_VERSION} --constraint="zlib static" --constraint="lzma static" -ftui
|
||||
fi
|
||||
|
||||
@@ -20,5 +20,5 @@ ghcup set 8.8.3
|
||||
cabal update
|
||||
cabal build --constraint="zlib static" --constraint="lzma static" -ftui
|
||||
cp "$(cabal new-exec --verbose=0 --offline sh -- -c 'command -v ghcup')" .
|
||||
strip -s ghcup
|
||||
strip ./ghcup
|
||||
cp ghcup "./${ARTIFACT}"
|
||||
|
||||
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,5 +1,15 @@
|
||||
# Revision history for ghcup
|
||||
|
||||
## 0.1.6 -- 2020-07-13
|
||||
|
||||
* Create a new curses (brick) based TUI, accessible via `ghcup tui` #24
|
||||
* Support multiple installed versions of cabal #23
|
||||
* Improvements to `ghcup list` (show unavailable bindists for platform)
|
||||
* Fix redhat downloads #29
|
||||
* Support for hadrian bindists (fixes alpine-8.10.1) #31
|
||||
* Add FreeBSD bindists 8.6.5 and 8.8.3
|
||||
* Fix memory leak during unpack
|
||||
|
||||
## 0.1.5 -- 2020-04-30
|
||||
|
||||
* Fix errors when PATH variable contains path components that are actually files
|
||||
|
||||
@@ -205,13 +205,10 @@ install' AppState {..} (_, ListResult {..}) = do
|
||||
#if !defined(TAR)
|
||||
, ArchiveResult
|
||||
#endif
|
||||
, DistroNotFound
|
||||
, FileDoesNotExistError
|
||||
, CopyError
|
||||
, NoCompatibleArch
|
||||
, NoDownload
|
||||
, NotInstalled
|
||||
, NoCompatiblePlatform
|
||||
, BuildFailed
|
||||
, TagNotFound
|
||||
, DigestError
|
||||
@@ -283,7 +280,11 @@ changelog' AppState {..} (_, ListResult {..}) = do
|
||||
Nothing -> pure $ Left
|
||||
[i|Could not find ChangeLog for #{lTool}, version #{prettyVer lVer}|]
|
||||
Just uri -> do
|
||||
exec "xdg-open" True [serializeURIRef' uri] Nothing Nothing >>= \case
|
||||
let cmd = case _rPlatform pfreq of
|
||||
Darwin -> "open"
|
||||
Linux _ -> "xdg-open"
|
||||
FreeBSD -> "xdg-open"
|
||||
exec cmd True [serializeURIRef' uri] Nothing Nothing >>= \case
|
||||
Right _ -> pure $ Right ()
|
||||
Left e -> pure $ Left [i|#{e}|]
|
||||
|
||||
|
||||
@@ -1308,9 +1308,14 @@ Make sure to clean up #{tmpdir} afterwards.|])
|
||||
pure ExitSuccess
|
||||
Just uri -> do
|
||||
let uri' = T.unpack . decUTF8Safe . serializeURIRef' $ uri
|
||||
cmd = case _rPlatform pfreq of
|
||||
Darwin -> "open"
|
||||
Linux _ -> "xdg-open"
|
||||
FreeBSD -> "xdg-open"
|
||||
|
||||
if clOpen
|
||||
then
|
||||
exec "xdg-open"
|
||||
exec cmd
|
||||
True
|
||||
[serializeURIRef' uri]
|
||||
Nothing
|
||||
|
||||
@@ -28,16 +28,17 @@ eghcup() {
|
||||
download_ghcup() {
|
||||
_plat="$(uname -s)"
|
||||
_arch=$(uname -m)
|
||||
_ghver="0.1.5"
|
||||
_ghver="0.1.6"
|
||||
_base_url="https://downloads.haskell.org/~ghcup"
|
||||
|
||||
case "${_plat}" in
|
||||
"linux"|"Linux")
|
||||
case "${_arch}" in
|
||||
x86_64|amd64)
|
||||
_url=https://downloads.haskell.org/~ghcup/${_ghver}/x86_64-linux-ghcup-${_ghver}
|
||||
_url=${_base_url}/${_ghver}/x86_64-linux-ghcup-${_ghver}
|
||||
;;
|
||||
i*86)
|
||||
_url=https://downloads.haskell.org/~ghcup/${_ghver}/i386-linux-ghcup-${_ghver}
|
||||
_url=${_base_url}/${_ghver}/i386-linux-ghcup-${_ghver}
|
||||
;;
|
||||
*) die "Unknown architecture: ${_arch}"
|
||||
;;
|
||||
@@ -53,7 +54,7 @@ download_ghcup() {
|
||||
*) die "Unknown architecture: ${_arch}"
|
||||
;;
|
||||
esac
|
||||
_url=https://downloads.haskell.org/~ghcup/${_ghver}/x86_64-portbld-freebsd-ghcup-${_ghver}
|
||||
_url=${_base_url}/${_ghver}/x86_64-portbld-freebsd-ghcup-${_ghver}
|
||||
;;
|
||||
"Darwin"|"darwin")
|
||||
case "${_arch}" in
|
||||
@@ -65,14 +66,14 @@ download_ghcup() {
|
||||
*) die "Unknown architecture: ${_arch}"
|
||||
;;
|
||||
esac
|
||||
_url=https://downloads.haskell.org/~ghcup/0.1.5/x86_64-apple-darwin-ghcup-0.1.5-p2 ;;
|
||||
_url=${_base_url}/${_ghver}/x86_64-apple-darwin-ghcup-${_ghver} ;;
|
||||
*) die "Unknown platform: ${_plat}"
|
||||
;;
|
||||
esac
|
||||
|
||||
edo curl -Lf "${_url}" > "${GHCUP_INSTALL_BASE_PREFIX}"/.ghcup/bin/ghcup
|
||||
|
||||
unset _plat _arch _url _ghver
|
||||
unset _plat _arch _url _ghver _base_url
|
||||
}
|
||||
|
||||
|
||||
@@ -129,10 +130,10 @@ if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||
read -r answer </dev/tty
|
||||
fi
|
||||
|
||||
eghcup --cache install "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
||||
eghcup --cache install ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
||||
|
||||
eghcup set "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
||||
eghcup --cache install-cabal "${BOOTSTRAP_HASKELL_CABAL_VERSION}"
|
||||
eghcup set ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"
|
||||
eghcup --cache install cabal "${BOOTSTRAP_HASKELL_CABAL_VERSION}"
|
||||
|
||||
edo cabal new-update
|
||||
|
||||
@@ -163,6 +164,9 @@ if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||
exit 0
|
||||
fi
|
||||
;;
|
||||
*/fish) # login shell is fish
|
||||
GHCUP_PROFILE_FILE="$HOME/.config/fish/config.fish"
|
||||
MY_SHELL="fish" ;;
|
||||
*) exit 0 ;;
|
||||
esac
|
||||
|
||||
@@ -178,7 +182,16 @@ if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
|
||||
|
||||
case $next_answer in
|
||||
[Yy]*)
|
||||
echo "[ -f \"\${GHCUP_INSTALL_BASE_PREFIX:=\$HOME}/.ghcup/env\" ] && source \"\${GHCUP_INSTALL_BASE_PREFIX:=\$HOME}/.ghcup/env\"" >> "${GHCUP_PROFILE_FILE}"
|
||||
case $MY_SHELL in
|
||||
"") break ;;
|
||||
fish)
|
||||
echo "set -q GHCUP_INSTALL_BASE_PREFIX[1]; or set GHCUP_INSTALL_BASE_PREFIX \$HOME" >> "${GHCUP_PROFILE_FILE}"
|
||||
echo "test -f \$GHCUP_INSTALL_BASE_PREFIX/.ghcup/env ; and set -gx PATH \$HOME/.cabal/bin \$GHCUP_INSTALL_BASE_PREFIX/.ghcup/bin \$PATH" >> "${GHCUP_PROFILE_FILE}"
|
||||
break ;;
|
||||
*)
|
||||
echo "[ -f \"\${GHCUP_INSTALL_BASE_PREFIX:=\$HOME}/.ghcup/env\" ] && source \"\${GHCUP_INSTALL_BASE_PREFIX:=\$HOME}/.ghcup/env\"" >> "${GHCUP_PROFILE_FILE}"
|
||||
break ;;
|
||||
esac
|
||||
printf "\\033[0;35m%s\\033[0m\\n" "OK! ${GHCUP_PROFILE_FILE} has been modified. Restart your terminal for the changes to take effect,"
|
||||
printf "\\033[0;35m%s\\033[0m\\n" "or type \"source ${GHCUP_INSTALL_BASE_PREFIX}/.ghcup/env\" to apply them in your current terminal session."
|
||||
exit 0;;
|
||||
|
||||
148
ghcup-0.0.2.json
148
ghcup-0.0.2.json
@@ -1250,6 +1250,136 @@
|
||||
"base-4.13.0.0"
|
||||
]
|
||||
},
|
||||
"8.8.4": {
|
||||
"viArch": {
|
||||
"A_64": {
|
||||
"Linux_Debian": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "4862559d221153caf978f4bf2c15a82c114d1e1f43b298b2ecff2ac94b586d20",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-deb9-linux.tar.xz"
|
||||
},
|
||||
"8": {
|
||||
"dlHash": "51a36892f1264744195274187298d13ac62bce2da86d4ddf76d8054ab90f2feb",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-deb8-linux.tar.xz"
|
||||
}
|
||||
},
|
||||
"Linux_Ubuntu": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "f32e37f8aa03e74bad533ae02f62dc27a4521e78199576af490888ba34b515db",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-fedora27-linux.tar.xz"
|
||||
},
|
||||
"16.04": {
|
||||
"dlHash": "4862559d221153caf978f4bf2c15a82c114d1e1f43b298b2ecff2ac94b586d20",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-deb9-linux.tar.xz"
|
||||
},
|
||||
"18.04": {
|
||||
"dlHash": "4862559d221153caf978f4bf2c15a82c114d1e1f43b298b2ecff2ac94b586d20",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-deb9-linux.tar.xz"
|
||||
}
|
||||
},
|
||||
"Darwin": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "e80a789e9d8cfb41dd87f3284b75432427c4461c1731d220d04ead8733ccdb5e",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-apple-darwin.tar.xz"
|
||||
}
|
||||
},
|
||||
"Linux_RedHat": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "a12aa4b1fd3c64240a8a6d15196d33e1c0e0d55b51ff78c387242126d0ef7910",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-centos7-linux.tar.xz"
|
||||
}
|
||||
},
|
||||
"Linux_UnknownLinux": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "f32e37f8aa03e74bad533ae02f62dc27a4521e78199576af490888ba34b515db",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-fedora27-linux.tar.xz"
|
||||
}
|
||||
},
|
||||
"Linux_Mint": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "4862559d221153caf978f4bf2c15a82c114d1e1f43b298b2ecff2ac94b586d20",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-deb9-linux.tar.xz"
|
||||
}
|
||||
},
|
||||
"Linux_Fedora": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "f32e37f8aa03e74bad533ae02f62dc27a4521e78199576af490888ba34b515db",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-fedora27-linux.tar.xz"
|
||||
}
|
||||
},
|
||||
"Linux_CentOS": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "a12aa4b1fd3c64240a8a6d15196d33e1c0e0d55b51ff78c387242126d0ef7910",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-centos7-linux.tar.xz"
|
||||
}
|
||||
},
|
||||
"Linux_AmazonLinux": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "a12aa4b1fd3c64240a8a6d15196d33e1c0e0d55b51ff78c387242126d0ef7910",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-centos7-linux.tar.xz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"A_32": {
|
||||
"FreeBSD": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "8cebe5ccf454e82acd1ff52ca57590d1ab0f3f44a981b46257ec12158c8c447e",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://files.hasufell.de/ghc/ghc-8.8.4-x86_64-portbld-freebsd.tar.xz"
|
||||
}
|
||||
},
|
||||
"Linux_Debian": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "43dd954910c9027694312cef0aabc7774d102d0422b7172802cfb72f7d5da3a0",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-i386-deb9-linux.tar.xz"
|
||||
}
|
||||
},
|
||||
"Linux_Ubuntu": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "43dd954910c9027694312cef0aabc7774d102d0422b7172802cfb72f7d5da3a0",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-i386-deb9-linux.tar.xz"
|
||||
}
|
||||
},
|
||||
"Linux_UnknownLinux": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "43dd954910c9027694312cef0aabc7774d102d0422b7172802cfb72f7d5da3a0",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-i386-deb9-linux.tar.xz"
|
||||
}
|
||||
},
|
||||
"Linux_Mint": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "43dd954910c9027694312cef0aabc7774d102d0422b7172802cfb72f7d5da3a0",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-i386-deb9-linux.tar.xz"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"viSourceDL": {
|
||||
"dlHash": "f0505e38b2235ff9f1090b51f44d6c8efd371068e5a6bb42a2a6d8b67b5ffc2d",
|
||||
"dlSubdir": "ghc-8.8.4",
|
||||
"dlUri": "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-src.tar.xz"
|
||||
},
|
||||
"viChangeLog": "https://downloads.haskell.org/~ghc/8.8.4/docs/html/users_guide/8.8.4-notes.html",
|
||||
"viTags": [
|
||||
"base-4.13.0.0"
|
||||
]
|
||||
},
|
||||
"8.4.3": {
|
||||
"viArch": {
|
||||
"A_64": {
|
||||
@@ -2322,37 +2452,37 @@
|
||||
}
|
||||
},
|
||||
"GHCup": {
|
||||
"0.1.5": {
|
||||
"0.1.6": {
|
||||
"viArch": {
|
||||
"A_64": {
|
||||
"FreeBSD": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "6dd57cc5958ef3a6ba7de22808d9292d31dada8af95277578b69be35fc090194",
|
||||
"dlHash": "6bbfb1047691ff3ae9249e8805cf9f37bab30a008dae130cb2a4b3aa5253e6e5",
|
||||
"dlSubdir": null,
|
||||
"dlUri": "https://downloads.haskell.org/~ghcup/0.1.5/x86_64-portbld-freebsd-ghcup-0.1.5"
|
||||
"dlUri": "https://downloads.haskell.org/~ghcup/0.1.6/x86_64-portbld-freebsd-ghcup-0.1.6"
|
||||
}
|
||||
},
|
||||
"Darwin": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "456770c3b1510d44a0e401e0677faa9f5670ef81a11646f47cbba1b95404e788",
|
||||
"dlHash": "1e025e66d7f7b75d94f17a7da6120efd7e2df918a8eac88c4711ed11d2aac4ec",
|
||||
"dlSubdir": null,
|
||||
"dlUri": "https://downloads.haskell.org/~ghcup/0.1.5/x86_64-apple-darwin-ghcup-0.1.5-p2"
|
||||
"dlUri": "https://downloads.haskell.org/~ghcup/0.1.6/x86_64-apple-darwin-ghcup-0.1.6"
|
||||
}
|
||||
},
|
||||
"Linux_UnknownLinux": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "cfdb01dde77121859b5d90b6707238b54e23787fcbb3003e18ab52a5dbfee330",
|
||||
"dlHash": "bdbec0cdf4c8511c4082dd83993d15034c0fbcb5722ecf418c1cee40667da8af",
|
||||
"dlSubdir": null,
|
||||
"dlUri": "https://downloads.haskell.org/~ghcup/0.1.5/x86_64-linux-ghcup-0.1.5"
|
||||
"dlUri": "https://downloads.haskell.org/~ghcup/0.1.6/x86_64-linux-ghcup-0.1.6"
|
||||
}
|
||||
}
|
||||
},
|
||||
"A_32": {
|
||||
"Linux_UnknownLinux": {
|
||||
"unknown_versioning": {
|
||||
"dlHash": "3707f60d703912709335dc0103fb1af5e5dfa83050825a8156b56bc81760b2a8",
|
||||
"dlHash": "0366ed6c00862c3c002cdefc3e37523ad80e655387956c7ab58b268aaa6fae5d",
|
||||
"dlSubdir": null,
|
||||
"dlUri": "https://downloads.haskell.org/~ghcup/0.1.5/i386-linux-ghcup-0.1.5"
|
||||
"dlUri": "https://downloads.haskell.org/~ghcup/0.1.6/i386-linux-ghcup-0.1.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
29
ghcup.cabal
29
ghcup.cabal
@@ -1,6 +1,6 @@
|
||||
cabal-version: 3.0
|
||||
name: ghcup
|
||||
version: 0.1.5
|
||||
version: 0.1.6
|
||||
synopsis: ghc toolchain installer as an exe/library
|
||||
description:
|
||||
A rewrite of the shell script ghcup, for providing
|
||||
@@ -105,11 +105,14 @@ common hpath-io
|
||||
common hpath-posix
|
||||
build-depends: hpath-posix >=0.13.2
|
||||
|
||||
common http-io-streams
|
||||
build-depends: http-io-streams >=0.1.2.0
|
||||
common http-client
|
||||
build-depends: http-client >=0.7.1
|
||||
|
||||
common io-streams
|
||||
build-depends: io-streams >=1.5
|
||||
common http-client-openssl
|
||||
build-depends: http-client-openssl >=0.3.1.0
|
||||
|
||||
common http-types
|
||||
build-depends: http-types >=0.12.3
|
||||
|
||||
common libarchive
|
||||
build-depends: libarchive >= 2.2.5.0
|
||||
@@ -120,6 +123,9 @@ common lzma
|
||||
common megaparsec
|
||||
build-depends: megaparsec >=8.0.0
|
||||
|
||||
common monad-control
|
||||
build-depends: monad-control >=1.0.2.3
|
||||
|
||||
common monad-logger
|
||||
build-depends: monad-logger >=0.3.31
|
||||
|
||||
@@ -189,6 +195,9 @@ common time
|
||||
common transformers
|
||||
build-depends: transformers >=0.5
|
||||
|
||||
common transformers-base
|
||||
build-depends: transformers-base >=0.4.4
|
||||
|
||||
common os-release
|
||||
build-depends: os-release >=1.0.0
|
||||
|
||||
@@ -263,6 +272,7 @@ library
|
||||
, hpath-posix
|
||||
, lzma
|
||||
, megaparsec
|
||||
, monad-control
|
||||
, monad-logger
|
||||
, mtl
|
||||
, optics
|
||||
@@ -282,6 +292,7 @@ library
|
||||
, text
|
||||
, time
|
||||
, transformers
|
||||
, transformers-base
|
||||
, os-release
|
||||
, unix
|
||||
, unix-bytestring
|
||||
@@ -299,7 +310,6 @@ library
|
||||
GHCup.Data.GHCupInfo
|
||||
GHCup.Data.ToolRequirements
|
||||
GHCup.Download
|
||||
GHCup.Download.Utils
|
||||
GHCup.Errors
|
||||
GHCup.Platform
|
||||
GHCup.Requirements
|
||||
@@ -323,10 +333,11 @@ library
|
||||
if flag(internal-downloader)
|
||||
import:
|
||||
HsOpenSSL
|
||||
, http-io-streams
|
||||
, io-streams
|
||||
, http-client
|
||||
, http-client-openssl
|
||||
, http-types
|
||||
, terminal-progress-bar
|
||||
exposed-modules: GHCup.Download.IOStreams
|
||||
exposed-modules: GHCup.Download.Internal
|
||||
cpp-options: -DINTERNAL_DOWNLOADER
|
||||
|
||||
if flag(tar)
|
||||
|
||||
@@ -50,7 +50,7 @@ import Data.Versions
|
||||
import Data.Word8
|
||||
import GHC.IO.Exception
|
||||
import HPath
|
||||
import HPath.IO
|
||||
import HPath.IO hiding ( hideError )
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Optics
|
||||
import Prelude hiding ( abs
|
||||
|
||||
@@ -846,6 +846,56 @@ ghc_883_64_freebsd = DownloadInfo
|
||||
|
||||
|
||||
|
||||
-----------------
|
||||
--[ GHC 8.8.4 ]--
|
||||
-----------------
|
||||
|
||||
|
||||
|
||||
ghc_884_64_deb8 :: DownloadInfo
|
||||
ghc_884_64_deb8 = DownloadInfo
|
||||
[uri|https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-deb8-linux.tar.xz|]
|
||||
(Just [rel|ghc-8.8.4|])
|
||||
"51a36892f1264744195274187298d13ac62bce2da86d4ddf76d8054ab90f2feb"
|
||||
|
||||
ghc_884_64_deb9 :: DownloadInfo
|
||||
ghc_884_64_deb9 = DownloadInfo
|
||||
[uri|https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-deb9-linux.tar.xz|]
|
||||
(Just [rel|ghc-8.8.4|])
|
||||
"4862559d221153caf978f4bf2c15a82c114d1e1f43b298b2ecff2ac94b586d20"
|
||||
|
||||
ghc_884_32_deb9 :: DownloadInfo
|
||||
ghc_884_32_deb9 = DownloadInfo
|
||||
[uri|https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-i386-deb9-linux.tar.xz|]
|
||||
(Just [rel|ghc-8.8.4|])
|
||||
"43dd954910c9027694312cef0aabc7774d102d0422b7172802cfb72f7d5da3a0"
|
||||
|
||||
ghc_884_64_fedora :: DownloadInfo
|
||||
ghc_884_64_fedora = DownloadInfo
|
||||
[uri|https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-fedora27-linux.tar.xz|]
|
||||
(Just [rel|ghc-8.8.4|])
|
||||
"f32e37f8aa03e74bad533ae02f62dc27a4521e78199576af490888ba34b515db"
|
||||
|
||||
ghc_884_64_centos :: DownloadInfo
|
||||
ghc_884_64_centos = DownloadInfo
|
||||
[uri|https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-centos7-linux.tar.xz|]
|
||||
(Just [rel|ghc-8.8.4|])
|
||||
"a12aa4b1fd3c64240a8a6d15196d33e1c0e0d55b51ff78c387242126d0ef7910"
|
||||
|
||||
ghc_884_64_darwin :: DownloadInfo
|
||||
ghc_884_64_darwin = DownloadInfo
|
||||
[uri|https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-apple-darwin.tar.xz|]
|
||||
(Just [rel|ghc-8.8.4|])
|
||||
"e80a789e9d8cfb41dd87f3284b75432427c4461c1731d220d04ead8733ccdb5e"
|
||||
|
||||
ghc_884_64_freebsd :: DownloadInfo
|
||||
ghc_884_64_freebsd = DownloadInfo
|
||||
[uri|https://files.hasufell.de/ghc/ghc-8.8.4-x86_64-portbld-freebsd.tar.xz|]
|
||||
(Just [rel|ghc-8.8.4|])
|
||||
"8cebe5ccf454e82acd1ff52ca57590d1ab0f3f44a981b46257ec12158c8c447e"
|
||||
|
||||
|
||||
|
||||
-----------------
|
||||
--[ GHC 8.10.1 ]--
|
||||
-----------------
|
||||
@@ -1039,32 +1089,32 @@ cabal_3200_64_alpine = DownloadInfo
|
||||
-------------
|
||||
|
||||
|
||||
ghcup_015_32_linux :: DownloadInfo
|
||||
ghcup_015_32_linux = DownloadInfo
|
||||
[uri|https://downloads.haskell.org/~ghcup/0.1.5/i386-linux-ghcup-0.1.5|]
|
||||
ghcup_016_32_linux :: DownloadInfo
|
||||
ghcup_016_32_linux = DownloadInfo
|
||||
[uri|https://downloads.haskell.org/~ghcup/0.1.6/i386-linux-ghcup-0.1.6|]
|
||||
Nothing
|
||||
"3707f60d703912709335dc0103fb1af5e5dfa83050825a8156b56bc81760b2a8"
|
||||
"0366ed6c00862c3c002cdefc3e37523ad80e655387956c7ab58b268aaa6fae5d"
|
||||
|
||||
|
||||
ghcup_015_64_linux :: DownloadInfo
|
||||
ghcup_015_64_linux = DownloadInfo
|
||||
[uri|https://downloads.haskell.org/~ghcup/0.1.5/x86_64-linux-ghcup-0.1.5|]
|
||||
ghcup_016_64_linux :: DownloadInfo
|
||||
ghcup_016_64_linux = DownloadInfo
|
||||
[uri|https://downloads.haskell.org/~ghcup/0.1.6/x86_64-linux-ghcup-0.1.6|]
|
||||
Nothing
|
||||
"cfdb01dde77121859b5d90b6707238b54e23787fcbb3003e18ab52a5dbfee330"
|
||||
"bdbec0cdf4c8511c4082dd83993d15034c0fbcb5722ecf418c1cee40667da8af"
|
||||
|
||||
|
||||
ghcup_015_64_freebsd :: DownloadInfo
|
||||
ghcup_015_64_freebsd = DownloadInfo
|
||||
[uri|https://downloads.haskell.org/~ghcup/0.1.5/x86_64-portbld-freebsd-ghcup-0.1.5|]
|
||||
ghcup_016_64_freebsd :: DownloadInfo
|
||||
ghcup_016_64_freebsd = DownloadInfo
|
||||
[uri|https://downloads.haskell.org/~ghcup/0.1.6/x86_64-portbld-freebsd-ghcup-0.1.6|]
|
||||
Nothing
|
||||
"6dd57cc5958ef3a6ba7de22808d9292d31dada8af95277578b69be35fc090194"
|
||||
"6bbfb1047691ff3ae9249e8805cf9f37bab30a008dae130cb2a4b3aa5253e6e5"
|
||||
|
||||
|
||||
ghcup_015_64_darwin10_13 :: DownloadInfo
|
||||
ghcup_015_64_darwin10_13 = DownloadInfo
|
||||
[uri|https://downloads.haskell.org/~ghcup/0.1.5/x86_64-apple-darwin-ghcup-0.1.5-p2|]
|
||||
ghcup_016_64_darwin10_13 :: DownloadInfo
|
||||
ghcup_016_64_darwin10_13 = DownloadInfo
|
||||
[uri|https://downloads.haskell.org/~ghcup/0.1.6/x86_64-apple-darwin-ghcup-0.1.6|]
|
||||
Nothing
|
||||
"456770c3b1510d44a0e401e0677faa9f5670ef81a11646f47cbba1b95404e788"
|
||||
"1e025e66d7f7b75d94f17a7da6120efd7e2df918a8eac88c4711ed11d2aac4ec"
|
||||
|
||||
|
||||
|
||||
@@ -1653,7 +1703,7 @@ ghcupDownloads = M.fromList
|
||||
)
|
||||
, (Darwin , M.fromList [(Nothing, ghc_865_64_darwin)])
|
||||
, (Linux Alpine, M.fromList [(Nothing, ghc_865_64_musl)])
|
||||
, (FreeBSD, M.fromList [(Nothing, ghc_865_64_freebsd)])
|
||||
, (FreeBSD , M.fromList [(Nothing, ghc_865_64_freebsd)])
|
||||
]
|
||||
)
|
||||
, ( A_32
|
||||
@@ -1832,6 +1882,59 @@ ghcupDownloads = M.fromList
|
||||
)
|
||||
]
|
||||
)
|
||||
, ( [vver|8.8.4|]
|
||||
, VersionInfo
|
||||
[Base [pver|4.13.0.0|]]
|
||||
(Just
|
||||
[uri|https://downloads.haskell.org/~ghc/8.8.4/docs/html/users_guide/8.8.4-notes.html|]
|
||||
)
|
||||
(Just $ DownloadInfo
|
||||
[uri|https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-src.tar.xz|]
|
||||
(Just [rel|ghc-8.8.4|])
|
||||
"f0505e38b2235ff9f1090b51f44d6c8efd371068e5a6bb42a2a6d8b67b5ffc2d"
|
||||
)
|
||||
$ M.fromList
|
||||
[ ( A_64
|
||||
, M.fromList
|
||||
[ ( Linux UnknownLinux
|
||||
, M.fromList [(Nothing, ghc_884_64_fedora)]
|
||||
)
|
||||
, (Linux Fedora, M.fromList [(Nothing, ghc_884_64_fedora)])
|
||||
, (Linux CentOS, M.fromList [(Nothing, ghc_884_64_centos)])
|
||||
, (Linux RedHat, M.fromList [(Nothing, ghc_884_64_centos)])
|
||||
, ( Linux AmazonLinux
|
||||
, M.fromList [(Nothing, ghc_884_64_centos)]
|
||||
)
|
||||
, ( Linux Ubuntu
|
||||
, M.fromList
|
||||
[ (Nothing , ghc_884_64_fedora)
|
||||
, (Just [vers|16.04|], ghc_884_64_deb9)
|
||||
, (Just [vers|18.04|], ghc_884_64_deb9)
|
||||
]
|
||||
)
|
||||
, (Linux Mint, M.fromList [(Nothing, ghc_884_64_deb9)])
|
||||
, ( Linux Debian
|
||||
, M.fromList
|
||||
[ (Nothing , ghc_884_64_deb9)
|
||||
, (Just [vers|8|], ghc_884_64_deb8)
|
||||
]
|
||||
)
|
||||
, (Darwin, M.fromList [(Nothing, ghc_884_64_darwin)])
|
||||
]
|
||||
)
|
||||
, ( A_32
|
||||
, M.fromList
|
||||
[ ( Linux UnknownLinux
|
||||
, M.fromList [(Nothing, ghc_884_32_deb9)]
|
||||
)
|
||||
, (Linux Ubuntu, M.fromList [(Nothing, ghc_884_32_deb9)])
|
||||
, (Linux Mint , M.fromList [(Nothing, ghc_884_32_deb9)])
|
||||
, (Linux Debian, M.fromList [(Nothing, ghc_884_32_deb9)])
|
||||
, (FreeBSD , M.fromList [(Nothing, ghc_884_64_freebsd)])
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
, ( [vver|8.10.1|]
|
||||
, VersionInfo
|
||||
[Latest, Base [pver|4.14.0.0|]]
|
||||
@@ -2005,7 +2108,7 @@ ghcupDownloads = M.fromList
|
||||
)
|
||||
, ( GHCup
|
||||
, M.fromList
|
||||
[ ( [vver|0.1.5|]
|
||||
[ ( [vver|0.1.6|]
|
||||
, VersionInfo
|
||||
[Recommended, Latest]
|
||||
(Just
|
||||
@@ -2016,16 +2119,16 @@ ghcupDownloads = M.fromList
|
||||
[ ( A_64
|
||||
, M.fromList
|
||||
[ ( Linux UnknownLinux
|
||||
, M.fromList [(Nothing, ghcup_015_64_linux)]
|
||||
, M.fromList [(Nothing, ghcup_016_64_linux)]
|
||||
)
|
||||
, (Darwin , M.fromList [(Nothing, ghcup_015_64_darwin10_13)])
|
||||
, (FreeBSD, M.fromList [(Nothing, ghcup_015_64_freebsd)])
|
||||
, (Darwin , M.fromList [(Nothing, ghcup_016_64_darwin10_13)])
|
||||
, (FreeBSD, M.fromList [(Nothing, ghcup_016_64_freebsd)])
|
||||
]
|
||||
)
|
||||
, ( A_32
|
||||
, M.fromList
|
||||
[ ( Linux UnknownLinux
|
||||
, M.fromList [(Nothing, ghcup_015_32_linux)]
|
||||
, M.fromList [(Nothing, ghcup_016_32_linux)]
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
module GHCup.Download where
|
||||
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
import GHCup.Download.IOStreams
|
||||
import GHCup.Download.Utils
|
||||
import GHCup.Download.Internal
|
||||
#endif
|
||||
import GHCup.Errors
|
||||
import GHCup.Types
|
||||
@@ -50,7 +49,7 @@ import Data.Versions
|
||||
import Data.Word8
|
||||
import GHC.IO.Exception
|
||||
import HPath
|
||||
import HPath.IO as HIO
|
||||
import HPath.IO as HIO hiding ( hideError )
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Optics
|
||||
import Prelude hiding ( abs
|
||||
@@ -233,16 +232,20 @@ getDownloads urlSource = do
|
||||
#if !defined(INTERNAL_DOWNLOADER)
|
||||
pure Nothing
|
||||
#else
|
||||
headers <-
|
||||
handleIO (\_ -> pure mempty)
|
||||
$ liftE
|
||||
$ ( catchAllE
|
||||
(\_ ->
|
||||
pure mempty :: Excepts '[] m1 (M.Map (CI ByteString) ByteString)
|
||||
Settings{..} <- lift ask
|
||||
case downloader of
|
||||
Internal -> do
|
||||
headers <-
|
||||
handleIO (\_ -> pure mempty)
|
||||
$ liftE
|
||||
$ ( catchAllE
|
||||
(\_ ->
|
||||
pure mempty :: Excepts '[] m1 (M.Map (CI ByteString) ByteString)
|
||||
)
|
||||
$ getHead uri'
|
||||
)
|
||||
$ getHead uri'
|
||||
)
|
||||
pure $ parseModifiedHeader headers
|
||||
pure $ parseModifiedHeader headers
|
||||
_ -> pure Nothing
|
||||
|
||||
parseModifiedHeader :: (M.Map (CI ByteString) ByteString) -> Maybe UTCTime
|
||||
parseModifiedHeader headers =
|
||||
@@ -339,9 +342,7 @@ download dli dest mfn
|
||||
liftE $ lEM @_ @'[ProcessError] $ liftIO $ exec "wget" True
|
||||
(o' ++ ["-O", toFilePath destFile , serializeURIRef' $ view dlUri dli]) Nothing Nothing
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
Internal -> do
|
||||
(https, host, fullPath, port) <- liftE $ uriToQuadruple (view dlUri dli)
|
||||
liftE $ downloadToFile https host fullPath port destFile
|
||||
Internal -> liftE $ downloadToFile (_dlUri dli) destFile
|
||||
#endif
|
||||
|
||||
liftE $ checkDigest dli destFile
|
||||
@@ -408,10 +409,8 @@ downloadBS :: (MonadReader Settings m, MonadCatch m, MonadIO m, MonadLogger m)
|
||||
m
|
||||
L.ByteString
|
||||
downloadBS uri'
|
||||
| scheme == "https"
|
||||
= dl True
|
||||
| scheme == "http"
|
||||
= dl False
|
||||
| scheme == "https" || scheme == "http"
|
||||
= dl
|
||||
| scheme == "file"
|
||||
= liftIOException doesNotExistErrorType (FileDoesNotExistError path)
|
||||
$ (liftIO $ RD.readFile path)
|
||||
@@ -421,11 +420,7 @@ downloadBS uri'
|
||||
where
|
||||
scheme = view (uriSchemeL' % schemeBSL') uri'
|
||||
path = view pathL' uri'
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
dl https = do
|
||||
#else
|
||||
dl _ = do
|
||||
#endif
|
||||
dl = do
|
||||
lift $ $(logDebug) [i|downloading: #{serializeURIRef' uri'}|]
|
||||
lift getDownloader >>= \case
|
||||
Curl -> do
|
||||
@@ -445,9 +440,7 @@ downloadBS uri'
|
||||
pure $ L.fromStrict stdout
|
||||
CapturedProcess (ExitFailure i') _ _ -> throwE $ NonZeroExit i' (toFilePath exe) args
|
||||
#if defined(INTERNAL_DOWNLOADER)
|
||||
Internal -> do
|
||||
(_, host', fullPath', port') <- liftE $ uriToQuadruple uri'
|
||||
liftE $ downloadBS' https host' fullPath' port'
|
||||
Internal -> liftE $ downloadBS' uri'
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,253 +0,0 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
|
||||
|
||||
module GHCup.Download.IOStreams where
|
||||
|
||||
|
||||
import GHCup.Download.Utils
|
||||
import GHCup.Errors
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Types.JSON ( )
|
||||
import GHCup.Utils.File
|
||||
import GHCup.Utils.Prelude
|
||||
|
||||
import Control.Applicative
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad
|
||||
import Control.Monad.Reader
|
||||
import Data.ByteString ( ByteString )
|
||||
import Data.ByteString.Builder
|
||||
import Data.CaseInsensitive ( CI )
|
||||
import Data.IORef
|
||||
import Data.Maybe
|
||||
import Data.Text.Read
|
||||
import HPath
|
||||
import HPath.IO as HIO
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Network.Http.Client hiding ( URL )
|
||||
import Optics
|
||||
import Prelude hiding ( abs
|
||||
, readFile
|
||||
, writeFile
|
||||
)
|
||||
import "unix" System.Posix.IO.ByteString
|
||||
hiding ( fdWrite )
|
||||
import "unix-bytestring" System.Posix.IO.ByteString
|
||||
( fdWrite )
|
||||
import System.ProgressBar
|
||||
import URI.ByteString
|
||||
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.ByteString.Lazy as L
|
||||
import qualified Data.Map.Strict as M
|
||||
import qualified System.IO.Streams as Streams
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
----------------------------
|
||||
--[ Low-level (non-curl) ]--
|
||||
----------------------------
|
||||
|
||||
|
||||
-- | Load the result of this download into memory at once.
|
||||
downloadBS' :: MonadIO m
|
||||
=> Bool -- ^ https?
|
||||
-> ByteString -- ^ host (e.g. "www.example.com")
|
||||
-> ByteString -- ^ path (e.g. "/my/file") including query
|
||||
-> Maybe Int -- ^ optional port (e.g. 3000)
|
||||
-> Excepts
|
||||
'[ HTTPStatusError
|
||||
, URIParseError
|
||||
, UnsupportedScheme
|
||||
, NoLocationHeader
|
||||
, TooManyRedirs
|
||||
]
|
||||
m
|
||||
(L.ByteString)
|
||||
downloadBS' https host path port = do
|
||||
bref <- liftIO $ newIORef (mempty :: Builder)
|
||||
let stepper bs = modifyIORef bref (<> byteString bs)
|
||||
downloadInternal False https host path port stepper
|
||||
liftIO (readIORef bref <&> toLazyByteString)
|
||||
|
||||
|
||||
downloadToFile :: (MonadMask m, MonadIO m)
|
||||
=> Bool -- ^ https?
|
||||
-> ByteString -- ^ host (e.g. "www.example.com")
|
||||
-> ByteString -- ^ path (e.g. "/my/file") including query
|
||||
-> Maybe Int -- ^ optional port (e.g. 3000)
|
||||
-> Path Abs -- ^ destination file to create and write to
|
||||
-> Excepts '[DownloadFailed] m ()
|
||||
downloadToFile https host fullPath port destFile = do
|
||||
fd <- liftIO $ createRegularFileFd newFilePerms destFile
|
||||
let stepper = fdWrite fd
|
||||
flip finally (liftIO $ closeFd fd)
|
||||
$ reThrowAll DownloadFailed $ downloadInternal True https host fullPath port stepper
|
||||
|
||||
|
||||
downloadInternal :: MonadIO m
|
||||
=> Bool -- ^ whether to show a progress bar
|
||||
-> Bool -- ^ https?
|
||||
-> ByteString -- ^ host
|
||||
-> ByteString -- ^ path with query
|
||||
-> Maybe Int -- ^ optional port
|
||||
-> (ByteString -> IO a) -- ^ the consuming step function
|
||||
-> Excepts
|
||||
'[ HTTPStatusError
|
||||
, URIParseError
|
||||
, UnsupportedScheme
|
||||
, NoLocationHeader
|
||||
, TooManyRedirs
|
||||
]
|
||||
m
|
||||
()
|
||||
downloadInternal = go (5 :: Int)
|
||||
|
||||
where
|
||||
go redirs progressBar https host path port consumer = do
|
||||
r <- liftIO $ withConnection' https host port action
|
||||
veitherToExcepts r >>= \case
|
||||
Just r' ->
|
||||
if redirs > 0 then followRedirectURL r' else throwE TooManyRedirs
|
||||
Nothing -> pure ()
|
||||
where
|
||||
action c = do
|
||||
let q = buildRequest1 $ http GET path
|
||||
|
||||
sendRequest c q emptyBody
|
||||
|
||||
receiveResponse
|
||||
c
|
||||
(\r i' -> runE $ do
|
||||
let scode = getStatusCode r
|
||||
if
|
||||
| scode >= 200 && scode < 300 -> downloadStream r i' >> pure Nothing
|
||||
| scode >= 300 && scode < 400 -> case getHeader r "Location" of
|
||||
Just r' -> pure $ Just $ r'
|
||||
Nothing -> throwE NoLocationHeader
|
||||
| otherwise -> throwE $ HTTPStatusError scode
|
||||
)
|
||||
|
||||
followRedirectURL bs = case parseURI strictURIParserOptions bs of
|
||||
Right uri' -> do
|
||||
(https', host', fullPath', port') <- liftE $ uriToQuadruple uri'
|
||||
go (redirs - 1) progressBar https' host' fullPath' port' consumer
|
||||
Left e -> throwE e
|
||||
|
||||
downloadStream r i' = do
|
||||
let size = case getHeader r "Content-Length" of
|
||||
Just x' -> case decimal $ decUTF8Safe x' of
|
||||
Left _ -> 0
|
||||
Right (r', _) -> r'
|
||||
Nothing -> 0
|
||||
|
||||
mpb <- if progressBar
|
||||
then Just <$> (liftIO $ newProgressBar defStyle 10 (Progress 0 size ()))
|
||||
else pure Nothing
|
||||
|
||||
outStream <- liftIO $ Streams.makeOutputStream
|
||||
(\case
|
||||
Just bs -> do
|
||||
forM_ mpb $ \pb -> incProgress pb (BS.length bs)
|
||||
void $ consumer bs
|
||||
Nothing -> pure ()
|
||||
)
|
||||
liftIO $ Streams.connect i' outStream
|
||||
|
||||
|
||||
getHead :: (MonadCatch m, MonadIO m)
|
||||
=> URI
|
||||
-> Excepts
|
||||
'[ HTTPStatusError
|
||||
, URIParseError
|
||||
, UnsupportedScheme
|
||||
, NoLocationHeader
|
||||
, TooManyRedirs
|
||||
, ProcessError
|
||||
]
|
||||
m
|
||||
(M.Map (CI ByteString) ByteString)
|
||||
getHead uri' | scheme == "https" = head' True
|
||||
| scheme == "http" = head' False
|
||||
| otherwise = throwE UnsupportedScheme
|
||||
|
||||
where
|
||||
scheme = view (uriSchemeL' % schemeBSL') uri'
|
||||
head' https = do
|
||||
(_, host', fullPath', port') <- liftE $ uriToQuadruple uri'
|
||||
liftE $ headInternal https host' fullPath' port'
|
||||
|
||||
|
||||
headInternal :: MonadIO m
|
||||
=> Bool -- ^ https?
|
||||
-> ByteString -- ^ host
|
||||
-> ByteString -- ^ path with query
|
||||
-> Maybe Int -- ^ optional port
|
||||
-> Excepts
|
||||
'[ HTTPStatusError
|
||||
, URIParseError
|
||||
, UnsupportedScheme
|
||||
, TooManyRedirs
|
||||
, NoLocationHeader
|
||||
]
|
||||
m
|
||||
(M.Map (CI ByteString) ByteString)
|
||||
headInternal = go (5 :: Int)
|
||||
|
||||
where
|
||||
go redirs https host path port = do
|
||||
r <- liftIO $ withConnection' https host port action
|
||||
veitherToExcepts r >>= \case
|
||||
Left r' ->
|
||||
if redirs > 0 then followRedirectURL r' else throwE TooManyRedirs
|
||||
Right hs -> pure hs
|
||||
where
|
||||
|
||||
action c = do
|
||||
let q = buildRequest1 $ http HEAD path
|
||||
|
||||
sendRequest c q emptyBody
|
||||
|
||||
unsafeReceiveResponse
|
||||
c
|
||||
(\r _ -> runE $ do
|
||||
let scode = getStatusCode r
|
||||
if
|
||||
| scode >= 200 && scode < 300 -> do
|
||||
let headers = getHeaderMap r
|
||||
pure $ Right $ headers
|
||||
| scode >= 300 && scode < 400 -> case getHeader r "Location" of
|
||||
Just r' -> pure $ Left $ r'
|
||||
Nothing -> throwE NoLocationHeader
|
||||
| otherwise -> throwE $ HTTPStatusError scode
|
||||
)
|
||||
|
||||
followRedirectURL bs = case parseURI strictURIParserOptions bs of
|
||||
Right uri' -> do
|
||||
(https', host', fullPath', port') <- liftE $ uriToQuadruple uri'
|
||||
go (redirs - 1) https' host' fullPath' port'
|
||||
Left e -> throwE e
|
||||
|
||||
|
||||
withConnection' :: Bool
|
||||
-> ByteString
|
||||
-> Maybe Int
|
||||
-> (Connection -> IO a)
|
||||
-> IO a
|
||||
withConnection' https host port action = bracket acquire closeConnection action
|
||||
|
||||
where
|
||||
acquire = case https of
|
||||
True -> do
|
||||
ctx <- baselineContextSSL
|
||||
openConnectionSSL ctx host (fromIntegral $ fromMaybe 443 port)
|
||||
False -> openConnection host (fromIntegral $ fromMaybe 80 port)
|
||||
213
lib/GHCup/Download/Internal.hs
Normal file
213
lib/GHCup/Download/Internal.hs
Normal file
@@ -0,0 +1,213 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
|
||||
|
||||
module GHCup.Download.Internal where
|
||||
|
||||
|
||||
import GHCup.Errors
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Types.JSON ( )
|
||||
import GHCup.Utils.File
|
||||
import GHCup.Utils.Prelude
|
||||
|
||||
import Control.Applicative
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad
|
||||
import Control.Monad.Reader
|
||||
import Data.ByteString ( ByteString )
|
||||
import Data.ByteString.Builder
|
||||
import Data.CaseInsensitive ( CI )
|
||||
import Data.IORef
|
||||
import Data.Maybe
|
||||
import Data.Text.Read
|
||||
import HPath
|
||||
import HPath.IO as HIO
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Network.HTTP.Client
|
||||
import Network.HTTP.Client.OpenSSL
|
||||
import Network.HTTP.Types.Status
|
||||
import Network.HTTP.Types.Header
|
||||
import Optics
|
||||
import Prelude hiding ( abs
|
||||
, readFile
|
||||
, writeFile
|
||||
)
|
||||
import "unix" System.Posix.IO.ByteString
|
||||
hiding ( fdWrite )
|
||||
import "unix-bytestring" System.Posix.IO.ByteString
|
||||
( fdWrite )
|
||||
import System.ProgressBar
|
||||
import URI.ByteString
|
||||
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.ByteString.Lazy as L
|
||||
import qualified Data.Map.Strict as M
|
||||
import qualified Data.Text as T
|
||||
import qualified OpenSSL.Session as SSL
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
----------------------------
|
||||
--[ Low-level (non-curl) ]--
|
||||
----------------------------
|
||||
|
||||
|
||||
-- | Load the result of this download into memory at once.
|
||||
downloadBS' :: (MonadThrow m, MonadIO m)
|
||||
=> URI
|
||||
-> Excepts
|
||||
'[HTTPStatusError]
|
||||
m
|
||||
(L.ByteString)
|
||||
downloadBS' uri' = do
|
||||
bref <- liftIO $ newIORef (mempty :: Builder)
|
||||
let stepper bs = modifyIORef bref (<> byteString bs)
|
||||
downloadInternal False
|
||||
(T.unpack . decUTF8Safe . serializeURIRef' $ uri')
|
||||
stepper
|
||||
liftIO (readIORef bref <&> toLazyByteString)
|
||||
|
||||
|
||||
downloadToFile :: (MonadMask m, MonadIO m)
|
||||
=> URI
|
||||
-> Path Abs -- ^ destination file to create and write to
|
||||
-> Excepts '[DownloadFailed] m ()
|
||||
downloadToFile uri' destFile = do
|
||||
fd <- liftIO $ createRegularFileFd newFilePerms destFile
|
||||
let stepper = fdWrite fd
|
||||
flip finally (liftIO $ closeFd fd)
|
||||
$ reThrowAll DownloadFailed
|
||||
$ downloadInternal True
|
||||
(T.unpack . decUTF8Safe . serializeURIRef' $ uri')
|
||||
stepper
|
||||
|
||||
|
||||
downloadInternal :: (MonadThrow m, MonadIO m)
|
||||
=> Bool -- ^ whether to show a progress bar
|
||||
-> String
|
||||
-> (ByteString -> IO a) -- ^ the consuming step function
|
||||
-> Excepts
|
||||
'[HTTPStatusError]
|
||||
m
|
||||
()
|
||||
downloadInternal progressBar uri' consumer = lEM $ liftIO $ withConnection' action
|
||||
where
|
||||
action :: (MonadThrow m, MonadIO m) => Manager -> m (Either HTTPStatusError ())
|
||||
action m = do
|
||||
request <- parseRequest ("GET " <> uri')
|
||||
liftIO $ withResponse
|
||||
request
|
||||
m
|
||||
(\r -> do
|
||||
let scode = statusCode . responseStatus $ r
|
||||
if
|
||||
| scode >= 200 && scode < 300 ->
|
||||
let headers = M.fromList . responseHeaders $ r
|
||||
in fmap Right $ liftIO $ downloadStream (responseBody r) headers
|
||||
| otherwise -> pure $ Left $ HTTPStatusError scode
|
||||
)
|
||||
|
||||
downloadStream :: BodyReader -> M.Map HeaderName ByteString -> IO ()
|
||||
downloadStream br headers = do
|
||||
let size = case M.lookup "Content-Length" headers of
|
||||
Just x' -> case decimal $ decUTF8Safe x' of
|
||||
Left _ -> 0
|
||||
Right (r', _) -> r'
|
||||
Nothing -> 0
|
||||
|
||||
mpb <- if progressBar
|
||||
then Just <$> (liftIO $ newProgressBar defStyle 10 (Progress 0 size ()))
|
||||
else pure Nothing
|
||||
|
||||
loop mpb
|
||||
|
||||
where
|
||||
loop mpb = do
|
||||
bs <- brRead br
|
||||
if BS.length bs == 0 then pure () else do
|
||||
void $ consumer bs
|
||||
forM_ mpb $ \pb -> incProgress pb (BS.length bs)
|
||||
loop mpb
|
||||
|
||||
|
||||
getHead :: (MonadCatch m, MonadIO m)
|
||||
=> URI
|
||||
-> Excepts
|
||||
'[HTTPStatusError, UnsupportedScheme]
|
||||
m
|
||||
(M.Map (CI ByteString) ByteString)
|
||||
getHead uri' | scheme == "https" || scheme == "http" = head'
|
||||
| otherwise = throwE UnsupportedScheme
|
||||
|
||||
where
|
||||
scheme = view (uriSchemeL' % schemeBSL') uri'
|
||||
head' =
|
||||
liftE $ headInternal (T.unpack . decUTF8Safe . serializeURIRef' $ uri')
|
||||
|
||||
|
||||
headInternal :: (MonadThrow m, MonadIO m)
|
||||
=> String
|
||||
-> Excepts
|
||||
'[HTTPStatusError]
|
||||
m
|
||||
(M.Map (CI ByteString) ByteString)
|
||||
headInternal uri' = lEM $ liftIO $ withConnection' action
|
||||
where
|
||||
action :: (MonadThrow m, MonadIO m)
|
||||
=> Manager
|
||||
-> m (Either HTTPStatusError (M.Map (CI ByteString) ByteString))
|
||||
action m = do
|
||||
request <- parseRequest ("HEAD " <> uri')
|
||||
liftIO $ withResponse
|
||||
request
|
||||
m
|
||||
(\r -> do
|
||||
let scode = statusCode . responseStatus $ r
|
||||
if
|
||||
| scode >= 200 && scode < 300 -> do
|
||||
let headers = responseHeaders r
|
||||
pure $ Right $ M.fromList $ headers
|
||||
| otherwise -> pure $ Left (HTTPStatusError scode)
|
||||
)
|
||||
|
||||
|
||||
withConnection' :: (Manager -> IO a) -> IO a
|
||||
withConnection' action = do
|
||||
mg <- newManager $ opensslManagerSettings baselineContextSSL
|
||||
withOpenSSL (action mg)
|
||||
|
||||
|
||||
baselineContextSSL :: IO SSL.SSLContext
|
||||
baselineContextSSL = withOpenSSL $ do
|
||||
ctx <- SSL.context
|
||||
SSL.contextSetDefaultCiphers ctx
|
||||
#if defined(darwin_HOST_OS)
|
||||
SSL.contextSetVerificationMode ctx SSL.VerifyNone
|
||||
#elif defined(mingw32_HOST_OS)
|
||||
SSL.contextSetVerificationMode ctx SSL.VerifyNone
|
||||
#elif defined(freebsd_HOST_OS)
|
||||
SSL.contextSetCAFile ctx "/usr/local/etc/ssl/cert.pem"
|
||||
SSL.contextSetVerificationMode ctx $ SSL.VerifyPeer True True Nothing
|
||||
#elif defined(openbsd_HOST_OS)
|
||||
SSL.contextSetCAFile ctx "/etc/ssl/cert.pem"
|
||||
SSL.contextSetVerificationMode ctx $ SSL.VerifyPeer True True Nothing
|
||||
#else
|
||||
fedora <- doesDirectoryExist [abs|/etc/pki/tls|]
|
||||
if fedora
|
||||
then do
|
||||
SSL.contextSetCAFile ctx "/etc/pki/tls/certs/ca-bundle.crt"
|
||||
else do
|
||||
SSL.contextSetCADirectory ctx "/etc/ssl/certs"
|
||||
SSL.contextSetVerificationMode ctx $ SSL.VerifyPeer True True Nothing
|
||||
#endif
|
||||
return ctx
|
||||
@@ -1,64 +0,0 @@
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveGeneric #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
|
||||
|
||||
module GHCup.Download.Utils where
|
||||
|
||||
|
||||
import GHCup.Errors
|
||||
import GHCup.Types.Optics
|
||||
import GHCup.Types.JSON ( )
|
||||
import GHCup.Utils.Prelude
|
||||
|
||||
import Control.Applicative
|
||||
import Control.Monad
|
||||
import Data.ByteString ( ByteString )
|
||||
import Data.Maybe
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Optics
|
||||
import Prelude hiding ( abs
|
||||
, readFile
|
||||
, writeFile
|
||||
)
|
||||
import URI.ByteString
|
||||
|
||||
import qualified Data.Binary.Builder as B
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.ByteString.Lazy as L
|
||||
|
||||
|
||||
-- | Extracts from a URI type: (https?, host, path+query, port)
|
||||
uriToQuadruple :: Monad m
|
||||
=> URI
|
||||
-> Excepts
|
||||
'[UnsupportedScheme]
|
||||
m
|
||||
(Bool, ByteString, ByteString, Maybe Int)
|
||||
uriToQuadruple URI {..} = do
|
||||
let scheme = view schemeBSL' uriScheme
|
||||
|
||||
host <-
|
||||
preview (_Just % authorityHostL' % hostBSL') uriAuthority
|
||||
?? UnsupportedScheme
|
||||
|
||||
https <- if
|
||||
| scheme == "https" -> pure True
|
||||
| scheme == "http" -> pure False
|
||||
| otherwise -> throwE UnsupportedScheme
|
||||
|
||||
let queryBS =
|
||||
BS.intercalate "&"
|
||||
. fmap (\(x, y) -> encodeQuery x <> "=" <> encodeQuery y)
|
||||
$ (queryPairs uriQuery)
|
||||
port =
|
||||
preview (_Just % authorityPortL' % _Just % portNumberL') uriAuthority
|
||||
fullpath = if BS.null queryBS then uriPath else uriPath <> "?" <> queryBS
|
||||
pure (https, host, fullpath, port)
|
||||
where encodeQuery = L.toStrict . B.toLazyByteString . urlEncodeQuery
|
||||
|
||||
@@ -45,7 +45,7 @@ import Data.Versions
|
||||
import Data.Word8
|
||||
import GHC.IO.Exception
|
||||
import HPath
|
||||
import HPath.IO
|
||||
import HPath.IO hiding ( hideError )
|
||||
import Haskus.Utils.Variant.Excepts
|
||||
import Optics
|
||||
import Prelude hiding ( abs
|
||||
|
||||
@@ -14,17 +14,20 @@ import Control.Exception ( evaluate )
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Trans.State.Strict
|
||||
import Data.ByteString ( ByteString )
|
||||
import Data.Foldable
|
||||
import Data.Functor
|
||||
import Data.IORef
|
||||
import Data.Maybe
|
||||
import Data.Sequence ( Seq, (|>) )
|
||||
import Data.Text ( Text )
|
||||
import Data.Void
|
||||
import Data.Word8
|
||||
import GHC.IO.Exception
|
||||
import HPath
|
||||
import HPath.IO
|
||||
import Optics
|
||||
import HPath.IO hiding ( hideError )
|
||||
import Optics hiding ((<|), (|>))
|
||||
import System.Console.Pretty
|
||||
import System.Console.Regions
|
||||
import System.IO.Error
|
||||
@@ -40,6 +43,7 @@ import Text.Regex.Posix
|
||||
|
||||
|
||||
import qualified Control.Exception as EX
|
||||
import qualified Data.Sequence as Sq
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.Encoding as E
|
||||
import qualified System.Posix.Process.ByteString
|
||||
@@ -53,6 +57,7 @@ import qualified "unix-bytestring" System.Posix.IO.ByteString
|
||||
|
||||
|
||||
|
||||
|
||||
-- | Bool signals whether the regions should be cleaned.
|
||||
data StopThread = StopThread Bool
|
||||
deriving Show
|
||||
@@ -113,115 +118,140 @@ execLogged :: (MonadReader Settings m, MonadIO m, MonadThrow m)
|
||||
-> Maybe [(ByteString, ByteString)] -- ^ optional environment
|
||||
-> m (Either ProcessError ())
|
||||
execLogged exe spath args lfile chdir env = do
|
||||
Settings{..} <- ask
|
||||
ldir <- liftIO ghcupLogsDir
|
||||
logfile <- (ldir </>) <$> parseRel (toFilePath lfile <> ".log")
|
||||
liftIO $ bracket (createFile (toFilePath logfile) newFilePerms) closeFd (action verbose)
|
||||
Settings {..} <- ask
|
||||
ldir <- liftIO ghcupLogsDir
|
||||
logfile <- (ldir </>) <$> parseRel (toFilePath lfile <> ".log")
|
||||
liftIO $ bracket (createFile (toFilePath logfile) newFilePerms)
|
||||
closeFd
|
||||
(action verbose)
|
||||
where
|
||||
action verbose fd = do
|
||||
actionWithPipes $ \(stdoutRead, stdoutWrite) -> do
|
||||
-- start the thread that logs to stdout in a region
|
||||
done <- newEmptyMVar
|
||||
tid <-
|
||||
forkIO
|
||||
-- start the thread that logs to stdout
|
||||
pState <- newEmptyMVar
|
||||
done <- newEmptyMVar
|
||||
void
|
||||
$ forkOS
|
||||
$ EX.handle (\(_ :: StopThread) -> pure ())
|
||||
$ EX.handle (\(_ :: IOException) -> pure ())
|
||||
$ flip finally (putMVar done ())
|
||||
$ (if verbose then tee fd stdoutRead else printToRegion fd stdoutRead 6)
|
||||
$ (if verbose
|
||||
then tee fd stdoutRead
|
||||
else printToRegion fd stdoutRead 6 pState
|
||||
)
|
||||
|
||||
-- fork our subprocess
|
||||
-- fork the subprocess
|
||||
pid <- SPPB.forkProcess $ do
|
||||
void $ dupTo stdoutWrite stdOutput
|
||||
void $ dupTo stdoutWrite stdError
|
||||
closeFd stdoutWrite
|
||||
closeFd stdoutRead
|
||||
closeFd stdoutWrite
|
||||
|
||||
-- execute the action
|
||||
maybe (pure ()) (changeWorkingDirectory . toFilePath) chdir
|
||||
SPPB.executeFile exe spath args env
|
||||
void $ SPPB.executeFile exe spath args env
|
||||
|
||||
closeFd stdoutWrite
|
||||
|
||||
-- wait for the subprocess to finish
|
||||
e <- SPPB.getProcessStatus True True pid >>= \case
|
||||
i@(Just (SPPB.Exited _)) -> pure $ toProcessError exe args i
|
||||
i -> pure $ toProcessError exe args i
|
||||
e <- toProcessError exe args <$!> SPPB.getProcessStatus True True pid
|
||||
putMVar pState (either (const False) (const True) e)
|
||||
|
||||
-- make sure the logging thread stops
|
||||
case e of
|
||||
Left _ -> EX.throwTo tid (StopThread False)
|
||||
Right _ -> EX.throwTo tid (StopThread True)
|
||||
takeMVar done
|
||||
|
||||
closeFd stdoutRead
|
||||
|
||||
pure e
|
||||
|
||||
tee fileFd fdIn = do
|
||||
flip finally (readTilEOF lineAction fdIn) -- make sure the last few lines don't get cut off
|
||||
$ do
|
||||
hideError eofErrorType $ readTilEOF lineAction fdIn
|
||||
forever (threadDelay 5000)
|
||||
tee :: Fd -> Fd -> IO ()
|
||||
tee fileFd fdIn = readTilEOF lineAction fdIn
|
||||
|
||||
where
|
||||
lineAction :: ByteString -> IO ()
|
||||
lineAction bs' = do
|
||||
void $ SPIB.fdWrite fileFd (bs' <> "\n")
|
||||
void $ SPIB.fdWrite stdOutput (bs' <> "\n")
|
||||
|
||||
-- Reads fdIn and logs the output in a continous scrolling area
|
||||
-- of 'size' terminal lines. Also writes to a log file.
|
||||
printToRegion fileFd fdIn size = do
|
||||
ref <- newIORef ([] :: [ByteString])
|
||||
displayConsoleRegions $ do
|
||||
rs <- sequence . replicate size . openConsoleRegion $ Linear
|
||||
flip finally (readTilEOF (lineAction ref rs) fdIn) -- make sure the last few lines don't get cut off
|
||||
printToRegion :: Fd -> Fd -> Int -> MVar Bool -> IO ()
|
||||
printToRegion fileFd fdIn size pState = do
|
||||
void $ displayConsoleRegions $ do
|
||||
rs <-
|
||||
liftIO
|
||||
. fmap Sq.fromList
|
||||
. sequence
|
||||
. replicate size
|
||||
. openConsoleRegion
|
||||
$ Linear
|
||||
flip runStateT mempty
|
||||
$ handle
|
||||
(\(StopThread b) -> do
|
||||
when b (forM_ rs closeConsoleRegion)
|
||||
EX.throw (StopThread b)
|
||||
(\(ex :: SomeException) -> do
|
||||
ps <- liftIO $ takeMVar pState
|
||||
when (ps == True) (forM_ rs (liftIO . closeConsoleRegion))
|
||||
throw ex
|
||||
)
|
||||
$ do
|
||||
hideError eofErrorType $ readTilEOF (lineAction ref rs) fdIn
|
||||
-- wait for explicit stop from the parent to signal what cleanup to run
|
||||
forever (threadDelay 5000)
|
||||
$ readTilEOF (lineAction rs) fdIn
|
||||
|
||||
where
|
||||
-- action to perform line by line
|
||||
-- TODO: do this with vty for efficiency
|
||||
lineAction ref rs bs' = do
|
||||
modifyIORef' ref (swapRegs bs')
|
||||
regs <- readIORef ref
|
||||
void $ SPIB.fdWrite fileFd (bs' <> "\n")
|
||||
forM (zip regs rs) $ \(bs, r) -> do
|
||||
setConsoleRegion r $ do
|
||||
w <- consoleWidth
|
||||
return
|
||||
. T.pack
|
||||
. color Blue
|
||||
. T.unpack
|
||||
. decUTF8Safe
|
||||
. trim w
|
||||
. (\b -> "[ " <> toFilePath lfile <> " ] " <> b)
|
||||
$ bs
|
||||
lineAction :: (MonadMask m, MonadIO m)
|
||||
=> Seq ConsoleRegion
|
||||
-> ByteString
|
||||
-> StateT (Seq ByteString) m ()
|
||||
lineAction rs = \bs' -> do
|
||||
void $ liftIO $ SPIB.fdWrite fileFd (bs' <> "\n")
|
||||
modify (swapRegs bs')
|
||||
regs <- get
|
||||
liftIO $ forM_ (Sq.zip regs rs) $ \(bs, r) -> setConsoleRegion r $ do
|
||||
w <- consoleWidth
|
||||
return
|
||||
. T.pack
|
||||
. color Blue
|
||||
. T.unpack
|
||||
. decUTF8Safe
|
||||
. trim w
|
||||
. (\b -> "[ " <> toFilePath lfile <> " ] " <> b)
|
||||
$ bs
|
||||
|
||||
swapRegs bs regs | length regs < size = regs ++ [bs]
|
||||
| otherwise = tail regs ++ [bs]
|
||||
swapRegs :: a -> Seq a -> Seq a
|
||||
swapRegs bs = \regs -> if
|
||||
| Sq.length regs < size -> regs |> bs
|
||||
| otherwise -> Sq.drop 1 regs |> bs
|
||||
|
||||
-- trim output line to terminal width
|
||||
trim w bs | BS.length bs > w && w > 5 = BS.take (w - 4) bs <> "..."
|
||||
| otherwise = bs
|
||||
trim :: Int -> ByteString -> ByteString
|
||||
trim w = \bs -> if
|
||||
| BS.length bs > w && w > 5 -> BS.take (w - 4) bs <> "..."
|
||||
| otherwise -> bs
|
||||
|
||||
-- read an entire line from the file descriptor (removes the newline char)
|
||||
readLine fd' = do
|
||||
bs <- SPIB.fdRead fd' 1
|
||||
if
|
||||
| bs == "\n" -> pure ""
|
||||
| bs == "" -> pure ""
|
||||
| otherwise -> fmap (bs <>) $ readLine fd'
|
||||
readLine :: MonadIO m => Fd -> ByteString -> m (ByteString, ByteString)
|
||||
readLine fd = go
|
||||
where
|
||||
go inBs = do
|
||||
bs <-
|
||||
liftIO
|
||||
$ handleIO (\e -> if isEOFError e then pure "" else ioError e)
|
||||
$ SPIB.fdRead fd 512
|
||||
let nbs = BS.append inBs bs
|
||||
(line, rest) = BS.span (/= _lf) nbs
|
||||
if
|
||||
| BS.length rest /= 0 -> pure (line, BS.tail rest)
|
||||
| BS.length line == 0 -> pure (mempty, mempty)
|
||||
| otherwise -> (\(l, r) -> (line <> l, r)) <$!> go mempty
|
||||
|
||||
readTilEOF action' fd' = do
|
||||
bs <- readLine fd'
|
||||
void $ action' bs
|
||||
readTilEOF action' fd'
|
||||
readTilEOF :: MonadIO m => (ByteString -> m a) -> Fd -> m ()
|
||||
readTilEOF ~action' fd' = go mempty
|
||||
where
|
||||
go bs' = do
|
||||
(bs, rest) <- readLine fd' bs'
|
||||
if
|
||||
| BS.length bs == 0 -> liftIO
|
||||
$ ioError (mkIOError eofErrorType "" Nothing Nothing)
|
||||
| otherwise -> do
|
||||
void $ action' bs
|
||||
go rest
|
||||
|
||||
|
||||
-- | Capture the stdout and stderr of the given action, which
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
{-# OPTIONS_GHC -Wno-orphans #-}
|
||||
|
||||
{-# LANGUAGE DataKinds #-}
|
||||
{-# LANGUAGE DeriveLift #-}
|
||||
{-# LANGUAGE FlexibleContexts #-}
|
||||
{-# LANGUAGE FlexibleInstances #-}
|
||||
{-# LANGUAGE QuasiQuotes #-}
|
||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||
{-# LANGUAGE UndecidableInstances #-}
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
{-# LANGUAGE TypeApplications #-}
|
||||
{-# LANGUAGE TypeFamilies #-}
|
||||
@@ -13,8 +17,10 @@ module GHCup.Utils.Prelude where
|
||||
import Control.Applicative
|
||||
import Control.Exception.Safe
|
||||
import Control.Monad
|
||||
import Control.Monad.Base
|
||||
import Control.Monad.IO.Class
|
||||
import Control.Monad.Trans.Class ( lift )
|
||||
import Control.Monad.Trans.Control
|
||||
import Data.Bifunctor
|
||||
import Data.ByteString ( ByteString )
|
||||
import Data.String
|
||||
@@ -165,6 +171,11 @@ liftIOException errType ex =
|
||||
. lift
|
||||
|
||||
|
||||
-- | Uses safe-exceptions.
|
||||
hideError :: (MonadIO m, MonadCatch m) => IOErrorType -> m () -> m ()
|
||||
hideError err = handleIO (\e -> if err == ioeGetErrorType e then pure () else liftIO . ioError $ e)
|
||||
|
||||
|
||||
hideErrorDef :: [IOErrorType] -> a -> IO a -> IO a
|
||||
hideErrorDef errs def =
|
||||
handleIO (\e -> if ioeGetErrorType e `elem` errs then pure def else ioError e)
|
||||
@@ -259,3 +270,40 @@ decUTF8Safe = E.decodeUtf8With E.lenientDecode
|
||||
|
||||
decUTF8Safe' :: L.ByteString -> Text
|
||||
decUTF8Safe' = TL.toStrict . TLE.decodeUtf8With E.lenientDecode
|
||||
|
||||
|
||||
instance MonadBaseControl b m => MonadBaseControl b (Excepts e m) where
|
||||
type StM (Excepts e m) a = ComposeSt (Excepts e) m a
|
||||
liftBaseWith = defaultLiftBaseWith
|
||||
restoreM = defaultRestoreM
|
||||
{-# INLINABLE liftBaseWith #-}
|
||||
{-# INLINABLE restoreM #-}
|
||||
|
||||
instance MonadTransControl (Excepts e) where
|
||||
type StT (Excepts e) a = VEither e a
|
||||
liftWith f = veitherMToExcepts <$> liftM return $ f $ runE
|
||||
restoreT = veitherMToExcepts
|
||||
{-# INLINABLE liftWith #-}
|
||||
{-# INLINABLE restoreT #-}
|
||||
|
||||
instance MonadBase b m => MonadBase b (Excepts e m) where
|
||||
liftBase = liftBaseDefault
|
||||
{-# INLINABLE liftBase #-}
|
||||
|
||||
instance MonadBaseControl (VEither e) (VEither e) where
|
||||
type StM (VEither e) a = a
|
||||
liftBaseWith f = f id
|
||||
restoreM = return
|
||||
{-# INLINABLE liftBaseWith #-}
|
||||
{-# INLINABLE restoreM #-}
|
||||
|
||||
instance MonadBase (VEither e) (VEither e) where
|
||||
liftBase = id
|
||||
{-# INLINABLE liftBase #-}
|
||||
|
||||
|
||||
veitherMToExcepts :: Monad m => m (VEither es a) -> Excepts es m a
|
||||
veitherMToExcepts ma = do
|
||||
ve <- lift ma
|
||||
veitherToExcepts ve
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ ghcupURL :: URI
|
||||
ghcupURL = [uri|https://www.haskell.org/ghcup/data/ghcup-0.0.2.json|]
|
||||
|
||||
ghcUpVer :: PVP
|
||||
ghcUpVer = [pver|0.1.5|]
|
||||
ghcUpVer = [pver|0.1.6|]
|
||||
|
||||
numericVer :: String
|
||||
numericVer = T.unpack . prettyPVP $ ghcUpVer
|
||||
|
||||
Reference in New Issue
Block a user