{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}
module Common.IO
( sh,
sh_,
trySh,
tryShAndReturnStdErr,
tryShExitCode,
tryTimeSh,
)
where
import Common.RefinedUtils
import Common.Utils
import qualified Control.Exception as Ex
import Data.Functor (($>))
import qualified Data.Text as T
import qualified System.Clock as C
import qualified System.Exit as Exit
import qualified System.Process as P
sh :: T.Text -> Maybe FilePath -> IO T.Text
sh :: Text -> Maybe FilePath -> IO Text
sh cmd :: Text
cmd fp :: Maybe FilePath
fp = FilePath -> Text
T.pack (FilePath -> Text) -> IO FilePath -> IO Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> CreateProcess -> FilePath -> IO FilePath
P.readCreateProcess CreateProcess
proc ""
where
proc :: CreateProcess
proc = (FilePath -> CreateProcess
P.shell (Text -> FilePath
T.unpack Text
cmd)) {cwd :: Maybe FilePath
P.cwd = Maybe FilePath
fp}
sh_ :: T.Text -> Maybe FilePath -> IO ()
sh_ :: Text -> Maybe FilePath -> IO ()
sh_ cmd :: Text
cmd fp :: Maybe FilePath
fp = CreateProcess -> FilePath -> IO FilePath
P.readCreateProcess CreateProcess
proc "" IO FilePath -> () -> IO ()
forall (f :: * -> *) a b. Functor f => f a -> b -> f b
$> ()
where
proc :: CreateProcess
proc = (FilePath -> CreateProcess
P.shell (Text -> FilePath
T.unpack Text
cmd)) {cwd :: Maybe FilePath
P.cwd = Maybe FilePath
fp}
shExitCode :: T.Text -> Maybe FilePath -> IO (Exit.ExitCode, String, String)
shExitCode :: Text -> Maybe FilePath -> IO (ExitCode, FilePath, FilePath)
shExitCode cmd :: Text
cmd path :: Maybe FilePath
path = CreateProcess -> FilePath -> IO (ExitCode, FilePath, FilePath)
P.readCreateProcessWithExitCode CreateProcess
proc ""
where
proc :: CreateProcess
proc = (FilePath -> CreateProcess
P.shell (Text -> FilePath
T.unpack Text
cmd)) {cwd :: Maybe FilePath
P.cwd = Maybe FilePath
path}
trySh :: T.Text -> Maybe FilePath -> IO (Either Ex.SomeException T.Text)
trySh :: Text -> Maybe FilePath -> IO (Either SomeException Text)
trySh cmd :: Text
cmd path :: Maybe FilePath
path = IO Text -> IO (Either SomeException Text)
forall e a. Exception e => IO a -> IO (Either e a)
Ex.try (Text -> Maybe FilePath -> IO Text
sh Text
cmd Maybe FilePath
path)
tryShAndReturnStdErr :: T.Text -> Maybe FilePath -> IO (Either T.Text T.Text)
tryShAndReturnStdErr :: Text -> Maybe FilePath -> IO (Either Text Text)
tryShAndReturnStdErr cmd :: Text
cmd path :: Maybe FilePath
path = do
(code :: ExitCode
code, _, err :: FilePath
err) <- Text -> Maybe FilePath -> IO (ExitCode, FilePath, FilePath)
shExitCode Text
cmd Maybe FilePath
path
Either Text Text -> IO (Either Text Text)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text Text -> IO (Either Text Text))
-> Either Text Text -> IO (Either Text Text)
forall a b. (a -> b) -> a -> b
$ case ExitCode
code of
Exit.ExitSuccess -> Text -> Either Text Text
forall a b. b -> Either a b
Right (Text -> Either Text Text) -> Text -> Either Text Text
forall a b. (a -> b) -> a -> b
$ Text -> Text
T.strip (FilePath -> Text
T.pack FilePath
err)
Exit.ExitFailure _ ->
Text -> Either Text Text
forall a b. a -> Either a b
Left (Text -> Either Text Text) -> Text -> Either Text Text
forall a b. (a -> b) -> a -> b
$
"Error running `"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
cmd
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "`: "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
T.strip (FilePath -> Text
T.pack FilePath
err)
tryShExitCode :: T.Text -> Maybe FilePath -> IO (Either T.Text T.Text)
tryShExitCode :: Text -> Maybe FilePath -> IO (Either Text Text)
tryShExitCode cmd :: Text
cmd path :: Maybe FilePath
path = do
(code :: ExitCode
code, out :: FilePath
out, err :: FilePath
err) <- Text -> Maybe FilePath -> IO (ExitCode, FilePath, FilePath)
shExitCode Text
cmd Maybe FilePath
path
Either Text Text -> IO (Either Text Text)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text Text -> IO (Either Text Text))
-> Either Text Text -> IO (Either Text Text)
forall a b. (a -> b) -> a -> b
$ case ExitCode
code of
Exit.ExitSuccess -> Text -> Either Text Text
forall a b. b -> Either a b
Right (Text -> Either Text Text) -> Text -> Either Text Text
forall a b. (a -> b) -> a -> b
$ Text -> Text
T.strip (FilePath -> Text
T.pack FilePath
out)
Exit.ExitFailure _ ->
Text -> Either Text Text
forall a b. a -> Either a b
Left (Text -> Either Text Text) -> Text -> Either Text Text
forall a b. (a -> b) -> a -> b
$
"Error running `"
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
cmd
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "`: "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
T.strip (FilePath -> Text
T.pack FilePath
err)
tryTimeSh ::
T.Text ->
Maybe FilePath ->
IO (Either (RNonNegative Int, T.Text) (RNonNegative Int, T.Text))
tryTimeSh :: Text
-> Maybe FilePath
-> IO (Either (RNonNegative Int, Text) (RNonNegative Int, Text))
tryTimeSh cmd :: Text
cmd path :: Maybe FilePath
path = do
TimeSpec
start <- Clock -> IO TimeSpec
C.getTime Clock
C.Monotonic
Either Text Text
res <- Text -> Maybe FilePath -> IO (Either Text Text)
tryShExitCode Text
cmd Maybe FilePath
path
TimeSpec
end <- Clock -> IO TimeSpec
C.getTime Clock
C.Monotonic
let diff :: RNonNegative Int
diff = TimeSpec -> TimeSpec -> RNonNegative Int
diffTime TimeSpec
start TimeSpec
end
Either (RNonNegative Int, Text) (RNonNegative Int, Text)
-> IO (Either (RNonNegative Int, Text) (RNonNegative Int, Text))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either (RNonNegative Int, Text) (RNonNegative Int, Text)
-> IO (Either (RNonNegative Int, Text) (RNonNegative Int, Text)))
-> Either (RNonNegative Int, Text) (RNonNegative Int, Text)
-> IO (Either (RNonNegative Int, Text) (RNonNegative Int, Text))
forall a b. (a -> b) -> a -> b
$ (Text -> (RNonNegative Int, Text))
-> Either Text Text
-> Either (RNonNegative Int, Text) (RNonNegative Int, Text)
forall (f :: * -> * -> *) a b.
Bifunctor f =>
(a -> b) -> f a a -> f b b
monoBimap (RNonNegative Int
diff,) Either Text Text
res