module Process ( externalGhcPkgDb , outsideGhcPkg , insideGhcPkg , runProcess , ghcPkgDbPathLocation ) where import Types import MyMonad import Paths import Util.IO (readProcessWithExitCodeInEnv, Environment) import Control.Monad (forM_) import Data.Maybe (fromMaybe) import System.FilePath (()) import System.Process (readProcessWithExitCode) import System.Exit (ExitCode(..)) runProcess :: Maybe Environment -> FilePath -> [String] -> Maybe String -> MyMonad String runProcess env prog args input = do debug $ unwords $ ["Executing:", prog] ++ args indentMessages $ case env of Nothing -> trace "using inherited variable environment" Just env' -> do trace "using following environment:" indentMessages $ forM_ env' $ \(var,val) -> trace $ var ++ ": " ++ val indentMessages $ case input of Nothing -> return () Just inp -> do trace "using the following input:" indentMessages $ forM_ (lines inp) trace let execProcess = case env of Nothing -> readProcessWithExitCode prog args (fromMaybe "" input) Just env' -> readProcessWithExitCodeInEnv env' prog args input (exitCode, output, errors) <- liftIO execProcess indentMessages $ debug $ case exitCode of ExitSuccess -> "Process exited successfully" ExitFailure errCode -> "Process failed with exit code " ++ show errCode indentMessages $ do trace "Process output:" indentMessages $ forM_ (lines output) trace indentMessages $ do trace "Process error output:" indentMessages $ forM_ (lines errors) trace case exitCode of ExitSuccess -> return output ExitFailure errCode -> throwError $ MyException $ prog ++ " process failed with status " ++ show errCode -- run outside ghc-pkg tool (uses system's or from ghc installed from tarball) outsideGhcPkg :: [String] -> MyMonad String outsideGhcPkg args = do ghc <- asks ghcSource dirStructure <- vheDirStructure ghcPkg <- case ghc of System -> do debug "Running system's version of ghc-pkg" return "ghc-pkg" Tarball _ -> do debug "Running ghc-pkg installed from GHC's tarball" return $ ghcDir dirStructure "bin" "ghc-pkg" indentMessages $ runProcess Nothing ghcPkg args Nothing -- returns path to GHC (installed from tarball) builtin package database externalGhcPkgDb :: MyMonad FilePath externalGhcPkgDb = do debug "Checking where GHC (installed from tarball) keeps its package database" out <- indentMessages $ outsideGhcPkg ["list"] indentMessages $ debug "Trying to parse ghc-pkg's output" case lines out of [] -> throwError $ MyException "ghc-pkg returned empty output" lineWithPath:_ -> case lineWithPath of "" -> throwError $ MyException "ghc-pkg's first line of output is empty" _ -> do -- ghc-pkg ends pkg db path with trailing colon -- but only when not run from the terminal let path = init lineWithPath indentMessages $ debug $ "Found: " ++ path return path -- run ghc-pkg tool (uses system's or from ghc installed from tarball) -- from the inside of Virtual Haskell Environment insideGhcPkg :: [String] -> Maybe String -> MyMonad String insideGhcPkg args input = do ghc <- asks ghcSource dirStructure <- vheDirStructure env <- getVirtualEnvironment ghcPkg <- case ghc of System -> do debug "Running system's version of ghc-pkg inside virtual environment" return "ghc-pkg" Tarball _ -> do debug "Running ghc-pkg, installed from GHC's tarball, inside virtual environment" return $ ghcDir dirStructure "bin" "ghc-pkg" indentMessages $ runProcess (Just env) ghcPkg args input -- returns value of GHC_PACKAGE_PATH that should be used inside virtual environment ghcPkgDbPathLocation :: MyMonad String ghcPkgDbPathLocation = do debug "Determining value of GHC_PACKAGE_PATH to be used inside virtual environment" dirStructure <- vheDirStructure ghc <- asks ghcSource case ghc of System -> return $ ghcPackagePath dirStructure Tarball _ -> do externalGhcPkgDbPath <- indentMessages externalGhcPkgDb return $ ghcPackagePath dirStructure ++ ":" ++ externalGhcPkgDbPath