opt-env-conf-0.12.2.0: src/OptEnvConf/Check.hs
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module OptEnvConf.Check
( runSettingsCheck,
runSettingsCheckOn,
CheckResult (..),
)
where
import qualified Data.Aeson as JSON
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as NE
import GHC.Generics (Generic)
import GHC.Stack (SrcLoc)
import OptEnvConf.Args as Args
import OptEnvConf.EnvMap (EnvMap (..))
import OptEnvConf.Error
import OptEnvConf.Parser
import OptEnvConf.Run
import OptEnvConf.Terminal (getTerminalCapabilitiesFromHandle)
import System.Exit
import System.IO (stderr, stdout)
import Text.Colour
runSettingsCheck :: Capabilities -> Parser a -> Args -> EnvMap -> Maybe JSON.Object -> IO void
runSettingsCheck capabilities p args envVars mConfig = do
stderrTc <- getTerminalCapabilitiesFromHandle stderr
errOrSets <- runSettingsCheckOn capabilities stderrTc p args envVars mConfig
case errOrSets of
CheckFailed errs -> do
hPutChunksLocaleWith stderrTc stderr $ renderErrors errs
exitFailure
CheckIncapable missingCaps -> do
tc <- getTerminalCapabilitiesFromHandle stdout
hPutChunksLocaleWith tc stdout ["Could not complete parsing settings because of missing capabilities, but no errors were found so far."]
hPutChunksLocaleWith stderrTc stderr $ renderMissingCapabilities missingCaps
exitSuccess
CheckSucceeded _ -> do
tc <- getTerminalCapabilitiesFromHandle stdout
hPutChunksLocaleWith tc stdout ["Settings parsed successfully."]
exitSuccess
renderMissingCapabilities :: NonEmpty MissingCapability -> [Chunk]
renderMissingCapabilities = renderErrors . NE.map capabilityErorr
where
capabilityErorr (MissingCapability mLoc cap) =
ParseError mLoc $ ParseErrorMissingCapability cap
data CheckResult a
= -- | Check succeeded
CheckSucceeded a
| -- | Check could not be completed because of missing capability
CheckIncapable (NonEmpty MissingCapability)
| -- | Check failed with parse errors
CheckFailed (NonEmpty ParseError)
deriving (Show, Generic, Functor)
data MissingCapability
= MissingCapability
-- Where the capability was needed
!(Maybe SrcLoc)
-- Where the capability was needed
!Capability
deriving (Show, Generic)
runSettingsCheckOn ::
Capabilities ->
-- DebugMode, always on
TerminalCapabilities ->
Parser a ->
Args ->
EnvMap ->
Maybe JSON.Object ->
IO (CheckResult a)
runSettingsCheckOn capabilities debugMode p args envVars mConfig = do
errOrSets <- runParserOn capabilities (Just debugMode) p args envVars mConfig
pure $ case errOrSets of
Right a -> CheckSucceeded a
Left errs ->
-- If all the errors are missing capability errors, return
-- CheckIncapable, otherwise CheckFailed
let mMissingCaps =
-- This MUST be mapM instead of mapMaybe because we need to ensure
-- ALL errors are missing capability errors
mapM
( \case
ParseError mLoc (ParseErrorMissingCapability cap) -> Just (MissingCapability mLoc cap)
_ -> Nothing
)
errs
in case mMissingCaps of
Just ne -> CheckIncapable ne
Nothing -> CheckFailed errs