{-#LANGUAGE NoImplicitPrelude #-} {-#LANGUAGE OverloadedStrings #-} {-#LANGUAGE OverloadedLists #-} {-#LANGUAGE LambdaCase #-} module Web.Sprinkles.ProjectConfig where import Web.Sprinkles.Prelude import Web.Sprinkles.Rule import Data.Aeson as JSON import Data.Aeson.TH import qualified Data.Yaml as YAML import Web.Sprinkles.Backends import Data.Default import System.FilePath.Glob (glob) import System.Environment (getEnv, lookupEnv) import Control.MaybeEitherMonad (maybeFail) import Data.AList (AList) import qualified Data.AList as AList import Web.Sprinkles.Exceptions data ProjectConfig = ProjectConfig { pcContextData :: AList Text BackendSpec , pcRules :: [Rule] } deriving (Show) makeProjectPathsAbsolute :: FilePath -> ProjectConfig -> ProjectConfig makeProjectPathsAbsolute dir (ProjectConfig context rules) = ProjectConfig (fmap goBackendSpec context) (fmap goRule rules) where goBackendSpec = makeBackendSpecPathsAbsolute dir goRule = makeRulePathsAbsolute dir instance Default ProjectConfig where def = ProjectConfig { pcContextData = AList.empty , pcRules = [] } instance Semigroup ProjectConfig where (<>) = pcAppend instance Monoid ProjectConfig where mempty = def mappend = pcAppend instance FromJSON ProjectConfig where parseJSON = withObject "ProjectConfig" $ \obj -> do contextData <- fromMaybe AList.empty <$> obj .:? "data" rulesValue <- fromMaybe (toJSON ([] :: [Value])) <$> (obj .:? "rules" <|> obj .:? "Rules") rules <- parseJSON rulesValue return ProjectConfig { pcContextData = contextData , pcRules = rules } pcAppend :: ProjectConfig -> ProjectConfig -> ProjectConfig pcAppend a b = ProjectConfig { pcContextData = pcContextData a <> pcContextData b , pcRules = pcRules a <> pcRules b } firstNonNull :: [a] -> [a] -> [a] firstNonNull [] xs = xs firstNonNull xs _ = xs loadProjectConfigFile :: FilePath -> IO ProjectConfig loadProjectConfigFile fn = YAML.decodeFileEither fn >>= either (throwM . withSourceContext (pack fn)) return loadProjectConfig :: FilePath -> IO ProjectConfig loadProjectConfig dir = fmap (makeProjectPathsAbsolute dir) . loadProjectConfigFile $ dir "project.yml"