This commit is contained in:
Julian Ospald 2020-01-24 23:43:11 +01:00
parent f6efca778a
commit 8e533e2465
No known key found for this signature in database
GPG Key ID: 511B62C09D50CD28
7 changed files with 94 additions and 39 deletions

View File

@ -6,6 +6,7 @@
* mirror support * mirror support
* checksums * checksums
* check for new version on start * check for new version on start
* tarball tags as well as version tags?
* --copy-compiler-tools * --copy-compiler-tools
* installing multiple versions in parallel? * installing multiple versions in parallel?

View File

@ -1,5 +1,7 @@
packages: ./ghcup.cabal packages: ./ghcup.cabal
with-compiler: ghc-8.6.5
optimization: 2 optimization: 2
package streamly package streamly
@ -7,3 +9,8 @@ package streamly
package ghcup package ghcup
ghc-options: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16 ghc-options: -O2 -fspec-constr-recursive=16 -fmax-worker-args=16
source-repository-package
type: git
location: https://github.com/composewell/streamly
tag: b8178cd08f7fc8180e4de83bde4b239cb0cfb31c

View File

@ -40,6 +40,7 @@ common parsec { build-depends: parsec >= 3.1 }
common safe-exceptions { build-depends: safe-exceptions >= 0.1 } common safe-exceptions { build-depends: safe-exceptions >= 0.1 }
common streamly { build-depends: streamly >= 0.7 } common streamly { build-depends: streamly >= 0.7 }
common strict-base { build-depends: strict-base >= 0.4 } common strict-base { build-depends: strict-base >= 0.4 }
common tar-bytestring { build-depends: tar-bytestring >= 0.6.1 }
common template-haskell { build-depends: template-haskell >= 2.7 } common template-haskell { build-depends: template-haskell >= 2.7 }
common text { build-depends: text >= 1.2 } common text { build-depends: text >= 1.2 }
common text-icu { build-depends: text-icu >= 0.7 } common text-icu { build-depends: text-icu >= 0.7 }
@ -88,6 +89,7 @@ library
, safe-exceptions , safe-exceptions
, streamly , streamly
, strict-base , strict-base
, tar-bytestring
, template-haskell , template-haskell
, text , text
, text-icu , text-icu

View File

