Compare commits

..

8 Commits
CI-x ... v0.1.8

Author SHA1 Message Date
b5440fc7d2 Fix bug in installCabalBin 2020-07-21 23:10:47 +02:00
4b21adadf1 Release 0.1.8 2020-07-21 22:47:21 +02:00
78ae77780b Fix bug in logging thread
It would die on newlines due to empty String blindness.
Also make sure takeMVar does not block.
2020-07-21 22:43:09 +02:00
ccb95bcbee f custom 2020-07-21 22:42:39 +02:00
21ac670bbe Update FreeBSD bindist 2020-07-21 21:08:41 +02:00
8b54dee66c Merge branch 'CI-m' 2020-07-21 20:21:53 +02:00
dad926f3ba Allow to specify custom bindist, fixes #14 2020-07-21 20:19:33 +02:00
a298d949b5 Remove FreeBSD workaround in CI 2020-07-21 19:00:10 +02:00
8 changed files with 157 additions and 79 deletions

View File

@@ -44,12 +44,6 @@ ghcup-gen check -f ghcup-${JSON_VERSION}.json
eghcup --numeric-version eghcup --numeric-version
# TODO: rm once we have tarballs
if [ "${OS}" = "FREEBSD" ] ; then
GHC_VERSION=8.6.3
CABAL_VERSION=2.4.1.0
fi
eghcup install ${GHC_VERSION} eghcup install ${GHC_VERSION}
eghcup set ${GHC_VERSION} eghcup set ${GHC_VERSION}
eghcup install-cabal ${CABAL_VERSION} eghcup install-cabal ${CABAL_VERSION}

View File

@@ -1,5 +1,10 @@
# Revision history for ghcup # Revision history for ghcup
## 0.1.8 -- 2020-07-21
* Fix bug in logging thread dying on newlines
* Allow to install from arbitrary bindists: `ghcup -n install ghc -u '{"dlHash": "", "dlSubdir": "ghc-8.10.1", "dlUri": "https://github.com/commercialhaskell/ghc/releases/download/ghc-8.10.1-release/ghc-8.10.1-x86_64-deb9-linux.tar.xz"}' 8.10.1`
## 0.1.7 -- 2020-07-20 ## 0.1.7 -- 2020-07-20
* Fix a bug in libarchive not unpacking some uncleanly packed bindists * Fix a bug in libarchive not unpacking some uncleanly packed bindists

View File

