module Shrun.IO.Types
( Stderr (..),
CommandResult (..),
ReadHandleResult (..),
readHandleResultToStderr,
readHandle,
)
where
import Data.Time.Relative (RelativeTime)
import Effects.FileSystem.HandleReader
( MonadHandleReader (hIsClosed),
hGetNonBlocking,
hIsReadable,
)
import Shrun.Data.Text (UnlinedText)
import Shrun.Data.Text qualified as ShrunText
import Shrun.Prelude
newtype Stderr = MkStderr {Stderr -> List UnlinedText
unStderr :: List UnlinedText}
deriving stock (Stderr -> Stderr -> Bool
(Stderr -> Stderr -> Bool)
-> (Stderr -> Stderr -> Bool) -> Eq Stderr
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Stderr -> Stderr -> Bool
== :: Stderr -> Stderr -> Bool
$c/= :: Stderr -> Stderr -> Bool
/= :: Stderr -> Stderr -> Bool
Eq, Int -> Stderr -> ShowS
[Stderr] -> ShowS
Stderr -> String
(Int -> Stderr -> ShowS)
-> (Stderr -> String) -> ([Stderr] -> ShowS) -> Show Stderr
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Stderr -> ShowS
showsPrec :: Int -> Stderr -> ShowS
$cshow :: Stderr -> String
show :: Stderr -> String
$cshowList :: [Stderr] -> ShowS
showList :: [Stderr] -> ShowS
Show)
data CommandResult
= CommandSuccess RelativeTime
| CommandFailure RelativeTime Stderr
deriving stock (CommandResult -> CommandResult -> Bool
(CommandResult -> CommandResult -> Bool)
-> (CommandResult -> CommandResult -> Bool) -> Eq CommandResult
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CommandResult -> CommandResult -> Bool
== :: CommandResult -> CommandResult -> Bool
$c/= :: CommandResult -> CommandResult -> Bool
/= :: CommandResult -> CommandResult -> Bool
Eq, Int -> CommandResult -> ShowS
[CommandResult] -> ShowS
CommandResult -> String
(Int -> CommandResult -> ShowS)
-> (CommandResult -> String)
-> ([CommandResult] -> ShowS)
-> Show CommandResult
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CommandResult -> ShowS
showsPrec :: Int -> CommandResult -> ShowS
$cshow :: CommandResult -> String
show :: CommandResult -> String
$cshowList :: [CommandResult] -> ShowS
showList :: [CommandResult] -> ShowS
Show)
data ReadHandleResult
=
ReadErr (List UnlinedText)
|
ReadSuccess (List UnlinedText)
|
ReadNoData
deriving stock (ReadHandleResult -> ReadHandleResult -> Bool
(ReadHandleResult -> ReadHandleResult -> Bool)
-> (ReadHandleResult -> ReadHandleResult -> Bool)
-> Eq ReadHandleResult
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ReadHandleResult -> ReadHandleResult -> Bool
== :: ReadHandleResult -> ReadHandleResult -> Bool
$c/= :: ReadHandleResult -> ReadHandleResult -> Bool
/= :: ReadHandleResult -> ReadHandleResult -> Bool
Eq, Int -> ReadHandleResult -> ShowS
[ReadHandleResult] -> ShowS
ReadHandleResult -> String
(Int -> ReadHandleResult -> ShowS)
-> (ReadHandleResult -> String)
-> ([ReadHandleResult] -> ShowS)
-> Show ReadHandleResult
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ReadHandleResult -> ShowS
showsPrec :: Int -> ReadHandleResult -> ShowS
$cshow :: ReadHandleResult -> String
show :: ReadHandleResult -> String
$cshowList :: [ReadHandleResult] -> ShowS
showList :: [ReadHandleResult] -> ShowS
Show)
instance Semigroup ReadHandleResult where
ReadSuccess List UnlinedText
l <> :: ReadHandleResult -> ReadHandleResult -> ReadHandleResult
<> ReadHandleResult
_ = List UnlinedText -> ReadHandleResult
ReadSuccess List UnlinedText
l
ReadHandleResult
_ <> ReadSuccess List UnlinedText
r = List UnlinedText -> ReadHandleResult
ReadSuccess List UnlinedText
r
ReadErr List UnlinedText
l <> ReadHandleResult
_ = List UnlinedText -> ReadHandleResult
ReadErr List UnlinedText
l
ReadHandleResult
_ <> ReadErr List UnlinedText
r = List UnlinedText -> ReadHandleResult
ReadErr List UnlinedText
r
ReadHandleResult
_ <> ReadHandleResult
_ = ReadHandleResult
ReadNoData
instance Monoid ReadHandleResult where
mempty :: ReadHandleResult
mempty = ReadHandleResult
ReadNoData
readHandleResultToStderr :: ReadHandleResult -> Stderr
readHandleResultToStderr :: ReadHandleResult -> Stderr
readHandleResultToStderr ReadHandleResult
ReadNoData = List UnlinedText -> Stderr
MkStderr (List UnlinedText -> Stderr) -> List UnlinedText -> Stderr
forall a b. (a -> b) -> a -> b
$ Text -> List UnlinedText
ShrunText.fromText Text
"<No data>"
readHandleResultToStderr (ReadErr List UnlinedText
errs) = List UnlinedText -> Stderr
MkStderr List UnlinedText
errs
readHandleResultToStderr (ReadSuccess List UnlinedText
errs) = List UnlinedText -> Stderr
MkStderr List UnlinedText
errs
readHandle ::
( HasCallStack,
MonadCatch m,
MonadHandleReader m
) =>
Int ->
Handle ->
m ReadHandleResult
readHandle :: forall (m :: Type -> Type).
(HasCallStack, MonadCatch m, MonadHandleReader m) =>
Int -> Handle -> m ReadHandleResult
readHandle Int
blockSize Handle
handle = do
m ReadHandleResult -> m (Either SomeException ReadHandleResult)
forall (m :: Type -> Type) a.
(HasCallStack, MonadCatch m) =>
m a -> m (Either SomeException a)
tryAny m ReadHandleResult
readHandle' m (Either SomeException ReadHandleResult)
-> (Either SomeException ReadHandleResult -> ReadHandleResult)
-> m ReadHandleResult
forall (f :: Type -> Type) a b. Functor f => f a -> (a -> b) -> f b
<&> \case
Left SomeException
ex -> List UnlinedText -> ReadHandleResult
ReadErr (List UnlinedText -> ReadHandleResult)
-> List UnlinedText -> ReadHandleResult
forall a b. (a -> b) -> a -> b
$ Text -> List UnlinedText
ShrunText.fromText (Text -> List UnlinedText) -> Text -> List UnlinedText
forall a b. (a -> b) -> a -> b
$ Text
"HandleException: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> SomeException -> Text
forall e. Exception e => e -> Text
displayExceptiont SomeException
ex
Right ReadHandleResult
x -> ReadHandleResult
x
where
readHandle' :: m ReadHandleResult
readHandle' =
m (Maybe Text)
nothingIfReady m (Maybe Text)
-> (Maybe Text -> m ReadHandleResult) -> m ReadHandleResult
forall a b. m a -> (a -> m b) -> m b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Just Text
err -> ReadHandleResult -> m ReadHandleResult
forall a. a -> m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (ReadHandleResult -> m ReadHandleResult)
-> ReadHandleResult -> m ReadHandleResult
forall a b. (a -> b) -> a -> b
$ List UnlinedText -> ReadHandleResult
ReadErr (List UnlinedText -> ReadHandleResult)
-> List UnlinedText -> ReadHandleResult
forall a b. (a -> b) -> a -> b
$ Text -> List UnlinedText
ShrunText.fromText Text
err
Maybe Text
Nothing ->
Handle -> Int -> m ByteString
forall (m :: Type -> Type).
(MonadHandleReader m, HasCallStack) =>
Handle -> Int -> m ByteString
hGetNonBlocking Handle
handle Int
blockSize m ByteString
-> (ByteString -> ReadHandleResult) -> m ReadHandleResult
forall (f :: Type -> Type) a b. Functor f => f a -> (a -> b) -> f b
<&> \case
ByteString
"" -> ReadHandleResult
ReadNoData
ByteString
bs -> List UnlinedText -> ReadHandleResult
ReadSuccess (Text -> List UnlinedText
ShrunText.fromText (Text -> List UnlinedText) -> Text -> List UnlinedText
forall a b. (a -> b) -> a -> b
$ ByteString -> Text
decodeUtf8Lenient ByteString
bs)
nothingIfReady :: m (Maybe Text)
nothingIfReady = do
Bool
isClosed <- Handle -> m Bool
forall (m :: Type -> Type).
(MonadHandleReader m, HasCallStack) =>
Handle -> m Bool
hIsClosed Handle
handle
if Bool
isClosed
then Maybe Text -> m (Maybe Text)
forall a. a -> m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Maybe Text -> m (Maybe Text)) -> Maybe Text -> m (Maybe Text)
forall a b. (a -> b) -> a -> b
$ Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"Handle closed"
else do
Bool
isReadable <- Handle -> m Bool
forall (m :: Type -> Type).
(MonadHandleReader m, HasCallStack) =>
Handle -> m Bool
hIsReadable Handle
handle
if Bool -> Bool
not Bool
isReadable
then Maybe Text -> m (Maybe Text)
forall a. a -> m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Maybe Text -> m (Maybe Text)) -> Maybe Text -> m (Maybe Text)
forall a b. (a -> b) -> a -> b
$ Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"Handle is not readable"
else Maybe Text -> m (Maybe Text)
forall a. a -> m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure Maybe Text
forall a. Maybe a
Nothing