@ -191,6 +191,7 @@ getLinuxDistro = do
| hasWord name ["exherbo"] -> Exherbo | hasWord name ["exherbo"] -> Exherbo
| hasWord name ["gentoo"] -> Gentoo | hasWord name ["gentoo"] -> Gentoo
| otherwise -> UnknownLinux | otherwise -> UnknownLinux
recreateSymlink undefined undefined Overwrite
pure (distro, parsedVer) pure (distro, parsedVer)
where where
hasWord t matches = foldr hasWord t matches = foldr
@ -208,8 +209,8 @@ getLinuxDistro = do
os_release = [abs|/etc/os-release|] os_release = [abs|/etc/os-release|]
lsb_release :: Path Abs lsb_release :: Path Abs
lsb_release = [abs|/etc/lsb-release|] lsb_release = [abs|/etc/lsb-release|]
lsb_release_cmd :: Path Fn lsb_release_cmd :: Path Rel
lsb_release_cmd = [fn|lsb-release|] lsb_release_cmd = [rel|lsb-release|]
redhat_release :: Path Abs redhat_release :: Path Abs
redhat_release = [abs|/etc/redhat-release|] redhat_release = [abs|/etc/redhat-release|]
debian_version :: Path Abs debian_version :: Path Abs
@ -269,12 +270,12 @@ getLinuxDistro = do
-- 2. otherwise create a random file -- 2. otherwise create a random file
-- --
-- The file must not exist. -- The file must not exist.
download :: Bool -- ^ https? download :: Bool -- ^ https?
-> String -- ^ host (e.g. "www.example.com") -> String -- ^ host (e.g. "www.example.com")
-> String -- ^ path (e.g. "/my/file") -> String -- ^ path (e.g. "/my/file")
-> Maybe Integer -- ^ optional port (e.g. 3000) -> Maybe Integer -- ^ optional port (e.g. 3000)
-> Path Abs -- ^ destination directory to download into -> Path Abs -- ^ destination directory to download into
-> Maybe (Path Fn) -- ^ optionally provided filename -> Maybe (Path Rel) -- ^ optionally provided filename
-> IO (Path Abs) -> IO (Path Abs)
download https host path port dest mfn = do download https host path port dest mfn = do
fromJust <$> downloadInternal https host path port (Right (dest, mfn)) fromJust <$> downloadInternal https host path port (Right (dest, mfn))
@ -283,7 +284,7 @@ download https host path port dest mfn = do
-- throw an exception if the url type or host protocol is not supported. -- throw an exception if the url type or host protocol is not supported.
-- --
-- Only Absolute HTTP/HTTPS is supported. -- Only Absolute HTTP/HTTPS is supported.
download' :: URL -> Path Abs -> Maybe (Path Fn) -> IO (Path Abs) download' :: URL -> Path Abs -> Maybe (Path Rel) -> IO (Path Abs)
download' url dest mfn = case url of download' url dest mfn = case url of
URL { url_type = Absolute (Host { protocol = HTTP https, host = host, port = port }), url_path = path, url_params = [] } URL { url_type = Absolute (Host { protocol = HTTP https, host = host, port = port }), url_path = path, url_params = [] }
-> download https host path port dest mfn -> download https host path port dest mfn
@ -306,7 +307,7 @@ downloadInternal :: Bool
-> String -> String
-> String -> String
-> Maybe Integer -> Maybe Integer
-> Either Fd (Path Abs, Maybe (Path Fn)) -> Either Fd (Path Abs, Maybe (Path Rel))
-> IO (Maybe (Path Abs)) -> IO (Maybe (Path Abs))
downloadInternal https host path port dest = do downloadInternal https host path port dest = do
c <- case https of c <- case https of
@ -345,7 +346,7 @@ downloadInternal https host path port dest = do
where where
-- Manage to find a file we can write the body into. -- Manage to find a file we can write the body into.
getFile :: Path Abs -> Maybe (Path Fn) -> IO (Fd, Path Abs) getFile :: Path Abs -> Maybe (Path Rel) -> IO (Fd, Path Abs)
getFile dest mfn = do getFile dest mfn = do
-- destination dir must exist -- destination dir must exist
hideError AlreadyExists $ createDirRecursive newDirPerms dest hideError AlreadyExists $ createDirRecursive newDirPerms dest
@ -358,7 +359,7 @@ downloadInternal https host path port dest = do
-- ...otherwise try to infer the filename from the URL path -- ...otherwise try to infer the filename from the URL path
case (snd . T.breakOnEnd (fS "/") . T.pack) <$> decString False path of case (snd . T.breakOnEnd (fS "/") . T.pack) <$> decString False path of
Just x -> do Just x -> do
fn' <- parseFn (C.pack $ T.unpack x) fn' <- parseRel (C.pack $ T.unpack x)
let fp = dest </> fn' let fp = dest </> fn'
fmap (, fp) $ createRegularFileFd newFilePerms fp fmap (, fp) $ createRegularFileFd newFilePerms fp
Nothing -> do Nothing -> do

View File

