dotenv-0.11.0.1: src/Configuration/Dotenv/ParsedVariable.hs
-- |
-- Module : Configuration.Dotenv.Types
-- Copyright : © 2015–2020 Stack Builders Inc.
-- License : MIT
--
-- Maintainer : Stack Builders <hackage@stackbuilders.com>
-- Stability : experimental
-- Portability : portable
--
-- Helpers to interpolate environment variables
module Configuration.Dotenv.ParsedVariable (ParsedVariable(..),
VarName,
VarValue(..),
VarContents,
VarFragment(..),
interpolateParsedVariables) where
import Configuration.Dotenv.Environment (lookupEnv)
import Control.Applicative ((<|>))
import Control.Monad (foldM)
import System.Process (proc, readCreateProcess)
-- | Name and value pair
data ParsedVariable
= ParsedVariable VarName VarValue deriving (Show, Eq)
-- | Variable name
type VarName = String
-- | Possible state of values
data VarValue
= Unquoted VarContents
| SingleQuoted VarContents
| DoubleQuoted VarContents deriving (Show, Eq)
-- | List of VarFragment
type VarContents = [VarFragment]
-- | Placeholder for possible values
data VarFragment
= VarInterpolation String
| VarLiteral String
| CommandInterpolation String [String] deriving (Show, Eq)
-- | Interpotales parsed variables
interpolateParsedVariables :: [ParsedVariable] -> IO [(String, String)]
interpolateParsedVariables = fmap reverse . foldM addInterpolated []
addInterpolated :: [(String, String)] -> ParsedVariable -> IO [(String, String)]
addInterpolated previous (ParsedVariable name value) = (: previous) <$> ((,) name <$> interpolate previous value)
interpolate :: [(String, String)] -> VarValue -> IO String
interpolate _ (SingleQuoted contents) = return $ joinContents contents
interpolate previous (DoubleQuoted contents) = interpolateContents previous contents
interpolate previous (Unquoted contents) = interpolateContents previous contents
interpolateContents :: [(String, String)] -> VarContents -> IO String
interpolateContents previous contents = concat <$> mapM (interpolateFragment previous) contents
interpolateFragment :: [(String, String)] -> VarFragment -> IO String
interpolateFragment _ (VarLiteral value ) = return value
interpolateFragment previous (VarInterpolation varname) = fromPreviousOrEnv >>= maybe (return "") return
where
fromPreviousOrEnv = (lookup varname previous <|>) <$> lookupEnv varname
interpolateFragment _ (CommandInterpolation commandName args) = init <$> readCreateProcess (proc commandName args) ""
joinContents :: VarContents -> String
joinContents = concatMap fragmentToString
where
fragmentToString (CommandInterpolation commandName args) = unwords $ commandName : args
fragmentToString (VarInterpolation value) = value
fragmentToString (VarLiteral value) = value