{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE NoImplicitPrelude #-} module System.Etc.Internal.Resolver.Env (resolveEnv, resolveEnvPure) where import RIO import qualified RIO.HashMap as HashMap import qualified RIO.Set as Set import qualified RIO.Text as Text import System.Environment (getEnvironment) import Control.Arrow ((***)) import qualified System.Etc.Internal.Spec.Types as Spec import System.Etc.Internal.Types resolveEnvVarSource :: (Text -> Maybe Text) -> Spec.ConfigValueType -> Bool -> Spec.ConfigSources cmd -> Maybe ConfigSource resolveEnvVarSource lookupEnv configValueType isSensitive specSources = let envTextToJSON = Spec.parseBytesToConfigValueJSON configValueType toEnvSource varname envValue = Env varname . markAsSensitive isSensitive <$> envTextToJSON envValue in do varname <- Spec.envVar specSources envText <- lookupEnv varname toEnvSource varname envText buildEnvVarResolver :: (Text -> Maybe Text) -> Spec.ConfigSpec cmd -> Maybe ConfigValue buildEnvVarResolver lookupEnv spec = let resolverReducer :: Text -> Spec.ConfigValue cmd -> Maybe ConfigValue -> Maybe ConfigValue resolverReducer specKey specValue mConfig = case specValue of Spec.ConfigValue { Spec.isSensitive, Spec.configValueType, Spec.configSources } -> let updateConfig = do envSource <- resolveEnvVarSource lookupEnv configValueType isSensitive configSources writeInSubConfig specKey (ConfigValue $ Set.singleton envSource) <$> mConfig in updateConfig <|> mConfig Spec.SubConfig specConfigMap -> let mSubConfig = specConfigMap & HashMap.foldrWithKey resolverReducer (Just emptySubConfig) & filterMaybe isEmptySubConfig updateConfig = writeInSubConfig specKey <$> mSubConfig <*> mConfig in updateConfig <|> mConfig in Spec.specConfigValues spec & HashMap.foldrWithKey resolverReducer (Just emptySubConfig) & filterMaybe isEmptySubConfig {-| Gathers all OS Environment Variable values (@env@ entries) from the @etc/spec@ entries inside a @ConfigSpec@. This version of the function gathers the input from a list of tuples rather than the OS. -} resolveEnvPure :: Spec.ConfigSpec cmd -- ^ ConfigSpec -> [(Text, Text)] -- ^ Environment Variable tuples -> Config -- ^ returns Configuration Map with Environment Variables values filled in resolveEnvPure spec envMap0 = let envMap = HashMap.fromList envMap0 lookupEnv key = HashMap.lookup key envMap in maybe (Config emptySubConfig) Config (buildEnvVarResolver lookupEnv spec) {-| Gathers all OS Environment Variable values (@env@ entries) from the @etc/spec@ entries inside a @ConfigSpec@ -} resolveEnv :: Spec.ConfigSpec cmd -- ^ Config Spec -> IO Config -- ^ returns Configuration Map with Environment Variables values filled in resolveEnv spec = let getEnvironmentTxt = map (Text.pack *** Text.pack) <$> getEnvironment in resolveEnvPure spec <$> getEnvironmentTxt