@@ -38,6 +38,7 @@ import Control.Monad.Fail ( MonadFail )
import Control.Monad.Logger import Control.Monad.Logger
import Control.Monad.Reader import Control.Monad.Reader
import Control.Monad.Trans.Resource import Control.Monad.Trans.Resource
import Data.Aeson ( eitherDecode )
import Data.Bifunctor import Data.Bifunctor
import Data.Char import Data.Char
import Data.Either import Data.Either
@@ -68,6 +69,7 @@ import URI.ByteString
import qualified Data.ByteString as B import qualified Data.ByteString as B
import qualified Data.ByteString.UTF8 as UTF8 import qualified Data.ByteString.UTF8 as UTF8
import qualified Data.ByteString.Lazy.UTF8 as BLU
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
@@ -119,6 +121,7 @@ data InstallCommand = InstallGHC InstallOptions
data InstallOptions = InstallOptions data InstallOptions = InstallOptions
{ instVer :: Maybe ToolVersion { instVer :: Maybe ToolVersion
, instPlatform :: Maybe PlatformRequest , instPlatform :: Maybe PlatformRequest
, instBindist :: Maybe DownloadInfo
} }
data SetCommand = SetGHC SetOptions data SetCommand = SetGHC SetOptions
@@ -405,7 +408,7 @@ installParser =
installOpts :: Parser InstallOptions installOpts :: Parser InstallOptions
installOpts = installOpts =
(flip InstallOptions) (\p u v -> InstallOptions v p u)
<$> (optional <$> (optional
(option (option
(eitherReader platformParser) (eitherReader platformParser)
@@ -417,6 +420,17 @@ installOpts =
) )
) )
) )
<*> (optional
(option
(eitherReader bindistParser)
( short 'u'
<> long "url"
<> metavar "BINDIST_URL"
<> help
"Provide DownloadInfo as json string, e.g.: '{ \"dlHash\": \"<sha256 hash>\", \"dlSubdir\": \"ghc-<ver>\", \"dlUri\": \"<uri>\" }'"
)
)
)
<*> optional toolVersionArgument <*> optional toolVersionArgument
@@ -800,6 +814,8 @@ platformParser s' = case MP.parse (platformP <* MP.eof) "" (T.pack s') of
pure v pure v
bindistParser :: String -> Either String DownloadInfo
bindistParser = eitherDecode . BLU.fromString
toSettings :: Options -> Settings toSettings :: Options -> Settings
@@ -1047,7 +1063,9 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
let installGHC InstallOptions{..} = let installGHC InstallOptions{..} =
(runInstTool $ do (runInstTool $ do
v <- liftE $ fromVersion dls instVer GHC v <- liftE $ fromVersion dls instVer GHC
liftE $ installGHCBin dls (_tvVersion v) (fromMaybe pfreq instPlatform) -- FIXME: ugly sharing of tool version case instBindist of
Nothing -> liftE $ installGHCBin dls (_tvVersion v) (fromMaybe pfreq instPlatform)
Just uri -> liftE $ installGHCBindist uri (_tvVersion v) (fromMaybe pfreq instPlatform)
) )
>>= \case >>= \case
VRight _ -> do VRight _ -> do
@@ -1081,7 +1099,9 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
let installCabal InstallOptions{..} = let installCabal InstallOptions{..} =
(runInstTool $ do (runInstTool $ do
v <- liftE $ fromVersion dls instVer Cabal v <- liftE $ fromVersion dls instVer Cabal
liftE $ installCabalBin dls (_tvVersion v) (fromMaybe pfreq instPlatform) -- FIXME: ugly sharing of tool version case instBindist of
Nothing -> liftE $ installCabalBin dls (_tvVersion v) (fromMaybe pfreq instPlatform)
Just uri -> liftE $ installCabalBindist uri (_tvVersion v) (fromMaybe pfreq instPlatform)
) )
>>= \case >>= \case
VRight _ -> do VRight _ -> do

View File

@@ -1,6 +1,6 @@
cabal-version: 3.0 cabal-version: 3.0
name: ghcup name: ghcup
version: 0.1.7 version: 0.1.8
synopsis: ghc toolchain installer as an exe/library synopsis: ghc toolchain installer as an exe/library
description: description:
A rewrite of the shell script ghcup, for providing A rewrite of the shell script ghcup, for providing
@@ -341,6 +341,7 @@ executable ghcup
import: import:
config config
, base , base
, aeson
, bytestring , bytestring
, containers , containers
, haskus-utils-variant , haskus-utils-variant

View File

