packages feed

hinit-0.2.0: src/Hinit/Process.hs

module Hinit.Process where

import Control.Effect.Lift
import Control.Effect.Terminal
import Control.Effect.Throw
import Control.Monad
import Data.Maybe
import Data.Text.Prettyprint.Doc
import Hinit.Errors
import Hinit.Types
import Hinit.Utils
import Path
import System.Directory
import System.Exit
import System.IO (hGetContents)
import System.Process

vcsInitProc :: VCS -> Maybe CreateProcess
vcsInitProc Git = Just $ proc "git" ["init"]
vcsInitProc Mercurial = Just $ proc "hg" ["init"]
vcsInitProc Darcs = Just $ proc "darcs" ["init"]
vcsInitProc Pijul = Just $ proc "pijul" ["init"]
vcsInitProc (Other _) = Nothing

guessExecutableExists :: Has (Lift IO) sig m => CmdSpec -> m Bool
guessExecutableExists ShellCommand {} = pure True
guessExecutableExists (RawCommand exe _) = isJust <$> sendIO (findExecutable exe)

initVCS ::
  ( Has (Lift IO) sig m,
    Has (Throw ProcessExitFailure) sig m,
    Has Terminal sig m
  ) =>
  VCS ->
  Path a Dir ->
  m ()
initVCS vcs dir = do
  whenJust (vcsInitProc vcs) $ \process -> do
    exists <- guessExecutableExists $ cmdspec process
    let cp =
          process
            { cwd = Just (toFilePath dir)
            }
    if not exists
      then prettyPrintWarning $ pretty $ VcsCmdNotFound vcs
      else runProc cp

runProc ::
  ( Has (Lift IO) sig m,
    Has (Throw ProcessExitFailure) sig m
  ) =>
  CreateProcess ->
  m ()
runProc cp = do
  ~(_, Just stdout, Just stderr, ph) <-
    sendIO $
      createProcess
        cp
          { std_out = CreatePipe,
            std_err = CreatePipe
          }
  c <- sendIO $ waitForProcess ph
  case c of
    ExitSuccess -> pure ()
    ExitFailure i -> do
      out <- sendIO $ hGetContents stdout
      err <- sendIO $ hGetContents stderr
      throwError $ ProcessExitFailure (cmdspec cp) i out err