{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE RecordWildCards            #-}
{-# LANGUAGE StandaloneDeriving         #-}
{-# LANGUAGE TypeOperators              #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE DefaultSignatures          #-}
{-# LANGUAGE ScopedTypeVariables        #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleInstances          #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE LambdaCase                 #-}
{-# LANGUAGE DataKinds                  #-}
{-# LANGUAGE KindSignatures             #-}
------------------------------------------------------------------------------
-- |
-- Module      : System.Envy
-- Copyright   : (c) David Johnson 2015
-- Maintainer  : djohnson.m@gmail.com
-- Stability   : experimental
-- Portability : POSIX
--
-- > {-# LANGUAGE DeriveGeneric #-}
-- >
-- > module Main ( main ) where
-- >
-- > import System.Envy
-- > import GHC.Generics
-- >
-- > data PGConfig = PGConfig {
-- >   pgHost :: String -- "PG_HOST"
-- > , pgPort :: Int    -- "PG_PORT"
-- > } deriving (Generic, Show)
-- >
-- > -- Default instance used if environment variable doesn't exist
-- > instance DefConfig PGConfig where
-- >   defConfig = PGConfig "localhost" 5432
-- >
-- > instance FromEnv PGConfig
-- > -- Generically produces the following body (no implementation needed if using Generics):
-- > -- fromEnv = PGConfig <$> envMaybe "PG_HOST" .!= "localhost"
-- > --                    <*> envMaybe "PG_PORT" .!= 5432
-- >
-- > main :: IO ()
-- > main =
-- >   print =<< do decodeEnv :: IO (Either String PGConfig)
-- >  -- PGConfig { pgHost = "custom-pg-url", pgPort = 5432 }
--
module System.Envy
       ( -- * Classes
         FromEnv (..)
       , GFromEnv (..)
       , ToEnv   (..)
       , Var     (..)
       , EnvList (..)
       , EnvVar  (..)
       , Parser  (..)
        -- * Functions
       , decodeEnv
       , decodeWithDefaults
       , decode
       , showEnv
       , setEnvironment
       , setEnvironment'
       , unsetEnvironment
       , unsetEnvironment'
       , makeEnv
       , env
       , envMaybe
       , (.=)
       , (.!=)
         -- * Utility Types
       , ReadShowVar (..)
         -- * Generics
       , DefConfig (..)
       , Option (..)
       , defOption
       , runEnv
       , gFromEnvCustom
       ) where
------------------------------------------------------------------------------
import           Control.Applicative
import           Control.Monad (MonadPlus)
import           Control.Monad.Except (ExceptT, MonadError, runExceptT, throwError)
import           Control.Monad.IO.Class (MonadIO, liftIO)
import           Control.Exception
import           Data.Functor.Identity
import           Data.Maybe
import           Data.Monoid
import           Data.Char
import           Data.Time
import           GHC.Generics
import           Data.Typeable
import           System.Environment.Blank
import           Text.Read (readMaybe)
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import           Data.Text (Text)
import           Data.Word
import           Data.Int
import qualified Data.ByteString.Char8 as B8
import qualified Data.ByteString.Lazy.Char8 as BL8
------------------------------------------------------------------------------
-- | Parser Monad for environment variable retrieval
newtype Parser a = Parser { forall a. Parser a -> ExceptT String IO a
runParser :: ExceptT String IO a }
  deriving ( forall a b. a -> Parser b -> Parser a
forall a b. (a -> b) -> Parser a -> Parser b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> Parser b -> Parser a
$c<$ :: forall a b. a -> Parser b -> Parser a
fmap :: forall a b. (a -> b) -> Parser a -> Parser b
$cfmap :: forall a b. (a -> b) -> Parser a -> Parser b
Functor, Applicative Parser
forall a. a -> Parser a
forall a b. Parser a -> Parser b -> Parser b
forall a b. Parser a -> (a -> Parser b) -> Parser b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: forall a. a -> Parser a
$creturn :: forall a. a -> Parser a
>> :: forall a b. Parser a -> Parser b -> Parser b
$c>> :: forall a b. Parser a -> Parser b -> Parser b
>>= :: forall a b. Parser a -> (a -> Parser b) -> Parser b
$c>>= :: forall a b. Parser a -> (a -> Parser b) -> Parser b
Monad, Functor Parser
forall a. a -> Parser a
forall a b. Parser a -> Parser b -> Parser a
forall a b. Parser a -> Parser b -> Parser b
forall a b. Parser (a -> b) -> Parser a -> Parser b
forall a b c. (a -> b -> c) -> Parser a -> Parser b -> Parser c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
<* :: forall a b. Parser a -> Parser b -> Parser a
$c<* :: forall a b. Parser a -> Parser b -> Parser a
*> :: forall a b. Parser a -> Parser b -> Parser b
$c*> :: forall a b. Parser a -> Parser b -> Parser b
liftA2 :: forall a b c. (a -> b -> c) -> Parser a -> Parser b -> Parser c
$cliftA2 :: forall a b c. (a -> b -> c) -> Parser a -> Parser b -> Parser c
<*> :: forall a b. Parser (a -> b) -> Parser a -> Parser b
$c<*> :: forall a b. Parser (a -> b) -> Parser a -> Parser b
pure :: forall a. a -> Parser a
$cpure :: forall a. a -> Parser a
Applicative, MonadError String
           , Monad Parser
forall a. IO a -> Parser a
forall (m :: * -> *).
Monad m -> (forall a. IO a -> m a) -> MonadIO m
liftIO :: forall a. IO a -> Parser a
$cliftIO :: forall a. IO a -> Parser a
MonadIO, Applicative Parser
forall a. Parser a
forall a. Parser a -> Parser [a]
forall a. Parser a -> Parser a -> Parser a
forall (f :: * -> *).
Applicative f
-> (forall a. f a)
-> (forall a. f a -> f a -> f a)
-> (forall a. f a -> f [a])
-> (forall a. f a -> f [a])
-> Alternative f
many :: forall a. Parser a -> Parser [a]
$cmany :: forall a. Parser a -> Parser [a]
some :: forall a. Parser a -> Parser [a]
$csome :: forall a. Parser a -> Parser [a]
<|> :: forall a. Parser a -> Parser a -> Parser a
$c<|> :: forall a. Parser a -> Parser a -> Parser a
empty :: forall a. Parser a
$cempty :: forall a. Parser a
Alternative, Monad Parser
Alternative Parser
forall a. Parser a
forall a. Parser a -> Parser a -> Parser a
forall (m :: * -> *).
Alternative m
-> Monad m
-> (forall a. m a)
-> (forall a. m a -> m a -> m a)
-> MonadPlus m
mplus :: forall a. Parser a -> Parser a -> Parser a
$cmplus :: forall a. Parser a -> Parser a -> Parser a
mzero :: forall a. Parser a
$cmzero :: forall a. Parser a
MonadPlus )

instance MonadFail Parser where
  fail :: forall a. String -> Parser a
fail = forall a. ExceptT String IO a -> Parser a
Parser forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError

------------------------------------------------------------------------------
-- | Variable type, smart constructor for handling environment variables.
data EnvVar = EnvVar {
  EnvVar -> String
variableName :: String,
  -- ^ The environment variable to set.
  EnvVar -> String
variableValue :: String
  -- ^ The value to assign this variable to.
  }
  deriving (Int -> EnvVar -> ShowS
[EnvVar] -> ShowS
EnvVar -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [EnvVar] -> ShowS
$cshowList :: [EnvVar] -> ShowS
show :: EnvVar -> String
$cshow :: EnvVar -> String
showsPrec :: Int -> EnvVar -> ShowS
$cshowsPrec :: Int -> EnvVar -> ShowS
Show, EnvVar -> EnvVar -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: EnvVar -> EnvVar -> Bool
$c/= :: EnvVar -> EnvVar -> Bool
== :: EnvVar -> EnvVar -> Bool
$c== :: EnvVar -> EnvVar -> Bool
Eq)

------------------------------------------------------------------------------
-- | Executes `Parser`
evalParser :: Parser a -> IO (Either String a)
evalParser :: forall a. Parser a -> IO (Either String a)
evalParser = forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Parser a -> ExceptT String IO a
runParser

------------------------------------------------------------------------------
-- | For use with Generics, no `FromEnv` typeclass necessary
--
-- > getPgConfig :: IO (Either String ConnectInfo)
-- > getPgConfig = runEnv $ gFromEnvCustom defOption
runEnv :: Parser a -> IO (Either String a)
runEnv :: forall a. Parser a -> IO (Either String a)
runEnv = forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Parser a -> ExceptT String IO a
runParser

------------------------------------------------------------------------------
-- | Environment variable getter. Fails if the variable is not set or
-- fails to parse.
env :: Var a
    => String   -- ^ Key to look up.
    -> Parser a -- ^ Return a value of this type or throw an error.
env :: forall a. Var a => String -> Parser a
env String
key = do
  Maybe String
result <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (String -> IO (Maybe String)
getEnv String
key)
  case Maybe String
result of
    Maybe String
Nothing -> forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall a b. (a -> b) -> a -> b
$ String
"Variable not found for: " forall a. [a] -> [a] -> [a]
++ String
key
    Just String
dv ->
      case forall a. Var a => String -> Maybe a
fromVar String
dv of
        Maybe a
Nothing -> forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError forall a b. (a -> b) -> a -> b
$ (String
"Parse failure: could not parse variable "
                                 forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show String
key forall a. [a] -> [a] -> [a]
++ String
" into type "
                                 forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (forall a. Typeable a => a -> TypeRep
typeOf String
dv))
        Just a
x -> forall (m :: * -> *) a. Monad m => a -> m a
return a
x

------------------------------------------------------------------------------
-- | Environment variable getter returning `Maybe`
envMaybe :: Var a
         => String           -- ^ Key to look up.
         -> Parser (Maybe a) -- ^ Return `Nothing` if variable isn't set.
envMaybe :: forall a. Var a => String -> Parser (Maybe a)
envMaybe String
key = do
  Maybe String
val <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (String -> IO (Maybe String)
getEnv String
key)
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ case Maybe String
val of
   Maybe String
Nothing -> forall a. Maybe a
Nothing
   Just String
x -> forall a. Var a => String -> Maybe a
fromVar String
x

------------------------------------------------------------------------------
-- | For use with `envMaybe` for providing default arguments.
(.!=) :: Parser (Maybe a) -- ^ Parser that might fail.
      -> a                -- ^ Value to return if the parser fails.
      -> Parser a         -- ^ Parser that returns the default on failure.
.!= :: forall a. Parser (Maybe a) -> a -> Parser a
(.!=) Parser (Maybe a)
parser a
def  = forall a. a -> Maybe a -> a
fromMaybe a
def forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser (Maybe a)
parser

------------------------------------------------------------------------------
-- | Infix environment variable setter
-- Smart constructor for producing types of `EnvVar`
(.=) :: Var a
     => String -- ^ The variable name to set.
     -> a      -- ^ Object to set in the environment.
     -> EnvVar -- ^ Mapping of Variable to Value.
.= :: forall a. Var a => String -> a -> EnvVar
(.=) String
variableName a
value = String -> String -> EnvVar
EnvVar String
variableName (forall a. Var a => a -> String
toVar a
value)

------------------------------------------------------------------------------
-- | `FromEnv` Typeclass w/ Generic default implementation
class FromEnv a where
  fromEnv :: Maybe a -> Parser a
  default fromEnv :: (Generic a, GFromEnv (Rep a)) => Maybe a -> Parser a
  fromEnv Maybe a
oa = forall a.
(Generic a, GFromEnv (Rep a)) =>
Option -> Maybe a -> Parser a
gFromEnvCustom Option
defOption Maybe a
oa

------------------------------------------------------------------------------
-- | Meant for specifying a custom `Option` for environment retrieval
--
-- > instance FromEnv PGConfig where
-- >   fromEnv = gFromEnvCustom Option { dropPrefixCount = 8, customPrefix = "PG" }
gFromEnvCustom :: forall a. (Generic a, GFromEnv (Rep a))
               => Option
               -> Maybe a
               -> Parser a
gFromEnvCustom :: forall a.
(Generic a, GFromEnv (Rep a)) =>
Option -> Maybe a -> Parser a
gFromEnvCustom Option
opts Maybe a
oa = forall a x. Generic a => Rep a x -> a
to forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *) a.
GFromEnv f =>
Option -> Maybe (f a) -> Parser (f a)
gFromEnv Option
opts (forall a x. Generic a => a -> Rep a x
from forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe a
oa)

------------------------------------------------------------------------------
-- | `Generic` FromEnv
class GFromEnv f where
  gFromEnv :: Option -> Maybe (f a) ->  Parser (f a)

------------------------------------------------------------------------------
-- | Type class for objects which have a default configuration.
class DefConfig a where defConfig :: a

------------------------------------------------------------------------------
-- | For customizing environment variable generation
data Option = Option {
    Option -> Int
dropPrefixCount :: Int  -- ^ Applied first
  , Option -> String
customPrefix :: String  -- ^ Converted toUpper
  } deriving Int -> Option -> ShowS
[Option] -> ShowS
Option -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Option] -> ShowS
$cshowList :: [Option] -> ShowS
show :: Option -> String
$cshow :: Option -> String
showsPrec :: Int -> Option -> ShowS
$cshowsPrec :: Int -> Option -> ShowS
Show

------------------------------------------------------------------------------
-- | Default `Option` for field modification
defOption :: Option
defOption :: Option
defOption = Int -> String -> Option
Option Int
0 forall a. Monoid a => a
mempty

------------------------------------------------------------------------------
-- | Products
instance (GFromEnv a, GFromEnv b) => GFromEnv (a :*: b) where
  gFromEnv :: forall a. Option -> Maybe ((:*:) a b a) -> Parser ((:*:) a b a)
gFromEnv Option
opts Maybe ((:*:) a b a)
ox = let (Maybe (a a)
oa, Maybe (b a)
ob) = case Maybe ((:*:) a b a)
ox of
                                             (Just (a a
a :*: b a
b)) -> (forall a. a -> Maybe a
Just a a
a, forall a. a -> Maybe a
Just b a
b)
                                             Maybe ((:*:) a b a)
_ -> (forall a. Maybe a
Nothing, forall a. Maybe a
Nothing) in
                            forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 forall k (f :: k -> *) (g :: k -> *) (p :: k).
f p -> g p -> (:*:) f g p
(:*:) (forall (f :: * -> *) a.
GFromEnv f =>
Option -> Maybe (f a) -> Parser (f a)
gFromEnv Option
opts Maybe (a a)
oa) (forall (f :: * -> *) a.
GFromEnv f =>
Option -> Maybe (f a) -> Parser (f a)
gFromEnv Option
opts Maybe (b a)
ob)

------------------------------------------------------------------------------
-- | Don't absorb meta data
instance GFromEnv a => GFromEnv (C1 i a) where
  gFromEnv :: forall a. Option -> Maybe (C1 i a a) -> Parser (C1 i a a)
gFromEnv  Option
opts (Just (M1 a a
x))= forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
M1 forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *) a.
GFromEnv f =>
Option -> Maybe (f a) -> Parser (f a)
gFromEnv Option
opts (forall a. a -> Maybe a
Just a a
x)
  gFromEnv  Option
opts            Maybe (C1 i a a)
_ = forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
M1 forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *) a.
GFromEnv f =>
Option -> Maybe (f a) -> Parser (f a)
gFromEnv Option
opts forall a. Maybe a
Nothing

------------------------------------------------------------------------------
-- | Don't absorb meta data
instance GFromEnv a => GFromEnv (D1 i a) where
  gFromEnv :: forall a. Option -> Maybe (D1 i a a) -> Parser (D1 i a a)
gFromEnv Option
opts (Just (M1 a a
x)) = forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
M1 forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *) a.
GFromEnv f =>
Option -> Maybe (f a) -> Parser (f a)
gFromEnv Option
opts (forall a. a -> Maybe a
Just a a
x)
  gFromEnv Option
opts             Maybe (D1 i a a)
_ = forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
M1 forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *) a.
GFromEnv f =>
Option -> Maybe (f a) -> Parser (f a)
gFromEnv Option
opts forall a. Maybe a
Nothing

------------------------------------------------------------------------------
-- | Construct a `Parser` from a `selName` and `DefConfig` record field
instance (Selector s, Var a) => GFromEnv (S1 s (K1 i a)) where
  gFromEnv :: forall a.
Option -> Maybe (S1 s (K1 i a) a) -> Parser (S1 s (K1 i a) a)
gFromEnv Option
opts Maybe (S1 s (K1 i a) a)
ox =
    let p :: Parser a
p = case Maybe (S1 s (K1 i a) a)
ox of
               Just (M1 (K1 a
def)) -> forall a. Var a => String -> Parser (Maybe a)
envMaybe String
envName forall a. Parser (Maybe a) -> a -> Parser a
.!= a
def
               Maybe (S1 s (K1 i a) a)
_                  -> forall a. Var a => String -> Parser a
env String
envName in
    forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
M1 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k i c (p :: k). c -> K1 i c p
K1 forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Parser a
p
     where
      envName :: String
envName = Option -> ShowS
toEnvName Option
opts forall a b. (a -> b) -> a -> b
$ forall {k} (s :: k) k1 (t :: k -> (k1 -> *) -> k1 -> *)
       (f :: k1 -> *) (a :: k1).
Selector s =>
t s f a -> String
selName (forall (s :: Meta) (f :: * -> *) a. SelectorProxy s f a
SelectorProxy :: SelectorProxy s Proxy ())

      toEnvName :: Option -> String -> String
      toEnvName :: Option -> ShowS
toEnvName Option{Int
String
customPrefix :: String
dropPrefixCount :: Int
customPrefix :: Option -> String
dropPrefixCount :: Option -> Int
..} String
xs =
        let name :: String
name = ShowS
snake (forall a. Int -> [a] -> [a]
drop Int
dropPrefixCount String
xs)
        in if String
customPrefix forall a. Eq a => a -> a -> Bool
== forall a. Monoid a => a
mempty
             then String
name
             else forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper String
customPrefix forall a. [a] -> [a] -> [a]
++ String
"_" forall a. [a] -> [a] -> [a]
++ String
name

      applyFirst :: (Char -> Char) -> String -> String
      applyFirst :: (Char -> Char) -> ShowS
applyFirst Char -> Char
_ []     = []
      applyFirst Char -> Char
f [Char
x]    = [Char -> Char
f Char
x]
      applyFirst Char -> Char
f (Char
x:String
xs) = Char -> Char
f Char
xforall a. a -> [a] -> [a]
: String
xs

      snakeCase :: String -> String
      snakeCase :: ShowS
snakeCase = ShowS
u forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Char) -> ShowS
applyFirst Char -> Char
toLower
        where u :: ShowS
