module System.Process.Dmc
        (run,
        shell,
        call,
        quote,
        join) where


import qualified System.Process as P
import System.Exit
import System.Process.TypeDmc
import Data.List
import Data.Coerce


{- | run executable with args
    
    waits 
    
    'Left' 'String' indicates error     -}
run::Cwd -> Cmd String -> [Arg String] -> IO (Either String ())
run :: Cwd -> Cmd String -> [Arg String] -> IO (Either String ())
run = (Cwd -> Cmd String -> [Arg String] -> CreateProcess)
-> Cwd -> Cmd String -> [Arg String] -> IO (Either String ())
runCommon Cwd -> Cmd String -> [Arg String] -> CreateProcess
forall a p.
Coercible a String =>
p -> Cmd String -> [a] -> CreateProcess
fn1
        where fn1 :: p -> Cmd String -> [a] -> CreateProcess
fn1 cwd1 :: p
cwd1 (Cmd sh1 :: String
sh1) arg1 :: [a]
arg1 = String -> [String] -> CreateProcess
P.proc String
sh1 ([String] -> CreateProcess) -> [String] -> CreateProcess
forall a b. (a -> b) -> a -> b
$ a -> String
forall a b. Coercible a b => a -> b
coerce (a -> String) -> [a] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [a]
arg1

{- | run shell cmd

    waits       
    
    'Left' 'String' indicates error     -}
shell::Cwd -> Cmd String -> IO (Either String ())
shell :: Cwd -> Cmd String -> IO (Either String ())
shell cwd0 :: Cwd
cwd0 cmd0 :: Cmd String
cmd0 = (Cwd -> Cmd String -> [Arg String] -> CreateProcess)
-> Cwd -> Cmd String -> [Arg String] -> IO (Either String ())
runCommon Cwd -> Cmd String -> [Arg String] -> CreateProcess
forall p p. p -> Cmd String -> p -> CreateProcess
fn1 Cwd
cwd0 Cmd String
cmd0 []
        where fn1 :: p -> Cmd String -> p -> CreateProcess
fn1 cwd1 :: p
cwd1 (Cmd sh1 :: String
sh1) _ = String -> CreateProcess
P.shell String
sh1


runCommon::(Cwd -> Cmd String -> [Arg String] -> P.CreateProcess) ->
    Cwd -> Cmd String -> [Arg String] ->
            IO (Either String ())
runCommon :: (Cwd -> Cmd String -> [Arg String] -> CreateProcess)
-> Cwd -> Cmd String -> [Arg String] -> IO (Either String ())
runCommon cp0 :: Cwd -> Cmd String -> [Arg String] -> CreateProcess
cp0 cwd0 :: Cwd
cwd0 sh0 :: Cmd String
sh0 arg0 :: [Arg String]
arg0 = do
            (in1 :: Maybe Handle
in1, out1 :: Maybe Handle
out1, err1 :: Maybe Handle
err1, ph1 :: ProcessHandle
ph1) <- CreateProcess
-> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
P.createProcess CreateProcess
p2
            ExitCode
code1 <- ProcessHandle -> IO ExitCode
P.waitForProcess ProcessHandle
ph1
            case ExitCode
code1 of
                ExitSuccess -> Either String () -> IO (Either String ())
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either String () -> IO (Either String ()))
-> Either String () -> IO (Either String ())
forall a b. (a -> b) -> a -> b
$ () -> Either String ()
forall a b. b -> Either a b
Right ()
                ExitFailure i :: Int
i -> Either String () -> IO (Either String ())
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either String () -> IO (Either String ()))
-> Either String () -> IO (Either String ())
forall a b. (a -> b) -> a -> b
$ String -> Either String ()
forall a b. a -> Either a b
Left (String -> Either String ()) -> String -> Either String ()
forall a b. (a -> b) -> a -> b
$ (String, Int, Cwd, Cmd String, [Arg String]) -> String
forall a. Show a => a -> String
show ("cmd failed", Int
i, Cwd
cwd0, Cmd String
sh0, [Arg String]
arg0)
        where p1 :: CreateProcess
p1 = Cwd -> Cmd String -> [Arg String] -> CreateProcess
cp0 Cwd
cwd0 Cmd String
sh0 [Arg String]
arg0
              Cwd cwd1 :: String
cwd1 = Cwd
cwd0
              p2 :: CreateProcess
p2 = CreateProcess
p1 {
                cwd :: Maybe String
P.cwd = String -> Maybe String
forall a. a -> Maybe a
Just String
cwd1
              }


-- | call cmd, get output 
call::Cwd -> Cmd String -> [Arg String] -> IO (ExitCode, Stdout, Stderr)
call :: Cwd -> Cmd String -> [Arg String] -> IO (ExitCode, Stdout, Stderr)
call (Cwd cwd0 :: String
cwd0) (Cmd sh0 :: String
sh0) arg0 :: [Arg String]
arg0 =
    CreateProcess -> String -> IO (ExitCode, String, String)
P.readCreateProcessWithExitCode CreateProcess
p2 "" IO (ExitCode, String, String)
-> ((ExitCode, String, String) -> IO (ExitCode, Stdout, Stderr))
-> IO (ExitCode, Stdout, Stderr)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= 
    \(code1 :: ExitCode
code1, std1 :: String
std1, err1 :: String
err1) ->
        (ExitCode, Stdout, Stderr) -> IO (ExitCode, Stdout, Stderr)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ExitCode
code1, String -> Stdout
Stdout String
std1, String -> Stderr
Stderr String
err1) 
        where p1 :: CreateProcess
p1 = String -> [String] -> CreateProcess
P.proc String
sh0 ([String] -> CreateProcess) -> [String] -> CreateProcess
forall a b. (a -> b) -> a -> b
$ Arg String -> String
forall a b. Coercible a b => a -> b
coerce (Arg String -> String) -> [Arg String] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Arg String]
arg0
              p2 :: CreateProcess
p2 = CreateProcess
p1 {
                cwd :: Maybe String
P.cwd = String -> Maybe String
forall a. a -> Maybe a
Just String
cwd0
              }


-- | enclose 'String' in \"\"
quote::String -> String
quote :: String -> String
quote s0 :: String
s0 = "\"" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s0 String -> String -> String
forall a. [a] -> [a] -> [a]
++ "\""


-- | join 'String' with \" \" : useful to construct 'shell' cmd 
join::[String] -> String
join :: [String] -> String
join = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate " "