{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE BangPatterns #-}
module HIE.Bios.Cradle (
findCradle
, loadCradle
, loadCustomCradle
, loadImplicitCradle
, yamlConfig
, defaultCradle
, isCabalCradle
, isStackCradle
, isDirectCradle
, isBiosCradle
, isNoneCradle
, isMultiCradle
, isDefaultCradle
, isOtherCradle
, getCradle
, readProcessWithOutputs
, readProcessWithCwd
, makeCradleResult
) where
import Control.Exception (handleJust)
import qualified Data.Yaml as Yaml
import Data.Void
import Data.Char (isSpace)
import System.Process
import System.Exit
import HIE.Bios.Types hiding (ActionName(..))
import qualified HIE.Bios.Types as Types
import HIE.Bios.Config
import HIE.Bios.Environment (getCacheDir)
import System.Directory hiding (findFile)
import Control.Monad.Trans.Cont
import Control.Monad.Trans.Maybe
import System.FilePath
import Control.Monad
import System.Info.Extra
import Control.Monad.IO.Class
import System.Environment
import Control.Applicative ((<|>), optional)
import System.IO.Temp
import System.IO.Error (isPermissionError)
import Data.List
import Data.Ord (Down(..))
import System.PosixCompat.Files
import HIE.Bios.Wrappers
import System.IO
import Control.DeepSeq
import Data.Conduit.Process
import qualified Data.Conduit.Combinators as C
import qualified Data.Conduit as C
import qualified Data.Conduit.Text as C
import qualified Data.Text as T
import qualified Data.HashMap.Strict as Map
import Data.Maybe (fromMaybe, maybeToList)
import GHC.Fingerprint (fingerprintString)
import DynFlags (dynamicGhc)
hie_bios_output :: String
hie_bios_output :: String
hie_bios_output = "HIE_BIOS_OUTPUT"
findCradle :: FilePath -> IO (Maybe FilePath)
findCradle :: String -> IO (Maybe String)
findCradle wfile :: String
wfile = do
let wdir :: String
wdir = String -> String
takeDirectory String
wfile
MaybeT IO String -> IO (Maybe String)
forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
runMaybeT (String -> MaybeT IO String
yamlConfig String
wdir)
loadCradle :: FilePath -> IO (Cradle Void)
loadCradle :: String -> IO (Cradle Void)
loadCradle = CradleOpts -> (Void -> Cradle Void) -> String -> IO (Cradle Void)
forall b a.
FromJSON b =>
CradleOpts -> (b -> Cradle a) -> String -> IO (Cradle a)
loadCradleWithOpts CradleOpts
Types.defaultCradleOpts Void -> Cradle Void
forall a. Void -> a
absurd
loadCustomCradle :: Yaml.FromJSON b => (b -> Cradle a) -> FilePath -> IO (Cradle a)
loadCustomCradle :: (b -> Cradle a) -> String -> IO (Cradle a)
loadCustomCradle = CradleOpts -> (b -> Cradle a) -> String -> IO (Cradle a)
forall b a.
FromJSON b =>
CradleOpts -> (b -> Cradle a) -> String -> IO (Cradle a)
loadCradleWithOpts CradleOpts
Types.defaultCradleOpts
loadImplicitCradle :: Show a => FilePath -> IO (Cradle a)
loadImplicitCradle :: String -> IO (Cradle a)
loadImplicitCradle wfile :: String
wfile = do
let wdir :: String
wdir = String -> String
takeDirectory String
wfile
Maybe (CradleConfig Void, String)
cfg <- MaybeT IO (CradleConfig Void, String)
-> IO (Maybe (CradleConfig Void, String))
forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
runMaybeT (String -> MaybeT IO (CradleConfig Void, String)
forall a. String -> MaybeT IO (CradleConfig a, String)
implicitConfig String
wdir)
Cradle a -> IO (Cradle a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Cradle a -> IO (Cradle a)) -> Cradle a -> IO (Cradle a)
forall a b. (a -> b) -> a -> b
$ case Maybe (CradleConfig Void, String)
cfg of
Just bc :: (CradleConfig Void, String)
bc -> (Void -> Cradle a) -> (CradleConfig Void, String) -> Cradle a
forall b a. (b -> Cradle a) -> (CradleConfig b, String) -> Cradle a
getCradle Void -> Cradle a
forall a. Void -> a
absurd (CradleConfig Void, String)
bc
Nothing -> String -> Cradle a
forall a. String -> Cradle a
defaultCradle String
wdir
loadCradleWithOpts :: (Yaml.FromJSON b) => CradleOpts -> (b -> Cradle a) -> FilePath -> IO (Cradle a)
loadCradleWithOpts :: CradleOpts -> (b -> Cradle a) -> String -> IO (Cradle a)
loadCradleWithOpts _copts :: CradleOpts
_copts buildCustomCradle :: b -> Cradle a
buildCustomCradle wfile :: String
wfile = do
CradleConfig b
cradleConfig <- String -> IO (CradleConfig b)
forall b. FromJSON b => String -> IO (CradleConfig b)
readCradleConfig String
wfile
Cradle a -> IO (Cradle a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Cradle a -> IO (Cradle a)) -> Cradle a -> IO (Cradle a)
forall a b. (a -> b) -> a -> b
$ (b -> Cradle a) -> (CradleConfig b, String) -> Cradle a
forall b a. (b -> Cradle a) -> (CradleConfig b, String) -> Cradle a
getCradle b -> Cradle a
buildCustomCradle (CradleConfig b
cradleConfig, String -> String
takeDirectory String
wfile)
getCradle :: (b -> Cradle a) -> (CradleConfig b, FilePath) -> Cradle a
getCradle :: (b -> Cradle a) -> (CradleConfig b, String) -> Cradle a
getCradle buildCustomCradle :: b -> Cradle a
buildCustomCradle (cc :: CradleConfig b
cc, wdir :: String
wdir) = [String] -> Cradle a -> Cradle a
forall a. [String] -> Cradle a -> Cradle a
addCradleDeps [String]
cradleDeps (Cradle a -> Cradle a) -> Cradle a -> Cradle a
forall a b. (a -> b) -> a -> b
$ case CradleConfig b -> CradleType b
forall a. CradleConfig a -> CradleType a
cradleType CradleConfig b
cc of
Cabal CabalType{ cabalComponent :: CabalType -> Maybe String
cabalComponent = Maybe String
mc } -> String -> Maybe String -> Cradle a
forall a. String -> Maybe String -> Cradle a
cabalCradle String
wdir Maybe String
mc
CabalMulti dc :: CabalType
dc ms :: [(String, CabalType)]
ms ->
(b -> Cradle a) -> (CradleConfig b, String) -> Cradle a
forall b a. (b -> Cradle a) -> (CradleConfig b, String) -> Cradle a
getCradle b -> Cradle a
buildCustomCradle ((CradleConfig b, String) -> Cradle a)
-> (CradleConfig b, String) -> Cradle a
forall a b. (a -> b) -> a -> b
$
([String] -> CradleType b -> CradleConfig b
forall a. [String] -> CradleType a -> CradleConfig a
CradleConfig [String]
cradleDeps
([(String, CradleConfig b)] -> CradleType b
forall a. [(String, CradleConfig a)] -> CradleType a
Multi [(String
p, [String] -> CradleType b -> CradleConfig b
forall a. [String] -> CradleType a -> CradleConfig a
CradleConfig [] (CabalType -> CradleType b
forall a. CabalType -> CradleType a
Cabal (CabalType -> CradleType b) -> CabalType -> CradleType b
forall a b. (a -> b) -> a -> b
$ CabalType
dc CabalType -> CabalType -> CabalType
forall a. Semigroup a => a -> a -> a
<> CabalType
c)) | (p :: String
p, c :: CabalType
c) <- [(String, CabalType)]
ms])
, String
wdir)
Stack StackType{ stackComponent :: StackType -> Maybe String
stackComponent = Maybe String
mc, stackYaml :: StackType -> Maybe String
stackYaml = Maybe String
syaml} ->
let
stackYamlConfig :: StackYaml
stackYamlConfig = String -> Maybe String -> StackYaml
stackYamlFromMaybe String
wdir Maybe String
syaml
in
String -> Maybe String -> StackYaml -> Cradle a
forall a. String -> Maybe String -> StackYaml -> Cradle a
stackCradle String
wdir Maybe String
mc StackYaml
stackYamlConfig
StackMulti ds :: StackType
ds ms :: [(String, StackType)]
ms ->
(b -> Cradle a) -> (CradleConfig b, String) -> Cradle a
forall b a. (b -> Cradle a) -> (CradleConfig b, String) -> Cradle a
getCradle b -> Cradle a
buildCustomCradle ((CradleConfig b, String) -> Cradle a)
-> (CradleConfig b, String) -> Cradle a
forall a b. (a -> b) -> a -> b
$
([String] -> CradleType b -> CradleConfig b
forall a. [String] -> CradleType a -> CradleConfig a
CradleConfig [String]
cradleDeps
([(String, CradleConfig b)] -> CradleType b
forall a. [(String, CradleConfig a)] -> CradleType a
Multi [(String
p, [String] -> CradleType b -> CradleConfig b
forall a. [String] -> CradleType a -> CradleConfig a
CradleConfig [] (StackType -> CradleType b
forall a. StackType -> CradleType a
Stack (StackType -> CradleType b) -> StackType -> CradleType b
forall a b. (a -> b) -> a -> b
$ StackType
ds StackType -> StackType -> StackType
forall a. Semigroup a => a -> a -> a
<> StackType
c)) | (p :: String
p, c :: StackType
c) <- [(String, StackType)]
ms])
, String
wdir)
Bios bios :: Callable
bios deps :: Maybe Callable
deps mbGhc :: Maybe String
mbGhc -> String -> Callable -> Maybe Callable -> Maybe String -> Cradle a
forall a.
String -> Callable -> Maybe Callable -> Maybe String -> Cradle a
biosCradle String
wdir Callable
bios Maybe Callable
deps Maybe String
mbGhc
Direct xs :: [String]
xs -> String -> [String] -> Cradle a
forall a. String -> [String] -> Cradle a
directCradle String
wdir [String]
xs
None -> String -> Cradle a
forall a. String -> Cradle a
noneCradle String
wdir
Multi ms :: [(String, CradleConfig b)]
ms -> (b -> Cradle a) -> String -> [(String, CradleConfig b)] -> Cradle a
forall b a.
(b -> Cradle a) -> String -> [(String, CradleConfig b)] -> Cradle a
multiCradle b -> Cradle a
buildCustomCradle String
wdir [(String, CradleConfig b)]
ms
Other a :: b
a _ -> b -> Cradle a
buildCustomCradle b
a
where
cradleDeps :: [String]
cradleDeps = CradleConfig b -> [String]
forall a. CradleConfig a -> [String]
cradleDependencies CradleConfig b
cc
addCradleDeps :: [FilePath] -> Cradle a -> Cradle a
addCradleDeps :: [String] -> Cradle a -> Cradle a
addCradleDeps deps :: [String]
deps c :: Cradle a
c =
Cradle a
c { cradleOptsProg :: CradleAction a
cradleOptsProg = CradleAction a -> CradleAction a
forall a. CradleAction a -> CradleAction a
addActionDeps (Cradle a -> CradleAction a
forall a. Cradle a -> CradleAction a
cradleOptsProg Cradle a
c) }
where
addActionDeps :: CradleAction a -> CradleAction a
addActionDeps :: CradleAction a -> CradleAction a
addActionDeps ca :: CradleAction a
ca =
CradleAction a
ca { runCradle :: LoggingFunction -> String -> IO (CradleLoadResult ComponentOptions)
runCradle = \l :: LoggingFunction
l fp :: String
fp ->
CradleAction a
-> LoggingFunction
-> String
-> IO (CradleLoadResult ComponentOptions)
forall a.
CradleAction a
-> LoggingFunction
-> String
-> IO (CradleLoadResult ComponentOptions)
runCradle CradleAction a
ca LoggingFunction
l String
fp
IO (CradleLoadResult ComponentOptions)
-> (CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions))
-> IO (CradleLoadResult ComponentOptions)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
CradleSuccess (ComponentOptions os' :: [String]
os' dir :: String
dir ds :: [String]
ds) ->
CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions))
-> CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall a b. (a -> b) -> a -> b
$ ComponentOptions -> CradleLoadResult ComponentOptions
forall r. r -> CradleLoadResult r
CradleSuccess ([String] -> String -> [String] -> ComponentOptions
ComponentOptions [String]
os' String
dir ([String]
ds [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
`union` [String]
deps))
CradleFail err :: CradleError
err ->
CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions))
-> CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall a b. (a -> b) -> a -> b
$ CradleError -> CradleLoadResult ComponentOptions
forall r. CradleError -> CradleLoadResult r
CradleFail
(CradleError
err { cradleErrorDependencies :: [String]
cradleErrorDependencies = CradleError -> [String]
cradleErrorDependencies CradleError
err [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
`union` [String]
deps })
CradleNone -> CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall (f :: * -> *) a. Applicative f => a -> f a
pure CradleLoadResult ComponentOptions
forall r. CradleLoadResult r
CradleNone
}
implicitConfig :: FilePath -> MaybeT IO (CradleConfig a, FilePath)
implicitConfig :: String -> MaybeT IO (CradleConfig a, String)
implicitConfig fp :: String
fp = do
(crdType :: CradleType a
crdType, wdir :: String
wdir) <- String -> MaybeT IO (CradleType a, String)
forall a. String -> MaybeT IO (CradleType a, String)
implicitConfig' String
fp
(CradleConfig a, String) -> MaybeT IO (CradleConfig a, String)
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> CradleType a -> CradleConfig a
forall a. [String] -> CradleType a -> CradleConfig a
CradleConfig [] CradleType a
crdType, String
wdir)
implicitConfig' :: FilePath -> MaybeT IO (CradleType a, FilePath)
implicitConfig' :: String -> MaybeT IO (CradleType a, String)
implicitConfig' fp :: String
fp = (\wdir :: String
wdir ->
(Callable -> Maybe Callable -> Maybe String -> CradleType a
forall a.
Callable -> Maybe Callable -> Maybe String -> CradleType a
Bios (String -> Callable
Program (String -> Callable) -> String -> Callable
forall a b. (a -> b) -> a -> b
$ String
wdir String -> String -> String
</> ".hie-bios") Maybe Callable
forall a. Maybe a
Nothing Maybe String
forall a. Maybe a
Nothing, String
wdir)) (String -> (CradleType a, String))
-> MaybeT IO String -> MaybeT IO (CradleType a, String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> MaybeT IO String
biosWorkDir String
fp
MaybeT IO (CradleType a, String)
-> MaybeT IO (CradleType a, String)
-> MaybeT IO (CradleType a, String)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (MaybeT IO String
stackExecutable MaybeT IO String
-> MaybeT IO (CradleType a, String)
-> MaybeT IO (CradleType a, String)
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (StackType -> CradleType a
forall a. StackType -> CradleType a
Stack (StackType -> CradleType a) -> StackType -> CradleType a
forall a b. (a -> b) -> a -> b
$ Maybe String -> Maybe String -> StackType
StackType Maybe String
forall a. Maybe a
Nothing Maybe String
forall a. Maybe a
Nothing,) (String -> (CradleType a, String))
-> MaybeT IO String -> MaybeT IO (CradleType a, String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> MaybeT IO String
stackWorkDir String
fp)
MaybeT IO (CradleType a, String)
-> MaybeT IO (CradleType a, String)
-> MaybeT IO (CradleType a, String)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ((CabalType -> CradleType a
forall a. CabalType -> CradleType a
Cabal (CabalType -> CradleType a) -> CabalType -> CradleType a
forall a b. (a -> b) -> a -> b
$ Maybe String -> CabalType
CabalType Maybe String
forall a. Maybe a
Nothing,) (String -> (CradleType a, String))
-> MaybeT IO String -> MaybeT IO (CradleType a, String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> MaybeT IO String
cabalWorkDir String
fp)
yamlConfig :: FilePath -> MaybeT IO FilePath
yamlConfig :: String -> MaybeT IO String
yamlConfig fp :: String
fp = do
String
configDir <- String -> MaybeT IO String
yamlConfigDirectory String
fp
String -> MaybeT IO String
forall (m :: * -> *) a. Monad m => a -> m a
return (String
configDir String -> String -> String
</> String
configFileName)
yamlConfigDirectory :: FilePath -> MaybeT IO FilePath
yamlConfigDirectory :: String -> MaybeT IO String
yamlConfigDirectory = (String -> Bool) -> String -> MaybeT IO String
findFileUpwards (String
configFileName String -> String -> Bool
forall a. Eq a => a -> a -> Bool
==)
readCradleConfig :: Yaml.FromJSON b => FilePath -> IO (CradleConfig b)
readCradleConfig :: String -> IO (CradleConfig b)
readCradleConfig yamlHie :: String
yamlHie = do
Config b
cfg <- IO (Config b) -> IO (Config b)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Config b) -> IO (Config b)) -> IO (Config b) -> IO (Config b)
forall a b. (a -> b) -> a -> b
$ String -> IO (Config b)
forall a. FromJSON a => String -> IO (Config a)
readConfig String
yamlHie
CradleConfig b -> IO (CradleConfig b)
forall (m :: * -> *) a. Monad m => a -> m a
return (Config b -> CradleConfig b
forall a. Config a -> CradleConfig a
cradle Config b
cfg)
configFileName :: FilePath
configFileName :: String
configFileName = "hie.yaml"
argDynamic :: [String]
argDynamic :: [String]
argDynamic = ["-dynamic" | Bool
dynamicGhc]
isCabalCradle :: Cradle a -> Bool
isCabalCradle :: Cradle a -> Bool
isCabalCradle crdl :: Cradle a
crdl = case CradleAction a -> ActionName a
forall a. CradleAction a -> ActionName a
actionName (Cradle a -> CradleAction a
forall a. Cradle a -> CradleAction a
cradleOptsProg Cradle a
crdl) of
Types.Cabal -> Bool
True
_ -> Bool
False
isStackCradle :: Cradle a -> Bool
isStackCradle :: Cradle a -> Bool
isStackCradle crdl :: Cradle a
crdl = case CradleAction a -> ActionName a
forall a. CradleAction a -> ActionName a
actionName (Cradle a -> CradleAction a
forall a. Cradle a -> CradleAction a
cradleOptsProg Cradle a
crdl) of
Types.Stack -> Bool
True
_ -> Bool
False
isDirectCradle :: Cradle a -> Bool
isDirectCradle :: Cradle a -> Bool
isDirectCradle crdl :: Cradle a
crdl = case CradleAction a -> ActionName a
forall a. CradleAction a -> ActionName a
actionName (Cradle a -> CradleAction a
forall a. Cradle a -> CradleAction a
cradleOptsProg Cradle a
crdl) of
Types.Direct -> Bool
True
_ -> Bool
False
isBiosCradle :: Cradle a -> Bool
isBiosCradle :: Cradle a -> Bool
isBiosCradle crdl :: Cradle a
crdl = case CradleAction a -> ActionName a
forall a. CradleAction a -> ActionName a
actionName (Cradle a -> CradleAction a
forall a. Cradle a -> CradleAction a
cradleOptsProg Cradle a
crdl) of
Types.Bios -> Bool
True
_ -> Bool
False
isMultiCradle :: Cradle a -> Bool
isMultiCradle :: Cradle a -> Bool
isMultiCradle crdl :: Cradle a
crdl = case CradleAction a -> ActionName a
forall a. CradleAction a -> ActionName a
actionName (Cradle a -> CradleAction a
forall a. Cradle a -> CradleAction a
cradleOptsProg Cradle a
crdl) of
Types.Multi -> Bool
True
_ -> Bool
False
isNoneCradle :: Cradle a -> Bool
isNoneCradle :: Cradle a -> Bool
isNoneCradle crdl :: Cradle a
crdl = case CradleAction a -> ActionName a
forall a. CradleAction a -> ActionName a
actionName (Cradle a -> CradleAction a
forall a. Cradle a -> CradleAction a
cradleOptsProg Cradle a
crdl) of
Types.None -> Bool
True
_ -> Bool
False
isDefaultCradle :: Cradle a -> Bool
isDefaultCradle :: Cradle a -> Bool
isDefaultCradle crdl :: Cradle a
crdl = case CradleAction a -> ActionName a
forall a. CradleAction a -> ActionName a
actionName (Cradle a -> CradleAction a
forall a. Cradle a -> CradleAction a
cradleOptsProg Cradle a
crdl) of
Types.Default -> Bool
True
_ -> Bool
False
isOtherCradle :: Cradle a -> Bool
isOtherCradle :: Cradle a -> Bool
isOtherCradle crdl :: Cradle a
crdl = case CradleAction a -> ActionName a
forall a. CradleAction a -> ActionName a
actionName (Cradle a -> CradleAction a
forall a. Cradle a -> CradleAction a
cradleOptsProg Cradle a
crdl) of
Types.Other _ -> Bool
True
_ -> Bool
False
defaultCradle :: FilePath -> Cradle a
defaultCradle :: String -> Cradle a
defaultCradle cur_dir :: String
cur_dir =
Cradle :: forall a. String -> CradleAction a -> Cradle a
Cradle
{ cradleRootDir :: String
cradleRootDir = String
cur_dir
, cradleOptsProg :: CradleAction a
cradleOptsProg = CradleAction :: forall a.
ActionName a
-> (LoggingFunction
-> String -> IO (CradleLoadResult ComponentOptions))
-> ([String] -> IO (CradleLoadResult String))
-> CradleAction a
CradleAction
{ actionName :: ActionName a
actionName = ActionName a
forall a. ActionName a
Types.Default
, runCradle :: LoggingFunction -> String -> IO (CradleLoadResult ComponentOptions)
runCradle = \_ _ ->
CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall (m :: * -> *) a. Monad m => a -> m a
return (ComponentOptions -> CradleLoadResult ComponentOptions
forall r. r -> CradleLoadResult r
CradleSuccess ([String] -> String -> [String] -> ComponentOptions
ComponentOptions [String]
argDynamic String
cur_dir []))
, runGhcCmd :: [String] -> IO (CradleLoadResult String)
runGhcCmd = String -> [String] -> IO (CradleLoadResult String)
runGhcCmdOnPath String
cur_dir
}
}
noneCradle :: FilePath -> Cradle a
noneCradle :: String -> Cradle a
noneCradle cur_dir :: String
cur_dir =
Cradle :: forall a. String -> CradleAction a -> Cradle a
Cradle
{ cradleRootDir :: String
cradleRootDir = String
cur_dir
, cradleOptsProg :: CradleAction a
cradleOptsProg = CradleAction :: forall a.
ActionName a
-> (LoggingFunction
-> String -> IO (CradleLoadResult ComponentOptions))
-> ([String] -> IO (CradleLoadResult String))
-> CradleAction a
CradleAction
{ actionName :: ActionName a
actionName = ActionName a
forall a. ActionName a
Types.None
, runCradle :: LoggingFunction -> String -> IO (CradleLoadResult ComponentOptions)
runCradle = \_ _ -> CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall (m :: * -> *) a. Monad m => a -> m a
return CradleLoadResult ComponentOptions
forall r. CradleLoadResult r
CradleNone
, runGhcCmd :: [String] -> IO (CradleLoadResult String)
runGhcCmd = \_ -> CradleLoadResult String -> IO (CradleLoadResult String)
forall (m :: * -> *) a. Monad m => a -> m a
return CradleLoadResult String
forall r. CradleLoadResult r
CradleNone
}
}
multiCradle :: (b -> Cradle a) -> FilePath -> [(FilePath, CradleConfig b)] -> Cradle a
multiCradle :: (b -> Cradle a) -> String -> [(String, CradleConfig b)] -> Cradle a
multiCradle buildCustomCradle :: b -> Cradle a
buildCustomCradle cur_dir :: String
cur_dir cs :: [(String, CradleConfig b)]
cs =
Cradle :: forall a. String -> CradleAction a -> Cradle a
Cradle
{ cradleRootDir :: String
cradleRootDir = String
cur_dir
, cradleOptsProg :: CradleAction a
cradleOptsProg = CradleAction :: forall a.
ActionName a
-> (LoggingFunction
-> String -> IO (CradleLoadResult ComponentOptions))
-> ([String] -> IO (CradleLoadResult String))
-> CradleAction a
CradleAction
{ actionName :: ActionName a
actionName = ActionName a
forall a. ActionName a
multiActionName
, runCradle :: LoggingFunction -> String -> IO (CradleLoadResult ComponentOptions)
runCradle = \l :: LoggingFunction
l fp :: String
fp -> String -> IO String
makeAbsolute String
fp IO String
-> (String -> IO (CradleLoadResult ComponentOptions))
-> IO (CradleLoadResult ComponentOptions)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (b -> Cradle a)
-> String
-> [(String, CradleConfig b)]
-> LoggingFunction
-> String
-> IO (CradleLoadResult ComponentOptions)
forall b a.
(b -> Cradle a)
-> String
-> [(String, CradleConfig b)]
-> LoggingFunction
-> String
-> IO (CradleLoadResult ComponentOptions)
multiAction b -> Cradle a
buildCustomCradle String
cur_dir [(String, CradleConfig b)]
cs LoggingFunction
l
, runGhcCmd :: [String] -> IO (CradleLoadResult String)
runGhcCmd = \args :: [String]
args ->
case (CradleConfig b -> Bool) -> [CradleConfig b] -> [CradleConfig b]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool)
-> (CradleConfig b -> Bool) -> CradleConfig b -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CradleConfig b -> Bool
forall a. CradleConfig a -> Bool
isNoneCradleConfig) ([CradleConfig b] -> [CradleConfig b])
-> [CradleConfig b] -> [CradleConfig b]
forall a b. (a -> b) -> a -> b
$ ((String, CradleConfig b) -> CradleConfig b)
-> [(String, CradleConfig b)] -> [CradleConfig b]
forall a b. (a -> b) -> [a] -> [b]
map (String, CradleConfig b) -> CradleConfig b
forall a b. (a, b) -> b
snd [(String, CradleConfig b)]
cs of
[] -> CradleLoadResult String -> IO (CradleLoadResult String)
forall (m :: * -> *) a. Monad m => a -> m a
return CradleLoadResult String
forall r. CradleLoadResult r
CradleNone
(cfg :: CradleConfig b
cfg:_) -> (CradleAction a -> [String] -> IO (CradleLoadResult String))
-> [String] -> CradleAction a -> IO (CradleLoadResult String)
forall a b c. (a -> b -> c) -> b -> a -> c
flip CradleAction a -> [String] -> IO (CradleLoadResult String)
forall a.
CradleAction a -> [String] -> IO (CradleLoadResult String)
runGhcCmd [String]
args (CradleAction a -> IO (CradleLoadResult String))
-> CradleAction a -> IO (CradleLoadResult String)
forall a b. (a -> b) -> a -> b
$ Cradle a -> CradleAction a
forall a. Cradle a -> CradleAction a
cradleOptsProg (Cradle a -> CradleAction a) -> Cradle a -> CradleAction a
forall a b. (a -> b) -> a -> b
$
(b -> Cradle a) -> (CradleConfig b, String) -> Cradle a
forall b a. (b -> Cradle a) -> (CradleConfig b, String) -> Cradle a
getCradle b -> Cradle a
buildCustomCradle (CradleConfig b
cfg, String
cur_dir)
}
}
where
cfgs :: [CradleConfig b]
cfgs = ((String, CradleConfig b) -> CradleConfig b)
-> [(String, CradleConfig b)] -> [CradleConfig b]
forall a b. (a -> b) -> [a] -> [b]
map (String, CradleConfig b) -> CradleConfig b
forall a b. (a, b) -> b
snd [(String, CradleConfig b)]
cs
multiActionName :: ActionName a
multiActionName
| (CradleConfig b -> Bool) -> [CradleConfig b] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (\c :: CradleConfig b
c -> CradleConfig b -> Bool
forall a. CradleConfig a -> Bool
isStackCradleConfig CradleConfig b
c Bool -> Bool -> Bool
|| CradleConfig b -> Bool
forall a. CradleConfig a -> Bool
isNoneCradleConfig CradleConfig b
c) [CradleConfig b]
cfgs
= ActionName a
forall a. ActionName a
Types.Stack
| (CradleConfig b -> Bool) -> [CradleConfig b] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (\c :: CradleConfig b
c -> CradleConfig b -> Bool
forall a. CradleConfig a -> Bool
isCabalCradleConfig CradleConfig b
c Bool -> Bool -> Bool
|| CradleConfig b -> Bool
forall a. CradleConfig a -> Bool
isNoneCradleConfig CradleConfig b
c) [CradleConfig b]
cfgs
= ActionName a
forall a. ActionName a
Types.Cabal
| Bool
otherwise
= ActionName a
forall a. ActionName a
Types.Multi
isStackCradleConfig :: CradleConfig a -> Bool
isStackCradleConfig cfg :: CradleConfig a
cfg = case CradleConfig a -> CradleType a
forall a. CradleConfig a -> CradleType a
cradleType CradleConfig a
cfg of
Stack{} -> Bool
True
StackMulti{} -> Bool
True
_ -> Bool
False
isCabalCradleConfig :: CradleConfig a -> Bool
isCabalCradleConfig cfg :: CradleConfig a
cfg = case CradleConfig a -> CradleType a
forall a. CradleConfig a -> CradleType a
cradleType CradleConfig a
cfg of
Cabal{} -> Bool
True
CabalMulti{} -> Bool
True
_ -> Bool
False
isNoneCradleConfig :: CradleConfig a -> Bool
isNoneCradleConfig cfg :: CradleConfig a
cfg = case CradleConfig a -> CradleType a
forall a. CradleConfig a -> CradleType a
cradleType CradleConfig a
cfg of
None -> Bool
True
_ -> Bool
False
multiAction :: forall b a
. (b -> Cradle a)
-> FilePath
-> [(FilePath, CradleConfig b)]
-> LoggingFunction
-> FilePath
-> IO (CradleLoadResult ComponentOptions)
multiAction :: (b -> Cradle a)
-> String
-> [(String, CradleConfig b)]
-> LoggingFunction
-> String
-> IO (CradleLoadResult ComponentOptions)
multiAction buildCustomCradle :: b -> Cradle a
buildCustomCradle cur_dir :: String
cur_dir cs :: [(String, CradleConfig b)]
cs l :: LoggingFunction
l cur_fp :: String
cur_fp =
[(String, CradleConfig b)]
-> IO (CradleLoadResult ComponentOptions)
selectCradle ([(String, CradleConfig b)]
-> IO (CradleLoadResult ComponentOptions))
-> IO [(String, CradleConfig b)]
-> IO (CradleLoadResult ComponentOptions)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO [(String, CradleConfig b)]
canonicalizeCradles
where
err_msg :: [String]
err_msg = ["Multi Cradle: No prefixes matched"
, "pwd: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
cur_dir
, "filepath: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
cur_fp
, "prefixes:"
] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [(String, CradleType b) -> String
forall a. Show a => a -> String
show (String
pf, CradleConfig b -> CradleType b
forall a. CradleConfig a -> CradleType a
cradleType CradleConfig b
cc) | (pf :: String
pf, cc :: CradleConfig b
cc) <- [(String, CradleConfig b)]
cs]
canonicalizeCradles :: IO [(FilePath, CradleConfig b)]
canonicalizeCradles :: IO [(String, CradleConfig b)]
canonicalizeCradles =
((String, CradleConfig b) -> Down String)
-> [(String, CradleConfig b)] -> [(String, CradleConfig b)]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn (String -> Down String
forall a. a -> Down a
Down (String -> Down String)
-> ((String, CradleConfig b) -> String)
-> (String, CradleConfig b)
-> Down String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String, CradleConfig b) -> String
forall a b. (a, b) -> a
fst)
([(String, CradleConfig b)] -> [(String, CradleConfig b)])
-> IO [(String, CradleConfig b)] -> IO [(String, CradleConfig b)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((String, CradleConfig b) -> IO (String, CradleConfig b))
-> [(String, CradleConfig b)] -> IO [(String, CradleConfig b)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (\(p :: String
p, c :: CradleConfig b
c) -> (,CradleConfig b
c) (String -> (String, CradleConfig b))
-> IO String -> IO (String, CradleConfig b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (String -> IO String
makeAbsolute (String
cur_dir String -> String -> String
</> String
p))) [(String, CradleConfig b)]
cs
selectCradle :: [(String, CradleConfig b)]
-> IO (CradleLoadResult ComponentOptions)
selectCradle [] =
CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall (m :: * -> *) a. Monad m => a -> m a
return (CradleError -> CradleLoadResult ComponentOptions
forall r. CradleError -> CradleLoadResult r
CradleFail ([String] -> ExitCode -> [String] -> CradleError
CradleError [] ExitCode
ExitSuccess [String]
err_msg))
selectCradle ((p :: String
p, c :: CradleConfig b
c): css :: [(String, CradleConfig b)]
css) =
if String
p String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
cur_fp
then CradleAction a
-> LoggingFunction
-> String
-> IO (CradleLoadResult ComponentOptions)
forall a.
CradleAction a
-> LoggingFunction
-> String
-> IO (CradleLoadResult ComponentOptions)
runCradle
(Cradle a -> CradleAction a
forall a. Cradle a -> CradleAction a
cradleOptsProg ((b -> Cradle a) -> (CradleConfig b, String) -> Cradle a
forall b a. (b -> Cradle a) -> (CradleConfig b, String) -> Cradle a
getCradle b -> Cradle a
buildCustomCradle (CradleConfig b
c, String
cur_dir)))
LoggingFunction
l
String
cur_fp
else [(String, CradleConfig b)]
-> IO (CradleLoadResult ComponentOptions)
selectCradle [(String, CradleConfig b)]
css
directCradle :: FilePath -> [String] -> Cradle a
directCradle :: String -> [String] -> Cradle a
directCradle wdir :: String
wdir args :: [String]
args =
Cradle :: forall a. String -> CradleAction a -> Cradle a
Cradle
{ cradleRootDir :: String
cradleRootDir = String
wdir
, cradleOptsProg :: CradleAction a
cradleOptsProg = CradleAction :: forall a.
ActionName a
-> (LoggingFunction
-> String -> IO (CradleLoadResult ComponentOptions))
-> ([String] -> IO (CradleLoadResult String))
-> CradleAction a
CradleAction
{ actionName :: ActionName a
actionName = ActionName a
forall a. ActionName a
Types.Direct
, runCradle :: LoggingFunction -> String -> IO (CradleLoadResult ComponentOptions)
runCradle = \_ _ ->
CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall (m :: * -> *) a. Monad m => a -> m a
return (ComponentOptions -> CradleLoadResult ComponentOptions
forall r. r -> CradleLoadResult r
CradleSuccess ([String] -> String -> [String] -> ComponentOptions
ComponentOptions ([String]
args [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
argDynamic) String
wdir []))
, runGhcCmd :: [String] -> IO (CradleLoadResult String)
runGhcCmd = String -> [String] -> IO (CradleLoadResult String)
runGhcCmdOnPath String
wdir
}
}
biosCradle :: FilePath -> Callable -> Maybe Callable -> Maybe FilePath -> Cradle a
biosCradle :: String -> Callable -> Maybe Callable -> Maybe String -> Cradle a
biosCradle wdir :: String
wdir biosCall :: Callable
biosCall biosDepsCall :: Maybe Callable
biosDepsCall mbGhc :: Maybe String
mbGhc =
Cradle :: forall a. String -> CradleAction a -> Cradle a
Cradle
{ cradleRootDir :: String
cradleRootDir = String
wdir
, cradleOptsProg :: CradleAction a
cradleOptsProg = CradleAction :: forall a.
ActionName a
-> (LoggingFunction
-> String -> IO (CradleLoadResult ComponentOptions))
-> ([String] -> IO (CradleLoadResult String))
-> CradleAction a
CradleAction
{ actionName :: ActionName a
actionName = ActionName a
forall a. ActionName a
Types.Bios
, runCradle :: LoggingFunction -> String -> IO (CradleLoadResult ComponentOptions)
runCradle = String
-> Callable
-> Maybe Callable
-> LoggingFunction
-> String
-> IO (CradleLoadResult ComponentOptions)
biosAction String
wdir Callable
biosCall Maybe Callable
biosDepsCall
, runGhcCmd :: [String] -> IO (CradleLoadResult String)
runGhcCmd = \args :: [String]
args -> String
-> String -> [String] -> String -> IO (CradleLoadResult String)
readProcessWithCwd String
wdir (String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe "ghc" Maybe String
mbGhc) [String]
args ""
}
}
biosWorkDir :: FilePath -> MaybeT IO FilePath
biosWorkDir :: String -> MaybeT IO String
biosWorkDir = (String -> Bool) -> String -> MaybeT IO String
findFileUpwards (".hie-bios" String -> String -> Bool
forall a. Eq a => a -> a -> Bool
==)
biosDepsAction :: LoggingFunction -> FilePath -> Maybe Callable -> FilePath -> IO [FilePath]
biosDepsAction :: LoggingFunction
-> String -> Maybe Callable -> String -> IO [String]
biosDepsAction l :: LoggingFunction
l wdir :: String
wdir (Just biosDepsCall :: Callable
biosDepsCall) fp :: String
fp = do
CreateProcess
biosDeps' <- Callable -> Maybe String -> IO CreateProcess
callableToProcess Callable
biosDepsCall (String -> Maybe String
forall a. a -> Maybe a
Just String
fp)
(ex :: ExitCode
ex, sout :: [String]
sout, serr :: [String]
serr, [(_, args :: Maybe [String]
args)]) <- [String]
-> LoggingFunction
-> String
-> CreateProcess
-> IO (ExitCode, [String], [String], [(String, Maybe [String])])
readProcessWithOutputs [String
hie_bios_output] LoggingFunction
l String
wdir CreateProcess
biosDeps'
case ExitCode
ex of
ExitFailure _ -> String -> IO [String]
forall a. HasCallStack => String -> a
error (String -> IO [String]) -> String -> IO [String]
forall a b. (a -> b) -> a -> b
$ (ExitCode, [String], [String]) -> String
forall a. Show a => a -> String
show (ExitCode
ex, [String]
sout, [String]
serr)
ExitSuccess -> [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> IO [String]) -> [String] -> IO [String]
forall a b. (a -> b) -> a -> b
$ [String] -> Maybe [String] -> [String]
forall a. a -> Maybe a -> a
fromMaybe [] Maybe [String]
args
biosDepsAction _ _ Nothing _ = [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return []
biosAction :: FilePath
-> Callable
-> Maybe Callable
-> LoggingFunction
-> FilePath
-> IO (CradleLoadResult ComponentOptions)
biosAction :: String
-> Callable
-> Maybe Callable
-> LoggingFunction
-> String
-> IO (CradleLoadResult ComponentOptions)
biosAction wdir :: String
wdir bios :: Callable
bios bios_deps :: Maybe Callable
bios_deps l :: LoggingFunction
l fp :: String
fp = do
CreateProcess
bios' <- Callable -> Maybe String -> IO CreateProcess
callableToProcess Callable
bios (String -> Maybe String
forall a. a -> Maybe a
Just String
fp)
(ex :: ExitCode
ex, _stdo :: [String]
_stdo, std :: [String]
std, [(_, res :: Maybe [String]
res),(_, mb_deps :: Maybe [String]
mb_deps)]) <-
[String]
-> LoggingFunction
-> String
-> CreateProcess
-> IO (ExitCode, [String], [String], [(String, Maybe [String])])
readProcessWithOutputs [String
hie_bios_output, "HIE_BIOS_DEPS"] LoggingFunction
l String
wdir CreateProcess
bios'
[String]
deps <- case Maybe [String]
mb_deps of
Just x :: [String]
x -> [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return [String]
x
Nothing -> LoggingFunction
-> String -> Maybe Callable -> String -> IO [String]
biosDepsAction LoggingFunction
l String
wdir Maybe Callable
bios_deps String
fp
CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall (m :: * -> *) a. Monad m => a -> m a
return (CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions))
-> CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall a b. (a -> b) -> a -> b
$ (ExitCode, [String], String, [String])
-> [String] -> CradleLoadResult ComponentOptions
makeCradleResult (ExitCode
ex, [String]
std, String
wdir, [String] -> Maybe [String] -> [String]
forall a. a -> Maybe a -> a
fromMaybe [] Maybe [String]
res) [String]
deps
callableToProcess :: Callable -> Maybe String -> IO CreateProcess
callableToProcess :: Callable -> Maybe String -> IO CreateProcess
callableToProcess (Command shellCommand :: String
shellCommand) file :: Maybe String
file = do
[(String, String)]
old_env <- IO [(String, String)]
getEnvironment
CreateProcess -> IO CreateProcess
forall (m :: * -> *) a. Monad m => a -> m a
return (CreateProcess -> IO CreateProcess)
-> CreateProcess -> IO CreateProcess
forall a b. (a -> b) -> a -> b
$ (String -> CreateProcess
shell String
shellCommand) { env :: Maybe [(String, String)]
env = ((String, String) -> [(String, String)] -> [(String, String)]
forall a. a -> [a] -> [a]
: [(String, String)]
old_env) ((String, String) -> [(String, String)])
-> (String -> (String, String)) -> String -> [(String, String)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (,) String
hieBiosArg (String -> [(String, String)])
-> Maybe String -> Maybe [(String, String)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe String
file }
where
hieBiosArg :: String
hieBiosArg = "HIE_BIOS_ARG"
callableToProcess (Program path :: String
path) file :: Maybe String
file = do
String
canon_path <- String -> IO String
canonicalizePath String
path
CreateProcess -> IO CreateProcess
forall (m :: * -> *) a. Monad m => a -> m a
return (CreateProcess -> IO CreateProcess)
-> CreateProcess -> IO CreateProcess
forall a b. (a -> b) -> a -> b
$ String -> [String] -> CreateProcess
proc String
canon_path (Maybe String -> [String]
forall a. Maybe a -> [a]
maybeToList Maybe String
file)
cabalCradle :: FilePath -> Maybe String -> Cradle a
cabalCradle :: String -> Maybe String -> Cradle a
cabalCradle wdir :: String
wdir mc :: Maybe String
mc =
Cradle :: forall a. String -> CradleAction a -> Cradle a
Cradle
{ cradleRootDir :: String
cradleRootDir = String
wdir
, cradleOptsProg :: CradleAction a
cradleOptsProg = CradleAction :: forall a.
ActionName a
-> (LoggingFunction
-> String -> IO (CradleLoadResult ComponentOptions))
-> ([String] -> IO (CradleLoadResult String))
-> CradleAction a
CradleAction
{ actionName :: ActionName a
actionName = ActionName a
forall a. ActionName a
Types.Cabal
, runCradle :: LoggingFunction -> String -> IO (CradleLoadResult ComponentOptions)
runCradle = String
-> Maybe String
-> LoggingFunction
-> String
-> IO (CradleLoadResult ComponentOptions)
cabalAction String
wdir Maybe String
mc
, runGhcCmd :: [String] -> IO (CradleLoadResult String)
runGhcCmd = \args :: [String]
args -> do
String
buildDir <- String -> IO String
cabalBuildDir String
wdir
Bool -> LoggingFunction
createDirectoryIfMissing Bool
True (String
buildDir String -> String -> String
</> "tmp")
String
wrapper_fp <- GhcProc -> String -> IO String
withCabalWrapperTool ("ghc", []) String
wdir
String
-> String -> [String] -> String -> IO (CradleLoadResult String)
readProcessWithCwd
String
wdir "cabal" (["--builddir="String -> String -> String
forall a. Semigroup a => a -> a -> a
<>String
buildDir,"v2-exec","--with-compiler", String
wrapper_fp, "ghc", "-v0", "--"] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
args) ""
}
}
cabalCradleDependencies :: FilePath -> FilePath -> IO [FilePath]
cabalCradleDependencies :: String -> String -> IO [String]
cabalCradleDependencies rootDir :: String
rootDir componentDir :: String
componentDir = do
let relFp :: String
relFp = String -> String -> String
makeRelative String
rootDir String
componentDir
[String]
cabalFiles' <- String -> IO [String]
findCabalFiles String
componentDir
let cabalFiles :: [String]
cabalFiles = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String
relFp String -> String -> String
</>) [String]
cabalFiles'
[String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> IO [String]) -> [String] -> IO [String]
forall a b. (a -> b) -> a -> b
$ (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
normalise ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ [String]
cabalFiles [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ ["cabal.project", "cabal.project.local"]
findCabalFiles :: FilePath -> IO [FilePath]
findCabalFiles :: String -> IO [String]
findCabalFiles wdir :: String
wdir = do
[String]
dirContent <- String -> IO [String]
listDirectory String
wdir
[String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> IO [String]) -> [String] -> IO [String]
forall a b. (a -> b) -> a -> b
$ (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter ((String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== ".cabal") (String -> Bool) -> (String -> String) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
takeExtension) [String]
dirContent
processCabalWrapperArgs :: [String] -> Maybe (FilePath, [String])
processCabalWrapperArgs :: [String] -> Maybe GhcProc
processCabalWrapperArgs args :: [String]
args =
case [String]
args of
(dir :: String
dir: ghc_args :: [String]
ghc_args) ->
let final_args :: [String]
final_args =
[String] -> [String]
removeVerbosityOpts
([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ [String] -> [String]
removeRTS
([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ [String] -> [String]
removeInteractive
([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$ [String]
ghc_args
in GhcProc -> Maybe GhcProc
forall a. a -> Maybe a
Just (String
dir, [String]
final_args)
_ -> Maybe GhcProc
forall a. Maybe a
Nothing
type GhcProc = (FilePath, [String])
withCabalWrapperTool :: GhcProc -> FilePath -> IO FilePath
withCabalWrapperTool :: GhcProc -> String -> IO String
withCabalWrapperTool (mbGhc :: String
mbGhc, ghcArgs :: [String]
ghcArgs) wdir :: String
wdir = do
String
cacheDir <- String -> IO String
getCacheDir ""
Bool -> LoggingFunction
createDirectoryIfMissing Bool
True String
cacheDir
let wrapperContents :: String
wrapperContents = if Bool
isWindows then String
cabalWrapperHs else String
cabalWrapper
suffix :: String -> String
suffix fp :: String
fp = if Bool
isWindows then String
fp String -> String -> String
<.> "exe" else String
fp
let srcHash :: String
srcHash = Fingerprint -> String
forall a. Show a => a -> String
show (String -> Fingerprint
fingerprintString String
wrapperContents)
let wrapper_name :: String
wrapper_name = "wrapper-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
srcHash
let wrapper_fp :: String
wrapper_fp = String -> String
suffix (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ String
cacheDir String -> String -> String
</> String
wrapper_name
Bool
exists <- String -> IO Bool
doesFileExist String
wrapper_fp
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
exists (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
if Bool
isWindows
then do
String -> LoggingFunction -> IO ()
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
String -> (String -> m a) -> m a
withSystemTempDirectory "hie-bios" (LoggingFunction -> IO ()) -> LoggingFunction -> IO ()
forall a b. (a -> b) -> a -> b
$ \ tmpDir :: String
tmpDir -> do
let wrapper_hs :: String
wrapper_hs = String
cacheDir String -> String -> String
</> String
wrapper_name String -> String -> String
<.> "hs"
String -> LoggingFunction
writeFile String
wrapper_hs String
wrapperContents
let ghc :: CreateProcess
ghc = (String -> [String] -> CreateProcess
proc String
mbGhc ([String] -> CreateProcess) -> [String] -> CreateProcess
forall a b. (a -> b) -> a -> b
$
[String]
ghcArgs [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ ["-rtsopts=ignore", "-outputdir", String
tmpDir, "-o", String
wrapper_fp, String
wrapper_hs])
{ cwd :: Maybe String
cwd = String -> Maybe String
forall a. a -> Maybe a
Just String
wdir }
CreateProcess -> String -> IO String
readCreateProcess CreateProcess
ghc "" IO String -> LoggingFunction -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= LoggingFunction
putStr
else String -> LoggingFunction
writeFile String
wrapper_fp String
wrapperContents
LoggingFunction
setMode String
wrapper_fp
String -> IO String
forall (f :: * -> *) a. Applicative f => a -> f a
pure String
wrapper_fp
where
setMode :: LoggingFunction
setMode wrapper_fp :: String
wrapper_fp = String -> FileMode -> IO ()
setFileMode String
wrapper_fp FileMode
accessModes
cabalBuildDir :: FilePath -> IO FilePath
cabalBuildDir :: String -> IO String
cabalBuildDir work_dir :: String
work_dir = do
String
abs_work_dir <- String -> IO String
makeAbsolute String
work_dir
let dirHash :: String
dirHash = Fingerprint -> String
forall a. Show a => a -> String
show (String -> Fingerprint
fingerprintString String
abs_work_dir)
String -> IO String
getCacheDir ("dist-"String -> String -> String
forall a. Semigroup a => a -> a -> a
<>(Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace) (String -> String
takeBaseName String
abs_work_dir)String -> String -> String
forall a. Semigroup a => a -> a -> a
<>"-"String -> String -> String
forall a. Semigroup a => a -> a -> a
<>String
dirHash)
cabalAction :: FilePath -> Maybe String -> LoggingFunction -> FilePath -> IO (CradleLoadResult ComponentOptions)
cabalAction :: String
-> Maybe String
-> LoggingFunction
-> String
-> IO (CradleLoadResult ComponentOptions)
cabalAction work_dir :: String
work_dir mc :: Maybe String
mc l :: LoggingFunction
l fp :: String
fp = do
String
wrapper_fp <- GhcProc -> String -> IO String
withCabalWrapperTool ("ghc", []) String
work_dir
String
buildDir <- String -> IO String
cabalBuildDir String
work_dir
let cab_args :: [String]
cab_args = ["--builddir="String -> String -> String
forall a. Semigroup a => a -> a -> a
<>String
buildDir,"v2-repl", "--with-compiler", String
wrapper_fp, String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe (String -> String
fixTargetPath String
fp) Maybe String
mc]
(ex :: ExitCode
ex, output :: [String]
output, stde :: [String]
stde, [(_,mb_args :: Maybe [String]
mb_args)]) <-
[String]
-> LoggingFunction
-> String
-> CreateProcess
-> IO (ExitCode, [String], [String], [(String, Maybe [String])])
readProcessWithOutputs [String
hie_bios_output] LoggingFunction
l String
work_dir (String -> [String] -> CreateProcess
proc "cabal" [String]
cab_args)
let args :: [String]
args = [String] -> Maybe [String] -> [String]
forall a. a -> Maybe a -> a
fromMaybe [] Maybe [String]
mb_args
case [String] -> Maybe GhcProc
processCabalWrapperArgs [String]
args of
Nothing -> do
[String]
deps <- String -> String -> IO [String]
cabalCradleDependencies String
work_dir String
work_dir
CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions))
-> CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall a b. (a -> b) -> a -> b
$ CradleError -> CradleLoadResult ComponentOptions
forall r. CradleError -> CradleLoadResult r
CradleFail ([String] -> ExitCode -> [String] -> CradleError
CradleError [String]
deps ExitCode
ex
["Failed to parse result of calling cabal"
, [String] -> String
unlines [String]
output
, [String] -> String
unlines [String]
stde
, [String] -> String
unlines ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ [String]
args])
Just (componentDir :: String
componentDir, final_args :: [String]
final_args) -> do
[String]
deps <- String -> String -> IO [String]
cabalCradleDependencies String
work_dir String
componentDir
CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions))
-> CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall a b. (a -> b) -> a -> b
$ (ExitCode, [String], String, [String])
-> [String] -> CradleLoadResult ComponentOptions
makeCradleResult (ExitCode
ex, [String]
stde, String
componentDir, [String]
final_args) [String]
deps
where
fixTargetPath :: String -> String
fixTargetPath x :: String
x
| Bool
isWindows Bool -> Bool -> Bool
&& String -> Bool
hasDrive String
x = String -> String -> String
makeRelative String
work_dir String
x
| Bool
otherwise = String
x
removeInteractive :: [String] -> [String]
removeInteractive :: [String] -> [String]
removeInteractive = (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= "--interactive")
data InRTS = OutsideRTS | InsideRTS
removeRTS :: [String] -> [String]
removeRTS :: [String] -> [String]
removeRTS = InRTS -> [String] -> [String]
go InRTS
OutsideRTS
where
go :: InRTS -> [String] -> [String]
go :: InRTS -> [String] -> [String]
go _ [] = []
go OutsideRTS (y :: String
y:ys :: [String]
ys)
| "+RTS" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
y = InRTS -> [String] -> [String]
go (if "-RTS" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isSuffixOf` String
y then InRTS
OutsideRTS else InRTS
InsideRTS) [String]
ys
| Bool
otherwise = String
y String -> [String] -> [String]
forall a. a -> [a] -> [a]
: InRTS -> [String] -> [String]
go InRTS
OutsideRTS [String]
ys
go InsideRTS (y :: String
y:ys :: [String]
ys) = InRTS -> [String] -> [String]
go (if "-RTS" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isSuffixOf` String
y then InRTS
OutsideRTS else InRTS
InsideRTS) [String]
ys
removeVerbosityOpts :: [String] -> [String]
removeVerbosityOpts :: [String] -> [String]
removeVerbosityOpts = (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool -> Bool
(&&) (Bool -> Bool -> Bool)
-> (String -> Bool) -> String -> Bool -> Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= "-v0") (String -> Bool -> Bool) -> (String -> Bool) -> String -> Bool
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= "-w"))
cabalWorkDir :: FilePath -> MaybeT IO FilePath
cabalWorkDir :: String -> MaybeT IO String
cabalWorkDir wdir :: String
wdir =
(String -> Bool) -> String -> MaybeT IO String
findFileUpwards (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "cabal.project") String
wdir
MaybeT IO String -> MaybeT IO String -> MaybeT IO String
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (String -> Bool) -> String -> MaybeT IO String
findFileUpwards (\fp :: String
fp -> String -> String
takeExtension String
fp String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== ".cabal") String
wdir
data StackYaml
= NoExplicitYaml
| ExplicitYaml FilePath
stackYamlFromMaybe :: FilePath -> Maybe FilePath -> StackYaml
stackYamlFromMaybe :: String -> Maybe String -> StackYaml
stackYamlFromMaybe _wdir :: String
_wdir Nothing = StackYaml
NoExplicitYaml
stackYamlFromMaybe wdir :: String
wdir (Just fp :: String
fp) = String -> StackYaml
ExplicitYaml (String
wdir String -> String -> String
</> String
fp)
stackYamlProcessArgs :: StackYaml -> [String]
stackYamlProcessArgs :: StackYaml -> [String]
stackYamlProcessArgs (ExplicitYaml yaml :: String
yaml) = ["--stack-yaml", String
yaml]
stackYamlProcessArgs NoExplicitYaml = []
stackYamlLocationOrDefault :: StackYaml -> FilePath
stackYamlLocationOrDefault :: StackYaml -> String
stackYamlLocationOrDefault NoExplicitYaml = "stack.yaml"
stackYamlLocationOrDefault (ExplicitYaml yaml :: String
yaml) = String
yaml
stackCradle :: FilePath -> Maybe String -> StackYaml -> Cradle a
stackCradle :: String -> Maybe String -> StackYaml -> Cradle a
stackCradle wdir :: String
wdir mc :: Maybe String
mc syaml :: StackYaml
syaml =
Cradle :: forall a. String -> CradleAction a -> Cradle a
Cradle
{ cradleRootDir :: String
cradleRootDir = String
wdir
, cradleOptsProg :: CradleAction a
cradleOptsProg = CradleAction :: forall a.
ActionName a
-> (LoggingFunction
-> String -> IO (CradleLoadResult ComponentOptions))
-> ([String] -> IO (CradleLoadResult String))
-> CradleAction a
CradleAction
{ actionName :: ActionName a
actionName = ActionName a
forall a. ActionName a
Types.Stack
, runCradle :: LoggingFunction -> String -> IO (CradleLoadResult ComponentOptions)
runCradle = String
-> Maybe String
-> StackYaml
-> LoggingFunction
-> String
-> IO (CradleLoadResult ComponentOptions)
stackAction String
wdir Maybe String
mc StackYaml
syaml
, runGhcCmd :: [String] -> IO (CradleLoadResult String)
runGhcCmd = \args :: [String]
args ->
String
-> String -> [String] -> String -> IO (CradleLoadResult String)
readProcessWithCwd String
wdir "stack"
(StackYaml -> [String]
stackYamlProcessArgs StackYaml
syaml [String] -> [String] -> [String]
forall a. Semigroup a => a -> a -> a
<> ["exec", "--silent", "ghc", "--"] [String] -> [String] -> [String]
forall a. Semigroup a => a -> a -> a
<> [String]
args)
""
}
}
stackCradleDependencies :: FilePath -> FilePath -> StackYaml -> IO [FilePath]
stackCradleDependencies :: String -> String -> StackYaml -> IO [String]
stackCradleDependencies wdir :: String
wdir componentDir :: String
componentDir syaml :: StackYaml
syaml = do
let relFp :: String
relFp = String -> String -> String
makeRelative String
wdir String
componentDir
[String]
cabalFiles' <- String -> IO [String]
findCabalFiles String
componentDir
let cabalFiles :: [String]
cabalFiles = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String
relFp String -> String -> String
</>) [String]
cabalFiles'
[String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> IO [String]) -> [String] -> IO [String]
forall a b. (a -> b) -> a -> b
$ (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
normalise ([String] -> [String]) -> [String] -> [String]
forall a b. (a -> b) -> a -> b
$
[String]
cabalFiles [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String
relFp String -> String -> String
</> "package.yaml", StackYaml -> String
stackYamlLocationOrDefault StackYaml
syaml]
stackAction :: FilePath -> Maybe String -> StackYaml -> LoggingFunction -> FilePath -> IO (CradleLoadResult ComponentOptions)
stackAction :: String
-> Maybe String
-> StackYaml
-> LoggingFunction
-> String
-> IO (CradleLoadResult ComponentOptions)
stackAction work_dir :: String
work_dir mc :: Maybe String
mc syaml :: StackYaml
syaml l :: LoggingFunction
l _fp :: String
_fp = do
let ghcProcArgs :: GhcProc
ghcProcArgs = ("stack", StackYaml -> [String]
stackYamlProcessArgs StackYaml
syaml [String] -> [String] -> [String]
forall a. Semigroup a => a -> a -> a
<> ["exec", "ghc", "--"])
String
wrapper_fp <- GhcProc -> String -> IO String
withCabalWrapperTool GhcProc
ghcProcArgs String
work_dir
(ex1 :: ExitCode
ex1, _stdo :: [String]
_stdo, stde :: [String]
stde, [(_, mb_args :: Maybe [String]
mb_args)]) <-
[String]
-> LoggingFunction
-> String
-> CreateProcess
-> IO (ExitCode, [String], [String], [(String, Maybe [String])])
readProcessWithOutputs [String
hie_bios_output] LoggingFunction
l String
work_dir (CreateProcess
-> IO (ExitCode, [String], [String], [(String, Maybe [String])]))
-> CreateProcess
-> IO (ExitCode, [String], [String], [(String, Maybe [String])])
forall a b. (a -> b) -> a -> b
$
StackYaml -> [String] -> CreateProcess
stackProcess StackYaml
syaml
([String] -> CreateProcess) -> [String] -> CreateProcess
forall a b. (a -> b) -> a -> b
$ ["repl", "--no-nix-pure", "--with-ghc", String
wrapper_fp]
[String] -> [String] -> [String]
forall a. Semigroup a => a -> a -> a
<> [ String
comp | Just comp :: String
comp <- [Maybe String
mc] ]
(ex2 :: ExitCode
ex2, pkg_args :: [String]
pkg_args, stdr :: [String]
stdr, _) <-
[String]
-> LoggingFunction
-> String
-> CreateProcess
-> IO (ExitCode, [String], [String], [(String, Maybe [String])])
readProcessWithOutputs [String
hie_bios_output] LoggingFunction
l String
work_dir (CreateProcess
-> IO (ExitCode, [String], [String], [(String, Maybe [String])]))
-> CreateProcess
-> IO (ExitCode, [String], [String], [(String, Maybe [String])])
forall a b. (a -> b) -> a -> b
$
StackYaml -> [String] -> CreateProcess
stackProcess StackYaml
syaml ["path", "--ghc-package-path"]
let split_pkgs :: [String]
split_pkgs = (String -> [String]) -> [String] -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap String -> [String]
splitSearchPath [String]
pkg_args
pkg_ghc_args :: [String]
pkg_ghc_args = (String -> [String]) -> [String] -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\p :: String
p -> ["-package-db", String
p] ) [String]
split_pkgs
args :: [String]
args = [String] -> Maybe [String] -> [String]
forall a. a -> Maybe a -> a
fromMaybe [] Maybe [String]
mb_args
case [String] -> Maybe GhcProc
processCabalWrapperArgs [String]
args of
Nothing -> do
[String]
deps <- String -> String -> StackYaml -> IO [String]
stackCradleDependencies String
work_dir String
work_dir StackYaml
syaml
CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions))
-> CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall a b. (a -> b) -> a -> b
$ CradleError -> CradleLoadResult ComponentOptions
forall r. CradleError -> CradleLoadResult r
CradleFail
([String] -> ExitCode -> [String] -> CradleError
CradleError [String]
deps ExitCode
ex1 ([String] -> CradleError) -> [String] -> CradleError
forall a b. (a -> b) -> a -> b
$
[ "Failed to parse result of calling stack" ]
[String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
stde
[String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
args
)
Just (componentDir :: String
componentDir, ghc_args :: [String]
ghc_args) -> do
[String]
deps <- String -> String -> StackYaml -> IO [String]
stackCradleDependencies String
work_dir String
componentDir StackYaml
syaml
CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions))
-> CradleLoadResult ComponentOptions
-> IO (CradleLoadResult ComponentOptions)
forall a b. (a -> b) -> a -> b
$ (ExitCode, [String], String, [String])
-> [String] -> CradleLoadResult ComponentOptions
makeCradleResult
( [ExitCode] -> ExitCode
combineExitCodes [ExitCode
ex1, ExitCode
ex2]
, [String]
stde [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
stdr, String
componentDir
, [String]
ghc_args [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
pkg_ghc_args
)
[String]
deps
stackProcess :: StackYaml -> [String] -> CreateProcess
stackProcess :: StackYaml -> [String] -> CreateProcess
stackProcess syaml :: StackYaml
syaml args :: [String]
args = String -> [String] -> CreateProcess
proc "stack" ([String] -> CreateProcess) -> [String] -> CreateProcess
forall a b. (a -> b) -> a -> b
$ StackYaml -> [String]
stackYamlProcessArgs StackYaml
syaml [String] -> [String] -> [String]
forall a. Semigroup a => a -> a -> a
<> [String]
args
combineExitCodes :: [ExitCode] -> ExitCode
combineExitCodes :: [ExitCode] -> ExitCode
combineExitCodes = (ExitCode -> ExitCode -> ExitCode)
-> ExitCode -> [ExitCode] -> ExitCode
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr ExitCode -> ExitCode -> ExitCode
go ExitCode
ExitSuccess
where
go :: ExitCode -> ExitCode -> ExitCode
go ExitSuccess b :: ExitCode
b = ExitCode
b
go a :: ExitCode
a _ = ExitCode
a
stackExecutable :: MaybeT IO FilePath
stackExecutable :: MaybeT IO String
stackExecutable = IO (Maybe String) -> MaybeT IO String
forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT (IO (Maybe String) -> MaybeT IO String)
-> IO (Maybe String) -> MaybeT IO String
forall a b. (a -> b) -> a -> b
$ String -> IO (Maybe String)
findExecutable "stack"
stackWorkDir :: FilePath -> MaybeT IO FilePath
stackWorkDir :: String -> MaybeT IO String
stackWorkDir = (String -> Bool) -> String -> MaybeT IO String
findFileUpwards String -> Bool
isStack
where
isStack :: String -> Bool
isStack name :: String
name = String
name String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "stack.yaml"
findFileUpwards :: (FilePath -> Bool) -> FilePath -> MaybeT IO FilePath
findFileUpwards :: (String -> Bool) -> String -> MaybeT IO String
findFileUpwards p :: String -> Bool
p dir :: String
dir = do
[String]
cnts <-
IO [String] -> MaybeT IO [String]
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO
(IO [String] -> MaybeT IO [String])
-> IO [String] -> MaybeT IO [String]
forall a b. (a -> b) -> a -> b
$ (IOError -> Maybe [String])
-> ([String] -> IO [String]) -> IO [String] -> IO [String]
forall e b a.
Exception e =>
(e -> Maybe b) -> (b -> IO a) -> IO a -> IO a
handleJust
(\(IOError
e :: IOError) -> if IOError -> Bool
isPermissionError IOError
e then [String] -> Maybe [String]
forall a. a -> Maybe a
Just [] else Maybe [String]
forall a. Maybe a
Nothing)
[String] -> IO [String]
forall (f :: * -> *) a. Applicative f => a -> f a
pure
((String -> Bool) -> String -> IO [String]
findFile String -> Bool
p String
dir)
case [String]
cnts of
[] | String
dir' String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
dir -> String -> MaybeT IO String
forall (m :: * -> *) a. MonadFail m => String -> m a
fail "No cabal files"
| Bool
otherwise -> (String -> Bool) -> String -> MaybeT IO String
findFileUpwards String -> Bool
p String
dir'
_ : _ -> String -> MaybeT IO String
forall (m :: * -> *) a. Monad m => a -> m a
return String
dir
where dir' :: String
dir' = String -> String
takeDirectory String
dir
findFile :: (FilePath -> Bool) -> FilePath -> IO [FilePath]
findFile :: (String -> Bool) -> String -> IO [String]
findFile p :: String -> Bool
p dir :: String
dir = do
Bool
b <- String -> IO Bool
doesDirectoryExist String
dir
if Bool
b then IO [String]
getFiles IO [String] -> ([String] -> IO [String]) -> IO [String]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (String -> IO Bool) -> [String] -> IO [String]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM String -> IO Bool
doesPredFileExist else [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return []
where
getFiles :: IO [String]
getFiles = (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter String -> Bool
p ([String] -> [String]) -> IO [String] -> IO [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO [String]
getDirectoryContents String
dir
doesPredFileExist :: String -> IO Bool
doesPredFileExist file :: String
file = String -> IO Bool
doesFileExist (String -> IO Bool) -> String -> IO Bool
forall a b. (a -> b) -> a -> b
$ String
dir String -> String -> String
</> String
file
getCleanEnvironment :: IO [(String, String)]
getCleanEnvironment :: IO [(String, String)]
getCleanEnvironment = do
[(String, String)]
e <- IO [(String, String)]
getEnvironment
[(String, String)] -> IO [(String, String)]
forall (m :: * -> *) a. Monad m => a -> m a
return ([(String, String)] -> IO [(String, String)])
-> [(String, String)] -> IO [(String, String)]
forall a b. (a -> b) -> a -> b
$ HashMap String String -> [(String, String)]
forall k v. HashMap k v -> [(k, v)]
Map.toList (HashMap String String -> [(String, String)])
-> HashMap String String -> [(String, String)]
forall a b. (a -> b) -> a -> b
$ String -> HashMap String String -> HashMap String String
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> HashMap k v
Map.delete "GHC_PACKAGE_PATH" (HashMap String String -> HashMap String String)
-> HashMap String String -> HashMap String String
forall a b. (a -> b) -> a -> b
$ [(String, String)] -> HashMap String String
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
Map.fromList [(String, String)]
e
type Outputs = [OutputName]
type OutputName = String
readProcessWithOutputs
:: Outputs
-> LoggingFunction
-> FilePath
-> CreateProcess
-> IO (ExitCode, [String], [String], [(OutputName, Maybe [String])])
readProcessWithOutputs :: [String]
-> LoggingFunction
-> String
-> CreateProcess
-> IO (ExitCode, [String], [String], [(String, Maybe [String])])
readProcessWithOutputs outputNames :: [String]
outputNames l :: LoggingFunction
l work_dir :: String
work_dir cp :: CreateProcess
cp = (ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(ExitCode, [String], [String], [(String, Maybe [String])])
-> ((ExitCode, [String], [String], [(String, Maybe [String])])
-> IO (ExitCode, [String], [String], [(String, Maybe [String])]))
-> IO (ExitCode, [String], [String], [(String, Maybe [String])]))
-> ((ExitCode, [String], [String], [(String, Maybe [String])])
-> IO (ExitCode, [String], [String], [(String, Maybe [String])]))
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(ExitCode, [String], [String], [(String, Maybe [String])])
-> IO (ExitCode, [String], [String], [(String, Maybe [String])])
forall a b c. (a -> b -> c) -> b -> a -> c
flip ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(ExitCode, [String], [String], [(String, Maybe [String])])
-> ((ExitCode, [String], [String], [(String, Maybe [String])])
-> IO (ExitCode, [String], [String], [(String, Maybe [String])]))
-> IO (ExitCode, [String], [String], [(String, Maybe [String])])
forall k (r :: k) (m :: k -> *) a. ContT r m a -> (a -> m r) -> m r
runContT (ExitCode, [String], [String], [(String, Maybe [String])])
-> IO (ExitCode, [String], [String], [(String, Maybe [String])])
forall (m :: * -> *) a. Monad m => a -> m a
return (ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(ExitCode, [String], [String], [(String, Maybe [String])])
-> IO (ExitCode, [String], [String], [(String, Maybe [String])]))
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(ExitCode, [String], [String], [(String, Maybe [String])])
-> IO (ExitCode, [String], [String], [(String, Maybe [String])])
forall a b. (a -> b) -> a -> b
$ do
[(String, String)]
old_env <- IO [(String, String)]
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
[(String, String)]
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO [(String, String)]
getCleanEnvironment
[(String, String)]
output_files <- (String
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(String, String))
-> [String]
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
[(String, String)]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse ([(String, String)]
-> String
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(String, String)
forall a.
[(String, String)] -> String -> ContT a IO (String, String)
withOutput [(String, String)]
old_env) [String]
outputNames
let process :: CreateProcess
process = CreateProcess
cp { env :: Maybe [(String, String)]
env = [(String, String)] -> Maybe [(String, String)]
forall a. a -> Maybe a
Just ([(String, String)] -> Maybe [(String, String)])
-> [(String, String)] -> Maybe [(String, String)]
forall a b. (a -> b) -> a -> b
$ [(String, String)]
output_files [(String, String)] -> [(String, String)] -> [(String, String)]
forall a. [a] -> [a] -> [a]
++ [(String, String)]
-> Maybe [(String, String)] -> [(String, String)]
forall a. a -> Maybe a -> a
fromMaybe [(String, String)]
old_env (CreateProcess -> Maybe [(String, String)]
env CreateProcess
cp),
cwd :: Maybe String
cwd = String -> Maybe String
forall a. a -> Maybe a
Just String
work_dir
}
let loggingConduit :: ConduitM ByteString c IO [String]
loggingConduit = ConduitT ByteString Text IO ()
forall (m :: * -> *). MonadThrow m => ConduitT ByteString Text m ()
C.decodeUtf8 ConduitT ByteString Text IO ()
-> ConduitM Text c IO [String] -> ConduitM ByteString c IO [String]
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
C..| ConduitT Text Text IO ()
forall (m :: * -> *). Monad m => ConduitT Text Text m ()
C.lines ConduitT Text Text IO ()
-> ConduitM Text c IO [String] -> ConduitM Text c IO [String]
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
C..| (Element Text -> Bool) -> ConduitT Text Text IO ()
forall seq (m :: * -> *).
(IsSequence seq, Monad m) =>
(Element seq -> Bool) -> ConduitT seq seq m ()
C.filterE (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '\r') ConduitT Text Text IO ()
-> ConduitM Text c IO [String] -> ConduitM Text c IO [String]
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
C..| (Text -> String) -> ConduitT Text String IO ()
forall (m :: * -> *) a b. Monad m => (a -> b) -> ConduitT a b m ()
C.map Text -> String
T.unpack ConduitT Text String IO ()
-> ConduitM String c IO [String] -> ConduitM Text c IO [String]
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
C..| LoggingFunction -> ConduitT String String IO ()
forall (m :: * -> *) a. Monad m => (a -> m ()) -> ConduitT a a m ()
C.iterM LoggingFunction
l ConduitT String String IO ()
-> ConduitM String c IO [String] -> ConduitM String c IO [String]
forall (m :: * -> *) a b c r.
Monad m =>
ConduitM a b m () -> ConduitM b c m r -> ConduitM a c m r
C..| ConduitM String c IO [String]
forall (m :: * -> *) a o. Monad m => ConduitT a o m [a]
C.sinkList
(ex :: ExitCode
ex, stdo :: [String]
stdo, stde :: [String]
stde) <- IO (ExitCode, [String], [String])
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(ExitCode, [String], [String])
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (ExitCode, [String], [String])
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(ExitCode, [String], [String]))
-> IO (ExitCode, [String], [String])
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(ExitCode, [String], [String])
forall a b. (a -> b) -> a -> b
$ CreateProcess
-> ConduitT () ByteString IO ()
-> ConduitT ByteString Void IO [String]
-> ConduitT ByteString Void IO [String]
-> IO (ExitCode, [String], [String])
forall (m :: * -> *) a b.
MonadUnliftIO m =>
CreateProcess
-> ConduitT () ByteString m ()
-> ConduitT ByteString Void m a
-> ConduitT ByteString Void m b
-> m (ExitCode, a, b)
sourceProcessWithStreams CreateProcess
process ConduitT () ByteString IO ()
forall a. Monoid a => a
mempty ConduitT ByteString Void IO [String]
forall c. ConduitM ByteString c IO [String]
loggingConduit ConduitT ByteString Void IO [String]
forall c. ConduitM ByteString c IO [String]
loggingConduit
[(String, Maybe [String])]
res <- [(String, String)]
-> ((String, String)
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(String, Maybe [String]))
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
[(String, Maybe [String])]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [(String, String)]
output_files (((String, String)
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(String, Maybe [String]))
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
[(String, Maybe [String])])
-> ((String, String)
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(String, Maybe [String]))
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
[(String, Maybe [String])]
forall a b. (a -> b) -> a -> b
$ \(name :: String
name,path :: String
path) ->
IO (String, Maybe [String])
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(String, Maybe [String])
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (String, Maybe [String])
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(String, Maybe [String]))
-> IO (String, Maybe [String])
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(String, Maybe [String])
forall a b. (a -> b) -> a -> b
$ (String
name,) (Maybe [String] -> (String, Maybe [String]))
-> IO (Maybe [String]) -> IO (String, Maybe [String])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO (Maybe [String])
readOutput String
path
(ExitCode, [String], [String], [(String, Maybe [String])])
-> ContT
(ExitCode, [String], [String], [(String, Maybe [String])])
IO
(ExitCode, [String], [String], [(String, Maybe [String])])
forall (m :: * -> *) a. Monad m => a -> m a
return (ExitCode
ex, [String]
stdo, [String]
stde, [(String, Maybe [String])]
res)
where
readOutput :: FilePath -> IO (Maybe [String])
readOutput :: String -> IO (Maybe [String])
readOutput path :: String
path = do
Bool
haveFile <- String -> IO Bool
doesFileExist String
path
if Bool
haveFile
then String
-> IOMode -> (Handle -> IO (Maybe [String])) -> IO (Maybe [String])
forall r. String -> IOMode -> (Handle -> IO r) -> IO r
withFile String
path IOMode
ReadMode ((Handle -> IO (Maybe [String])) -> IO (Maybe [String]))
-> (Handle -> IO (Maybe [String])) -> IO (Maybe [String])
forall a b. (a -> b) -> a -> b
$ \handle :: Handle
handle -> do
Handle -> BufferMode -> IO ()
hSetBuffering Handle
handle BufferMode
LineBuffering
!String
res <- String -> String
forall a. NFData a => a -> a
force (String -> String) -> IO String -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Handle -> IO String
hGetContents Handle
handle
Maybe [String] -> IO (Maybe [String])
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe [String] -> IO (Maybe [String]))
-> Maybe [String] -> IO (Maybe [String])
forall a b. (a -> b) -> a -> b
$ [String] -> Maybe [String]
forall a. a -> Maybe a
Just ([String] -> Maybe [String]) -> [String] -> Maybe [String]
forall a b. (a -> b) -> a -> b
$ String -> [String]
lines (String -> [String]) -> String -> [String]
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
filter (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= '\r') String
res
else
Maybe [String] -> IO (Maybe [String])
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe [String]
forall a. Maybe a
Nothing
withOutput :: [(String,String)] -> OutputName -> ContT a IO (OutputName, String)
withOutput :: [(String, String)] -> String -> ContT a IO (String, String)
withOutput env' :: [(String, String)]
env' name :: String
name =
case String -> [(String, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup String
name [(String, String)]
env' of
Just file :: String
file@(_:_) -> (((String, String) -> IO a) -> IO a) -> ContT a IO (String, String)
forall k (r :: k) (m :: k -> *) a.
((a -> m r) -> m r) -> ContT r m a
ContT ((((String, String) -> IO a) -> IO a)
-> ContT a IO (String, String))
-> (((String, String) -> IO a) -> IO a)
-> ContT a IO (String, String)
forall a b. (a -> b) -> a -> b
$ \action :: (String, String) -> IO a
action -> do
LoggingFunction
removeFileIfExists String
file
(String, String) -> IO a
action (String
name, String
file)
_ -> (((String, String) -> IO a) -> IO a) -> ContT a IO (String, String)
forall k (r :: k) (m :: k -> *) a.
((a -> m r) -> m r) -> ContT r m a
ContT ((((String, String) -> IO a) -> IO a)
-> ContT a IO (String, String))
-> (((String, String) -> IO a) -> IO a)
-> ContT a IO (String, String)
forall a b. (a -> b) -> a -> b
$ \action :: (String, String) -> IO a
action -> String -> (String -> Handle -> IO a) -> IO a
forall (m :: * -> *) a.
(MonadIO m, MonadMask m) =>
String -> (String -> Handle -> m a) -> m a
withSystemTempFile String
name ((String -> Handle -> IO a) -> IO a)
-> (String -> Handle -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \ file :: String
file h :: Handle
h -> do
Handle -> IO ()
hClose Handle
h
LoggingFunction
removeFileIfExists String
file
(String, String) -> IO a
action (String
name, String
file)
removeFileIfExists :: FilePath -> IO ()
removeFileIfExists :: LoggingFunction
removeFileIfExists f :: String
f = do
Bool
yes <- String -> IO Bool
doesFileExist String
f
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
yes (LoggingFunction
removeFile String
f)
makeCradleResult :: (ExitCode, [String], FilePath, [String]) -> [FilePath] -> CradleLoadResult ComponentOptions
makeCradleResult :: (ExitCode, [String], String, [String])
-> [String] -> CradleLoadResult ComponentOptions
makeCradleResult (ex :: ExitCode
ex, err :: [String]
err, componentDir :: String
componentDir, gopts :: [String]
gopts) deps :: [String]
deps =
case ExitCode
ex of
ExitFailure _ -> CradleError -> CradleLoadResult ComponentOptions
forall r. CradleError -> CradleLoadResult r
CradleFail ([String] -> ExitCode -> [String] -> CradleError
CradleError [String]
deps ExitCode
ex [String]
err)
_ ->
let compOpts :: ComponentOptions
compOpts = [String] -> String -> [String] -> ComponentOptions
ComponentOptions [String]
gopts String
componentDir [String]
deps
in ComponentOptions -> CradleLoadResult ComponentOptions
forall r. r -> CradleLoadResult r
CradleSuccess ComponentOptions
compOpts
runGhcCmdOnPath :: FilePath -> [String] -> IO (CradleLoadResult String)
runGhcCmdOnPath :: String -> [String] -> IO (CradleLoadResult String)
runGhcCmdOnPath wdir :: String
wdir args :: [String]
args = String
-> String -> [String] -> String -> IO (CradleLoadResult String)
readProcessWithCwd String
wdir "ghc" [String]
args ""
readProcessWithCwd :: FilePath -> FilePath -> [String] -> String -> IO (CradleLoadResult String)
readProcessWithCwd :: String
-> String -> [String] -> String -> IO (CradleLoadResult String)
readProcessWithCwd dir :: String
dir cmd :: String
cmd args :: [String]
args stdi :: String
stdi = do
[(String, String)]
cleanEnv <- IO [(String, String)]
getCleanEnvironment
let createProc :: CreateProcess
createProc = (String -> [String] -> CreateProcess
proc String
cmd [String]
args) { cwd :: Maybe String
cwd = String -> Maybe String
forall a. a -> Maybe a
Just String
dir, env :: Maybe [(String, String)]
env = [(String, String)] -> Maybe [(String, String)]
forall a. a -> Maybe a
Just [(String, String)]
cleanEnv }
Maybe (ExitCode, String, String)
mResult <- IO (ExitCode, String, String)
-> IO (Maybe (ExitCode, String, String))
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional (IO (ExitCode, String, String)
-> IO (Maybe (ExitCode, String, String)))
-> IO (ExitCode, String, String)
-> IO (Maybe (ExitCode, String, String))
forall a b. (a -> b) -> a -> b
$ CreateProcess -> String -> IO (ExitCode, String, String)
readCreateProcessWithExitCode CreateProcess
createProc String
stdi
case Maybe (ExitCode, String, String)
mResult of
Just (ExitSuccess, stdo :: String
stdo, _) -> CradleLoadResult String -> IO (CradleLoadResult String)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CradleLoadResult String -> IO (CradleLoadResult String))
-> CradleLoadResult String -> IO (CradleLoadResult String)
forall a b. (a -> b) -> a -> b
$ String -> CradleLoadResult String
forall r. r -> CradleLoadResult r
CradleSuccess String
stdo
Just (exitCode :: ExitCode
exitCode, stdo :: String
stdo, stde :: String
stde) -> CradleLoadResult String -> IO (CradleLoadResult String)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CradleLoadResult String -> IO (CradleLoadResult String))
-> CradleLoadResult String -> IO (CradleLoadResult String)
forall a b. (a -> b) -> a -> b
$ CradleError -> CradleLoadResult String
forall r. CradleError -> CradleLoadResult r
CradleFail (CradleError -> CradleLoadResult String)
-> CradleError -> CradleLoadResult String
forall a b. (a -> b) -> a -> b
$
[String] -> ExitCode -> [String] -> CradleError
CradleError [] ExitCode
exitCode ["Error when calling " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
cmd String -> String -> String
forall a. Semigroup a => a -> a -> a
<> " " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> [String] -> String
unwords [String]
args, String
stdo, String
stde]
Nothing -> CradleLoadResult String -> IO (CradleLoadResult String)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (CradleLoadResult String -> IO (CradleLoadResult String))
-> CradleLoadResult String -> IO (CradleLoadResult String)
forall a b. (a -> b) -> a -> b
$ CradleError -> CradleLoadResult String
forall r. CradleError -> CradleLoadResult r
CradleFail (CradleError -> CradleLoadResult String)
-> CradleError -> CradleLoadResult String
forall a b. (a -> b) -> a -> b
$
[String] -> ExitCode -> [String] -> CradleError
CradleError [] ExitCode
ExitSuccess ["Couldn't execute " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
cmd String -> String -> String
forall a. Semigroup a => a -> a -> a
<> " " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> [String] -> String
unwords [String]
args]