{-# LANGUAGE NoImplicitPrelude #-} -- | -- Module: Data.Salak -- Copyright: (c) 2018 Daniel YU -- License: BSD3 -- Maintainer: Daniel YU -- Stability: experimental -- Portability: portable -- -- Configuration Loader for Production in Haskell. -- module Data.Salak( -- * How to use this library -- $use -- * Properties Loader defaultProperties , ParseCommandLine , defaultProperties' , defaultPropertiesWithFile , empty -- * Lookup Properties , lookup , toKeys -- * Types , Property(..) , Properties(..) , Key , FromProperties(..) , Return(..) -- * Properties Loader Helper , insert , makePropertiesFromEnvironment , defaultParseCommandLine , makePropertiesFromCommandLine , makePropertiesFromJson , makePropertiesFromYaml , FileName ) where import Data.Maybe import Data.Salak.Aeson import Data.Salak.CommandLine import Data.Salak.Environment import Data.Salak.Types import Data.Salak.Yaml import Prelude hiding (empty, lookup) import System.Directory import System.FilePath (()) -- | Initialize default properties from `CommandLine` and `Environment`. -- `CommandLine` use default parser. defaultProperties :: IO Properties defaultProperties = defaultProperties' defaultParseCommandLine -- | Initialize default properties from `CommandLine` and `Environment`. defaultProperties' :: ParseCommandLine -> IO Properties defaultProperties' dpc = makePropertiesFromCommandLine dpc empty >>= makePropertiesFromEnvironment -- | Yaml file name. type FileName = String -- | Initialize default properties from `CommandLine`, `Environment` and `Yaml` files. -- All these configuration sources has orders, from highest order to lowest order: -- -- > 1. CommandLine -- > 2. Environment -- > 3. Specified Yaml file(file in "salak.config.dir") -- > 4. Yaml file in current directory -- > 5. Yaml file in home directory -- defaultPropertiesWithFile :: FileName -- ^ specify default config file name, can reset by config "salak.config.name" from `CommandLine` or `Environment`. -> IO Properties defaultPropertiesWithFile name = do p <- defaultProperties let n = fromMaybe name $ (lookup "salak.config.name" p :: Maybe String) p' = insert (toKeys "salak.config.name") (PStr n) p c <- getCurrentDirectory h <- getHomeDirectory foldl (go n) (return p') $ [(lookup "salak.config.dir" p, False), (Just c, True), (Just h, True)] where go _ p (Nothing, _) = p go name p (Just d, ok) = let f = d name in do p' <- p b <- doesFileExist f if b then makePropertiesFromYaml f p' else if ok then return p' else error $ "File " ++ f ++ " not found" -- $use -- -- | This library default a standard configuration load process. It can load properties from `CommandLine`, `Environment`, -- `JSON value` and `Yaml` files. They all load to the same format `Properties`. Earler property source has higher order -- to load property. For example: -- -- > CommandLine: --package.a.enabled=true -- > Environment: PACKAGE_A_ENABLED: false -- -- > lookup "package.a.enabled" properties => Just True -- -- `CommandLine` has higher order then `Environment`, for the former load properties earler then later. -- -- Usage: -- -- > data Config = Config -- > { name :: Text -- > , dir :: Maybe Text -- > , ext :: Int -- > } deriving (Eq, Show) -- > -- > instance FromJSON Config where -- > parseJSON = withObject "Config" $ \v -> Config -- > <$> v .: "name" -- > <*> v .:? "dir" -- > <*> (fromMaybe 1 <$> v .:? "ext") -- -- > main = do -- > p <- defaultPropertiesWithFile "salak.yml" -- > let Just config = lookup "salak.config" p :: Maybe Config -- > print config