tricorder-0.2.0.0: src/Tricorder/Config.hs
module Tricorder.Config
( LoadedConfig (..)
, runLoadedConfig
, inputLoadedConfig
, configFileName
) where
import Atelier.Config (LoadedConfig (..))
import Atelier.Effects.FileSystem (FileSystem)
import Atelier.Effects.Input (Input, runInputEff)
import Effectful.Reader.Static (Reader, ask, runReader)
import System.FilePath ((</>))
import Atelier.Effects.FileSystem qualified as FileSystem
import Data.Aeson qualified as Aeson
import Data.Aeson.KeyMap qualified as KM
import Data.Yaml qualified as Yaml
import Tricorder.Runtime (ProjectRoot (..))
-- | Load config from .tricorder.yaml in the project root.
-- Falls back to empty config (all defaults) if the file is absent or cannot be parsed.
loadTricorderConfig :: (FileSystem :> es) => FilePath -> Eff es LoadedConfig
loadTricorderConfig projectRoot = do
exists <- FileSystem.doesFileExist yamlPath
if not exists then
pure $ LoadedConfig (Aeson.Object KM.empty)
else do
bs <- FileSystem.readFileBs yamlPath
pure . LoadedConfig $ case Yaml.decodeEither' @Aeson.Value bs of
Left _ -> Aeson.Object KM.empty
Right v -> v
where
yamlPath = projectRoot </> configFileName
configFileName :: FilePath
configFileName = ".tricorder.yaml"
runLoadedConfig
:: ( FileSystem :> es
, Reader ProjectRoot :> es
)
=> Eff (Reader LoadedConfig : es) a -> Eff es a
runLoadedConfig act = do
ProjectRoot projectRoot <- ask
cfg <- loadTricorderConfig projectRoot
runReader cfg act
inputLoadedConfig
:: ( FileSystem :> es
, Reader ProjectRoot :> es
)
=> Eff (Input LoadedConfig : es) a -> Eff es a
inputLoadedConfig = runInputEff do
ProjectRoot projectRoot <- ask
loadTricorderConfig projectRoot