Advance Install menu implements functionality.

This commit is contained in:
Luis Morillo 2024-03-01 09:17:25 +01:00
parent 40f94fa016
commit cd8d13ff2b
4 changed files with 129 additions and 26 deletions

View File

@ -18,7 +18,7 @@ import GHCup.Types.Optics ( getDirs, getPlatformReq )
import GHCup.Types hiding ( LeanAppState(..) ) import GHCup.Types hiding ( LeanAppState(..) )
import GHCup.Utils import GHCup.Utils
import GHCup.OptParse.Common (logGHCPostRm) import GHCup.OptParse.Common (logGHCPostRm)
import GHCup.Prelude ( decUTF8Safe ) import GHCup.Prelude ( decUTF8Safe, runBothE' )
import GHCup.Prelude.Logger import GHCup.Prelude.Logger
import GHCup.Prelude.Process import GHCup.Prelude.Process
import GHCup.Prompts import GHCup.Prompts
@ -173,12 +173,19 @@ withIOAction action = do
pure (updateList data' as) pure (updateList data' as)
Left err -> throwIO $ userError err Left err -> throwIO $ userError err
install' :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m, Alternative m) installWithOptions :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m, Alternative m)
=> (Int, ListResult) => AdvanceInstall.InstallOptions
-> (Int, ListResult)
-> m (Either String ()) -> m (Either String ())
install' (_, ListResult {..}) = do installWithOptions opts (_, ListResult {..}) = do
AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask AppState { ghcupInfo = GHCupInfo { _ghcupDownloads = dls }} <- ask
let
misolated = opts ^. AdvanceInstall.isolateDirL
shouldIsolate = maybe GHCupInternal IsolateDir (opts ^. AdvanceInstall.isolateDirL)
shouldForce = opts ^. AdvanceInstall.forceInstallL
shouldSet = opts ^. AdvanceInstall.instSetL
extraArgs = opts ^. AdvanceInstall.addConfArgsL
v = GHCTargetVersion lCross lVer
let run = let run =
runResourceT runResourceT
. runE . runE
@ -208,6 +215,7 @@ install' (_, ListResult {..}) = do
, UnsupportedSetupCombo , UnsupportedSetupCombo
, DistroNotFound , DistroNotFound
, NoCompatibleArch , NoCompatibleArch
, InstallSetError
] ]
run (do run (do
@ -216,20 +224,81 @@ install' (_, ListResult {..}) = do
dirs <- lift getDirs dirs <- lift getDirs
case lTool of case lTool of
GHC -> do GHC -> do
let vi = getVersionInfo (GHCTargetVersion lCross lVer) GHC dls let vi = getVersionInfo v GHC dls
liftE $ installGHCBin (GHCTargetVersion lCross lVer) GHCupInternal False [] $> (vi, dirs, ce) case opts ^. AdvanceInstall.instBindistL of
Nothing -> do
liftE $
runBothE'
(installGHCBin v shouldIsolate shouldForce extraArgs)
(when (shouldSet && isNothing misolated) (liftE $ void $ setGHC v SetGHCOnly Nothing))
pure (vi, dirs, ce)
Just uri -> do
liftE $
runBothE'
(installGHCBindist
(DownloadInfo uri (Just $ RegexDir "ghc-.*") "" Nothing Nothing)
v
shouldIsolate
shouldForce
extraArgs)
(when (shouldSet && isNothing misolated) (liftE $ void $ setGHC v SetGHCOnly Nothing))
pure (vi, dirs, ce)
Cabal -> do Cabal -> do
let vi = getVersionInfo (GHCTargetVersion lCross lVer) Cabal dls let vi = getVersionInfo v Cabal dls
liftE $ installCabalBin lVer GHCupInternal False $> (vi, dirs, ce) case opts ^. AdvanceInstall.instBindistL of
Nothing -> do
liftE $
runBothE'
(installCabalBin lVer shouldIsolate shouldForce)
(when (shouldSet && isNothing misolated) (liftE $ void $ setCabal lVer))
pure (vi, dirs, ce)
Just uri -> do
liftE $
runBothE'
(installCabalBindist (DownloadInfo uri Nothing "" Nothing Nothing) lVer shouldIsolate shouldForce)
(when (shouldSet && isNothing misolated) (liftE $ void $ setCabal lVer))
pure (vi, dirs, ce)
GHCup -> do GHCup -> do
let vi = snd <$> getLatest dls GHCup let vi = snd <$> getLatest dls GHCup
liftE $ upgradeGHCup Nothing False False $> (vi, dirs, ce) liftE $ upgradeGHCup Nothing False False $> (vi, dirs, ce)
HLS -> do HLS -> do
let vi = getVersionInfo (GHCTargetVersion lCross lVer) HLS dls let vi = getVersionInfo v HLS dls
liftE $ installHLSBin lVer GHCupInternal False $> (vi, dirs, ce) case opts ^. AdvanceInstall.instBindistL of
Nothing -> do
liftE $
runBothE'
(installHLSBin lVer shouldIsolate shouldForce)
(when (shouldSet && isNothing misolated) (liftE $ void $ setHLS lVer SetHLSOnly Nothing))
pure (vi, dirs, ce)
Just uri -> do
liftE $
runBothE'
(installHLSBindist
(DownloadInfo uri (if isWindows then Nothing else Just (RegexDir "haskell-language-server-*")) "" Nothing Nothing)
lVer
shouldIsolate
shouldForce)
(when (shouldSet && isNothing misolated) (liftE $ void $ setHLS lVer SetHLSOnly Nothing))
pure (vi, dirs, ce)
Stack -> do Stack -> do
let vi = getVersionInfo (GHCTargetVersion lCross lVer) Stack dls let vi = getVersionInfo v Stack dls
liftE $ installStackBin lVer GHCupInternal False $> (vi, dirs, ce) case opts ^. AdvanceInstall.instBindistL of
Nothing -> do
liftE $
runBothE'
(installStackBin lVer shouldIsolate shouldForce)
(when (shouldSet && isNothing misolated) (liftE $ void $ setStack lVer))
pure (vi, dirs, ce)
Just uri -> do
liftE $
runBothE'
(installStackBindist (DownloadInfo uri Nothing "" Nothing Nothing) lVer shouldIsolate shouldForce)
(when (shouldSet && isNothing misolated) (liftE $ void $ setStack lVer))
pure (vi, dirs, ce)
) )
>>= \case >>= \case
VRight (vi, Dirs{..}, Just ce) -> do VRight (vi, Dirs{..}, Just ce) -> do
@ -256,6 +325,9 @@ install' (_, ListResult {..}) = do
VLeft e -> pure $ Left $ prettyHFError e <> "\n" VLeft e -> pure $ Left $ prettyHFError e <> "\n"
<> "Also check the logs in ~/.ghcup/logs" <> "Also check the logs in ~/.ghcup/logs"
install' :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m, Alternative m)
=> (Int, ListResult) -> m (Either String ())
install' = installWithOptions (AdvanceInstall.InstallOptions Nothing False Nothing False [])
set' :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m, Alternative m) set' :: (MonadReader AppState m, MonadIO m, MonadThrow m, MonadFail m, MonadMask m, MonadUnliftIO m, Alternative m)
=> (Int, ListResult) => (Int, ListResult)