u []                 = []
              u (Char
x:String
xs) | Char -> Bool
isUpper Char
x = Char
'_' forall a. a -> [a] -> [a]
: Char -> Char
toLower Char
x forall a. a -> [a] -> [a]
: ShowS
snakeCase String
xs
                       | Bool
otherwise = Char
x forall a. a -> [a] -> [a]
: ShowS
u String
xs

      snake :: String -> String
      snake :: ShowS
snake = forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
snakeCase

data SelectorProxy (s :: Meta) (f :: * -> *) a = SelectorProxy

------------------------------------------------------------------------------
-- | Type class for objects which can be converted to a set of
-- environment variable settings.
class ToEnv a where
  -- | Convert an object into a list of environment variable settings.
  toEnv :: a -> EnvList a

------------------------------------------------------------------------------
-- | List of environment variables. Captures a "phantom type" which
-- allows the type checker to detect the proper implementation of toEnv
-- to use.
data EnvList a = EnvList [EnvVar] deriving (Int -> EnvList a -> ShowS
forall a. Int -> EnvList a -> ShowS
forall a. [EnvList a] -> ShowS
forall a. EnvList a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [EnvList a] -> ShowS
$cshowList :: forall a. [EnvList a] -> ShowS
show :: EnvList a -> String
$cshow :: forall a. EnvList a -> String
showsPrec :: Int -> EnvList a -> ShowS
$cshowsPrec :: forall a. Int -> EnvList a -> ShowS
Show)