@@ -77,7 +77,7 @@ import qualified Data.Text.Encoding as E
installGHCBin :: ( MonadFail m installGHCBindist :: ( MonadFail m
, MonadMask m , MonadMask m
, MonadCatch m , MonadCatch m
, MonadReader Settings m , MonadReader Settings m
@@ -85,7 +85,7 @@ installGHCBin :: ( MonadFail m
, MonadResource m , MonadResource m
, MonadIO m , MonadIO m
) )
=> GHCupDownloads => DownloadInfo
-> Version -> Version
-> PlatformRequest -> PlatformRequest
-> Excepts -> Excepts
@@ -102,14 +102,13 @@ installGHCBin :: ( MonadFail m
] ]
m m
() ()
installGHCBin bDls ver pfreq@(PlatformRequest {..}) = do installGHCBindist dlinfo ver (PlatformRequest {..}) = do
let tver = (mkTVer ver) let tver = (mkTVer ver)
lift $ $(logDebug) [i|Requested to install GHC with #{ver}|] lift $ $(logDebug) [i|Requested to install GHC with #{ver}|]
whenM (liftIO $ ghcInstalled tver) whenM (liftIO $ ghcInstalled tver)
$ (throwE $ AlreadyInstalled GHC ver) $ (throwE $ AlreadyInstalled GHC ver)
-- download (or use cached version) -- download (or use cached version)
dlinfo <- lE $ getDownloadInfo GHC ver pfreq bDls
dl <- liftE $ downloadCached dlinfo Nothing dl <- liftE $ downloadCached dlinfo Nothing
-- unpack -- unpack
@@ -150,32 +149,62 @@ installGHCBin bDls ver pfreq@(PlatformRequest {..}) = do
| otherwise = [] | otherwise = []
installCabalBin :: ( MonadMask m installGHCBin :: ( MonadFail m
, MonadCatch m , MonadMask m
, MonadReader Settings m , MonadCatch m
, MonadLogger m , MonadReader Settings m
, MonadResource m , MonadLogger m
, MonadIO m , MonadResource m
, MonadFail m , MonadIO m
) )
=> GHCupDownloads => GHCupDownloads
-> Version -> Version
-> PlatformRequest -> PlatformRequest
-> Excepts -> Excepts
'[ AlreadyInstalled '[ AlreadyInstalled
, CopyError , BuildFailed
, DigestError , DigestError
, DownloadFailed , DownloadFailed
, NoDownload , NoDownload
, NotInstalled , NotInstalled
, UnknownArchive , UnknownArchive
#if !defined(TAR) #if !defined(TAR)
, ArchiveResult , ArchiveResult
#endif #endif
] ]
m m
() ()
installCabalBin bDls ver pfreq@(PlatformRequest {..}) = do installGHCBin bDls ver pfreq = do
dlinfo <- lE $ getDownloadInfo GHC ver pfreq bDls
installGHCBindist dlinfo ver pfreq
installCabalBindist :: ( MonadMask m
, MonadCatch m
, MonadReader Settings m
, MonadLogger m
, MonadResource m
, MonadIO m
, MonadFail m
)
=> DownloadInfo
-> Version
-> PlatformRequest
-> Excepts
'[ AlreadyInstalled
, CopyError
, DigestError
, DownloadFailed
, NoDownload
, NotInstalled
, UnknownArchive
#if !defined(TAR)
, ArchiveResult
#endif
]
m
()
installCabalBindist dlinfo ver (PlatformRequest {..}) = do
lift $ $(logDebug) [i|Requested to install cabal version #{ver}|] lift $ $(logDebug) [i|Requested to install cabal version #{ver}|]
bindir <- liftIO ghcupBinDir bindir <- liftIO ghcupBinDir
@@ -190,7 +219,6 @@ installCabalBin bDls ver pfreq@(PlatformRequest {..}) = do
$ (throwE $ AlreadyInstalled Cabal ver) $ (throwE $ AlreadyInstalled Cabal ver)
-- download (or use cached version) -- download (or use cached version)
dlinfo <- lE $ getDownloadInfo Cabal ver pfreq bDls
dl <- liftE $ downloadCached dlinfo Nothing dl <- liftE $ downloadCached dlinfo Nothing
-- unpack -- unpack
@@ -227,6 +255,37 @@ installCabalBin bDls ver pfreq@(PlatformRequest {..}) = do
Overwrite Overwrite
installCabalBin :: ( MonadMask m
, MonadCatch m
, MonadReader Settings m
, MonadLogger m
, MonadResource m
, MonadIO m
, MonadFail m
)
=> GHCupDownloads
-> Version
-> PlatformRequest
-> Excepts
'[ AlreadyInstalled
, CopyError
, DigestError
, DownloadFailed
, NoDownload
, NotInstalled
, UnknownArchive
#if !defined(TAR)
, ArchiveResult
#endif
]
m
()
installCabalBin bDls ver pfreq = do
dlinfo <- lE $ getDownloadInfo Cabal ver pfreq bDls
installCabalBindist dlinfo ver pfreq
--------------------- ---------------------
--[ Set GHC/cabal ]-- --[ Set GHC/cabal ]--

