headroom-0.3.1.0: src/Headroom/Configuration.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
{-|
Module : Headroom.Configuration
Description : Configuration handling (loading, parsing, validating)
Copyright : (c) 2019-2020 Vaclav Svejcar
License : BSD-3-Clause
Maintainer : vaclav.svejcar@gmail.com
Stability : experimental
Portability : POSIX
This module provides logic for working with the cofiguration data types.
Headroom uses the
<https://medium.com/@jonathangfischoff/the-partial-options-monoid-pattern-31914a71fc67 partial options monoid>
pattern for the configuration.
-}
module Headroom.Configuration
( -- * Loading & Parsing Configuration
loadConfiguration
, parseConfiguration
-- * Processing Partial Configuration
, makeConfiguration
, makeHeadersConfig
, makeHeaderConfig
)
where
import Data.Monoid ( Last(..) )
import qualified Data.Yaml as Y
import Headroom.Configuration.Types ( Configuration(..)
, ConfigurationError(..)
, ConfigurationKey(..)
, CtConfiguration
, CtHeaderConfig
, CtHeaderFnConfig
, CtHeaderFnConfigs
, CtHeadersConfig
, CtUpdateCopyrightConfig
, HeaderConfig(..)
, HeaderFnConfig(..)
, HeaderFnConfigs(..)
, HeadersConfig(..)
, Phase(..)
, PtConfiguration
, PtHeaderConfig
, PtHeaderFnConfig
, PtHeaderFnConfigs
, PtHeadersConfig
, PtUpdateCopyrightConfig
, UpdateCopyrightConfig(..)
)
import Headroom.Data.Lens ( suffixLenses )
import Headroom.FileType.Types ( FileType(..) )
import RIO
import qualified RIO.ByteString as B
suffixLenses ''HeaderFnConfig
suffixLenses ''HeaderFnConfigs
suffixLenses ''UpdateCopyrightConfig
-- | Loads and parses application configuration from given /YAML/ file.
loadConfiguration :: MonadIO m
=> FilePath
-- ^ path to /YAML/ configuration file
-> m PtConfiguration
-- ^ parsed configuration
loadConfiguration path = liftIO $ B.readFile path >>= parseConfiguration
-- | Parses application configuration from given raw input in /YAML/ format.
parseConfiguration :: MonadThrow m
=> B.ByteString
-- ^ raw input to parse
-> m PtConfiguration
-- ^ parsed application configuration
parseConfiguration = Y.decodeThrow
-- | Makes full 'CtConfiguration' from provided 'PtConfiguration' (if valid).
makeConfiguration :: MonadThrow m
=> PtConfiguration
-- ^ source 'PtConfiguration'
-> m CtConfiguration
-- ^ full 'CtConfiguration'
makeConfiguration pt = do
cRunMode <- lastOrError CkRunMode (cRunMode pt)
cSourcePaths <- lastOrError CkSourcePaths (cSourcePaths pt)
cExcludedPaths <- lastOrError CkExcludedPaths (cExcludedPaths pt)
cTemplateSource <- lastOrError CkTemplateSource (cTemplateSource pt)
cLicenseHeaders <- makeHeadersConfig (cLicenseHeaders pt)
cHeaderFnConfigs <- makeHeaderFnConfigs (cHeaderFnConfigs pt)
cVariables <- pure $ cVariables pt
pure Configuration { .. }
-- | Makes full 'CtHeadersConfig' from provided 'PtHeadersConfig' (if valid).
makeHeadersConfig :: MonadThrow m
=> PtHeadersConfig
-- ^ source 'PtHeadersConfig'
-> m CtHeadersConfig
-- ^ full 'CtHeadersConfig'
makeHeadersConfig pt = do
hscC <- makeHeaderConfig C (hscC pt)
hscCpp <- makeHeaderConfig CPP (hscCpp pt)
hscCss <- makeHeaderConfig CSS (hscCss pt)
hscHaskell <- makeHeaderConfig Haskell (hscHaskell pt)
hscHtml <- makeHeaderConfig HTML (hscHtml pt)
hscJava <- makeHeaderConfig Java (hscJava pt)
hscJs <- makeHeaderConfig JS (hscJs pt)
hscPureScript <- makeHeaderConfig PureScript (hscPureScript pt)
hscRust <- makeHeaderConfig Rust (hscRust pt)
hscScala <- makeHeaderConfig Scala (hscScala pt)
hscShell <- makeHeaderConfig Shell (hscShell pt)
pure HeadersConfig { .. }
-- | Makes full 'CtHeaderConfig' from provided 'PtHeaderConfig' (if valid).
makeHeaderConfig :: MonadThrow m
=> FileType
-- ^ determines for which file type this configuration is
-> PtHeaderConfig
-- ^ source 'PtHeaderConfig'
-> m CtHeaderConfig
-- ^ full 'CtHeaderConfig'
makeHeaderConfig fileType pt = do
hcFileExtensions <- lastOrError (CkFileExtensions fileType)
(hcFileExtensions pt)
hcMarginAfter <- lastOrError (CkMarginAfter fileType) (hcMarginAfter pt)
hcMarginBefore <- lastOrError (CkMarginBefore fileType) (hcMarginBefore pt)
hcPutAfter <- lastOrError (CkPutAfter fileType) (hcPutAfter pt)
hcPutBefore <- lastOrError (CkPutBefore fileType) (hcPutBefore pt)
hcHeaderSyntax <- lastOrError (CkHeaderSyntax fileType) (hcHeaderSyntax pt)
pure HeaderConfig { .. }
makeHeaderFnConfigs :: MonadThrow m => PtHeaderFnConfigs -> m CtHeaderFnConfigs
makeHeaderFnConfigs pt = do
hfcsUpdateCopyright <- makeHeaderFnConfig (pt ^. hfcsUpdateCopyrightL)
makeUpdateCopyrightConfig
pure HeaderFnConfigs { .. }
makeHeaderFnConfig :: MonadThrow m
=> PtHeaderFnConfig c
-> (c 'Partial -> m (c 'Complete))
-> m (CtHeaderFnConfig c)
makeHeaderFnConfig pt fn = do
hfcEnabled <- lastOrError CkEnabled (pt ^. hfcEnabledL)
hfcConfig <- fn $ pt ^. hfcConfigL
pure HeaderFnConfig { .. }
makeUpdateCopyrightConfig :: MonadThrow m
=> PtUpdateCopyrightConfig
-> m CtUpdateCopyrightConfig
makeUpdateCopyrightConfig pt = do
let uccSelectedAuthors = lastOrNothing $ pt ^. uccSelectedAuthorsL
pure UpdateCopyrightConfig { .. }
------------------------------ Private Functions -----------------------------
lastOrError :: MonadThrow m => ConfigurationKey -> Last a -> m a
lastOrError key (Last a) = maybe (throwM $ MissingConfiguration key) pure a
lastOrNothing :: Last (Maybe a) -> Maybe a
lastOrNothing (Last a) = fromMaybe Nothing a