------------------------------------------------------------------------------
-- | Smart constructor, environment creation helper.
makeEnv :: [EnvVar] -> EnvList a
makeEnv :: forall a. [EnvVar] -> EnvList a
makeEnv = forall a. [EnvVar] -> EnvList a
EnvList

------------------------------------------------------------------------------
-- | Class for converting to / from an environment variable
class Typeable a => Var a where
  -- | Convert a value into an environment variable.
  toVar   :: a -> String
  -- | Parse an environment variable.
  fromVar :: String -> Maybe a

------------------------------------------------------------------------------
instance Var Text where toVar :: Text -> String
toVar = Text -> String
T.unpack; fromVar :: String -> Maybe Text
fromVar = forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack
instance Var TL.Text where toVar :: Text -> String
toVar = Text -> String
TL.unpack; fromVar :: String -> Maybe Text
fromVar = forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
TL.pack
instance Var BL8.ByteString where toVar :: ByteString -> String
toVar = ByteString -> String
BL8.unpack; fromVar :: String -> Maybe ByteString
fromVar = forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
BL8.pack
instance Var B8.ByteString where toVar :: ByteString -> String
toVar = ByteString -> String
B8.unpack; fromVar :: String -> Maybe ByteString
fromVar = forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
B8.pack
instance Var Int where toVar :: Int -> String
toVar = forall a. Show a => a -> String
show; fromVar :: String -> Maybe Int
fromVar = forall a. Read a => String -> Maybe a
readMaybe
instance Var Int8 where toVar :: Int8 -> String
toVar = forall a. Show a => a -> String
show; fromVar :: String -> Maybe Int8
fromVar = forall a. Read a => String -> Maybe a
readMaybe
instance Var Int16 where toVar :: Int16 -> String
toVar = forall a. Show a => a -> String
show; fromVar :: String -> Maybe Int16
fromVar = forall a. Read a => String -> Maybe a
readMaybe
instance Var Int32 where toVar :: Int32 -> String
toVar = forall a. Show a => a -> String
show; fromVar :: String -> Maybe Int32
fromVar = forall a. Read a => String -> Maybe a
readMaybe
instance Var Int64 where toVar :: Int64 -> String
toVar = forall a. Show a => a -> String
show; fromVar :: String -> Maybe Int64
fromVar = forall a. Read a => String -> Maybe a
readMaybe
instance Var Integer where toVar :: Integer -> String
toVar = forall a. Show a => a -> String
show; fromVar :: String -> Maybe Integer
fromVar = forall a. Read a => String -> Maybe a
readMaybe
instance Var UTCTime where toVar :: UTCTime -> String
toVar = forall a. Show a => a -> String
show; fromVar :: String -> Maybe UTCTime
fromVar = forall a. Read a => String -> Maybe a
readMaybe
instance Var Day where toVar :: Day -> String
toVar = forall a. Show a => a -> String
show; fromVar :: String -> Maybe Day
fromVar = forall a. Read a => String -> Maybe a
readMaybe
instance Var Word8 where toVar :: Word8 -> String
toVar = forall a. Show a => a -> String
show; fromVar :: String -> Maybe Word8
fromVar = forall a. Read a => String -> Maybe a
readMaybe
instance Var Bool where toVar :: Bool -> String
toVar = forall a. Show a => a -> String
show; fromVar :: String -> Maybe Bool
fromVar = forall a. Read a => String -> Maybe a
readMaybe
instance Var Double where toVar :: Double -> String
toVar = forall a. Show a => a -> String
show; fromVar :: String -> Maybe Double
fromVar = forall a. Read a => String -> Maybe a
readMaybe
instance Var Word16 where toVar :: Word16 -> String
toVar = forall a. Show a => a -> String
show; fromVar :: String -> Maybe Word16
fromVar = forall a. Read a => String -> Maybe a
readMaybe
instance Var Word32 where toVar :: Word32 -> String
toVar = forall a. Show a => a -> String
show; fromVar :: String -> Maybe Word32
fromVar = forall a. Read a => String -> Maybe a
readMaybe
instance Var Word64 where toVar :: Word64 -> String
toVar = forall a. Show a => a -> String
show; fromVar :: String -> Maybe Word64
fromVar = forall a. Read a => String -> Maybe a
readMaybe
instance Var String where toVar :: ShowS
toVar = forall a. a -> a
id; fromVar :: String -> Maybe String
fromVar = forall a. a -> Maybe a
Just
instance Var () where toVar :: () -> String
toVar = forall a b. a -> b -> a
const String
"()"; fromVar :: String -> Maybe ()
fromVar = forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a
Just ()
instance Var a => Var (Maybe a) where
  toVar :: Maybe a -> String
