{-# LANGUAGE OverloadedStrings, TemplateHaskell #-}
module System.Which where

import qualified Shelly as Sh
import qualified Data.Text as T
import Language.Haskell.TH (Exp, Q, reportError, runIO)
import Data.Monoid ((<>))
import Data.List (isPrefixOf)

-- | Determine which executable would run if the given path were executed, or return Nothing if a suitable executable cannot be found
which :: FilePath -> IO (Maybe FilePath)
which f = fmap (fmap (T.unpack . Sh.toTextIgnore)) $ Sh.shelly $ Sh.which $ Sh.fromText $ T.pack f

-- | Run `which` at compile time, and substitute the full path to the executable.
--
-- This is useful in NixOS to ensure that the resulting executable contains the dependency in its closure and that it refers to the same version at run time as at compile time
staticWhich :: FilePath -> Q Exp
staticWhich f = do
  mf' <- runIO $ which f
  case mf' of
    Nothing -> compileError $ "Could not find executable for " <> show f
    Just f'
      | "/nix/store/" `isPrefixOf` f' -> [| f' |]
      | otherwise -> compileError $ "Path to executable " <> show f <> " was found in " <> show f' <> " which is not in /nix/store. Be sure to add the relevant package to 'backendTools' in default.nix."

  where
    compileError msg' = do
      let msg = "staticWhich: " <> msg'
      reportError msg
      [| error msg |]