axel-0.0.6: src/Axel/Eff/Process.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Axel.Eff.Process where
import Control.Monad.Freer
( type (~>)
, Eff
, LastMember
, Member
, interpretM
, send
)
import Data.Singletons (Sing, SingI, sing)
import Data.Singletons.TH (singletons)
import qualified System.Environment (getArgs)
import System.Exit (ExitCode)
import qualified System.Process (readProcessWithExitCode)
import qualified System.Process.Typed (proc, runProcess)
$(singletons
[d|
data StreamSpecification = CreateStreams
| InheritStreams
|])
type family StreamsHandler (a :: StreamSpecification) (f :: * -> *) :: *
type instance StreamsHandler 'CreateStreams f =
String -> f (ExitCode, String, String)
type instance StreamsHandler 'InheritStreams f = f ExitCode
type ProcessRunner' (streamSpec :: StreamSpecification) f
= forall streamsHandler. (streamsHandler ~ StreamsHandler streamSpec f) =>
streamsHandler
type ProcessRunnerPrimitive (streamSpec :: StreamSpecification) (f :: * -> *)
= FilePath -> [String] -> ProcessRunner' streamSpec f
type ProcessRunner (streamSpec :: StreamSpecification) (f :: * -> *)
= (SingI streamSpec) =>
ProcessRunner' streamSpec f
data Process r where
GetArgs :: Process [String]
RunProcessCreatingStreams
:: FilePath -> [String] -> String -> Process (ExitCode, String, String)
RunProcessInheritingStreams :: FilePath -> [String] -> Process ExitCode
getArgs :: (Member Process effs) => Eff effs [String]
getArgs = send GetArgs
runProcessCreatingStreams ::
(Member Process effs) => ProcessRunnerPrimitive 'CreateStreams (Eff effs)
runProcessCreatingStreams cmd args stdin =
send $ RunProcessCreatingStreams cmd args stdin
runProcessInheritingStreams ::
(Member Process effs) => ProcessRunnerPrimitive 'InheritStreams (Eff effs)
runProcessInheritingStreams cmd args =
send $ RunProcessInheritingStreams cmd args
runEff :: (LastMember IO effs) => Eff (Process ': effs) ~> Eff effs
runEff =
interpretM
(\case
GetArgs -> System.Environment.getArgs
RunProcessCreatingStreams cmd args stdin ->
System.Process.readProcessWithExitCode cmd args stdin
RunProcessInheritingStreams cmd args ->
System.Process.Typed.runProcess (System.Process.Typed.proc cmd args))
runProcess ::
forall (streamSpec :: StreamSpecification) effs. (Member Process effs)
=> FilePath
-> [String]
-> ProcessRunner streamSpec (Eff effs)
runProcess cmd args =
case sing :: Sing streamSpec of
SCreateStreams -> runProcessCreatingStreams cmd args
SInheritStreams -> runProcessInheritingStreams cmd args