Compare commits

..

1 Commits

Author SHA1 Message Date
14168a41fe Lala 2020-08-27 23:39:47 +02:00
29 changed files with 683 additions and 12314 deletions

View File

@@ -17,7 +17,7 @@ variables:
BIT: "64" BIT: "64"
.alpine:64bit: .alpine:64bit:
image: "alpine:3.12" image: "alpine:edge"
tags: tags:
- x86_64-linux - x86_64-linux
variables: variables:
@@ -25,7 +25,7 @@ variables:
BIT: "64" BIT: "64"
.alpine:32bit: .alpine:32bit:
image: "i386/alpine:3.12" image: "i386/alpine:edge"
tags: tags:
- x86_64-linux - x86_64-linux
variables: variables:

View File

@@ -20,28 +20,22 @@ git describe --always
ecabal update ecabal update
ecabal install -w ghc-${GHC_VERSION} --installdir="$CI_PROJECT_DIR"/.local/bin hspec-discover
if [ "${OS}" = "DARWIN" ] ; then if [ "${OS}" = "DARWIN" ] ; then
ecabal build -w ghc-${GHC_VERSION} -ftui ecabal build -w ghc-${GHC_VERSION} -ftui
ecabal test -w ghc-${GHC_VERSION} -ftui ghcup-test
elif [ "${OS}" = "LINUX" ] ; then elif [ "${OS}" = "LINUX" ] ; then
if [ "${BIT}" = "32" ] ; then if [ "${BIT}" = "32" ] ; then
ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui -ftar ecabal build -w ghc-${GHC_VERSION} -finternal-downloader -ftui -ftar
ecabal test -w ghc-${GHC_VERSION} -finternal-downloader -ftui -ftar ghcup-test
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
fi fi
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
fi fi
ecabal haddock -w ghc-${GHC_VERSION} -ftar ecabal haddock -w ghc-${GHC_VERSION} -ftar
cp "$(ecabal new-exec -w ghc-${GHC_VERSION} --verbose=0 --offline sh -- -c 'command -v ghcup')" . cp "$(ecabal new-exec -w ghc-${GHC_VERSION} --enable-tests --verbose=0 --offline sh -- -c 'command -v ghcup')" .
cp "$(ecabal new-exec -w ghc-${GHC_VERSION} --verbose=0 --offline sh -- -c 'command -v ghcup-gen')" . cp "$(ecabal new-exec -w ghc-${GHC_VERSION} --enable-tests --verbose=0 --offline sh -- -c 'command -v ghcup-gen')" .
cp ./ghcup "$CI_PROJECT_DIR"/.local/bin/ghcup cp ./ghcup "$CI_PROJECT_DIR"/.local/bin/ghcup
cp ./ghcup-gen "$CI_PROJECT_DIR"/.local/bin/ghcup-gen cp ./ghcup-gen "$CI_PROJECT_DIR"/.local/bin/ghcup-gen
@@ -93,18 +87,6 @@ eghcup set ${GHC_VERSION}
eghcup rm 8.4.4 eghcup rm 8.4.4
[ "$(ghc --numeric-version)" = "${ghc_ver}" ] [ "$(ghc --numeric-version)" = "${ghc_ver}" ]
# install hls
if [ "${OS}" = "DARWIN" ] ; then
eghcup install hls
haskell-language-server-wrapper --version
elif [ "${OS}" = "LINUX" ] ; then
if [ "${BIT}" = "64" ] ; then
eghcup install hls
haskell-language-server-wrapper --version
fi
fi
eghcup rm $(ghc --numeric-version) eghcup rm $(ghc --numeric-version)
eghcup upgrade eghcup upgrade

View File

@@ -1,16 +1,5 @@
# Revision history for ghcup # Revision history for ghcup
## 0.1.11 -- ????-??-??
* Add support for installing haskell-language-server, wrt #65
* When compiling GHC from source create a bindist first, store that bindist in `~/.ghcup/cache` and install it, wrt #51
* Allow to compile over existing version (`ghcup compile ghc -v 8.6.5 -b 8.6.5`) and replace it wrt #59
* simplify installing from custom bindist wrt #60
- `ghcup install ghc -u <url> <version>`
* fix bug when cabal isn't marked executable in bindist
* fix bug when `~/.ghcup` is a valid symlink wrt #49
* Drop support for compiling cabal from source (the old bootstrap script is discontinued)
## 0.1.10 -- 2020-08-14 ## 0.1.10 -- 2020-08-14
* Show stray Cabals (useful for pre-releases or compiled ones) * Show stray Cabals (useful for pre-releases or compiled ones)

View File

@@ -9,15 +9,11 @@ Similar in scope to [rustup](https://github.com/rust-lang-nursery/rustup.rs), [p
## Table of Contents ## Table of Contents
* [Installation](#installation) * [Installation](#installation)
* [Simple bootstrap](#simple-bootstrap)
* [Manual install](#manual-install)
* [Vim integration](#vim-integration)
* [Usage](#usage) * [Usage](#usage)
* [Manpages](#manpages) * [Manpages](#manpages)
* [Shell-completion](#shell-completion) * [Shell-completion](#shell-completion)
* [Cross support](#cross-support) * [Cross support](#cross-support)
* [XDG support](#xdg-support) * [XDG support](#xdg-support)
* [Installing custom bindists](#installing-custom-bindists)
* [Design goals](#design-goals) * [Design goals](#design-goals)
* [How](#how) * [How](#how)
* [Known users](#known-users) * [Known users](#known-users)
@@ -41,10 +37,6 @@ Then adjust your `PATH` in `~/.bashrc` (or similar, depending on your shell) lik
export PATH="$HOME/.cabal/bin:$HOME/.ghcup/bin:$PATH" export PATH="$HOME/.cabal/bin:$HOME/.ghcup/bin:$PATH"
``` ```
### Vim integration
See [ghcup.vim](https://github.com/hasufell/ghcup.vim).
## Usage ## Usage
See `ghcup --help`. See `ghcup --help`.
@@ -115,22 +107,6 @@ Then you can control the locations via XDG environment variables as such:
* `XDG_CACHE_HOME`: logs and download files will be stored in `ghcup` subdir * `XDG_CACHE_HOME`: logs and download files will be stored in `ghcup` subdir
* `XDG_BIN_HOME`: binaries end up here (default: `~/.local/bin`) * `XDG_BIN_HOME`: binaries end up here (default: `~/.local/bin`)
### Installing custom bindists
There are a couple of good use cases to install custom bindists:
1. manually built bindists (e.g. with patches)
- example: `ghcup install ghc -u 'file:///home/mearwald/tmp/ghc-eff-patches/ghc-8.10.2-x86_64-deb10-linux.tar.xz' 8.10.2-eff`
2. GHC head CI bindists
- example: `ghcup install ghc -u 'https://gitlab.haskell.org/api/v4/projects/1/jobs/artifacts/master/raw/ghc-x86_64-fedora27-linux.tar.xz?job=validate-x86_64-linux-fedora27' head`
3. DWARF bindists
- example: `ghcup install ghc -u 'https://downloads.haskell.org/~ghc/8.10.2/ghc-8.10.2-x86_64-deb10-linux-dwarf.tar.xz' 8.10.2-dwarf`
Since the version parser is pretty lax, `8.10.2-eff` and `head` are both valid versions
and produce the binaries `ghc-8.10.2-eff` and `ghc-head` respectively.
GHCup always needs to know which version the bindist corresponds to (this is not automatically
detected).
## Design goals ## Design goals
1. simplicity 1. simplicity

View File

@@ -8,6 +8,7 @@ import GHCup
import GHCup.Download import GHCup.Download
import GHCup.Types import GHCup.Types
import GHCup.Utils.Dirs import GHCup.Utils.Dirs
import GHCup.Utils.File
import GHCup.Utils.Logger import GHCup.Utils.Logger
import GHCup.Utils.Version.QQ import GHCup.Utils.Version.QQ
@@ -55,7 +56,7 @@ validate :: (Monad m, MonadLogger m, MonadThrow m, MonadIO m, MonadUnliftIO m)
validate dls = do validate dls = do
ref <- liftIO $ newIORef 0 ref <- liftIO $ newIORef 0
-- verify binary downloads -- -- * verify binary downloads * --
flip runReaderT ref $ do flip runReaderT ref $ do
-- unique tags -- unique tags
forM_ (M.toList dls) $ \(t, _) -> checkUniqueTags t forM_ (M.toList dls) $ \(t, _) -> checkUniqueTags t
@@ -192,7 +193,7 @@ validateTarballs dls = do
where where
downloadAll dli = do downloadAll dli = do
dirs <- liftIO getDirs dirs <- liftIO getDirs
let settings = Settings True False Never Curl False dirs let settings = Settings True False Never Curl False dirs defExecCb
let runLogger = myLoggerT LoggerConfig { lcPrintDebug = True let runLogger = myLoggerT LoggerConfig { lcPrintDebug = True
, colorOutter = B.hPut stderr , colorOutter = B.hPut stderr
, rawOutter = (\_ -> pure ()) , rawOutter = (\_ -> pure ())

View File

@@ -14,8 +14,10 @@ import GHCup.Types
import GHCup.Utils import GHCup.Utils
import GHCup.Utils.File import GHCup.Utils.File
import GHCup.Utils.Logger import GHCup.Utils.Logger
import GHCup.Utils.Prelude
import Brick import Brick
import Brick.BChan
import Brick.Widgets.Border import Brick.Widgets.Border
import Brick.Widgets.Border.Style import Brick.Widgets.Border.Style
import Brick.Widgets.Center import Brick.Widgets.Center
@@ -23,11 +25,14 @@ import Brick.Widgets.List
#if !defined(TAR) #if !defined(TAR)
import Codec.Archive import Codec.Archive
#endif #endif
import Control.Concurrent
import Control.Concurrent.MVar
import Control.Exception.Safe import Control.Exception.Safe
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.Bool import Data.Bool
import Data.ByteString ( ByteString )
import Data.Functor import Data.Functor
import Data.List import Data.List
import Data.Maybe import Data.Maybe
@@ -37,22 +42,40 @@ 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 HPath
import HPath.IO hiding ( hideError )
import Prelude hiding ( abs, appendFile, writeFile )
import System.Exit import System.Exit
import System.IO.Unsafe import System.IO.Unsafe
import System.Posix.Types
import URI.ByteString import URI.ByteString
import qualified Data.Text as T import qualified Data.Text as T
import qualified Graphics.Vty as Vty import qualified Graphics.Vty as Vty
import qualified Data.Vector as V import qualified Data.Vector as V
import qualified "unix-bytestring" System.Posix.IO.ByteString
as SPIB
data SubProcess = SubProcess {
procName :: String
, exited :: Maybe (Either ProcessError ())
, procId :: Maybe ProcessID
, logLine :: Maybe ByteString
}
data AppState = AppState { data AppState = AppState {
lr :: LR lr :: LR
, dls :: GHCupDownloads , dls :: GHCupDownloads
, pfreq :: PlatformRequest , pfreq :: PlatformRequest
, mproc :: Maybe SubProcess
} }
data MyAppEvent = LogLine ByteString
| StartProc String
| GotProcId ProcessID
| EndProc (Either ProcessError ())
type LR = GenericList String Vector ListResult type LR = GenericList String Vector ListResult
@@ -68,29 +91,29 @@ keyHandlers =
ui :: AppState -> Widget String ui :: AppState -> Widget String
ui AppState {..} = ui AppState {..} =
( padBottom Max case mproc of
$ ( withBorderStyle unicode Just _ -> logDialog
$ borderWithLabel (str "GHCup") Nothing ->
$ (center $ (header <=> hBorder <=> renderList renderItem True lr)) ( padBottom Max
) $ ( withBorderStyle unicode
) $ borderWithLabel (str "GHCup")
<=> footer $ (center $ renderList renderItem True lr)
)
)
<=> ( withAttr "help"
. txtWrap
. T.pack
. foldr1 (\x y -> x <> " " <> y)
. (++ ["↑↓:Navigation"])
$ (fmap (\(c, s, _) -> (c : ':' : s)) keyHandlers)
)
where where
footer = logDialog = case mproc of
withAttr "help" Nothing -> emptyWidget
. txtWrap Just (SubProcess name Nothing _ (Just logLine)) -> centerLayer . txtWrap . decUTF8Safe $ logLine
. T.pack Just (SubProcess name Nothing _ (Just logLine)) -> centerLayer . txtWrap $ ""
. foldr1 (\x y -> x <> " " <> y) renderItem b ListResult {..} =
. (++ ["↑↓:Navigation"])
$ (fmap (\(c, s, _) -> (c : ':' : s)) keyHandlers)
header =
(minHSize 2 $ emptyWidget)
<+> (padLeft (Pad 2) $ minHSize 6 $ str "Tool")
<+> (minHSize 15 $ str "Version")
<+> (padLeft (Pad 1) $ minHSize 25 $ str "Tags")
<+> (padLeft (Pad 5) $ str "Notes")
renderItem b listResult@(ListResult {..}) =
let marks = if let marks = if
| lSet -> (withAttr "set" $ str "✔✔") | lSet -> (withAttr "set" $ str "✔✔")
| lInstalled -> (withAttr "installed" $ str "") | lInstalled -> (withAttr "installed" $ str "")
@@ -101,28 +124,20 @@ ui AppState {..} =
dim = if lNoBindist dim = if lNoBindist
then updateAttrMap (const dimAttributes) . withAttr "no-bindist" then updateAttrMap (const dimAttributes) . withAttr "no-bindist"
else id else id
active = if b then withAttr "active" else id
in dim in dim
( marks ( marks
<+> (( padLeft (Pad 2) <+> ( padLeft (Pad 2)
$ active $ minHSize 20
$ minHSize 6 $ ((if b then withAttr "active" else id)
$ (str (fmap toLower . show $ lTool)) (str $ (fmap toLower . show $ lTool) <> " " <> ver)
) )
) )
<+> (minHSize 15 $ active $ (str ver)) <+> (padLeft (Pad 1) $ if null lTag
<+> (padLeft (Pad 1) $ minHSize 25 $ if null lTag
then emptyWidget then emptyWidget
else else
foldr1 (\x y -> x <+> str "," <+> y) foldr1 (\x y -> x <+> str "," <+> y)
$ (fmap printTag $ sort lTag) $ (fmap printTag $ sort lTag)
) )
<+> ( padLeft (Pad 5)
$ let notes = printNotes listResult
in if null notes
then emptyWidget
else foldr1 (\x y -> x <+> str "," <+> y) $ notes
)
) )
printTag Recommended = withAttr "recommended" $ str "recommended" printTag Recommended = withAttr "recommended" $ str "recommended"
@@ -131,19 +146,12 @@ ui AppState {..} =
printTag (Base pvp'') = str ("base-" ++ T.unpack (prettyPVP pvp'')) printTag (Base pvp'') = str ("base-" ++ T.unpack (prettyPVP pvp''))
printTag (UnknownTag t ) = str t printTag (UnknownTag t ) = str t
printNotes ListResult {..} =
(if hlsPowered then [withAttr "hls-powered" $ str "hls-powered"] else mempty
)
++ (if fromSrc then [withAttr "compiled" $ str "compiled"] else mempty)
++ (if lStray then [withAttr "stray" $ str "stray"] else mempty)
minHSize :: Int -> Widget n -> Widget n minHSize :: Int -> Widget n -> Widget n
minHSize s' = hLimit s' . vLimit 1 . (<+> fill ' ') minHSize s' = hLimit s' . vLimit 1 . (<+> fill ' ')
app :: App AppState e String app :: App AppState MyAppEvent String
app = App { appDraw = \st -> [ui st] app = App { appDraw = \st -> [ui st]
, appHandleEvent = eventHandler , appHandleEvent = eventHandler
, appStartEvent = return , appStartEvent = return
@@ -159,11 +167,8 @@ defaultAttributes = attrMap
, ("set" , Vty.defAttr `Vty.withForeColor` Vty.green) , ("set" , Vty.defAttr `Vty.withForeColor` Vty.green)
, ("installed" , Vty.defAttr `Vty.withForeColor` Vty.green) , ("installed" , Vty.defAttr `Vty.withForeColor` Vty.green)
, ("recommended" , Vty.defAttr `Vty.withForeColor` Vty.green) , ("recommended" , Vty.defAttr `Vty.withForeColor` Vty.green)
, ("hls-powered" , Vty.defAttr `Vty.withForeColor` Vty.green)
, ("latest" , Vty.defAttr `Vty.withForeColor` Vty.yellow) , ("latest" , Vty.defAttr `Vty.withForeColor` Vty.yellow)
, ("prerelease" , Vty.defAttr `Vty.withForeColor` Vty.red) , ("prerelease" , Vty.defAttr `Vty.withForeColor` Vty.red)
, ("compiled" , Vty.defAttr `Vty.withForeColor` Vty.blue)
, ("stray" , Vty.defAttr `Vty.withForeColor` Vty.blue)
, ("help" , Vty.defAttr `Vty.withStyle` Vty.italic) , ("help" , Vty.defAttr `Vty.withStyle` Vty.italic)
] ]
@@ -177,19 +182,33 @@ dimAttributes = attrMap
eventHandler :: AppState -> BrickEvent n e -> EventM n (Next AppState) eventHandler :: AppState -> BrickEvent n MyAppEvent -> EventM n (Next AppState)
eventHandler st (VtyEvent (Vty.EvResize _ _)) = continue st eventHandler st (VtyEvent (Vty.EvResize _ _)) = continue st
eventHandler st (VtyEvent (Vty.EvKey (Vty.KChar 'q') _)) = halt st eventHandler st (VtyEvent (Vty.EvKey (Vty.KChar 'q') _)) = halt st
eventHandler st (VtyEvent (Vty.EvKey Vty.KEsc _)) = halt st eventHandler st (VtyEvent (Vty.EvKey Vty.KEsc _)) = halt st
eventHandler AppState {..} (VtyEvent (Vty.EvKey (Vty.KUp) _)) = eventHandler AppState {..} (VtyEvent (Vty.EvKey (Vty.KUp) _)) =
continue (AppState (listMoveUp lr) dls pfreq) continue (AppState (listMoveUp lr) dls pfreq mproc)
eventHandler AppState {..} (VtyEvent (Vty.EvKey (Vty.KDown) _)) = eventHandler AppState {..} (VtyEvent (Vty.EvKey (Vty.KDown) _)) =
continue (AppState (listMoveDown lr) dls pfreq) continue (AppState (listMoveDown lr) dls pfreq mproc)
eventHandler as (VtyEvent (Vty.EvKey (Vty.KChar c) _)) = eventHandler as (VtyEvent (Vty.EvKey (Vty.KChar c) _)) =
case find (\(c', _, _) -> c' == c) keyHandlers of case find (\(c', _, _) -> c' == c) keyHandlers of
Nothing -> continue as Nothing -> continue as
Just (_, _, handler) -> handler as Just (_, _, handler) -> handler as
eventHandler st _ = continue st eventHandler st (AppEvent (StartProc str')) = continue st
{ mproc = Just SubProcess { procName = str'
, exited = Nothing
, procId = Nothing
, logLine = Nothing
}
}
eventHandler st@AppState { mproc = Just sp } (AppEvent (GotProcId pid)) =
continue st { mproc = Just sp { procId = Just pid } }
eventHandler st@AppState { mproc = Just sp } (AppEvent (EndProc exited)) =
continue st { mproc = Just sp { exited = Just exited, procId = Nothing } }
eventHandler st@AppState { mproc = Just sp } (AppEvent (LogLine bs)) =
continue st { mproc = Just sp { logLine = Just bs } }
eventHandler st (AppEvent _) = error "noes" -- TODO
eventHandler st _ = continue st
-- | Suspend the current UI and run an IO action in terminal. If the -- | Suspend the current UI and run an IO action in terminal. If the
@@ -199,19 +218,18 @@ withIOAction :: (AppState -> (Int, ListResult) -> IO (Either String a))
-> EventM n (Next AppState) -> EventM n (Next AppState)
withIOAction action as = case listSelectedElement (lr as) of withIOAction action as = case listSelectedElement (lr as) of
Nothing -> continue as Nothing -> continue as
Just (ix, e) -> suspendAndResume $ do Just (ix, e) -> do
action as (ix, e) >>= \case liftIO $ forkIO $ void $ action as (ix, e)
Left err -> putStrLn $ ("Error: " <> err) continue as
Right _ -> putStrLn "Success" -- apps <- (fmap . fmap)
apps <- (fmap . fmap) -- (\AppState {..} -> AppState { lr = listMoveTo ix lr, .. })
(\AppState {..} -> AppState { lr = listMoveTo ix lr, .. }) -- $ getAppState Nothing (pfreq as)
$ getAppState Nothing (pfreq as) -- case apps of
case apps of -- Right nas -> do
Right nas -> do -- putStrLn "Press enter to continue"
putStrLn "Press enter to continue" -- _ <- getLine
_ <- getLine -- pure nas
pure nas -- Left err -> throwIO $ userError err
Left err -> throwIO $ userError err
install' :: AppState -> (Int, ListResult) -> IO (Either String ()) install' :: AppState -> (Int, ListResult) -> IO (Either String ())
@@ -248,7 +266,6 @@ install' AppState {..} (_, ListResult {..}) = do
GHC -> liftE $ installGHCBin dls lVer pfreq GHC -> liftE $ installGHCBin dls lVer pfreq
Cabal -> liftE $ installCabalBin dls lVer pfreq Cabal -> liftE $ installCabalBin dls lVer pfreq
GHCup -> liftE $ upgradeGHCup dls Nothing False pfreq $> () GHCup -> liftE $ upgradeGHCup dls Nothing False pfreq $> ()
HLS -> liftE $ installHLSBin dls lVer pfreq $> ()
) )
>>= \case >>= \case
VRight _ -> pure $ Right () VRight _ -> pure $ Right ()
@@ -277,7 +294,6 @@ set' _ (_, ListResult {..}) = do
case lTool of case lTool of
GHC -> liftE $ setGHC (GHCTargetVersion lCross lVer) SetGHCOnly $> () GHC -> liftE $ setGHC (GHCTargetVersion lCross lVer) SetGHCOnly $> ()
Cabal -> liftE $ setCabal lVer $> () Cabal -> liftE $ setCabal lVer $> ()
HLS -> liftE $ setHLS lVer $> ()
GHCup -> pure () GHCup -> pure ()
) )
>>= \case >>= \case
@@ -297,7 +313,6 @@ del' _ (_, ListResult {..}) = do
case lTool of case lTool of
GHC -> liftE $ rmGHCVer (GHCTargetVersion lCross lVer) $> () GHC -> liftE $ rmGHCVer (GHCTargetVersion lCross lVer) $> ()
Cabal -> liftE $ rmCabalVer lVer $> () Cabal -> liftE $ rmCabalVer lVer $> ()
HLS -> liftE $ rmHLSVer lVer $> ()
GHCup -> pure () GHCup -> pure ()
) )
>>= \case >>= \case
@@ -330,12 +345,13 @@ settings' :: IORef Settings
settings' = unsafePerformIO $ do settings' = unsafePerformIO $ do
dirs <- getDirs dirs <- getDirs
newIORef Settings { cache = True newIORef Settings { cache = True
, noVerify = False , noVerify = False
, keepDirs = Never , keepDirs = Never
, downloader = Curl , downloader = Curl
, verbose = False , verbose = False
, .. , execCb = (\_ _ _ _ _ -> liftIO $ writeFile [abs|/home/jule/git/ghcup-hs/cb.log|] Nothing "settings'")
} , ..
}
logger' :: IORef LoggerConfig logger' :: IORef LoggerConfig
@@ -349,16 +365,22 @@ logger' = unsafePerformIO
brickMain :: Settings -> Maybe URI -> LoggerConfig -> GHCupDownloads -> PlatformRequest -> IO () brickMain :: Settings -> Maybe URI -> LoggerConfig -> GHCupDownloads -> PlatformRequest -> IO ()
brickMain s muri l av pfreq' = do brickMain _ muri _ av pfreq' = do
writeIORef uri' muri writeIORef uri' muri
writeIORef settings' s s <- readIORef settings'
-- logger interpreter -- logger interpreter
writeIORef logger' l -- writeIORef logger' l
l <- readIORef logger'
let runLogger = myLoggerT l let runLogger = myLoggerT l
eApps <- getAppState (Just av) pfreq' eApps <- getAppState (Just av) pfreq'
case eApps of case eApps of
Right as -> defaultMain app (selectLatest as) $> () Right as -> do
eventChan <- newBChan 1000
let builder = Vty.mkVty Vty.defaultConfig
initialVty <- builder
writeIORef settings' s{ execCb = brickExecCb eventChan }
customMain initialVty builder (Just eventChan) app (selectLatest as) $> ()
Left e -> do Left e -> do
runLogger ($(logError) [i|Error building app state: #{show e}|]) runLogger ($(logError) [i|Error building app state: #{show e}|])
exitWith $ ExitFailure 2 exitWith $ ExitFailure 2
@@ -387,8 +409,25 @@ getAppState mg pfreq' = do
dls <- maybe (fmap _ghcupDownloads $ liftE $ getDownloadsF (maybe GHCupURL OwnSource muri)) pure mg dls <- maybe (fmap _ghcupDownloads $ liftE $ getDownloadsF (maybe GHCupURL OwnSource muri)) pure mg
lV <- lift $ listVersions dls Nothing Nothing pfreq' lV <- lift $ listVersions dls Nothing Nothing pfreq'
pure $ (AppState (list "Tool versions" (V.fromList lV) 1) dls pfreq') pure $ (AppState (list "Tool versions" (V.fromList lV) 1) dls pfreq' Nothing)
case r of case r of
VRight a -> pure $ Right a VRight a -> pure $ Right a
VLeft e -> pure $ Left [i|#{e}|] VLeft e -> pure $ Left [i|#{e}|]
brickExecCb :: BChan MyAppEvent -> ExecCb
brickExecCb chan _ fileFd stdoutRead pState lfile = do
liftIO $ writeFile [abs|/home/jule/git/ghcup-hs/cb.log|] Nothing "brickExecCb"
writeBChan chan (StartProc . T.unpack . decUTF8Safe $ lfile)
readLineTilEOF lineAction stdoutRead
takeMVar pState >>= \case
PExited e@(Left _) -> writeBChan chan (EndProc e)
_ -> error "no"
where
lineAction bs = do
void $ SPIB.fdWrite fileFd (bs <> "\n")
error "blah"
writeBChan chan (LogLine bs)

View File

@@ -39,6 +39,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
@@ -64,15 +65,16 @@ import System.Environment
import System.Exit import System.Exit
import System.IO hiding ( appendFile ) import System.IO hiding ( appendFile )
import Text.Read hiding ( lift ) import Text.Read hiding ( lift )
import Text.Layout.Table
import URI.ByteString 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
import qualified Text.Megaparsec as MP import qualified Text.Megaparsec as MP
import qualified Text.Megaparsec.Char as MPC
@@ -116,17 +118,15 @@ prettyToolVer (ToolTag t) = show t
data InstallCommand = InstallGHC InstallOptions data InstallCommand = InstallGHC InstallOptions
| InstallCabal InstallOptions | InstallCabal InstallOptions
| InstallHLS InstallOptions
data InstallOptions = InstallOptions data InstallOptions = InstallOptions
{ instVer :: Maybe ToolVersion { instVer :: Maybe ToolVersion
, instPlatform :: Maybe PlatformRequest , instPlatform :: Maybe PlatformRequest
, instBindist :: Maybe URI , instBindist :: Maybe DownloadInfo
} }
data SetCommand = SetGHC SetOptions data SetCommand = SetGHC SetOptions
| SetCabal SetOptions | SetCabal SetOptions
| SetHLS SetOptions
data SetOptions = SetOptions data SetOptions = SetOptions
{ sToolVer :: Maybe ToolVersion { sToolVer :: Maybe ToolVersion
@@ -140,7 +140,6 @@ data ListOptions = ListOptions
data RmCommand = RmGHC RmOptions data RmCommand = RmGHC RmOptions
| RmCabal Version | RmCabal Version
| RmHLS Version
data RmOptions = RmOptions data RmOptions = RmOptions
{ ghcVer :: GHCTargetVersion { ghcVer :: GHCTargetVersion
@@ -148,6 +147,7 @@ data RmOptions = RmOptions
data CompileCommand = CompileGHC GHCCompileOptions data CompileCommand = CompileGHC GHCCompileOptions
| CompileCabal CabalCompileOptions
data GHCCompileOptions = GHCCompileOptions data GHCCompileOptions = GHCCompileOptions
@@ -207,8 +207,8 @@ opts =
( long "keep" ( long "keep"
<> metavar "<always|errors|never>" <> metavar "<always|errors|never>"
<> help <> help
"Keep build directories? (default: errors)" "Keep build directories? (default: never)"
<> value Errors <> value Never
<> hidden <> hidden
) )
<*> option <*> option
@@ -396,29 +396,10 @@ installParser =
) )
) )
) )
<> command
"hls"
( InstallHLS
<$> (info
(installOpts <**> helper)
( progDesc "Install haskell-languge-server"
<> footerDoc (Just $ text installHLSFooter)
)
)
)
) )
) )
<|> (Right <$> installOpts) <|> (Right <$> installOpts)
where where
installHLSFooter :: String
installHLSFooter = [s|Discussion:
Installs haskell-language-server binaries and wrapper
into "~/.ghcup/bin"
Examples:
# install recommended GHC
ghcup install hls|]
installGHCFooter :: String installGHCFooter :: String
installGHCFooter = [s|Discussion: installGHCFooter = [s|Discussion:
Installs the specified GHC version (or a recommended default one) into Installs the specified GHC version (or a recommended default one) into
@@ -426,22 +407,13 @@ Examples:
and symlinks the ghc binaries to "~/.ghcup/bin/<binary>-<ghcver>". and symlinks the ghc binaries to "~/.ghcup/bin/<binary>-<ghcver>".
Examples: Examples:
# install recommended GHC # install GHC head
ghcup install ghc ghcup -n install ghc -u '{"dlHash": "", "dlSubdir": { "RegexDir": "ghc-.*"}, "dlUri": "https://gitlab.haskell.org/api/v4/projects/1/jobs/artifacts/master/raw/ghc-x86_64-fedora27-linux.tar.xz?job=validate-x86_64-linux-fedora27" }' head|]
# install latest GHC
ghcup install ghc latest
# install GHC 8.10.2
ghcup install ghc 8.10.2
# install GHC head fedora bindist
ghcup install ghc -u https://gitlab.haskell.org/api/v4/projects/1/jobs/artifacts/master/raw/ghc-x86_64-fedora27-linux.tar.xz?job=validate-x86_64-linux-fedora27 head|]
installOpts :: Parser InstallOptions installOpts :: Parser InstallOptions
installOpts = installOpts =
(\p (u, v) -> InstallOptions v p u) (\p u v -> InstallOptions v p u)
<$> (optional <$> (optional
(option (option
(eitherReader platformParser) (eitherReader platformParser)
@@ -453,19 +425,18 @@ installOpts =
) )
) )
) )
<*> ( ( (,) <*> (optional
<$> (optional (option
(option (eitherReader bindistParser)
(eitherReader bindistParser) ( short 'u'
(short 'u' <> long "url" <> metavar "BINDIST_URL" <> help <> long "url"
"Install the specified version from this bindist" <> metavar "BINDIST_URL"
) <> help
) "Provide DownloadInfo as json string, e.g.: '{ \"dlHash\": \"<sha256 hash>\", \"dlSubdir\": { \"RegexDir\": \"ghc-.*\"}, \"dlUri\": \"<uri>\" }'"
)
<*> (Just <$> toolVersionArgument)
) )
<|> ((,) <$> pure Nothing <*> optional toolVersionArgument) )
) )
<*> optional toolVersionArgument
setParser :: Parser (Either SetCommand SetOptions) setParser :: Parser (Either SetCommand SetOptions)
@@ -491,16 +462,6 @@ setParser =
) )
) )
) )
<> command
"hls"
( SetHLS
<$> (info
(setOpts <**> helper)
( progDesc "Set haskell-language-server version"
<> footerDoc (Just $ text setHLSFooter)
)
)
)
) )
) )
<|> (Right <$> setOpts) <|> (Right <$> setOpts)
@@ -515,10 +476,6 @@ setParser =
setCabalFooter = [s|Discussion: setCabalFooter = [s|Discussion:
Sets the the current Cabal version.|] Sets the the current Cabal version.|]
setHLSFooter :: String
setHLSFooter = [s|Discussion:
Sets the the current haskell-language-server version.|]
setOpts :: Parser SetOptions setOpts :: Parser SetOptions
setOpts = SetOptions <$> optional toolVersionArgument setOpts = SetOptions <$> optional toolVersionArgument
@@ -561,13 +518,6 @@ rmParser =
(progDesc "Remove Cabal version") (progDesc "Remove Cabal version")
) )
) )
<> command
"hls"
( RmHLS
<$> (info (versionParser' <**> helper)
(progDesc "Remove haskell-language-server version")
)
)
) )
) )
<|> (Right <$> rmOpts) <|> (Right <$> rmOpts)
@@ -611,6 +561,16 @@ compileP = subparser
) )
) )
) )
<> command
"cabal"
( CompileCabal
<$> (info
(cabalCompileOpts <**> helper)
( progDesc "Compile Cabal from source"
<> footerDoc (Just $ text compileCabalFooter)
)
)
)
) )
where where
compileFooter = [s|Discussion: compileFooter = [s|Discussion:
@@ -631,6 +591,13 @@ Examples:
ghcup compile ghc -j 4 -v 8.4.2 -b /usr/bin/ghc-8.2.2 ghcup compile ghc -j 4 -v 8.4.2 -b /usr/bin/ghc-8.2.2
# build cross compiler # build cross compiler
ghcup compile ghc -j 4 -v 8.4.2 -b 8.2.2 -x armv7-unknown-linux-gnueabihf --config $(pwd)/build.mk -- --enable-unregisterised|] ghcup compile ghc -j 4 -v 8.4.2 -b 8.2.2 -x armv7-unknown-linux-gnueabihf --config $(pwd)/build.mk -- --enable-unregisterised|]
compileCabalFooter = [i|Discussion:
Compiles and installs the specified Cabal version
into "~/.ghcup/bin".
Examples:
ghcup compile cabal -j 4 -v 3.2.0.0 -b 8.6.5
ghcup compile cabal -j 4 -v 3.2.0.0 -b /usr/bin/ghc-8.6.5|]
ghcCompileOpts :: Parser GHCCompileOptions ghcCompileOpts :: Parser GHCCompileOptions
@@ -852,8 +819,8 @@ platformParser s' = case MP.parse (platformP <* MP.eof) "" (T.pack s') of
pure v pure v
bindistParser :: String -> Either String URI bindistParser :: String -> Either String DownloadInfo
bindistParser = first show . parseURI strictURIParserOptions . UTF8.fromString bindistParser = eitherDecode . BLU.fromString
toSettings :: Options -> IO Settings toSettings :: Options -> IO Settings
@@ -864,7 +831,7 @@ toSettings Options {..} = do
downloader = optsDownloader downloader = optsDownloader
verbose = optVerbose verbose = optVerbose
dirs <- getDirs dirs <- getDirs
pure $ Settings { .. } pure $ Settings { execCb = (\_ _ _ _ _ -> liftIO $ HPath.IO.writeFile [HPath.abs|/home/jule/git/ghcup-hs/cb.log|] Nothing "toSettings"), ..}
upgradeOptsP :: Parser UpgradeOpts upgradeOptsP :: Parser UpgradeOpts
@@ -943,7 +910,7 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
settings@Settings{dirs = Dirs{..}, ..} <- toSettings opt settings@Settings{dirs = Dirs{..}, ..} <- toSettings opt
-- create ~/.ghcup dir -- create ~/.ghcup dir
createDirRecursive' baseDir createDirRecursive newDirPerms baseDir
-- logger interpreter -- logger interpreter
logfile <- flip runReaderT settings $ initGHCupFileLogging [rel|ghcup.log|] logfile <- flip runReaderT settings $ initGHCupFileLogging [rel|ghcup.log|]
@@ -959,9 +926,9 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
-- Effect interpreters -- -- Effect interpreters --
------------------------- -------------------------
let runInstTool' settings' = let runInstTool =
runLogger runLogger
. flip runReaderT settings' . flip runReaderT settings
. runResourceT . runResourceT
. runE . runE
@'[ AlreadyInstalled @'[ AlreadyInstalled
@@ -980,8 +947,6 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
, TarDirDoesNotExist , TarDirDoesNotExist
] ]
let runInstTool = runInstTool' settings
let let
runSetGHC = runSetGHC =
runLogger runLogger
@@ -1001,15 +966,6 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
, TagNotFound , TagNotFound
] ]
let
runSetHLS =
runLogger
. flip runReaderT settings
. runE
@'[ NotInstalled
, TagNotFound
]
let runListGHC = runLogger . flip runReaderT settings let runListGHC = runLogger . flip runReaderT settings
let runRm = let runRm =
@@ -1036,7 +992,26 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
, PatchFailed , PatchFailed
, UnknownArchive , UnknownArchive
, TarDirDoesNotExist , TarDirDoesNotExist
#if !defined(TAR)
, ArchiveResult
#endif
]
let runCompileCabal =
runLogger
. flip runReaderT settings
. runResourceT
. runE
@'[ AlreadyInstalled
, BuildFailed
, CopyError
, DigestError
, DownloadFailed
, NoDownload
, NotInstalled , NotInstalled
, PatchFailed
, UnknownArchive
, TarDirDoesNotExist
#if !defined(TAR) #if !defined(TAR)
, ArchiveResult , ArchiveResult
#endif #endif
@@ -1095,16 +1070,11 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
----------------------- -----------------------
let installGHC InstallOptions{..} = let installGHC InstallOptions{..} =
(case instBindist of (runInstTool $ do
Nothing -> runInstTool $ do v <- liftE $ fromVersion dls instVer GHC
v <- liftE $ fromVersion dls instVer GHC case instBindist of
liftE $ installGHCBin dls (_tvVersion v) (fromMaybe pfreq instPlatform) Nothing -> liftE $ installGHCBin dls (_tvVersion v) (fromMaybe pfreq instPlatform)
Just uri -> runInstTool' settings{noVerify = True} $ do Just uri -> liftE $ installGHCBindist uri (_tvVersion v) (fromMaybe pfreq instPlatform)
v <- liftE $ fromVersion dls instVer GHC
liftE $ installGHCBindist
(DownloadInfo uri (Just $ RegexDir "ghc-.*") "")
(_tvVersion v)
(fromMaybe pfreq instPlatform)
) )
>>= \case >>= \case
VRight _ -> do VRight _ -> do
@@ -1112,7 +1082,7 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
pure ExitSuccess pure ExitSuccess
VLeft (V (AlreadyInstalled _ v)) -> do VLeft (V (AlreadyInstalled _ v)) -> do
runLogger $ $(logWarn) runLogger $ $(logWarn)
[i|GHC ver #{prettyVer v} already installed, you may want to run 'ghcup rm ghc #{prettyVer v}' first|] [i|GHC ver #{prettyVer v} already installed|]
pure ExitSuccess pure ExitSuccess
VLeft (V (BuildFailed tmpdir e)) -> do VLeft (V (BuildFailed tmpdir e)) -> do
case keepDirs of case keepDirs of
@@ -1136,16 +1106,11 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
let installCabal InstallOptions{..} = let installCabal InstallOptions{..} =
(case instBindist of (runInstTool $ do
Nothing -> runInstTool $ do v <- liftE $ fromVersion dls instVer Cabal
v <- liftE $ fromVersion dls instVer Cabal case instBindist of
liftE $ installCabalBin dls (_tvVersion v) (fromMaybe pfreq instPlatform) Nothing -> liftE $ installCabalBin dls (_tvVersion v) (fromMaybe pfreq instPlatform)
Just uri -> runInstTool' settings{noVerify = True} $ do Just uri -> liftE $ installCabalBindist uri (_tvVersion v) (fromMaybe pfreq instPlatform)
v <- liftE $ fromVersion dls instVer Cabal
liftE $ installCabalBindist
(DownloadInfo uri Nothing "")
(_tvVersion v)
(fromMaybe pfreq instPlatform)
) )
>>= \case >>= \case
VRight _ -> do VRight _ -> do
@@ -1153,7 +1118,7 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
pure ExitSuccess pure ExitSuccess
VLeft (V (AlreadyInstalled _ v)) -> do VLeft (V (AlreadyInstalled _ v)) -> do
runLogger $ $(logWarn) runLogger $ $(logWarn)
[i|Cabal ver #{prettyVer v} already installed, you may want to run 'ghcup rm cabal #{prettyVer v}' first|] [i|Cabal ver #{prettyVer v} already installed|]
pure ExitSuccess pure ExitSuccess
VLeft (V NoDownload) -> do VLeft (V NoDownload) -> do
@@ -1168,40 +1133,6 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
$(logError) [i|Also check the logs in #{logsDir}|] $(logError) [i|Also check the logs in #{logsDir}|]
pure $ ExitFailure 4 pure $ ExitFailure 4
let installHLS InstallOptions{..} =
(case instBindist of
Nothing -> runInstTool $ do
v <- liftE $ fromVersion dls instVer HLS
liftE $ installHLSBin dls (_tvVersion v) (fromMaybe pfreq instPlatform)
Just uri -> runInstTool' settings{noVerify = True} $ do
v <- liftE $ fromVersion dls instVer HLS
liftE $ installHLSBindist
(DownloadInfo uri Nothing "")
(_tvVersion v)
(fromMaybe pfreq instPlatform)
)
>>= \case
VRight _ -> do
runLogger $ $(logInfo) ("HLS installation successful")
pure ExitSuccess
VLeft (V (AlreadyInstalled _ v)) -> do
runLogger $ $(logWarn)
[i|HLS ver #{prettyVer v} already installed, you may want to run 'ghcup rm hls #{prettyVer v}' first|]
pure ExitSuccess
VLeft (V NoDownload) -> do
runLogger $ do
case instVer of
Just iver -> $(logError) [i|No available HLS version for #{prettyToolVer iver}|]
Nothing -> $(logError) [i|No available recommended HLS version|]
pure $ ExitFailure 4
VLeft e -> do
runLogger $ do
$(logError) [i|#{e}|]
$(logError) [i|Also check the logs in #{logsDir}|]
pure $ ExitFailure 4
let setGHC' SetOptions{..} = let setGHC' SetOptions{..} =
(runSetGHC $ do (runSetGHC $ do
v <- liftE $ fromVersion dls sToolVer GHC v <- liftE $ fromVersion dls sToolVer GHC
@@ -1228,17 +1159,6 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
runLogger ($(logError) [i|#{e}|]) runLogger ($(logError) [i|#{e}|])
pure $ ExitFailure 14 pure $ ExitFailure 14
let setHLS' SetOptions{..} =
(runSetHLS $ do
v <- liftE $ fromVersion dls sToolVer HLS
liftE $ setHLS (_tvVersion v)
)
>>= \case
VRight _ -> pure ExitSuccess
VLeft e -> do
runLogger ($(logError) [i|#{e}|])
pure $ ExitFailure 14
let rmGHC' RmOptions{..} = let rmGHC' RmOptions{..} =
(runRm $ do (runRm $ do
liftE $ rmGHCVer ghcVer liftE $ rmGHCVer ghcVer
@@ -1259,15 +1179,6 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
runLogger ($(logError) [i|#{e}|]) runLogger ($(logError) [i|#{e}|])
pure $ ExitFailure 15 pure $ ExitFailure 15
let rmHLS' tv =
(runRm $ do
liftE $ rmHLSVer tv
)
>>= \case
VRight _ -> pure ExitSuccess
VLeft e -> do
runLogger ($(logError) [i|#{e}|])
pure $ ExitFailure 15
res <- case optCommand of res <- case optCommand of
@@ -1279,7 +1190,6 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
installGHC iopts installGHC iopts
Install (Left (InstallGHC iopts)) -> installGHC iopts Install (Left (InstallGHC iopts)) -> installGHC iopts
Install (Left (InstallCabal iopts)) -> installCabal iopts Install (Left (InstallCabal iopts)) -> installCabal iopts
Install (Left (InstallHLS iopts)) -> installHLS iopts
InstallCabalLegacy iopts -> do InstallCabalLegacy iopts -> do
runLogger ($(logWarn) [i|This is an old-style command for installing cabal. Use 'ghcup install cabal' instead.|]) runLogger ($(logWarn) [i|This is an old-style command for installing cabal. Use 'ghcup install cabal' instead.|])
installCabal iopts installCabal iopts
@@ -1289,7 +1199,6 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
setGHC' sopts setGHC' sopts
Set (Left (SetGHC sopts)) -> setGHC' sopts Set (Left (SetGHC sopts)) -> setGHC' sopts
Set (Left (SetCabal sopts)) -> setCabal' sopts Set (Left (SetCabal sopts)) -> setCabal' sopts
Set (Left (SetHLS sopts)) -> setHLS' sopts
List (ListOptions {..}) -> List (ListOptions {..}) ->
(runListGHC $ do (runListGHC $ do
@@ -1303,7 +1212,6 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
rmGHC' rmopts rmGHC' rmopts
Rm (Left (RmGHC rmopts)) -> rmGHC' rmopts Rm (Left (RmGHC rmopts)) -> rmGHC' rmopts
Rm (Left (RmCabal rmopts)) -> rmCabal' rmopts Rm (Left (RmCabal rmopts)) -> rmCabal' rmopts
Rm (Left (RmHLS rmopts)) -> rmHLS' rmopts
DInfo -> DInfo ->
do do
@@ -1333,7 +1241,7 @@ Report bugs at <https://gitlab.haskell.org/haskell/ghcup-hs/issues>|]
pure ExitSuccess pure ExitSuccess
VLeft (V (AlreadyInstalled _ v)) -> do VLeft (V (AlreadyInstalled _ v)) -> do
runLogger $ $(logWarn) runLogger $ $(logWarn)
[i|GHC ver #{prettyVer v} already installed, you may want to run 'ghcup rm ghc #{prettyVer v}' first|] [i|GHC ver #{prettyVer v} already installed|]
pure ExitSuccess pure ExitSuccess
VLeft (V (BuildFailed tmpdir e)) -> do VLeft (V (BuildFailed tmpdir e)) -> do
case keepDirs of case keepDirs of
@@ -1347,6 +1255,28 @@ Make sure to clean up #{tmpdir} afterwards.|])
runLogger ($(logError) [i|#{e}|]) runLogger ($(logError) [i|#{e}|])
pure $ ExitFailure 9 pure $ ExitFailure 9
Compile (CompileCabal CabalCompileOptions {..}) ->
(runCompileCabal $ do
liftE $ compileCabal dls targetVer bootstrapGhc jobs patchDir pfreq
)
>>= \case
VRight _ -> do
runLogger
($(logInfo)
"Cabal successfully compiled and installed"
)
pure ExitSuccess
VLeft (V (BuildFailed tmpdir e)) -> do
case keepDirs of
Never -> runLogger ($(logError) [i|Build failed with #{e}|])
_ -> runLogger ($(logError) [i|Build failed with #{e}
Check the logs at #{logsDir} and the build directory #{tmpdir} for more clues.
Make sure to clean up #{tmpdir} afterwards.|])
pure $ ExitFailure 10
VLeft e -> do
runLogger ($(logError) [i|#{e}|])
pure $ ExitFailure 10
Upgrade (uOpts) force -> do Upgrade (uOpts) force -> do
target <- case uOpts of target <- case uOpts of
UpgradeInplace -> do UpgradeInplace -> do
@@ -1463,144 +1393,49 @@ printListResult raw lr = do
setLocaleEncoding utf8 setLocaleEncoding utf8
let let
rows = formatted =
(\x -> if raw gridString
then x ( (if raw then [] else [column expand left def def])
else [color Green "", "Tool", "Version", "Tags", "Notes"] : x ++ [ column expand left def def
) , column expand left def def
. fmap , column expand left def def
, column expand left def def
]
)
. (\x -> if raw
then x
else [color Green "", "Tool", "Version", "Tags", "Notes"] : x
)
$ fmap
(\ListResult {..} -> (\ListResult {..} ->
let marks = if let marks = if
| lSet -> (color Green "✔✔") | lSet -> (color Green "✔✔")
| lInstalled -> (color Green " ") | lInstalled -> (color Green "")
| otherwise -> (color Red " ") | otherwise -> (color Red "")
in in (if raw then [] else [marks])
(if raw then [] else [marks]) ++ [ fmap toLower . show $ lTool
++ [ fmap toLower . show $ lTool , case lCross of
, case lCross of Nothing -> T.unpack . prettyVer $ lVer
Nothing -> T.unpack . prettyVer $ lVer Just c -> T.unpack (c <> "-" <> prettyVer lVer)
Just c -> T.unpack (c <> "-" <> prettyVer lVer) , intercalate "," $ (fmap printTag $ sort lTag)
, intercalate "," $ (fmap printTag $ sort lTag) , intercalate ","
, intercalate "," $ (if fromSrc then [color' Blue "compiled"] else mempty)
$ (if hlsPowered ++ (if lStray then [color' Yellow "stray"] else mempty)
then [color' Green "hls-powered"] ++ (if lNoBindist then [color' Red "no-bindist"] else mempty)
else mempty ]
)
++ (if fromSrc then [color' Blue "compiled"] else mempty)
++ (if lStray then [color' Yellow "stray"] else mempty)
++ (if lNoBindist
then [color' Red "no-bindist"]
else mempty
)
]
) )
$ lr lr
let cols = putStrLn $ formatted
foldr (\xs ys -> zipWith (:) xs ys) (replicate (length rows) []) rows
lengths = fmap maximum . (fmap . fmap) strWidth $ cols
padded = fmap (\xs -> zipWith padTo xs lengths) rows
forM_ padded $ \row -> putStrLn $ intercalate " " row
where where
printTag Recommended = color' Green "recommended" printTag Recommended = color' Green "recommended"
printTag Latest = color' Yellow "latest" printTag Latest = color' Yellow "latest"
printTag Prerelease = color' Red "prerelease" printTag Prerelease = color' Red "prerelease"
printTag (Base pvp'') = "base-" ++ T.unpack (prettyPVP pvp'') printTag (Base pvp'') = "base-" ++ T.unpack (prettyPVP pvp'')
printTag (UnknownTag t ) = t printTag (UnknownTag t ) = t
color' = case raw of color' = case raw of
True -> flip const True -> flip const
False -> color False -> color
padTo str' x =
let lstr = strWidth str'
add' = x - lstr
in if add' < 0 then str' else str' ++ replicate add' ' '
-- | Calculate the render width of a string, considering
-- wide characters (counted as double width), ANSI escape codes
-- (not counted), and line breaks (in a multi-line string, the longest
-- line determines the width).
strWidth :: String -> Int
strWidth =
maximum
. (0 :)
. map (foldr (\a b -> charWidth a + b) 0)
. lines
. stripAnsi
-- | Strip ANSI escape sequences from a string.
--
-- >>> stripAnsi "\ESC[31m-1\ESC[m"
-- "-1"
stripAnsi :: String -> String
stripAnsi s' =
case
MP.parseMaybe (many $ "" <$ MP.try ansi <|> pure <$> MP.anySingle) s'
of
Nothing -> error "Bad ansi escape" -- PARTIAL: should not happen
Just xs -> concat xs
where
-- This parses lots of invalid ANSI escape codes, but that should be fine
ansi =
MPC.string "\ESC[" *> digitSemicolons *> suffix MP.<?> "ansi" :: MP.Parsec
Void
String
Char
digitSemicolons = MP.takeWhileP Nothing (\c -> isDigit c || c == ';')
suffix = MP.oneOf ['A', 'B', 'C', 'D', 'H', 'J', 'K', 'f', 'm', 's', 'u']
-- | Get the designated render width of a character: 0 for a combining
-- character, 1 for a regular character, 2 for a wide character.
-- (Wide characters are rendered as exactly double width in apps and
-- fonts that support it.) (From Pandoc.)
charWidth :: Char -> Int
charWidth c = case c of
_ | c < '\x0300' -> 1
| c >= '\x0300' && c <= '\x036F' -> 0
| -- combining
c >= '\x0370' && c <= '\x10FC' -> 1
| c >= '\x1100' && c <= '\x115F' -> 2
| c >= '\x1160' && c <= '\x11A2' -> 1
| c >= '\x11A3' && c <= '\x11A7' -> 2
| c >= '\x11A8' && c <= '\x11F9' -> 1
| c >= '\x11FA' && c <= '\x11FF' -> 2
| c >= '\x1200' && c <= '\x2328' -> 1
| c >= '\x2329' && c <= '\x232A' -> 2
| c >= '\x232B' && c <= '\x2E31' -> 1
| c >= '\x2E80' && c <= '\x303E' -> 2
| c == '\x303F' -> 1
| c >= '\x3041' && c <= '\x3247' -> 2
| c >= '\x3248' && c <= '\x324F' -> 1
| -- ambiguous
c >= '\x3250' && c <= '\x4DBF' -> 2
| c >= '\x4DC0' && c <= '\x4DFF' -> 1
| c >= '\x4E00' && c <= '\xA4C6' -> 2
| c >= '\xA4D0' && c <= '\xA95F' -> 1
| c >= '\xA960' && c <= '\xA97C' -> 2
| c >= '\xA980' && c <= '\xABF9' -> 1
| c >= '\xAC00' && c <= '\xD7FB' -> 2
| c >= '\xD800' && c <= '\xDFFF' -> 1
| c >= '\xE000' && c <= '\xF8FF' -> 1
| -- ambiguous
c >= '\xF900' && c <= '\xFAFF' -> 2
| c >= '\xFB00' && c <= '\xFDFD' -> 1
| c >= '\xFE00' && c <= '\xFE0F' -> 1
| -- ambiguous
c >= '\xFE10' && c <= '\xFE19' -> 2
| c >= '\xFE20' && c <= '\xFE26' -> 1
| c >= '\xFE30' && c <= '\xFE6B' -> 2
| c >= '\xFE70' && c <= '\xFEFF' -> 1
| c >= '\xFF01' && c <= '\xFF60' -> 2
| c >= '\xFF61' && c <= '\x16A38' -> 1
| c >= '\x1B000' && c <= '\x1B001' -> 2
| c >= '\x1D000' && c <= '\x1F1FF' -> 1
| c >= '\x1F200' && c <= '\x1F251' -> 2
| c >= '\x1F300' && c <= '\x1F773' -> 1
| c >= '\x20000' && c <= '\x3FFFD' -> 2
| otherwise -> 1
checkForUpdates :: (MonadReader Settings m, MonadCatch m, MonadLogger m, MonadThrow m, MonadIO m, MonadFail m, MonadLogger m) checkForUpdates :: (MonadReader Settings m, MonadCatch m, MonadLogger m, MonadThrow m, MonadIO m, MonadFail m, MonadLogger m)
=> GHCupDownloads => GHCupDownloads
-> PlatformRequest -> PlatformRequest
@@ -1626,13 +1461,6 @@ checkForUpdates dls pfreq = do
$ $(logWarn) $ $(logWarn)
[i|New Cabal version available: #{prettyVer l}. To upgrade, run 'ghcup install cabal #{prettyVer l}'|] [i|New Cabal version available: #{prettyVer l}. To upgrade, run 'ghcup install cabal #{prettyVer l}'|]
forM_ (getLatest dls HLS) $ \l -> do
mcabal_ver <- latestInstalled HLS
forM mcabal_ver $ \cabal_ver ->
when (l > cabal_ver)
$ $(logWarn)
[i|New HLS version available: #{prettyVer l}. To upgrade, run 'ghcup install hls #{prettyVer l}'|]
where where
latestInstalled tool = (fmap lVer . lastMay) latestInstalled tool = (fmap lVer . lastMay)
<$> (listVersions dls (Just tool) (Just ListInstalled) pfreq) <$> (listVersions dls (Just tool) (Just ListInstalled) pfreq)
@@ -1648,4 +1476,20 @@ GHCup cache directory: #{toFilePath diCacheDir}
Architecture: #{prettyArch diArch} Architecture: #{prettyArch diArch}
Platform: #{prettyPlatform diPlatform} Platform: #{prettyPlatform diPlatform}
Version: #{describe_result}|] Version: #{describe_result}|]
where
prettyArch :: Architecture -> String
prettyArch A_64 = "amd64"
prettyArch A_32 = "i386"
prettyArch A_PowerPC = "PowerPC"
prettyArch A_PowerPC64 = "PowerPC64"
prettyArch A_Sparc = "Sparc"
prettyArch A_Sparc64 = "Sparc64"
prettyArch A_ARM = "ARM"
prettyArch A_ARM64 = "ARM64"
prettyPlatform :: PlatformResult -> String
prettyPlatform PlatformResult { _platform = plat, _distroVersion = Just v' }
= show plat <> ", " <> show v'
prettyPlatform PlatformResult { _platform = plat, _distroVersion = Nothing }
= show plat

View File

@@ -235,7 +235,7 @@ if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
if ! grep -q "ghcup-env" "${GHCUP_PROFILE_FILE}" ; then if ! grep -q "ghcup-env" "${GHCUP_PROFILE_FILE}" ; then
echo "# ghcup-env" >> "${GHCUP_PROFILE_FILE}" echo "# ghcup-env" >> "${GHCUP_PROFILE_FILE}"
echo "set -q GHCUP_INSTALL_BASE_PREFIX[1]; or set GHCUP_INSTALL_BASE_PREFIX \$HOME" >> "${GHCUP_PROFILE_FILE}" echo "set -q GHCUP_INSTALL_BASE_PREFIX[1]; or set GHCUP_INSTALL_BASE_PREFIX \$HOME" >> "${GHCUP_PROFILE_FILE}"
echo "test -f $GHCUP_DIR/env ; and set -gx PATH \$HOME/.cabal/bin $GHCUP_BIN \$PATH" >> "${GHCUP_PROFILE_FILE}" echo "test -f $GHCUP_DIR/env ; and set -gx PATH \$HOME/.cabal/bin $GHCUP_BIN/bin \$PATH" >> "${GHCUP_PROFILE_FILE}"
fi fi
break ;; break ;;
*) *)

View File

@@ -8,24 +8,6 @@ source-repository-package
tag: 80a1c5fc07f7226c424250ec17f674cd4d618f42 tag: 80a1c5fc07f7226c424250ec17f674cd4d618f42
subdir: haskus-utils-types subdir: haskus-utils-types
source-repository-package
type: git
location: https://github.com/hasufell/hpath.git
tag: bf6d28cf989b70286e12fecc183d5bbf5454a1a2
subdir: hpath-io
source-repository-package
type: git
location: https://github.com/hasufell/hpath.git
tag: bf6d28cf989b70286e12fecc183d5bbf5454a1a2
subdir: hpath-directory
-- https://github.com/cjdev/text-conversions/pull/10
source-repository-package
type: git
location: https://github.com/hasufell/text-conversions.git
tag: 9abf0e5e5664a3178367597c32db19880477a53c
optimization: 2 optimization: 2
package streamly package streamly
@@ -37,6 +19,6 @@ package ghcup
constraints: http-io-streams -brotli constraints: http-io-streams -brotli
package libarchive package libarchive
flags: -system-libarchive flags: +static
allow-newer: base, ghc-prim, template-haskell allow-newer: base, ghc-prim, template-haskell

View File

@@ -1159,7 +1159,7 @@ ghcupDownloads:
Linux_Alpine: Linux_Alpine:
unknown_versioning: unknown_versioning:
dlUri: https://downloads.haskell.org/~ghc/8.10.2/ghc-8.10.2-x86_64-alpine3.10-linux-integer-simple.tar.xz dlUri: https://downloads.haskell.org/~ghc/8.10.2/ghc-8.10.2-x86_64-alpine3.10-linux-integer-simple.tar.xz
dlSubdir: ghc-8.10.2-x86_64-unknown-linux dlSubdir: ghc-8.10.2
dlHash: 14d09a508f2a3a11875c140be8e6c5f6982ac5cd448f089ca10b7adc955fec76 dlHash: 14d09a508f2a3a11875c140be8e6c5f6982ac5cd448f089ca10b7adc955fec76
Linux_AmazonLinux: Linux_AmazonLinux:
unknown_versioning: *ghc-8102-64-centos unknown_versioning: *ghc-8102-64-centos
@@ -1197,6 +1197,10 @@ ghcupDownloads:
2.4.1.0: 2.4.1.0:
viTags: [] viTags: []
viChangeLog: https://downloads.haskell.org/~cabal/cabal-install-2.4.1.0/changelog viChangeLog: https://downloads.haskell.org/~cabal/cabal-install-2.4.1.0/changelog
viSourceDL:
dlUri: https://github.com/haskell/cabal/archive/cabal-install-v2.4.1.0.tar.gz
dlSubdir: cabal-cabal-install-v2.4.1.0/cabal-install
dlHash: 61eb64a5addafca026aff9277291f4643fe07e83886f76d059d42c734fed829c
viArch: viArch:
A_64: A_64:
Linux_Alpine: Linux_Alpine:
@@ -1228,6 +1232,10 @@ ghcupDownloads:
3.0.0.0: 3.0.0.0:
viTags: [] viTags: []
viChangeLog: https://downloads.haskell.org/~cabal/cabal-install-3.0.0.0/changelog viChangeLog: https://downloads.haskell.org/~cabal/cabal-install-3.0.0.0/changelog
viSourceDL:
dlUri: https://github.com/haskell/cabal/archive/cabal-install-v3.0.0.0.tar.gz
dlSubdir: cabal-cabal-install-v3.0.0.0/cabal-install
dlHash: c0b26817a7b7c2907e45cb38235ce1157e732211880f62e92eaff4066202e674
viArch: viArch:
A_64: A_64:
Linux_Alpine: Linux_Alpine:
@@ -1260,6 +1268,10 @@ ghcupDownloads:
- Recommended - Recommended
- Latest - Latest
viChangeLog: https://downloads.haskell.org/~cabal/cabal-install-3.2.0.0/changelog viChangeLog: https://downloads.haskell.org/~cabal/cabal-install-3.2.0.0/changelog
viSourceDL:
dlUri: https://github.com/haskell/cabal/archive/cabal-install-v3.2.0.0.tar.gz
dlSubdir: cabal-cabal-install-v3.2.0.0/cabal-install
dlHash: 77202358bdf0b481c09326268ce18880df14194c5aaa840f99510bdd1a124b75
viArch: viArch:
A_64: A_64:
Linux_Alpine: Linux_Alpine:
@@ -1287,30 +1299,29 @@ ghcupDownloads:
unknown_versioning: unknown_versioning:
dlUri: https://downloads.haskell.org/~cabal/cabal-install-3.2.0.0/cabal-install-3.2.0.0-i386-unknown-linux.tar.xz dlUri: https://downloads.haskell.org/~cabal/cabal-install-3.2.0.0/cabal-install-3.2.0.0-i386-unknown-linux.tar.xz
dlHash: 2b3ac28549916de5f3379241797eaf60e84b6c001f2abbe73d9fadbbaf768e93 dlHash: 2b3ac28549916de5f3379241797eaf60e84b6c001f2abbe73d9fadbbaf768e93
3.4.0.0-rc3: 3.4.0.0-rc1:
viTags: viTags:
- Prerelease - Prerelease
viChangeLog: https://github.com/haskell/cabal/blob/master/release-notes/cabal-install-3.4.0.0.md
viArch: viArch:
A_64: A_64:
Linux_Ubuntu: Linux_Ubuntu:
unknown_versioning: &cabal-3400rc3-ubuntu unknown_versioning: &cabal-3400rc1-ubuntu
dlUri: https://oleg.fi/cabal-install-3.4.0.0-rc3/cabal-install-3.4.0.0-x86_64-ubuntu-16.04.tar.xz dlUri: http://oleg.fi/cabal-install-3.4.0.0-rc1/cabal-install-3.4.0.0-x86_64-ubuntu-16.04.tar.xz
dlHash: a97f0362b8cdc78ba4a7891f8b288082dc11e20c64b1b3c8e6c2bd3766446d10 dlHash: 4a693eeacf91993d639b0296a366af7aec6899992352595835f7671e5adef4c6
Linux_Alpine: Linux_Alpine:
unknown_versioning: unknown_versioning:
dlUri: https://oleg.fi/cabal-install-3.4.0.0-rc3/cabal-install-3.4.0.0-x86_64-alpine-3.11.6-static-noofd.tar.xz dlUri: http://oleg.fi/cabal-install-3.4.0.0-rc1/cabal-install-3.4.0.0-x86_64-alpine-3.11.6-static-noofd.tar.xz
dlHash: a82c7dc7e46da823f6a982465b9b29e0640a5ce2e5b573d3dd55a47e20740305 dlHash: 143160e1768c9c21bad613f720a37aad34051f41fb3473f5f28c030f9ccb7aca
Linux_UnknownLinux: Linux_UnknownLinux:
unknown_versioning: *cabal-3400rc3-ubuntu unknown_versioning: *cabal-3400rc1-ubuntu
Darwin: Darwin:
unknown_versioning: unknown_versioning:
dlUri: https://oleg.fi/cabal-install-3.4.0.0-rc3/cabal-install-3.4.0.0-x86_64-darwin-sierra.tar.xz dlUri: http://oleg.fi/cabal-install-3.4.0.0-rc1/cabal-install-3.4.0.0-x86_64-darwin-sierra.tar.xz
dlHash: 4553eaea3031c09ab5156af8d4a62bf1ecbbea2c3b57a876f267cbf4b5a15658 dlHash: 98e362a57c3b5c1a76f75ede2c2a7c29439902a3e21c3e4f8dcd701e276b164f
FreeBSD: FreeBSD:
unknown_versioning: unknown_versioning:
dlUri: https://oleg.fi/cabal-install-3.4.0.0-rc3/cabal-install-3.4.0.0-x86_64-freebsd-12.1-release.tar.xz dlUri: http://oleg.fi/cabal-install-3.4.0.0-rc1/cabal-install-3.4.0.0-amd64-freebsd-12.1-release.tar.xz
dlHash: 44e25e0b0d15361acb369f4bf2206a39d2432a08fb922cc40a9b8a045d0a3a6f dlHash: 0035cc5d35db15d254037a9448697e1daff0a6d21b12c8d43d72522c82cc7319
GHCup: GHCup:
0.1.10: 0.1.10:
viTags: viTags:
@@ -1341,20 +1352,3 @@ ghcupDownloads:
dlHash: 50ac43199b64bc0724400b0a3db674bef3ec53cf6d41acc04a2c4ca8557e534f dlHash: 50ac43199b64bc0724400b0a3db674bef3ec53cf6d41acc04a2c4ca8557e534f
Linux_Alpine: Linux_Alpine:
unknown_versioning: *ghcup-32 unknown_versioning: *ghcup-32
HLS:
0.4.0:
viTags:
- Recommended
- Latest
viChangeLog: https://github.com/haskell/haskell-language-server/blob/master/ChangeLog.md#040
viArch:
A_64:
Linux_UnknownLinux:
unknown_versioning:
dlUri: https://github.com/haskell/haskell-language-server/releases/download/0.4.0/haskell-language-server-Linux-0.4.0.tar.gz
dlHash: 325b21b38a5e570f00b983885e8ec1eadcb5504a29b28ea4cbe1b85b32058f6d
Darwin:
unknown_versioning:
dlUri: https://github.com/haskell/haskell-language-server/releases/download/0.4.0/haskell-language-server-macOS-0.4.0.tar.gz
dlHash: 06a23f1495086438e9676213f7aeddbbc382014ad8016ed7c8ad241a2a15fcfe

View File

@@ -1,6 +1,6 @@
cabal-version: 3.0 cabal-version: 3.0
name: ghcup name: ghcup
version: 0.1.11 version: 0.1.10
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
@@ -81,9 +81,6 @@ common containers
common cryptohash-sha256 common cryptohash-sha256
build-depends: cryptohash-sha256 >= 0.11.101.0 build-depends: cryptohash-sha256 >= 0.11.101.0
common generic-arbitrary
build-depends: generic-arbitrary >=0.1.0
common generics-sop common generics-sop
build-depends: generics-sop >=0.5 build-depends: generics-sop >=0.5
@@ -97,13 +94,13 @@ common hpath
build-depends: hpath >=0.11 build-depends: hpath >=0.11
common hpath-directory common hpath-directory
build-depends: hpath-directory >=0.14.1 build-depends: hpath-directory >=0.14
common hpath-filepath common hpath-filepath
build-depends: hpath-filepath >=0.10.3 build-depends: hpath-filepath >=0.10.3
common hpath-io common hpath-io
build-depends: hpath-io >=0.14.1 build-depends: hpath-io >=0.14
common hpath-posix common hpath-posix
build-depends: hpath-posix >=0.13.2 build-depends: hpath-posix >=0.13.2
@@ -111,17 +108,11 @@ common hpath-posix
common http-io-streams common http-io-streams
build-depends: http-io-streams >=0.1.2.0 build-depends: http-io-streams >=0.1.2.0
common hspec
build-depends: hspec >=2.7.4
common hspec-golden-aeson
build-depends: hspec-golden-aeson >=0.7
common io-streams common io-streams
build-depends: io-streams >=1.5 build-depends: io-streams >=1.5
common libarchive common libarchive
build-depends: libarchive >= 3.0.0.0 build-depends: libarchive >= 2.2.5.0
common lzma common lzma
build-depends: lzma >=0.0.0.3 build-depends: lzma >=0.0.0.3
@@ -180,6 +171,9 @@ common strict-base
common string-interpolate common string-interpolate
build-depends: string-interpolate >=0.2.0.0 build-depends: string-interpolate >=0.2.0.0
common table-layout
build-depends: table-layout >=0.8
common template-haskell common template-haskell
build-depends: template-haskell >=2.7 build-depends: template-haskell >=2.7
@@ -201,12 +195,6 @@ common transformers
common os-release common os-release
build-depends: os-release >=1.0.0 build-depends: os-release >=1.0.0
common QuickCheck
build-depends: QuickCheck >=2.14.1
common quickcheck-arbitrary-adt
build-depends: quickcheck-arbitrary-adt >=0.3.1.0
common unix common unix
build-depends: unix >=2.7 build-depends: unix >=2.7
@@ -252,6 +240,8 @@ common config
PackageImports PackageImports
RecordWildCards RecordWildCards
ScopedTypeVariables ScopedTypeVariables
Strict
StrictData
TupleSections TupleSections
library library
@@ -331,10 +321,6 @@ library
GHCup.Utils.Version.QQ GHCup.Utils.Version.QQ
GHCup.Version GHCup.Version
default-extensions:
Strict
StrictData
-- other-modules: -- other-modules:
-- other-extensions: -- other-extensions:
hs-source-dirs: lib hs-source-dirs: lib
@@ -375,8 +361,10 @@ executable ghcup
, safe , safe
, safe-exceptions , safe-exceptions
, string-interpolate , string-interpolate
, table-layout
, template-haskell , template-haskell
, text , text
, unix-bytestring
, uri-bytestring , uri-bytestring
, utf8-string , utf8-string
, versions , versions
@@ -390,10 +378,6 @@ executable ghcup
hs-source-dirs: app/ghcup hs-source-dirs: app/ghcup
default-language: Haskell2010 default-language: Haskell2010
default-extensions:
Strict
StrictData
if flag(internal-downloader) if flag(internal-downloader)
cpp-options: -DINTERNAL_DOWNLOADER cpp-options: -DINTERNAL_DOWNLOADER
@@ -429,6 +413,7 @@ executable ghcup-gen
, resourcet , resourcet
, safe-exceptions , safe-exceptions
, string-interpolate , string-interpolate
, table-layout
, text , text
, transformers , transformers
, uri-bytestring , uri-bytestring
@@ -447,25 +432,8 @@ executable ghcup-gen
default-language: Haskell2010 default-language: Haskell2010
test-suite ghcup-test test-suite ghcup-test
import: default-language: Haskell2010
config
, base
, bytestring
, containers
, QuickCheck
, generic-arbitrary
, hpath
, hspec
, hspec-golden-aeson
, quickcheck-arbitrary-adt
, text
, uri-bytestring
, versions
type: exitcode-stdio-1.0 type: exitcode-stdio-1.0
build-depends: ghcup
hs-source-dirs: test hs-source-dirs: test
main-is: Main.hs main-is: MyLibTest.hs
other-modules: build-depends: base >=4.12.0.0
GHCup.ArbitraryTypes
GHCup.Types.JSONSpec
Spec

File diff suppressed because it is too large Load Diff

View File

@@ -2,5 +2,3 @@ cradle:
cabal: cabal:
- path: "." - path: "."
component: "ghcup:lib:ghcup" component: "ghcup:lib:ghcup"
- path: "."
component: "ghcup:exe:ghcup"

View File

@@ -75,12 +75,9 @@ import Prelude hiding ( abs
import Safe hiding ( at ) import Safe hiding ( at )
import System.IO.Error import System.IO.Error
import System.Posix.Env.ByteString ( getEnvironment ) import System.Posix.Env.ByteString ( getEnvironment )
import System.Posix.FilePath ( getSearchPath, takeExtension ) import System.Posix.FilePath ( getSearchPath )
import System.Posix.Files.ByteString import System.Posix.Files.ByteString
import Text.Regex.Posix
import qualified Crypto.Hash.SHA256 as SHA256
import qualified Data.ByteString.Base16 as B16
import qualified Data.ByteString as B import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Lazy as BL
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
@@ -122,7 +119,7 @@ installGHCBindist :: ( MonadFail m
] ]
m m
() ()
installGHCBindist dlinfo ver pfreq = 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 (lift $ ghcInstalled tver) whenM (lift $ ghcInstalled tver)
@@ -131,79 +128,41 @@ installGHCBindist dlinfo ver pfreq = do
-- download (or use cached version) -- download (or use cached version)
dl <- liftE $ downloadCached dlinfo Nothing dl <- liftE $ downloadCached dlinfo Nothing
-- prepare paths
ghcdir <- lift $ ghcupGHCDir tver
liftE $ installPackedGHC dl (view dlSubdir dlinfo) ghcdir ver pfreq
liftE $ postGHCInstall tver
-- | Install a packed GHC distribution. This only deals with unpacking and the GHC
-- build system and nothing else.
installPackedGHC :: ( MonadMask m
, MonadCatch m
, MonadReader Settings m
, MonadThrow m
, MonadLogger m
, MonadIO m
)
=> Path Abs -- ^ Path to the packed GHC bindist
-> Maybe TarDir -- ^ Subdir of the archive
-> Path Abs -- ^ Path to install to
-> Version -- ^ The GHC version
-> PlatformRequest
-> Excepts
'[ BuildFailed
, UnknownArchive
, TarDirDoesNotExist
#if !defined(TAR)
, ArchiveResult
#endif
] m ()
installPackedGHC dl msubdir inst ver pfreq@(PlatformRequest {..}) = do
-- unpack -- unpack
tmpUnpack <- lift mkGhcupTmpDir tmpUnpack <- lift mkGhcupTmpDir
liftE $ unpackToDir tmpUnpack dl liftE $ unpackToDir tmpUnpack dl
void $ liftIO $ darwinNotarization _rPlatform tmpUnpack void $ liftIO $ darwinNotarization _rPlatform tmpUnpack
-- prepare paths
ghcdir <- lift $ ghcupGHCDir tver
-- the subdir of the archive where we do the work -- the subdir of the archive where we do the work
workdir <- maybe (pure tmpUnpack) workdir <- maybe (pure tmpUnpack) (liftE . intoSubdir tmpUnpack) (view dlSubdir dlinfo)
(liftE . intoSubdir tmpUnpack)
(msubdir)
liftE $ runBuildAction tmpUnpack liftE $ runBuildAction tmpUnpack (Just ghcdir) (installGHC' workdir ghcdir)
(Just inst)
(installUnpackedGHC workdir inst ver pfreq)
liftE $ postGHCInstall tver
-- | Install an unpacked GHC distribution. This only deals with the GHC
-- build system and nothing else.
installUnpackedGHC :: ( MonadReader Settings m
, MonadThrow m
, MonadLogger m
, MonadIO m
)
=> Path Abs -- ^ Path to the unpacked GHC bindist (where the configure script resides)
-> Path Abs -- ^ Path to install to
-> Version -- ^ The GHC version
-> PlatformRequest
-> Excepts '[ProcessError] m ()
installUnpackedGHC path inst ver (PlatformRequest {..}) = do
lift $ $(logInfo) "Installing GHC (this may take a while)"
lEM $ execLogged "./configure"
False
(["--prefix=" <> toFilePath inst] ++ alpineArgs)
[rel|ghc-configure|]
(Just path)
Nothing
lEM $ make ["install"] (Just path)
pure ()
where where
-- | Install an unpacked GHC distribution. This only deals with the GHC build system and nothing else.
installGHC' :: (MonadReader Settings m, MonadThrow m, MonadLogger m, MonadIO m)
=> Path Abs -- ^ Path to the unpacked GHC bindist (where the configure script resides)
-> Path Abs -- ^ Path to install to
-> Excepts '[ProcessError] m ()
installGHC' path inst = do
lift $ $(logInfo) "Installing GHC (this may take a while)"
lEM $ execLogged "./configure"
False
(["--prefix=" <> toFilePath inst] ++ alpineArgs)
(Just path)
Nothing
lEM $ make ["install"] (Just path)
pure ()
alpineArgs alpineArgs
| ver >= [vver|8.2.2|], Linux Alpine <- _rPlatform | ver >= [vver|8.2.2|]
= ["--disable-ld-override"] , Linux Alpine <- _rPlatform = ["--disable-ld-override"]
| otherwise | otherwise = []
= []
-- | Installs GHC into @~\/.ghcup\/ghc/\<ver\>@ and places the -- | Installs GHC into @~\/.ghcup\/ghc/\<ver\>@ and places the
@@ -313,7 +272,7 @@ installCabalBindist dlinfo ver (PlatformRequest {..}) = do
installCabal' path inst = do installCabal' path inst = do
lift $ $(logInfo) "Installing cabal" lift $ $(logInfo) "Installing cabal"
let cabalFile = [rel|cabal|] let cabalFile = [rel|cabal|]
liftIO $ createDirRecursive' inst liftIO $ createDirRecursive newDirPerms inst
destFileName <- lift $ parseRel (toFilePath cabalFile <> "-" <> verToBS ver) destFileName <- lift $ parseRel (toFilePath cabalFile <> "-" <> verToBS ver)
let destPath = inst </> destFileName let destPath = inst </> destFileName
handleIO (throwE . CopyError . show) $ liftIO $ copyFile handleIO (throwE . CopyError . show) $ liftIO $ copyFile
@@ -357,130 +316,6 @@ installCabalBin bDls ver pfreq = do
installCabalBindist dlinfo ver pfreq installCabalBindist dlinfo ver pfreq
-- | Like 'installHLSBin, except takes the 'DownloadInfo' as
-- argument instead of looking it up from 'GHCupDownloads'.
installHLSBindist :: ( 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
, TarDirDoesNotExist
#if !defined(TAR)
, ArchiveResult
#endif
]
m
()
installHLSBindist dlinfo ver (PlatformRequest {..}) = do
lift $ $(logDebug) [i|Requested to install hls version #{ver}|]
Settings {dirs = Dirs {..}} <- lift ask
whenM (lift (hlsInstalled ver))
$ (throwE $ AlreadyInstalled HLS ver)
-- download (or use cached version)
dl <- liftE $ downloadCached dlinfo Nothing
-- unpack
tmpUnpack <- lift withGHCupTmpDir
liftE $ unpackToDir tmpUnpack dl
void $ liftIO $ darwinNotarization _rPlatform tmpUnpack
-- the subdir of the archive where we do the work
workdir <- maybe (pure tmpUnpack) (liftE . intoSubdir tmpUnpack) (view dlSubdir dlinfo)
liftE $ installHLS' workdir binDir
-- create symlink if this is the latest version
hlsVers <- lift $ fmap rights $ getInstalledHLSs
let lInstHLS = headMay . reverse . sort $ hlsVers
when (maybe True (ver >=) lInstHLS) $ liftE $ setHLS ver
pure ()
where
-- | Install an unpacked hls distribution.
installHLS' :: (MonadFail m, MonadLogger m, MonadCatch m, MonadIO m)
=> Path Abs -- ^ Path to the unpacked hls bindist (where the executable resides)
-> Path Abs -- ^ Path to install to
-> Excepts '[CopyError] m ()
installHLS' path inst = do
lift $ $(logInfo) "Installing HLS"
liftIO $ createDirRecursive' inst
-- install haskell-language-server-<ghcver>
bins@(_:_) <- liftIO $ findFiles
path
(makeRegexOpts compExtended
execBlank
([s|^haskell-language-server-[0-9].*$|] :: ByteString)
)
forM_ bins $ \f -> do
toF <- parseRel (toFilePath f <> "~" <> verToBS ver)
handleIO (throwE . CopyError . show) $ liftIO $ copyFile
(path </> f)
(inst </> toF)
Overwrite
lift $ chmod_777 (inst </> toF)
-- install haskell-language-server-wrapper
let wrapper = [rel|haskell-language-server-wrapper|]
toF <- parseRel (toFilePath wrapper <> "-" <> verToBS ver)
handleIO (throwE . CopyError . show) $ liftIO $ copyFile
(path </> wrapper)
(inst </> toF)
Overwrite
lift $ chmod_777 (inst </> toF)
-- | Installs hls binaries @haskell-language-server-\<ghcver\>@
-- into @~\/.ghcup\/bin/@, as well as @haskell-languager-server-wrapper@.
installHLSBin :: ( 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
, TarDirDoesNotExist
#if !defined(TAR)
, ArchiveResult
#endif
]
m
()
installHLSBin bDls ver pfreq = do
dlinfo <- lE $ getDownloadInfo HLS ver pfreq bDls
installHLSBindist dlinfo ver pfreq
--------------------- ---------------------
@@ -516,7 +351,7 @@ setGHC ver sghc = do
-- symlink destination -- symlink destination
Settings { dirs = Dirs {..} } <- lift ask Settings { dirs = Dirs {..} } <- lift ask
liftIO $ createDirRecursive' binDir liftIO $ hideError AlreadyExists $ createDirRecursive newDirPerms binDir
-- first delete the old symlinks (this fixes compatibility issues -- first delete the old symlinks (this fixes compatibility issues
-- with old ghcup) -- with old ghcup)
@@ -588,7 +423,7 @@ setCabal ver = do
-- symlink destination -- symlink destination
Settings {dirs = Dirs {..}} <- lift ask Settings {dirs = Dirs {..}} <- lift ask
liftIO $ createDirRecursive' binDir liftIO $ hideError AlreadyExists $ createDirRecursive newDirPerms binDir
whenM (liftIO $ fmap not $ doesFileExist (binDir </> targetFile)) whenM (liftIO $ fmap not $ doesFileExist (binDir </> targetFile))
$ throwE $ throwE
@@ -611,55 +446,6 @@ setCabal ver = do
-- | Set the haskell-language-server symlinks.
setHLS :: ( MonadCatch m
, MonadReader Settings m
, MonadLogger m
, MonadThrow m
, MonadFail m
, MonadIO m
)
=> Version
-> Excepts '[NotInstalled] m ()
setHLS ver = do
Settings { dirs = Dirs {..} } <- lift ask
liftIO $ createDirRecursive' binDir
-- Delete old symlinks, since these might have different ghc versions than the
-- selected version, so we could end up with stray or incorrect symlinks.
oldSyms <- lift hlsSymlinks
forM_ oldSyms $ \f -> do
lift $ $(logDebug) [i|rm #{toFilePath (binDir </> f)}|]
liftIO $ deleteFile (binDir </> f)
-- set haskell-language-server-<ghcver> symlinks
bins <- lift $ hlsServerBinaries ver
when (bins == []) $ throwE $ NotInstalled HLS (prettyVer ver)
forM_ bins $ \f -> do
let destL = toFilePath f
target <- parseRel . head . B.split _tilde . toFilePath $ f
lift $ $(logDebug) [i|rm -f #{toFilePath (binDir </> target)}|]
liftIO $ hideError doesNotExistErrorType $ deleteFile (binDir </> target)
lift $ $(logDebug) [i|ln -s #{destL} #{toFilePath (binDir </> target)}|]
liftIO $ createSymlink (binDir </> target) destL
-- set haskell-language-server-wrapper symlink
let destL = "haskell-language-server-wrapper-" <> verToBS ver
let wrapper = binDir </> [rel|haskell-language-server-wrapper|]
lift $ $(logDebug) [i|rm -f #{toFilePath wrapper}|]
liftIO $ hideError doesNotExistErrorType $ deleteFile wrapper
lift $ $(logDebug) [i|ln -s #{destL} #{toFilePath wrapper}|]
liftIO $ createSymlink wrapper destL
pure ()
------------------ ------------------
@@ -684,7 +470,6 @@ data ListResult = ListResult
, fromSrc :: Bool -- ^ compiled from source , fromSrc :: Bool -- ^ compiled from source
, lStray :: Bool -- ^ not in download info , lStray :: Bool -- ^ not in download info
, lNoBindist :: Bool -- ^ whether the version is available for this platform/arch , lNoBindist :: Bool -- ^ whether the version is available for this platform/arch
, hlsPowered :: Bool
} }
deriving (Eq, Ord, Show) deriving (Eq, Ord, Show)
@@ -718,25 +503,22 @@ listVersions av lt criteria pfreq = do
lr <- filter' <$> forM (Map.toList avTools) (toListResult t) lr <- filter' <$> forM (Map.toList avTools) (toListResult t)
case t of case t of
-- append stray GHCs
GHC -> do GHC -> do
slr <- strayGHCs avTools slr <- strayGHCs avTools
pure $ (sort (slr ++ lr)) pure $ (sort (slr ++ lr))
Cabal -> do Cabal -> do
slr <- strayCabals avTools slr <- strayCabals avTools
pure $ (sort (slr ++ lr)) pure $ (sort (slr ++ lr))
HLS -> do _ -> pure lr
slr <- strayHLS avTools
pure $ (sort (slr ++ lr))
GHCup -> pure lr
Nothing -> do Nothing -> do
ghcvers <- listVersions av (Just GHC) criteria pfreq ghcvers <- listVersions av (Just GHC) criteria pfreq
cabalvers <- listVersions av (Just Cabal) criteria pfreq cabalvers <- listVersions av (Just Cabal) criteria pfreq
hlsvers <- listVersions av (Just HLS) criteria pfreq
ghcupvers <- listVersions av (Just GHCup) criteria pfreq ghcupvers <- listVersions av (Just GHCup) criteria pfreq
pure (ghcvers <> cabalvers <> hlsvers <> ghcupvers) pure (ghcvers <> cabalvers <> ghcupvers)
where where
strayGHCs :: (MonadCatch m, MonadReader Settings m, MonadThrow m, MonadLogger m, MonadIO m) strayGHCs :: (MonadReader Settings m, MonadThrow m, MonadLogger m, MonadIO m)
=> Map.Map Version [Tag] => Map.Map Version [Tag]
-> m [ListResult] -> m [ListResult]
strayGHCs avTools = do strayGHCs avTools = do
@@ -748,7 +530,6 @@ listVersions av lt criteria pfreq = do
Nothing -> do Nothing -> do
lSet <- fmap (maybe False (\(GHCTargetVersion _ v ) -> v == _tvVersion)) $ ghcSet Nothing lSet <- fmap (maybe False (\(GHCTargetVersion _ v ) -> v == _tvVersion)) $ ghcSet Nothing
fromSrc <- ghcSrcInstalled tver fromSrc <- ghcSrcInstalled tver
hlsPowered <- fmap (elem _tvVersion) $ hlsGHCVersions
pure $ Just $ ListResult pure $ Just $ ListResult
{ lTool = GHC { lTool = GHC
, lVer = _tvVersion , lVer = _tvVersion
@@ -762,7 +543,6 @@ listVersions av lt criteria pfreq = do
Right tver@GHCTargetVersion{ .. } -> do Right tver@GHCTargetVersion{ .. } -> do
lSet <- fmap (maybe False (\(GHCTargetVersion _ v ) -> v == _tvVersion)) $ ghcSet _tvTarget lSet <- fmap (maybe False (\(GHCTargetVersion _ v ) -> v == _tvVersion)) $ ghcSet _tvTarget
fromSrc <- ghcSrcInstalled tver fromSrc <- ghcSrcInstalled tver
hlsPowered <- fmap (elem _tvVersion) $ hlsGHCVersions
pure $ Just $ ListResult pure $ Just $ ListResult
{ lTool = GHC { lTool = GHC
, lVer = _tvVersion , lVer = _tvVersion
@@ -798,35 +578,6 @@ listVersions av lt criteria pfreq = do
, lStray = maybe True (const False) (Map.lookup ver avTools) , lStray = maybe True (const False) (Map.lookup ver avTools)
, lNoBindist = False , lNoBindist = False
, fromSrc = False -- actually, we don't know :> , fromSrc = False -- actually, we don't know :>
, hlsPowered = False
, ..
}
Left e -> do
$(logWarn)
[i|Could not parse version of stray directory #{toFilePath e}|]
pure Nothing
strayHLS :: (MonadReader Settings m, MonadCatch m, MonadThrow m, MonadLogger m, MonadIO m)
=> Map.Map Version [Tag]
-> m [ListResult]
strayHLS avTools = do
hlss <- getInstalledHLSs
fmap catMaybes $ forM hlss $ \case
Right ver ->
case Map.lookup ver avTools of
Just _ -> pure Nothing
Nothing -> do
lSet <- fmap (maybe False (== ver)) $ hlsSet
pure $ Just $ ListResult
{ lTool = HLS
, lVer = ver
, lCross = Nothing
, lTag = []
, lInstalled = True
, lStray = maybe True (const False) (Map.lookup ver avTools)
, lNoBindist = False
, fromSrc = False -- actually, we don't know :>
, hlsPowered = False
, .. , ..
} }
Left e -> do Left e -> do
@@ -843,7 +594,6 @@ listVersions av lt criteria pfreq = do
lSet <- fmap (maybe False (\(GHCTargetVersion _ v') -> v' == v)) $ ghcSet Nothing lSet <- fmap (maybe False (\(GHCTargetVersion _ v') -> v' == v)) $ ghcSet Nothing
lInstalled <- ghcInstalled tver lInstalled <- ghcInstalled tver
fromSrc <- ghcSrcInstalled tver fromSrc <- ghcSrcInstalled tver
hlsPowered <- fmap (elem v) $ hlsGHCVersions
pure ListResult { lVer = v, lCross = Nothing , lTag = tags, lTool = t, lStray = False, .. } pure ListResult { lVer = v, lCross = Nothing , lTag = tags, lTool = t, lStray = False, .. }
Cabal -> do Cabal -> do
let lNoBindist = isLeft $ getDownloadInfo Cabal v pfreq av let lNoBindist = isLeft $ getDownloadInfo Cabal v pfreq av
@@ -855,7 +605,6 @@ listVersions av lt criteria pfreq = do
, lTool = t , lTool = t
, fromSrc = False , fromSrc = False
, lStray = False , lStray = False
, hlsPowered = False
, .. , ..
} }
GHCup -> do GHCup -> do
@@ -868,20 +617,6 @@ listVersions av lt criteria pfreq = do
, fromSrc = False , fromSrc = False
, lStray = False , lStray = False
, lNoBindist = False , lNoBindist = False
, hlsPowered = False
, ..
}
HLS -> do
let lNoBindist = isLeft $ getDownloadInfo HLS v pfreq av
lSet <- fmap (maybe False (== v)) $ hlsSet
lInstalled <- hlsInstalled v
pure ListResult { lVer = v
, lCross = Nothing
, lTag = tags
, lTool = t
, fromSrc = False
, lStray = False
, hlsPowered = False
, .. , ..
} }
@@ -973,35 +708,6 @@ rmCabalVer ver = do
(binDir </> [rel|cabal|]) (binDir </> [rel|cabal|])
-- | Delete a hls version. Will try to fix the hls symlinks
-- after removal (e.g. setting it to an older version).
rmHLSVer :: (MonadReader Settings m, MonadThrow m, MonadLogger m, MonadIO m, MonadFail m, MonadCatch m)
=> Version
-> Excepts '[NotInstalled] m ()
rmHLSVer ver = do
whenM (lift $ fmap not $ hlsInstalled ver) $ throwE (NotInstalled HLS (prettyVer ver))
isHlsSet <- lift $ hlsSet
Settings {dirs = Dirs {..}} <- lift ask
bins <- lift $ hlsAllBinaries ver
forM_ bins $ \f -> liftIO $ deleteFile (binDir </> f)
when (maybe False (== ver) isHlsSet) $ do
-- delete all set symlinks
oldSyms <- lift hlsSymlinks
forM_ oldSyms $ \f -> do
lift $ $(logDebug) [i|rm #{toFilePath (binDir </> f)}|]
liftIO $ deleteFile (binDir </> f)
-- set latest hls
hlsVers <- lift $ fmap rights $ getInstalledHLSs
case headMay . reverse . sort $ hlsVers of
Just latestver -> setHLS latestver
Nothing -> pure ()
------------------ ------------------
--[ Debug info ]-- --[ Debug info ]--
@@ -1060,74 +766,51 @@ compileGHC :: ( MonadMask m
, PatchFailed , PatchFailed
, UnknownArchive , UnknownArchive
, TarDirDoesNotExist , TarDirDoesNotExist
, NotInstalled
#if !defined(TAR) #if !defined(TAR)
, ArchiveResult , ArchiveResult
#endif #endif
] ]
m m
() ()
compileGHC dls tver bstrap jobs mbuildConfig patchdir aargs pfreq@(PlatformRequest {..}) compileGHC dls tver bstrap jobs mbuildConfig patchdir aargs PlatformRequest {..} = do
= do lift $ $(logDebug) [i|Requested to compile: #{tver} with #{bstrap}|]
lift $ $(logDebug) [i|Requested to compile: #{tver} with #{bstrap}|] whenM (lift $ ghcInstalled tver)
(throwE $ AlreadyInstalled GHC (tver ^. tvVersion))
alreadyInstalled <- lift $ ghcInstalled tver -- download source tarball
alreadySet <- fmap (maybe False (==tver)) $ lift $ ghcSet (_tvTarget tver) dlInfo <-
preview (ix GHC % ix (tver ^. tvVersion) % viSourceDL % _Just) dls
?? NoDownload
dl <- liftE $ downloadCached dlInfo Nothing
-- download source tarball -- unpack
dlInfo <- tmpUnpack <- lift mkGhcupTmpDir
preview (ix GHC % ix (tver ^. tvVersion) % viSourceDL % _Just) dls liftE $ unpackToDir tmpUnpack dl
?? NoDownload void $ liftIO $ darwinNotarization _rPlatform tmpUnpack
dl <- liftE $ downloadCached dlInfo Nothing
-- unpack bghc <- case bstrap of
tmpUnpack <- lift mkGhcupTmpDir Right g -> pure $ Right g
liftE $ unpackToDir tmpUnpack dl Left bver -> Left <$> parseRel ("ghc-" <> verToBS bver)
void $ liftIO $ darwinNotarization _rPlatform tmpUnpack workdir <- maybe (pure tmpUnpack) (liftE . intoSubdir tmpUnpack) (view dlSubdir dlInfo)
ghcdir <- lift $ ghcupGHCDir tver
bghc <- case bstrap of liftE $ runBuildAction
Right g -> pure $ Right g tmpUnpack
Left bver -> Left <$> parseRel ("ghc-" <> verToBS bver) (Just ghcdir)
workdir <- maybe (pure tmpUnpack) (compile bghc ghcdir workdir >> markSrcBuilt ghcdir workdir)
(liftE . intoSubdir tmpUnpack)
(view dlSubdir dlInfo)
ghcdir <- lift $ ghcupGHCDir tver
(bindist, bmk) <- liftE $ runBuildAction reThrowAll GHCupSetError $ postGHCInstall tver
tmpUnpack pure ()
Nothing
(do
b <- compileBindist bghc ghcdir workdir
bmk <- liftIO $ readFileStrict (build_mk workdir)
pure (b, bmk)
)
when alreadyInstalled $ do
lift $ $(logInfo) [i|Deleting existing installation|]
liftE $ rmGHCVer tver
liftE $ installPackedGHC bindist
(view dlSubdir dlInfo)
ghcdir
(tver ^. tvVersion)
pfreq
liftIO $ writeFile (ghcdir </> ghcUpSrcBuiltFile) (Just newFilePerms) bmk
reThrowAll GHCupSetError $ postGHCInstall tver
-- restore
when alreadySet $ liftE $ void $ setGHC tver SetGHCOnly
pure ()
where where
defaultConf = case _tvTarget tver of defaultConf = case _tvTarget tver of
Nothing -> [s| Nothing -> [s|
V=0 V=0
BUILD_MAN = NO BUILD_MAN = NO
BUILD_SPHINX_HTML = NO BUILD_SPHINX_HTML = NO
BUILD_SPHINX_PDF = NO BUILD_SPHINX_PDF = NO
HADDOCK_DOCS = YES|] HADDOCK_DOCS = YES|]
Just _ -> [s| Just _ -> [s|
V=0 V=0
BUILD_MAN = NO BUILD_MAN = NO
BUILD_SPHINX_HTML = NO BUILD_SPHINX_HTML = NO
@@ -1135,26 +818,23 @@ BUILD_SPHINX_PDF = NO
HADDOCK_DOCS = NO HADDOCK_DOCS = NO
Stage1Only = YES|] Stage1Only = YES|]
compileBindist :: ( MonadReader Settings m compile :: (MonadReader Settings m, MonadThrow m, MonadCatch m, MonadLogger m, MonadIO m)
, MonadThrow m => Either (Path Rel) (Path Abs)
, MonadCatch m -> Path Abs
, MonadLogger m -> Path Abs
, MonadIO m -> Excepts
, MonadFail m '[ FileDoesNotExistError
) , InvalidBuildConfig
=> Either (Path Rel) (Path Abs) , PatchFailed
-> Path Abs , ProcessError
-> Path Abs , NotFoundInPATH
-> Excepts ]
'[FileDoesNotExistError, InvalidBuildConfig, PatchFailed, ProcessError, NotFoundInPATH, CopyError] m
m ()
(Path Abs) -- ^ output path of bindist compile bghc ghcdir workdir = do
compileBindist bghc ghcdir workdir = do
lift $ $(logInfo) [i|configuring build|] lift $ $(logInfo) [i|configuring build|]
liftE $ checkBuildConfig liftE $ checkBuildConfig
Settings { dirs = Dirs {..} } <- lift ask
forM_ patchdir $ \dir -> liftE $ applyPatches dir workdir forM_ patchdir $ \dir -> liftE $ applyPatches dir workdir
cEnv <- liftIO $ getEnvironment cEnv <- liftIO $ getEnvironment
@@ -1176,7 +856,6 @@ Stage1Only = YES|]
) )
++ fmap E.encodeUtf8 aargs ++ fmap E.encodeUtf8 aargs
) )
[rel|ghc-conf|]
(Just workdir) (Just workdir)
(Just (("GHC", toFilePath bghcPath) : cEnv)) (Just (("GHC", toFilePath bghcPath) : cEnv))
| otherwise -> do | otherwise -> do
@@ -1192,7 +871,6 @@ Stage1Only = YES|]
) )
++ fmap E.encodeUtf8 aargs ++ fmap E.encodeUtf8 aargs
) )
[rel|ghc-conf|]
(Just workdir) (Just workdir)
(Just cEnv) (Just cEnv)
@@ -1205,49 +883,29 @@ Stage1Only = YES|]
liftIO $ writeFile (build_mk workdir) (Just newFilePerms) defaultConf liftIO $ writeFile (build_mk workdir) (Just newFilePerms) defaultConf
lift $ $(logInfo) [i|Building (this may take a while)...|] lift $ $(logInfo) [i|Building (this may take a while)...|]
lEM $ make (maybe [] (\j -> ["-j" <> fS (show j)]) jobs) (Just workdir) lEM $ make (maybe [] (\j -> ["-j" <> fS (show j)]) jobs)
(Just workdir)
lift $ $(logInfo) [i|Creating bindist...|] lift $ $(logInfo) [i|Installing...|]
lEM $ make ["binary-dist"] (Just workdir) lEM $ make ["install"] (Just workdir)
[tar] <- liftIO $ findFiles
workdir markSrcBuilt ghcdir workdir = do
(makeRegexOpts compExtended let dest = (ghcdir </> ghcUpSrcBuiltFile)
execBlank liftIO $ copyFile (build_mk workdir) dest Overwrite
([s|^ghc-.*\.tar\..*$|] :: ByteString)
)
c <- liftIO $ readFile (workdir </> tar)
cDigest <-
fmap (T.take 8)
. lift
. throwEither
. E.decodeUtf8'
. B16.encode
. SHA256.hashlazy
$ c
tarName <-
parseRel
[i|ghc-#{prettyTVer tver}-#{prettyPfReq pfreq}-#{cDigest}.tar#{takeExtension (toFilePath tar)}|]
let tarPath = cacheDir </> tarName
handleIO (throwE . CopyError . show) $ liftIO $ copyFile (workdir </> tar)
tarPath
Strict
lift $ $(logInfo) [i|Copied bindist to #{tarPath}|]
pure tarPath
build_mk workdir = workdir </> [rel|mk/build.mk|] build_mk workdir = workdir </> [rel|mk/build.mk|]
checkBuildConfig :: (MonadCatch m, MonadIO m) checkBuildConfig :: (MonadCatch m, MonadIO m)
=> Excepts => Excepts
'[FileDoesNotExistError, InvalidBuildConfig] '[FileDoesNotExistError , InvalidBuildConfig]
m m
() ()
checkBuildConfig = do checkBuildConfig = do
c <- case mbuildConfig of c <- case mbuildConfig of
Just bc -> do Just bc -> do
BL.toStrict <$> liftIOException BL.toStrict <$> liftIOException doesNotExistErrorType
doesNotExistErrorType (FileDoesNotExistError $ toFilePath bc)
(FileDoesNotExistError $ toFilePath bc) (liftIO $ readFile bc)
(liftIO $ readFile bc)
Nothing -> pure defaultConf Nothing -> pure defaultConf
let lines' = fmap T.strip . T.lines $ decUTF8Safe c let lines' = fmap T.strip . T.lines $ decUTF8Safe c
@@ -1261,6 +919,121 @@ Stage1Only = YES|]
-- | Compile a cabal from source. This behaves wrt symlinks and installation
-- the same as 'installCabalBin'.
compileCabal :: ( MonadReader Settings m
, MonadResource m
, MonadMask m
, MonadLogger m
, MonadIO m
, MonadFail m
)
=> GHCupDownloads
-> Version -- ^ version to install
-> Either Version (Path Abs) -- ^ version to bootstrap with
-> Maybe Int
-> Maybe (Path Abs)
-> PlatformRequest
-> Excepts
'[ AlreadyInstalled
, BuildFailed
, CopyError
, DigestError
, DownloadFailed
, NoDownload
, NotInstalled
, PatchFailed
, UnknownArchive
, TarDirDoesNotExist
#if !defined(TAR)
, ArchiveResult
#endif
]
m
()
compileCabal dls tver bghc jobs patchdir PlatformRequest{..} = do
lift $ $(logDebug) [i|Requested to compile: #{tver} with ghc-#{bghc}|]
Settings {dirs = Dirs {..}} <- lift ask
whenM
(lift (cabalInstalled tver) >>= \a -> liftIO $
handleIO (\_ -> pure False)
$ fmap (\x -> a && isSymbolicLink x)
-- ignore when the installation is a legacy cabal (binary, not symlink)
$ getSymbolicLinkStatus (toFilePath (binDir </> [rel|cabal|]))
)
$ (throwE $ AlreadyInstalled Cabal tver)
-- download source tarball
dlInfo <- preview (ix Cabal % ix tver % viSourceDL % _Just) dls ?? NoDownload
dl <- liftE $ downloadCached dlInfo Nothing
-- unpack
tmpUnpack <- lift mkGhcupTmpDir
liftE $ unpackToDir tmpUnpack dl
void $ liftIO $ darwinNotarization _rPlatform tmpUnpack
workdir <- maybe (pure tmpUnpack) (liftE . intoSubdir tmpUnpack) (view dlSubdir dlInfo)
cbin <- liftE $ runBuildAction tmpUnpack Nothing (compile workdir)
destFileName <- lift $ parseRel ("cabal-" <> verToBS tver)
handleIO (throwE . CopyError . show) $ liftIO $ copyFile
cbin
(binDir </> destFileName)
Overwrite
-- create symlink if this is the latest version
cVers <- lift $ fmap rights $ getInstalledCabals
let lInstCabal = headMay . reverse . sort $ cVers
when (maybe True (tver >=) lInstCabal) $ liftE $ setCabal tver
pure ()
where
compile :: (MonadReader Settings m, MonadThrow m, MonadLogger m, MonadIO m, MonadResource m)
=> Path Abs
-> Excepts '[ProcessError , PatchFailed] m (Path Abs)
compile workdir = do
lift $ $(logInfo) [i|Building (this may take a while)...|]
forM_ patchdir $ \dir -> liftE $ applyPatches dir workdir
ghcEnv <- case bghc of
Right path -> do
-- recover the version from /foo/ghc-6.5.4
bn <- basename path
let dn = toFilePath $ dirname path
let ver = snd . B.break (== _hyphen) . toFilePath $ bn
pure
[ ("GHC" , toFilePath path)
, ("GHC_PKG", dn <> "/" <> "ghc-pkg" <> ver)
, ("HADDOCK", dn <> "/" <> "haddock" <> ver)
]
Left bver -> do
let v' = verToBS bver
pure
[ ("GHC" , "ghc-" <> v')
, ("GHC_PKG", "ghc-pkg-" <> v')
, ("HADDOCK", "haddock-" <> v')
]
tmp <- lift withGHCupTmpDir
liftIO $ createDirRecursive newDirPerms (tmp </> [rel|bin|])
newEnv <- lift $ addToCurrentEnv (("PREFIX", toFilePath tmp) : ghcEnv)
lift $ $(logDebug) [i|Environment: #{newEnv}|]
lEM $ execLogged "./bootstrap.sh"
False
(maybe [] (\j -> ["-j", fS (show j)]) jobs)
(Just workdir)
(Just newEnv)
pure $ (tmp </> [rel|bin/cabal|])
--------------------- ---------------------
--[ Upgrade GHCup ]-- --[ Upgrade GHCup ]--

View File

@@ -226,7 +226,7 @@ getDownloads urlSource = do
else -- access in less than 5 minutes, re-use file else -- access in less than 5 minutes, re-use file
liftIO $ readFile json_file liftIO $ readFile json_file
else do else do
liftIO $ createDirRecursive' cacheDir liftIO $ createDirRecursive newDirPerms cacheDir
getModTime >>= \case getModTime >>= \case
Just modTime -> dlWithMod modTime json_file Just modTime -> dlWithMod modTime json_file
Nothing -> do Nothing -> do
@@ -330,7 +330,7 @@ download dli dest mfn
scheme = view (dlUri % uriSchemeL' % schemeBSL') dli scheme = view (dlUri % uriSchemeL' % schemeBSL') dli
cp = do cp = do
-- destination dir must exist -- destination dir must exist
liftIO $ createDirRecursive' dest liftIO $ hideError AlreadyExists $ createDirRecursive newDirPerms dest
destFile <- getDestFile destFile <- getDestFile
fromFile <- parseAbs path fromFile <- parseAbs path
liftIO $ copyFile fromFile destFile Strict liftIO $ copyFile fromFile destFile Strict
@@ -340,7 +340,7 @@ download dli dest mfn
lift $ $(logInfo) [i|downloading: #{uri'}|] lift $ $(logInfo) [i|downloading: #{uri'}|]
-- destination dir must exist -- destination dir must exist
liftIO $ createDirRecursive' dest liftIO $ hideError AlreadyExists $ createDirRecursive newDirPerms dest
destFile <- getDestFile destFile <- getDestFile
-- download -- download

View File

@@ -13,6 +13,7 @@ module GHCup.Download.IOStreams where
import GHCup.Download.Utils import GHCup.Download.Utils
import GHCup.Errors import GHCup.Errors
import GHCup.Types
import GHCup.Types.Optics import GHCup.Types.Optics
import GHCup.Types.JSON ( ) import GHCup.Types.JSON ( )
import GHCup.Utils.File import GHCup.Utils.File

View File

@@ -152,10 +152,3 @@ data ParseError = ParseError String
deriving Show deriving Show
instance Exception ParseError instance Exception ParseError
data UnexpectedListLength = UnexpectedListLength String
deriving Show
instance Exception UnexpectedListLength

View File

@@ -48,7 +48,7 @@ prettyRequirements :: Requirements -> T.Text
prettyRequirements Requirements {..} = prettyRequirements Requirements {..} =
let d = if not . null $ _distroPKGs let d = if not . null $ _distroPKGs
then then
"\n Please install the following distro packages: " "\n Install the following distro packages: "
<> T.intercalate " " _distroPKGs <> T.intercalate " " _distroPKGs
else "" else ""
n = if not . T.null $ _notes then "\n Note: " <> _notes else "" n = if not . T.null $ _notes then "\n Note: " <> _notes else ""

View File

@@ -1,6 +1,10 @@
{-# OPTIONS_GHC -Wno-orphans #-}
{-# LANGUAGE CPP #-} {-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-| {-|
Module : GHCup.Types Module : GHCup.Types
@@ -13,13 +17,15 @@ Portability : POSIX
-} -}
module GHCup.Types where module GHCup.Types where
import Control.Concurrent.MVar
import Data.ByteString ( ByteString )
import Data.Map.Strict ( Map ) import Data.Map.Strict ( Map )
import Data.Text ( Text ) import Data.Text ( Text )
import Data.Versions import Data.Versions
import HPath import HPath
import URI.ByteString import URI.ByteString
import System.Posix.Types
import qualified Data.Text as T
import qualified GHC.Generics as GHC import qualified GHC.Generics as GHC
@@ -76,7 +82,6 @@ type PlatformVersionSpec = Map (Maybe Versioning) DownloadInfo
data Tool = GHC data Tool = GHC
| Cabal | Cabal
| GHCup | GHCup
| HLS
deriving (Eq, GHC.Generic, Ord, Show) deriving (Eq, GHC.Generic, Ord, Show)
@@ -88,7 +93,7 @@ data VersionInfo = VersionInfo
, _viSourceDL :: Maybe DownloadInfo -- ^ source tarball , _viSourceDL :: Maybe DownloadInfo -- ^ source tarball
, _viArch :: ArchitectureSpec -- ^ descend for binary downloads per arch , _viArch :: ArchitectureSpec -- ^ descend for binary downloads per arch
} }
deriving (Eq, GHC.Generic, Show) deriving (Eq, Show)
-- | A tag. These are currently attached to a version of a tool. -- | A tag. These are currently attached to a version of a tool.
@@ -97,7 +102,7 @@ data Tag = Latest
| Prerelease | Prerelease
| Base PVP | Base PVP
| UnknownTag String -- ^ used for upwardscompat | UnknownTag String -- ^ used for upwardscompat
deriving (Ord, Eq, GHC.Generic, Show) -- FIXME: manual JSON instance deriving (Ord, Eq, Show) -- FIXME: manual JSON instance
data Architecture = A_64 data Architecture = A_64
@@ -110,15 +115,6 @@ data Architecture = A_64
| A_ARM64 | A_ARM64
deriving (Eq, GHC.Generic, Ord, Show) deriving (Eq, GHC.Generic, Ord, Show)
prettyArch :: Architecture -> String
prettyArch A_64 = "x86_64"
prettyArch A_32 = "i386"
prettyArch A_PowerPC = "powerpc"
prettyArch A_PowerPC64 = "powerpc64"
prettyArch A_Sparc = "sparc"
prettyArch A_Sparc64 = "sparc64"
prettyArch A_ARM = "arm"
prettyArch A_ARM64 = "aarch64"
data Platform = Linux LinuxDistro data Platform = Linux LinuxDistro
-- ^ must exit -- ^ must exit
@@ -127,11 +123,6 @@ data Platform = Linux LinuxDistro
| FreeBSD | FreeBSD
deriving (Eq, GHC.Generic, Ord, Show) deriving (Eq, GHC.Generic, Ord, Show)
prettyPlatfrom :: Platform -> String
prettyPlatfrom (Linux distro) = "linux-" ++ prettyDistro distro
prettyPlatfrom Darwin = "darwin"
prettyPlatfrom FreeBSD = "freebsd"
data LinuxDistro = Debian data LinuxDistro = Debian
| Ubuntu | Ubuntu
| Mint | Mint
@@ -148,19 +139,6 @@ data LinuxDistro = Debian
-- ^ must exit -- ^ must exit
deriving (Eq, GHC.Generic, Ord, Show) deriving (Eq, GHC.Generic, Ord, Show)
prettyDistro :: LinuxDistro -> String
prettyDistro Debian = "debian"
prettyDistro Ubuntu = "ubuntu"
prettyDistro Mint= "mint"
prettyDistro Fedora = "fedora"
prettyDistro CentOS = "centos"
prettyDistro RedHat = "redhat"
prettyDistro Alpine = "alpine"
prettyDistro AmazonLinux = "amazon"
prettyDistro Gentoo = "gentoo"
prettyDistro Exherbo = "exherbo"
prettyDistro UnknownLinux = "unknown"
-- | An encapsulation of a download. This can be used -- | An encapsulation of a download. This can be used
-- to download, extract and install a tool. -- to download, extract and install a tool.
@@ -169,7 +147,7 @@ data DownloadInfo = DownloadInfo
, _dlSubdir :: Maybe TarDir , _dlSubdir :: Maybe TarDir
, _dlHash :: Text , _dlHash :: Text
} }
deriving (Eq, GHC.Generic, Show) deriving (Eq, Show)
@@ -182,14 +160,35 @@ data DownloadInfo = DownloadInfo
-- | How to descend into a tar archive. -- | How to descend into a tar archive.
data TarDir = RealDir (Path Rel) data TarDir = RealDir (Path Rel)
| RegexDir String -- ^ will be compiled to regex, the first match will "win" | RegexDir String -- ^ will be compiled to regex, the first match will "win"
deriving (Eq, GHC.Generic, Show) deriving (Eq, Show)
-- | Where to fetch GHCupDownloads from. -- | Where to fetch GHCupDownloads from.
data URLSource = GHCupURL data URLSource = GHCupURL
| OwnSource URI | OwnSource URI
| OwnSpec GHCupInfo | OwnSpec GHCupInfo
deriving (GHC.Generic, Show) deriving Show
data ProcessError = NonZeroExit Int ByteString [ByteString]
| PTerminated ByteString [ByteString]
| PStopped ByteString [ByteString]
| NoSuchPid ByteString [ByteString]
deriving (Eq, Show)
data ProcState = PRunning ProcessID
| PExited (Either ProcessError ())
deriving Eq
type ExecCb = Bool -- verbose
-> Fd -- log file fd
-> Fd -- input fd to read from
-> MVar ProcState -- state of the producing process
-> ByteString -- log filename
-> IO ()
instance Show ExecCb where
show _ = "**ExecCb**"
data Settings = Settings data Settings = Settings
@@ -202,6 +201,7 @@ data Settings = Settings
-- set on app start -- set on app start
, dirs :: Dirs , dirs :: Dirs
, execCb :: ExecCb
} }
deriving Show deriving Show
@@ -248,12 +248,6 @@ data PlatformResult = PlatformResult
} }
deriving (Eq, Show) deriving (Eq, Show)
prettyPlatform :: PlatformResult -> String
prettyPlatform PlatformResult { _platform = plat, _distroVersion = Just v' }
= show plat <> ", " <> show v'
prettyPlatform PlatformResult { _platform = plat, _distroVersion = Nothing }
= show plat
data PlatformRequest = PlatformRequest data PlatformRequest = PlatformRequest
{ _rArch :: Architecture { _rArch :: Architecture
, _rPlatform :: Platform , _rPlatform :: Platform
@@ -261,13 +255,6 @@ data PlatformRequest = PlatformRequest
} }
deriving (Eq, Show) deriving (Eq, Show)
prettyPfReq :: PlatformRequest -> String
prettyPfReq (PlatformRequest arch plat ver) =
prettyArch arch ++ "-" ++ prettyPlatfrom plat ++ pver
where
pver = case ver of
Just v' -> "-" ++ (T.unpack $ prettyV v')
Nothing -> ""
-- | A GHC identified by the target platform triple -- | A GHC identified by the target platform triple
-- and the version. -- and the version.

View File

@@ -36,7 +36,7 @@ import GHCup.Utils.Prelude
import GHCup.Utils.String.QQ import GHCup.Utils.String.QQ
#if !defined(TAR) #if !defined(TAR)
import Codec.Archive hiding ( Directory ) import Codec.Archive
#endif #endif
import Control.Applicative import Control.Applicative
import Control.Exception.Safe import Control.Exception.Safe
@@ -301,150 +301,6 @@ cabalSet = do
-- | Get all installed hls, by matching on
-- @~\/.ghcup\/bin/haskell-language-server-wrapper-<\hlsver\>@.
getInstalledHLSs :: (MonadReader Settings m, MonadIO m, MonadCatch m)
=> m [Either (Path Rel) Version]
getInstalledHLSs = do
Settings { dirs = Dirs {..} } <- ask
bins <- liftIO $ handleIO (\_ -> pure []) $ findFiles
binDir
(makeRegexOpts compExtended
execBlank
([s|^haskell-language-server-wrapper-.*$|] :: ByteString)
)
vs <- forM bins $ \f ->
case
fmap
version
(fmap decUTF8Safe . B.stripPrefix "haskell-language-server-wrapper-" . toFilePath $ f)
of
Just (Right r) -> pure $ Right r
Just (Left _) -> pure $ Left f
Nothing -> pure $ Left f
pure $ vs
-- | Whether the given HLS version is installed.
hlsInstalled :: (MonadIO m, MonadReader Settings m, MonadCatch m) => Version -> m Bool
hlsInstalled ver = do
vers <- fmap rights $ getInstalledHLSs
pure $ elem ver $ vers
-- Return the currently set hls version, if any.
hlsSet :: (MonadReader Settings m, MonadIO m, MonadThrow m, MonadCatch m) => m (Maybe Version)
hlsSet = do
Settings {dirs = Dirs {..}} <- ask
let hlsBin = binDir </> [rel|haskell-language-server-wrapper|]
liftIO $ handleIO' NoSuchThing (\_ -> pure $ Nothing) $ do
broken <- isBrokenSymlink hlsBin
if broken
then pure Nothing
else do
link <- readSymbolicLink $ toFilePath hlsBin
Just <$> linkVersion link
where
linkVersion :: MonadThrow m => ByteString -> m Version
linkVersion bs = do
t <- throwEither $ E.decodeUtf8' bs
throwEither $ MP.parse parser "" t
where
parser =
MP.chunk "haskell-language-server-wrapper-" *> version'
-- | Return the GHC versions the currently selected HLS supports.
hlsGHCVersions :: ( MonadReader Settings m
, MonadIO m
, MonadThrow m
, MonadCatch m
)
=> m [Version]
hlsGHCVersions = do
h <- hlsSet
vers <- forM h $ \h' -> do
bins <- hlsServerBinaries h'
pure $ fmap
(\bin ->
version
. decUTF8Safe
. fromJust
. B.stripPrefix "haskell-language-server-"
. head
. B.split _tilde
. toFilePath
$ bin
)
bins
pure . rights . concat . maybeToList $ vers
-- | Get all server binaries for an hls version, if any.
hlsServerBinaries :: (MonadReader Settings m, MonadIO m)
=> Version
-> m [Path Rel]
hlsServerBinaries ver = do
Settings { dirs = Dirs {..} } <- ask
liftIO $ handleIO (\_ -> pure []) $ findFiles
binDir
(makeRegexOpts
compExtended
execBlank
([s|^haskell-language-server-.*~|] <> escapeVerRex ver <> [s|$|] :: ByteString
)
)
-- | Get the wrapper binary for an hls version, if any.
hlsWrapperBinary :: (MonadReader Settings m, MonadThrow m, MonadIO m)
=> Version
-> m (Maybe (Path Rel))
hlsWrapperBinary ver = do
Settings { dirs = Dirs {..} } <- ask
wrapper <- liftIO $ handleIO (\_ -> pure []) $ findFiles
binDir
(makeRegexOpts
compExtended
execBlank
([s|^haskell-language-server-wrapper-|] <> escapeVerRex ver <> [s|$|] :: ByteString
)
)
case wrapper of
[] -> pure $ Nothing
[x] -> pure $ Just x
_ -> throwM $ UnexpectedListLength
"There were multiple hls wrapper binaries for a single version"
-- | Get all binaries for an hls version, if any.
hlsAllBinaries :: (MonadReader Settings m, MonadIO m, MonadThrow m) => Version -> m [Path Rel]
hlsAllBinaries ver = do
hls <- hlsServerBinaries ver
wrapper <- hlsWrapperBinary ver
pure (maybeToList wrapper ++ hls)
-- | Get the active symlinks for hls.
hlsSymlinks :: (MonadReader Settings m, MonadIO m, MonadCatch m) => m [Path Rel]
hlsSymlinks = do
Settings { dirs = Dirs {..} } <- ask
oldSyms <- liftIO $ handleIO (\_ -> pure []) $ findFiles
binDir
(makeRegexOpts compExtended
execBlank
([s|^haskell-language-server-.*$|] :: ByteString)
)
filterM
( fmap (== SymbolicLink)
. liftIO
. getFileType
. (binDir </>)
)
oldSyms
----------------------------------------- -----------------------------------------
@@ -694,7 +550,7 @@ make args workdir = do
spaths <- catMaybes . fmap parseAbs <$> (liftIO getSearchPath) spaths <- catMaybes . fmap parseAbs <$> (liftIO getSearchPath)
has_gmake <- isJust <$> (liftIO $ searchPath spaths [rel|gmake|]) has_gmake <- isJust <$> (liftIO $ searchPath spaths [rel|gmake|])
let mymake = if has_gmake then "gmake" else "make" let mymake = if has_gmake then "gmake" else "make"
execLogged mymake True args [rel|ghc-make|] workdir Nothing execLogged mymake True args workdir Nothing
-- | Try to apply patches in order. Fails with 'PatchFailed' -- | Try to apply patches in order. Fails with 'PatchFailed'
@@ -740,8 +596,8 @@ getChangeLog dls tool (Right tag) =
-- 1. the build directory, depending on the KeepDirs setting -- 1. the build directory, depending on the KeepDirs setting
-- 2. the install destination, depending on whether the build failed -- 2. the install destination, depending on whether the build failed
runBuildAction :: (Show (V e), MonadReader Settings m, MonadIO m, MonadMask m) runBuildAction :: (Show (V e), MonadReader Settings m, MonadIO m, MonadMask m)
=> Path Abs -- ^ build directory (cleaned up depending on Settings) => Path Abs -- ^ build directory
-> Maybe (Path Abs) -- ^ dir to *always* clean up on exception -> Maybe (Path Abs) -- ^ install location (e.g. for GHC)
-> Excepts e m a -> Excepts e m a
-> Excepts '[BuildFailed] m a -> Excepts '[BuildFailed] m a
runBuildAction bdir instdir action = do runBuildAction bdir instdir action = do
@@ -765,25 +621,3 @@ runBuildAction bdir instdir action = do
when (keepDirs == Never || keepDirs == Errors) $ liftIO $ deleteDirRecursive when (keepDirs == Never || keepDirs == Errors) $ liftIO $ deleteDirRecursive
bdir bdir
pure v pure v
-- | More permissive version of 'createDirRecursive'. This doesn't
-- error when the destination is a symlink to a directory.
createDirRecursive' :: Path b -> IO ()
createDirRecursive' p =
handleIO (\e -> if isAlreadyExistsError e then isSymlinkDir e else throwIO e)
. createDirRecursive newDirPerms
$ p
where
isSymlinkDir e = do
ft <- getFileType p
case ft of
SymbolicLink -> do
rp <- canonicalizePath p
rft <- getFileType rp
case rft of
Directory -> pure ()
_ -> throwIO e
_ -> throwIO e

View File

@@ -72,14 +72,6 @@ import qualified "unix-bytestring" System.Posix.IO.ByteString
as SPIB as SPIB
data ProcessError = NonZeroExit Int ByteString [ByteString]
| PTerminated ByteString [ByteString]
| PStopped ByteString [ByteString]
| NoSuchPid ByteString [ByteString]
deriving Show
data CapturedProcess = CapturedProcess data CapturedProcess = CapturedProcess
{ _exitCode :: ExitCode { _exitCode :: ExitCode
, _stdOut :: ByteString , _stdOut :: ByteString
@@ -121,30 +113,31 @@ execLogged :: (MonadReader Settings m, MonadIO m, MonadThrow m)
=> ByteString -- ^ thing to execute => ByteString -- ^ thing to execute
-> Bool -- ^ whether to search PATH for the thing -> Bool -- ^ whether to search PATH for the thing
-> [ByteString] -- ^ args for the thing -> [ByteString] -- ^ args for the thing
-> Path Rel -- ^ log filename
-> Maybe (Path Abs) -- ^ optionally chdir into this -> Maybe (Path Abs) -- ^ optionally chdir into this
-> Maybe [(ByteString, ByteString)] -- ^ optional environment -> Maybe [(ByteString, ByteString)] -- ^ optional environment
-> m (Either ProcessError ()) -> m (Either ProcessError ())
execLogged exe spath args lfile chdir env = do execLogged exe spath args chdir env = do
Settings {dirs = Dirs {..}, ..} <- ask Settings {dirs = Dirs {..}, ..} <- ask
logfile <- (logsDir </>) <$> parseRel (toFilePath lfile <> ".log") logfile <- (logsDir </>) <$> parseRel (lfile <> ".log")
liftIO $ bracket (createFile (toFilePath logfile) newFilePerms) liftIO $ bracket (createFile (toFilePath logfile) newFilePerms)
closeFd closeFd
(action verbose) (action verbose execCb)
where where
action verbose fd = do lfile = fromMaybe exe $ BS.stripPrefix "./" exe
action verbose cb 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
done <- newEmptyMVar done <- newEmptyMVar
liftIO $ HPath.IO.writeFile [HPath.abs|/home/jule/git/ghcup-hs/cb.log|] Nothing "execLogged1"
void void
$ forkIO $ forkIO
$ EX.handle (\(_ :: IOException) -> pure ()) $ EX.handle (\(_ :: IOException) -> pure ())
$ flip EX.finally (putMVar done ()) $ flip EX.finally (putMVar done ())
$ (if verbose $ (do
then tee fd stdoutRead liftIO $ HPath.IO.writeFile [HPath.abs|/home/jule/git/ghcup-hs/cb.log|] Nothing "execLogged"
else printToRegion fd stdoutRead 6 pState cb verbose fd stdoutRead pState lfile)
)
-- fork the subprocess -- fork the subprocess
pid <- SPPB.forkProcess $ do pid <- SPPB.forkProcess $ do
@@ -157,115 +150,57 @@ execLogged exe spath args lfile chdir env = do
maybe (pure ()) (changeWorkingDirectory . toFilePath) chdir maybe (pure ()) (changeWorkingDirectory . toFilePath) chdir
void $ SPPB.executeFile exe spath args env void $ SPPB.executeFile exe spath args env
putMVar pState (PRunning pid)
closeFd stdoutWrite closeFd stdoutWrite
-- wait for the subprocess to finish -- wait for the subprocess to finish
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) void $ swapMVar pState (PExited e)
void $ race (takeMVar done) (threadDelay (1000000 * 3)) void $ race (takeMVar done) (threadDelay (1000000 * 3))
closeFd stdoutRead closeFd stdoutRead
pure e pure e
tee :: Fd -> Fd -> IO ()
tee fileFd fdIn = readTilEOF lineAction fdIn
where readLineTilEOF :: MonadIO m => (ByteString -> m a) -> Fd -> m ()
lineAction :: ByteString -> IO () readLineTilEOF ~action' fd' = go mempty
lineAction bs' = do where
void $ SPIB.fdWrite fileFd (bs' <> "\n") go bs' = do
void $ SPIB.fdWrite stdOutput (bs' <> "\n") (bs, rest, eof) <- readLine fd' bs'
if eof
then liftIO $ ioError (mkIOError eofErrorType "" Nothing Nothing)
else (void $ action' bs) >> go rest
-- Reads fdIn and logs the output in a continous scrolling area
-- of 'size' terminal lines. Also writes to a log file.
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
(\(ex :: SomeException) -> do
ps <- liftIO $ takeMVar pState
when (ps == True) (forM_ rs (liftIO . closeConsoleRegion))
throw ex
)
$ readTilEOF (lineAction rs) fdIn
where -- Consecutively read from Fd in 512 chunks until we hit
-- action to perform line by line -- newline or EOF.
-- TODO: do this with vty for efficiency readLine :: MonadIO m
lineAction :: (MonadMask m, MonadIO m) => Fd -- ^ input file descriptor
=> Seq ConsoleRegion -> ByteString -- ^ rest buffer (read across newline)
-> ByteString -> m (ByteString, ByteString, Bool) -- ^ (full line, rest, eof)
-> StateT (Seq ByteString) m () readLine fd = \inBs -> go inBs
lineAction rs = \bs' -> do where
void $ liftIO $ SPIB.fdWrite fileFd (bs' <> "\n") go inBs = do
modify (swapRegs bs') -- if buffer is not empty, process it first
regs <- get mbs <- if BS.length inBs == 0
liftIO $ forM_ (Sq.zip regs rs) $ \(bs, r) -> setConsoleRegion r $ do -- otherwise attempt read
w <- consoleWidth then liftIO
return $ handleIO (\e -> if isEOFError e then pure Nothing else ioError e)
. T.pack $ fmap Just
. color Blue $ SPIB.fdRead fd 512
. T.unpack else pure $ Just inBs
. decUTF8Safe case mbs of
. trim w Nothing -> pure ("", "", True)
. (\b -> "[ " <> toFilePath lfile <> " ] " <> b) Just bs -> do
$ bs -- 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
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 :: Int -> ByteString -> ByteString
trim w = \bs -> if
| BS.length bs > w && w > 5 -> BS.take (w - 4) bs <> "..."
| otherwise -> bs
-- Consecutively read from Fd in 512 chunks until we hit
-- newline or EOF.
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
go inBs = do
-- if buffer is not empty, process it first
mbs <- if BS.length inBs == 0
-- otherwise attempt read
then liftIO
$ handleIO (\e -> if isEOFError e then pure Nothing else ioError e)
$ fmap Just
$ SPIB.fdRead fd 512
else pure $ Just inBs
case mbs of
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 ~action' fd' = go mempty
where
go bs' = do
(bs, rest, eof) <- readLine fd' bs'
if eof
then liftIO $ ioError (mkIOError eofErrorType "" Nothing Nothing)
else (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
@@ -450,3 +385,76 @@ chmod_777 (toFilePath -> fp) = do
$(logDebug) [i|chmod 777 #{fp}|] $(logDebug) [i|chmod 777 #{fp}|]
liftIO $ setFileMode fp exe_mode liftIO $ setFileMode fp exe_mode
-- | The default callback for logging/printing on 'execLogged'.
defExecCb :: ExecCb
defExecCb verbose fd stdoutRead pState lfile = if verbose
then tee fd stdoutRead
else printToRegion fd stdoutRead 6
where
tee :: Fd -> Fd -> IO ()
tee fileFd fdIn = readLineTilEOF 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 :: Fd -> Fd -> Int -> IO ()
printToRegion fileFd fdIn size = do
void $ displayConsoleRegions $ do
rs <-
liftIO
. fmap Sq.fromList
. sequence
. replicate size
. openConsoleRegion
$ Linear
flip runStateT mempty
$ handle
(\(ex :: SomeException) -> do
let closeEventually = readMVar pState >>= \case
PExited (Right _) -> forM_ rs (liftIO . closeConsoleRegion)
_ -> threadDelay 500 >> closeEventually
void $ liftIO $ race closeEventually (threadDelay (1000000 * 3))
throw ex
)
$ readLineTilEOF (lineAction rs) fdIn
where
-- action to perform line by line
-- TODO: do this with vty for efficiency
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 -> "[ " <> lfile <> " ] " <> b)
$ 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 :: Int -> ByteString -> ByteString
trim w = \bs -> if
| BS.length bs > w && w > 5 -> BS.take (w - 4) bs <> "..."
| otherwise -> bs

View File

@@ -15,7 +15,6 @@ Here we define our main logger.
module GHCup.Utils.Logger where module GHCup.Utils.Logger where
import GHCup.Types import GHCup.Types
import GHCup.Utils
import Control.Monad import Control.Monad
import Control.Monad.IO.Class import Control.Monad.IO.Class
@@ -70,7 +69,7 @@ initGHCupFileLogging context = do
Settings {dirs = Dirs {..}} <- ask Settings {dirs = Dirs {..}} <- ask
let logfile = logsDir </> context let logfile = logsDir </> context
liftIO $ do liftIO $ do
createDirRecursive' logsDir createDirRecursive newDirPerms logsDir
hideError doesNotExistErrorType $ deleteFile logfile hideError doesNotExistErrorType $ deleteFile logfile
createRegularFile newFilePerms logfile createRegularFile newFilePerms logfile
pure logfile pure logfile

View File

@@ -31,13 +31,11 @@ import Data.ByteString ( ByteString )
import Data.String import Data.String
import Data.Text ( Text ) import Data.Text ( Text )
import Data.Versions import Data.Versions
import Data.Word8
import Haskus.Utils.Types.List import Haskus.Utils.Types.List
import Haskus.Utils.Variant.Excepts import Haskus.Utils.Variant.Excepts
import System.IO.Error import System.IO.Error
import System.Posix.Env.ByteString ( getEnvironment ) import System.Posix.Env.ByteString ( getEnvironment )
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.Text as T import qualified Data.Text as T
@@ -277,13 +275,3 @@ decUTF8Safe = E.decodeUtf8With E.lenientDecode
decUTF8Safe' :: L.ByteString -> Text decUTF8Safe' :: L.ByteString -> Text
decUTF8Safe' = TL.toStrict . TLE.decodeUtf8With E.lenientDecode decUTF8Safe' = TL.toStrict . TLE.decodeUtf8With E.lenientDecode
-- | Escape a version for use in regex
escapeVerRex :: Version -> ByteString
escapeVerRex = B.pack . go . B.unpack . verToBS
where
go [] = []
go (x : xs) | x == _period = [_backslash, _period] ++ go xs
| otherwise = x : go xs

View File

@@ -22,11 +22,11 @@ import qualified Data.Text as T
-- | This reflects the API version of the YAML. -- | This reflects the API version of the YAML.
ghcupURL :: URI ghcupURL :: URI
ghcupURL = [uri|https://www.haskell.org/ghcup/data/ghcup-0.0.3.yaml|] ghcupURL = [uri|https://www.haskell.org/ghcup/data/ghcup-0.0.2.yaml|]
-- | The current ghcup version. -- | The current ghcup version.
ghcUpVer :: PVP ghcUpVer :: PVP
ghcUpVer = [pver|0.1.11|] ghcUpVer = [pver|0.1.10|]
-- | ghcup version as numeric string. -- | ghcup version as numeric string.
numericVer :: String numericVer :: String

View File

@@ -1,193 +0,0 @@
{-# OPTIONS_GHC -Wno-orphans #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
module GHCup.ArbitraryTypes where
import GHCup.Types
import Data.ByteString ( ByteString )
import Data.Versions
import Data.List.NonEmpty
import HPath
import Test.QuickCheck
import Test.QuickCheck.Arbitrary.ADT ( ToADTArbitrary )
import Test.QuickCheck.Arbitrary.Generic
import URI.ByteString
import qualified Data.Map.Strict as M
import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import qualified Data.Text.Lazy as T
( toStrict )
import qualified Data.Text.Lazy.Builder as B
import qualified Data.Text.Lazy.Builder.Int as B
-----------------
--[ utilities ]--
-----------------
intToText :: Integral a => a -> T.Text
intToText = T.toStrict . B.toLazyText . B.decimal
genVer :: Gen (Int, Int, Int)
genVer =
(\x y z -> (getPositive x, getPositive y, getPositive z))
<$> arbitrary
<*> arbitrary
<*> arbitrary
instance ToADTArbitrary GHCupInfo
----------------------
--[ base arbitrary ]--
----------------------
instance Arbitrary T.Text where
arbitrary = fmap T.pack $ listOf $ elements ['a' .. 'z']
shrink xs = T.pack <$> shrink (T.unpack xs)
instance Arbitrary (NonEmpty Word) where
arbitrary = fmap fromList $ listOf1 $ arbitrary
-- utf8 encoded bytestring
instance Arbitrary ByteString where
arbitrary = fmap (E.encodeUtf8 . T.pack) $ listOf $ elements ['a' .. 'z']
---------------------
--[ uri arbitrary ]--
---------------------
instance Arbitrary Scheme where
arbitrary = oneof [ Scheme <$> pure "http", Scheme <$> pure "https" ]
instance Arbitrary Host where
arbitrary = genericArbitrary
shrink = genericShrink
instance Arbitrary Port where
arbitrary = genericArbitrary
shrink = genericShrink
instance Arbitrary (URIRef Absolute) where
arbitrary =
URI <$> arbitrary <*> pure Nothing <*> arbitrary <*> (Query <$> pure []) <*> pure Nothing
-------------------------
--[ version arbitrary ]--
-------------------------
instance Arbitrary Mess where
arbitrary = do
(x, y, z) <- genVer
pure
$ either (error . show) id
$ mess
$ (intToText x <> "." <> intToText y <> "." <> intToText z)
instance Arbitrary Version where
arbitrary = do
(x, y, z) <- genVer
pure
$ either (error . show) id
$ version
$ (intToText x <> "." <> intToText y <> "." <> intToText z)
instance Arbitrary SemVer where
arbitrary = do
(x, y, z) <- genVer
pure
$ either (error . show) id
$ semver
$ (intToText x <> "." <> intToText y <> "." <> intToText z)
instance Arbitrary PVP where
arbitrary = do
(x, y, z) <- genVer
pure
$ either (error . show) id
$ pvp
$ (intToText x <> "." <> intToText y <> "." <> intToText z)
instance Arbitrary Versioning where
arbitrary = Ideal <$> arbitrary
-----------------------
--[ ghcup arbitrary ]--
-----------------------
instance Arbitrary Requirements where
arbitrary = genericArbitrary
shrink = genericShrink
instance Arbitrary DownloadInfo where
arbitrary = genericArbitrary
shrink = genericShrink
instance Arbitrary LinuxDistro where
arbitrary = genericArbitrary
shrink = genericShrink
instance Arbitrary Platform where
arbitrary = genericArbitrary
shrink = genericShrink
instance Arbitrary Tag where
arbitrary = genericArbitrary
shrink = genericShrink
instance Arbitrary Architecture where
arbitrary = genericArbitrary
shrink = genericShrink
instance Arbitrary VersionInfo where
arbitrary = genericArbitrary
shrink = genericShrink
instance Arbitrary (Path Rel) where
arbitrary =
(either (error . show) id . parseRel . E.encodeUtf8 . T.pack)
<$> (listOf1 $ elements ['a' .. 'z'])
instance Arbitrary TarDir where
arbitrary = genericArbitrary
shrink = genericShrink
instance Arbitrary Tool where
arbitrary = genericArbitrary
shrink = genericShrink
instance Arbitrary GHCupInfo where
arbitrary = genericArbitrary
shrink = genericShrink
-- our maps are nested... the default size easily blows up most ppls ram
instance {-# OVERLAPS #-} Arbitrary v => Arbitrary (M.Map Tool v) where
arbitrary = resize 8 $ M.fromList <$> arbitrary
instance {-# OVERLAPS #-} Arbitrary v => Arbitrary (M.Map (Maybe Version) v) where
arbitrary = resize 8 $ M.fromList <$> arbitrary
instance {-# OVERLAPS #-} Arbitrary v => Arbitrary (M.Map Platform v) where
arbitrary = resize 8 $ M.fromList <$> arbitrary
instance {-# OVERLAPS #-} Arbitrary v => Arbitrary (M.Map (Maybe Versioning) v) where
arbitrary = resize 8 $ M.fromList <$> arbitrary

View File

@@ -1,17 +0,0 @@
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeApplications #-}
module GHCup.Types.JSONSpec where
import GHCup.ArbitraryTypes ()
import GHCup.Types
import GHCup.Types.JSON ()
import Test.Aeson.GenericSpecs
import Test.Hspec
spec :: Spec
spec = do
roundtripAndGoldenSpecs (Proxy @GHCupInfo)

View File

@@ -1,12 +0,0 @@
{-# LANGUAGE OverloadedStrings #-}
import Test.Hspec.Runner
import Test.Hspec.Formatters
import qualified Spec
main :: IO ()
main =
hspecWith
defaultConfig { configFormatter = Just progress }
$ Spec.spec

4
test/MyLibTest.hs Normal file
View File

@@ -0,0 +1,4 @@
module Main (main) where
main :: IO ()
main = putStrLn "Test suite not yet implemented."

View File

@@ -1,2 +0,0 @@
-- file test/Spec.hs
{-# OPTIONS_GHC -F -pgmF hspec-discover -optF --module-name=Spec #-}