{-# 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 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