{-|
Module      : Headroom.Command.Run.Env
Description : Environment for the Run command
Copyright   : (c) 2019-2020 Vaclav Svejcar
License     : BSD-3
Maintainer  : vaclav.svejcar@gmail.com
Stability   : experimental
Portability : POSIX

Data types and instances for the /Run/ command environment.
-}
{-# LANGUAGE NoImplicitPrelude #-}
module Headroom.Command.Run.Env
  ( RunOptions(..)
  , StartupEnv(..)
  , Env(..)
  , HasAppConfig(..)
  , HasRunOptions(..)
  , toAppConfig
  )
where

import           Headroom.AppConfig             ( AppConfig(..)
                                                , parseVariables
                                                )
import           Headroom.Types                 ( RunMode )
import           RIO


-- | Options for the /Run/ command.
data RunOptions = RunOptions
  { RunOptions -> RunMode
roRunMode       :: RunMode    -- ^ used /Run/ command mode
  , RunOptions -> [FilePath]
roSourcePaths   :: [FilePath] -- ^ source code file paths
  , RunOptions -> [FilePath]
roTemplatePaths :: [FilePath] -- ^ template file paths
  , RunOptions -> [Text]
roVariables     :: [Text]     -- ^ raw variables
  , RunOptions -> Bool
roDebug         :: Bool       -- ^ whether to run in debug mode
  }
  deriving (RunOptions -> RunOptions -> Bool
(RunOptions -> RunOptions -> Bool)
-> (RunOptions -> RunOptions -> Bool) -> Eq RunOptions
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RunOptions -> RunOptions -> Bool
$c/= :: RunOptions -> RunOptions -> Bool
== :: RunOptions -> RunOptions -> Bool
$c== :: RunOptions -> RunOptions -> Bool
Eq, Int -> RunOptions -> ShowS
[RunOptions] -> ShowS
RunOptions -> FilePath
(Int -> RunOptions -> ShowS)
-> (RunOptions -> FilePath)
-> ([RunOptions] -> ShowS)
-> Show RunOptions
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
showList :: [RunOptions] -> ShowS
$cshowList :: [RunOptions] -> ShowS
show :: RunOptions -> FilePath
$cshow :: RunOptions -> FilePath
showsPrec :: Int -> RunOptions -> ShowS
$cshowsPrec :: Int -> RunOptions -> ShowS
Show)

-- | Initial /RIO/ startup environment for the /Run/ command.
data StartupEnv = StartupEnv
  { StartupEnv -> LogFunc
envLogFunc    :: !LogFunc    -- ^ logging function
  , StartupEnv -> RunOptions
envRunOptions :: !RunOptions -- ^ options
  }

-- | Full /RIO/ environment for the /Run/ command.
data Env = Env
  { Env -> StartupEnv
envEnv       :: !StartupEnv -- ^ startup /RIO/ environment
  , Env -> AppConfig
envAppConfig :: !AppConfig  -- ^ application configuration
  }

-- | Environment value with application configuration.
class HasAppConfig env where
  -- | Application config lens.
  appConfigL :: Lens' env AppConfig

class (HasLogFunc env, HasRunOptions env) => HasEnv env where
  envL :: Lens' env StartupEnv

-- | Environment value with /Run/ command options.
class HasRunOptions env where
  -- | /Run/ command options lens.
  runOptionsL :: Lens' env RunOptions

instance HasAppConfig Env where
  appConfigL :: (AppConfig -> f AppConfig) -> Env -> f Env
appConfigL = (Env -> AppConfig)
-> (Env -> AppConfig -> Env) -> Lens' Env AppConfig
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens Env -> AppConfig
envAppConfig (\x :: Env
x y :: AppConfig
y -> Env
x { envAppConfig :: AppConfig
envAppConfig = AppConfig
y })

instance HasEnv StartupEnv where
  envL :: (StartupEnv -> f StartupEnv) -> StartupEnv -> f StartupEnv
envL = (StartupEnv -> f StartupEnv) -> StartupEnv -> f StartupEnv
forall a. a -> a
id

instance HasEnv Env where
  envL :: (StartupEnv -> f StartupEnv) -> Env -> f Env
envL = (Env -> StartupEnv)
-> (Env -> StartupEnv -> Env) -> Lens' Env StartupEnv
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens Env -> StartupEnv
envEnv (\x :: Env
x y :: StartupEnv
y -> Env
x { envEnv :: StartupEnv
envEnv = StartupEnv
y })

instance HasLogFunc StartupEnv where
  logFuncL :: (LogFunc -> f LogFunc) -> StartupEnv -> f StartupEnv
logFuncL = (StartupEnv -> LogFunc)
-> (StartupEnv -> LogFunc -> StartupEnv)
-> Lens' StartupEnv LogFunc
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens StartupEnv -> LogFunc
envLogFunc (\x :: StartupEnv
x y :: LogFunc
y -> StartupEnv
x { envLogFunc :: LogFunc
envLogFunc = LogFunc
y })

instance HasLogFunc Env where
  logFuncL :: (LogFunc -> f LogFunc) -> Env -> f Env
logFuncL = (StartupEnv -> f StartupEnv) -> Env -> f Env
forall env. HasEnv env => Lens' env StartupEnv
envL ((StartupEnv -> f StartupEnv) -> Env -> f Env)
-> ((LogFunc -> f LogFunc) -> StartupEnv -> f StartupEnv)
-> (LogFunc -> f LogFunc)
-> Env
-> f Env
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (LogFunc -> f LogFunc) -> StartupEnv -> f StartupEnv
forall env. HasLogFunc env => Lens' env LogFunc
logFuncL

instance HasRunOptions StartupEnv where
  runOptionsL :: (RunOptions -> f RunOptions) -> StartupEnv -> f StartupEnv
runOptionsL = (StartupEnv -> RunOptions)
-> (StartupEnv -> RunOptions -> StartupEnv)
-> Lens' StartupEnv RunOptions
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens StartupEnv -> RunOptions
envRunOptions (\x :: StartupEnv
x y :: RunOptions
y -> StartupEnv
x { envRunOptions :: RunOptions
envRunOptions = RunOptions
y })

instance HasRunOptions Env where
  runOptionsL :: (RunOptions -> f RunOptions) -> Env -> f Env
runOptionsL = (StartupEnv -> f StartupEnv) -> Env -> f Env
forall env. HasEnv env => Lens' env StartupEnv
envL ((StartupEnv -> f StartupEnv) -> Env -> f Env)
-> ((RunOptions -> f RunOptions) -> StartupEnv -> f StartupEnv)
-> (RunOptions -> f RunOptions)
-> Env
-> f Env
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (RunOptions -> f RunOptions) -> StartupEnv -> f StartupEnv
forall env. HasRunOptions env => Lens' env RunOptions
runOptionsL

-- | Converts options for /Run/ command into application config.
toAppConfig :: MonadThrow m
            => RunOptions  -- ^ /Run/ command options
            -> m AppConfig -- ^ application configuration
toAppConfig :: RunOptions -> m AppConfig
toAppConfig opts :: RunOptions
opts = do
  HashMap Text Text
variables' <- [Text] -> m (HashMap Text Text)
forall (m :: * -> *).
MonadThrow m =>
[Text] -> m (HashMap Text Text)
parseVariables (RunOptions -> [Text]
roVariables RunOptions
opts)
  AppConfig -> m AppConfig
forall (m :: * -> *) a. Monad m => a -> m a
return (AppConfig -> m AppConfig) -> AppConfig -> m AppConfig
forall a b. (a -> b) -> a -> b
$ AppConfig
forall a. Monoid a => a
mempty { acSourcePaths :: [FilePath]
acSourcePaths   = RunOptions -> [FilePath]
roSourcePaths RunOptions
opts
                  , acTemplatePaths :: [FilePath]
acTemplatePaths = RunOptions -> [FilePath]
roTemplatePaths RunOptions
opts
                  , acRunMode :: RunMode
acRunMode       = RunOptions -> RunMode
roRunMode RunOptions
opts
                  , acVariables :: HashMap Text Text
acVariables     = HashMap Text Text
variables'
                  }