toVar = forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"" forall a. Var a => a -> String
toVar
  fromVar :: String -> Maybe (Maybe a)
fromVar String
"" = forall a. Maybe a
Nothing
  fromVar  String
s = forall a. a -> Maybe a
Just forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Var a => String -> Maybe a
fromVar String
s

------------------------------------------------------------------------------
deriving instance (Var a, Typeable a) => Var (Last a)
deriving instance (Var a, Typeable a) => Var (First a)
deriving instance (Var a, Typeable a) => Var (Identity a)

------------------------------------------------------------------------------
-- | A utility type to use any instance of 'Read' and 'Show' as an instance of
--   'Var'.
newtype ReadShowVar a = ReadShowVar { forall a. ReadShowVar a -> a
unReadShowVar :: a }

instance (Typeable a, Show a, Read a) => Var (ReadShowVar a) where
  toVar :: ReadShowVar a -> String
toVar = forall a. Show a => a -> String
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ReadShowVar a -> a
unReadShowVar
  fromVar :: String -> Maybe (ReadShowVar a)
fromVar = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. a -> ReadShowVar a
ReadShowVar forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Read a => String -> Maybe a
readMaybe
------------------------------------------------------------------------------
-- | Environment retrieval with failure info
decodeEnv :: FromEnv a => IO (Either String a)
decodeEnv :: forall a. FromEnv a => IO (Either String a)
decodeEnv = forall a. Parser a -> IO (Either String a)
evalParser (forall a. FromEnv a => Maybe a -> Parser a
fromEnv forall a. Maybe a
Nothing)