View File

@@ -866,9 +866,9 @@ ghc_8101_32_alpine = DownloadInfo
ghc_8101_64_freebsd :: DownloadInfo ghc_8101_64_freebsd :: DownloadInfo
ghc_8101_64_freebsd = DownloadInfo ghc_8101_64_freebsd = DownloadInfo
[uri|https://downloads.haskell.org/ghc/8.10.1/ghc-8.10.1-x86_64-portbld-freebsd.tar.xz|] [uri|https://files.hasufell.de/ghc/ghc-8.10.1-x86_64-portbld-freebsd.tar.xz|]
(Just [rel|ghc-8.10.1|]) (Just [rel|ghc-8.10.1|])
"52d27dbf9de82005dde9bfc521bff612e381b5228af194259c2306d2b75825c2" "e8646ec9b60fd40aa9505ee055f22f04601290ab7a1342c2cf37c34de9d3f142"

View File

@@ -10,6 +10,7 @@ import GHCup.Utils.Prelude
import GHCup.Types import GHCup.Types
import Control.Concurrent import Control.Concurrent
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
@@ -57,14 +58,6 @@ import qualified "unix-bytestring" System.Posix.IO.ByteString
-- | Bool signals whether the regions should be cleaned.
data StopThread = StopThread Bool
deriving Show
instance Exception StopThread
data ProcessError = NonZeroExit Int ByteString [ByteString] data ProcessError = NonZeroExit Int ByteString [ByteString]
| PTerminated ByteString [ByteString] | PTerminated ByteString [ByteString]
| PStopped ByteString [ByteString] | PStopped ByteString [ByteString]
@@ -131,10 +124,9 @@ execLogged exe spath args lfile chdir env = do
pState <- newEmptyMVar pState <- newEmptyMVar
done <- newEmptyMVar done <- newEmptyMVar
void void
$ forkOS $ forkIO
$ EX.handle (\(_ :: StopThread) -> pure ())
$ EX.handle (\(_ :: IOException) -> pure ()) $ EX.handle (\(_ :: IOException) -> pure ())
$ flip finally (putMVar done ()) $ flip EX.finally (putMVar done ())
$ (if verbose $ (if verbose
then tee fd stdoutRead then tee fd stdoutRead
else printToRegion fd stdoutRead 6 pState else printToRegion fd stdoutRead 6 pState
@@ -157,7 +149,7 @@ execLogged exe spath args lfile chdir env = do
e <- toProcessError exe args <$!> SPPB.getProcessStatus True True pid e <- toProcessError exe args <$!> SPPB.getProcessStatus True True pid
putMVar pState (either (const False) (const True) e) putMVar pState (either (const False) (const True) e)
takeMVar done void $ race (takeMVar done) (threadDelay (1000000 * 3))
closeFd stdoutRead closeFd stdoutRead
pure e pure e
@@ -225,33 +217,41 @@ execLogged exe spath args lfile chdir env = do
| BS.length bs > w && w > 5 -> BS.take (w - 4) bs <> "..." | BS.length bs > w && w > 5 -> BS.take (w - 4) bs <> "..."
| otherwise -> bs | otherwise -> bs
-- read an entire line from the file descriptor (removes the newline char) -- Consecutively read from Fd in 512 chunks until we hit
readLine :: MonadIO m => Fd -> ByteString -> m (ByteString, ByteString) -- newline or EOF.
readLine fd = go readLine :: MonadIO m
=> Fd -- ^ input file descriptor
-> ByteString -- ^ rest buffer (read across newline)
-> m (ByteString, ByteString, Bool) -- ^ (full line, rest, eof)
readLine fd = \inBs -> go inBs
where where
go inBs = do go inBs = do
bs <- -- if buffer is not empty, process it first
liftIO mbs <- if BS.length inBs == 0
$ handleIO (\e -> if isEOFError e then pure "" else ioError e) -- otherwise attempt read
$ SPIB.fdRead fd 512 then liftIO
let nbs = BS.append inBs bs $ handleIO (\e -> if isEOFError e then pure Nothing else ioError e)
(line, rest) = BS.span (/= _lf) nbs $ fmap Just
if $ SPIB.fdRead fd 512
| BS.length rest /= 0 -> pure (line, BS.tail rest) else pure $ Just inBs
| BS.length line == 0 -> pure (mempty, mempty) case mbs of
| otherwise -> (\(l, r) -> (line <> l, r)) <$!> go mempty Nothing -> pure ("", "", True)
Just bs -> do
-- split on newline
let (line, rest) = BS.span (/= _lf) bs
if
| BS.length rest /= 0 -> pure (line, BS.tail rest, False)
-- if rest is empty, then there was no newline, process further
| otherwise -> (\(l, r, b) -> (line <> l, r, b)) <$!> go mempty
readTilEOF :: MonadIO m => (ByteString -> m a) -> Fd -> m () readTilEOF :: MonadIO m => (ByteString -> m a) -> Fd -> m ()
readTilEOF ~action' fd' = go mempty readTilEOF ~action' fd' = go mempty
where where
go bs' = do go bs' = do
(bs, rest) <- readLine fd' bs' (bs, rest, eof) <- readLine fd' bs'
if if eof
| BS.length bs == 0 -> liftIO then liftIO $ ioError (mkIOError eofErrorType "" Nothing Nothing)
$ ioError (mkIOError eofErrorType "" Nothing Nothing) else (void $ action' bs) >> go rest
| otherwise -> do
void $ action' bs
go rest
-- | Capture the stdout and stderr of the given action, which -- | Capture the stdout and stderr of the given action, which
@@ -288,13 +288,12 @@ captureOutStreams action = do
done <- newEmptyMVar done <- newEmptyMVar
_ <- _ <-
forkIO forkIO
$ EX.handle (\(_ :: StopThread) -> pure ())
$ EX.handle (\(_ :: IOException) -> pure ()) $ EX.handle (\(_ :: IOException) -> pure ())
$ flip finally (putMVar done ()) $ flip EX.finally (putMVar done ())
$ writeStds parentStdoutRead parentStderrRead refOut refErr $ writeStds parentStdoutRead parentStderrRead refOut refErr
status <- SPPB.getProcessStatus True True pid status <- SPPB.getProcessStatus True True pid
takeMVar done void $ race (takeMVar done) (threadDelay (1000000 * 3))
case status of case status of
-- readFd will take care of closing the fd -- readFd will take care of closing the fd
@@ -314,13 +313,13 @@ captureOutStreams action = do
void void
$ forkIO $ forkIO
$ hideError eofErrorType $ hideError eofErrorType
$ flip finally (putMVar doneOut ()) $ flip EX.finally (putMVar doneOut ())
$ readTilEOF (\x -> modifyIORef' rout (<> x)) pout $ readTilEOF (\x -> modifyIORef' rout (<> x)) pout
doneErr <- newEmptyMVar doneErr <- newEmptyMVar
void void
$ forkIO $ forkIO
$ hideError eofErrorType $ hideError eofErrorType
$ flip finally (putMVar doneErr ()) $ flip EX.finally (putMVar doneErr ())
$ readTilEOF (\x -> modifyIORef' rerr (<> x)) perr $ readTilEOF (\x -> modifyIORef' rerr (<> x)) perr
takeMVar doneOut takeMVar doneOut
takeMVar doneErr takeMVar doneErr

View File

@@ -16,7 +16,7 @@ ghcupURL :: URI
ghcupURL = [uri|https://www.haskell.org/ghcup/data/ghcup-0.0.2.json|] ghcupURL = [uri|https://www.haskell.org/ghcup/data/ghcup-0.0.2.json|]
ghcUpVer :: PVP ghcUpVer :: PVP
ghcUpVer = [pver|0.1.7|] ghcUpVer = [pver|0.1.8|]
numericVer :: String numericVer :: String
numericVer = T.unpack . prettyPVP $ ghcUpVer numericVer = T.unpack . prettyPVP $ ghcUpVer