blob: 066f68bbe0dfb482ce55b16e47c28edaf6773de2 (
plain) (
tree)
|
|
{-# LANGUAGE QuasiQuotes #-}
module Tool where
import Data.Error.Tree
import Label
import PossehlAnalyticsPrelude
import System.Environment qualified as Env
import System.Exit qualified as Exit
import System.FilePath ((</>))
import System.Posix qualified as Posix
import ValidationParseT
data Tool = Tool
{ -- | absolute path to the executable
toolPath :: FilePath
}
deriving stock (Show)
-- | Reads all tools from the @toolsEnvVar@ variable or aborts.
readTools ::
Label "toolsEnvVar" Text ->
-- | Parser for Tools we bring with us at build time.
--
-- These are executables that we need available, and that we have to ship with the distribution of @pa-cli@.
ToolParserT IO tools ->
IO tools
readTools env toolParser =
Env.lookupEnv (env.toolsEnvVar & textToString) >>= \case
Nothing -> do
Exit.die [fmt|Please set {env.toolsEnvVar} to a directory with all tools we need (see `Tools` in the code).|]
Just toolsDir ->
(Posix.fileExist toolsDir & ifTrueOrErr () [fmt|{env.toolsEnvVar} directory does not exist: {toolsDir}|])
& thenValidate
( \() ->
(Posix.getFileStatus toolsDir <&> Posix.isDirectory)
& ifTrueOrErr () [fmt|{env.toolsEnvVar} does not point to a directory: {toolsDir}|]
)
& thenValidate
(\() -> toolParser.unToolParser toolsDir)
<&> first (errorTree [fmt|Could not find all tools in {env.toolsEnvVar}|])
>>= \case
Failure err -> Exit.die (err & prettyErrorTree & textToString)
Success t -> pure t
newtype ToolParserT m a = ToolParserT
{ unToolParser ::
FilePath ->
m (Validation (NonEmpty Error) a)
}
deriving
(Functor, Applicative)
via (ValidationParseT FilePath m)
-- | Given a file path and the name of the tool executable, see whether it is an executable and return its full path.
readTool :: Text -> ToolParserT IO Tool
readTool exeName = ToolParserT $ \toolDir -> do
let toolPath :: FilePath = toolDir </> (exeName & textToString)
let read' = True
let write = False
let exec = True
Posix.fileExist toolPath
& ifTrueOrErr () [fmt|Tool does not exist: {toolPath}|]
& thenValidate
( \() ->
Posix.fileAccess toolPath read' write exec
& ifTrueOrErr (Tool {..}) [fmt|Tool is not readable/executable: {toolPath}|]
)
-- | helper
ifTrueOrErr :: Functor f => a -> Text -> f Bool -> f (Validation (NonEmpty Error) a)
ifTrueOrErr true err io =
io <&> \case
True -> Success true
False -> Failure $ singleton $ newError err
|