-- | Template haskell expression to embed executables.
module Hydra.Node.EmbedTH where

import Hydra.Prelude

import Data.FileEmbed (embedFile)
import Language.Haskell.TH (Exp, Q, runIO)
import System.Directory (findExecutable)
import System.Environment qualified as Env

-- | Embed an executable selected by an environment variable, falling back to
-- PATH for native development builds. Cross builds supply the target executable
-- explicitly, independently of the tools running on the build machine.
embedExecutable :: String -> String -> Q Exp
embedExecutable :: String -> String -> Q Exp
embedExecutable String
pathVariable String
exe = do
  String
fp <- IO String -> Q String
forall a. IO a -> Q a
runIO (IO String -> Q String) -> IO String -> Q String
forall a b. (a -> b) -> a -> b
$ do
    Maybe String
configured <- String -> IO (Maybe String)
Env.lookupEnv String
pathVariable
    Maybe String
candidate <- IO (Maybe String)
-> (String -> IO (Maybe String))
-> Maybe String
-> IO (Maybe String)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> IO (Maybe String)
findExecutable String
exe) (Maybe String -> IO (Maybe String)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe String -> IO (Maybe String))
-> (String -> Maybe String) -> String -> IO (Maybe String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Maybe String
forall a. a -> Maybe a
Just) Maybe String
configured
    case Maybe String
candidate of
      Maybe String
Nothing -> String -> IO String
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO String) -> String -> IO String
forall a b. (a -> b) -> a -> b
$ String
exe String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" not found, ensure it is in PATH when compiling (and do a cabal clean)"
      Just String
fp -> do
        String -> IO ()
forall (m :: * -> *). MonadIO m => String -> m ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Embedding " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
exe String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
" from: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
fp
        String -> IO String
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure String
fp
  String -> Q Exp
embedFile String
fp