------------------------------------------------------------------------------
-- | Environment retrieval (with no failure info)
decode :: FromEnv a => IO (Maybe a)
decode :: forall a. FromEnv a => IO (Maybe a)
decode = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall {a} {a}. Either a a -> Maybe a
eitherToMaybe forall a. FromEnv a => IO (Either String a)
decodeEnv
  where
    eitherToMaybe :: Either a a -> Maybe a
eitherToMaybe (Left a
_)  = forall a. Maybe a
Nothing
    eitherToMaybe (Right a
x) = forall a. a -> Maybe a
Just a
x

------------------------------------------------------------------------------
-- | Environment retrieval with default values provided
decodeWithDefaults :: FromEnv a => a -> IO a
decodeWithDefaults :: forall a. FromEnv a => a -> IO a
decodeWithDefaults a
def = (\(Right a
x) -> a
x) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Parser a -> IO (Either String a)
evalParser (forall a. FromEnv a => Maybe a -> Parser a
fromEnv (forall a. a -> Maybe a
Just a
def))

------------------------------------------------------------------------------
-- | Catch an IO exception and return it in an Either.
wrapIOException :: IO a -> IO (Either String a)
wrapIOException :: forall a. IO a -> IO (Either String a)
wrapIOException IO a
action = forall e a. Exception e => IO a -> IO (Either e a)
try IO a
action forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
  Left (IOException
ex :: IOException) -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> String
show IOException
ex
  Right a
