which-0.2: src/System/Which.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
module System.Which (which, staticWhich, staticWhichNix) 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
staticWhichImpl :: (FilePath -> Maybe String) -> FilePath -> Q Exp
staticWhichImpl test f = do
mf' <- runIO $ which f
case mf' of
Nothing -> compileError $ "Could not find executable for " <> show f
Just f' -> case test f' of
Just err -> compileError err
Nothing -> [| f' |]
where
compileError msg' = do
let msg = "staticWhich: " <> msg'
reportError msg
[| error msg |]
-- | Run `which` at compile time, and substitute the full path to the executable.
staticWhich :: FilePath -> Q Exp
staticWhich = staticWhichImpl (const Nothing)
-- A variant of 'staticWhich' that ensures the executable is in the nix store.
-- 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
staticWhichNix :: FilePath -> Q Exp
staticWhichNix = staticWhichImpl $ \x ->
if "/nix/store/" `isPrefixOf` x
then Nothing
else Just $ "Executable was found in " <> x <> " which is not in /nix/store."