{-# LANGUAGE CPP #-} module Configuration.Dotenv.ParsedVariable (ParsedVariable(..), VarName, VarValue(..), VarContents, VarFragment(..), interpolateParsedVariables) where import Control.Monad (foldM) #if !MIN_VERSION_base(4,8,0) import Data.Functor ((<$>)) #endif import Control.Applicative ((<|>)) import System.Environment (lookupEnv) import System.Process (readCreateProcess, shell) data ParsedVariable = ParsedVariable VarName VarValue deriving (Show, Eq) type VarName = String data VarValue = Unquoted VarContents | SingleQuoted VarContents | DoubleQuoted VarContents deriving (Show, Eq) type VarContents = [VarFragment] data VarFragment = VarInterpolation String | VarLiteral String | CommandInterpolation String deriving (Show, Eq) 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) = init <$> readCreateProcess (shell commandName) "" joinContents :: VarContents -> String joinContents = concatMap fragmentToString where fragmentToString (CommandInterpolation value) = value fragmentToString (VarInterpolation value) = value fragmentToString (VarLiteral value) = value