@ -49,24 +49,11 @@ data CapturedProcess = CapturedProcess {
makeLenses ''CapturedProcess makeLenses ''CapturedProcess
-- |Checks whether a file is executable. Follows symlinks.
--
-- Only eACCES, eROFS, eTXTBSY, ePERM are catched (and return False).
--
-- Throws:
--
-- - `NoSuchThing` if the file does not exist
--
-- Note: calls `access`
isExecutable :: Path b -> IO Bool
isExecutable p = fileAccess (toFilePath p) False False True
readFd :: Fd -> IO L.ByteString readFd :: Fd -> IO L.ByteString
readFd fd = do readFd fd = do
handle' <- fdToHandle fd handle' <- fdToHandle fd
let stream = let stream =
(S.unfold (SU.finally hClose FH.readChunks) handle') (S.unfold (SU.finallyIO hClose FH.readChunks) handle')
>>= arrayToByteString >>= arrayToByteString
toLazyByteString <$> S.fold FL.mconcat (fmap byteString stream) toLazyByteString <$> S.fold FL.mconcat (fmap byteString stream)
@ -89,7 +76,7 @@ readFileLines p = do
-- --
-- This shouldn't throw IO exceptions, unless getting the environment variable -- This shouldn't throw IO exceptions, unless getting the environment variable
-- PATH does. -- PATH does.
findExecutable :: RelC r => Path r -> IO (Maybe (Path Abs)) findExecutable :: Path Rel -> IO (Maybe (Path Abs))
findExecutable ex = do findExecutable ex = do
sPaths <- fmap catMaybes . (fmap . fmap) parseAbs $ getSearchPath sPaths <- fmap catMaybes . (fmap . fmap) parseAbs $ getSearchPath
-- We don't want exceptions to mess up our result. If we can't -- We don't want exceptions to mess up our result. If we can't
@ -102,10 +89,10 @@ findExecutable ex = do
-- | Execute the given command and collect the stdout, stderr and the exit code. -- | Execute the given command and collect the stdout, stderr and the exit code.
-- The command is run in a subprocess. -- The command is run in a subprocess.
executeOut :: Path Fn -- ^ command as filename, e.g. 'ls' executeOut :: Path Rel -- ^ command as filename, e.g. 'ls'
-> [ByteString] -- ^ arguments to the command -> [ByteString] -- ^ arguments to the command
-> IO (Maybe CapturedProcess) -> IO (Maybe CapturedProcess)
executeOut path args = withFnPath path executeOut path args = withRelPath path
$ \fp -> captureOutStreams $ SPPB.executeFile fp True args Nothing $ \fp -> captureOutStreams $ SPPB.executeFile fp True args Nothing

View File

@ -6,16 +6,7 @@ import Data.Map.Strict ( Map )
import Network.URL import Network.URL
import qualified GHC.Generics as GHC import qualified GHC.Generics as GHC
import Data.Versions import Data.Versions
import HPath
import System.Posix.Types
data DownloadDestination = DPath {
dDestDir :: Path Abs
, dFileName :: Maybe (Path Fn)
} |
Fd {
dFd :: Fd
}
data Tool = GHC data Tool = GHC
| Cabal | Cabal

66
update-index-state.sh Executable file
View File

@ -0,0 +1,66 @@
#!/usr/bin/env bash
set -eu
status_message() {
printf "\\033[0;32m%s\\033[0m\\n" "$1"
}
error_message() {
printf "\\033[0;31m%s\\033[0m\\n" "$1"
}
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
CACHE_LOCATION="${HOME}/.cabal/packages/hackage.haskell.org/01-index.cache"
if [ ! -f "${CACHE_LOCATION}" ] ; then
error_message "${CACHE_LOCATION} does not exist, did you run 'cabal update'?"
exit 1
fi
if [ ! -f "${SCRIPTPATH}/cabal.project" ] ; then
error_message "Could not find ${SCRIPTPATH}/cabal.project, skipping index state update."
exit 3
fi
cabal v2-update
arch=$(getconf LONG_BIT)
case "${arch}" in
32)
byte_size=4
magic_word="CABA1002"
;;
64)
byte_size=8
magic_word="00000000CABA1002"
;;
*)
error_message "Unknown architecture (long bit): ${arch}"
exit 2
;;
esac
# This is the logic to parse the binary format of 01-index.cache.
# The first word is a magic 'caba1002', the second one is the timestamp in unix epoch.
# Better than copying the cabal-install source code.
if [ "$(xxd -u -p -l${byte_size} -s 0 "${CACHE_LOCATION}")" != "${magic_word}" ] ; then
error_message "Magic word does not match!"
exit 4
fi
cache_timestamp=$(echo "ibase=16;obase=A;$(xxd -u -p -l${byte_size} -s ${byte_size} "${CACHE_LOCATION}")" | bc)
# If we got junk from the binary file, this should fail.
cache_date=$(date --utc --date "@${cache_timestamp}" "+%FT%TZ")
status_message "Updating index state in ${SCRIPTPATH}/cabal.project"
if grep -q "^index-state: .*" "${SCRIPTPATH}/cabal.project" ; then
awk '/index-state:/ {gsub(/.*/, "index-state: '${cache_date}'")}; { print }' "${SCRIPTPATH}/cabal.project" > "${SCRIPTPATH}/cabal.project.tmp"
mv "${SCRIPTPATH}/cabal.project.tmp" "${SCRIPTPATH}/cabal.project"
else
printf "index-state: %s\n" "${cache_date}" >> "${SCRIPTPATH}/cabal.project"
fi