module Distribution.Simple.Program.Find (
ProgramSearchPath,
ProgramSearchPathEntry(..),
defaultProgramSearchPath,
findProgramOnSearchPath,
programSearchPathAsPATHVar,
) where
import Distribution.Verbosity
( Verbosity )
import Distribution.Simple.Utils
( debug )
import Distribution.System
( OS(..), buildOS )
import System.Directory
( findExecutable, doesFileExist, Permissions(..), getPermissions )
import Distribution.Compat.Environment
( getEnvironment )
import System.FilePath
( (</>), (<.>), splitSearchPath, searchPathSeparator )
import Data.List
( intercalate )
type ProgramSearchPath = [ProgramSearchPathEntry]
data ProgramSearchPathEntry =
ProgramSearchPathDir FilePath
| ProgramSearchPathDefault
defaultProgramSearchPath :: ProgramSearchPath
defaultProgramSearchPath = [ProgramSearchPathDefault]
findProgramOnSearchPath :: Verbosity -> ProgramSearchPath
-> FilePath -> IO (Maybe FilePath)
findProgramOnSearchPath verbosity searchpath prog = do
debug verbosity $ "Searching for " ++ prog ++ " in path."
res <- tryPathElems searchpath
case res of
Nothing -> debug verbosity ("Cannot find " ++ prog ++ " on the path")
Just path -> debug verbosity ("Found " ++ prog ++ " at "++ path)
return res
where
tryPathElems [] = return Nothing
tryPathElems (pe:pes) = do
res <- tryPathElem pe
case res of
Nothing -> tryPathElems pes
Just _ -> return res
tryPathElem (ProgramSearchPathDir dir) =
findFirstExe [ dir </> prog <.> ext | ext <- extensions ]
where
extensions = case buildOS of
Windows -> ["", "exe"]
_ -> [""]
tryPathElem ProgramSearchPathDefault =
findExecutable prog
findFirstExe [] = return Nothing
findFirstExe (f:fs) = do
exists <- doesFileExist f
if exists
then do perms <- getPermissions f
if executable perms
then return (Just f)
else findFirstExe fs
else findFirstExe fs
programSearchPathAsPATHVar :: ProgramSearchPath -> IO String
programSearchPathAsPATHVar searchpath = do
ess <- mapM getEntries searchpath
return (intercalate [searchPathSeparator] (concat ess))
where
getEntries (ProgramSearchPathDir dir) = return [dir]
getEntries ProgramSearchPathDefault = do
env <- getEnvironment
return (maybe [] splitSearchPath (lookup "PATH" env))