View File

@ -148,10 +148,13 @@ advanceInstallHandler ev = do
case (ev, focusedElement) of case (ev, focusedElement) of
(_ , Nothing) -> pure () (_ , Nothing) -> pure ()
(VtyEvent (Vty.EvKey k m), Just n) (VtyEvent (Vty.EvKey k m), Just n)
| k == exitKey | k == exitKey
&& m == mods && m == mods
&& n `elem` [Menu.fieldName button | button <- buttons] && n `elem` [Menu.fieldName button | button <- buttons]
-> mode .= ContextPanel -> mode .= ContextPanel
(VtyEvent (Vty.EvKey Vty.KEnter []), Just (MenuElement Common.OkButton)) -> do
let iopts = ctx ^. Menu.menuStateL
Actions.withIOAction $ Actions.installWithOptions iopts
_ -> Common.zoom advanceInstallMenu $ AdvanceInstall.handler ev _ -> Common.zoom advanceInstallMenu $ AdvanceInstall.handler ev
compileGHCHandler :: BrickEvent Name e -> EventM Name BrickState () compileGHCHandler :: BrickEvent Name e -> EventM Name BrickState ()

View File

@ -14,7 +14,18 @@
{-# LANGUAGE InstanceSigs #-} {-# LANGUAGE InstanceSigs #-}
{-# OPTIONS_GHC -Wno-incomplete-patterns #-} {-# OPTIONS_GHC -Wno-incomplete-patterns #-}
module GHCup.Brick.Widgets.Menus.AdvanceInstall (InstallOptions, AdvanceInstallMenu, create, handler, draw) where module GHCup.Brick.Widgets.Menus.AdvanceInstall (
InstallOptions (..),
AdvanceInstallMenu,
create,
handler,
draw,
instBindistL,
instSetL,
isolateDirL,
forceInstallL,
addConfArgsL,
) where
import GHCup.Brick.Widgets.Menu (Menu) import GHCup.Brick.Widgets.Menu (Menu)
import qualified GHCup.Brick.Widgets.Menu as Menu import qualified GHCup.Brick.Widgets.Menu as Menu
@ -35,6 +46,8 @@ import Data.Bifunctor (Bifunctor(..))
import Data.Function ((&)) import Data.Function ((&))
import Optics ((.~)) import Optics ((.~))
import Data.Char (isSpace) import Data.Char (isSpace)
import System.FilePath (isValid, isAbsolute, normalise)
import GHCup.Prelude (stripNewlineEnd)
data InstallOptions = InstallOptions data InstallOptions = InstallOptions
{ instBindist :: Maybe URI { instBindist :: Maybe URI
@ -71,9 +84,14 @@ create k = Menu.createMenu AdvanceInstallBox initialState k [ok] fields
filepathValidator :: T.Text -> Either Menu.ErrorMessage (Maybe FilePath) filepathValidator :: T.Text -> Either Menu.ErrorMessage (Maybe FilePath)
filepathValidator i = filepathValidator i =
case not $ emptyEditor i of case not $ emptyEditor i of
True -> Right . Just . T.unpack $ i True -> absolutePathParser (T.unpack i)
False -> Right Nothing False -> Right Nothing
absolutePathParser :: FilePath -> Either Menu.ErrorMessage (Maybe FilePath)
absolutePathParser f = case isValid f && isAbsolute f of
True -> Right . Just . stripNewlineEnd . normalise $ f
False -> Left "Please enter a valid absolute filepath."
additionalValidator :: T.Text -> Either Menu.ErrorMessage [T.Text] additionalValidator :: T.Text -> Either Menu.ErrorMessage [T.Text]
additionalValidator = Right . T.split isSpace additionalValidator = Right . T.split isSpace

View File

@ -36,9 +36,10 @@ import Data.Function ((&))
import Optics ((.~)) import Optics ((.~))
import Data.Char (isSpace) import Data.Char (isSpace)
import Data.Versions (Version, version) import Data.Versions (Version, version)
import System.FilePath (isPathSeparator) import System.FilePath (isPathSeparator, isValid, isAbsolute, normalise)
import Control.Applicative (Alternative((<|>))) import Control.Applicative (Alternative((<|>)))
import Text.Read (readEither) import Text.Read (readEither)
import GHCup.Prelude (stripNewlineEnd)
data CompileGHCOptions = CompileGHCOptions data CompileGHCOptions = CompileGHCOptions
{ _bootstrapGhc :: Either Version FilePath { _bootstrapGhc :: Either Version FilePath
@ -84,10 +85,11 @@ create k = Menu.createMenu CompileGHCBox initialState k buttons fields
case not $ emptyEditor i of case not $ emptyEditor i of
True -> True ->
let readVersion = bimap (const "Not a valid version") Left (version (T.init i)) -- Brick adds \n at the end, hence T.init let readVersion = bimap (const "Not a valid version") Left (version (T.init i)) -- Brick adds \n at the end, hence T.init
readPath readPath = do
= if isPathSeparator (T.head i) mfilepath <- filepathV i
then pure $ Right (T.unpack i) case mfilepath of
else Left "Not an absolute Path" Nothing -> Left "Invalid Empty value"
Just f -> Right (Right f)
in if T.any isPathSeparator i in if T.any isPathSeparator i
then readPath then readPath
else readVersion else readVersion
@ -113,7 +115,15 @@ create k = Menu.createMenu CompileGHCBox initialState k buttons fields
in first T.pack $ x <|> y in first T.pack $ x <|> y
filepathV :: T.Text -> Either Menu.ErrorMessage (Maybe FilePath) filepathV :: T.Text -> Either Menu.ErrorMessage (Maybe FilePath)
filepathV = whenEmpty Nothing (Right . Just . T.unpack) filepathV i =
case not $ emptyEditor i of
True -> absolutePathParser (T.unpack i)
False -> Right Nothing
absolutePathParser :: FilePath -> Either Menu.ErrorMessage (Maybe FilePath)
absolutePathParser f = case isValid f && isAbsolute f of
True -> Right . Just . stripNewlineEnd . normalise $ f
False -> Left "Please enter a valid absolute filepath."
additionalValidator :: T.Text -> Either Menu.ErrorMessage [T.Text] additionalValidator :: T.Text -> Either Menu.ErrorMessage [T.Text]
additionalValidator = Right . T.split isSpace additionalValidator = Right . T.split isSpace