{-# LANGUAGE OverloadedStrings #-} module Bricoleur.Config ( Config(..) , Source(..) , Expose(..) , getConfig , example ) where import Control.Applicative ((<|>)) import qualified Data.Adnot as A import qualified Data.ByteString as B import qualified Data.Map.Strict as M import qualified Data.Text as T import qualified Data.Vector as V data Config = Config { confDocument :: FilePath , confSources :: [Source] } deriving (Eq, Show) instance A.FromAdnot Config where parseAdnot = A.withSumNamed "config file" "document" go where go payload | Just file <- payload V.!? 0 = Config <$> A.parseAdnot file <*> mapM A.parseAdnot (V.toList (V.tail payload)) | otherwise = Left "expected source file in config" data Source = Source { sourceName :: T.Text , sourceDir :: FilePath , sourceCommands :: [String] , sourceExpose :: Expose } deriving (Eq, Show) instance A.FromAdnot Source where parseAdnot = A.withProduct "source" $ \p -> do name <- p A..: "name" dir <- p A..: "dir" cmds <- p A..: "cmd" expose <- p A..: "expose" return (Source name dir cmds expose) data Expose = ExposeFile FilePath | ExposeSections FilePath | NamedMap (M.Map T.Text Expose) deriving (Eq, Show) instance A.FromAdnot Expose where parseAdnot v = file v <|> sections v <|> namedMap v where file = A.withSumNamed "exposed fragments" "file" $ \ ps -> case V.toList ps of [] -> Left "Expected name for file" [f] -> ExposeFile <$> A.parseAdnot f _ -> Left "Too many arguments to file" sections = A.withSumNamed "exposed fragments" "sections" $ \ ps -> case V.toList ps of [] -> Left "Expected name for sections" [f] -> ExposeSections <$> A.parseAdnot f _ -> Left "Too many arguments to sections" namedMap = A.withProduct "exposed fragments" $ \ p -> NamedMap <$> mapM A.parseAdnot p parseConfig :: B.ByteString -> Either String Config parseConfig = A.decode getConfig :: FilePath -> IO (Either String Config) getConfig loc = do conf <- B.readFile loc return (parseConfig conf) example :: Config example = Config { confDocument = "main.md" , confSources = [ Source { sourceName = "rust-sample" , sourceDir = "s1" , sourceCommands = ["cargo clean", "cargo build"] , sourceExpose = ExposeFile "src/main.rs" } , Source { sourceName = "haskell-sample" , sourceDir = "s2" , sourceCommands = ["cabal new-build"] , sourceExpose = ExposeSections "Main.hs" } ] }