module Iris.Tool (
need,
Tool (..),
ToolSelector (..),
defaultToolSelector,
ToolCheckResult (..),
ToolCheckError (..),
ToolCheckException (..),
checkTool,
) where
import Control.Exception (Exception, throwIO)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Foldable (traverse_)
import Data.String (IsString (..))
import Data.Text (Text)
import System.Directory (findExecutable)
import System.Process (readProcess)
import qualified Data.Text as Text
data Tool = Tool
{ Tool -> Text
toolName :: Text
, Tool -> Maybe ToolSelector
toolSelector :: Maybe ToolSelector
}
instance IsString Tool where
fromString :: String -> Tool
fromString :: String -> Tool
fromString String
s =
Tool
{ toolName :: Text
toolName = forall a. IsString a => String -> a
fromString String
s
, toolSelector :: Maybe ToolSelector
toolSelector = forall a. Maybe a
Nothing
}
data ToolSelector = ToolSelector
{ ToolSelector -> Text -> Bool
toolSelectorFunction :: Text -> Bool
, ToolSelector -> Maybe Text
toolSelectorVersionArg :: Maybe Text
}
defaultToolSelector :: ToolSelector
defaultToolSelector :: ToolSelector
defaultToolSelector =
ToolSelector
{ toolSelectorFunction :: Text -> Bool
toolSelectorFunction = forall a b. a -> b -> a
const Bool
True
, toolSelectorVersionArg :: Maybe Text
toolSelectorVersionArg = forall a. Maybe a
Nothing
}
data ToolCheckResult
=
ToolCheckError ToolCheckError
|
ToolOk
deriving stock
( Int -> ToolCheckResult -> ShowS
[ToolCheckResult] -> ShowS
ToolCheckResult -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ToolCheckResult] -> ShowS
$cshowList :: [ToolCheckResult] -> ShowS
show :: ToolCheckResult -> String
$cshow :: ToolCheckResult -> String
showsPrec :: Int -> ToolCheckResult -> ShowS
$cshowsPrec :: Int -> ToolCheckResult -> ShowS
Show
, ToolCheckResult -> ToolCheckResult -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ToolCheckResult -> ToolCheckResult -> Bool
$c/= :: ToolCheckResult -> ToolCheckResult -> Bool
== :: ToolCheckResult -> ToolCheckResult -> Bool
$c== :: ToolCheckResult -> ToolCheckResult -> Bool
Eq
)
data ToolCheckError
=
ToolNotFound Text
|
ToolWrongVersion Text
deriving stock
( Int -> ToolCheckError -> ShowS
[ToolCheckError] -> ShowS
ToolCheckError -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ToolCheckError] -> ShowS
$cshowList :: [ToolCheckError] -> ShowS
show :: ToolCheckError -> String
$cshow :: ToolCheckError -> String
showsPrec :: Int -> ToolCheckError -> ShowS
$cshowsPrec :: Int -> ToolCheckError -> ShowS
Show
, ToolCheckError -> ToolCheckError -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ToolCheckError -> ToolCheckError -> Bool
$c/= :: ToolCheckError -> ToolCheckError -> Bool
== :: ToolCheckError -> ToolCheckError -> Bool
$c== :: ToolCheckError -> ToolCheckError -> Bool
Eq
)
checkTool :: Tool -> IO ToolCheckResult
checkTool :: Tool -> IO ToolCheckResult
checkTool Tool{Maybe ToolSelector
Text
toolSelector :: Maybe ToolSelector
toolName :: Text
toolSelector :: Tool -> Maybe ToolSelector
toolName :: Tool -> Text
..} =
String -> IO (Maybe String)
findExecutable (Text -> String
Text.unpack Text
toolName) forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Maybe String
Nothing -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ ToolCheckError -> ToolCheckResult
ToolCheckError forall a b. (a -> b) -> a -> b
$ Text -> ToolCheckError
ToolNotFound Text
toolName
Just String
exe -> case Maybe ToolSelector
toolSelector of
Maybe ToolSelector
Nothing -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ToolCheckResult
ToolOk
Just ToolSelector{Maybe Text
Text -> Bool
toolSelectorVersionArg :: Maybe Text
toolSelectorFunction :: Text -> Bool
toolSelectorVersionArg :: ToolSelector -> Maybe Text
toolSelectorFunction :: ToolSelector -> Text -> Bool
..} -> case Maybe Text
toolSelectorVersionArg of
Maybe Text
Nothing -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ToolCheckResult
ToolOk
Just Text
versionArg -> do
String
toolVersionOutput <- String -> [String] -> String -> IO String
readProcess String
exe [Text -> String
Text.unpack Text
versionArg] String
""
let version :: Text
version = Text -> Text
Text.strip forall a b. (a -> b) -> a -> b
$ String -> Text
Text.pack String
toolVersionOutput
if Text -> Bool
toolSelectorFunction Text
version
then forall (f :: * -> *) a. Applicative f => a -> f a
pure ToolCheckResult
ToolOk
else forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ ToolCheckError -> ToolCheckResult
ToolCheckError forall a b. (a -> b) -> a -> b
$ Text -> ToolCheckError
ToolWrongVersion Text
version
newtype ToolCheckException = ToolCheckException ToolCheckError
deriving stock
( Int -> ToolCheckException -> ShowS
[ToolCheckException] -> ShowS
ToolCheckException -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ToolCheckException] -> ShowS
$cshowList :: [ToolCheckException] -> ShowS
show :: ToolCheckException -> String
$cshow :: ToolCheckException -> String
showsPrec :: Int -> ToolCheckException -> ShowS
$cshowsPrec :: Int -> ToolCheckException -> ShowS
Show
)
deriving newtype
( ToolCheckException -> ToolCheckException -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ToolCheckException -> ToolCheckException -> Bool
$c/= :: ToolCheckException -> ToolCheckException -> Bool
== :: ToolCheckException -> ToolCheckException -> Bool
$c== :: ToolCheckException -> ToolCheckException -> Bool
Eq
)
deriving anyclass
( Show ToolCheckException
Typeable ToolCheckException
SomeException -> Maybe ToolCheckException
ToolCheckException -> String
ToolCheckException -> SomeException
forall e.
Typeable e
-> Show e
-> (e -> SomeException)
-> (SomeException -> Maybe e)
-> (e -> String)
-> Exception e
displayException :: ToolCheckException -> String
$cdisplayException :: ToolCheckException -> String
fromException :: SomeException -> Maybe ToolCheckException
$cfromException :: SomeException -> Maybe ToolCheckException
toException :: ToolCheckException -> SomeException
$ctoException :: ToolCheckException -> SomeException
Exception
)
need :: MonadIO m => [Tool] -> m ()
need :: forall (m :: * -> *). MonadIO m => [Tool] -> m ()
need = forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ forall a b. (a -> b) -> a -> b
$ \Tool
tool ->
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$
Tool -> IO ToolCheckResult
checkTool Tool
tool forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
ToolCheckResult
ToolOk -> forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
ToolCheckError ToolCheckError
toolErr -> forall e a. Exception e => e -> IO a
throwIO forall a b. (a -> b) -> a -> b
$ ToolCheckError -> ToolCheckException
ToolCheckException ToolCheckError
toolErr