packages feed

configifier-0.0.4: examples/Main.hs

{-# LANGUAGE DataKinds                                #-}
{-# LANGUAGE FlexibleInstances                        #-}
{-# LANGUAGE GADTs                                    #-}
{-# LANGUAGE MultiParamTypeClasses                    #-}
{-# LANGUAGE OverlappingInstances                     #-}
{-# LANGUAGE OverloadedStrings                        #-}
{-# LANGUAGE PolyKinds                                #-}
{-# LANGUAGE ScopedTypeVariables                      #-}
{-# LANGUAGE StandaloneDeriving                       #-}
{-# LANGUAGE TypeFamilies                             #-}
{-# LANGUAGE TypeOperators                            #-}
{-# LANGUAGE UndecidableInstances                     #-}

{-# OPTIONS  #-}

module Main
where

import Control.Applicative ((<$>))
import Data.String.Conversions (ST, cs, (<>))
import Data.Typeable (Proxy(Proxy))
import System.Environment (getEnvironment, getArgs)
import Text.Show.Pretty (ppShow)

import qualified Data.ByteString as SBS
import qualified Data.Text.IO as ST

import Data.Configifier


-- * an interesting example

type Cfg = ToConfigCode Cfg'
type Cfg' =
             "frontend"      :> ServerCfg' :>: "descr"
  :*> Maybe ("backend"       :> ServerCfg')
  :*>        "default_users" :> [UserCfg'] :>: "list of users that are created on start if database is empty"

type ServerCfg = ToConfigCode ServerCfg'
type ServerCfg' =
             "bind_port"   :> Int
  :*>        "bind_host"   :> ST
  :*> Maybe ("expose_host" :> ST)

type UserCfg = ToConfigCode UserCfg'
type UserCfg' =
             "name"     :> ST :>: "user name (must be unique)"
  :*>        "email"    :> ST :>: "email address (must also be unique)"
  :*>        "password" :> ST :>: "password (not encrypted)"


defaultCfg :: Tagged Cfg
defaultCfg = Tagged $
      Id (Id 8001 :*> Id "localhost" :*> JustO (Id "expose"))
  :*> JustO (Id (Id 8002 :*> Id "localhost" :*> NothingO))
  :*> Id [u1, u2]
  where
    u1 = Id "ralf" :*> Id "ralf@localhost" :*> Id "gandalf"
    u2 = Id "claudi" :*> Id "claudi@remotehost" :*> Id "also_gandalf"


main :: IO ()
main = do
    sources <- sequence
        [ YamlString  <$> SBS.readFile "examples/config.yaml"
        , ShellEnv    <$> getEnvironment
        , CommandLine <$> getArgs
        ]

    ST.putStrLn $ docs (Proxy :: Proxy Cfg) <> "\n\n"

    let dump cfg = do
            putStrLn $ ppShow cfg
            putStrLn . cs . renderConfigFile $ cfg

    dump defaultCfg

    cfg :: Tagged Cfg <- configify sources
    dump cfg

    putStrLn "accessing config values:"
    print $ (Tagged (cfg >>. (Proxy :: Proxy '["frontend"])) :: Tagged ServerCfg)
    print $ cfg >>. (Proxy :: Proxy '["frontend", "expose_host"])
    print $ cfg >>. (Proxy :: Proxy '["frontend", "bind_port"])


{-

Example session:

$ configifier-example
[...]
accessing config values:
(Tagged Id 8001 :*> (Id "localhost" :*> JustO (Id "fost")))
Just "fost"
8001

$ FRONTEND_BIND_PORT=31 configifier-example
[...]
accessing config values:
(Tagged Id 31 :*> (Id "localhost" :*> JustO (Id "fost")))
Just "fost"
31

$ FRONTEND_BIND_PORT=31 configifier-example --frontend-bind-port 15
[...]
accessing config values:
(Tagged Id 15 :*> (Id "localhost" :*> JustO (Id "fost")))
Just "fost"
15

$ configifier-example --frontend-expose-host "false"
[...]
configifier-example: CommandLinePrimitiveOtherError (ShellEnvNoParse {shellEnvNoParseType = "Text", shellEnvNoParseValue = "false", shellEnvNoParseMsg = "when expecting a Text, encountered Boolean instead"})

$ configifier-example --frontend-expose-host "\"false\""
[...]
accessing config values:
(Tagged Id 8001 :*> (Id "localhost" :*> JustO (Id "false")))
Just "false"
8001

$ configifier-example --config examples/config2.yaml
[...]
backend:
  bind_host: arrr
  bind_port: 281
[...]

-}