x -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. b -> Either a b
Right a
x

------------------------------------------------------------------------------
-- | Set environment via a ToEnv constrained type
setEnvironment :: EnvList a -> IO (Either String ())
setEnvironment :: forall a. EnvList a -> IO (Either String ())
setEnvironment (EnvList [EnvVar]
envVars) = forall a. IO a -> IO (Either String a)
wrapIOException forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ EnvVar -> IO ()
set [EnvVar]
envVars
  where set :: EnvVar -> IO ()
set EnvVar
var = String -> String -> Bool -> IO ()
setEnv (EnvVar -> String
variableName EnvVar
var) (EnvVar -> String
variableValue EnvVar
var) Bool
True

------------------------------------------------------------------------------
-- | Set environment directly using a value of class ToEnv
setEnvironment' :: ToEnv a => a -> IO (Either String ())
setEnvironment' :: forall a. ToEnv a => a -> IO (Either String ())
setEnvironment' = forall a. EnvList a -> IO (Either String ())
setEnvironment forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ToEnv a => a -> EnvList a
toEnv

------------------------------------------------------------------------------
-- | Unset Environment from a `ToEnv` constrained type
unsetEnvironment :: EnvList a -> IO (Either String ())
unsetEnvironment :: forall a. EnvList a -> IO (Either String ())
unsetEnvironment (EnvList [EnvVar]
envVars) = forall a. IO a -> IO (Either String a)
wrapIOException forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ EnvVar -> IO ()
unset [EnvVar]
envVars
  where unset :: EnvVar -> IO ()
unset EnvVar
var = String -> IO ()
unsetEnv (EnvVar -> String
variableName EnvVar
var)

------------------------------------------------------------------------------
-- | Unset Environment using a value of class ToEnv
unsetEnvironment' :: ToEnv a => a -> IO (Either String ())
unsetEnvironment' :: forall a. ToEnv a => a -> IO (Either String ())
unsetEnvironment' = forall a. EnvList a -> IO (Either String ())
unsetEnvironment forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ToEnv a => a -> EnvList a
toEnv

------------------------------------------------------------------------------
-- | Display all environment variables, for convenience
showEnv :: IO ()
showEnv :: IO ()
showEnv = forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ forall a. Show a => a -> IO ()
print forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO [(String, String)]
getEnvironment