packages feed

headroom 0.4.2.0 → 0.4.3.0

raw patch · 137 files changed

+3621/−1608 lines, 137 filesdep +microlens-aesondep +persistentdep +persistent-sqlitePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: microlens-aeson, persistent, persistent-sqlite

API changes (from Hackage documentation)

- Headroom.Command.Run: instance Headroom.Data.Has.Has Headroom.Command.Run.StartupEnv Headroom.Command.Run.Env
- Headroom.Command.Run: instance Headroom.Data.Has.Has Headroom.Command.Run.StartupEnv Headroom.Command.Run.StartupEnv
- Headroom.Command.Run: instance Headroom.Data.Has.Has Headroom.Command.Types.CommandRunOptions Headroom.Command.Run.StartupEnv
- Headroom.Command.Run: instance Headroom.Data.Has.Has Headroom.Configuration.Types.CtConfiguration Headroom.Command.Run.Env
- Headroom.Command.Run: instance Headroom.Data.Has.Has Headroom.Configuration.Types.CtPostProcessConfigs Headroom.Command.Run.Env
- Headroom.Command.Run: instance RIO.Prelude.Logger.HasLogFunc Headroom.Command.Run.StartupEnv
- Headroom.Configuration: loadConfiguration :: (MonadIO m, MonadThrow m) => FilePath -> m PtConfiguration
- Headroom.Configuration: makeConfiguration :: MonadThrow m => PtConfiguration -> m CtConfiguration
- Headroom.Configuration: makeHeaderConfig :: MonadThrow m => FileType -> PtHeaderConfig -> m CtHeaderConfig
- Headroom.Configuration: makeHeadersConfig :: MonadThrow m => PtHeadersConfig -> m CtHeadersConfig
- Headroom.Configuration: parseConfiguration :: MonadThrow m => ByteString -> m PtConfiguration
- Headroom.Configuration.Compat: CannotParseVersion :: VersionError
- Headroom.Configuration.Compat: NewerVersionDetected :: Version -> VersionError
- Headroom.Configuration.Compat: UnsupportedVersion :: [Version] -> Version -> VersionError
- Headroom.Configuration.Compat: checkCompatibility :: MonadThrow m => [Version] -> Version -> ByteString -> m Version
- Headroom.Configuration.Compat: data VersionError
- Headroom.Configuration.Compat: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Configuration.Compat.VersionObj
- Headroom.Configuration.Compat: instance GHC.Classes.Eq Headroom.Configuration.Compat.VersionError
- Headroom.Configuration.Compat: instance GHC.Classes.Eq Headroom.Configuration.Compat.VersionObj
- Headroom.Configuration.Compat: instance GHC.Exception.Type.Exception Headroom.Configuration.Compat.VersionError
- Headroom.Configuration.Compat: instance GHC.Show.Show Headroom.Configuration.Compat.VersionError
- Headroom.Configuration.Compat: instance GHC.Show.Show Headroom.Configuration.Compat.VersionObj
- Headroom.Configuration.Enrich: Array :: ValueType
- Headroom.Configuration.Enrich: Enrich :: (Text -> Text) -> Enrich
- Headroom.Configuration.Enrich: String :: ValueType
- Headroom.Configuration.Enrich: [enrich] :: Enrich -> Text -> Text
- Headroom.Configuration.Enrich: data ValueType
- Headroom.Configuration.Enrich: instance GHC.Base.Monoid Headroom.Configuration.Enrich.Enrich
- Headroom.Configuration.Enrich: instance GHC.Base.Semigroup Headroom.Configuration.Enrich.Enrich
- Headroom.Configuration.Enrich: instance GHC.Classes.Eq Headroom.Configuration.Enrich.ValueType
- Headroom.Configuration.Enrich: instance GHC.Show.Show Headroom.Configuration.Enrich.ValueType
- Headroom.Configuration.Enrich: newtype Enrich
- Headroom.Configuration.Enrich: replaceEmptyValue :: Text -> (Text -> (ValueType, Text)) -> Enrich
- Headroom.Configuration.Enrich: withArray :: ToJSON a => [a] -> Text -> (ValueType, Text)
- Headroom.Configuration.Enrich: withText :: Text -> Text -> (ValueType, Text)
- Headroom.Configuration.Types: Add :: RunMode
- Headroom.Configuration.Types: Apache2 :: LicenseType
- Headroom.Configuration.Types: BSD3 :: LicenseType
- Headroom.Configuration.Types: BlockComment :: Regex -> Regex -> Maybe Text -> HeaderSyntax
- Headroom.Configuration.Types: Check :: RunMode
- Headroom.Configuration.Types: CkBuiltInTemplates :: ConfigurationKey
- Headroom.Configuration.Types: CkEnabled :: ConfigurationKey
- Headroom.Configuration.Types: CkExcludeIgnoredPaths :: ConfigurationKey
- Headroom.Configuration.Types: CkExcludedPaths :: ConfigurationKey
- Headroom.Configuration.Types: CkFileExtensions :: FileType -> ConfigurationKey
- Headroom.Configuration.Types: CkHeaderSyntax :: FileType -> ConfigurationKey
- Headroom.Configuration.Types: CkMarginBottomCode :: FileType -> ConfigurationKey
- Headroom.Configuration.Types: CkMarginBottomFile :: FileType -> ConfigurationKey
- Headroom.Configuration.Types: CkMarginTopCode :: FileType -> ConfigurationKey
- Headroom.Configuration.Types: CkMarginTopFile :: FileType -> ConfigurationKey
- Headroom.Configuration.Types: CkPutAfter :: FileType -> ConfigurationKey
- Headroom.Configuration.Types: CkPutBefore :: FileType -> ConfigurationKey
- Headroom.Configuration.Types: CkRunMode :: ConfigurationKey
- Headroom.Configuration.Types: CkSourcePaths :: ConfigurationKey
- Headroom.Configuration.Types: CkVariables :: ConfigurationKey
- Headroom.Configuration.Types: Complete :: Phase
- Headroom.Configuration.Types: Configuration :: (p ::: RunMode) -> (p ::: [FilePath]) -> (p ::: [Regex]) -> (p ::: Bool) -> (p ::: Maybe LicenseType) -> [TemplateRef] -> Variables -> HeadersConfig p -> PostProcessConfigs p -> Configuration (p :: Phase)
- Headroom.Configuration.Types: Drop :: RunMode
- Headroom.Configuration.Types: GPL2 :: LicenseType
- Headroom.Configuration.Types: GPL3 :: LicenseType
- Headroom.Configuration.Types: GenConfigFile :: GenMode
- Headroom.Configuration.Types: GenLicense :: (LicenseType, FileType) -> GenMode
- Headroom.Configuration.Types: HeaderConfig :: (p ::: [Text]) -> (p ::: Int) -> (p ::: Int) -> (p ::: Int) -> (p ::: Int) -> (p ::: [Regex]) -> (p ::: [Regex]) -> (p ::: HeaderSyntax) -> HeaderConfig (p :: Phase)
- Headroom.Configuration.Types: HeadersConfig :: HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeadersConfig (p :: Phase)
- Headroom.Configuration.Types: LineComment :: Regex -> Maybe Text -> HeaderSyntax
- Headroom.Configuration.Types: MIT :: LicenseType
- Headroom.Configuration.Types: MPL2 :: LicenseType
- Headroom.Configuration.Types: MissingConfiguration :: ConfigurationKey -> ConfigurationError
- Headroom.Configuration.Types: MixedHeaderSyntax :: ConfigurationError
- Headroom.Configuration.Types: Partial :: Phase
- Headroom.Configuration.Types: PostProcessConfig :: (p ::: Bool) -> c p -> PostProcessConfig (p :: Phase) c
- Headroom.Configuration.Types: PostProcessConfigs :: PostProcessConfig p UpdateCopyrightConfig -> PostProcessConfigs (p :: Phase)
- Headroom.Configuration.Types: Replace :: RunMode
- Headroom.Configuration.Types: UpdateCopyrightConfig :: (p ::: Maybe (NonEmpty Text)) -> UpdateCopyrightConfig (p :: Phase)
- Headroom.Configuration.Types: [cBuiltInTemplates] :: Configuration (p :: Phase) -> p ::: Maybe LicenseType
- Headroom.Configuration.Types: [cExcludeIgnoredPaths] :: Configuration (p :: Phase) -> p ::: Bool
- Headroom.Configuration.Types: [cExcludedPaths] :: Configuration (p :: Phase) -> p ::: [Regex]
- Headroom.Configuration.Types: [cLicenseHeaders] :: Configuration (p :: Phase) -> HeadersConfig p
- Headroom.Configuration.Types: [cPostProcessConfigs] :: Configuration (p :: Phase) -> PostProcessConfigs p
- Headroom.Configuration.Types: [cRunMode] :: Configuration (p :: Phase) -> p ::: RunMode
- Headroom.Configuration.Types: [cSourcePaths] :: Configuration (p :: Phase) -> p ::: [FilePath]
- Headroom.Configuration.Types: [cTemplateRefs] :: Configuration (p :: Phase) -> [TemplateRef]
- Headroom.Configuration.Types: [cVariables] :: Configuration (p :: Phase) -> Variables
- Headroom.Configuration.Types: [hcFileExtensions] :: HeaderConfig (p :: Phase) -> p ::: [Text]
- Headroom.Configuration.Types: [hcHeaderSyntax] :: HeaderConfig (p :: Phase) -> p ::: HeaderSyntax
- Headroom.Configuration.Types: [hcMarginBottomCode] :: HeaderConfig (p :: Phase) -> p ::: Int
- Headroom.Configuration.Types: [hcMarginBottomFile] :: HeaderConfig (p :: Phase) -> p ::: Int
- Headroom.Configuration.Types: [hcMarginTopCode] :: HeaderConfig (p :: Phase) -> p ::: Int
- Headroom.Configuration.Types: [hcMarginTopFile] :: HeaderConfig (p :: Phase) -> p ::: Int
- Headroom.Configuration.Types: [hcPutAfter] :: HeaderConfig (p :: Phase) -> p ::: [Regex]
- Headroom.Configuration.Types: [hcPutBefore] :: HeaderConfig (p :: Phase) -> p ::: [Regex]
- Headroom.Configuration.Types: [hscC] :: HeadersConfig (p :: Phase) -> HeaderConfig p
- Headroom.Configuration.Types: [hscCpp] :: HeadersConfig (p :: Phase) -> HeaderConfig p
- Headroom.Configuration.Types: [hscCss] :: HeadersConfig (p :: Phase) -> HeaderConfig p
- Headroom.Configuration.Types: [hscGo] :: HeadersConfig (p :: Phase) -> HeaderConfig p
- Headroom.Configuration.Types: [hscHaskell] :: HeadersConfig (p :: Phase) -> HeaderConfig p
- Headroom.Configuration.Types: [hscHtml] :: HeadersConfig (p :: Phase) -> HeaderConfig p
- Headroom.Configuration.Types: [hscJava] :: HeadersConfig (p :: Phase) -> HeaderConfig p
- Headroom.Configuration.Types: [hscJs] :: HeadersConfig (p :: Phase) -> HeaderConfig p
- Headroom.Configuration.Types: [hscPureScript] :: HeadersConfig (p :: Phase) -> HeaderConfig p
- Headroom.Configuration.Types: [hscRust] :: HeadersConfig (p :: Phase) -> HeaderConfig p
- Headroom.Configuration.Types: [hscScala] :: HeadersConfig (p :: Phase) -> HeaderConfig p
- Headroom.Configuration.Types: [hscShell] :: HeadersConfig (p :: Phase) -> HeaderConfig p
- Headroom.Configuration.Types: [ppcConfig] :: PostProcessConfig (p :: Phase) c -> c p
- Headroom.Configuration.Types: [ppcEnabled] :: PostProcessConfig (p :: Phase) c -> p ::: Bool
- Headroom.Configuration.Types: [ppcsUpdateCopyright] :: PostProcessConfigs (p :: Phase) -> PostProcessConfig p UpdateCopyrightConfig
- Headroom.Configuration.Types: [uccSelectedAuthors] :: UpdateCopyrightConfig (p :: Phase) -> p ::: Maybe (NonEmpty Text)
- Headroom.Configuration.Types: data Configuration (p :: Phase)
- Headroom.Configuration.Types: data ConfigurationError
- Headroom.Configuration.Types: data ConfigurationKey
- Headroom.Configuration.Types: data GenMode
- Headroom.Configuration.Types: data HeaderConfig (p :: Phase)
- Headroom.Configuration.Types: data HeaderSyntax
- Headroom.Configuration.Types: data HeadersConfig (p :: Phase)
- Headroom.Configuration.Types: data LicenseType
- Headroom.Configuration.Types: data Phase
- Headroom.Configuration.Types: data PostProcessConfig (p :: Phase) c
- Headroom.Configuration.Types: data PostProcessConfigs (p :: Phase)
- Headroom.Configuration.Types: data RunMode
- Headroom.Configuration.Types: data UpdateCopyrightConfig (p :: Phase)
- Headroom.Configuration.Types: instance (Data.Aeson.Types.FromJSON.FromJSON (c 'Headroom.Configuration.Types.Partial), GHC.Base.Monoid (c 'Headroom.Configuration.Types.Partial)) => Data.Aeson.Types.FromJSON.FromJSON (Headroom.Configuration.Types.PtPostProcessConfig c)
- Headroom.Configuration.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Configuration.Types.BlockComment'
- Headroom.Configuration.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Configuration.Types.LineComment'
- Headroom.Configuration.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Configuration.Types.PtConfiguration
- Headroom.Configuration.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Configuration.Types.PtHeaderConfig
- Headroom.Configuration.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Configuration.Types.PtHeadersConfig
- Headroom.Configuration.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Configuration.Types.PtPostProcessConfigs
- Headroom.Configuration.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Configuration.Types.PtUpdateCopyrightConfig
- Headroom.Configuration.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Configuration.Types.RunMode
- Headroom.Configuration.Types: instance GHC.Base.Monoid (c 'Headroom.Configuration.Types.Partial) => GHC.Base.Monoid (Headroom.Configuration.Types.PtPostProcessConfig c)
- Headroom.Configuration.Types: instance GHC.Base.Monoid Headroom.Configuration.Types.PtConfiguration
- Headroom.Configuration.Types: instance GHC.Base.Monoid Headroom.Configuration.Types.PtHeaderConfig
- Headroom.Configuration.Types: instance GHC.Base.Monoid Headroom.Configuration.Types.PtHeadersConfig
- Headroom.Configuration.Types: instance GHC.Base.Monoid Headroom.Configuration.Types.PtPostProcessConfigs
- Headroom.Configuration.Types: instance GHC.Base.Monoid Headroom.Configuration.Types.PtUpdateCopyrightConfig
- Headroom.Configuration.Types: instance GHC.Base.Semigroup (c 'Headroom.Configuration.Types.Partial) => GHC.Base.Semigroup (Headroom.Configuration.Types.PtPostProcessConfig c)
- Headroom.Configuration.Types: instance GHC.Base.Semigroup Headroom.Configuration.Types.PtConfiguration
- Headroom.Configuration.Types: instance GHC.Base.Semigroup Headroom.Configuration.Types.PtHeaderConfig
- Headroom.Configuration.Types: instance GHC.Base.Semigroup Headroom.Configuration.Types.PtHeadersConfig
- Headroom.Configuration.Types: instance GHC.Base.Semigroup Headroom.Configuration.Types.PtPostProcessConfigs
- Headroom.Configuration.Types: instance GHC.Base.Semigroup Headroom.Configuration.Types.PtUpdateCopyrightConfig
- Headroom.Configuration.Types: instance GHC.Classes.Eq (c 'Headroom.Configuration.Types.Complete) => GHC.Classes.Eq (Headroom.Configuration.Types.CtPostProcessConfig c)
- Headroom.Configuration.Types: instance GHC.Classes.Eq (c 'Headroom.Configuration.Types.Partial) => GHC.Classes.Eq (Headroom.Configuration.Types.PtPostProcessConfig c)
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.BlockComment'
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.ConfigurationError
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.ConfigurationKey
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.CtConfiguration
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.CtHeaderConfig
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.CtHeadersConfig
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.CtPostProcessConfigs
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.CtUpdateCopyrightConfig
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.GenMode
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.HeaderSyntax
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.LineComment'
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.PtConfiguration
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.PtHeaderConfig
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.PtHeadersConfig
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.PtPostProcessConfigs
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.PtUpdateCopyrightConfig
- Headroom.Configuration.Types: instance GHC.Classes.Eq Headroom.Configuration.Types.RunMode
- Headroom.Configuration.Types: instance GHC.Exception.Type.Exception Headroom.Configuration.Types.ConfigurationError
- Headroom.Configuration.Types: instance GHC.Generics.Generic (Headroom.Configuration.Types.PtPostProcessConfig c)
- Headroom.Configuration.Types: instance GHC.Generics.Generic Headroom.Configuration.Types.BlockComment'
- Headroom.Configuration.Types: instance GHC.Generics.Generic Headroom.Configuration.Types.LineComment'
- Headroom.Configuration.Types: instance GHC.Generics.Generic Headroom.Configuration.Types.PtConfiguration
- Headroom.Configuration.Types: instance GHC.Generics.Generic Headroom.Configuration.Types.PtHeaderConfig
- Headroom.Configuration.Types: instance GHC.Generics.Generic Headroom.Configuration.Types.PtHeadersConfig
- Headroom.Configuration.Types: instance GHC.Generics.Generic Headroom.Configuration.Types.PtPostProcessConfigs
- Headroom.Configuration.Types: instance GHC.Generics.Generic Headroom.Configuration.Types.PtUpdateCopyrightConfig
- Headroom.Configuration.Types: instance GHC.Show.Show (c 'Headroom.Configuration.Types.Complete) => GHC.Show.Show (Headroom.Configuration.Types.CtPostProcessConfig c)
- Headroom.Configuration.Types: instance GHC.Show.Show (c 'Headroom.Configuration.Types.Partial) => GHC.Show.Show (Headroom.Configuration.Types.PtPostProcessConfig c)
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.BlockComment'
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.ConfigurationError
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.ConfigurationKey
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.CtConfiguration
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.CtHeaderConfig
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.CtHeadersConfig
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.CtPostProcessConfigs
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.CtUpdateCopyrightConfig
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.GenMode
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.HeaderSyntax
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.LineComment'
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.PtConfiguration
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.PtHeaderConfig
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.PtHeadersConfig
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.PtPostProcessConfigs
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.PtUpdateCopyrightConfig
- Headroom.Configuration.Types: instance GHC.Show.Show Headroom.Configuration.Types.RunMode
- Headroom.Configuration.Types: type CtConfiguration = Configuration 'Complete
- Headroom.Configuration.Types: type CtHeaderConfig = HeaderConfig 'Complete
- Headroom.Configuration.Types: type CtHeadersConfig = HeadersConfig 'Complete
- Headroom.Configuration.Types: type CtPostProcessConfig c = PostProcessConfig 'Complete c
- Headroom.Configuration.Types: type CtPostProcessConfigs = PostProcessConfigs 'Complete
- Headroom.Configuration.Types: type CtUpdateCopyrightConfig = UpdateCopyrightConfig 'Complete
- Headroom.Configuration.Types: type PtConfiguration = Configuration 'Partial
- Headroom.Configuration.Types: type PtHeaderConfig = HeaderConfig 'Partial
- Headroom.Configuration.Types: type PtHeadersConfig = HeadersConfig 'Partial
- Headroom.Configuration.Types: type PtPostProcessConfig c = PostProcessConfig 'Partial c
- Headroom.Configuration.Types: type PtPostProcessConfigs = PostProcessConfigs 'Partial
- Headroom.Configuration.Types: type PtUpdateCopyrightConfig = UpdateCopyrightConfig 'Partial
- Headroom.Configuration.Types: type family (p :: Phase) ::: a
+ Headroom.Command.Bootstrap: BootstrapEnv :: GlobalConfig -> BootstrapEnv
+ Headroom.Command.Bootstrap: [beGlobalConfig] :: BootstrapEnv -> GlobalConfig
+ Headroom.Command.Bootstrap: bootstrap :: (HasRIO FileSystem env, HasRIO KVStore env, HasRIO Network env, HasLogFunc env) => RIO env BootstrapEnv
+ Headroom.Command.Bootstrap: data BootstrapEnv
+ Headroom.Command.Bootstrap: globalKVStore :: HasRIO FileSystem env => RIO env (KVStore (RIO env))
+ Headroom.Command.Bootstrap: runRIO' :: (LogFunc -> IO env) -> Bool -> RIO env a -> IO a
+ Headroom.Command.Run: instance Headroom.Data.Has.Has (Headroom.IO.KVStore.KVStore (RIO.Prelude.RIO.RIO Headroom.Command.Run.Env)) Headroom.Command.Run.Env
+ Headroom.Command.Run: instance Headroom.Data.Has.Has Headroom.Config.Types.CtAppConfig Headroom.Command.Run.Env
+ Headroom.Command.Run: instance Headroom.Data.Has.Has Headroom.Config.Types.CtPostProcessConfigs Headroom.Command.Run.Env
+ Headroom.Config: loadAppConfig :: (MonadIO m, MonadThrow m) => FilePath -> m PtAppConfig
+ Headroom.Config: makeAppConfig :: MonadThrow m => PtAppConfig -> m CtAppConfig
+ Headroom.Config: makeHeaderConfig :: MonadThrow m => FileType -> PtHeaderConfig -> m CtHeaderConfig
+ Headroom.Config: makeHeadersConfig :: MonadThrow m => PtHeadersConfig -> m CtHeadersConfig
+ Headroom.Config: parseAppConfig :: MonadThrow m => ByteString -> m PtAppConfig
+ Headroom.Config.Compat: CannotParseVersion :: VersionError
+ Headroom.Config.Compat: NewerVersionDetected :: Version -> VersionError
+ Headroom.Config.Compat: UnsupportedVersion :: [Version] -> Version -> VersionError
+ Headroom.Config.Compat: checkCompatibility :: MonadThrow m => [Version] -> Version -> ByteString -> m Version
+ Headroom.Config.Compat: data VersionError
+ Headroom.Config.Compat: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Config.Compat.VersionObj
+ Headroom.Config.Compat: instance GHC.Classes.Eq Headroom.Config.Compat.VersionError
+ Headroom.Config.Compat: instance GHC.Classes.Eq Headroom.Config.Compat.VersionObj
+ Headroom.Config.Compat: instance GHC.Exception.Type.Exception Headroom.Config.Compat.VersionError
+ Headroom.Config.Compat: instance GHC.Show.Show Headroom.Config.Compat.VersionError
+ Headroom.Config.Compat: instance GHC.Show.Show Headroom.Config.Compat.VersionObj
+ Headroom.Config.Enrich: Array :: ValueType
+ Headroom.Config.Enrich: Enrich :: (Text -> Text) -> Enrich
+ Headroom.Config.Enrich: String :: ValueType
+ Headroom.Config.Enrich: [enrich] :: Enrich -> Text -> Text
+ Headroom.Config.Enrich: data ValueType
+ Headroom.Config.Enrich: instance GHC.Base.Monoid Headroom.Config.Enrich.Enrich
+ Headroom.Config.Enrich: instance GHC.Base.Semigroup Headroom.Config.Enrich.Enrich
+ Headroom.Config.Enrich: instance GHC.Classes.Eq Headroom.Config.Enrich.ValueType
+ Headroom.Config.Enrich: instance GHC.Show.Show Headroom.Config.Enrich.ValueType
+ Headroom.Config.Enrich: newtype Enrich
+ Headroom.Config.Enrich: replaceEmptyValue :: Text -> (Text -> (ValueType, Text)) -> Enrich
+ Headroom.Config.Enrich: withArray :: ToJSON a => [a] -> Text -> (ValueType, Text)
+ Headroom.Config.Enrich: withText :: Text -> Text -> (ValueType, Text)
+ Headroom.Config.Global: GlobalConfig :: UpdaterConfig -> GlobalConfig
+ Headroom.Config.Global: UpdaterConfig :: Bool -> Integer -> UpdaterConfig
+ Headroom.Config.Global: [gcUpdates] :: GlobalConfig -> UpdaterConfig
+ Headroom.Config.Global: [ucCheckForUpdates] :: UpdaterConfig -> Bool
+ Headroom.Config.Global: [ucUpdateIntervalDays] :: UpdaterConfig -> Integer
+ Headroom.Config.Global: data GlobalConfig
+ Headroom.Config.Global: data UpdaterConfig
+ Headroom.Config.Global: globalConfigPath :: HasRIO FileSystem env => RIO env FilePath
+ Headroom.Config.Global: initGlobalConfigIfNeeded :: HasRIO FileSystem env => RIO env ()
+ Headroom.Config.Global: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Config.Global.GlobalConfig
+ Headroom.Config.Global: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Config.Global.UpdaterConfig
+ Headroom.Config.Global: instance GHC.Classes.Eq Headroom.Config.Global.GlobalConfig
+ Headroom.Config.Global: instance GHC.Classes.Eq Headroom.Config.Global.UpdaterConfig
+ Headroom.Config.Global: instance GHC.Generics.Generic Headroom.Config.Global.GlobalConfig
+ Headroom.Config.Global: instance GHC.Generics.Generic Headroom.Config.Global.UpdaterConfig
+ Headroom.Config.Global: instance GHC.Show.Show Headroom.Config.Global.GlobalConfig
+ Headroom.Config.Global: instance GHC.Show.Show Headroom.Config.Global.UpdaterConfig
+ Headroom.Config.Global: loadGlobalConfig :: HasRIO FileSystem env => RIO env GlobalConfig
+ Headroom.Config.Global: parseGlobalConfig :: MonadThrow m => ByteString -> m GlobalConfig
+ Headroom.Config.Types: Add :: RunMode
+ Headroom.Config.Types: Apache2 :: LicenseType
+ Headroom.Config.Types: AppConfig :: (p ::: RunMode) -> (p ::: [FilePath]) -> (p ::: [Regex]) -> (p ::: Bool) -> (p ::: Maybe LicenseType) -> [TemplateRef] -> Variables -> HeadersConfig p -> PostProcessConfigs p -> AppConfig (p :: Phase)
+ Headroom.Config.Types: BSD3 :: LicenseType
+ Headroom.Config.Types: BlockComment :: Regex -> Regex -> Maybe Text -> HeaderSyntax
+ Headroom.Config.Types: Check :: RunMode
+ Headroom.Config.Types: CkBuiltInTemplates :: ConfigurationKey
+ Headroom.Config.Types: CkEnabled :: ConfigurationKey
+ Headroom.Config.Types: CkExcludeIgnoredPaths :: ConfigurationKey
+ Headroom.Config.Types: CkExcludedPaths :: ConfigurationKey
+ Headroom.Config.Types: CkFileExtensions :: FileType -> ConfigurationKey
+ Headroom.Config.Types: CkHeaderSyntax :: FileType -> ConfigurationKey
+ Headroom.Config.Types: CkMarginBottomCode :: FileType -> ConfigurationKey
+ Headroom.Config.Types: CkMarginBottomFile :: FileType -> ConfigurationKey
+ Headroom.Config.Types: CkMarginTopCode :: FileType -> ConfigurationKey
+ Headroom.Config.Types: CkMarginTopFile :: FileType -> ConfigurationKey
+ Headroom.Config.Types: CkPutAfter :: FileType -> ConfigurationKey
+ Headroom.Config.Types: CkPutBefore :: FileType -> ConfigurationKey
+ Headroom.Config.Types: CkRunMode :: ConfigurationKey
+ Headroom.Config.Types: CkSourcePaths :: ConfigurationKey
+ Headroom.Config.Types: CkVariables :: ConfigurationKey
+ Headroom.Config.Types: Complete :: Phase
+ Headroom.Config.Types: Drop :: RunMode
+ Headroom.Config.Types: GPL2 :: LicenseType
+ Headroom.Config.Types: GPL3 :: LicenseType
+ Headroom.Config.Types: GenConfigFile :: GenMode
+ Headroom.Config.Types: GenLicense :: (LicenseType, FileType) -> GenMode
+ Headroom.Config.Types: HeaderConfig :: (p ::: [Text]) -> (p ::: Int) -> (p ::: Int) -> (p ::: Int) -> (p ::: Int) -> (p ::: [Regex]) -> (p ::: [Regex]) -> (p ::: HeaderSyntax) -> HeaderConfig (p :: Phase)
+ Headroom.Config.Types: HeadersConfig :: HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeaderConfig p -> HeadersConfig (p :: Phase)
+ Headroom.Config.Types: LineComment :: Regex -> Maybe Text -> HeaderSyntax
+ Headroom.Config.Types: MIT :: LicenseType
+ Headroom.Config.Types: MPL2 :: LicenseType
+ Headroom.Config.Types: MissingConfiguration :: ConfigurationKey -> ConfigurationError
+ Headroom.Config.Types: MixedHeaderSyntax :: ConfigurationError
+ Headroom.Config.Types: Partial :: Phase
+ Headroom.Config.Types: PostProcessConfig :: (p ::: Bool) -> c p -> PostProcessConfig (p :: Phase) c
+ Headroom.Config.Types: PostProcessConfigs :: PostProcessConfig p UpdateCopyrightConfig -> PostProcessConfigs (p :: Phase)
+ Headroom.Config.Types: Replace :: RunMode
+ Headroom.Config.Types: UpdateCopyrightConfig :: (p ::: Maybe (NonEmpty Text)) -> UpdateCopyrightConfig (p :: Phase)
+ Headroom.Config.Types: [acBuiltInTemplates] :: AppConfig (p :: Phase) -> p ::: Maybe LicenseType
+ Headroom.Config.Types: [acExcludeIgnoredPaths] :: AppConfig (p :: Phase) -> p ::: Bool
+ Headroom.Config.Types: [acExcludedPaths] :: AppConfig (p :: Phase) -> p ::: [Regex]
+ Headroom.Config.Types: [acLicenseHeaders] :: AppConfig (p :: Phase) -> HeadersConfig p
+ Headroom.Config.Types: [acPostProcessConfigs] :: AppConfig (p :: Phase) -> PostProcessConfigs p
+ Headroom.Config.Types: [acRunMode] :: AppConfig (p :: Phase) -> p ::: RunMode
+ Headroom.Config.Types: [acSourcePaths] :: AppConfig (p :: Phase) -> p ::: [FilePath]
+ Headroom.Config.Types: [acTemplateRefs] :: AppConfig (p :: Phase) -> [TemplateRef]
+ Headroom.Config.Types: [acVariables] :: AppConfig (p :: Phase) -> Variables
+ Headroom.Config.Types: [hcFileExtensions] :: HeaderConfig (p :: Phase) -> p ::: [Text]
+ Headroom.Config.Types: [hcHeaderSyntax] :: HeaderConfig (p :: Phase) -> p ::: HeaderSyntax
+ Headroom.Config.Types: [hcMarginBottomCode] :: HeaderConfig (p :: Phase) -> p ::: Int
+ Headroom.Config.Types: [hcMarginBottomFile] :: HeaderConfig (p :: Phase) -> p ::: Int
+ Headroom.Config.Types: [hcMarginTopCode] :: HeaderConfig (p :: Phase) -> p ::: Int
+ Headroom.Config.Types: [hcMarginTopFile] :: HeaderConfig (p :: Phase) -> p ::: Int
+ Headroom.Config.Types: [hcPutAfter] :: HeaderConfig (p :: Phase) -> p ::: [Regex]
+ Headroom.Config.Types: [hcPutBefore] :: HeaderConfig (p :: Phase) -> p ::: [Regex]
+ Headroom.Config.Types: [hscC] :: HeadersConfig (p :: Phase) -> HeaderConfig p
+ Headroom.Config.Types: [hscCpp] :: HeadersConfig (p :: Phase) -> HeaderConfig p
+ Headroom.Config.Types: [hscCss] :: HeadersConfig (p :: Phase) -> HeaderConfig p
+ Headroom.Config.Types: [hscDart] :: HeadersConfig (p :: Phase) -> HeaderConfig p
+ Headroom.Config.Types: [hscGo] :: HeadersConfig (p :: Phase) -> HeaderConfig p
+ Headroom.Config.Types: [hscHaskell] :: HeadersConfig (p :: Phase) -> HeaderConfig p
+ Headroom.Config.Types: [hscHtml] :: HeadersConfig (p :: Phase) -> HeaderConfig p
+ Headroom.Config.Types: [hscJava] :: HeadersConfig (p :: Phase) -> HeaderConfig p
+ Headroom.Config.Types: [hscJs] :: HeadersConfig (p :: Phase) -> HeaderConfig p
+ Headroom.Config.Types: [hscKotlin] :: HeadersConfig (p :: Phase) -> HeaderConfig p
+ Headroom.Config.Types: [hscPhp] :: HeadersConfig (p :: Phase) -> HeaderConfig p
+ Headroom.Config.Types: [hscPureScript] :: HeadersConfig (p :: Phase) -> HeaderConfig p
+ Headroom.Config.Types: [hscRust] :: HeadersConfig (p :: Phase) -> HeaderConfig p
+ Headroom.Config.Types: [hscScala] :: HeadersConfig (p :: Phase) -> HeaderConfig p
+ Headroom.Config.Types: [hscShell] :: HeadersConfig (p :: Phase) -> HeaderConfig p
+ Headroom.Config.Types: [ppcConfig] :: PostProcessConfig (p :: Phase) c -> c p
+ Headroom.Config.Types: [ppcEnabled] :: PostProcessConfig (p :: Phase) c -> p ::: Bool
+ Headroom.Config.Types: [ppcsUpdateCopyright] :: PostProcessConfigs (p :: Phase) -> PostProcessConfig p UpdateCopyrightConfig
+ Headroom.Config.Types: [uccSelectedAuthors] :: UpdateCopyrightConfig (p :: Phase) -> p ::: Maybe (NonEmpty Text)
+ Headroom.Config.Types: data AppConfig (p :: Phase)
+ Headroom.Config.Types: data ConfigurationError
+ Headroom.Config.Types: data ConfigurationKey
+ Headroom.Config.Types: data GenMode
+ Headroom.Config.Types: data HeaderConfig (p :: Phase)
+ Headroom.Config.Types: data HeaderSyntax
+ Headroom.Config.Types: data HeadersConfig (p :: Phase)
+ Headroom.Config.Types: data LicenseType
+ Headroom.Config.Types: data Phase
+ Headroom.Config.Types: data PostProcessConfig (p :: Phase) c
+ Headroom.Config.Types: data PostProcessConfigs (p :: Phase)
+ Headroom.Config.Types: data RunMode
+ Headroom.Config.Types: data UpdateCopyrightConfig (p :: Phase)
+ Headroom.Config.Types: instance (Data.Aeson.Types.FromJSON.FromJSON (c 'Headroom.Config.Types.Partial), GHC.Base.Monoid (c 'Headroom.Config.Types.Partial)) => Data.Aeson.Types.FromJSON.FromJSON (Headroom.Config.Types.PtPostProcessConfig c)
+ Headroom.Config.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Config.Types.BlockComment'
+ Headroom.Config.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Config.Types.LineComment'
+ Headroom.Config.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Config.Types.PtAppConfig
+ Headroom.Config.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Config.Types.PtHeaderConfig
+ Headroom.Config.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Config.Types.PtHeadersConfig
+ Headroom.Config.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Config.Types.PtPostProcessConfigs
+ Headroom.Config.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Config.Types.PtUpdateCopyrightConfig
+ Headroom.Config.Types: instance Data.Aeson.Types.FromJSON.FromJSON Headroom.Config.Types.RunMode
+ Headroom.Config.Types: instance GHC.Base.Monoid (c 'Headroom.Config.Types.Partial) => GHC.Base.Monoid (Headroom.Config.Types.PtPostProcessConfig c)
+ Headroom.Config.Types: instance GHC.Base.Monoid Headroom.Config.Types.PtAppConfig
+ Headroom.Config.Types: instance GHC.Base.Monoid Headroom.Config.Types.PtHeaderConfig
+ Headroom.Config.Types: instance GHC.Base.Monoid Headroom.Config.Types.PtHeadersConfig
+ Headroom.Config.Types: instance GHC.Base.Monoid Headroom.Config.Types.PtPostProcessConfigs
+ Headroom.Config.Types: instance GHC.Base.Monoid Headroom.Config.Types.PtUpdateCopyrightConfig
+ Headroom.Config.Types: instance GHC.Base.Semigroup (c 'Headroom.Config.Types.Partial) => GHC.Base.Semigroup (Headroom.Config.Types.PtPostProcessConfig c)
+ Headroom.Config.Types: instance GHC.Base.Semigroup Headroom.Config.Types.PtAppConfig
+ Headroom.Config.Types: instance GHC.Base.Semigroup Headroom.Config.Types.PtHeaderConfig
+ Headroom.Config.Types: instance GHC.Base.Semigroup Headroom.Config.Types.PtHeadersConfig
+ Headroom.Config.Types: instance GHC.Base.Semigroup Headroom.Config.Types.PtPostProcessConfigs
+ Headroom.Config.Types: instance GHC.Base.Semigroup Headroom.Config.Types.PtUpdateCopyrightConfig
+ Headroom.Config.Types: instance GHC.Classes.Eq (c 'Headroom.Config.Types.Complete) => GHC.Classes.Eq (Headroom.Config.Types.CtPostProcessConfig c)
+ Headroom.Config.Types: instance GHC.Classes.Eq (c 'Headroom.Config.Types.Partial) => GHC.Classes.Eq (Headroom.Config.Types.PtPostProcessConfig c)
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.BlockComment'
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.ConfigurationError
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.ConfigurationKey
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.CtAppConfig
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.CtHeaderConfig
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.CtHeadersConfig
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.CtPostProcessConfigs
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.CtUpdateCopyrightConfig
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.GenMode
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.HeaderSyntax
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.LineComment'
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.PtAppConfig
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.PtHeaderConfig
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.PtHeadersConfig
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.PtPostProcessConfigs
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.PtUpdateCopyrightConfig
+ Headroom.Config.Types: instance GHC.Classes.Eq Headroom.Config.Types.RunMode
+ Headroom.Config.Types: instance GHC.Exception.Type.Exception Headroom.Config.Types.ConfigurationError
+ Headroom.Config.Types: instance GHC.Generics.Generic (Headroom.Config.Types.PtPostProcessConfig c)
+ Headroom.Config.Types: instance GHC.Generics.Generic Headroom.Config.Types.BlockComment'
+ Headroom.Config.Types: instance GHC.Generics.Generic Headroom.Config.Types.LineComment'
+ Headroom.Config.Types: instance GHC.Generics.Generic Headroom.Config.Types.PtAppConfig
+ Headroom.Config.Types: instance GHC.Generics.Generic Headroom.Config.Types.PtHeaderConfig
+ Headroom.Config.Types: instance GHC.Generics.Generic Headroom.Config.Types.PtHeadersConfig
+ Headroom.Config.Types: instance GHC.Generics.Generic Headroom.Config.Types.PtPostProcessConfigs
+ Headroom.Config.Types: instance GHC.Generics.Generic Headroom.Config.Types.PtUpdateCopyrightConfig
+ Headroom.Config.Types: instance GHC.Show.Show (c 'Headroom.Config.Types.Complete) => GHC.Show.Show (Headroom.Config.Types.CtPostProcessConfig c)
+ Headroom.Config.Types: instance GHC.Show.Show (c 'Headroom.Config.Types.Partial) => GHC.Show.Show (Headroom.Config.Types.PtPostProcessConfig c)
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.BlockComment'
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.ConfigurationError
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.ConfigurationKey
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.CtAppConfig
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.CtHeaderConfig
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.CtHeadersConfig
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.CtPostProcessConfigs
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.CtUpdateCopyrightConfig
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.GenMode
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.HeaderSyntax
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.LineComment'
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.PtAppConfig
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.PtHeaderConfig
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.PtHeadersConfig
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.PtPostProcessConfigs
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.PtUpdateCopyrightConfig
+ Headroom.Config.Types: instance GHC.Show.Show Headroom.Config.Types.RunMode
+ Headroom.Config.Types: type CtAppConfig = AppConfig 'Complete
+ Headroom.Config.Types: type CtHeaderConfig = HeaderConfig 'Complete
+ Headroom.Config.Types: type CtHeadersConfig = HeadersConfig 'Complete
+ Headroom.Config.Types: type CtPostProcessConfig c = PostProcessConfig 'Complete c
+ Headroom.Config.Types: type CtPostProcessConfigs = PostProcessConfigs 'Complete
+ Headroom.Config.Types: type CtUpdateCopyrightConfig = UpdateCopyrightConfig 'Complete
+ Headroom.Config.Types: type PtAppConfig = AppConfig 'Partial
+ Headroom.Config.Types: type PtHeaderConfig = HeaderConfig 'Partial
+ Headroom.Config.Types: type PtHeadersConfig = HeadersConfig 'Partial
+ Headroom.Config.Types: type PtPostProcessConfig c = PostProcessConfig 'Partial c
+ Headroom.Config.Types: type PtPostProcessConfigs = PostProcessConfigs 'Partial
+ Headroom.Config.Types: type PtUpdateCopyrightConfig = UpdateCopyrightConfig 'Partial
+ Headroom.Config.Types: type family (p :: Phase) ::: a
+ Headroom.Data.Has: type HasRIO a env = Has (a (RIO env)) env
+ Headroom.Embedded: defaultGlobalConfig :: IsString a => a
+ Headroom.Embedded.TH: embedDefaultGlobalConfig :: Q Exp
+ Headroom.FileSupport.Dart: fileSupport :: FileSupport
+ Headroom.FileSupport.Kotlin: fileSupport :: FileSupport
+ Headroom.FileSupport.PHP: fileSupport :: FileSupport
+ Headroom.FileType.Types: Dart :: FileType
+ Headroom.FileType.Types: Kotlin :: FileType
+ Headroom.FileType.Types: PHP :: FileType
+ Headroom.IO.FileSystem: [fsGetUserDirectory] :: FileSystem m -> GetUserDirectoryFn m
+ Headroom.IO.FileSystem: [fsWriteFile] :: FileSystem m -> WriteFileFn m
+ Headroom.IO.FileSystem: type GetUserDirectoryFn m = m FilePath
+ Headroom.IO.FileSystem: type WriteFileFn m = FilePath " file path" -> Text " file content" -> m () " write result"
+ Headroom.IO.KVStore: KVStore :: GetValueFn m -> PutValueFn m -> KVStore m
+ Headroom.IO.KVStore: StorePath :: Text -> StorePath
+ Headroom.IO.KVStore: ValueKey :: Text -> ValueKey a
+ Headroom.IO.KVStore: [kvGetValue] :: KVStore m -> GetValueFn m
+ Headroom.IO.KVStore: [kvPutValue] :: KVStore m -> PutValueFn m
+ Headroom.IO.KVStore: class ValueCodec a
+ Headroom.IO.KVStore: data KVStore m
+ Headroom.IO.KVStore: decodeValue :: ValueCodec a => Text -> Maybe a
+ Headroom.IO.KVStore: encodeValue :: ValueCodec a => a -> Text
+ Headroom.IO.KVStore: inMemoryKVStore :: MonadIO m => m (KVStore m)
+ Headroom.IO.KVStore: instance (TypeError ...) => Database.Persist.Class.PersistUnique.AtLeastOneUniqueKey Headroom.IO.KVStore.StoreRecord
+ Headroom.IO.KVStore: instance (TypeError ...) => Database.Persist.Class.PersistUnique.OnlyOneUniqueKey Headroom.IO.KVStore.StoreRecord
+ Headroom.IO.KVStore: instance Data.Aeson.Types.FromJSON.FromJSON (Database.Persist.Class.PersistEntity.Key Headroom.IO.KVStore.StoreRecord)
+ Headroom.IO.KVStore: instance Data.Aeson.Types.ToJSON.ToJSON (Database.Persist.Class.PersistEntity.Key Headroom.IO.KVStore.StoreRecord)
+ Headroom.IO.KVStore: instance Database.Persist.Class.PersistEntity.PersistEntity Headroom.IO.KVStore.StoreRecord
+ Headroom.IO.KVStore: instance Database.Persist.Class.PersistEntity.SymbolToField "id" Headroom.IO.KVStore.StoreRecord (Database.Persist.Class.PersistEntity.Key Headroom.IO.KVStore.StoreRecord)
+ Headroom.IO.KVStore: instance Database.Persist.Class.PersistEntity.SymbolToField "value" Headroom.IO.KVStore.StoreRecord Data.Text.Internal.Text
+ Headroom.IO.KVStore: instance Database.Persist.Class.PersistField.PersistField (Database.Persist.Class.PersistEntity.Key Headroom.IO.KVStore.StoreRecord)
+ Headroom.IO.KVStore: instance Database.Persist.Class.PersistField.PersistField Headroom.IO.KVStore.StoreRecord
+ Headroom.IO.KVStore: instance Database.Persist.Sql.Class.PersistFieldSql (Database.Persist.Class.PersistEntity.Key Headroom.IO.KVStore.StoreRecord)
+ Headroom.IO.KVStore: instance Database.Persist.Sql.Class.PersistFieldSql Headroom.IO.KVStore.StoreRecord
+ Headroom.IO.KVStore: instance GHC.Classes.Eq (Database.Persist.Class.PersistEntity.Key Headroom.IO.KVStore.StoreRecord)
+ Headroom.IO.KVStore: instance GHC.Classes.Eq (Headroom.IO.KVStore.ValueKey a)
+ Headroom.IO.KVStore: instance GHC.Classes.Eq Headroom.IO.KVStore.StorePath
+ Headroom.IO.KVStore: instance GHC.Classes.Ord (Database.Persist.Class.PersistEntity.Key Headroom.IO.KVStore.StoreRecord)
+ Headroom.IO.KVStore: instance GHC.Read.Read (Database.Persist.Class.PersistEntity.Key Headroom.IO.KVStore.StoreRecord)
+ Headroom.IO.KVStore: instance GHC.Show.Show (Database.Persist.Class.PersistEntity.Key Headroom.IO.KVStore.StoreRecord)
+ Headroom.IO.KVStore: instance GHC.Show.Show (Headroom.IO.KVStore.ValueKey a)
+ Headroom.IO.KVStore: instance GHC.Show.Show Headroom.IO.KVStore.StorePath
+ Headroom.IO.KVStore: instance GHC.Show.Show Headroom.IO.KVStore.StoreRecord
+ Headroom.IO.KVStore: instance Headroom.IO.KVStore.ValueCodec Data.Text.Internal.Text
+ Headroom.IO.KVStore: instance Headroom.IO.KVStore.ValueCodec Data.Time.Clock.Internal.UTCTime.UTCTime
+ Headroom.IO.KVStore: instance Web.Internal.HttpApiData.FromHttpApiData (Database.Persist.Class.PersistEntity.Key Headroom.IO.KVStore.StoreRecord)
+ Headroom.IO.KVStore: instance Web.Internal.HttpApiData.ToHttpApiData (Database.Persist.Class.PersistEntity.Key Headroom.IO.KVStore.StoreRecord)
+ Headroom.IO.KVStore: instance Web.PathPieces.PathPiece (Database.Persist.Class.PersistEntity.Key Headroom.IO.KVStore.StoreRecord)
+ Headroom.IO.KVStore: newtype StorePath
+ Headroom.IO.KVStore: newtype ValueKey a
+ Headroom.IO.KVStore: sqliteKVStore :: MonadIO m => StorePath -> KVStore m
+ Headroom.IO.KVStore: type PutValueFn m = forall a. (ValueCodec a) => ValueKey a " key for the value" -> a " value to put into store" -> m () " operation result"
+ Headroom.IO.KVStore: valueKey :: Text -> ValueKey a
+ Headroom.IO.Network: ConnectionFailure :: URI -> Text -> NetworkError
+ Headroom.IO.Network: InvalidStatus :: URI -> Int -> Text -> NetworkError
+ Headroom.IO.Network: InvalidURL :: URI -> NetworkError
+ Headroom.IO.Network: data NetworkError
+ Headroom.Meta: cacheFileName :: IsString a => a
+ Headroom.Meta: globalConfigDirName :: IsString a => a
+ Headroom.Meta: globalConfigFileName :: IsString a => a
+ Headroom.Meta: productVendor :: IsString a => a
+ Headroom.UI.Message: Error :: MessageType
+ Headroom.UI.Message: Info :: MessageType
+ Headroom.UI.Message: Message :: MessageType -> Text -> Message
+ Headroom.UI.Message: Warn :: MessageType
+ Headroom.UI.Message: data Message
+ Headroom.UI.Message: data MessageType
+ Headroom.UI.Message: instance GHC.Classes.Eq Headroom.UI.Message.Message
+ Headroom.UI.Message: instance GHC.Classes.Eq Headroom.UI.Message.MessageType
+ Headroom.UI.Message: instance GHC.Show.Show Headroom.UI.Message.Message
+ Headroom.UI.Message: instance GHC.Show.Show Headroom.UI.Message.MessageType
+ Headroom.UI.Message: instance RIO.Prelude.Display.Display Headroom.UI.Message.Message
+ Headroom.UI.Message: instance RIO.Prelude.Display.Display Headroom.UI.Message.MessageType
+ Headroom.UI.Message: messageError :: Text -> Message
+ Headroom.UI.Message: messageInfo :: Text -> Message
+ Headroom.UI.Message: messageWarn :: Text -> Message
+ Headroom.Updater: CannotDetectVersion :: Text -> UpdaterError
+ Headroom.Updater: checkUpdates :: (HasRIO KVStore env, HasRIO Network env) => UpdaterConfig -> RIO env (Maybe Version)
+ Headroom.Updater: data UpdaterError
+ Headroom.Updater: fetchLatestVersion :: HasRIO Network env => RIO env Version
+ Headroom.Updater: instance GHC.Classes.Eq Headroom.Updater.UpdaterError
+ Headroom.Updater: instance GHC.Exception.Type.Exception Headroom.Updater.UpdaterError
+ Headroom.Updater: instance GHC.Show.Show Headroom.Updater.UpdaterError
+ Headroom.Updater: parseLatestVersion :: MonadThrow m => Value -> m Version
- Headroom.Command.Init: doesAppConfigExist :: (HasLogFunc env, Has (FileSystem (RIO env)) env, Has Paths env) => RIO env Bool
+ Headroom.Command.Init: doesAppConfigExist :: (HasLogFunc env, HasRIO FileSystem env, Has Paths env) => RIO env Bool
- Headroom.Command.Run: loadTemplateRefs :: forall a env. (Template a, Has (Network (RIO env)) env, Has (FileSystem (RIO env)) env, HasLogFunc env) => [TemplateRef] -> RIO env (Map FileType a)
+ Headroom.Command.Run: loadTemplateRefs :: forall a env. (Template a, HasRIO Network env, HasRIO FileSystem env, HasLogFunc env) => [TemplateRef] -> RIO env (Map FileType a)
- Headroom.IO.FileSystem: FileSystem :: CreateDirectoryFn m -> DoesFileExistFn m -> FindFilesFn m -> FindFilesByExtsFn m -> FindFilesByTypesFn m -> GetCurrentDirectoryFn m -> ListFilesFn m -> LoadFileFn m -> FileSystem m
+ Headroom.IO.FileSystem: FileSystem :: CreateDirectoryFn m -> DoesFileExistFn m -> FindFilesFn m -> FindFilesByExtsFn m -> FindFilesByTypesFn m -> GetCurrentDirectoryFn m -> GetUserDirectoryFn m -> ListFilesFn m -> LoadFileFn m -> WriteFileFn m -> FileSystem m
- Headroom.IO.Network: downloadContent :: MonadIO m => URI -> m Text
+ Headroom.IO.Network: downloadContent :: MonadIO m => URI -> m ByteString
- Headroom.IO.Network: type DownloadContentFn m = URI " /URI/ of remote resource" -> m Text " downloaded content"
+ Headroom.IO.Network: type DownloadContentFn m = URI " /URI/ of remote resource" -> m ByteString " downloaded content"

Files

CHANGELOG.md view
@@ -1,6 +1,14 @@ # Changelog All notable changes to this project will be documented in this file. +## 0.4.3.0 (released 2022-01-20)+- [#78] Check automatically for Headroom updates+- [#81] Add support for _PHP_ language+- [#83] FIXED: _Update Copyright_ post-processor incorrectly changes years in some cases+- [#84] Add support for _Dart_ language+- [#85] Add support for _Kotlin_ language+- Bump _LTS Haskell_ to `18.22`+ ## 0.4.2.0 (released 2021-07-01) - [#42] Add option to exclude source paths ignored by VCS - [#66] Allow loading templates from HTTP(S) resource
LICENSE view
@@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2019-2021, Vaclav Svejcar+Copyright (c) 2019-2022, Vaclav Svejcar All rights reserved.  Redistribution and use in source and binary forms, with or without
README.md view
@@ -2,8 +2,6 @@  __Headroom__ also offers much more than just [adding, replacing or dropping][doc:running-headroom] license headers. It can also [update years in copyrights][doc:post-processing] for you, provides [content-aware templates][doc:templates] for some source code file types, and much more! -[![asciicast](https://asciinema.org/a/DkSBMZPHMJvJ4jyDtvT9ehfs8.svg)](https://asciinema.org/a/DkSBMZPHMJvJ4jyDtvT9ehfs8)- ## Main Features - __License Header Management__ - [Add, replace or drop license headers][doc:running-headroom] in your source code files with a single command. What's more, contrary to many similar tools, _Headroom_ allows you to also replace/drop headers that weren't previously generated by _Headroom_, using smart header auto-detection. - __Powerful Customization__ - Default [configuration][doc:configuration] should cover most use-cases, but if you need to put empty lines before/after generated header, use different comment style of headers, you can customize the configuration to match exactly your needs.@@ -24,6 +22,9 @@ - [kowainik/hit-on](https://github.com/kowainik/hit-on) - Kowainik Git Workflow Helper Tool - [kowainik/summoner](https://github.com/kowainik/summoner) - Tool for scaffolding batteries-included production-level Haskell projects - [wireapp/wire-server](https://github.com/wireapp/wire-server) - Wire back-end services (https://wire.com)++## Mentions+- [Bind The Gap magazine, issue #2](https://bindthegap.news/issues/02dec2020.html) has chapter dedicated to _Headroom_ (pages _17-18_).  ## Documentation * for end-user documentation, [official project microsite][web:headroom]
app/Main.hs view
@@ -6,7 +6,7 @@ {-| Module      : Main Description : Main application launcher-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
doctest/Main.hs view
@@ -1,6 +1,18 @@-module Main (main) where+module Main+  ( main+  )+where -import Test.DocTest-    +import           Test.DocTest+ main :: IO ()-main = doctest ["-XOverloadedStrings", "src"]+main = doctest+  [ "-XDeriveAnyClass"+  , "-XFlexibleContexts"+  , "-XOverloadedStrings"+  , "-XTemplateHaskell"+  , "-XTypeApplications"+  , "-XTypeFamilies"+  , "-XQuasiQuotes"+  , "src"+  ]
embedded/default-config.yaml view
@@ -138,6 +138,18 @@       starts-with: ^\/\*       ends-with: \*\/$ +  ## Dart configuration+  dart:+    file-extensions: ["dart"]+    margin-top-code: 0+    margin-top-file: 0+    margin-bottom-code: 0+    margin-bottom-file: 0+    put-after: []+    put-before: []+    line-comment:+      prefixed-by: ^\/\/+   ## Go configuration   go:     file-extensions: ["go"]@@ -200,6 +212,32 @@     put-before: []     block-comment:       starts-with: ^\/\*+      ends-with: \*\/$++  ## Kotlin configuration+  kotlin:+    file-extensions: ["kt"]+    margin-top-code: 0+    margin-top-file: 0+    margin-bottom-code: 0+    margin-bottom-file: 0+    put-after: []+    put-before: ["^package"]+    block-comment:+      starts-with: ^\/\*+      ends-with: \*\/$++  ## PHP configuration+  php:+    file-extensions: ["php"]+    margin-top-code: 0+    margin-top-file: 0+    margin-bottom-code: 0+    margin-bottom-file: 0+    put-after: []+    put-before: []+    block-comment:+      starts-with: ^\/\*\*       ends-with: \*\/$    ## PureScript configuration
+ embedded/default-global-config.yaml view
@@ -0,0 +1,11 @@+## This is the global configuration file for Headroom.+## See https://github.com/vaclavsvejcar/headroom for more details.++## Configuration for Headroom Updater.+updates:++  ## Whether Headroom should automatically check for available updates. +  check-for-updates: true++  ## How often (in days) should Headroom check for updates.+  update-interval-days: 7
+ embedded/license/apache2/dart.mustache view
@@ -0,0 +1,14 @@+// {{ project }}+// Copyright {{ year }} {{ author }}+// +// Licensed under the Apache License, Version 2.0 (the "License");+// you may not use this file except in compliance with the License.+// You may obtain a copy of the License at+// +// http://www.apache.org/licenses/LICENSE-2.0+// +// Unless required by applicable law or agreed to in writing, software+// distributed under the License is distributed on an "AS IS" BASIS,+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+// or implied. See the License for the specific language governing+// permissions and limitations under the License.
+ embedded/license/apache2/kotlin.mustache view
@@ -0,0 +1,16 @@+/*+ * {{ project }}+ * Copyright {{ year }} {{ author }}+ * + * Licensed under the Apache License, Version 2.0 (the "License");+ * you may not use this file except in compliance with the License.+ * You may obtain a copy of the License at+ * + * http://www.apache.org/licenses/LICENSE-2.0+ * + * Unless required by applicable law or agreed to in writing, software+ * distributed under the License is distributed on an "AS IS" BASIS,+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+ * or implied. See the License for the specific language governing+ * permissions and limitations under the License.+ */
+ embedded/license/apache2/php.mustache view
@@ -0,0 +1,16 @@+/**+ * {{ project }}+ * Copyright {{ year }} {{ author }}+ * + * Licensed under the Apache License, Version 2.0 (the "License");+ * you may not use this file except in compliance with the License.+ * You may obtain a copy of the License at+ * + * http://www.apache.org/licenses/LICENSE-2.0+ * + * Unless required by applicable law or agreed to in writing, software+ * distributed under the License is distributed on an "AS IS" BASIS,+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express+ * or implied. See the License for the specific language governing+ * permissions and limitations under the License.+ */
+ embedded/license/bsd3/dart.mustache view
@@ -0,0 +1,27 @@+// {{ project }}+// Copyright (c) {{ year }} {{ author }}+// All rights reserved.+// +// Redistribution and use in source and binary forms, with or without+// modification, are permitted provided that the following conditions are met:+// +// 1. Redistributions of source code must retain the above copyright notice,+//    this list of conditions and the following disclaimer.+// 2. Redistributions in binary form must reproduce the above copyright+//    notice, this list of conditions and the following disclaimer in the+//    documentation and/or other materials provided with the distribution.+// 3. Neither the name of copyright holder nor the names of its+//    contributors may be used to endorse or promote products derived from+//    this software without specific prior written permission.+// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+// POSSIBILITY OF SUCH DAMAGE.
+ embedded/license/bsd3/kotlin.mustache view
@@ -0,0 +1,29 @@+/*+ * {{ project }}+ * Copyright (c) {{ year }} {{ author }}+ * All rights reserved.+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions are met:+ *+ * 1. Redistributions of source code must retain the above copyright notice,+ *    this list of conditions and the following disclaimer.+ * 2. Redistributions in binary form must reproduce the above copyright+ *    notice, this list of conditions and the following disclaimer in the+ *    documentation and/or other materials provided with the distribution.+ * 3. Neither the name of copyright holder nor the names of its+ *    contributors may be used to endorse or promote products derived from+ *    this software without specific prior written permission.+ *+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+ * POSSIBILITY OF SUCH DAMAGE.+ */
+ embedded/license/bsd3/php.mustache view
@@ -0,0 +1,29 @@+/**+ * {{ project }}+ * Copyright (c) {{ year }} {{ author }}+ * All rights reserved.+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions are met:+ *+ * 1. Redistributions of source code must retain the above copyright notice,+ *    this list of conditions and the following disclaimer.+ * 2. Redistributions in binary form must reproduce the above copyright+ *    notice, this list of conditions and the following disclaimer in the+ *    documentation and/or other materials provided with the distribution.+ * 3. Neither the name of copyright holder nor the names of its+ *    contributors may be used to endorse or promote products derived from+ *    this software without specific prior written permission.+ *+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+ * POSSIBILITY OF SUCH DAMAGE.+ */
+ embedded/license/gpl2/dart.mustache view
@@ -0,0 +1,17 @@+// {{ project }}+// Copyright (c) {{ year }} {{ author }}+// +// This program is free software; you can redistribute it and/or modify+// it under the terms of the GNU General Public License as published by+// the Free Software Foundation; either version 2 of the License, or (at+// your option) any later version.+// +// This program is distributed in the hope that it will be useful, but+// WITHOUT ANY WARRANTY; without even the implied warranty of+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU+// General Public License for more details.+// +// You should have received a copy of the GNU General Public License+// along with this program; if not, write to the Free Software+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307+// USA.
+ embedded/license/gpl2/kotlin.mustache view
@@ -0,0 +1,19 @@+/*+ * {{ project }}+ * Copyright (c) {{ year }} {{ author }}+ * + * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation; either version 2 of the License, or (at+ * your option) any later version.+ * + * This program is distributed in the hope that it will be useful, but+ * WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU+ * General Public License for more details.+ * + * You should have received a copy of the GNU General Public License+ * along with this program; if not, write to the Free Software+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307+ * USA.+ */
+ embedded/license/gpl2/php.mustache view
@@ -0,0 +1,19 @@+/**+ * {{ project }}+ * Copyright (c) {{ year }} {{ author }}+ * + * This program is free software; you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation; either version 2 of the License, or (at+ * your option) any later version.+ * + * This program is distributed in the hope that it will be useful, but+ * WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU+ * General Public License for more details.+ * + * You should have received a copy of the GNU General Public License+ * along with this program; if not, write to the Free Software+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307+ * USA.+ */
+ embedded/license/gpl3/dart.mustache view
@@ -0,0 +1,15 @@+// {{ project }}+// Copyright (C) {{ year }} {{ author }}+// +// This program is free software: you can redistribute it and/or modify+// it under the terms of the GNU General Public License as published by+// the Free Software Foundation, either version 3 of the License, or+// (at your option) any later version.+// +// This program is distributed in the hope that it will be useful,+// but WITHOUT ANY WARRANTY; without even the implied warranty of+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+// GNU General Public License for more details.+// +// You should have received a copy of the GNU General Public License+// along with this program.  If not, see http://www.gnu.org/licenses/.
+ embedded/license/gpl3/kotlin.mustache view
@@ -0,0 +1,17 @@+/*+ * {{ project }}+ * Copyright (C) {{ year }} {{ author }}+ * + * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 3 of the License, or+ * (at your option) any later version.+ * + * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+ * GNU General Public License for more details.+ * + * You should have received a copy of the GNU General Public License+ * along with this program.  If not, see http://www.gnu.org/licenses/.+ */
+ embedded/license/gpl3/php.mustache view
@@ -0,0 +1,17 @@+/**+ * {{ project }}+ * Copyright (C) {{ year }} {{ author }}+ * + * This program is free software: you can redistribute it and/or modify+ * it under the terms of the GNU General Public License as published by+ * the Free Software Foundation, either version 3 of the License, or+ * (at your option) any later version.+ * + * This program is distributed in the hope that it will be useful,+ * but WITHOUT ANY WARRANTY; without even the implied warranty of+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+ * GNU General Public License for more details.+ * + * You should have received a copy of the GNU General Public License+ * along with this program.  If not, see http://www.gnu.org/licenses/.+ */
+ embedded/license/mit/dart.mustache view
@@ -0,0 +1,22 @@+// The MIT License+// +// {{ project }}+// Copyright (c) {{ year }} {{ author }}+// +// Permission is hereby granted, free of charge, to any person obtaining a copy+// of this software and associated documentation files (the "Software"), to deal+// in the Software without restriction, including without limitation the rights+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+// copies of the Software, and to permit persons to whom the Software is+// furnished to do so, subject to the following conditions:+// +// The above copyright notice and this permission notice shall be included in+// all copies or substantial portions of the Software.+// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+// THE SOFTWARE.
+ embedded/license/mit/kotlin.mustache view
@@ -0,0 +1,24 @@+/*+ * The MIT License+ *+ * {{ project }}+ * Copyright (c) {{ year }} {{ author }}+ *+ * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ *+ * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+ * THE SOFTWARE.+ */
+ embedded/license/mit/php.mustache view
@@ -0,0 +1,24 @@+/**+ * The MIT License+ *+ * {{ project }}+ * Copyright (c) {{ year }} {{ author }}+ *+ * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ *+ * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ *+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+ * THE SOFTWARE.+ */
embedded/license/mpl2/c.mustache view
@@ -2,7 +2,7 @@  * {{ project }}  * Copyright (c) {{ year }} {{ author }}  *- * This Source Code Form is subject to the terms of the Mozilla Public+ * This Source Code Form is subject to the terms of the Mozilla Public  * License, version 2.0. If a copy of the MPL was not distributed with this  * file, You can obtain one at http://mozilla.org/MPL/2.0/.  */
embedded/license/mpl2/cpp.mustache view
@@ -2,7 +2,7 @@  * {{ project }}  * Copyright (c) {{ year }} {{ author }}  *- * This Source Code Form is subject to the terms of the Mozilla Public+ * This Source Code Form is subject to the terms of the Mozilla Public  * License, version 2.0. If a copy of the MPL was not distributed with this  * file, You can obtain one at http://mozilla.org/MPL/2.0/.  */
embedded/license/mpl2/css.mustache view
@@ -2,7 +2,7 @@  * {{ project }}  * Copyright (c) {{ year }} {{ author }}  *- * This Source Code Form is subject to the terms of the Mozilla Public+ * This Source Code Form is subject to the terms of the Mozilla Public  * License, version 2.0. If a copy of the MPL was not distributed with this  * file, You can obtain one at http://mozilla.org/MPL/2.0/.  */
+ embedded/license/mpl2/dart.mustache view
@@ -0,0 +1,6 @@+// {{ project }}+// Copyright (c) {{ year }} {{ author }}+// +// This Source Code Form is subject to the terms of the Mozilla Public+// License, version 2.0. If a copy of the MPL was not distributed with this+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
embedded/license/mpl2/java.mustache view
@@ -2,7 +2,7 @@  * {{ project }}  * Copyright (c) {{ year }} {{ author }}  *- * This Source Code Form is subject to the terms of the Mozilla Public+ * This Source Code Form is subject to the terms of the Mozilla Public  * License, version 2.0. If a copy of the MPL was not distributed with this  * file, You can obtain one at http://mozilla.org/MPL/2.0/.  */
embedded/license/mpl2/js.mustache view
@@ -2,7 +2,7 @@  * {{ project }}  * Copyright (c) {{ year }} {{ author }}  *- * This Source Code Form is subject to the terms of the Mozilla Public+ * This Source Code Form is subject to the terms of the Mozilla Public  * License, version 2.0. If a copy of the MPL was not distributed with this  * file, You can obtain one at http://mozilla.org/MPL/2.0/.  */
+ embedded/license/mpl2/kotlin.mustache view
@@ -0,0 +1,8 @@+/*+ * {{ project }}+ * Copyright (c) {{ year }} {{ author }}+ *+ * This Source Code Form is subject to the terms of the Mozilla Public+ * License, version 2.0. If a copy of the MPL was not distributed with this+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.+ */
+ embedded/license/mpl2/php.mustache view
@@ -0,0 +1,8 @@+/**+ * {{ project }}+ * Copyright (c) {{ year }} {{ author }}+ *+ * This Source Code Form is subject to the terms of the Mozilla Public+ * License, version 2.0. If a copy of the MPL was not distributed with this+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.+ */
embedded/license/mpl2/purescript.mustache view
@@ -1,6 +1,6 @@ -- {{ project }} -- Copyright (c) {{ year }} {{ author }} ----- This Source Code Form is subject to the terms of the Mozilla Public+-- This Source Code Form is subject to the terms of the Mozilla Public -- License, version 2.0. If a copy of the MPL was not distributed with this -- file, You can obtain one at http://mozilla.org/MPL/2.0/.
embedded/license/mpl2/rust.mustache view
@@ -2,7 +2,7 @@  * {{ project }}  * Copyright (c) {{ year }} {{ author }}  *- * This Source Code Form is subject to the terms of the Mozilla Public+ * This Source Code Form is subject to the terms of the Mozilla Public  * License, version 2.0. If a copy of the MPL was not distributed with this  * file, You can obtain one at http://mozilla.org/MPL/2.0/.  */
embedded/license/mpl2/scala.mustache view
@@ -2,7 +2,7 @@  * {{ project }}  * Copyright (c) {{ year }} {{ author }}  *- * This Source Code Form is subject to the terms of the Mozilla Public+ * This Source Code Form is subject to the terms of the Mozilla Public  * License, version 2.0. If a copy of the MPL was not distributed with this  * file, You can obtain one at http://mozilla.org/MPL/2.0/.  */
embedded/license/mpl2/shell.mustache view
@@ -1,6 +1,6 @@ # {{ project }} # Copyright (c) {{ year }} {{ author }} #-# This Source Code Form is subject to the terms of the Mozilla Public+# This Source Code Form is subject to the terms of the Mozilla Public # License, version 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/.
headroom.cabal view
@@ -1,13 +1,13 @@ cabal-version: 2.2 --- This file has been generated from package.yaml by hpack version 0.33.0.+-- This file has been generated from package.yaml by hpack version 0.34.4. -- -- see: https://github.com/sol/hpack ----- hash: 65abf7f836c076afc90aa5cf7190e8d0cabee4309c39c66ebd00b9da3a773b92+-- hash: 8dbd94f20b545137c016234c26cc395c68c918d80a2b0da9edc45410b77d95f4  name:           headroom-version:        0.4.2.0+version:        0.4.3.0 synopsis:       License Header Manager description:    Would you like to have nice, up-to-date license/copyright headers in your source code files but hate to manage them by hand? Then Headroom is the right tool for you! Now you can define your license header as Mustache template, put all the variables (such as author's name, year, etc.) into the YAML config file and Headroom will take care to add such license headers to all your source code files. category:       Utils@@ -15,7 +15,7 @@ bug-reports:    https://github.com/vaclavsvejcar/headroom/issues author:         Vaclav Svejcar maintainer:     vaclav.svejcar@gmail.com-copyright:      Copyright (c) 2019-2021 Vaclav Svejcar+copyright:      Copyright (c) 2019-2022 Vaclav Svejcar license:        BSD-3-Clause license-file:   LICENSE build-type:     Simple@@ -25,14 +25,18 @@     README.md     embedded/config-file.yaml     embedded/default-config.yaml+    embedded/default-global-config.yaml     embedded/license/apache2/c.mustache     embedded/license/apache2/cpp.mustache     embedded/license/apache2/css.mustache+    embedded/license/apache2/dart.mustache     embedded/license/apache2/go.mustache     embedded/license/apache2/haskell.mustache     embedded/license/apache2/html.mustache     embedded/license/apache2/java.mustache     embedded/license/apache2/js.mustache+    embedded/license/apache2/kotlin.mustache+    embedded/license/apache2/php.mustache     embedded/license/apache2/purescript.mustache     embedded/license/apache2/rust.mustache     embedded/license/apache2/scala.mustache@@ -40,11 +44,14 @@     embedded/license/bsd3/c.mustache     embedded/license/bsd3/cpp.mustache     embedded/license/bsd3/css.mustache+    embedded/license/bsd3/dart.mustache     embedded/license/bsd3/go.mustache     embedded/license/bsd3/haskell.mustache     embedded/license/bsd3/html.mustache     embedded/license/bsd3/java.mustache     embedded/license/bsd3/js.mustache+    embedded/license/bsd3/kotlin.mustache+    embedded/license/bsd3/php.mustache     embedded/license/bsd3/purescript.mustache     embedded/license/bsd3/rust.mustache     embedded/license/bsd3/scala.mustache@@ -52,11 +59,14 @@     embedded/license/gpl2/c.mustache     embedded/license/gpl2/cpp.mustache     embedded/license/gpl2/css.mustache+    embedded/license/gpl2/dart.mustache     embedded/license/gpl2/go.mustache     embedded/license/gpl2/haskell.mustache     embedded/license/gpl2/html.mustache     embedded/license/gpl2/java.mustache     embedded/license/gpl2/js.mustache+    embedded/license/gpl2/kotlin.mustache+    embedded/license/gpl2/php.mustache     embedded/license/gpl2/purescript.mustache     embedded/license/gpl2/rust.mustache     embedded/license/gpl2/scala.mustache@@ -64,11 +74,14 @@     embedded/license/gpl3/c.mustache     embedded/license/gpl3/cpp.mustache     embedded/license/gpl3/css.mustache+    embedded/license/gpl3/dart.mustache     embedded/license/gpl3/go.mustache     embedded/license/gpl3/haskell.mustache     embedded/license/gpl3/html.mustache     embedded/license/gpl3/java.mustache     embedded/license/gpl3/js.mustache+    embedded/license/gpl3/kotlin.mustache+    embedded/license/gpl3/php.mustache     embedded/license/gpl3/purescript.mustache     embedded/license/gpl3/rust.mustache     embedded/license/gpl3/scala.mustache@@ -76,11 +89,14 @@     embedded/license/mit/c.mustache     embedded/license/mit/cpp.mustache     embedded/license/mit/css.mustache+    embedded/license/mit/dart.mustache     embedded/license/mit/go.mustache     embedded/license/mit/haskell.mustache     embedded/license/mit/html.mustache     embedded/license/mit/java.mustache     embedded/license/mit/js.mustache+    embedded/license/mit/kotlin.mustache+    embedded/license/mit/php.mustache     embedded/license/mit/purescript.mustache     embedded/license/mit/rust.mustache     embedded/license/mit/scala.mustache@@ -88,11 +104,14 @@     embedded/license/mpl2/c.mustache     embedded/license/mpl2/cpp.mustache     embedded/license/mpl2/css.mustache+    embedded/license/mpl2/dart.mustache     embedded/license/mpl2/go.mustache     embedded/license/mpl2/haskell.mustache     embedded/license/mpl2/html.mustache     embedded/license/mpl2/java.mustache     embedded/license/mpl2/js.mustache+    embedded/license/mpl2/kotlin.mustache+    embedded/license/mpl2/php.mustache     embedded/license/mpl2/purescript.mustache     embedded/license/mpl2/rust.mustache     embedded/license/mpl2/scala.mustache@@ -104,6 +123,7 @@     test-data/code-samples/cpp/sample2.cpp     test-data/code-samples/css/sample1.css     test-data/code-samples/css/sample2.css+    test-data/code-samples/dart/sample1.dart     test-data/code-samples/go/sample1.go     test-data/code-samples/haskell/full.hs     test-data/code-samples/haskell/header.hs@@ -116,6 +136,8 @@     test-data/code-samples/java/sample2.java     test-data/code-samples/js/sample1.js     test-data/code-samples/js/sample2.js+    test-data/code-samples/kotlin/sample1.kt+    test-data/code-samples/php/sample1.php     test-data/code-samples/purescript/full.purs     test-data/code-samples/rust/sample1.rs     test-data/code-samples/scala/sample1.scala@@ -127,6 +149,7 @@     test-data/test-traverse/foo/b.html     test-data/test-traverse/foo/test.xml     test-data/test-traverse/foo/bar/c.html+    test-data/updater/github-resp.json  source-repository head   type: git@@ -135,16 +158,18 @@ library   exposed-modules:       Headroom.Command+      Headroom.Command.Bootstrap       Headroom.Command.Gen       Headroom.Command.Init       Headroom.Command.Readers       Headroom.Command.Run       Headroom.Command.Types       Headroom.Command.Utils-      Headroom.Configuration-      Headroom.Configuration.Compat-      Headroom.Configuration.Enrich-      Headroom.Configuration.Types+      Headroom.Config+      Headroom.Config.Compat+      Headroom.Config.Enrich+      Headroom.Config.Global+      Headroom.Config.Types       Headroom.Data.Coerce       Headroom.Data.EnumExtra       Headroom.Data.Has@@ -158,12 +183,15 @@       Headroom.FileSupport.C       Headroom.FileSupport.CPP       Headroom.FileSupport.CSS+      Headroom.FileSupport.Dart       Headroom.FileSupport.Go       Headroom.FileSupport.Haskell       Headroom.FileSupport.Haskell.Haddock       Headroom.FileSupport.HTML       Headroom.FileSupport.Java       Headroom.FileSupport.JS+      Headroom.FileSupport.Kotlin+      Headroom.FileSupport.PHP       Headroom.FileSupport.PureScript       Headroom.FileSupport.Rust       Headroom.FileSupport.Scala@@ -176,6 +204,7 @@       Headroom.Header.Sanitize       Headroom.Header.Types       Headroom.IO.FileSystem+      Headroom.IO.KVStore       Headroom.IO.Network       Headroom.Meta       Headroom.Meta.Version@@ -188,8 +217,10 @@       Headroom.Template.TemplateRef       Headroom.Types       Headroom.UI+      Headroom.UI.Message       Headroom.UI.Progress       Headroom.UI.Table+      Headroom.Updater       Headroom.Variables       Headroom.Variables.Types   other-modules:@@ -209,6 +240,7 @@     , http-client     , http-types     , microlens+    , microlens-aeson     , microlens-th     , modern-uri     , mtl@@ -216,6 +248,8 @@     , optparse-applicative     , pcre-heavy     , pcre-light+    , persistent+    , persistent-sqlite     , req     , rio     , string-interpolate@@ -261,9 +295,10 @@       Headroom.Command.InitSpec       Headroom.Command.ReadersSpec       Headroom.Command.RunSpec-      Headroom.Configuration.CompatSpec-      Headroom.Configuration.EnrichSpec-      Headroom.ConfigurationSpec+      Headroom.Config.CompatSpec+      Headroom.Config.EnrichSpec+      Headroom.Config.GlobalSpec+      Headroom.ConfigSpec       Headroom.Data.CoerceSpec       Headroom.Data.EnumExtraSpec       Headroom.Data.RegexSpec@@ -272,12 +307,15 @@       Headroom.FileSupport.CPPSpec       Headroom.FileSupport.CSpec       Headroom.FileSupport.CSSSpec+      Headroom.FileSupport.DartSpec       Headroom.FileSupport.GoSpec       Headroom.FileSupport.Haskell.HaddockSpec       Headroom.FileSupport.HaskellSpec       Headroom.FileSupport.HTMLSpec       Headroom.FileSupport.JavaSpec       Headroom.FileSupport.JSSpec+      Headroom.FileSupport.KotlinSpec+      Headroom.FileSupport.PHPSpec       Headroom.FileSupport.PureScriptSpec       Headroom.FileSupport.RustSpec       Headroom.FileSupport.ScalaSpec@@ -287,6 +325,7 @@       Headroom.Header.SanitizeSpec       Headroom.HeaderSpec       Headroom.IO.FileSystemSpec+      Headroom.IO.KVStoreSpec       Headroom.Meta.VersionSpec       Headroom.PostProcess.TypesSpec       Headroom.PostProcess.UpdateCopyrightSpec@@ -295,8 +334,10 @@       Headroom.Template.MustacheSpec       Headroom.Template.TemplateRefSpec       Headroom.TypesSpec+      Headroom.UI.MessageSpec       Headroom.UI.ProgressSpec       Headroom.UI.TableSpec+      Headroom.UpdaterSpec       Headroom.VariablesSpec       Paths_headroom   hs-source-dirs:
src/Headroom/Command.hs view
@@ -5,7 +5,7 @@ {-| Module      : Headroom.Command Description : Support for parsing command line arguments-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -26,7 +26,7 @@                                                      , templateRefReader                                                      ) import           Headroom.Command.Types              ( Command(..) )-import           Headroom.Configuration.Types        ( LicenseType+import           Headroom.Config.Types               ( LicenseType                                                      , RunMode(..)                                                      ) import           Headroom.Data.EnumExtra             ( EnumExtra(..) )
+ src/Headroom/Command/Bootstrap.hs view
@@ -0,0 +1,142 @@+{-# LANGUAGE FlexibleContexts  #-}+{-# LANGUAGE LambdaCase        #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes       #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}++{-|+Module      : Headroom.Command.Bootstrap+Description : Logic for bootstrapping Headroom+Copyright   : (c) 2019-2022 Vaclav Svejcar+License     : BSD-3-Clause+Maintainer  : vaclav.svejcar@gmail.com+Stability   : experimental+Portability : POSIX++Logic for running shared code and bootstrapping all /Headroom/ command /RIO/+applications.+-}++module Headroom.Command.Bootstrap+  ( BootstrapEnv(..)+  , bootstrap+  , runRIO'+  , globalKVStore+  )+where++import           Data.String.Interpolate             ( iii )+import           Headroom.Config.Global              ( GlobalConfig(..)+                                                     , globalConfigPath+                                                     , initGlobalConfigIfNeeded+                                                     , loadGlobalConfig+                                                     )+import           Headroom.Data.Has                   ( Has(..)+                                                     , HasRIO+                                                     )+import           Headroom.IO.FileSystem              ( FileSystem(..) )+import           Headroom.IO.KVStore                 ( KVStore+                                                     , StorePath(..)+                                                     , sqliteKVStore+                                                     )+import           Headroom.IO.Network                 ( Network )+import           Headroom.Meta                       ( cacheFileName+                                                     , globalConfigDirName+                                                     , productInfo+                                                     , webRepo+                                                     )+import           Headroom.Meta.Version               ( Version+                                                     , printVersionP+                                                     )+import           Headroom.UI.Message                 ( messageInfo )+import           Headroom.Updater                    ( UpdaterError(..)+                                                     , checkUpdates+                                                     )+import           RIO+import           RIO.FilePath                        ( (</>) )+import qualified RIO.Text                           as T+++-- | Bootstrap environment, containing pieces shared between all commands.+data BootstrapEnv = BootstrapEnv+  { beGlobalConfig :: GlobalConfig -- ^ loaded global configuration+  }+++-- | Runs /RIO/ application using provided environment data and flag+-- whether to run in debug mode.+runRIO' :: (LogFunc -> IO env)+        -- ^ function returning environment data+        -> Bool+        -- ^ whether to run in debug mode+        -> RIO env a+        -- ^ /RIO/ application to execute+        -> IO a+        -- ^ execution result+runRIO' enfFn isDebug logic = do+  defLogOptions <- logOptionsHandle stderr isDebug+  withLogFunc (setLogUseLoc False defLogOptions) $ \logFunc -> do+    env <- liftIO $ enfFn logFunc+    runRIO env logic+++-- | Executes the initialization logic that should be performed before any other+-- code is executed. During this bootstrap, for example /global configuration/+-- is initialized and loaded, welcome message is printed to console and updates+-- are checked.+bootstrap :: ( HasRIO FileSystem env+             , HasRIO KVStore env+             , HasRIO Network env+             , HasLogFunc env+             )+          => RIO env BootstrapEnv+bootstrap = do+  welcomeMessage+  initGlobalConfigIfNeeded+  globalConfig@GlobalConfig {..} <- loadGlobalConfig+  catch (checkUpdates gcUpdates) onError >>= \case+    Nothing         -> pure ()+    Just newVersion -> displayUpdate newVersion+  pure BootstrapEnv { beGlobalConfig = globalConfig }+ where+  onError err = do+    logWarn . display . T.pack $ displayException (err :: UpdaterError)+    pure Nothing+++-- | Shared /SQLite/-based 'KVStore'.+globalKVStore :: (HasRIO FileSystem env) => RIO env (KVStore (RIO env))+globalKVStore = do+  FileSystem {..} <- viewL+  userDir         <- fsGetUserDirectory+  pure+    .   sqliteKVStore+    .   StorePath+    .   T.pack+    $   userDir+    </> globalConfigDirName+    </> cacheFileName+++------------------------------  PRIVATE FUNCTIONS  -----------------------------++welcomeMessage :: HasLogFunc env => RIO env ()+welcomeMessage = logInfo . display $ productInfo+++displayUpdate :: (HasRIO FileSystem env, HasLogFunc env)+              => Version+              -> RIO env ()+displayUpdate version = do+  configPath <- globalConfigPath+  logInfo . display . messageInfo $ message configPath+ where+  message configPath = [iii|+      New version #{printVersionP version} is available for download, you can+      get it from #{webRepo}.\n\t+      Tired of seeing this message? You can change the behaviour in global+      config file here:\n\t+      #{configPath}+    |]
src/Headroom/Command/Gen.hs view
@@ -8,7 +8,7 @@ {-| Module      : Headroom.Command.Gen Description : Handler for the @gen@ command.-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -31,11 +31,11 @@                                                      , CommandGenOptions(..)                                                      ) import           Headroom.Command.Utils              ( bootstrap )-import           Headroom.Configuration.Enrich       ( Enrich(..)+import           Headroom.Config.Enrich              ( Enrich(..)                                                      , replaceEmptyValue                                                      , withText                                                      )-import           Headroom.Configuration.Types        ( GenMode(..) )+import           Headroom.Config.Types               ( GenMode(..) ) import           Headroom.Data.Lens                  ( suffixLensesFor ) import           Headroom.Embedded                   ( configFileStub                                                      , licenseTemplate
src/Headroom/Command/Init.hs view
@@ -14,7 +14,7 @@ {-| Module      : Headroom.Command.Init Description : Handler for the @init@ command-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -37,18 +37,20 @@ import           Data.String.Interpolate             ( iii ) import           Headroom.Command.Types              ( CommandInitOptions(..) ) import           Headroom.Command.Utils              ( bootstrap )-import           Headroom.Configuration              ( makeHeadersConfig-                                                     , parseConfiguration+import           Headroom.Config                     ( makeHeadersConfig+                                                     , parseAppConfig                                                      )-import           Headroom.Configuration.Enrich       ( Enrich(..)+import           Headroom.Config.Enrich              ( Enrich(..)                                                      , replaceEmptyValue                                                      , withArray                                                      , withText                                                      )-import           Headroom.Configuration.Types        ( Configuration(..)+import           Headroom.Config.Types               ( AppConfig(..)                                                      , LicenseType(..)                                                      )-import           Headroom.Data.Has                   ( Has(..) )+import           Headroom.Data.Has                   ( Has(..)+                                                     , HasRIO+                                                     ) import           Headroom.Data.Lens                  ( suffixLenses ) import           Headroom.Embedded                   ( configFileStub                                                      , defaultConfig@@ -132,10 +134,8 @@ ------------------------------  PUBLIC FUNCTIONS  ------------------------------  -- | Handler for @init@ command.-commandInit :: CommandInitOptions-            -- ^ @init@ command options-            -> IO ()-            -- ^ execution result+commandInit :: CommandInitOptions -- ^ @init@ command options+            -> IO ()              -- ^ execution result commandInit opts = bootstrap (env' opts) False $ doesAppConfigExist >>= \case   False -> do     fileTypes <- findSupportedFileTypes@@ -153,7 +153,7 @@                        => RIO env [FileType] findSupportedFileTypes = do   opts           <- viewL-  pHeadersConfig <- cLicenseHeaders <$> parseConfiguration defaultConfig+  pHeadersConfig <- acLicenseHeaders <$> parseAppConfig defaultConfig   headersConfig  <- makeHeadersConfig pHeadersConfig   fileTypes      <- do     allFiles <- mapM (\path -> findFiles path (const True))@@ -169,10 +169,7 @@   -- | Checks whether application config file already exists.-doesAppConfigExist :: ( HasLogFunc env-                      , Has (FileSystem (RIO env)) env-                      , Has Paths env-                      )+doesAppConfigExist :: (HasLogFunc env, HasRIO FileSystem env, Has Paths env)                    => RIO env Bool doesAppConfigExist = do   FileSystem {..} <- viewL@@ -223,10 +220,7 @@     ]  -makeTemplatesDir :: ( HasLogFunc env-                    , Has (FileSystem (RIO env)) env-                    , Has Paths env-                    )+makeTemplatesDir :: (HasLogFunc env, HasRIO FileSystem env, Has Paths env)                  => RIO env () makeTemplatesDir = do   FileSystem {..} <- viewL
src/Headroom/Command/Readers.hs view
@@ -5,7 +5,7 @@ {-| Module      : Headroom.Command.Readers Description : Custom readers for /optparse-applicative/ library-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -25,7 +25,7 @@ where  import           Data.Either.Combinators             ( maybeToRight )-import           Headroom.Configuration.Types        ( LicenseType )+import           Headroom.Config.Types               ( LicenseType ) import           Headroom.Data.EnumExtra             ( EnumExtra(..) ) import           Headroom.Data.Regex                 ( Regex(..)                                                      , compile
src/Headroom/Command/Run.hs view
@@ -18,7 +18,7 @@ {-| Module      : Headroom.Command.Run Description : Handler for the @run@ command.-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -52,22 +52,27 @@                                                      , Repo(..)                                                      , findRepo                                                      )+import           Headroom.Command.Bootstrap          ( bootstrap+                                                     , globalKVStore+                                                     , runRIO'+                                                     ) import           Headroom.Command.Types              ( CommandRunOptions(..) )-import           Headroom.Command.Utils              ( bootstrap )-import           Headroom.Configuration              ( loadConfiguration-                                                     , makeConfiguration-                                                     , parseConfiguration+import           Headroom.Config                     ( loadAppConfig+                                                     , makeAppConfig+                                                     , parseAppConfig                                                      )-import           Headroom.Configuration.Types        ( Configuration(..)-                                                     , CtConfiguration+import           Headroom.Config.Types               ( AppConfig(..)+                                                     , CtAppConfig                                                      , CtPostProcessConfigs                                                      , HeaderConfig(..)                                                      , HeaderSyntax(..)-                                                     , PtConfiguration+                                                     , PtAppConfig                                                      , RunMode(..)                                                      ) import           Headroom.Data.EnumExtra             ( EnumExtra(..) )-import           Headroom.Data.Has                   ( Has(..) )+import           Headroom.Data.Has                   ( Has(..)+                                                     , HasRIO+                                                     ) import           Headroom.Data.Lens                  ( suffixLenses                                                      , suffixLensesFor                                                      )@@ -94,12 +99,12 @@                                                      , fileExtension                                                      , mkFileSystem                                                      )+import           Headroom.IO.KVStore                 ( KVStore ) import           Headroom.IO.Network                 ( Network(..)                                                      , mkNetwork                                                      ) import           Headroom.Meta                       ( TemplateType                                                      , configFileName-                                                     , productInfo                                                      ) import           Headroom.PostProcess                ( mkConfiguredEnv                                                      , postProcessHeader@@ -128,7 +133,7 @@ import qualified RIO.Text                           as T  -suffixLensesFor ["cPostProcessConfigs"] ''Configuration+suffixLensesFor ["acPostProcessConfigs"] ''AppConfig   -- | Action to be performed based on the selected 'RunMode'.@@ -140,48 +145,30 @@   }  --- | Initial /RIO/ startup environment for the /Run/ command.-data StartupEnv = StartupEnv-  { envLogFunc    :: LogFunc           -- ^ logging function-  , envRunOptions :: CommandRunOptions -- ^ options-  }--suffixLenses ''StartupEnv- -- | Full /RIO/ environment for the /Run/ command. data Env = Env-  { envEnv           :: StartupEnv           -- ^ startup /RIO/ environment-  , envConfiguration :: CtConfiguration      -- ^ application configuration+  { envLogFunc       :: LogFunc              -- ^ logging function+  , envRunOptions    :: CommandRunOptions    -- ^ options+  , envConfiguration :: ~CtAppConfig         -- ^ application configuration   , envCurrentYear   :: CurrentYear          -- ^ current year+  , envKVStore       :: ~(KVStore (RIO Env)) -- ^ key-value store   , envNetwork       :: Network (RIO Env)    -- ^ network operations   , envFileSystem    :: FileSystem (RIO Env) -- ^ file system operations   }  suffixLenses ''Env -instance Has CtConfiguration Env where+instance Has CtAppConfig Env where   hasLens = envConfigurationL  instance Has CtPostProcessConfigs Env where-  hasLens = envConfigurationL . cPostProcessConfigsL--instance Has StartupEnv StartupEnv where-  hasLens = id--instance Has StartupEnv Env where-  hasLens = envEnvL--instance HasLogFunc StartupEnv where-  logFuncL = envLogFuncL+  hasLens = envConfigurationL . acPostProcessConfigsL  instance HasLogFunc Env where-  logFuncL = hasLens @StartupEnv . logFuncL--instance Has CommandRunOptions StartupEnv where-  hasLens = envRunOptionsL+  logFuncL = envLogFuncL  instance Has CommandRunOptions Env where-  hasLens = hasLens @StartupEnv . hasLens+  hasLens = envRunOptionsL  instance Has CurrentYear Env where   hasLens = envCurrentYearL@@ -192,24 +179,34 @@ instance Has (FileSystem (RIO Env)) Env where   hasLens = envFileSystemL +instance Has (KVStore (RIO Env)) Env where+  hasLens = envKVStoreL -env' :: CommandRunOptions -> LogFunc -> IO Env-env' opts logFunc = do-  let envEnv        = StartupEnv { envLogFunc = logFunc, envRunOptions = opts }-      envNetwork    = mkNetwork-      envFileSystem = mkFileSystem-  envConfiguration <- runRIO envEnv finalConfiguration-  envCurrentYear   <- currentYear-  pure Env { .. } +getEnv :: CommandRunOptions -> LogFunc -> IO Env+getEnv opts logFunc = do+  currentYear' <- currentYear+  let env0 = Env { envLogFunc       = logFunc+                 , envRunOptions    = opts+                 , envConfiguration = undefined+                 , envCurrentYear   = currentYear'+                 , envKVStore       = undefined+                 , envNetwork       = mkNetwork+                 , envFileSystem    = mkFileSystem+                 }+  config  <- runRIO env0 finalConfiguration+  kvStore <- runRIO env0 globalKVStore+  pure env0 { envConfiguration = config, envKVStore = kvStore } + -- | Handler for /Run/ command. commandRun :: CommandRunOptions -- ^ /Run/ command options            -> IO ()             -- ^ execution result-commandRun opts = bootstrap (env' opts) (croDebug opts) $ do+commandRun opts = runRIO' (getEnv opts) (croDebug opts) $ do+  _                      <- bootstrap   CommandRunOptions {..} <- viewL-  Configuration {..}     <- viewL @CtConfiguration-  let isCheck = cRunMode == Check+  AppConfig {..}         <- viewL @CtAppConfig+  let isCheck = acRunMode == Check   warnOnDryRun   startTS            <- liftIO getPOSIXTime   templates          <- loadTemplates@@ -238,19 +235,17 @@   when croDryRun $ logWarn "[!] Running with '--dry-run', no files are changed!"  -findSourceFiles :: ( Has CtConfiguration env-                   , Has (FileSystem (RIO env)) env-                   , HasLogFunc env-                   )+findSourceFiles :: (Has CtAppConfig env, HasRIO FileSystem env, HasLogFunc env)                 => [FileType]                 -> RIO env [FilePath] findSourceFiles fileTypes = do-  Configuration {..} <- viewL-  FileSystem {..}    <- viewL-  logDebug $ "Using source paths: " <> displayShow cSourcePaths+  AppConfig {..}  <- viewL+  FileSystem {..} <- viewL+  logDebug $ "Using source paths: " <> displayShow acSourcePaths   files <--    mconcat <$> mapM (fsFindFilesByTypes cLicenseHeaders fileTypes) cSourcePaths-  notIgnored <- excludePaths cExcludedPaths <$> excludeIgnored files+    mconcat+      <$> mapM (fsFindFilesByTypes acLicenseHeaders fileTypes) acSourcePaths+  notIgnored <- excludePaths acExcludedPaths <$> excludeIgnored files   logInfo [iii|       Found #{length notIgnored} files to process       (excluded #{length files - length notIgnored})@@ -258,24 +253,21 @@   pure notIgnored  -excludeIgnored :: ( Has CtConfiguration env-                  , Has (FileSystem (RIO env)) env-                  , HasLogFunc env-                  )+excludeIgnored :: (Has CtAppConfig env, HasRIO FileSystem env, HasLogFunc env)                => [FilePath]                -> RIO env [FilePath] excludeIgnored paths = do-  Configuration {..} <- viewL @CtConfiguration-  FileSystem {..}    <- viewL-  currentDir         <- fsGetCurrentDirectory-  maybeRepo          <- ifM (pure cExcludeIgnoredPaths)-                            (findRepo' currentDir)-                            (pure Nothing)+  AppConfig {..}  <- viewL @CtAppConfig+  FileSystem {..} <- viewL+  currentDir      <- fsGetCurrentDirectory+  maybeRepo       <- ifM (pure acExcludeIgnoredPaths)+                         (findRepo' currentDir)+                         (pure Nothing)   case maybeRepo of     Just repo -> filterM (fmap not . isIgnored repo) paths     Nothing   -> pure paths  where-  findRepo' = \dir -> do+  findRepo' dir = do     logInfo "Searching for VCS repository to extract exclude patterns from..."     maybeRepo <- findRepo @_ @Git dir     case maybeRepo of@@ -286,7 +278,7 @@  processSourceFiles :: forall a env                     . ( Template a-                      , Has CtConfiguration env+                      , Has CtAppConfig env                       , Has CtPostProcessConfigs env                       , Has CommandRunOptions env                       , Has CurrentYear env@@ -296,11 +288,11 @@                    -> [FilePath]                    -> RIO env (Int, Int) processSourceFiles templates paths = do-  Configuration {..} <- viewL-  year               <- viewL+  AppConfig {..} <- viewL+  year           <- viewL   let dVars        = dynamicVariables year-      withTemplate = mapMaybe (template cLicenseHeaders) paths-  cVars     <- compileVariables @a (dVars <> cVariables)+      withTemplate = mapMaybe (template acLicenseHeaders) paths+  cVars     <- compileVariables @a (dVars <> acVariables)   processed <- mapM (process cVars dVars) (zipWithProgress withTemplate)   pure (length withTemplate, length . filter (== True) $ processed)  where@@ -312,7 +304,7 @@ processSourceFile :: forall a env                    . ( Template a                      , Has CommandRunOptions env-                     , Has CtConfiguration env+                     , Has CtAppConfig env                      , Has CtPostProcessConfigs env                      , Has CurrentYear env                      , HasLogFunc env@@ -324,7 +316,7 @@                   -> FilePath                   -> RIO env Bool processSourceFile cVars dVars progress ht@HeaderTemplate {..} path = do-  Configuration {..}     <- viewL @CtConfiguration+  AppConfig {..}         <- viewL @CtAppConfig   CommandRunOptions {..} <- viewL   fileContent            <- readFileUtf8 path   let fs                         = fileSupport htFileType@@ -339,7 +331,7 @@       changed = raProcessed && (source /= result)       message = if changed then raProcessedMsg else raSkippedMsg       logFn   = if changed then logInfo else logSticky-      isCheck = cRunMode == Check+      isCheck = acRunMode == Check   logDebug $ "Header info: " <> displayShow headerInfo   logFn $ mconcat [display progress, " ", display message, fromString path]   when (not croDryRun && not isCheck && changed)@@ -347,14 +339,11 @@   pure changed  -chooseAction :: (Has CtConfiguration env)-             => HeaderInfo-             -> Text-             -> RIO env RunAction+chooseAction :: (Has CtAppConfig env) => HeaderInfo -> Text -> RIO env RunAction chooseAction info header = do-  Configuration {..} <- viewL @CtConfiguration+  AppConfig {..} <- viewL @CtAppConfig   let hasHeader = isJust $ hiHeaderPos info-  pure $ go cRunMode hasHeader+  pure $ go acRunMode hasHeader  where   go runMode hasHeader = case runMode of     Add     -> aAction hasHeader@@ -386,8 +375,8 @@ -- of 'TemplateRef' is selected). loadTemplateRefs :: forall a env                   . ( Template a-                    , Has (Network (RIO env)) env-                    , Has (FileSystem (RIO env)) env+                    , HasRIO Network env+                    , HasRIO FileSystem env                     , HasLogFunc env                     )                  => [TemplateRef]            -- ^ template references@@ -400,37 +389,37 @@   refsWCtn   <- mapM (loadContent fileSystem network) (filterPreferred refsWTp)   M.fromList <$> mapM loadTemplate refsWCtn  where-  zipRs      = \rs -> fmap (`zip` rs) . mapM getFileType $ rs-  exts       = toList $ templateExtensions @a-  getAllRefs = \fs ref -> case ref of+  zipRs rs = fmap (`zip` rs) . mapM getFileType $ rs+  exts = toList $ templateExtensions @a+  getAllRefs fs ref = case ref of     LocalTemplateRef p -> fmap LocalTemplateRef <$> fsFindFilesByExts fs p exts     _                  -> pure [ref]-  loadContent = \fs n (ft, ref) -> (ft, ref, ) <$> case ref of+  loadContent fs n (ft, ref) = (ft, ref, ) <$> case ref of     InlineRef        content -> pure content     LocalTemplateRef path    -> fsLoadFile fs path-    UriTemplateRef   uri     -> nDownloadContent n uri+    UriTemplateRef   uri     -> decodeUtf8Lenient <$> nDownloadContent n uri     BuiltInRef lt ft'        -> pure $ licenseTemplate lt ft'-  loadTemplate = \(ft, ref, T.strip -> c) -> (ft, ) <$> parseTemplate @a ref c-  getFileType  = \case+  loadTemplate (ft, ref, T.strip -> c) = (ft, ) <$> parseTemplate @a ref c+  getFileType = \case     InlineRef _     -> pure Nothing     BuiltInRef _ ft -> pure . Just $ ft     other           -> typeOfTemplate . T.unpack . renderRef $ other-  filterPreferred rs =-    mapMaybe (L.headMaybe . L.sort) . L.groupBy (\x y -> fst x == fst y) $ rs+  filterPreferred =+    mapMaybe (L.headMaybe . L.sort) . L.groupBy (\x y -> fst x == fst y)  -loadTemplates :: ( Has CtConfiguration env-                 , Has (FileSystem (RIO env)) env-                 , Has (Network (RIO env)) env+loadTemplates :: ( Has CtAppConfig env+                 , HasRIO Network env+                 , HasRIO FileSystem env                  , HasLogFunc env                  )               => RIO env (Map FileType HeaderTemplate) loadTemplates = do-  Configuration {..} <- viewL @CtConfiguration-  let allRefs = builtInRefs cBuiltInTemplates <> cTemplateRefs+  AppConfig {..} <- viewL @CtAppConfig+  let allRefs = builtInRefs acBuiltInTemplates <> acTemplateRefs   templates <- loadTemplateRefs @TemplateType allRefs   logInfo . display . stats . M.toList $ templates-  pure $ M.mapWithKey (extractHeaderTemplate cLicenseHeaders) templates+  pure $ M.mapWithKey (extractHeaderTemplate acLicenseHeaders) templates  where   stats = Table2 . fmap     (\(ft, t) -> ([i|Using #{ft} template:|], renderRef . templateRef $ t))@@ -452,8 +441,8 @@  loadConfigurationSafe :: (HasLogFunc env)                       => FilePath-                      -> RIO env (Maybe PtConfiguration)-loadConfigurationSafe path = catch (Just <$> loadConfiguration path) onError+                      -> RIO env (Maybe PtAppConfig)+loadConfigurationSafe path = catch (Just <$> loadAppConfig path) onError  where   onError err = do     logDebug $ displayShow (err :: IOException)@@ -471,15 +460,14 @@   finalConfiguration :: (HasLogFunc env, Has CommandRunOptions env)-                   => RIO env CtConfiguration+                   => RIO env CtAppConfig finalConfiguration = do-  logInfo $ display productInfo-  defaultConfig' <- Just <$> parseConfiguration defaultConfig+  defaultConfig' <- Just <$> parseAppConfig defaultConfig   cmdLineConfig  <- Just <$> optionsToConfiguration   yamlConfig     <- loadConfigurationSafe configFileName   let mergedConfig =         mconcat . catMaybes $ [defaultConfig', yamlConfig, cmdLineConfig]-  config <- makeConfiguration mergedConfig+  config <- makeAppConfig mergedConfig   logDebug $ "Default config: " <> displayShow defaultConfig'   logDebug $ "YAML config: " <> displayShow yamlConfig   logDebug $ "CmdLine config: " <> displayShow cmdLineConfig@@ -488,20 +476,20 @@   pure config  -optionsToConfiguration :: (Has CommandRunOptions env) => RIO env PtConfiguration+optionsToConfiguration :: (Has CommandRunOptions env) => RIO env PtAppConfig optionsToConfiguration = do   CommandRunOptions {..} <- viewL   variables              <- parseVariables croVariables-  pure Configuration-    { cRunMode             = maybe mempty pure croRunMode-    , cSourcePaths         = ifNot null croSourcePaths-    , cExcludedPaths       = ifNot null croExcludedPaths-    , cExcludeIgnoredPaths = ifNot (== False) croExcludeIgnoredPaths-    , cBuiltInTemplates    = pure croBuiltInTemplates-    , cTemplateRefs        = croTemplateRefs-    , cVariables           = variables-    , cLicenseHeaders      = mempty-    , cPostProcessConfigs  = mempty+  pure AppConfig+    { acRunMode             = maybe mempty pure croRunMode+    , acSourcePaths         = ifNot null croSourcePaths+    , acExcludedPaths       = ifNot null croExcludedPaths+    , acExcludeIgnoredPaths = ifNot (== False) croExcludeIgnoredPaths+    , acBuiltInTemplates    = pure croBuiltInTemplates+    , acTemplateRefs        = croTemplateRefs+    , acVariables           = variables+    , acLicenseHeaders      = mempty+    , acPostProcessConfigs  = mempty     }   where ifNot cond value = if cond value then mempty else pure value 
src/Headroom/Command/Types.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.Command.Types Description : Data types for "Headroom.Command"-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -21,7 +21,7 @@   ) where -import           Headroom.Configuration.Types        ( GenMode+import           Headroom.Config.Types               ( GenMode                                                      , LicenseType                                                      , RunMode                                                      )
src/Headroom/Command/Utils.hs view
@@ -3,7 +3,7 @@ {-| Module      : Headroom.Command.Utils Description : Shared code for individual command handlers-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
+ src/Headroom/Config.hs view
@@ -0,0 +1,184 @@+{-# LANGUAGE DataKinds         #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE TemplateHaskell   #-}++{-|+Module      : Headroom.Config+Description : Configuration handling (loading, parsing, validating)+Copyright   : (c) 2019-2022 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.Config+  ( -- * Loading & Parsing Configuration+    loadAppConfig+  , parseAppConfig+    -- * Processing Partial Configuration+  , makeAppConfig+  , makeHeadersConfig+  , makeHeaderConfig+  )+where++import           Data.Monoid                         ( Last(..) )+import qualified Data.Yaml                          as Y+import           Headroom.Config.Compat              ( checkCompatibility )+import           Headroom.Config.Types               ( AppConfig(..)+                                                     , ConfigurationError(..)+                                                     , ConfigurationKey(..)+                                                     , CtAppConfig+                                                     , CtHeaderConfig+                                                     , CtHeadersConfig+                                                     , CtPostProcessConfig+                                                     , CtPostProcessConfigs+                                                     , CtUpdateCopyrightConfig+                                                     , HeaderConfig(..)+                                                     , HeadersConfig(..)+                                                     , Phase(..)+                                                     , PostProcessConfig(..)+                                                     , PostProcessConfigs(..)+                                                     , PtAppConfig+                                                     , PtHeaderConfig+                                                     , PtHeadersConfig+                                                     , PtPostProcessConfig+                                                     , PtPostProcessConfigs+                                                     , PtUpdateCopyrightConfig+                                                     , UpdateCopyrightConfig(..)+                                                     )+import           Headroom.Data.Lens                  ( suffixLenses )+import           Headroom.FileType.Types             ( FileType(..) )+import           Headroom.Meta                       ( buildVersion+                                                     , configBreakingChanges+                                                     )+import           RIO+import qualified RIO.ByteString                     as B+++suffixLenses ''PostProcessConfig+suffixLenses ''PostProcessConfigs+suffixLenses ''UpdateCopyrightConfig+++------------------------------  PUBLIC FUNCTIONS  ------------------------------++-- | Loads and parses application configuration from given /YAML/ file.+loadAppConfig :: (MonadIO m, MonadThrow m) => FilePath -> m PtAppConfig+loadAppConfig path = do+  content <- liftIO $ B.readFile path+  _       <- checkCompatibility configBreakingChanges buildVersion content+  parseAppConfig content+++-- | Parses application configuration from given raw input in /YAML/ format.+parseAppConfig :: MonadThrow m+               => ByteString    -- ^ raw input to parse+               -> m PtAppConfig -- ^ parsed application configuration+parseAppConfig = Y.decodeThrow+++-- | Makes full 'CtAppConfig' from provided 'PtAppConfig' (if valid).+makeAppConfig :: MonadThrow m+              => PtAppConfig   -- ^ source 'PtAppConfig'+              -> m CtAppConfig -- ^ full 'CtAppConfig'+makeAppConfig pt = do+  acRunMode             <- lastOrError CkRunMode (acRunMode pt)+  acSourcePaths         <- lastOrError CkSourcePaths (acSourcePaths pt)+  acExcludedPaths       <- lastOrError CkExcludedPaths (acExcludedPaths pt)+  acExcludeIgnoredPaths <- lastOrError CkExcludeIgnoredPaths+                                       (acExcludeIgnoredPaths pt)+  acBuiltInTemplates   <- lastOrError CkBuiltInTemplates (acBuiltInTemplates pt)+  acTemplateRefs       <- pure $ acTemplateRefs pt+  acLicenseHeaders     <- makeHeadersConfig (acLicenseHeaders pt)+  acPostProcessConfigs <- makePostProcessConfigs (acPostProcessConfigs pt)+  acVariables          <- pure $ acVariables pt+  pure AppConfig { .. }+++-- | 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)+  hscDart       <- makeHeaderConfig Dart (hscDart pt)+  hscGo         <- makeHeaderConfig Go (hscGo pt)+  hscHaskell    <- makeHeaderConfig Haskell (hscHaskell pt)+  hscHtml       <- makeHeaderConfig HTML (hscHtml pt)+  hscJava       <- makeHeaderConfig Java (hscJava pt)+  hscJs         <- makeHeaderConfig JS (hscJs pt)+  hscKotlin     <- makeHeaderConfig Kotlin (hscKotlin pt)+  hscPhp        <- makeHeaderConfig PHP (hscPhp 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 file type of configuration+                 -> PtHeaderConfig   -- ^ source 'PtHeaderConfig'+                 -> m CtHeaderConfig -- ^ full 'CtHeaderConfig'+makeHeaderConfig fileType pt = do+  hcFileExtensions <- lastOrError (CkFileExtensions fileType)+                                  (hcFileExtensions pt)+  hcMarginTopCode <- lastOrError (CkMarginTopCode fileType) (hcMarginTopCode pt)+  hcMarginTopFile <- lastOrError (CkMarginTopFile fileType) (hcMarginTopFile pt)+  hcMarginBottomCode <- lastOrError (CkMarginBottomCode fileType)+                                    (hcMarginBottomCode pt)+  hcMarginBottomFile <- lastOrError (CkMarginBottomFile fileType)+                                    (hcMarginBottomFile pt)+  hcPutAfter     <- lastOrError (CkPutAfter fileType) (hcPutAfter pt)+  hcPutBefore    <- lastOrError (CkPutBefore fileType) (hcPutBefore pt)+  hcHeaderSyntax <- lastOrError (CkHeaderSyntax fileType) (hcHeaderSyntax pt)+  pure HeaderConfig { .. }+++------------------------------  PRIVATE FUNCTIONS  -----------------------------++makePostProcessConfigs :: MonadThrow m+                       => PtPostProcessConfigs+                       -> m CtPostProcessConfigs+makePostProcessConfigs pt = do+  ppcsUpdateCopyright <- makePostProcessConfig (pt ^. ppcsUpdateCopyrightL)+                                               makeUpdateCopyrightConfig+  pure PostProcessConfigs { .. }+++makePostProcessConfig :: MonadThrow m+                      => PtPostProcessConfig c+                      -> (c 'Partial -> m (c 'Complete))+                      -> m (CtPostProcessConfig c)+makePostProcessConfig pt fn = do+  ppcEnabled <- lastOrError CkEnabled (pt ^. ppcEnabledL)+  ppcConfig  <- fn $ pt ^. ppcConfigL+  pure PostProcessConfig { .. }+++makeUpdateCopyrightConfig :: MonadThrow m+                          => PtUpdateCopyrightConfig+                          -> m CtUpdateCopyrightConfig+makeUpdateCopyrightConfig pt = do+  let uccSelectedAuthors = lastOrNothing $ pt ^. uccSelectedAuthorsL+  pure UpdateCopyrightConfig { .. }+++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
+ src/Headroom/Config/Compat.hs view
@@ -0,0 +1,139 @@+{-# LANGUAGE LambdaCase        #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes       #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}++{-|+Module      : Headroom.Config.Compat+Description : Compatibility checks for YAML configuration+Copyright   : (c) 2019-2022 Vaclav Svejcar+License     : BSD-3-Clause+Maintainer  : vaclav.svejcar@gmail.com+Stability   : experimental+Portability : POSIX++This module contains functions and data types used for checking compatibility of+user's YAML configuration with current version of Headroom.+-}++module Headroom.Config.Compat+  ( VersionError(..)+  , checkCompatibility+  )+where++import           Data.Aeson                          ( FromJSON(..)+                                                     , withObject+                                                     , (.:)+                                                     )+import           Data.String.Interpolate             ( iii )+import qualified Data.Yaml                          as Y+import           Headroom.Meta                       ( buildVersion+                                                     , configFileName+                                                     , productName+                                                     , webDocMigration+                                                     )+import           Headroom.Meta.Version               ( Version(..)+                                                     , printVersionP+                                                     , pvp+                                                     )+import           Headroom.Types                      ( fromHeadroomError+                                                     , toHeadroomError+                                                     )+import           RIO+import qualified RIO.List                           as L+++---------------------------------  DATA TYPES  ---------------------------------++newtype VersionObj = VersionObj Version deriving (Eq, Show)++instance FromJSON VersionObj where+  parseJSON = withObject "VersionObj" $ \obj -> do+    version <- obj .: "version"+    pure $ VersionObj version+++---------------------------------  ERROR TYPES  --------------------------------++-- | Exception specific to the "Headroom.Configuration.Compat" module.+data VersionError+  = CannotParseVersion+  -- ^ cannot parse version info from given YAML configuration+  | NewerVersionDetected Version+  -- ^ configuration has newer version than Headroom+  | UnsupportedVersion [Version] Version+  -- ^ given YAML configuration is not compatible+  deriving (Eq, Show)+++instance Exception VersionError where+  displayException = displayException'+  toException      = toHeadroomError+  fromException    = fromHeadroomError+++------------------------------  PUBLIC FUNCTIONS  ------------------------------++-- | Checks whether the given not yet parsed YAML configuration is compatible,+-- using list of versions that caused breaking changes into configuration.+checkCompatibility :: MonadThrow m+                   => [Version]+                   -- ^ list of versions with breaking changes in configuration+                   -> Version+                   -- ^ current Headroom version+                   -> ByteString+                   -- ^ raw, not yet parsed YAML configuration+                   -> m Version+                   -- ^ detected compatible version or error+checkCompatibility breakingVersions current raw = do+  VersionObj version <- parseObj+  _                  <- checkBreakingChanges breakingVersions version+  _                  <- checkNewerVersion current version+  pure version+ where+  parseObj = either (const . throwM $ CannotParseVersion) pure decoded+  decoded  = Y.decodeEither' raw+++------------------------------  PRIVATE FUNCTIONS  -----------------------------++checkBreakingChanges :: MonadThrow m => [Version] -> Version -> m ()+checkBreakingChanges vs v = case L.filter (v <) . L.sort $ vs of+  []    -> pure ()+  newer -> throwM $ UnsupportedVersion newer v+++checkNewerVersion :: MonadThrow m => Version -> Version -> m ()+checkNewerVersion current checked =+  if current < checked then throwM $ NewerVersionDetected checked else pure ()+++displayException' :: VersionError -> String+displayException' = \case+  CannotParseVersion -> [iii|+      Cannot find 'version' key in #{configFileName :: String} configuration+      file. This field is required to check whether your current configuration+      is compatible with installed version of #{productName}. This functionality+      has been added in version 0.4.0.0, please see following migration guide+      for more details on how to proceed:+      #{"\n\t" <> webDocMigration v0400}+    |]+  NewerVersionDetected version -> [iii|+      The version set in your #{configFileName :: String} configuration file+      (#{printVersionP version}) is newer than version of installed+      #{productName} (#{printVersionP buildVersion}). Please upgrade+      #{productName} first.+    |]+  UnsupportedVersion versions version -> [iii|+      Your #{configFileName :: String} configuration file has version+      #{printVersionP version}, which is incompatible with current version of+      #{productName} (#{printVersionP buildVersion}). Please perform steps+      described in these migration guides first (in given order):+      #{migrationGuides versions}+    |]+ where+  v0400           = [pvp|0.4.0.0|]+  migrationGuides = mconcat . fmap (\v -> "\n\t- " <> webDocMigration v)
+ src/Headroom/Config/Enrich.hs view
@@ -0,0 +1,111 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE StrictData        #-}++{-|+Module      : Headroom.Config.Enrich+Description : Simple enrichment of YAML configuration stubs+Copyright   : (c) 2019-2022 Vaclav Svejcar+License     : BSD-3-Clause+Maintainer  : vaclav.svejcar@gmail.com+Stability   : experimental+Portability : POSIX++This module contains mini-DSL for enrichment of generated /YAML/ configurations,+i.e. replacing default values with real ones, etc. This is intentionally done+without the "Data.Yaml" and parsing, because that way all comments inside YAML+file would be lost.+-}++module Headroom.Config.Enrich+  ( -- * Data Types+    Enrich(..)+  , ValueType(..)+    -- * Field Generators+  , withArray+  , withText+    -- * Field Manipulation+  , replaceEmptyValue+  )+where++import           Data.Aeson                          ( ToJSON(..) )+import           Headroom.Data.Serialization         ( prettyPrintYAML )+import           RIO+import qualified RIO.Map                            as M+import qualified RIO.Text                           as T+import qualified RIO.Text.Partial                   as TP+++---------------------------------  DATA TYPES  ---------------------------------++-- | Simple wrapper representing single step of enrichment.+newtype Enrich = Enrich+  { enrich :: Text -> Text+  -- ^ takes input text and does enrichment+  }+++instance Semigroup Enrich where+  Enrich fnA <> Enrich fnB = Enrich $ fnA . fnB+++instance Monoid Enrich where+  mempty = Enrich id+++-- | Represents type of the field value.+data ValueType+  = Array+  -- ^ type of /YAML/ array+  | String+  -- ^ type of /YAML/ string+  deriving (Eq, Show)+++------------------------------  PUBLIC FUNCTIONS  ------------------------------++-- | Generates /YAML/ array field from given list and field name.+withArray :: ToJSON a+          => [a]+          -- ^ input list used as value+          -> Text+          -- ^ field name+          -> (ValueType, Text)+          -- ^ generated fields as @(valueType, generatedField)@+withArray list field = (Array, asYAML field list)+++-- | Generates /YAML/ string from given text value and field name.+withText :: Text+         -- ^ input text value+         -> Text+         -- ^ field name+         -> (ValueType, Text)+         -- ^ generated fields as @(valueType, generatedField)@+withText text field = (String, asYAML field text)+++-- | Replaces empty value of given field with actual generated value.+replaceEmptyValue :: Text+                  -- ^ field name+                  -> (Text -> (ValueType, Text))+                  -- ^ field value generator function+                  -> Enrich+                  -- ^ resulting enrichment step+replaceEmptyValue field replaceFn = Enrich $ \doc -> do+  TP.replace old new doc+ where+  (tpe, new) = replaceFn field+  old        = field <> ": " <> emptyValue tpe+++------------------------------  PRIVATE FUNCTIONS  -----------------------------++asYAML :: ToJSON a => Text -> a -> Text+asYAML field value = T.stripEnd . prettyPrintYAML $ M.fromList [(field, value)]+++emptyValue :: ValueType -> Text+emptyValue Array  = "[]"+emptyValue String = "\"\""
+ src/Headroom/Config/Global.hs view
@@ -0,0 +1,102 @@+{-# LANGUAGE DeriveGeneric     #-}+{-# LANGUAGE FlexibleContexts  #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE StrictData        #-}++{-|+Module      : Headroom.Config.Global+Description : Global configutation+Copyright   : (c) 2019-2022 Vaclav Svejcar+License     : BSD-3-Clause+Maintainer  : vaclav.svejcar@gmail.com+Stability   : experimental+Portability : POSIX++/Global configuration/ is configuration shared between all /Headroom/ instances+and it's located in user's home directory.+-}++module Headroom.Config.Global+  ( GlobalConfig(..)+  , UpdaterConfig(..)+  , initGlobalConfigIfNeeded+  , loadGlobalConfig+  , parseGlobalConfig+  , globalConfigPath+  )+where++import           Data.Aeson                          ( FromJSON(..)+                                                     , genericParseJSON+                                                     )+import qualified Data.Yaml                          as Y+import           Headroom.Data.Has                   ( Has(..)+                                                     , HasRIO+                                                     )+import           Headroom.Data.Serialization         ( aesonOptions )+import           Headroom.Embedded                   ( defaultGlobalConfig )+import           Headroom.IO.FileSystem              ( FileSystem(..) )+import           Headroom.Meta                       ( globalConfigDirName+                                                     , globalConfigFileName+                                                     )+import           RIO+import qualified RIO.ByteString                     as B+import           RIO.FilePath                        ( (</>) )+++---------------------------------  DATA TYPES  ---------------------------------++-- | Data type representing updater configuration.+data UpdaterConfig = UpdaterConfig+  { ucCheckForUpdates    :: Bool    -- ^ whether to check for updates+  , ucUpdateIntervalDays :: Integer -- ^ how ofter check for updates+  }+  deriving (Eq, Generic, Show)++instance FromJSON UpdaterConfig where+  parseJSON = genericParseJSON aesonOptions++-- | Data type representing global configuration options.+data GlobalConfig = GlobalConfig+  { gcUpdates :: UpdaterConfig -- ^ config for updater+  }+  deriving (Eq, Generic, Show)++instance FromJSON GlobalConfig where+  parseJSON = genericParseJSON aesonOptions+++------------------------------  PUBLIC FUNCTIONS  ------------------------------++-- | Checks if global configuration /YAML/ file is already present and if not,+-- it creates one with default values.+initGlobalConfigIfNeeded :: (HasRIO FileSystem env) => RIO env ()+initGlobalConfigIfNeeded = do+  FileSystem {..} <- viewL+  userDir         <- fsGetUserDirectory+  configPath      <- globalConfigPath+  whenM (not <$> fsDoesFileExist configPath) $ do+    fsCreateDirectory $ userDir </> globalConfigDirName+    fsWriteFile configPath defaultGlobalConfig+++-- | Loads global configuration from /YAML/ file.+loadGlobalConfig :: (HasRIO FileSystem env) => RIO env GlobalConfig+loadGlobalConfig = do+  configPath <- globalConfigPath+  content    <- liftIO . B.readFile $ configPath+  Y.decodeThrow content+++-- | Parses global configuration /YAML/ file.+parseGlobalConfig :: (MonadThrow m) => ByteString -> m GlobalConfig+parseGlobalConfig = Y.decodeThrow+++-- | Path to global configuration /YAML/ file in user's directory.+globalConfigPath :: HasRIO FileSystem env => RIO env FilePath+globalConfigPath = do+  FileSystem {..} <- viewL+  userDir         <- fsGetUserDirectory+  pure $ userDir </> globalConfigDirName </> globalConfigFileName
+ src/Headroom/Config/Types.hs view
@@ -0,0 +1,579 @@+{-# LANGUAGE DataKinds            #-}+{-# LANGUAGE DeriveAnyClass       #-}+{-# LANGUAGE DeriveGeneric        #-}+{-# LANGUAGE DerivingVia          #-}+{-# LANGUAGE FlexibleContexts     #-}+{-# LANGUAGE FlexibleInstances    #-}+{-# LANGUAGE LambdaCase           #-}+{-# LANGUAGE NoImplicitPrelude    #-}+{-# LANGUAGE OverloadedStrings    #-}+{-# LANGUAGE QuasiQuotes          #-}+{-# LANGUAGE RecordWildCards      #-}+{-# LANGUAGE StandaloneDeriving   #-}+{-# LANGUAGE StrictData           #-}+{-# LANGUAGE TypeFamilies         #-}+{-# LANGUAGE TypeOperators        #-}+{-# LANGUAGE UndecidableInstances #-}++{-|+Module      : Headroom.Config.Types+Description : Data types for /Headroom/ configuration+Copyright   : (c) 2019-2022 Vaclav Svejcar+License     : BSD-3-Clause+Maintainer  : vaclav.svejcar@gmail.com+Stability   : experimental+Portability : POSIX++This module contains data types representing /Headroom/ configuration options.+Related logic is available in "Headroom.Configuration" module.++Data types related to /Headroom/ configuration uses the+<https://medium.com/@jonathangfischoff/the-partial-options-monoid-pattern-31914a71fc67 partial options monoid>+pattern, but instead of defining separate data type for each /phase/+(/partial/ or /complete/ configuration), the /phase/ is expressed by the 'Phase'+data type and related /closed type family/.+-}++module Headroom.Config.Types+  ( -- * Error Types+    ConfigurationError(..)+  , ConfigurationKey(..)+    -- * Type Families+  , Phase(..)+  , (:::)+    -- * Data Types+    -- ** Top Level Configuration+  , AppConfig(..)+  , CtAppConfig+  , PtAppConfig+  , HeadersConfig(..)+  , CtHeadersConfig+  , PtHeadersConfig+  , HeaderConfig(..)+  , CtHeaderConfig+  , PtHeaderConfig+    -- ** Header Functions+  , CtUpdateCopyrightConfig+  , PtUpdateCopyrightConfig+  , UpdateCopyrightConfig(..)+  , CtPostProcessConfig+  , PtPostProcessConfig+  , PostProcessConfig(..)+  , CtPostProcessConfigs+  , PtPostProcessConfigs+  , PostProcessConfigs(..)+    -- ** Additional Data Types+  , HeaderSyntax(..)+  , GenMode(..)+  , LicenseType(..)+  , RunMode(..)+  )+where++import           Control.Exception                   ( throw )+import           Data.Aeson                          ( FromJSON(..)+                                                     , Value(String)+                                                     , genericParseJSON+                                                     , withObject+                                                     , (.!=)+                                                     , (.:?)+                                                     )+import           Data.Monoid                         ( Last(..) )+import           Data.String.Interpolate             ( i+                                                     , iii+                                                     )+import           Generic.Data                        ( Generically(..) )+import           Headroom.Data.Regex                 ( Regex(..) )+import           Headroom.Data.Serialization         ( aesonOptions )+import           Headroom.FileType.Types             ( FileType )+import           Headroom.Meta                       ( webDocConfigCurr )+import           Headroom.Template.TemplateRef       ( TemplateRef )+import           Headroom.Types                      ( LicenseType(..)+                                                     , fromHeadroomError+                                                     , toHeadroomError+                                                     )+import           Headroom.Variables.Types            ( Variables(..) )+import           RIO+import qualified RIO.Text                           as T+++------------------------------------  Phase  -----------------------------------++-- | Data type representing state of given configuration data type.+data Phase+  = Partial+  -- ^ partial configuration, could be combined with another or validated to+  -- produce the complete configuration+  | Complete+  -- ^ complete configuration, result of combining and validation of partial+  -- configuration+++-- | /Closed type family/ used to express the phase of given data type.+type family (p :: Phase) ::: a where+  'Partial  ::: a = Last a+  'Complete ::: a = a+++--------------------------------  HeaderSyntax  --------------------------------++-- | Syntax of the license header comment.+data HeaderSyntax+  = BlockComment Regex Regex (Maybe Text)+  -- ^ block (multi-line) comment syntax (e.g. @/* */@)+  | LineComment Regex (Maybe Text)+  -- ^ single line comment syntax (e.g. @//@)+  deriving (Eq, Show)++-- | Internal representation of the block style of 'HeaderSyntax'.+data BlockComment' = BlockComment'+  { bcStartsWith :: Regex+  -- ^ starting pattern (e.g. @/*@)+  , bcEndsWith   :: Regex+  -- ^ ending pattern (e.g. @*/@)+  }+  deriving (Eq, Generic, Show)++instance FromJSON BlockComment' where+  parseJSON = genericParseJSON aesonOptions++-- | Internal representation of the line style of 'HeaderSyntax'.+newtype LineComment' = LineComment'+  { lcPrefixedBy :: Regex+  -- ^ prefix of the comment line (e.g. @//@)+  }+  deriving (Eq, Generic, Show)++instance FromJSON LineComment' where+  parseJSON = genericParseJSON aesonOptions+++-----------------------------------  RunMode  ----------------------------------++-- | Represents what action should the @run@ command perform.+data RunMode+  = Add+  -- ^ /add mode/ for @run@ command+  | Check+  -- ^ /check mode/ for @run@ command+  | Drop+  -- ^ /drop mode/ for @run@ command+  | Replace+  -- ^ /replace mode/ for @run@ command+  deriving (Eq, Show)++instance FromJSON RunMode where+  parseJSON = \case+    String s -> case T.toLower s of+      "add"     -> pure Add+      "check"   -> pure Check+      "drop"    -> pure Drop+      "replace" -> pure Replace+      _         -> error $ "Unknown run mode: " <> T.unpack s+    other -> error $ "Invalid value for run mode: " <> show other+++-----------------------------------  GenMode  ----------------------------------++-- | Represents what action should the @gen@ command perform.+data GenMode+  = GenConfigFile+  -- ^ generate /YAML/ config file stub+  | GenLicense (LicenseType, FileType)+  -- ^ generate license header template+  deriving (Eq, Show)+++----------------------------  UpdateCopyrightConfig  ---------------------------++-- | Main configuration for the "Headroom.PostProcess.UpdateCopyright"+-- /post-processor/.+data UpdateCopyrightConfig (p :: Phase) = UpdateCopyrightConfig+  { uccSelectedAuthors :: p ::: Maybe (NonEmpty Text)+  -- ^ if specified, years will be updated only in copyright statements of+  -- given authors+  }++-- | Alias for complete variant of 'UpdateCopyrightConfig'.+type CtUpdateCopyrightConfig = UpdateCopyrightConfig 'Complete++-- | Alias for partial variant of 'UpdateCopyrightConfig'.+type PtUpdateCopyrightConfig = UpdateCopyrightConfig 'Partial++deriving instance Eq CtUpdateCopyrightConfig+deriving instance Eq PtUpdateCopyrightConfig+deriving instance Show CtUpdateCopyrightConfig+deriving instance Show PtUpdateCopyrightConfig+deriving instance Generic PtUpdateCopyrightConfig++deriving via (Generically PtUpdateCopyrightConfig)+         instance Semigroup PtUpdateCopyrightConfig+deriving via (Generically PtUpdateCopyrightConfig)+         instance Monoid PtUpdateCopyrightConfig++instance FromJSON PtUpdateCopyrightConfig where+  parseJSON = withObject "PtUpdateCopyrightConfig" $ \obj -> do+    uccSelectedAuthors <- Last <$> obj .:? "selected-authors-only"+    pure UpdateCopyrightConfig { .. }++-------------------------------  PostProcessConfig  -------------------------------++-- | Configuration for selected /post-processor/.+data PostProcessConfig (p :: Phase) c = PostProcessConfig+  { ppcEnabled :: p ::: Bool -- ^ whether this function is enabled or not+  , ppcConfig  :: c p        -- ^ custom configuration of the /post-processor/+  }++-- | Alias for complete variant of 'PostProcessConfig'.+type CtPostProcessConfig c = PostProcessConfig 'Complete c++-- | Alias for partial variant of 'PostProcessConfig'.+type PtPostProcessConfig c = PostProcessConfig 'Partial c+++deriving instance (Eq (c 'Complete)) => Eq (CtPostProcessConfig c)+deriving instance (Eq (c 'Partial)) => Eq (PtPostProcessConfig c)+deriving instance (Show (c 'Complete)) => Show (CtPostProcessConfig c)+deriving instance (Show (c 'Partial)) => Show (PtPostProcessConfig c)+deriving instance Generic (PtPostProcessConfig c)++deriving via (Generically (PtPostProcessConfig c))+         instance Semigroup (c 'Partial) => Semigroup (PtPostProcessConfig c)+deriving via (Generically (PtPostProcessConfig c))+         instance Monoid (c 'Partial) => Monoid (PtPostProcessConfig c)++instance (FromJSON (c 'Partial), Monoid (c 'Partial)) => FromJSON (PtPostProcessConfig c) where+  parseJSON = withObject "PtPostProcessConfig" $ \obj -> do+    ppcEnabled <- Last <$> obj .:? "enabled"+    ppcConfig  <- obj .:? "config" .!= mempty+    pure PostProcessConfig { .. }+++-------------------------------  PostProcessConfigs  ------------------------------++-- | Configuration of all known /post-processors/.+data PostProcessConfigs (p :: Phase) = PostProcessConfigs+  { ppcsUpdateCopyright :: PostProcessConfig p UpdateCopyrightConfig+  -- ^ configuration for the "Headroom.PostProcess.UpdateCopyright"+  }++-- | Alias for complete variant of 'PostProcessConfigs'.+type CtPostProcessConfigs = PostProcessConfigs 'Complete++-- | Alias for partial variant of 'PostProcessConfigs'.+type PtPostProcessConfigs = PostProcessConfigs 'Partial++deriving instance Eq CtPostProcessConfigs+deriving instance Eq PtPostProcessConfigs+deriving instance Show CtPostProcessConfigs+deriving instance Show PtPostProcessConfigs+deriving instance Generic PtPostProcessConfigs++deriving via (Generically PtPostProcessConfigs)+         instance Semigroup PtPostProcessConfigs+deriving via (Generically PtPostProcessConfigs)+         instance Monoid PtPostProcessConfigs++instance FromJSON PtPostProcessConfigs where+  parseJSON = withObject "PtPostProcessConfigs" $ \obj -> do+    ppcsUpdateCopyright <- obj .:? "update-copyright" .!= mempty+    pure PostProcessConfigs { .. }+++--------------------------------  Configuration  -------------------------------++-- | Application configuration.+data AppConfig (p :: Phase) = AppConfig+  { acRunMode             :: p ::: RunMode+  -- ^ mode of the @run@ command+  , acSourcePaths         :: p ::: [FilePath]+  -- ^ paths to source code files+  , acExcludedPaths       :: p ::: [Regex]+  -- ^ excluded source paths+  , acExcludeIgnoredPaths :: p ::: Bool+  -- ^ whether to exclude paths ignored by VCS+  , acBuiltInTemplates    :: p ::: Maybe LicenseType+  -- ^ used built-in templates+  , acTemplateRefs        :: [TemplateRef]+  -- ^ template references+  , acVariables           :: Variables+  -- ^ variable values for templates+  , acLicenseHeaders      :: HeadersConfig p+  -- ^ configuration of license headers+  , acPostProcessConfigs  :: PostProcessConfigs p+  -- ^ configuration of post-processors+  }++-- | Alias for complete variant of 'AppConfig'.+type CtAppConfig = AppConfig 'Complete++-- | Alias for partial variant of 'AppConfig'.+type PtAppConfig = AppConfig 'Partial++deriving instance Eq CtAppConfig+deriving instance Eq PtAppConfig+deriving instance Show CtAppConfig+deriving instance Show PtAppConfig+deriving instance Generic PtAppConfig++deriving via (Generically PtAppConfig)+         instance Semigroup PtAppConfig+deriving via (Generically PtAppConfig)+         instance Monoid PtAppConfig+++instance FromJSON PtAppConfig where+  parseJSON = withObject "PtAppConfig" $ \obj -> do+    acRunMode             <- Last <$> obj .:? "run-mode"+    acSourcePaths         <- Last <$> obj .:? "source-paths"+    acExcludedPaths       <- Last <$> obj .:? "excluded-paths"+    acExcludeIgnoredPaths <- Last <$> obj .:? "exclude-ignored-paths"+    acBuiltInTemplates    <- Last <$> obj .:? "builtin-templates"+    acTemplateRefs        <- obj .:? "template-paths" .!= mempty+    acVariables           <- Variables <$> obj .:? "variables" .!= mempty+    acLicenseHeaders      <- obj .:? "license-headers" .!= mempty+    acPostProcessConfigs  <- obj .:? "post-process" .!= mempty+    pure AppConfig { .. }+++--------------------------------  HeaderConfig  --------------------------------++-- | Configuration for specific license header.+data HeaderConfig (p :: Phase) = HeaderConfig+  { hcFileExtensions   :: p ::: [Text]+  -- ^ list of file extensions (without dot)+  , hcMarginTopCode    :: p ::: Int+  -- ^ margin between header top and preceding code (if present)+  , hcMarginTopFile    :: p ::: Int+  -- ^ margin between header top and start of file (if no code is between)+  , hcMarginBottomCode :: p ::: Int+  -- ^ margin between header bottom and following code (if present)+  , hcMarginBottomFile :: p ::: Int+  -- ^ margin between header bottom and end of file (if no code is between)+  , hcPutAfter         :: p ::: [Regex]+  -- ^ /regexp/ patterns after which to put the header+  , hcPutBefore        :: p ::: [Regex]+  -- ^ /regexp/ patterns before which to put the header+  , hcHeaderSyntax     :: p ::: HeaderSyntax+  -- ^ syntax of the license header comment+  }++-- | Alias for complete variant of 'HeaderConfig'.+type CtHeaderConfig = HeaderConfig 'Complete++-- | Alias for partial variant of 'HeaderConfig'.+type PtHeaderConfig = HeaderConfig 'Partial++deriving instance Eq CtHeaderConfig+deriving instance Eq PtHeaderConfig+deriving instance Show CtHeaderConfig+deriving instance Show PtHeaderConfig+deriving instance Generic PtHeaderConfig++deriving via (Generically PtHeaderConfig)+         instance Semigroup PtHeaderConfig+deriving via (Generically PtHeaderConfig)+         instance Monoid PtHeaderConfig++instance FromJSON PtHeaderConfig where+  parseJSON = withObject "PartialHeaderConfig" $ \obj -> do+    hcFileExtensions   <- Last <$> obj .:? "file-extensions"+    hcMarginTopCode    <- Last <$> obj .:? "margin-top-code"+    hcMarginTopFile    <- Last <$> obj .:? "margin-top-file"+    hcMarginBottomCode <- Last <$> obj .:? "margin-bottom-code"+    hcMarginBottomFile <- Last <$> obj .:? "margin-bottom-file"+    hcPutAfter         <- Last <$> obj .:? "put-after"+    hcPutBefore        <- Last <$> obj .:? "put-before"+    blockComment       <- obj .:? "block-comment"+    lineComment        <- obj .:? "line-comment"+    hcHeaderSyntax     <- pure . Last $ syntax blockComment lineComment+    pure HeaderConfig { .. }+   where+    syntax (Just (BlockComment' s e)) Nothing = Just $ BlockComment s e Nothing+    syntax Nothing (Just (LineComment' p)) = Just $ LineComment p Nothing+    syntax Nothing Nothing = Nothing+    syntax _ _ = throw MixedHeaderSyntax++--------------------------------  HeadersConfig  -------------------------------++-- | Group of 'HeaderConfig' configurations for supported file types.+data HeadersConfig (p :: Phase) = HeadersConfig+  { hscC          :: HeaderConfig p -- ^ configuration for /C/+  , hscCpp        :: HeaderConfig p -- ^ configuration for /C++/+  , hscCss        :: HeaderConfig p -- ^ configuration for /CSS/+  , hscDart       :: HeaderConfig p -- ^ configuration for /Dart/+  , hscGo         :: HeaderConfig p -- ^ configuration for /Go/+  , hscHaskell    :: HeaderConfig p -- ^ configuration for /Haskell/+  , hscHtml       :: HeaderConfig p -- ^ configuration for /HTML/+  , hscJava       :: HeaderConfig p -- ^ configuration for /Java/+  , hscJs         :: HeaderConfig p -- ^ configuration for /JavaScript/+  , hscKotlin     :: HeaderConfig p -- ^ configuration for /Kotlin/+  , hscPhp        :: HeaderConfig p -- ^ configuration for /PHP/+  , hscPureScript :: HeaderConfig p -- ^ configuration for /PureScript/+  , hscRust       :: HeaderConfig p -- ^ configuration for /Rust/+  , hscScala      :: HeaderConfig p -- ^ configuration for /Scala/+  , hscShell      :: HeaderConfig p -- ^ configuration for /Shell/+  }++-- | Alias for complete variant of 'HeadersConfig'.+type CtHeadersConfig = HeadersConfig 'Complete++-- | Alias for partial variant of 'HeadersConfig'.+type PtHeadersConfig = HeadersConfig 'Partial++deriving instance Eq CtHeadersConfig+deriving instance Eq PtHeadersConfig+deriving instance Show CtHeadersConfig+deriving instance Show PtHeadersConfig+deriving instance Generic PtHeadersConfig++deriving via (Generically PtHeadersConfig)+         instance Semigroup PtHeadersConfig+deriving via (Generically PtHeadersConfig)+         instance Monoid PtHeadersConfig++instance FromJSON PtHeadersConfig where+  parseJSON = withObject "PartialHeadersConfig" $ \obj -> do+    hscC          <- obj .:? "c" .!= mempty+    hscCpp        <- obj .:? "cpp" .!= mempty+    hscCss        <- obj .:? "css" .!= mempty+    hscDart       <- obj .:? "dart" .!= mempty+    hscGo         <- obj .:? "go" .!= mempty+    hscHaskell    <- obj .:? "haskell" .!= mempty+    hscHtml       <- obj .:? "html" .!= mempty+    hscJava       <- obj .:? "java" .!= mempty+    hscJs         <- obj .:? "js" .!= mempty+    hscKotlin     <- obj .:? "kotlin" .!= mempty+    hscPhp        <- obj .:? "php" .!= mempty+    hscPureScript <- obj .:? "purescript" .!= mempty+    hscRust       <- obj .:? "rust" .!= mempty+    hscScala      <- obj .:? "scala" .!= mempty+    hscShell      <- obj .:? "shell" .!= mempty+    pure HeadersConfig { .. }+++---------------------------------  Error Types  --------------------------------++-- | Represents single key in the configuration.+data ConfigurationKey+  = CkFileExtensions FileType+  -- ^ no configuration for @file-extensions@+  | CkHeaderSyntax FileType+  -- ^ no configuration for header syntax+  | CkMarginTopCode FileType+  -- ^ no configuration for margin between header top and preceding code+  | CkMarginTopFile FileType+  -- ^ no configuration for margin between header top and start of file+  | CkMarginBottomCode FileType+  -- ^ no configuration for margin between header bottom and following code+  | CkMarginBottomFile FileType+  -- ^ no configuration for margin between header bottom and end of file+  | CkPutAfter FileType+  -- ^ no configuration for @put-after@+  | CkPutBefore FileType+  -- ^ no configuration for @put-before@+  | CkRunMode+  -- ^ no configuration for @run-mode@+  | CkSourcePaths+  -- ^ no configuration for @source-paths@+  | CkExcludedPaths+  -- ^ no configuration for @excluded-paths@+  | CkExcludeIgnoredPaths+  -- ^ no configuration for @exclude-ignored-paths@+  | CkBuiltInTemplates+  -- ^ no configuration for built in templates+  | CkVariables+  -- ^ no configuration for @variables@+  | CkEnabled+  -- ^ no configuration for @enabled@+  deriving (Eq, Show)+++-- | Exception specific to the "Headroom.Configuration" module.+data ConfigurationError+  = MissingConfiguration ConfigurationKey+  -- ^ some of the required configuration keys has not been specified+  | MixedHeaderSyntax+  -- ^ illegal configuration for 'HeaderSyntax'+  deriving (Eq, Show, Typeable)++instance Exception ConfigurationError where+  displayException = displayException'+  toException      = toHeadroomError+  fromException    = fromHeadroomError+++displayException' :: ConfigurationError -> String+displayException' = T.unpack . \case+  MissingConfiguration key -> case key of+    CkFileExtensions fileType -> missingConfig+      (withFT "file-extensions" fileType)+      (Just "file-extensions")+      Nothing+    CkHeaderSyntax fileType -> missingConfig+      (withFT "comment-syntax" fileType)+      (Just "block-comment|line-comment")+      Nothing+    CkMarginTopCode fileType -> missingConfig+      (withFT "margin-top-code" fileType)+      (Just "margin-top-code")+      Nothing+    CkMarginTopFile fileType -> missingConfig+      (withFT "margin-top-file" fileType)+      (Just "margin-top-file")+      Nothing+    CkMarginBottomCode fileType -> missingConfig+      (withFT "margin-bottom-code" fileType)+      (Just "margin-bottom-code")+      Nothing+    CkMarginBottomFile fileType -> missingConfig+      (withFT "margin-bottom-file" fileType)+      (Just "margin-bottom-file")+      Nothing+    CkPutAfter fileType ->+      missingConfig (withFT "put-after" fileType) (Just "put-after") Nothing+    CkPutBefore fileType ->+      missingConfig (withFT "put-before" fileType) (Just "put-before") Nothing+    CkRunMode -> missingConfig+      "mode of the run command"+      (Just "run-mode")+      (Just+        "(-a|--add-headers)|(-c|--check-header)|(-d|--drop-header)|(-r|--replace-headers)"+      )+    CkSourcePaths -> missingConfig "paths to source code files"+                                   (Just "source-paths")+                                   (Just "-s|--source-path")+    CkExcludedPaths -> missingConfig "excluded paths"+                                     (Just "excluded-paths")+                                     (Just "-e|--excluded-path")+    CkExcludeIgnoredPaths -> missingConfig "whether to exclude ignored paths"+                                           (Just "exclude-ignored-paths")+                                           (Just "--exclude-ignored-paths")+    CkBuiltInTemplates -> missingConfig+      "use of built-in templates"+      (Just "builtin-templates")+      (Just "(-t|--template-path)|--builtin-templates")+    CkVariables -> missingConfig "template variables"+                                 (Just "variables")+                                 (Just "-v|--variable")+    CkEnabled -> missingConfig "enabled" (Just "enabled") Nothing+  MixedHeaderSyntax -> mixedHeaderSyntax+ where+  withFT msg fileType = [i|#{msg :: Text} (#{fileType})|]+  mixedHeaderSyntax = [iii|+      Invalid configuration, combining 'block-comment' with 'line-comment'+      is not allowed. Either use 'block-comment' to define multi-line+      comment header, or 'line-comment' to define header composed of+      multiple single-line comments.+    |]+++missingConfig :: Text -> Maybe Text -> Maybe Text -> Text+missingConfig desc yaml cli = [iii|+    Missing configuration for '#{desc}' (#{options}). See following page for+    more details: #{webDocConfigCurr}+  |]+ where+  cliText  = fmap (\c -> [i|command line option '#{c}'|]) cli+  yamlText = fmap (\c -> [i|YAML option '#{c}'|]) yaml+  options  = T.intercalate " or " . catMaybes $ [cliText, yamlText]
− src/Headroom/Configuration.hs
@@ -1,190 +0,0 @@-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards   #-}-{-# LANGUAGE TemplateHaskell   #-}--{-|-Module      : Headroom.Configuration-Description : Configuration handling (loading, parsing, validating)-Copyright   : (c) 2019-2021 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.Compat       ( checkCompatibility )-import           Headroom.Configuration.Types        ( Configuration(..)-                                                     , ConfigurationError(..)-                                                     , ConfigurationKey(..)-                                                     , CtConfiguration-                                                     , CtHeaderConfig-                                                     , CtHeadersConfig-                                                     , CtPostProcessConfig-                                                     , CtPostProcessConfigs-                                                     , CtUpdateCopyrightConfig-                                                     , HeaderConfig(..)-                                                     , HeadersConfig(..)-                                                     , Phase(..)-                                                     , PostProcessConfig(..)-                                                     , PostProcessConfigs(..)-                                                     , PtConfiguration-                                                     , PtHeaderConfig-                                                     , PtHeadersConfig-                                                     , PtPostProcessConfig-                                                     , PtPostProcessConfigs-                                                     , PtUpdateCopyrightConfig-                                                     , UpdateCopyrightConfig(..)-                                                     )-import           Headroom.Data.Lens                  ( suffixLenses )-import           Headroom.FileType.Types             ( FileType(..) )-import           Headroom.Meta                       ( buildVersion-                                                     , configBreakingChanges-                                                     )-import           RIO-import qualified RIO.ByteString                     as B---suffixLenses ''PostProcessConfig-suffixLenses ''PostProcessConfigs-suffixLenses ''UpdateCopyrightConfig---------------------------------  PUBLIC FUNCTIONS  ---------------------------------- | Loads and parses application configuration from given /YAML/ file.-loadConfiguration :: (MonadIO m, MonadThrow m) => FilePath -> m PtConfiguration-loadConfiguration path = do-  content <- liftIO $ B.readFile path-  _       <- checkCompatibility configBreakingChanges buildVersion content-  parseConfiguration content----- | Parses application configuration from given raw input in /YAML/ format.-parseConfiguration :: MonadThrow m-                   => 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)-  cExcludeIgnoredPaths <- lastOrError CkExcludeIgnoredPaths-                                      (cExcludeIgnoredPaths pt)-  cBuiltInTemplates   <- lastOrError CkBuiltInTemplates (cBuiltInTemplates pt)-  cTemplateRefs       <- pure $ cTemplateRefs pt-  cLicenseHeaders     <- makeHeadersConfig (cLicenseHeaders pt)-  cPostProcessConfigs <- makePostProcessConfigs (cPostProcessConfigs 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)-  hscGo         <- makeHeaderConfig Go (hscGo 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)-  hcMarginTopCode <- lastOrError (CkMarginTopCode fileType) (hcMarginTopCode pt)-  hcMarginTopFile <- lastOrError (CkMarginTopFile fileType) (hcMarginTopFile pt)-  hcMarginBottomCode <- lastOrError (CkMarginBottomCode fileType)-                                    (hcMarginBottomCode pt)-  hcMarginBottomFile <- lastOrError (CkMarginBottomFile fileType)-                                    (hcMarginBottomFile pt)-  hcPutAfter     <- lastOrError (CkPutAfter fileType) (hcPutAfter pt)-  hcPutBefore    <- lastOrError (CkPutBefore fileType) (hcPutBefore pt)-  hcHeaderSyntax <- lastOrError (CkHeaderSyntax fileType) (hcHeaderSyntax pt)-  pure HeaderConfig { .. }---------------------------------  PRIVATE FUNCTIONS  -------------------------------makePostProcessConfigs :: MonadThrow m-                       => PtPostProcessConfigs-                       -> m CtPostProcessConfigs-makePostProcessConfigs pt = do-  ppcsUpdateCopyright <- makePostProcessConfig (pt ^. ppcsUpdateCopyrightL)-                                               makeUpdateCopyrightConfig-  pure PostProcessConfigs { .. }---makePostProcessConfig :: MonadThrow m-                      => PtPostProcessConfig c-                      -> (c 'Partial -> m (c 'Complete))-                      -> m (CtPostProcessConfig c)-makePostProcessConfig pt fn = do-  ppcEnabled <- lastOrError CkEnabled (pt ^. ppcEnabledL)-  ppcConfig  <- fn $ pt ^. ppcConfigL-  pure PostProcessConfig { .. }---makeUpdateCopyrightConfig :: MonadThrow m-                          => PtUpdateCopyrightConfig-                          -> m CtUpdateCopyrightConfig-makeUpdateCopyrightConfig pt = do-  let uccSelectedAuthors = lastOrNothing $ pt ^. uccSelectedAuthorsL-  pure UpdateCopyrightConfig { .. }---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
− src/Headroom/Configuration/Compat.hs
@@ -1,139 +0,0 @@-{-# LANGUAGE LambdaCase        #-}-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes       #-}-{-# LANGUAGE RecordWildCards   #-}-{-# LANGUAGE StrictData        #-}--{-|-Module      : Headroom.Configuration.Compat-Description : Compatibility checks for YAML configuration-Copyright   : (c) 2019-2021 Vaclav Svejcar-License     : BSD-3-Clause-Maintainer  : vaclav.svejcar@gmail.com-Stability   : experimental-Portability : POSIX--This module contains functions and data types used for checking compatibility of-user's YAML configuration with current version of Headroom.--}--module Headroom.Configuration.Compat-  ( VersionError(..)-  , checkCompatibility-  )-where--import           Data.Aeson                          ( FromJSON(..)-                                                     , withObject-                                                     , (.:)-                                                     )-import           Data.String.Interpolate             ( iii )-import qualified Data.Yaml                          as Y-import           Headroom.Meta                       ( buildVersion-                                                     , configFileName-                                                     , productName-                                                     , webDocMigration-                                                     )-import           Headroom.Meta.Version               ( Version(..)-                                                     , printVersionP-                                                     , pvp-                                                     )-import           Headroom.Types                      ( fromHeadroomError-                                                     , toHeadroomError-                                                     )-import           RIO-import qualified RIO.List                           as L------------------------------------  DATA TYPES  -----------------------------------newtype VersionObj = VersionObj Version deriving (Eq, Show)--instance FromJSON VersionObj where-  parseJSON = withObject "VersionObj" $ \obj -> do-    version <- obj .: "version"-    pure $ VersionObj version------------------------------------  ERROR TYPES  ------------------------------------ | Exception specific to the "Headroom.Configuration.Compat" module.-data VersionError-  = CannotParseVersion-  -- ^ cannot parse version info from given YAML configuration-  | NewerVersionDetected Version-  -- ^ configuration has newer version than Headroom-  | UnsupportedVersion [Version] Version-  -- ^ given YAML configuration is not compatible-  deriving (Eq, Show)---instance Exception VersionError where-  displayException = displayException'-  toException      = toHeadroomError-  fromException    = fromHeadroomError---------------------------------  PUBLIC FUNCTIONS  ---------------------------------- | Checks whether the given not yet parsed YAML configuration is compatible,--- using list of versions that caused breaking changes into configuration.-checkCompatibility :: MonadThrow m-                   => [Version]-                   -- ^ list of versions with breaking changes in configuration-                   -> Version-                   -- ^ current Headroom version-                   -> ByteString-                   -- ^ raw, not yet parsed YAML configuration-                   -> m Version-                   -- ^ detected compatible version or error-checkCompatibility breakingVersions current raw = do-  VersionObj version <- parseObj-  _                  <- checkBreakingChanges breakingVersions version-  _                  <- checkNewerVersion current version-  pure version- where-  parseObj = either (const . throwM $ CannotParseVersion) pure decoded-  decoded  = Y.decodeEither' raw---------------------------------  PRIVATE FUNCTIONS  -------------------------------checkBreakingChanges :: MonadThrow m => [Version] -> Version -> m ()-checkBreakingChanges vs v = case L.filter (v <) . L.sort $ vs of-  []    -> pure ()-  newer -> throwM $ UnsupportedVersion newer v---checkNewerVersion :: MonadThrow m => Version -> Version -> m ()-checkNewerVersion current checked =-  if current < checked then throwM $ NewerVersionDetected checked else pure ()---displayException' :: VersionError -> String-displayException' = \case-  CannotParseVersion -> [iii|-      Cannot find 'version' key in #{configFileName :: String} configuration-      file. This field is required to check whether your current configuration-      is compatible with installed version of #{productName}. This functionality-      has been added in version 0.4.0.0, please see following migration guide-      for more details on how to proceed:-      #{"\n\t" <> webDocMigration v0400}-    |]-  NewerVersionDetected version -> [iii|-      The version set in your #{configFileName :: String} configuration file-      (#{printVersionP version}) is newer than version of installed-      #{productName} (#{printVersionP buildVersion}). Please upgrade-      #{productName} first.-    |]-  UnsupportedVersion versions version -> [iii|-      Your #{configFileName :: String} configuration file has version-      #{printVersionP version}, which is incompatible with current version of-      #{productName} (#{printVersionP buildVersion}). Please perform steps-      described in these migration guides first (in given order):-      #{migrationGuides versions}-    |]- where-  v0400           = [pvp|0.4.0.0|]-  migrationGuides = mconcat . fmap (\v -> "\n\t- " <> webDocMigration v)
− src/Headroom/Configuration/Enrich.hs
@@ -1,111 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE StrictData        #-}--{-|-Module      : Headroom.Configuration.Enrich-Description : Simple enrichment of YAML configuration stubs-Copyright   : (c) 2019-2021 Vaclav Svejcar-License     : BSD-3-Clause-Maintainer  : vaclav.svejcar@gmail.com-Stability   : experimental-Portability : POSIX--This module contains mini-DSL for enrichment of generated /YAML/ configurations,-i.e. replacing default values with real ones, etc. This is intentionally done-without the "Data.Yaml" and parsing, because that way all comments inside YAML-file would be lost.--}--module Headroom.Configuration.Enrich-  ( -- * Data Types-    Enrich(..)-  , ValueType(..)-    -- * Field Generators-  , withArray-  , withText-    -- * Field Manipulation-  , replaceEmptyValue-  )-where--import           Data.Aeson                          ( ToJSON(..) )-import           Headroom.Data.Serialization         ( prettyPrintYAML )-import           RIO-import qualified RIO.Map                            as M-import qualified RIO.Text                           as T-import qualified RIO.Text.Partial                   as TP------------------------------------  DATA TYPES  ------------------------------------- | Simple wrapper representing single step of enrichment.-newtype Enrich = Enrich-  { enrich :: Text -> Text-  -- ^ takes input text and does enrichment-  }---instance Semigroup Enrich where-  Enrich fnA <> Enrich fnB = Enrich $ fnA . fnB---instance Monoid Enrich where-  mempty = Enrich id----- | Represents type of the field value.-data ValueType-  = Array-  -- ^ type of /YAML/ array-  | String-  -- ^ type of /YAML/ string-  deriving (Eq, Show)---------------------------------  PUBLIC FUNCTIONS  ---------------------------------- | Generates /YAML/ array field from given list and field name.-withArray :: ToJSON a-          => [a]-          -- ^ input list used as value-          -> Text-          -- ^ field name-          -> (ValueType, Text)-          -- ^ generated fields as @(valueType, generatedField)@-withArray list field = (Array, asYAML field list)----- | Generates /YAML/ string from given text value and field name.-withText :: Text-         -- ^ input text value-         -> Text-         -- ^ field name-         -> (ValueType, Text)-         -- ^ generated fields as @(valueType, generatedField)@-withText text field = (String, asYAML field text)----- | Replaces empty value of given field with actual generated value.-replaceEmptyValue :: Text-                  -- ^ field name-                  -> (Text -> (ValueType, Text))-                  -- ^ field value generator function-                  -> Enrich-                  -- ^ resulting enrichment step-replaceEmptyValue field replaceFn = Enrich $ \doc -> do-  TP.replace old new doc- where-  (tpe, new) = replaceFn field-  old        = field <> ": " <> emptyValue tpe---------------------------------  PRIVATE FUNCTIONS  -------------------------------asYAML :: ToJSON a => Text -> a -> Text-asYAML field value = T.stripEnd . prettyPrintYAML $ M.fromList [(field, value)]---emptyValue :: ValueType -> Text-emptyValue Array  = "[]"-emptyValue String = "\"\""
− src/Headroom/Configuration/Types.hs
@@ -1,585 +0,0 @@-{-# LANGUAGE DataKinds            #-}-{-# LANGUAGE DeriveAnyClass       #-}-{-# LANGUAGE DeriveGeneric        #-}-{-# LANGUAGE DerivingVia          #-}-{-# LANGUAGE FlexibleContexts     #-}-{-# LANGUAGE FlexibleInstances    #-}-{-# LANGUAGE LambdaCase           #-}-{-# LANGUAGE NoImplicitPrelude    #-}-{-# LANGUAGE OverloadedStrings    #-}-{-# LANGUAGE QuasiQuotes          #-}-{-# LANGUAGE RecordWildCards      #-}-{-# LANGUAGE StandaloneDeriving   #-}-{-# LANGUAGE StrictData           #-}-{-# LANGUAGE TypeFamilies         #-}-{-# LANGUAGE TypeOperators        #-}-{-# LANGUAGE UndecidableInstances #-}--{-|-Module      : Headroom.Configuration.Types-Description : Data types for /Headroom/ configuration-Copyright   : (c) 2019-2021 Vaclav Svejcar-License     : BSD-3-Clause-Maintainer  : vaclav.svejcar@gmail.com-Stability   : experimental-Portability : POSIX--This module contains data types representing /Headroom/ configuration options.-Related logic is available in "Headroom.Configuration" module.--Data types related to /Headroom/ configuration uses the-<https://medium.com/@jonathangfischoff/the-partial-options-monoid-pattern-31914a71fc67 partial options monoid>-pattern, but instead of defining separate data type for each /phase/-(/partial/ or /complete/ configuration), the /phase/ is expressed by the 'Phase'-data type and related /closed type family/.--}--module Headroom.Configuration.Types-  ( -- * Error Types-    ConfigurationError(..)-  , ConfigurationKey(..)-    -- * Type Families-  , Phase(..)-  , (:::)-    -- * Data Types-    -- ** Top Level Configuration-  , Configuration(..)-  , CtConfiguration-  , PtConfiguration-  , HeadersConfig(..)-  , CtHeadersConfig-  , PtHeadersConfig-  , HeaderConfig(..)-  , CtHeaderConfig-  , PtHeaderConfig-    -- ** Header Functions-  , CtUpdateCopyrightConfig-  , PtUpdateCopyrightConfig-  , UpdateCopyrightConfig(..)-  , CtPostProcessConfig-  , PtPostProcessConfig-  , PostProcessConfig(..)-  , CtPostProcessConfigs-  , PtPostProcessConfigs-  , PostProcessConfigs(..)-    -- ** Additional Data Types-  , HeaderSyntax(..)-  , GenMode(..)-  , LicenseType(..)-  , RunMode(..)-  )-where--import           Control.Exception                   ( throw )-import           Data.Aeson                          ( FromJSON(..)-                                                     , Value(String)-                                                     , genericParseJSON-                                                     , withObject-                                                     , (.!=)-                                                     , (.:?)-                                                     )-import           Data.Monoid                         ( Last(..) )-import           Data.String.Interpolate             ( i-                                                     , iii-                                                     )-import           Generic.Data                        ( Generically(..) )-import           Headroom.Data.Regex                 ( Regex(..) )-import           Headroom.Data.Serialization         ( aesonOptions )-import           Headroom.FileType.Types             ( FileType )-import           Headroom.Meta                       ( webDocConfigCurr )-import           Headroom.Template.TemplateRef       ( TemplateRef )-import           Headroom.Types                      ( LicenseType(..)-                                                     , fromHeadroomError-                                                     , toHeadroomError-                                                     )-import           Headroom.Variables.Types            ( Variables(..) )-import           RIO-import qualified RIO.Text                           as T---------------------------------------  Phase  --------------------------------------- | Data type representing state of given configuration data type.-data Phase-  = Partial-  -- ^ partial configuration, could be combined with another or validated to-  -- produce the complete configuration-  | Complete-  -- ^ complete configuration, result of combining and validation of partial-  -- configuration----- | /Closed type family/ used to express the phase of given data type.-type family (p :: Phase) ::: a where-  'Partial  ::: a = Last a-  'Complete ::: a = a-----------------------------------  HeaderSyntax  ------------------------------------ | Syntax of the license header comment.-data HeaderSyntax-  = BlockComment Regex Regex (Maybe Text)-  -- ^ block (multi-line) comment syntax (e.g. @/* */@)-  | LineComment Regex (Maybe Text)-  -- ^ single line comment syntax (e.g. @//@)-  deriving (Eq, Show)---- | Internal representation of the block style of 'HeaderSyntax'.-data BlockComment' = BlockComment'-  { bcStartsWith :: Regex-  -- ^ starting pattern (e.g. @/*@)-  , bcEndsWith   :: Regex-  -- ^ ending pattern (e.g. @*/@)-  }-  deriving (Eq, Generic, Show)--instance FromJSON BlockComment' where-  parseJSON = genericParseJSON aesonOptions---- | Internal representation of the line style of 'HeaderSyntax'.-newtype LineComment' = LineComment'-  { lcPrefixedBy :: Regex-  -- ^ prefix of the comment line (e.g. @//@)-  }-  deriving (Eq, Generic, Show)--instance FromJSON LineComment' where-  parseJSON = genericParseJSON aesonOptions--------------------------------------  RunMode  -------------------------------------- | Represents what action should the @run@ command perform.-data RunMode-  = Add-  -- ^ /add mode/ for @run@ command-  | Check-  -- ^ /check mode/ for @run@ command-  | Drop-  -- ^ /drop mode/ for @run@ command-  | Replace-  -- ^ /replace mode/ for @run@ command-  deriving (Eq, Show)--instance FromJSON RunMode where-  parseJSON = \case-    String s -> case T.toLower s of-      "add"     -> pure Add-      "check"   -> pure Check-      "drop"    -> pure Drop-      "replace" -> pure Replace-      _         -> error $ "Unknown run mode: " <> T.unpack s-    other -> error $ "Invalid value for run mode: " <> show other--------------------------------------  GenMode  -------------------------------------- | Represents what action should the @gen@ command perform.-data GenMode-  = GenConfigFile-  -- ^ generate /YAML/ config file stub-  | GenLicense (LicenseType, FileType)-  -- ^ generate license header template-  deriving (Eq, Show)-------------------------------  UpdateCopyrightConfig  ------------------------------- | Main configuration for the "Headroom.PostProcess.UpdateCopyright"--- /post-processor/.-data UpdateCopyrightConfig (p :: Phase) = UpdateCopyrightConfig-  { uccSelectedAuthors :: p ::: Maybe (NonEmpty Text)-  -- ^ if specified, years will be updated only in copyright statements of-  -- given authors-  }---- | Alias for complete variant of 'UpdateCopyrightConfig'.-type CtUpdateCopyrightConfig = UpdateCopyrightConfig 'Complete---- | Alias for partial variant of 'UpdateCopyrightConfig'.-type PtUpdateCopyrightConfig = UpdateCopyrightConfig 'Partial--deriving instance Eq CtUpdateCopyrightConfig-deriving instance Eq PtUpdateCopyrightConfig-deriving instance Show CtUpdateCopyrightConfig-deriving instance Show PtUpdateCopyrightConfig-deriving instance Generic PtUpdateCopyrightConfig--deriving via (Generically PtUpdateCopyrightConfig)-         instance Semigroup PtUpdateCopyrightConfig-deriving via (Generically PtUpdateCopyrightConfig)-         instance Monoid PtUpdateCopyrightConfig--instance FromJSON PtUpdateCopyrightConfig where-  parseJSON = withObject "PtUpdateCopyrightConfig" $ \obj -> do-    uccSelectedAuthors <- Last <$> obj .:? "selected-authors-only"-    pure UpdateCopyrightConfig { .. }---------------------------------  PostProcessConfig  ----------------------------------- | Configuration for selected /post-processor/.-data PostProcessConfig (p :: Phase) c = PostProcessConfig-  { ppcEnabled :: p ::: Bool -- ^ whether this function is enabled or not-  , ppcConfig  :: c p        -- ^ custom configuration of the /post-processor/-  }---- | Alias for complete variant of 'PostProcessConfig'.-type CtPostProcessConfig c = PostProcessConfig 'Complete c---- | Alias for partial variant of 'PostProcessConfig'.-type PtPostProcessConfig c = PostProcessConfig 'Partial c---deriving instance (Eq (c 'Complete)) => Eq (CtPostProcessConfig c)-deriving instance (Eq (c 'Partial)) => Eq (PtPostProcessConfig c)-deriving instance (Show (c 'Complete)) => Show (CtPostProcessConfig c)-deriving instance (Show (c 'Partial)) => Show (PtPostProcessConfig c)-deriving instance Generic (PtPostProcessConfig c)--deriving via (Generically (PtPostProcessConfig c))-         instance Semigroup (c 'Partial) => Semigroup (PtPostProcessConfig c)-deriving via (Generically (PtPostProcessConfig c))-         instance Monoid (c 'Partial) => Monoid (PtPostProcessConfig c)--instance (FromJSON (c 'Partial), Monoid (c 'Partial)) => FromJSON (PtPostProcessConfig c) where-  parseJSON = withObject "PtPostProcessConfig" $ \obj -> do-    ppcEnabled <- Last <$> obj .:? "enabled"-    ppcConfig  <- obj .:? "config" .!= mempty-    pure PostProcessConfig { .. }----------------------------------  PostProcessConfigs  ---------------------------------- | Configuration of all known /post-processors/.-data PostProcessConfigs (p :: Phase) = PostProcessConfigs-  { ppcsUpdateCopyright :: PostProcessConfig p UpdateCopyrightConfig-  -- ^ configuration for the "Headroom.PostProcess.UpdateCopyright"-  }---- | Alias for complete variant of 'PostProcessConfigs'.-type CtPostProcessConfigs = PostProcessConfigs 'Complete---- | Alias for partial variant of 'PostProcessConfigs'.-type PtPostProcessConfigs = PostProcessConfigs 'Partial--deriving instance Eq CtPostProcessConfigs-deriving instance Eq PtPostProcessConfigs-deriving instance Show CtPostProcessConfigs-deriving instance Show PtPostProcessConfigs-deriving instance Generic PtPostProcessConfigs--deriving via (Generically PtPostProcessConfigs)-         instance Semigroup PtPostProcessConfigs-deriving via (Generically PtPostProcessConfigs)-         instance Monoid PtPostProcessConfigs--instance FromJSON PtPostProcessConfigs where-  parseJSON = withObject "PtPostProcessConfigs" $ \obj -> do-    ppcsUpdateCopyright <- obj .:? "update-copyright" .!= mempty-    pure PostProcessConfigs { .. }-----------------------------------  Configuration  ----------------------------------- | Application configuration.-data Configuration (p :: Phase) = Configuration-  { cRunMode             :: p ::: RunMode-  -- ^ mode of the @run@ command-  , cSourcePaths         :: p ::: [FilePath]-  -- ^ paths to source code files-  , cExcludedPaths       :: p ::: [Regex]-  -- ^ excluded source paths-  , cExcludeIgnoredPaths :: p ::: Bool-  -- ^ whether to exclude paths ignored by VCS-  , cBuiltInTemplates    :: p ::: Maybe LicenseType-  -- ^ used built-in templates-  , cTemplateRefs        :: [TemplateRef]-  -- ^ template references-  , cVariables           :: Variables-  -- ^ variable values for templates-  , cLicenseHeaders      :: HeadersConfig p-  -- ^ configuration of license headers-  , cPostProcessConfigs  :: PostProcessConfigs p-  -- ^ configuration of post-processors-  }---- | Alias for complete variant of 'Configuration'.-type CtConfiguration = Configuration 'Complete---- | Alias for partial variant of 'Configuration'.-type PtConfiguration = Configuration 'Partial--deriving instance Eq CtConfiguration-deriving instance Eq PtConfiguration-deriving instance Show CtConfiguration-deriving instance Show PtConfiguration-deriving instance Generic PtConfiguration--deriving via (Generically PtConfiguration)-         instance Semigroup PtConfiguration-deriving via (Generically PtConfiguration)-         instance Monoid PtConfiguration---instance FromJSON PtConfiguration where-  parseJSON = withObject "PtConfiguration" $ \obj -> do-    cRunMode             <- Last <$> obj .:? "run-mode"-    cSourcePaths         <- Last <$> obj .:? "source-paths"-    cExcludedPaths       <- Last <$> obj .:? "excluded-paths"-    cExcludeIgnoredPaths <- Last <$> obj .:? "exclude-ignored-paths"-    cBuiltInTemplates    <- Last <$> obj .:? "builtin-templates"-    cTemplateRefs        <- obj .:? "template-paths" .!= mempty-    cVariables           <- Variables <$> obj .:? "variables" .!= mempty-    cLicenseHeaders      <- obj .:? "license-headers" .!= mempty-    cPostProcessConfigs  <- obj .:? "post-process" .!= mempty-    pure Configuration { .. }-----------------------------------  HeaderConfig  ------------------------------------ | Configuration for specific license header.-data HeaderConfig (p :: Phase) = HeaderConfig-  { hcFileExtensions   :: p ::: [Text]-  -- ^ list of file extensions (without dot)-  , hcMarginTopCode    :: p ::: Int-  -- ^ margin between header top and preceding code (if present)-  , hcMarginTopFile    :: p ::: Int-  -- ^ margin between header top and start of file (if no code is between)-  , hcMarginBottomCode :: p ::: Int-  -- ^ margin between header bottom and following code (if present)-  , hcMarginBottomFile :: p ::: Int-  -- ^ margin between header bottom and end of file (if no code is between)-  , hcPutAfter         :: p ::: [Regex]-  -- ^ /regexp/ patterns after which to put the header-  , hcPutBefore        :: p ::: [Regex]-  -- ^ /regexp/ patterns before which to put the header-  , hcHeaderSyntax     :: p ::: HeaderSyntax-  -- ^ syntax of the license header comment-  }---- | Alias for complete variant of 'HeaderConfig'.-type CtHeaderConfig = HeaderConfig 'Complete---- | Alias for partial variant of 'HeaderConfig'.-type PtHeaderConfig = HeaderConfig 'Partial--deriving instance Eq CtHeaderConfig-deriving instance Eq PtHeaderConfig-deriving instance Show CtHeaderConfig-deriving instance Show PtHeaderConfig-deriving instance Generic PtHeaderConfig--deriving via (Generically PtHeaderConfig)-         instance Semigroup PtHeaderConfig-deriving via (Generically PtHeaderConfig)-         instance Monoid PtHeaderConfig--instance FromJSON PtHeaderConfig where-  parseJSON = withObject "PartialHeaderConfig" $ \obj -> do-    hcFileExtensions   <- Last <$> obj .:? "file-extensions"-    hcMarginTopCode    <- Last <$> obj .:? "margin-top-code"-    hcMarginTopFile    <- Last <$> obj .:? "margin-top-file"-    hcMarginBottomCode <- Last <$> obj .:? "margin-bottom-code"-    hcMarginBottomFile <- Last <$> obj .:? "margin-bottom-file"-    hcPutAfter         <- Last <$> obj .:? "put-after"-    hcPutBefore        <- Last <$> obj .:? "put-before"-    blockComment       <- obj .:? "block-comment"-    lineComment        <- obj .:? "line-comment"-    hcHeaderSyntax     <- pure . Last $ syntax blockComment lineComment-    pure HeaderConfig { .. }-   where-    syntax (Just (BlockComment' s e)) Nothing = Just $ BlockComment s e Nothing-    syntax Nothing (Just (LineComment' p)) = Just $ LineComment p Nothing-    syntax Nothing Nothing = Nothing-    syntax _ _ = throw MixedHeaderSyntax----------------------------------  HeadersConfig  ----------------------------------- | Group of 'HeaderConfig' configurations for supported file types.-data HeadersConfig (p :: Phase) = HeadersConfig-  { hscC          :: HeaderConfig p-  -- ^ configuration for /C/ programming language-  , hscCpp        :: HeaderConfig p-  -- ^ configuration for /C++/ programming language-  , hscCss        :: HeaderConfig p-  -- ^ configuration for /CSS/-  , hscGo         :: HeaderConfig p-  -- ^ configuration for /Go/-  , hscHaskell    :: HeaderConfig p-  -- ^ configuration for /Haskell/ programming language-  , hscHtml       :: HeaderConfig p-  -- ^ configuration for /HTML/-  , hscJava       :: HeaderConfig p-  -- ^ configuration for /Java/ programming language-  , hscJs         :: HeaderConfig p-  -- ^ configuration for /JavaScript/ programming language-  , hscPureScript :: HeaderConfig p-  -- ^ configuration for /PureScript/ programming language-  , hscRust       :: HeaderConfig p-  -- ^ configuration for /Rust/ programming language-  , hscScala      :: HeaderConfig p-  -- ^ configuration for /Scala/ programming language-  , hscShell      :: HeaderConfig p-  -- ^ configuration for /Shell/-  }---- | Alias for complete variant of 'HeadersConfig'.-type CtHeadersConfig = HeadersConfig 'Complete---- | Alias for partial variant of 'HeadersConfig'.-type PtHeadersConfig = HeadersConfig 'Partial--deriving instance Eq CtHeadersConfig-deriving instance Eq PtHeadersConfig-deriving instance Show CtHeadersConfig-deriving instance Show PtHeadersConfig-deriving instance Generic PtHeadersConfig--deriving via (Generically PtHeadersConfig)-         instance Semigroup PtHeadersConfig-deriving via (Generically PtHeadersConfig)-         instance Monoid PtHeadersConfig--instance FromJSON PtHeadersConfig where-  parseJSON = withObject "PartialHeadersConfig" $ \obj -> do-    hscC          <- obj .:? "c" .!= mempty-    hscCpp        <- obj .:? "cpp" .!= mempty-    hscCss        <- obj .:? "css" .!= mempty-    hscGo         <- obj .:? "go" .!= mempty-    hscHaskell    <- obj .:? "haskell" .!= mempty-    hscHtml       <- obj .:? "html" .!= mempty-    hscJava       <- obj .:? "java" .!= mempty-    hscJs         <- obj .:? "js" .!= mempty-    hscPureScript <- obj .:? "purescript" .!= mempty-    hscRust       <- obj .:? "rust" .!= mempty-    hscScala      <- obj .:? "scala" .!= mempty-    hscShell      <- obj .:? "shell" .!= mempty-    pure HeadersConfig { .. }------------------------------------  Error Types  ------------------------------------ | Represents single key in the configuration.-data ConfigurationKey-  = CkFileExtensions FileType-  -- ^ no configuration for @file-extensions@-  | CkHeaderSyntax FileType-  -- ^ no configuration for header syntax-  | CkMarginTopCode FileType-  -- ^ no configuration for margin between header top and preceding code-  | CkMarginTopFile FileType-  -- ^ no configuration for margin between header top and start of file-  | CkMarginBottomCode FileType-  -- ^ no configuration for margin between header bottom and following code-  | CkMarginBottomFile FileType-  -- ^ no configuration for margin between header bottom and end of file-  | CkPutAfter FileType-  -- ^ no configuration for @put-after@-  | CkPutBefore FileType-  -- ^ no configuration for @put-before@-  | CkRunMode-  -- ^ no configuration for @run-mode@-  | CkSourcePaths-  -- ^ no configuration for @source-paths@-  | CkExcludedPaths-  -- ^ no configuration for @excluded-paths@-  | CkExcludeIgnoredPaths-  -- ^ no configuration for @exclude-ignored-paths@-  | CkBuiltInTemplates-  -- ^ no configuration for built in templates-  | CkVariables-  -- ^ no configuration for @variables@-  | CkEnabled-  -- ^ no configuration for @enabled@-  deriving (Eq, Show)----- | Exception specific to the "Headroom.Configuration" module.-data ConfigurationError-  = MissingConfiguration ConfigurationKey-  -- ^ some of the required configuration keys has not been specified-  | MixedHeaderSyntax-  -- ^ illegal configuration for 'HeaderSyntax'-  deriving (Eq, Show, Typeable)--instance Exception ConfigurationError where-  displayException = displayException'-  toException      = toHeadroomError-  fromException    = fromHeadroomError---displayException' :: ConfigurationError -> String-displayException' = T.unpack . \case-  MissingConfiguration key -> case key of-    CkFileExtensions fileType -> missingConfig-      (withFT "file-extensions" fileType)-      (Just "file-extensions")-      Nothing-    CkHeaderSyntax fileType -> missingConfig-      (withFT "comment-syntax" fileType)-      (Just "block-comment|line-comment")-      Nothing-    CkMarginTopCode fileType -> missingConfig-      (withFT "margin-top-code" fileType)-      (Just "margin-top-code")-      Nothing-    CkMarginTopFile fileType -> missingConfig-      (withFT "margin-top-file" fileType)-      (Just "margin-top-file")-      Nothing-    CkMarginBottomCode fileType -> missingConfig-      (withFT "margin-bottom-code" fileType)-      (Just "margin-bottom-code")-      Nothing-    CkMarginBottomFile fileType -> missingConfig-      (withFT "margin-bottom-file" fileType)-      (Just "margin-bottom-file")-      Nothing-    CkPutAfter fileType ->-      missingConfig (withFT "put-after" fileType) (Just "put-after") Nothing-    CkPutBefore fileType ->-      missingConfig (withFT "put-before" fileType) (Just "put-before") Nothing-    CkRunMode -> missingConfig-      "mode of the run command"-      (Just "run-mode")-      (Just-        "(-a|--add-headers)|(-c|--check-header)|(-d|--drop-header)|(-r|--replace-headers)"-      )-    CkSourcePaths -> missingConfig "paths to source code files"-                                   (Just "source-paths")-                                   (Just "-s|--source-path")-    CkExcludedPaths -> missingConfig "excluded paths"-                                     (Just "excluded-paths")-                                     (Just "-e|--excluded-path")-    CkExcludeIgnoredPaths -> missingConfig "whether to exclude ignored paths"-                                           (Just "exclude-ignored-paths")-                                           (Just "--exclude-ignored-paths")-    CkBuiltInTemplates -> missingConfig-      "use of built-in templates"-      (Just "builtin-templates")-      (Just "(-t|--template-path)|--builtin-templates")-    CkVariables -> missingConfig "template variables"-                                 (Just "variables")-                                 (Just "-v|--variable")-    CkEnabled -> missingConfig "enabled" (Just "enabled") Nothing-  MixedHeaderSyntax -> mixedHeaderSyntax- where-  withFT msg fileType = [i|#{msg :: Text} (#{fileType})|]-  mixedHeaderSyntax = [iii|-      Invalid configuration, combining 'block-comment' with 'line-comment'-      is not allowed. Either use 'block-comment' to define multi-line-      comment header, or 'line-comment' to define header composed of-      multiple single-line comments.-    |]---missingConfig :: Text -> Maybe Text -> Maybe Text -> Text-missingConfig desc yaml cli = [iii|-    Missing configuration for '#{desc}' (#{options}). See following page for-    more details: #{webDocConfigCurr}-  |]- where-  cliText  = fmap (\c -> [i|command line option '#{c}'|]) cli-  yamlText = fmap (\c -> [i|YAML option '#{c}'|]) yaml-  options  = T.intercalate " or " . catMaybes $ [cliText, yamlText]
src/Headroom/Data/Coerce.hs view
@@ -3,7 +3,7 @@ {-| Module      : Headroom.Data.Coerce Description : Extra functionality for coercion-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/Data/EnumExtra.hs view
@@ -6,7 +6,7 @@ {-| Module      : Headroom.Data.EnumExtra Description : Extra functionality for enum types-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -34,7 +34,6 @@    -- | Returns list of all enum values.   ---  -- >>> :set -XDeriveAnyClass -XTypeApplications   -- >>> data Test = Foo | Bar deriving (Bounded, Enum, EnumExtra, Eq, Ord, Show)   -- >>> allValues @Test   -- [Foo,Bar]@@ -45,7 +44,6 @@   -- | Returns all values of enum as single string, individual values separated   -- with comma.   ---  -- >>> :set -XDeriveAnyClass -XTypeApplications   -- >>> data Test = Foo | Bar deriving (Bounded, Enum, EnumExtra, Eq, Ord, Show)   -- >>> allValuesToText @Test   -- "Foo, Bar"@@ -55,7 +53,6 @@    -- | Returns textual representation of enum value. Opposite to 'textToEnum'.   ---  -- >>> :set -XDeriveAnyClass   -- >>> data Test = Foo | Bar deriving (Bounded, Enum, EnumExtra, Eq, Ord, Show)   -- >>> enumToText Bar   -- "Bar"@@ -66,7 +63,6 @@   -- | Returns enum value from its textual representation.   -- Opposite to 'enumToText'.   ---  -- >>> :set -XDeriveAnyClass   -- >>> data Test = Foo | Bar deriving (Bounded, Enum, EnumExtra, Eq, Ord, Show)   -- >>> (textToEnum "Foo") :: (Maybe Test)   -- Just Foo
src/Headroom/Data/Has.hs view
@@ -1,10 +1,11 @@+{-# LANGUAGE ConstraintKinds       #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NoImplicitPrelude     #-}  {-| Module      : Headroom.Data.Has Description : Simplified variant of @Data.Has@-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -16,6 +17,7 @@  module Headroom.Data.Has   ( Has(..)+  , HasRIO   ) where @@ -42,3 +44,19 @@    viewL :: MonadReader t m => m a   viewL = view hasLens+++-- | Handy type alias that allows to avoid ugly type singatures. Allows to+-- transform this:+--+-- @+-- foo :: (Has (Network (RIO env)) env) => RIO env ()+-- @+--+-- into+--+-- @+-- foo :: (HasRIO Network env) => RIO env ()+-- @+--+type HasRIO a env = Has (a (RIO env)) env
src/Headroom/Data/Lens.hs view
@@ -3,7 +3,7 @@ {-| Module      : Headroom.Data.Lens Description : Custom functionality related to /lens/-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/Data/Regex.hs view
@@ -1,15 +1,15 @@-{-# LANGUAGE BangPatterns      #-}-{-# LANGUAGE LambdaCase        #-}-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes       #-}-{-# LANGUAGE StrictData        #-}-{-# LANGUAGE TemplateHaskell   #-}+{-# LANGUAGE BangPatterns          #-}+{-# LANGUAGE LambdaCase            #-}+{-# LANGUAGE NoImplicitPrelude     #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE QuasiQuotes           #-}+{-# LANGUAGE StrictData            #-}+{-# LANGUAGE TemplateHaskellQuotes #-}  {-| Module      : Headroom.Data.Regex Description : Helper functions for regular expressions-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -116,7 +116,7 @@                  , quoteDec  = undefined                  }  where-  quoteExpRegex txt = [| compileUnsafe . T.pack $ txt |]+  quoteExpRegex txt = [|compileUnsafe . T.pack $ txt|]     where !_ = compileUnsafe . T.pack $ txt -- check at compile time  
src/Headroom/Data/Serialization.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.Data.Serialization Description : Various functions for data (de)serialization-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/Data/Text.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.Data.Text Description : Additional utilities for text manipulation-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/Embedded.hs view
@@ -5,7 +5,7 @@ {-| Module      : Headroom.Embedded Description : Embedded files-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -17,13 +17,15 @@ module Headroom.Embedded   ( configFileStub   , defaultConfig+  , defaultGlobalConfig   , licenseTemplate   ) where -import           Headroom.Configuration.Types        ( LicenseType(..) )+import           Headroom.Config.Types               ( LicenseType(..) ) import           Headroom.Embedded.TH                ( embedConfigFile                                                      , embedDefaultConfig+                                                     , embedDefaultGlobalConfig                                                      , embedTemplate                                                      ) import           Headroom.FileType.Types             ( FileType(..) )@@ -40,24 +42,29 @@ defaultConfig = $(embedDefaultConfig)  +-- | Default /YAML/ configuration for the global configuration file.+defaultGlobalConfig :: IsString a => a+defaultGlobalConfig = $(embedDefaultGlobalConfig)++ -- | License template for given license. licenseTemplate :: IsString a-                => LicenseType-                -- ^ license for which to return the template-                -> FileType-                -- ^ license for which to return the template-                -> a-                -- ^ template text+                => LicenseType -- ^ license for which to return the template+                -> FileType    -- ^ license for which to return the template+                -> a           -- ^ template text licenseTemplate licenseType fileType = case licenseType of   Apache2 -> case fileType of     C          -> $(embedTemplate Apache2 C)     CPP        -> $(embedTemplate Apache2 CPP)     CSS        -> $(embedTemplate Apache2 CSS)+    Dart       -> $(embedTemplate Apache2 Dart)     Go         -> $(embedTemplate Apache2 Go)     Haskell    -> $(embedTemplate Apache2 Haskell)     HTML       -> $(embedTemplate Apache2 HTML)     Java       -> $(embedTemplate Apache2 Java)     JS         -> $(embedTemplate Apache2 JS)+    Kotlin     -> $(embedTemplate Apache2 Kotlin)+    PHP        -> $(embedTemplate Apache2 PHP)     PureScript -> $(embedTemplate Apache2 PureScript)     Rust       -> $(embedTemplate Apache2 Rust)     Scala      -> $(embedTemplate Apache2 Scala)@@ -66,11 +73,14 @@     C          -> $(embedTemplate BSD3 C)     CPP        -> $(embedTemplate BSD3 CPP)     CSS        -> $(embedTemplate BSD3 CSS)+    Dart       -> $(embedTemplate BSD3 Dart)     Go         -> $(embedTemplate BSD3 Go)     Haskell    -> $(embedTemplate BSD3 Haskell)     HTML       -> $(embedTemplate BSD3 HTML)     Java       -> $(embedTemplate BSD3 Java)     JS         -> $(embedTemplate BSD3 JS)+    Kotlin     -> $(embedTemplate BSD3 Kotlin)+    PHP        -> $(embedTemplate BSD3 PHP)     PureScript -> $(embedTemplate BSD3 PureScript)     Rust       -> $(embedTemplate BSD3 Rust)     Scala      -> $(embedTemplate BSD3 Scala)@@ -79,11 +89,14 @@     C          -> $(embedTemplate GPL2 C)     CPP        -> $(embedTemplate GPL2 CPP)     CSS        -> $(embedTemplate GPL2 CSS)+    Dart       -> $(embedTemplate GPL2 Dart)     Go         -> $(embedTemplate GPL2 Go)     Haskell    -> $(embedTemplate GPL2 Haskell)     HTML       -> $(embedTemplate GPL2 HTML)     Java       -> $(embedTemplate GPL2 Java)     JS         -> $(embedTemplate GPL2 JS)+    Kotlin     -> $(embedTemplate GPL2 Kotlin)+    PHP        -> $(embedTemplate GPL2 PHP)     PureScript -> $(embedTemplate GPL2 PureScript)     Rust       -> $(embedTemplate GPL2 Rust)     Scala      -> $(embedTemplate GPL2 Scala)@@ -92,11 +105,14 @@     C          -> $(embedTemplate GPL3 C)     CPP        -> $(embedTemplate GPL3 CPP)     CSS        -> $(embedTemplate GPL3 CSS)+    Dart       -> $(embedTemplate GPL3 Dart)     Go         -> $(embedTemplate GPL3 Go)     Haskell    -> $(embedTemplate GPL3 Haskell)     HTML       -> $(embedTemplate GPL3 HTML)     Java       -> $(embedTemplate GPL3 Java)     JS         -> $(embedTemplate GPL3 JS)+    Kotlin     -> $(embedTemplate GPL3 Kotlin)+    PHP        -> $(embedTemplate GPL3 PHP)     PureScript -> $(embedTemplate GPL3 PureScript)     Rust       -> $(embedTemplate GPL3 Rust)     Scala      -> $(embedTemplate GPL3 Scala)@@ -105,11 +121,14 @@     C          -> $(embedTemplate MIT C)     CPP        -> $(embedTemplate MIT CPP)     CSS        -> $(embedTemplate MIT CSS)+    Dart       -> $(embedTemplate MIT Dart)     Go         -> $(embedTemplate MIT Go)     Haskell    -> $(embedTemplate MIT Haskell)     HTML       -> $(embedTemplate MIT HTML)     Java       -> $(embedTemplate MIT Java)     JS         -> $(embedTemplate MIT JS)+    Kotlin     -> $(embedTemplate MIT Kotlin)+    PHP        -> $(embedTemplate MIT PHP)     PureScript -> $(embedTemplate MIT PureScript)     Rust       -> $(embedTemplate MIT Rust)     Scala      -> $(embedTemplate MIT Scala)@@ -118,11 +137,14 @@     C          -> $(embedTemplate MPL2 C)     CPP        -> $(embedTemplate MPL2 CPP)     CSS        -> $(embedTemplate MPL2 CSS)+    Dart       -> $(embedTemplate MPL2 Dart)     Go         -> $(embedTemplate MPL2 Go)     Haskell    -> $(embedTemplate MPL2 Haskell)     HTML       -> $(embedTemplate MPL2 HTML)     Java       -> $(embedTemplate MPL2 Java)     JS         -> $(embedTemplate MPL2 JS)+    Kotlin     -> $(embedTemplate MPL2 Kotlin)+    PHP        -> $(embedTemplate MPL2 PHP)     PureScript -> $(embedTemplate MPL2 PureScript)     Rust       -> $(embedTemplate MPL2 Rust)     Scala      -> $(embedTemplate MPL2 Scala)
src/Headroom/Embedded/TH.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.Embedded.TH Description : /Template Haskell/ functions for "Headroom.Embedded"-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -18,12 +18,13 @@ module Headroom.Embedded.TH   ( embedConfigFile   , embedDefaultConfig+  , embedDefaultGlobalConfig   , embedTemplate   ) where  import           Data.FileEmbed                      ( embedStringFile )-import           Headroom.Configuration.Types        ( LicenseType(..) )+import           Headroom.Config.Types               ( LicenseType(..) ) import           Headroom.Data.EnumExtra             ( EnumExtra(..) ) import           Headroom.FileType.Types             ( FileType(..) ) import           Headroom.Meta                       ( TemplateType )@@ -44,6 +45,12 @@ -- | Embeds default configuration file to source code. embedDefaultConfig :: Q Exp embedDefaultConfig = embedStringFile "embedded/default-config.yaml"+++-- | Embeds default global configuration file to source code.+embedDefaultGlobalConfig :: Q Exp+embedDefaultGlobalConfig =+  embedStringFile "embedded/default-global-config.yaml"   -- | Embeds /template file/ to the source code.
src/Headroom/FileSupport.hs view
@@ -6,7 +6,7 @@ {-| Module      : Headroom.FileSupport Description : Support for handling various source code file types-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -30,11 +30,14 @@ import qualified Headroom.FileSupport.C             as C import qualified Headroom.FileSupport.CPP           as CPP import qualified Headroom.FileSupport.CSS           as CSS+import qualified Headroom.FileSupport.Dart          as Dart import qualified Headroom.FileSupport.Go            as Go import qualified Headroom.FileSupport.Haskell       as Haskell import qualified Headroom.FileSupport.HTML          as HTML import qualified Headroom.FileSupport.Java          as Java import qualified Headroom.FileSupport.JS            as JS+import qualified Headroom.FileSupport.Kotlin        as Kotlin+import qualified Headroom.FileSupport.PHP           as PHP import qualified Headroom.FileSupport.PureScript    as PureScript import qualified Headroom.FileSupport.Rust          as Rust import qualified Headroom.FileSupport.Scala         as Scala@@ -58,11 +61,14 @@ fileSupport C          = C.fileSupport fileSupport CPP        = CPP.fileSupport fileSupport CSS        = CSS.fileSupport+fileSupport Dart       = Dart.fileSupport fileSupport Go         = Go.fileSupport fileSupport Haskell    = Haskell.fileSupport fileSupport HTML       = HTML.fileSupport fileSupport Java       = Java.fileSupport fileSupport JS         = JS.fileSupport+fileSupport Kotlin     = Kotlin.fileSupport+fileSupport PHP        = PHP.fileSupport fileSupport PureScript = PureScript.fileSupport fileSupport Rust       = Rust.fileSupport fileSupport Scala      = Scala.fileSupport
src/Headroom/FileSupport/C.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.FileSupport.C Description : Support for /C/ source code files-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/FileSupport/CPP.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.FileSupport.CPP Description : Support for /C++/ source code files-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/FileSupport/CSS.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.FileSupport.CSS Description : Support for /CSS/ source code files-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
+ src/Headroom/FileSupport/Dart.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE QuasiQuotes       #-}++{-|+Module      : Headroom.FileSupport.Dart+Description : Support for /Dart/ source code files+Copyright   : (c) 2019-2022 Vaclav Svejcar+License     : BSD-3-Clause+Maintainer  : vaclav.svejcar@gmail.com+Stability   : experimental+Portability : POSIX++Basic support for /Dart language/ source code files. This implementation doesn't+extract any variables or template data.+-}++module Headroom.FileSupport.Dart+  ( fileSupport+  )+where++import           Headroom.Data.Regex                 ( isMatch+                                                     , re+                                                     )+import           Headroom.FileSupport.Types          ( FileSupport(..)+                                                     , SyntaxAnalysis(..)+                                                     , defaultFileSupport+                                                     )+import           Headroom.FileType.Types             ( FileType(Dart) )+++------------------------------  PUBLIC FUNCTIONS  ------------------------------++-- | Implementation of 'FileSupport' for /Dart/.+fileSupport :: FileSupport+fileSupport = defaultFileSupport Dart syntaxAnalysis+++------------------------------  PRIVATE FUNCTIONS  -----------------------------++syntaxAnalysis :: SyntaxAnalysis+syntaxAnalysis = SyntaxAnalysis { saIsCommentStart = isMatch [re|^\/\*|^\/\/|]+                                , saIsCommentEnd   = isMatch [re|\*\/$|^\/\/|]+                                }
src/Headroom/FileSupport/Go.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.FileSupport.Go Description : Support for /Go/ source code files-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -31,7 +31,7 @@  ------------------------------  PUBLIC FUNCTIONS  ------------------------------ --- | Implementation of 'FileSupport' for /C/.+-- | Implementation of 'FileSupport' for /Go/. fileSupport :: FileSupport fileSupport = defaultFileSupport Go syntaxAnalysis 
src/Headroom/FileSupport/HTML.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.FileSupport.HTML Description : Support for /HTML/ source code files-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/FileSupport/Haskell.hs view
@@ -9,7 +9,7 @@ {-| Module      : Headroom.FileSupport.Haskell Description : Support for /Haskell/ source code files-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -57,7 +57,7 @@                                                      , SyntaxAnalysis(..)                                                      ) -import           Headroom.Configuration.Types        ( HeaderConfig(..)+import           Headroom.Config.Types               ( HeaderConfig(..)                                                      , HeaderSyntax                                                      ) import           Headroom.FileType.Types             ( FileType(Haskell) )
src/Headroom/FileSupport/Haskell/Haddock.hs view
@@ -9,7 +9,7 @@ {-| Module      : Headroom.FileSupport.Haskell.Haddock Description : Extraction of /Haddock module header/ fields-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -29,7 +29,7 @@  import           Control.Applicative                 ( Alternative(..) ) import           Control.Monad                       ( ap )-import           Headroom.Configuration.Types        ( HeaderSyntax )+import           Headroom.Config.Types               ( HeaderSyntax ) import           Headroom.Data.Regex                 ( re                                                      , scan                                                      )
src/Headroom/FileSupport/JS.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.FileSupport.JS Description : Support for /Javascript/ source code files-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/FileSupport/Java.hs view
@@ -7,7 +7,7 @@ {-| Module      : Headroom.FileSupport.Java Description : Support for /Java/ source code files-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
+ src/Headroom/FileSupport/Kotlin.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes       #-}+{-# LANGUAGE TupleSections     #-}+{-# LANGUAGE TypeApplications  #-}++{-|+Module      : Headroom.FileSupport.Kotlin+Description : Support for /Kotlin/ source code files+Copyright   : (c) 2019-2022 Vaclav Svejcar+License     : BSD-3-Clause+Maintainer  : vaclav.svejcar@gmail.com+Stability   : experimental+Portability : POSIX++Support for /Kotlin/ source code files. This implementation extracts /Kotlin/+package name as variable.++= Extracted Variables for Templates+This implementation extracts following variables from source code file:++* @___kotlin_package_name__@ - name of the /Kotlin/ package++= Extracted Custom Data+This implementation does not extract any custom data from template file.+-}++module Headroom.FileSupport.Kotlin+  ( fileSupport+  )+where++import           Headroom.Data.Regex                 ( isMatch+                                                     , match+                                                     , re+                                                     )+import           Headroom.FileSupport.TemplateData   ( TemplateData(..) )+import           Headroom.FileSupport.Types          ( FileSupport(..)+                                                     , SyntaxAnalysis(..)+                                                     )+import           Headroom.FileType.Types             ( FileType(Kotlin) )+import           Headroom.Header.Types               ( HeaderTemplate )+import           Headroom.SourceCode                 ( LineType(..)+                                                     , SourceCode(..)+                                                     , firstMatching+                                                     )+import           Headroom.Variables                  ( mkVariables )+import           Headroom.Variables.Types            ( Variables(..) )+import           RIO+import           RIO.Lens                            ( ix )+++------------------------------  PUBLIC FUNCTIONS  ------------------------------++-- | Implementation of 'FileSupport' for /Kotlin/.+fileSupport :: FileSupport+fileSupport = FileSupport+  { fsSyntaxAnalysis      = syntaxAnalysis+  , fsExtractTemplateData = const . const $ NoTemplateData+  , fsExtractVariables    = extractVariables+  , fsFileType            = Kotlin+  }+++------------------------------  PRIVATE FUNCTIONS  -----------------------------++syntaxAnalysis :: SyntaxAnalysis+syntaxAnalysis = SyntaxAnalysis { saIsCommentStart = isMatch [re|^\/\*|^\/\/|]+                                , saIsCommentEnd   = isMatch [re|\*\/$|^\/\/|]+                                }+++extractVariables :: HeaderTemplate+                 -> Maybe (Int, Int)+                 -> SourceCode+                 -> Variables+extractVariables _ _ source = (mkVariables . catMaybes)+  [("_kotlin_package_name", ) <$> extractPackageName source]+++extractPackageName :: SourceCode -> Maybe Text+extractPackageName = fmap snd . firstMatching f+ where+  f (lt, l) | lt == Code = match [re|^package (.*)$|] l >>= (^? ix 1)+            | otherwise  = Nothing
+ src/Headroom/FileSupport/PHP.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE QuasiQuotes       #-}++{-|+Module      : Headroom.FileSupport.PHP+Description : Support for /PHP/ source code files+Copyright   : (c) 2019-2022 Vaclav Svejcar+License     : BSD-3-Clause+Maintainer  : vaclav.svejcar@gmail.com+Stability   : experimental+Portability : POSIX++Basic support for /PHP/ source code files. This implementation doesn't+extract any variables or template data.+-}++module Headroom.FileSupport.PHP+  ( fileSupport+  )+where++import           Headroom.Data.Regex                 ( isMatch+                                                     , re+                                                     )+import           Headroom.FileSupport.Types          ( FileSupport(..)+                                                     , SyntaxAnalysis(..)+                                                     , defaultFileSupport+                                                     )+import           Headroom.FileType.Types             ( FileType(PHP) )+++------------------------------  PUBLIC FUNCTIONS  ------------------------------++-- | Implementation of 'FileSupport' for /Javascript/.+fileSupport :: FileSupport+fileSupport = defaultFileSupport PHP syntaxAnalysis+++------------------------------  PRIVATE FUNCTIONS  -----------------------------++syntaxAnalysis :: SyntaxAnalysis+syntaxAnalysis = SyntaxAnalysis { saIsCommentStart = isMatch [re|^\/\*|^\/\/|]+                                , saIsCommentEnd   = isMatch [re|\*\/$|^\/\/|]+                                }
src/Headroom/FileSupport/PureScript.hs view
@@ -9,7 +9,7 @@ {-| Module      : Headroom.FileSupport.PureScript Description : Support for /PureScript/ source code files-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/FileSupport/Rust.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.FileSupport.Rust Description : Support for /Rust/ source code files-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/FileSupport/Scala.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.FileSupport.Scala Description : Support for /Scala/ source code files-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/FileSupport/Shell.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.FileSupport.Shell Description : Support for /Shell/ source code files-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/FileSupport/TemplateData.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.FileSupport.TemplateData Description : Custom data specific to file support implementations-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/FileSupport/Types.hs view
@@ -5,7 +5,7 @@ {-| Module      : Headroom.FileSupport.Types Description : Data types for "Headroom.FileSupport" module-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -27,7 +27,7 @@   ) where -import           Headroom.Configuration.Types        ( HeaderSyntax )+import           Headroom.Config.Types               ( HeaderSyntax ) import           Headroom.FileSupport.TemplateData   ( TemplateData(..) ) import           Headroom.FileType.Types             ( FileType ) import           Headroom.Header.Types               ( HeaderTemplate )
src/Headroom/FileType.hs view
@@ -5,7 +5,7 @@ {-| Module      : Headroom.FileType Description : Logic for handlig supported file types-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -22,7 +22,7 @@   ) where -import           Headroom.Configuration.Types        ( CtHeaderConfig+import           Headroom.Config.Types               ( CtHeaderConfig                                                      , CtHeadersConfig                                                      , HeaderConfig(..)                                                      , HeadersConfig(..)@@ -33,48 +33,41 @@ import qualified RIO.List                           as L  - -- | Returns 'FileType' for given file extension (without dot), using configured -- values from the 'HeadersConfig'.-fileTypeByExt :: CtHeadersConfig-              -- ^ license headers configuration-              -> Text-              -- ^ file extension (without dot)-              -> Maybe FileType-              -- ^ found 'FileType'+fileTypeByExt :: CtHeadersConfig -- ^ license headers configuration+              -> Text            -- ^ file extension (without dot)+              -> Maybe FileType  -- ^ found 'FileType' fileTypeByExt config ext =   L.find (elem ext . listExtensions config) (allValues @FileType)   -- | Lists all recognized file extensions for given 'FileType', using configured -- values from the 'HeadersConfig'.-listExtensions :: CtHeadersConfig-               -- ^ license headers configuration-               -> FileType-               -- ^ 'FileType' for which to list extensions-               -> [Text]-               -- ^ list of appropriate file extensions+listExtensions :: CtHeadersConfig -- ^ license headers configuration+               -> FileType        -- ^ 'FileType' for which to list extensions+               -> [Text]          -- ^ list of appropriate file extensions listExtensions config fileType =   hcFileExtensions (configByFileType config fileType)   -- | Returns the proper 'HeaderConfig' for the given 'FileType', selected -- from the 'HeadersConfig'.-configByFileType :: CtHeadersConfig-                 -- ^ license headers configuration-                 -> FileType-                 -- ^ selected 'FileType'-                 -> CtHeaderConfig-                 -- ^ appropriate 'HeaderConfig'+configByFileType :: CtHeadersConfig -- ^ license headers configuration+                 -> FileType        -- ^ selected 'FileType'+                 -> CtHeaderConfig  -- ^ appropriate 'HeaderConfig' configByFileType HeadersConfig {..} fileType = case fileType of   C          -> hscC   CPP        -> hscCpp   CSS        -> hscCss+  Dart       -> hscDart   Go         -> hscGo   Haskell    -> hscHaskell   HTML       -> hscHtml   Java       -> hscJava   JS         -> hscJs+  Kotlin     -> hscKotlin+  PHP        -> hscPhp   PureScript -> hscPureScript   Rust       -> hscRust   Scala      -> hscScala
src/Headroom/FileType/Types.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.FileType.Types Description : Data types for "Headroom.FileType"-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -18,30 +18,22 @@ import           Headroom.Data.EnumExtra             ( EnumExtra(..) ) import           RIO + -- | Supported type of source code file. data FileType-  = C-  -- ^ support for /C/ programming language-  | CPP-  -- ^ support for /C++/ programming language-  | CSS-  -- ^ support for /CSS/-  | Go-  -- ^ support for /Go/ programming language-  | Haskell-  -- ^ support for /Haskell/ programming language-  | HTML-  -- ^ support for /HTML/-  | Java-  -- ^ support for /Java/ programming language-  | JS-  -- ^ support for /JavaScript/ programming language-  | PureScript-  -- ^ support for /PureScript/ programming language-  | Rust-  -- ^ support for /Rust/ programming language-  | Scala-  -- ^ support for /Scala/ programming language-  | Shell-  -- ^ support for /Shell/+  = C          -- ^ support for /C/ programming language+  | CPP        -- ^ support for /C++/ programming language+  | CSS        -- ^ support for /CSS/+  | Dart       -- ^ support for /Dart/ programming language+  | Go         -- ^ support for /Go/ programming language+  | Haskell    -- ^ support for /Haskell/ programming language+  | HTML       -- ^ support for /HTML/+  | Java       -- ^ support for /Java/ programming language+  | JS         -- ^ support for /JavaScript/ programming language+  | Kotlin     -- ^ support for /Kotlin/ programming language+  | PHP        -- ^ support for /PHP/ programming language+  | PureScript -- ^ support for /PureScript/ programming language+  | Rust       -- ^ support for /Rust/ programming language+  | Scala      -- ^ support for /Scala/ programming language+  | Shell      -- ^ support for /Shell/   deriving (Bounded, Enum, EnumExtra, Eq, Ord, Show)
src/Headroom/Header.hs view
@@ -9,7 +9,7 @@ {-| Module      : Headroom.Header Description : Operations with copyright/license headers-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -35,12 +35,10 @@   ) where -import           Headroom.Configuration.Types        ( CtHeaderConfig+import           Headroom.Config.Types               ( CtHeaderConfig                                                      , CtHeadersConfig                                                      , HeaderConfig(..)-                                                     , HeaderConfig(..)                                                      , HeaderSyntax(..)-                                                     , HeaderSyntax(..)                                                      ) import           Headroom.Data.Coerce                ( coerce                                                      , inner@@ -181,7 +179,6 @@ -- Based on the 'HeaderSyntax' specified in given 'HeaderConfig', this function -- delegates its work to either 'findBlockHeader' or 'findLineHeader'. ----- >>> :set -XFlexibleContexts -XTypeFamilies -XQuasiQuotes -- >>> import Headroom.Data.Regex (re) -- >>> let hc = HeaderConfig ["hs"] 0 0 0 0 [] [] (BlockComment [re|^{-|] [re|(?<!#)-}$|] Nothing) -- >>> findHeader hc $ SourceCode [(Code, "foo"), (Code, "bar"), (Comment, "{- HEADER -}")]@@ -203,7 +200,6 @@ -- | Finds header in the form of /multi-line comment/ syntax, which is delimited -- with starting and ending pattern. ----- >>> :set -XQuasiQuotes -- >>> import Headroom.Data.Regex (re) -- >>> let sc = SourceCode [(Code, ""), (Comment, "{- HEADER -}"), (Code, ""), (Code,"")] -- >>> findBlockHeader [re|^{-|] [re|(?<!#)-}$|] sc 0@@ -236,7 +232,6 @@ -- | Finds header in the form of /single-line comment/ syntax, which is -- delimited with the prefix pattern. ----- >>> :set -XQuasiQuotes -- >>> import Headroom.Data.Regex (re) -- >>> let sc = SourceCode [(Code, ""), (Code, "a"), (Comment, "-- first"), (Comment, "-- second"), (Code, "foo")] -- >>> findLineHeader [re|^--|] sc 0@@ -272,7 +267,6 @@ -- If both first and second patterns are empty, then all lines are returned in -- the middle part. ----- >>> :set -XQuasiQuotes -- >>> import Headroom.Data.Regex (re) -- -- >>> let ls = [(Code, "text"), (Code, "->"), (Code, "RESULT"), (Code, "<-"), (Code, "foo")]
src/Headroom/Header/Sanitize.hs view
@@ -5,7 +5,7 @@ {-| Module      : Headroom.Header.Sanitize Description : Logic for sanitizing license headers-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -26,7 +26,7 @@   ) where -import           Headroom.Configuration.Types        ( HeaderSyntax(..) )+import           Headroom.Config.Types               ( HeaderSyntax(..) ) import qualified Headroom.Data.Regex                as R import qualified Headroom.Data.Text                 as T import           RIO@@ -41,7 +41,6 @@ -- syntax (just the syntax for comment itself - like @//@ or @--@). If such -- prefix is found, it's then added to the input 'HeaderSyntax'. ----- >>> :set -XQuasiQuotes -- >>> import Headroom.Data.Regex (re) -- >>> findPrefix (BlockComment [re|^\/\*|] [re|\*\/$|] Nothing) "/*\n * foo\n * bar\n */" -- BlockComment "^\\/\\*" "\\*\\/$" (Just " *")@@ -65,7 +64,6 @@ -- comments, this is to make it visually unified, but for line comments it's -- necessary in order not to break syntax of target source code file. ----- >>> :set -XQuasiQuotes -- >>> import Headroom.Data.Regex (re) -- >>> sanitizeSyntax (LineComment [re|^--|] (Just "--")) "-- foo\nbar" -- "-- foo\n-- bar"@@ -87,7 +85,6 @@  -- | Strips comment syntax from given text. ----- >>> :set -XQuasiQuotes -- >>> import Headroom.Data.Regex (re) -- >>> stripCommentSyntax (LineComment [re|^--|] (Just "--")) "-- a\n-- b" -- "a\n b"
src/Headroom/Header/Types.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.Header.Types Description : Data types for "Headroom.Header"-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -20,7 +20,7 @@   ) where -import           Headroom.Configuration.Types        ( CtHeaderConfig )+import           Headroom.Config.Types               ( CtHeaderConfig ) import           Headroom.FileSupport.TemplateData   ( TemplateData ) import           Headroom.FileType.Types             ( FileType ) import           Headroom.Meta                       ( TemplateType )
src/Headroom/IO/FileSystem.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.IO.FileSystem Description : File system related IO operations-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -22,8 +22,10 @@   , FindFilesByExtsFn   , FindFilesByTypesFn   , GetCurrentDirectoryFn+  , GetUserDirectoryFn   , ListFilesFn   , LoadFileFn+  , WriteFileFn     -- * Polymorphic Record   , FileSystem(..)   , mkFileSystem@@ -40,18 +42,19 @@   ) where -import           Headroom.Configuration.Types        ( CtHeadersConfig )+import           Headroom.Config.Types               ( CtHeadersConfig ) import           Headroom.Data.Regex                 ( Regex                                                      , match                                                      ) import           Headroom.FileType                   ( listExtensions ) import           Headroom.FileType.Types             ( FileType ) import           RIO-import           RIO.Directory                       ( createDirectory+import           RIO.Directory                       ( createDirectoryIfMissing                                                      , doesDirectoryExist                                                      , doesFileExist                                                      , getCurrentDirectory                                                      , getDirectoryContents+                                                     , getHomeDirectory                                                      ) import           RIO.FilePath                        ( isExtensionOf                                                      , takeExtension@@ -65,54 +68,40 @@  -- | Type of a function that creates new empty directory on the given path. type CreateDirectoryFn m-  =  FilePath-  -- ^ path of new directory-  -> m ()-  -- ^ /IO/ action result+  =  FilePath -- ^ path of new directory+  -> m ()     -- ^ /IO/ action result   -- | Type of a function that returns 'True' if the argument file exists and is -- not a directory, and 'False' otherwise. type DoesFileExistFn m-  =  FilePath-  -- ^ path to check-  -> m Bool-  -- ^ whether the given path is existing file+  =  FilePath -- ^ path to check+  -> m Bool   -- ^ whether the given path is existing file   -- | Type of a function that recursively finds files on given path whose -- filename matches the predicate. type FindFilesFn m-  =  FilePath-  -- ^ path to search-  -> (FilePath -> Bool)-  -- ^ predicate to match filename-  -> m [FilePath]-  -- ^ found files+  =  FilePath           -- ^ path to search+  -> (FilePath -> Bool) -- ^ predicate to match filename+  -> m [FilePath]       -- ^ found files   -- | Type of a function that recursively finds files on given path by file -- extensions. type FindFilesByExtsFn m-  =  FilePath-  -- ^ path to search-  -> [Text]-  -- ^ list of file extensions (without dot)-  -> m [FilePath]-  -- ^ list of found files+  =  FilePath     -- ^ path to search+  -> [Text]       -- ^ list of file extensions (without dot)+  -> m [FilePath] -- ^ list of found files   -- | Type of a function that recursively find files on given path by their -- file types. type FindFilesByTypesFn m-  =  CtHeadersConfig-  -- ^ configuration of license headers-  -> [FileType]-  -- ^ list of file types-  -> FilePath-  -- ^ path to search-  -> m [FilePath]-  -- ^ list of found files+  =  CtHeadersConfig -- ^ configuration of license headers+  -> [FileType]      -- ^ list of file types+  -> FilePath        -- ^ path to search+  -> m [FilePath]    -- ^ list of found files   -- | Type of a function that obtains the current working directory as an@@ -120,21 +109,29 @@ type GetCurrentDirectoryFn m = m FilePath  +-- | Type of a function that obtains the user's home directory as an absolute+-- path.+type GetUserDirectoryFn m = m FilePath++ -- | Type of a function that recursively find all files on given path. If file -- reference is passed instead of directory, such file path is returned. type ListFilesFn m-  =  FilePath-  -- ^ path to search-  -> m [FilePath]-  -- ^ list of found files+  =  FilePath     -- ^ path to search+  -> m [FilePath] -- ^ list of found files --- | Type of a function that loads file content in UTF8 encoding.+-- | Type of a function that loads file content in UTF-8 encoding. type LoadFileFn m-  =  FilePath-  -- ^ file path-  -> m Text-  -- ^ file content+  =  FilePath -- ^ file path+  -> m Text   -- ^ file content ++-- | Type of a function that writes file content in UTF-8 encoding.+type WriteFileFn m+  =  FilePath -- ^ file path+  -> Text    -- ^ file content+  -> m ()    -- ^ write result+ -----------------------------  POLYMORPHIC RECORD  -----------------------------  -- | /Polymorphic record/ composed of file system /IO/ function types, allowing@@ -158,24 +155,30 @@   -- ^ Function that recursively find files on given path by their file types.   , fsGetCurrentDirectory :: GetCurrentDirectoryFn m   -- ^ Function that obtains the current working directory as an absolute path.+  , fsGetUserDirectory    :: GetUserDirectoryFn m+  -- ^ Function that obtains the user's home directory as an absolute path.   , fsListFiles           :: ListFilesFn m   -- ^ Function that recursively find all files on given path. If file reference   -- is passed instead of directory, such file path is returned.   , fsLoadFile            :: LoadFileFn m-  -- ^ Function that loads file content in UTF8 encoding.+  -- ^ Function that loads file content in UTF-8 encoding.+  , fsWriteFile           :: WriteFileFn m+  -- ^ Function that writes file content in UTF-8 encoding.   }   -- | Creates new 'FileSystem' that performs actual disk /IO/ operations. mkFileSystem :: MonadIO m => FileSystem m-mkFileSystem = FileSystem { fsCreateDirectory     = createDirectory+mkFileSystem = FileSystem { fsCreateDirectory = createDirectoryIfMissing True                           , fsDoesFileExist       = doesFileExist                           , fsFindFiles           = findFiles                           , fsFindFilesByExts     = findFilesByExts                           , fsFindFilesByTypes    = findFilesByTypes                           , fsGetCurrentDirectory = getCurrentDirectory+                          , fsGetUserDirectory    = getHomeDirectory                           , fsListFiles           = listFiles                           , fsLoadFile            = loadFile+                          , fsWriteFile           = writeFileUtf8                           }  @@ -235,7 +238,6 @@ -- | Takes list of patterns and file paths and returns list of file paths where -- those matching the given patterns are excluded. ----- >>> :set -XQuasiQuotes -- >>> import Headroom.Data.Regex (re) -- >>> excludePaths [[re|\.hidden|], [re|zzz|]] ["foo/.hidden", "test/bar", "x/zzz/e"] -- ["test/bar"]
+ src/Headroom/IO/KVStore.hs view
@@ -0,0 +1,193 @@+{-# LANGUAGE DataKinds                  #-}+{-# LANGUAGE DerivingStrategies         #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE GADTs                      #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses      #-}+{-# LANGUAGE NoImplicitPrelude          #-}+{-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE QuasiQuotes                #-}+{-# LANGUAGE RankNTypes                 #-}+{-# LANGUAGE StandaloneDeriving         #-}+{-# LANGUAGE StrictData                 #-}+{-# LANGUAGE TemplateHaskell            #-}+{-# LANGUAGE TypeApplications           #-}+{-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE UndecidableInstances       #-}++{-|+Module      : Headroom.IO.KVStore+Description : Key-value persistent store+Copyright   : (c) 2019-2022 Vaclav Svejcar+License     : BSD-3-Clause+Maintainer  : vaclav.svejcar@gmail.com+Stability   : experimental+Portability : POSIX++This is really simple /key-value/ persistent store that uses /SQLite/ as a+backend. Main goal is to provide /type-safe/ way how to define value keys, that+can be later used to set/put the actual value into the store.+-}++module Headroom.IO.KVStore+  ( -- * Type Aliases+    GetValueFn+  , PutValueFn+  , KVStore(..)+    -- * Type Classes+  , ValueCodec(..)+    -- * Data Types+  , ValueKey(..)+  , StorePath(..)+    -- * Public Functions+  , inMemoryKVStore+  , sqliteKVStore+  , valueKey+  )+where++import           Database.Persist                    ( PersistStoreRead(..)+                                                     , PersistStoreWrite(..)+                                                     )+import           Database.Persist.Sqlite             ( runMigrationSilent+                                                     , runSqlite+                                                     )+import           Database.Persist.TH                 ( mkMigrate+                                                     , mkPersist+                                                     , persistLowerCase+                                                     , share+                                                     , sqlSettings+                                                     )+import           RIO+import qualified RIO.Map                            as M+import qualified RIO.Text                           as T+import           RIO.Time                            ( UTCTime+                                                     , defaultTimeLocale+                                                     , formatTime+                                                     , parseTimeM+                                                     )++------------------------------  TEMPLATE HASKELL  ------------------------------++share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|+StoreRecord+  Id Text+  value Text+  deriving Show+|]+++--------------------------------  TYPE ALIASES  --------------------------------++-- | Gets the value for given 'ValueKey' from the store.+type GetValueFn m+  =  forall a+   . (ValueCodec a)+  => ValueKey a  -- ^ key for the value+  -> m (Maybe a) -- ^ value (if found)+++-- | Puts the value for given 'ValueKey' into the store.+type PutValueFn m+  =  forall a+   . (ValueCodec a)+  => ValueKey a -- ^ key for the value+  -> a          -- ^ value to put into store+  -> m ()       -- ^ operation result+++-----------------------------  POLYMORPHIC RECORD  -----------------------------++-- | /Polymorphic record/ composed of /key-value/ store operations, allowing to+-- abstract over concrete implementation without (ab)using /type classes/.+data KVStore m = KVStore+  { kvGetValue :: GetValueFn m+  , kvPutValue :: PutValueFn m+  }+++-- | Constructs persistent instance of 'KVStore' that uses /SQLite/ as a backend.+sqliteKVStore :: MonadIO m+              => StorePath -- ^ path of the store location+              -> KVStore m -- ^ store instance+sqliteKVStore sp =+  KVStore { kvGetValue = getValueSQLite sp, kvPutValue = putValueSQLite sp }+++-- | Constructs non-persistent in-memory instance of 'KVStore'.+inMemoryKVStore :: MonadIO m => m (KVStore m)+inMemoryKVStore = do+  ref <- newIORef M.empty+  pure KVStore { kvGetValue = getValueInMemory ref+               , kvPutValue = putValueInMemory ref+               }++--------------------------------  TYPE CLASSES  --------------------------------++-- | Represents way how to encode/decode concrete types into textual+-- representation used by the store to hold values.+class ValueCodec a where++  -- | Encodes value into textual representation.+  encodeValue :: a    -- ^ value to encode+              -> Text -- ^ textual representation+++  -- | Decodes value from textual representation.+  decodeValue :: Text    -- ^ value to decode+              -> Maybe a -- ^ decoded value (if available)+++instance ValueCodec Text where+  encodeValue = id+  decodeValue = Just++instance ValueCodec UTCTime where+  encodeValue = T.pack . formatTime defaultTimeLocale "%FT%T%Q"+  decodeValue = parseTimeM True defaultTimeLocale "%FT%T%Q" . T.unpack++---------------------------------  DATA TYPES  ---------------------------------++-- | /Type-safe/ representation of the key for specific value.+newtype ValueKey a = ValueKey Text deriving (Eq, Show)+++-- | Constructor function for 'ValueKey'.+valueKey :: Text -> ValueKey a+valueKey = ValueKey+++-- | Path to the store (e.g. path of the /SQLite/ database on filesystem).+newtype StorePath = StorePath Text deriving (Eq, Show)+++------------------------------  PRIVATE FUNCTIONS  -----------------------------++getValueInMemory :: MonadIO m => IORef (Map Text Text) -> GetValueFn m+getValueInMemory ref (ValueKey key) = do+  storeMap <- readIORef ref+  pure $ M.lookup key storeMap >>= decodeValue+++putValueInMemory :: MonadIO m => IORef (Map Text Text) -> PutValueFn m+putValueInMemory ref (ValueKey key) value = do+  modifyIORef ref $ M.insert key (encodeValue value)+  pure ()+++getValueSQLite :: MonadIO m => StorePath -> GetValueFn m+getValueSQLite (StorePath path) (ValueKey key) = do+  liftIO . runSqlite path $ do+    _          <- runMigrationSilent migrateAll+    maybeValue <- get $ StoreRecordKey key+    case maybeValue of+      Just (StoreRecord v) -> pure . decodeValue $ v+      Nothing              -> pure Nothing+++putValueSQLite :: MonadIO m => StorePath -> PutValueFn m+putValueSQLite (StorePath path) (ValueKey key) value = do+  liftIO . runSqlite path $ do+    _ <- runMigrationSilent migrateAll+    repsert (StoreRecordKey key) (StoreRecord $ encodeValue value)
src/Headroom/IO/Network.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE LambdaCase        #-} {-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes       #-} {-# LANGUAGE TypeApplications  #-} {-# LANGUAGE TypeFamilies      #-}@@ -7,7 +8,7 @@ {-| Module      : Headroom.IO.Network Description : Network related IO operations-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -25,10 +26,17 @@   , mkNetwork     -- * Network IO operations   , downloadContent+  , -- * Error Data Types+    NetworkError(..)   ) where  import           Data.String.Interpolate             ( i )+import           Headroom.Meta                       ( buildVersion+                                                     , productName+                                                     , productVendor+                                                     )+import           Headroom.Meta.Version               ( printVersion ) import           Headroom.Types                      ( fromHeadroomError                                                      , toHeadroomError                                                      )@@ -40,24 +48,26 @@                                                      , NoReqBody(NoReqBody)                                                      , bsResponse                                                      , defaultHttpConfig+                                                     , header                                                      , req                                                      , responseBody                                                      , runReq                                                      , useURI                                                      )+import qualified Network.HTTP.Req                   as Req import qualified Network.HTTP.Types.Status          as HC import           RIO import qualified RIO.Text                           as T-import           Text.URI                            ( URI ) import qualified Text.URI                           as URI+import           Text.URI                            ( URI )   --------------------------------  TYPE ALIASES  --------------------------------  -- | Type of a function that returns content of remote resource. type DownloadContentFn m-  =  URI    -- ^ /URI/ of remote resource-  -> m Text -- ^ downloaded content+  =  URI          -- ^ /URI/ of remote resource+  -> m ByteString -- ^ downloaded content   -----------------------------  POLYMORPHIC RECORD  -----------------------------@@ -75,20 +85,23 @@  ------------------------------  PUBLIC FUNCTIONS  ------------------------------ --- | Downloads content of remote resource as 'Text'. Note that only @http@ and--- @https@ is supported at this moment.+-- | Downloads content of remote resource as 'ByteString'. Note that only+-- @http@ and @https@ protocols are supported at this moment. downloadContent :: MonadIO m-                => URI    -- ^ /URI/ of remote resource-                -> m Text -- ^ downloaded content+                => URI          -- ^ /URI/ of remote resource+                -> m ByteString -- ^ downloaded content downloadContent uri = runReq defaultHttpConfig $ do   response <- httpGet uri-  case T.decodeUtf8' $ responseBody response of-    Left  err  -> throwM $ InvalidResponse uri (T.pack $ displayException err)-    Right body -> pure body-+  pure $ responseBody response  ------------------------------  PRIVATE FUNCTIONS  ----------------------------- +headers :: Req.Option scheme+headers = header "User-Agent" $ encodeUtf8 ua+ where+  ua = productVendor <> "/" <> productName <> "-" <> printVersion buildVersion++ httpGet :: (MonadHttp m, MonadThrow m, MonadUnliftIO m) => URI -> m BsResponse httpGet uri = do   urlE      <- maybe (throwM $ InvalidURL uri) pure (useURI uri)@@ -99,7 +112,7 @@     Left  err -> handleHttpException uri err     Right res -> pure res  where-  doGet = \u -> try @_ @HttpException $ req GET u NoReqBody bsResponse mempty+  doGet u = try @_ @HttpException $ req GET u NoReqBody bsResponse headers   handleHttpException :: MonadThrow m => URI -> HttpException -> m BsResponse@@ -119,9 +132,8 @@ -- | Error related to network operations. data NetworkError   = ConnectionFailure URI Text -- ^ connection failure-  | InvalidResponse URI Text        -- ^ error during obtaining response-  | InvalidStatus URI Int Text      -- ^ invalid response status-  | InvalidURL URI                  -- ^ given /URI/ is not valid+  | InvalidStatus URI Int Text -- ^ invalid response status+  | InvalidURL URI             -- ^ given /URI/ is not valid   deriving (Eq, Show)  @@ -134,8 +146,6 @@ displayException' :: NetworkError -> String displayException' = \case   ConnectionFailure uri ex -> [i|Error connecting to #{URI.render uri}: #{ex}|]-  InvalidResponse uri reason ->-    [i|Cannot decode response for '#{URI.render uri}': #{reason}|]   InvalidStatus uri status message ->     [i|Error downloading #{URI.render uri}: #{status} #{message}|]   InvalidURL uri -> [i|Cannot build URL from input URI: #{URI.render uri}|]
src/Headroom/Meta.hs view
@@ -5,7 +5,7 @@ {-| Module      : Headroom.Meta Description : Application metadata (name, vendor, etc.)-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -20,9 +20,13 @@   , buildVersion   , configBreakingChanges   , configFileName+  , cacheFileName+  , globalConfigDirName+  , globalConfigFileName   , productDesc   , productInfo   , productName+  , productVendor   , webDoc   , webDocConfigCurr   , webDocMigration@@ -63,6 +67,21 @@ configFileName = ".headroom.yaml"  +-- | Name of the global configuration directory+globalConfigDirName :: IsString a => a+globalConfigDirName = ".headroom"+++-- | Name of the YAML global configuration file.+globalConfigFileName :: IsString a => a+globalConfigFileName = "global-config.yaml"+++-- | Name of the global cache file.+cacheFileName :: IsString a => a+cacheFileName = "cache.sqlite"++ -- | Full product description. productDesc :: Text productDesc = "manage your source code license headers"@@ -78,6 +97,9 @@ productName :: Text productName = "headroom" +-- | Product vendor.+productVendor :: IsString a => a+productVendor = "norcane"  -- | Product documentation website for given version. webDoc :: Version -> Text
src/Headroom/Meta/Version.hs view
@@ -1,14 +1,14 @@-{-# LANGUAGE BangPatterns      #-}-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes       #-}-{-# LANGUAGE StrictData        #-}-{-# LANGUAGE TemplateHaskell   #-}+{-# LANGUAGE BangPatterns          #-}+{-# LANGUAGE NoImplicitPrelude     #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE QuasiQuotes           #-}+{-# LANGUAGE StrictData            #-}+{-# LANGUAGE TemplateHaskellQuotes #-}  {-| Module      : Headroom.Meta.Version Description : Type safe representation of Haskell PVP version-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -80,7 +80,7 @@              -> Maybe Version              -- ^ parsed 'Version' parseVersion raw = do-  groups <- match [re|^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$|] raw+  groups <- match [re|^v?([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$|] raw   check . catMaybes $ T.read <$> groups  where   check [ma1, ma2, mi, p] = Just $ Version ma1 ma2 mi p
src/Headroom/PostProcess.hs view
@@ -15,7 +15,7 @@ {-| Module      : Headroom.PostProcess Description : Support for /post-processors/-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -37,7 +37,7 @@   ) where -import           Headroom.Configuration.Types        ( CtPostProcessConfigs+import           Headroom.Config.Types               ( CtPostProcessConfigs                                                      , PostProcessConfig(..)                                                      , PostProcessConfigs(..)                                                      , UpdateCopyrightConfig(..)@@ -65,46 +65,6 @@ suffixLensesFor ["ppcConfig"] ''PostProcessConfig  --- | Runs the /post-processing function/ using the given /environment/ and text--- of rendered /license header/ as input.-postProcess :: PostProcess env-            -- ^ /post-processor/ to run-            -> env-            -- ^ environment value-            -> Text-            -- ^ text of rendered /license header/-            -> Text-            -- ^ processed text of /license header/-postProcess (PostProcess fn) env input = runReader (fn input) env----- | Composition of various /post-processors/, which environment is--- based on /YAML/ configuration and which can be enabled/disabled to fit--- end user's needs.-configuredPostProcess :: (Has CurrentYear env, Has UpdateCopyrightMode env)-                      => CtPostProcessConfigs-                      -- ^ configuration of /post-processors/-                      -> PostProcess env-                      -- ^ composed /post-processor/-configuredPostProcess PostProcessConfigs {..} = mconcat-  [ifEnabled ppcsUpdateCopyright updateCopyright]- where-  ifEnabled PostProcessConfig {..} fn | ppcEnabled = fn-                                      | otherwise  = mempty----- | Takes already rendered /license header/ and post-process it based on the--- given configuration.-postProcessHeader :: ConfiguredEnv-                  -- ^ configuration used to define post-processing behaviour-                  -> Text-                  -- ^ rendered text of /license header/-                  -> Text-                  -- ^ post-processed text of /license header/-postProcessHeader env =-  postProcess (configuredPostProcess (cePostProcessConfigs env)) env-- -- | Environemnt data type for the composed /post-processor/ -- ('configuredPostProcess'). data ConfiguredEnv = ConfiguredEnv@@ -148,6 +108,46 @@   mode     = \configs' -> maybe UpdateAllAuthors                                 (UpdateSelectedAuthors . SelectedAuthors)                                 (configs' ^. authorsL)+++-- | Runs the /post-processing function/ using the given /environment/ and text+-- of rendered /license header/ as input.+postProcess :: PostProcess env+            -- ^ /post-processor/ to run+            -> env+            -- ^ environment value+            -> Text+            -- ^ text of rendered /license header/+            -> Text+            -- ^ processed text of /license header/+postProcess (PostProcess fn) env input = runReader (fn input) env+++-- | Composition of various /post-processors/, which environment is+-- based on /YAML/ configuration and which can be enabled/disabled to fit+-- end user's needs.+configuredPostProcess :: (Has CurrentYear env, Has UpdateCopyrightMode env)+                      => CtPostProcessConfigs+                      -- ^ configuration of /post-processors/+                      -> PostProcess env+                      -- ^ composed /post-processor/+configuredPostProcess PostProcessConfigs {..} = mconcat+  [ifEnabled ppcsUpdateCopyright updateCopyright]+ where+  ifEnabled PostProcessConfig {..} fn | ppcEnabled = fn+                                      | otherwise  = mempty+++-- | Takes already rendered /license header/ and post-process it based on the+-- given configuration.+postProcessHeader :: ConfiguredEnv+                  -- ^ configuration used to define post-processing behaviour+                  -> Text+                  -- ^ rendered text of /license header/+                  -> Text+                  -- ^ post-processed text of /license header/+postProcessHeader env =+  postProcess (configuredPostProcess (cePostProcessConfigs env)) env   ------------------------------  PRIVATE FUNCTIONS  -----------------------------
src/Headroom/PostProcess/Types.hs view
@@ -3,7 +3,7 @@ {-| Module      : Headroom.PostProcess.Types Description : Data types for /post-processing/-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/PostProcess/UpdateCopyright.hs view
@@ -8,7 +8,7 @@ {-| Module      : Headroom.PostProcess.UpdateCopyright Description : /Post-processor/ for updating years in copyrights-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -29,6 +29,7 @@   ) where +import           Data.String.Interpolate             ( i ) import           Headroom.Data.Has                   ( Has(..) ) import           Headroom.Data.Regex                 ( re                                                      , replace@@ -45,7 +46,6 @@  ---------------------------------  DATA TYPES  --------------------------------- - -- | Non-empty list of authors for which to update years in their copyrights. newtype SelectedAuthors = SelectedAuthors (NonEmpty Text) deriving (Eq, Show) @@ -59,7 +59,6 @@  ------------------------------  PUBLIC FUNCTIONS  ------------------------------ - -- | /Post-processor/ that updates years and year ranges in any -- present copyright statements. --@@ -96,15 +95,21 @@ updateYears :: CurrentYear -- ^ current year             -> Text        -- ^ text to update             -> Text        -- ^ text with updated years-updateYears (CurrentYear year) = processYear . processRange+updateYears cy = replace [re|(\d{4})(?:-)?(\d{4})?|] go  where-  processYear  = replace [re|(?!\d{4}-)(?<!-)(\d{4})|] processYear'-  processRange = replace [re|(\d{4})-(\d{4})|] processRange'-  replaceYear curr | read curr == Just year = tshow year-                   | otherwise              = mconcat [curr, "-", tshow year]-  replaceRange full fY tY | read tY == Just year = full-                          | otherwise            = mconcat [fY, "-", tshow year]-  processYear' _    (curr : _) = replaceYear curr-  processYear' full _          = full-  processRange' full (fromY : toY : _) = replaceRange full fromY toY-  processRange' full _                 = full+  go _ [r1] | (Just y1) <- read r1 = bumpYear cy y1+  go _ rs@[_, _] | [Just y1, Just y2] <- read <$> rs = bumpRange cy y1 y2+  go other _                       = other+++------------------------------  PRIVATE FUNCTIONS  -----------------------------++bumpYear :: CurrentYear -> Integer -> Text+bumpYear (CurrentYear cy) y | y >= cy   = tshow y+                            | otherwise = [i|#{y}-#{cy}|]+++bumpRange :: CurrentYear -> Integer -> Integer -> Text+bumpRange (CurrentYear cy) y1 y2 | y2 >= cy  = [i|#{y1}-#{y2}|]+                                 | otherwise = [i|#{y1}-#{cy}|]+
src/Headroom/SourceCode.hs view
@@ -8,7 +8,7 @@ {-| Module      : Headroom.SourceCode Description : Type safe representation of analyzed source code-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/Template.hs view
@@ -8,7 +8,7 @@ {-| Module      : Headroom.Template Description : Extensible templating support-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/Template/Mustache.hs view
@@ -6,7 +6,7 @@ {-| Module      : Headroom.Template.Mustache Description : Implementation of /Mustache/ template support-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/Template/TemplateRef.hs view
@@ -13,7 +13,7 @@ {-| Module      : Headroom.Template.TemplateRef Description : Representation of reference to template file-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -52,10 +52,10 @@                                                      ) import           RIO import qualified RIO.Text                           as T+import qualified Text.URI                           as URI import           Text.URI                            ( URI(..)                                                      , mkURI                                                      )-import qualified Text.URI                           as URI   ---------------------------------  DATA TYPES  ---------------------------------
src/Headroom/Types.hs view
@@ -7,7 +7,7 @@ {-| Module      : Headroom.Types Description : Application data types-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/UI.hs view
@@ -3,7 +3,7 @@ {-| Module      : Headroom.UI Description : UI Components-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
+ src/Headroom/UI/Message.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes       #-}+{-# LANGUAGE StrictData        #-}++{-|+Module      : Headroom.UI.Message+Description : UI component for message box+Copyright   : (c) 2019-2022 Vaclav Svejcar+License     : BSD-3-Clause+Maintainer  : vaclav.svejcar@gmail.com+Stability   : experimental+Portability : POSIX++Module providing UI component for message box (info/warning/error).+-}++module Headroom.UI.Message+  ( MessageType(..)+  , Message(..)+  , messageInfo+  , messageWarn+  , messageError+  )+where++import           Data.String.Interpolate             ( i )+import           RIO+++-- | Type of the message box (info/warning/error).+data MessageType+  = Info  -- ^ info message type+  | Warn  -- ^ warning message type+  | Error -- ^ error message type+  deriving (Eq, Show)++instance Display MessageType where+  textDisplay Info  = "[i]"+  textDisplay Warn  = "[!]"+  textDisplay Error = "[x]"+++-- | Data type for message box.+data Message = Message MessageType Text+  deriving (Eq, Show)++instance Display Message where+  textDisplay (Message tp tx) = [i|#{textDisplay tp} #{tx}|]+++-- | Creates 'Message' of type 'Info'.+messageInfo :: Text -> Message+messageInfo = Message Info+++-- | Creates 'Message' of type 'Warn'.+messageWarn :: Text -> Message+messageWarn = Message Warn+++-- | Creates 'Message' of type 'Error'.+messageError :: Text -> Message+messageError = Message Error
src/Headroom/UI/Progress.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.UI.Progress Description : UI component for displaying progress-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
src/Headroom/UI/Table.hs view
@@ -4,7 +4,7 @@ {-| Module      : Headroom.UI.Table Description : UI components for rendering tables-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
+ src/Headroom/Updater.hs view
@@ -0,0 +1,127 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE LambdaCase          #-}+{-# LANGUAGE NoImplicitPrelude   #-}+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE QuasiQuotes         #-}+{-# LANGUAGE RecordWildCards     #-}+{-# LANGUAGE TypeApplications    #-}++{-|+Module      : Headroom.Updater+Description : Update Manager for Headroom+Copyright   : (c) 2019-2022 Vaclav Svejcar+License     : BSD-3-Clause+Maintainer  : vaclav.svejcar@gmail.com+Stability   : experimental+Portability : POSIX++/Update Manager (Updater)/ is responsible for fetching data about latest version+of /Headroom/ and informing user about available updates. In future versions, it+might be capable to update /Headroom/ binaries automatically.+-}++module Headroom.Updater+  ( checkUpdates+  , fetchLatestVersion+  , parseLatestVersion+    -- * Error Data Types+  , UpdaterError(..)+  )+where++import           Data.Aeson                          ( Value(String) )+import qualified Data.Aeson                         as A+import           Data.String.Interpolate             ( iii )+import           Data.Time                           ( UTCTime(utctDay) )+import           Headroom.Config.Global              ( UpdaterConfig(..) )+import           Headroom.Data.Has                   ( Has(..)+                                                     , HasRIO+                                                     )+import           Headroom.IO.KVStore                 ( KVStore(..)+                                                     , valueKey+                                                     )+import           Headroom.IO.Network                 ( Network(..) )+import           Headroom.Meta                       ( buildVersion )+import           Headroom.Meta.Version               ( Version+                                                     , parseVersion+                                                     )+import           Headroom.Types                      ( fromHeadroomError+                                                     , toHeadroomError+                                                     )+import           Lens.Micro.Aeson                    ( key )+import           RIO+import qualified RIO.ByteString.Lazy                as BL+import qualified RIO.Text                           as T+import           RIO.Time                            ( diffDays+                                                     , getCurrentTime+                                                     )+import qualified Text.URI                           as URI+++-- | Check whether newer version is available (if enabled by configuration).+checkUpdates :: (HasRIO KVStore env, HasRIO Network env)+             => UpdaterConfig+             -> RIO env (Maybe Version)+checkUpdates UpdaterConfig {..} = do+  KVStore {..}       <- viewL+  now                <- getCurrentTime+  maybeLastCheckDate <- kvGetValue lastCheckDateKey+  let today       = utctDay now+      shouldCheck = ucCheckForUpdates && case utctDay <$> maybeLastCheckDate of+        Just lastCheck+          | abs (diffDays lastCheck today) > ucUpdateIntervalDays -> True+          | otherwise -> False+        Nothing -> True+  when shouldCheck $ kvPutValue lastCheckDateKey now+  if shouldCheck then isNewer <$> fetchLatestVersion else pure Nothing+ where+  lastCheckDateKey = valueKey @UTCTime "updater/last-check-date"+  isNewer version | version > buildVersion = Just version+                  | otherwise              = Nothing+++-- | Fetches and parses latest version from update server.+fetchLatestVersion :: (HasRIO Network env) => RIO env Version+fetchLatestVersion = do+  Network {..} <- viewL+  apiURI       <- latestVersionApiURI+  resp         <- catchAny (nDownloadContent apiURI) handleError+  case A.decode (BL.fromStrict resp) of+    Just json -> parseLatestVersion json+    _         -> throwM $ CannotDetectVersion "cannot fetch response"+ where+  handleError         = throwM . CannotDetectVersion . T.pack . displayException+  latestVersionApiURI = URI.mkURI+    "https://api.github.com/repos/vaclavsvejcar/headroom/releases/latest"++++-- | Parses latest version number from /GitHub/ API response.+parseLatestVersion :: MonadThrow m+                   => Value     -- ^ raw JSON response from /GitHub/+                   -> m Version -- ^ parsed version+parseLatestVersion json = case json ^? key "name" of+  Just (String rawValue) -> case parseVersion rawValue of+    Just version -> pure version+    _            -> throwM $ CannotDetectVersion "cannot parse version"+  _ -> throwM $ CannotDetectVersion "cannot parse response"+++---------------------------------  ERROR TYPES  --------------------------------++-- | Error during processing updates.+data UpdaterError = CannotDetectVersion Text+  deriving (Eq, Show, Typeable)++instance Exception UpdaterError where+  displayException = displayException'+  toException      = toHeadroomError+  fromException    = fromHeadroomError+++displayException' :: UpdaterError -> String+displayException' = \case+  CannotDetectVersion reason -> [iii|+    Cannot get latest Headroom version from update servers, reason: #{reason}.+  |]
src/Headroom/Variables.hs view
@@ -10,7 +10,7 @@ {-| Module      : Headroom.Variables Description : Support for template variables-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental@@ -86,7 +86,6 @@ -- Note that recursive variable reference and/or cyclic references are not -- supported. ----- >>> :set -XTypeApplications -- >>> import Headroom.Template.Mustache (Mustache) -- >>> let compiled = compileVariables @Mustache $ mkVariables [("name", "John"), ("msg", "Hello, {{ name }}")] -- >>> let expected = mkVariables [("name", "John"), ("msg", "Hello, John")]
src/Headroom/Variables/Types.hs view
@@ -3,7 +3,7 @@ {-| Module      : Headroom.Variables.Types Description : Data types for "Headroom.Variables"-Copyright   : (c) 2019-2021 Vaclav Svejcar+Copyright   : (c) 2019-2022 Vaclav Svejcar License     : BSD-3-Clause Maintainer  : vaclav.svejcar@gmail.com Stability   : experimental
+ test-data/code-samples/dart/sample1.dart view
@@ -0,0 +1,11 @@++// This is the+// header++// this is not header++// this is not the header+void main() {+  /* another comment */+  print('Hello, World!');+}
+ test-data/code-samples/kotlin/sample1.kt view
@@ -0,0 +1,10 @@+/*+ * This is copyright header+ */++package foo++/** this is not license header */+fun main(args : Array<String>) {+    println("Hello, World!")+}
+ test-data/code-samples/php/sample1.php view
@@ -0,0 +1,13 @@+<?php++/**+ * This is a file-level DocBlock+ * + * A warning will be raised, saying that to document the define, use+ * another DocBlock+ * @package SomePackage+ */++define('foo', 'bar');++/* not a header */
+ test-data/updater/github-resp.json view
@@ -0,0 +1,142 @@+{+  "url": "https://api.github.com/repos/vaclavsvejcar/headroom/releases/45555690",+  "assets_url": "https://api.github.com/repos/vaclavsvejcar/headroom/releases/45555690/assets",+  "upload_url": "https://uploads.github.com/repos/vaclavsvejcar/headroom/releases/45555690/assets{?name,label}",+  "html_url": "https://github.com/vaclavsvejcar/headroom/releases/tag/v0.4.2.0",+  "id": 45555690,+  "author": {+    "login": "github-actions[bot]",+    "id": 41898282,+    "node_id": "MDM6Qm90NDE4OTgyODI=",+    "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4",+    "gravatar_id": "",+    "url": "https://api.github.com/users/github-actions%5Bbot%5D",+    "html_url": "https://github.com/apps/github-actions",+    "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers",+    "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}",+    "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}",+    "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}",+    "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions",+    "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs",+    "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos",+    "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}",+    "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events",+    "type": "Bot",+    "site_admin": false+  },+  "node_id": "MDc6UmVsZWFzZTQ1NTU1Njkw",+  "tag_name": "v0.4.2.0",+  "target_commitish": "41136f4b5e0560a9a6339d14b3178254f59f73fa",+  "name": "v0.4.2.0",+  "draft": false,+  "prerelease": false,+  "created_at": "2021-07-01T11:47:02Z",+  "published_at": "2021-07-01T12:44:37Z",+  "assets": [+    {+      "url": "https://api.github.com/repos/vaclavsvejcar/headroom/releases/assets/39549995",+      "id": 39549995,+      "node_id": "MDEyOlJlbGVhc2VBc3NldDM5NTQ5OTk1",+      "name": "headroom-0.4.2.0-Linux-ghc-8.10.4",+      "label": "",+      "uploader": {+        "login": "github-actions[bot]",+        "id": 41898282,+        "node_id": "MDM6Qm90NDE4OTgyODI=",+        "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4",+        "gravatar_id": "",+        "url": "https://api.github.com/users/github-actions%5Bbot%5D",+        "html_url": "https://github.com/apps/github-actions",+        "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers",+        "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}",+        "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}",+        "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}",+        "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions",+        "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs",+        "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos",+        "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}",+        "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events",+        "type": "Bot",+        "site_admin": false+      },+      "content_type": "application/octet-stream",+      "state": "uploaded",+      "size": 31106168,+      "download_count": 58,+      "created_at": "2021-07-01T12:27:39Z",+      "updated_at": "2021-07-01T12:27:40Z",+      "browser_download_url": "https://github.com/vaclavsvejcar/headroom/releases/download/v0.4.2.0/headroom-0.4.2.0-Linux-ghc-8.10.4"+    },+    {+      "url": "https://api.github.com/repos/vaclavsvejcar/headroom/releases/assets/39550810",+      "id": 39550810,+      "node_id": "MDEyOlJlbGVhc2VBc3NldDM5NTUwODEw",+      "name": "headroom-0.4.2.0-macOS-ghc-8.10.4",+      "label": "",+      "uploader": {+        "login": "github-actions[bot]",+        "id": 41898282,+        "node_id": "MDM6Qm90NDE4OTgyODI=",+        "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4",+        "gravatar_id": "",+        "url": "https://api.github.com/users/github-actions%5Bbot%5D",+        "html_url": "https://github.com/apps/github-actions",+        "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers",+        "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}",+        "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}",+        "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}",+        "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions",+        "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs",+        "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos",+        "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}",+        "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events",+        "type": "Bot",+        "site_admin": false+      },+      "content_type": "application/octet-stream",+      "state": "uploaded",+      "size": 10052904,+      "download_count": 8,+      "created_at": "2021-07-01T12:41:51Z",+      "updated_at": "2021-07-01T12:41:52Z",+      "browser_download_url": "https://github.com/vaclavsvejcar/headroom/releases/download/v0.4.2.0/headroom-0.4.2.0-macOS-ghc-8.10.4"+    },+    {+      "url": "https://api.github.com/repos/vaclavsvejcar/headroom/releases/assets/39552138",+      "id": 39552138,+      "node_id": "MDEyOlJlbGVhc2VBc3NldDM5NTUyMTM4",+      "name": "headroom-v0.4.2.0-macos-x64.tar.gz",+      "label": null,+      "uploader": {+        "login": "vaclavsvejcar",+        "id": 5843430,+        "node_id": "MDQ6VXNlcjU4NDM0MzA=",+        "avatar_url": "https://avatars.githubusercontent.com/u/5843430?v=4",+        "gravatar_id": "",+        "url": "https://api.github.com/users/vaclavsvejcar",+        "html_url": "https://github.com/vaclavsvejcar",+        "followers_url": "https://api.github.com/users/vaclavsvejcar/followers",+        "following_url": "https://api.github.com/users/vaclavsvejcar/following{/other_user}",+        "gists_url": "https://api.github.com/users/vaclavsvejcar/gists{/gist_id}",+        "starred_url": "https://api.github.com/users/vaclavsvejcar/starred{/owner}{/repo}",+        "subscriptions_url": "https://api.github.com/users/vaclavsvejcar/subscriptions",+        "organizations_url": "https://api.github.com/users/vaclavsvejcar/orgs",+        "repos_url": "https://api.github.com/users/vaclavsvejcar/repos",+        "events_url": "https://api.github.com/users/vaclavsvejcar/events{/privacy}",+        "received_events_url": "https://api.github.com/users/vaclavsvejcar/received_events",+        "type": "User",+        "site_admin": false+      },+      "content_type": "application/x-gzip",+      "state": "uploaded",+      "size": 2601053,+      "download_count": 5,+      "created_at": "2021-07-01T13:02:16Z",+      "updated_at": "2021-07-01T13:02:28Z",+      "browser_download_url": "https://github.com/vaclavsvejcar/headroom/releases/download/v0.4.2.0/headroom-v0.4.2.0-macos-x64.tar.gz"+    }+  ],+  "tarball_url": "https://api.github.com/repos/vaclavsvejcar/headroom/tarball/v0.4.2.0",+  "zipball_url": "https://api.github.com/repos/vaclavsvejcar/headroom/zipball/v0.4.2.0",+  "body": "This is a minor release that brings some new cool features, but doesn't require any migration from previous version.\r\n\r\n- https://doc.norcane.com/headroom/v0.4.2.0/whats-new/\r\n- https://doc.norcane.com/headroom/v0.4.2.0/migration-guide/\r\n\r\n#### New & noteworthy\r\n- [#42] Add option to exclude source paths ignored by VCS\r\n- [#66] Allow loading templates from HTTP(S) resource"+}
test/Headroom/Command/InitSpec.hs view
@@ -12,7 +12,7 @@  import           Headroom.Command.Init import           Headroom.Command.Types              ( CommandInitOptions(..) )-import           Headroom.Configuration.Types        ( LicenseType(..) )+import           Headroom.Config.Types               ( LicenseType(..) ) import           Headroom.Data.Has                   ( Has(..) ) import           Headroom.Data.Lens                  ( suffixLenses                                                      , suffixLensesFor@@ -81,7 +81,9 @@                              , fsFindFilesByExts     = undefined                              , fsFindFilesByTypes    = undefined                              , fsGetCurrentDirectory = undefined+                             , fsGetUserDirectory    = undefined                              , fsListFiles           = undefined                              , fsLoadFile            = undefined+                             , fsWriteFile           = undefined                              } 
test/Headroom/Command/ReadersSpec.hs view
@@ -8,7 +8,7 @@ where  import           Headroom.Command.Readers-import           Headroom.Configuration.Types        ( LicenseType )+import           Headroom.Config.Types               ( LicenseType ) import           Headroom.Data.EnumExtra             ( EnumExtra(..) ) import           Headroom.FileType.Types             ( FileType ) import           RIO
test/Headroom/Command/RunSpec.hs view
@@ -18,7 +18,7 @@ where  import           Headroom.Command.Run-import           Headroom.Configuration.Types        ( CtPostProcessConfigs+import           Headroom.Config.Types               ( CtPostProcessConfigs                                                      , HeaderSyntax(..)                                                      , PostProcessConfig(..)                                                      , PostProcessConfigs(..)@@ -150,8 +150,10 @@                               , fsFindFilesByExts     = undefined                               , fsFindFilesByTypes    = undefined                               , fsGetCurrentDirectory = undefined+                              , fsGetUserDirectory    = undefined                               , fsListFiles           = undefined                               , fsLoadFile            = undefined+                              , fsWriteFile           = undefined                               }   envNetwork            = Network { nDownloadContent = undefined }   envPostProcessConfigs = PostProcessConfigs
+ test/Headroom/Config/CompatSpec.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes       #-}++module Headroom.Config.CompatSpec+  ( spec+  )+where++import           Headroom.Config.Compat+import           Headroom.Meta.Version               ( Version(..)+                                                     , pvp+                                                     )+import           RIO+import           Test.Hspec+++spec :: Spec+spec = do+  describe "checkCompatibility" $ do+    it "passes when config version is compatible" $ do+      let yaml     = "version: 0.4.0.0"+          curr     = [pvp|0.4.0.0|]+          version  = [pvp|0.4.0.0|]+          versions = [[pvp|0.1.0.0|], [pvp|0.2.1.0|], [pvp|0.4.0.0|]]+      checkCompatibility versions curr yaml `shouldBe` Just version++    it "fails when config version is not compatible" $ do+      let yaml     = "version: 0.2.1.0"+          curr     = [pvp|0.2.1.0|]+          versions = [[pvp|0.1.0.0|], [pvp|0.2.1.0|], [pvp|0.4.0.0|]]+      let err (UnsupportedVersion [Version 0 4 0 0] (Version 0 2 1 0)) = True+          err _ = False+      checkCompatibility versions curr yaml `shouldThrow` err++    it "fails when version is newer than Headroom version" $ do+      let yaml     = "version: 0.2.1.0"+          curr     = [pvp|0.2.0.0|]+          versions = [[pvp|0.1.0.0|]]+      let err (NewerVersionDetected (Version 0 2 1 0)) = True+          err _ = False+      checkCompatibility versions curr yaml `shouldThrow` err++    it "fails when config version cannot be determined" $ do+      let yaml     = ""+          curr     = [pvp|0.2.0.0|]+          versions = [[pvp|0.1.0.0|], [pvp|0.2.1.0|], [pvp|0.4.0.0|]]+      let err CannotParseVersion = True+          err _                  = False+      checkCompatibility versions curr yaml `shouldThrow` err
+ test/Headroom/Config/EnrichSpec.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}++module Headroom.Config.EnrichSpec+  ( spec+  )+where++import           Headroom.Config.Enrich+import           RIO+import           Test.Hspec+++spec :: Spec+spec = do+  describe "withArray" $ do+    it "produces valid YAML array field" $ do+      let field  = "name"+          values = ["foo", "bar"] :: [Text]+      withArray values field `shouldBe` (Array, "name:\n- foo\n- bar")+++  describe "withText" $ do+    it "produces valid YAML string from Text value" $ do+      let field = "name"+          value = "John Smith" :: Text+      withText value field `shouldBe` (String, "name: John Smith")+++  describe "replaceEmptyValue" $ do+    it "replaces YAML array field" $ do+      let field  = "name"+          values = ["foo", "bar"] :: [Text]+          yaml   = "name: []"+          action = replaceEmptyValue field $ withArray values+      enrich action yaml `shouldBe` "name:\n- foo\n- bar"++    it "replaces multiple YAML array fields using Semigroup instance" $ do+      let animalsF      = "animals"+          animals       = ["dog", "cat"] :: [Text]+          colorsF       = "colors"+          colors        = ["blue", "red"] :: [Text]+          yaml          = "colors: []\nanimals: []"+          enrichAnimals = replaceEmptyValue animalsF $ withArray animals+          enrichColors  = replaceEmptyValue colorsF (withArray colors)+          action        = enrichAnimals <> enrichColors+          expected      = "colors:\n- blue\n- red\nanimals:\n- dog\n- cat"+      enrich action yaml `shouldBe` expected
+ test/Headroom/Config/GlobalSpec.hs view
@@ -0,0 +1,86 @@+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NoImplicitPrelude     #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE StrictData            #-}+{-# LANGUAGE TemplateHaskell       #-}++module Headroom.Config.GlobalSpec+  ( spec+  )+where++import           Headroom.Config.Global+import           Headroom.Data.Has                   ( Has(..) )+import           Headroom.Data.Lens                  ( suffixLenses+                                                     , suffixLensesFor+                                                     )+import           Headroom.Embedded                   ( defaultGlobalConfig )+import           Headroom.IO.FileSystem              ( FileSystem(..)+                                                     , mkFileSystem+                                                     )+import           Headroom.Meta                       ( globalConfigDirName+                                                     , globalConfigFileName+                                                     )+import           RIO+import           RIO.Directory                       ( doesFileExist )+import           RIO.FilePath                        ( (</>) )+import           Test.Hspec++++data TestEnv = TestEnv+  { envFileSystem :: FileSystem (RIO TestEnv)+  }++suffixLenses ''TestEnv+suffixLensesFor [ "fsCreateDirectory"+                , "fsDoesFileExist"+                , "fsGetUserDirectory"+                , "fsWriteFile"+                ] ''FileSystem++instance Has (FileSystem (RIO TestEnv)) TestEnv where+  hasLens = envFileSystemL++env :: TestEnv+env = TestEnv+  { envFileSystem = FileSystem { fsCreateDirectory     = undefined+                               , fsDoesFileExist       = undefined+                               , fsFindFiles           = undefined+                               , fsFindFilesByExts     = undefined+                               , fsFindFilesByTypes    = undefined+                               , fsGetCurrentDirectory = undefined+                               , fsGetUserDirectory    = undefined+                               , fsListFiles           = undefined+                               , fsLoadFile            = undefined+                               , fsWriteFile           = undefined+                               }+  }+++spec :: Spec+spec = do++  describe "initGlobalConfigIfNeeded" $ do+    it "creates new config file and parent directory when needed" $ do+      withSystemTempDirectory "global-config" $ \dir -> do+        let cfgPath = dir </> globalConfigDirName </> globalConfigFileName+            fsCreateDirectory0 = fsCreateDirectory mkFileSystem+            fsWriteFile0 = fsWriteFile mkFileSystem+            env' =+              env+                & (envFileSystemL . fsCreateDirectoryL .~ fsCreateDirectory0)+                & (envFileSystemL . fsDoesFileExistL .~ fsDoesFileExist')+                & (envFileSystemL . fsGetUserDirectoryL .~ fsGetUserDirectory')+                & (envFileSystemL . fsWriteFileL .~ fsWriteFile0)+            fsDoesFileExist'    = const . pure $ False+            fsGetUserDirectory' = pure dir+        _      <- runRIO env' initGlobalConfigIfNeeded+        result <- doesFileExist cfgPath+        result `shouldBe` True+++  describe "parseGlobalConfig" $ do+    it "parses embedded default config YAML" $ do+      parseGlobalConfig defaultGlobalConfig `shouldSatisfy` isRight
+ test/Headroom/ConfigSpec.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+module Headroom.ConfigSpec+  ( spec+  )+where++import           Headroom.Config+import           Headroom.Embedded                   ( defaultConfig )+import           RIO+import           Test.Hspec+++spec :: Spec+spec = do+  describe "parseAppConfig" $ do+    it "should parse default bundled configuration" $ do+      parseAppConfig defaultConfig `shouldSatisfy` isJust
− test/Headroom/Configuration/CompatSpec.hs
@@ -1,50 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes       #-}--module Headroom.Configuration.CompatSpec-  ( spec-  )-where--import           Headroom.Configuration.Compat-import           Headroom.Meta.Version               ( Version(..)-                                                     , pvp-                                                     )-import           RIO-import           Test.Hspec---spec :: Spec-spec = do-  describe "checkCompatibility" $ do-    it "passes when config version is compatible" $ do-      let yaml     = "version: 0.4.0.0"-          curr     = [pvp|0.4.0.0|]-          version  = [pvp|0.4.0.0|]-          versions = [[pvp|0.1.0.0|], [pvp|0.2.1.0|], [pvp|0.4.0.0|]]-      checkCompatibility versions curr yaml `shouldBe` Just version--    it "fails when config version is not compatible" $ do-      let yaml     = "version: 0.2.1.0"-          curr     = [pvp|0.2.1.0|]-          versions = [[pvp|0.1.0.0|], [pvp|0.2.1.0|], [pvp|0.4.0.0|]]-      let err (UnsupportedVersion [Version 0 4 0 0] (Version 0 2 1 0)) = True-          err _ = False-      checkCompatibility versions curr yaml `shouldThrow` err--    it "fails when version is newer than Headroom version" $ do-      let yaml     = "version: 0.2.1.0"-          curr     = [pvp|0.2.0.0|]-          versions = [[pvp|0.1.0.0|]]-      let err (NewerVersionDetected (Version 0 2 1 0)) = True-          err _ = False-      checkCompatibility versions curr yaml `shouldThrow` err--    it "fails when config version cannot be determined" $ do-      let yaml     = ""-          curr     = [pvp|0.2.0.0|]-          versions = [[pvp|0.1.0.0|], [pvp|0.2.1.0|], [pvp|0.4.0.0|]]-      let err CannotParseVersion = True-          err _                  = False-      checkCompatibility versions curr yaml `shouldThrow` err
− test/Headroom/Configuration/EnrichSpec.hs
@@ -1,48 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE OverloadedStrings #-}--module Headroom.Configuration.EnrichSpec-  ( spec-  )-where--import           Headroom.Configuration.Enrich-import           RIO-import           Test.Hspec---spec :: Spec-spec = do-  describe "withArray" $ do-    it "produces valid YAML array field" $ do-      let field  = "name"-          values = ["foo", "bar"] :: [Text]-      withArray values field `shouldBe` (Array, "name:\n- foo\n- bar")---  describe "withText" $ do-    it "produces valid YAML string from Text value" $ do-      let field = "name"-          value = "John Smith" :: Text-      withText value field `shouldBe` (String, "name: John Smith")---  describe "replaceEmptyValue" $ do-    it "replaces YAML array field" $ do-      let field  = "name"-          values = ["foo", "bar"] :: [Text]-          yaml   = "name: []"-          action = replaceEmptyValue field $ withArray values-      enrich action yaml `shouldBe` "name:\n- foo\n- bar"--    it "replaces multiple YAML array fields using Semigroup instance" $ do-      let animalsF      = "animals"-          animals       = ["dog", "cat"] :: [Text]-          colorsF       = "colors"-          colors        = ["blue", "red"] :: [Text]-          yaml          = "colors: []\nanimals: []"-          enrichAnimals = replaceEmptyValue animalsF $ withArray animals-          enrichColors  = replaceEmptyValue colorsF (withArray colors)-          action        = enrichAnimals <> enrichColors-          expected      = "colors:\n- blue\n- red\nanimals:\n- dog\n- cat"-      enrich action yaml `shouldBe` expected
− test/Headroom/ConfigurationSpec.hs
@@ -1,18 +0,0 @@-{-# LANGUAGE NoImplicitPrelude #-}-{-# LANGUAGE OverloadedStrings #-}-module Headroom.ConfigurationSpec-  ( spec-  )-where--import           Headroom.Configuration-import           Headroom.Embedded                   ( defaultConfig )-import           RIO-import           Test.Hspec---spec :: Spec-spec = do-  describe "parseConfiguration" $ do-    it "should parse default bundled configuration" $ do-      parseConfiguration defaultConfig `shouldSatisfy` isJust
+ test/Headroom/FileSupport/DartSpec.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}++module Headroom.FileSupport.DartSpec+  ( spec+  )+where++import           Headroom.FileSupport.Dart+import           Headroom.FileSupport.Types          ( FileSupport(..)+                                                     , SyntaxAnalysis(..)+                                                     )+import           RIO+import           Test.Hspec+++spec :: Spec+spec = do++  describe "fsSyntaxAnalysis" $ do+    it "correctly detects comment starts/ends" $ do+      let samples =+            [ ("non comment line"             , (False, False))+            , ("// single line comment"       , (True, True))+            , ("not // single line comment"   , (False, False))+            , ("/* block comment start"       , (True, False))+            , ("block comment end */"         , (False, True))+            , ("/* block comment start/end */", (True, True))+            ]+      all checkSyntaxAnalysis samples `shouldBe` True++ where+  checkSyntaxAnalysis (l, (s, e)) =+    let SyntaxAnalysis {..} = fsSyntaxAnalysis fileSupport+    in  saIsCommentStart l == s && saIsCommentEnd l == e
test/Headroom/FileSupport/Haskell/HaddockSpec.hs view
@@ -8,7 +8,7 @@   ) where -import           Headroom.Configuration.Types        ( HeaderSyntax(..)+import           Headroom.Config.Types               ( HeaderSyntax(..)                                                      , LicenseType(..)                                                      ) import           Headroom.Data.Regex                 ( re )
test/Headroom/FileSupport/HaskellSpec.hs view
@@ -10,10 +10,10 @@ where  import           Data.String.Interpolate             ( __i )-import           Headroom.Configuration              ( makeHeadersConfig-                                                     , parseConfiguration+import           Headroom.Config                     ( makeHeadersConfig+                                                     , parseAppConfig                                                      )-import           Headroom.Configuration.Types        ( Configuration(..)+import           Headroom.Config.Types               ( AppConfig(..)                                                      , HeaderSyntax(..)                                                      , LicenseType(..)                                                      )@@ -76,8 +76,8 @@   describe "fsExtractVariables" $ do     it "extract variables from Haskell source code" $ do       template       <- emptyTemplate @_ @Mustache-      defaultConfig' <- parseConfiguration defaultConfig-      config         <- makeHeadersConfig (cLicenseHeaders defaultConfig')+      defaultConfig' <- parseAppConfig defaultConfig+      config         <- makeHeadersConfig (acLicenseHeaders defaultConfig')       raw            <- loadFile $ codeSamples </> "full.hs"       let ht = extractHeaderTemplate config Haskell template           headerPos = Just (1, 29)
test/Headroom/FileSupport/JavaSpec.hs view
@@ -8,10 +8,10 @@   ) where -import           Headroom.Configuration              ( makeHeadersConfig-                                                     , parseConfiguration+import           Headroom.Config                     ( makeHeadersConfig+                                                     , parseAppConfig                                                      )-import           Headroom.Configuration.Types        ( Configuration(..) )+import           Headroom.Config.Types               ( AppConfig(..) ) import           Headroom.Embedded                   ( defaultConfig ) import           Headroom.FileSupport                ( analyzeSourceCode                                                      , fileSupport@@ -20,7 +20,7 @@ import           Headroom.FileSupport.Types          ( FileSupport(..)                                                      , SyntaxAnalysis(..)                                                      )-import           Headroom.FileType.Types             ( FileType(..) )+import           Headroom.FileType.Types             ( FileType(Java) ) import           Headroom.Header                     ( extractHeaderTemplate ) import           Headroom.IO.FileSystem              ( loadFile ) import           Headroom.Template                   ( emptyTemplate )@@ -39,12 +39,13 @@   describe "fsSyntaxAnalysis" $ do     it "correctly detects comment starts/ends" $ do       let samples =-            [ ("non comment line"             , (False, False))-            , ("// single line comment"       , (True, True))-            , ("not // single line comment"   , (False, False))-            , ("/* block comment start"       , (True, False))-            , ("block comment end */"         , (False, True))-            , ("/* block comment start/end */", (True, True))+            [ ("non comment line"                , (False, False))+            , ("// single line comment"          , (True, True))+            , ("not // single line comment"      , (False, False))+            , ("/* block comment start"          , (True, False))+            , ("block comment end */"            , (False, True))+            , ("/* block comment start/end */"   , (True, True))+            , ("/** JavaDoc comment start/end */", (True, True))             ]       all checkSyntaxAnalysis samples `shouldBe` True @@ -60,8 +61,8 @@   describe "fsExtractVariables" $ do     it "extract variables from Java source code" $ do       template       <- emptyTemplate @_ @Mustache-      defaultConfig' <- parseConfiguration defaultConfig-      config         <- makeHeadersConfig (cLicenseHeaders defaultConfig')+      defaultConfig' <- parseAppConfig defaultConfig+      config         <- makeHeadersConfig (acLicenseHeaders defaultConfig')       raw            <- loadFile $ codeSamples </> "sample1.java"       let ht        = extractHeaderTemplate config Java template           headerPos = Just (0, 2)
+ test/Headroom/FileSupport/KotlinSpec.hs view
@@ -0,0 +1,82 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE TypeApplications  #-}++module Headroom.FileSupport.KotlinSpec+  ( spec+  )+where++import           Headroom.Config                     ( makeHeadersConfig+                                                     , parseAppConfig+                                                     )+import           Headroom.Config.Types               ( AppConfig(..) )+import           Headroom.Embedded                   ( defaultConfig )+import           Headroom.FileSupport                ( analyzeSourceCode+                                                     , fileSupport+                                                     )+import           Headroom.FileSupport.TemplateData   ( TemplateData(..) )+import           Headroom.FileSupport.Types          ( FileSupport(..)+                                                     , SyntaxAnalysis(..)+                                                     )+import           Headroom.FileType.Types             ( FileType(Kotlin) )+import           Headroom.Header                     ( extractHeaderTemplate )+import           Headroom.IO.FileSystem              ( loadFile )+import           Headroom.Template                   ( emptyTemplate )+import           Headroom.Template.Mustache          ( Mustache )+import           Headroom.Variables                  ( mkVariables )+import           RIO+import           RIO.FilePath                        ( (</>) )+import           Test.Hspec+++spec :: Spec+spec = do+  let codeSamples = "test-data" </> "code-samples" </> "kotlin"+++  describe "fsSyntaxAnalysis" $ do+    it "correctly detects comment starts/ends" $ do+      let samples =+            [ ("non comment line"             , (False, False))+            , ("// single line comment"       , (True, True))+            , ("not // single line comment"   , (False, False))+            , ("/* block comment start"       , (True, False))+            , ("block comment end */"         , (False, True))+            , ("/* block comment start/end */", (True, True))+            , ("/** KDoc comment start/end */", (True, True))+            ]+      all checkSyntaxAnalysis samples `shouldBe` True+++  describe "fsExtractTemplateData" $ do+    it "doesn't provide any custom data for Kotlin" $ do+      template <- emptyTemplate @_ @Mustache+      let syntax   = undefined+          expected = NoTemplateData+      fsExtractTemplateData fileSupport' template syntax `shouldBe` expected+++  describe "fsExtractVariables" $ do+    it "extract variables from Kotlin source code" $ do+      template       <- emptyTemplate @_ @Mustache+      defaultConfig' <- parseAppConfig defaultConfig+      config         <- makeHeadersConfig (acLicenseHeaders defaultConfig')+      raw            <- loadFile $ codeSamples </> "sample1.kt"+      let ht        = extractHeaderTemplate config Kotlin template+          headerPos = Just (0, 2)+          expected  = mkVariables [("_kotlin_package_name", "foo")]+          sample    = analyzeSourceCode fileSupport' raw+      fsExtractVariables fileSupport' ht headerPos sample `shouldBe` expected+++  describe "fsFileType" $ do+    it "matches correct type for Kotlin" $ do+      fsFileType fileSupport' `shouldBe` Kotlin++ where+  fileSupport' = fileSupport Kotlin+  checkSyntaxAnalysis (l, (s, e)) =+    let SyntaxAnalysis {..} = fsSyntaxAnalysis fileSupport'+    in  saIsCommentStart l == s && saIsCommentEnd l == e
+ test/Headroom/FileSupport/PHPSpec.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}++module Headroom.FileSupport.PHPSpec+  ( spec+  )+where++import           Headroom.FileSupport.PHP+import           Headroom.FileSupport.Types          ( FileSupport(..)+                                                     , SyntaxAnalysis(..)+                                                     )+import           RIO+import           Test.Hspec+++spec :: Spec+spec = do++  describe "fsSyntaxAnalysis" $ do+    it "correctly detects comment starts/ends" $ do+      let samples =+            [ ("non comment line"                 , (False, False))+            , ("// single line comment"           , (True, True))+            , ("not // single line comment"       , (False, False))+            , ("/* block comment start"           , (True, False))+            , ("/** DocBlock comment start"       , (True, False))+            , ("block comment end */"             , (False, True))+            , ("/* block comment start/end */"    , (True, True))+            , ("/** DocBlock comment start/end */", (True, True))+            ]+      all checkSyntaxAnalysis samples `shouldBe` True++ where+  checkSyntaxAnalysis (l, (s, e)) =+    let SyntaxAnalysis {..} = fsSyntaxAnalysis fileSupport+    in  saIsCommentStart l == s && saIsCommentEnd l == e
test/Headroom/FileSupport/PureScriptSpec.hs view
@@ -8,10 +8,10 @@   ) where -import           Headroom.Configuration              ( makeHeadersConfig-                                                     , parseConfiguration+import           Headroom.Config                     ( makeHeadersConfig+                                                     , parseAppConfig                                                      )-import           Headroom.Configuration.Types        ( Configuration(..) )+import           Headroom.Config.Types               ( AppConfig(..) ) import           Headroom.Embedded                   ( defaultConfig ) import           Headroom.FileSupport                ( analyzeSourceCode                                                      , fileSupport@@ -60,8 +60,8 @@   describe "fsExtractVariables" $ do     it "extract variables from PureScript source code" $ do       template       <- emptyTemplate @_ @Mustache-      defaultConfig' <- parseConfiguration defaultConfig-      config         <- makeHeadersConfig (cLicenseHeaders defaultConfig')+      defaultConfig' <- parseAppConfig defaultConfig+      config         <- makeHeadersConfig (acLicenseHeaders defaultConfig')       raw            <- loadFile $ codeSamples </> "full.purs"       let ht        = extractHeaderTemplate config PureScript template           headerPos = Just (1, 13)
test/Headroom/FileSupportSpec.hs view
@@ -90,7 +90,7 @@             ]       analyzeSourceCode (fileSupport CSS) sample `shouldBe` expected -    it "analyzes Go source code" $ do+    it "analyzes Dart source code" $ do       sample <- loadFile $ codeSamples </> "go" </> "sample1.go"       let expected = SourceCode             [ (Code   , "")@@ -112,6 +112,23 @@             ]       analyzeSourceCode (fileSupport Go) sample `shouldBe` expected +    it "analyzes Go source code" $ do+      sample <- loadFile $ codeSamples </> "dart" </> "sample1.dart"+      let expected = SourceCode+            [ (Code   , "")+            , (Comment, "// This is the")+            , (Comment, "// header")+            , (Code   , "")+            , (Comment, "// this is not header")+            , (Code   , "")+            , (Comment, "// this is not the header")+            , (Code   , "void main() {")+            , (Comment, "  /* another comment */")+            , (Code   , "  print('Hello, World!');")+            , (Code   , "}")+            ]+      analyzeSourceCode (fileSupport Dart) sample `shouldBe` expected+     it "analyzes Haskell source code" $ do       sample <- loadFile $ codeSamples </> "haskell" </> "full.hs"       let expected = SourceCode@@ -220,6 +237,44 @@             , (Code   , "}")             ]       analyzeSourceCode (fileSupport JS) sample `shouldBe` expected++    it "analyzes Kotlin source code" $ do+      sample <- loadFile $ codeSamples </> "kotlin" </> "sample1.kt"+      let expected = SourceCode+            [ (Comment, "/*")+            , (Comment, " * This is copyright header")+            , (Comment, " */")+            , (Code   , "")+            , (Code   , "package foo")+            , (Code   , "")+            , (Comment, "/** this is not license header */")+            , (Code, "fun main(args : Array<String>) {")+            , (Code   , "    println(\"Hello, World!\")")+            , (Code   , "}")+            ]+      analyzeSourceCode (fileSupport Kotlin) sample `shouldBe` expected++    it "analyzes PHP source code" $ do+      sample <- loadFile $ codeSamples </> "php" </> "sample1.php"+      let+        expected = SourceCode+          [ (Code   , "<?php")+          , (Code   , "")+          , (Comment, "/**")+          , (Comment, " * This is a file-level DocBlock")+          , (Comment, " * ")+          , ( Comment+            , " * A warning will be raised, saying that to document the define, use"+            )+          , (Comment, " * another DocBlock")+          , (Comment, " * @package SomePackage")+          , (Comment, " */")+          , (Code   , "")+          , (Code   , "define('foo', 'bar');")+          , (Code   , "")+          , (Comment, "/* not a header */")+          ]+      analyzeSourceCode (fileSupport PHP) sample `shouldBe` expected      it "analyzes PureScript source code" $ do       sample <- loadFile $ codeSamples </> "purescript" </> "full.purs"
test/Headroom/FileTypeSpec.hs view
@@ -5,10 +5,10 @@   ) where -import           Headroom.Configuration              ( makeHeadersConfig-                                                     , parseConfiguration+import           Headroom.Config                     ( makeHeadersConfig+                                                     , parseAppConfig                                                      )-import           Headroom.Configuration.Types        ( Configuration(..) )+import           Headroom.Config.Types               ( AppConfig(..) ) import           Headroom.Embedded                   ( defaultConfig ) import           Headroom.FileType import           Headroom.FileType.Types             ( FileType(..) )@@ -20,6 +20,6 @@ spec = do   describe "fileTypeByExt" $ do     it "parses FileType from file extension" $ do-      pHeadersConfig <- cLicenseHeaders <$> parseConfiguration defaultConfig+      pHeadersConfig <- acLicenseHeaders <$> parseAppConfig defaultConfig       headersConfig  <- makeHeadersConfig pHeadersConfig       fileTypeByExt headersConfig "hs" `shouldBe` Just Haskell
test/Headroom/Header/SanitizeSpec.hs view
@@ -7,7 +7,7 @@   ) where -import           Headroom.Configuration.Types        ( HeaderSyntax(..) )+import           Headroom.Config.Types               ( HeaderSyntax(..) ) import           Headroom.Data.Regex                 ( re ) import           Headroom.Data.Text                  ( fromLines ) import           Headroom.Header.Sanitize
test/Headroom/HeaderSpec.hs view
@@ -10,10 +10,10 @@   ) where -import           Headroom.Configuration              ( makeHeadersConfig-                                                     , parseConfiguration+import           Headroom.Config                     ( makeHeadersConfig+                                                     , parseAppConfig                                                      )-import           Headroom.Configuration.Types        ( Configuration(..)+import           Headroom.Config.Types               ( AppConfig(..)                                                      , HeaderConfig(..)                                                      , HeaderSyntax(..)                                                      , HeadersConfig(..)@@ -385,14 +385,15 @@     it "correctly detects headers using default YAML configuration" $ do       let loadSample = \ft p ->             analyzeSourceCode (fileSupport ft) <$> loadFile (samplesDir </> p)-      defaultConfig'     <- parseConfiguration defaultConfig-      HeadersConfig {..} <- makeHeadersConfig (cLicenseHeaders defaultConfig')+      defaultConfig'     <- parseAppConfig defaultConfig+      HeadersConfig {..} <- makeHeadersConfig (acLicenseHeaders defaultConfig')       sampleC1           <- loadSample C $ "c" </> "sample1.c"       sampleC2           <- loadSample C $ "c" </> "sample2.c"       sampleCpp1         <- loadSample CPP $ "cpp" </> "sample1.cpp"       sampleCpp2         <- loadSample CPP $ "cpp" </> "sample2.cpp"       sampleCss1         <- loadSample CSS $ "css" </> "sample1.css"       sampleCss2         <- loadSample CSS $ "css" </> "sample2.css"+      sampleDart         <- loadSample Dart $ "dart" </> "sample1.dart"       sampleGo           <- loadSample Go $ "go" </> "sample1.go"       sampleHs1          <- loadSample Haskell $ "haskell" </> "sample1.hs"       sampleHs2          <- loadSample Haskell $ "haskell" </> "sample2.hs"@@ -401,6 +402,8 @@       sampleJava1        <- loadSample Java $ "java" </> "sample1.java"       sampleJava2        <- loadSample Java $ "java" </> "sample2.java"       sampleJs1          <- loadSample JS $ "js" </> "sample1.js"+      sampleKotlin       <- loadSample Kotlin $ "kotlin" </> "sample1.kt"+      samplePhp1         <- loadSample PHP $ "php" </> "sample1.php"       sampleRust1        <- loadSample Rust $ "rust" </> "sample1.rs"       sampleScala1       <- loadSample Scala $ "scala" </> "sample1.scala"       sampleScala2       <- loadSample Scala $ "scala" </> "sample2.scala"@@ -411,6 +414,7 @@       findHeader hscCpp sampleCpp2 `shouldBe` Nothing       findHeader hscCss sampleCss1 `shouldBe` Just (1, 4)       findHeader hscCss sampleCss2 `shouldBe` Nothing+      findHeader hscDart sampleDart `shouldBe` Just (1, 2)       findHeader hscGo sampleGo `shouldBe` Just (1, 2)       findHeader hscHaskell sampleHs1 `shouldBe` Just (1, 3)       findHeader hscHaskell sampleHs2 `shouldBe` Nothing@@ -419,6 +423,8 @@       findHeader hscJava sampleJava1 `shouldBe` Just (0, 2)       findHeader hscJava sampleJava2 `shouldBe` Nothing       findHeader hscJs sampleJs1 `shouldBe` Just (0, 2)+      findHeader hscKotlin sampleKotlin `shouldBe` Just (0, 2)+      findHeader hscPhp samplePhp1 `shouldBe` Just (2, 8)       findHeader hscRust sampleRust1 `shouldBe` Just (0, 2)       findHeader hscScala sampleScala1 `shouldBe` Just (0, 2)       findHeader hscScala sampleScala2 `shouldBe` Nothing
test/Headroom/IO/FileSystemSpec.hs view
@@ -11,8 +11,8 @@ import           Headroom.IO.FileSystem import           RIO import           RIO.FilePath                        ( (</>) )-import           RIO.List                            ( sort ) import qualified RIO.List                           as L+import           RIO.List                            ( sort ) import           Test.Hspec  
+ test/Headroom/IO/KVStoreSpec.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# LANGUAGE TypeApplications  #-}++module Headroom.IO.KVStoreSpec+  ( spec+  )+where++import           Headroom.IO.KVStore+import           RIO+import           RIO.FilePath                        ( (</>) )+import qualified RIO.Text                           as T+import           RIO.Time+import           Test.Hspec+++spec :: Spec+spec = do++  describe "SQLite store" $ do+    it "reads and writes values from/to store" $ do+      withSystemTempDirectory "sqlite-kvstore" $ \dir -> do+        let path         = StorePath . T.pack $ dir </> "test-db.sqlite"+            fstKey       = valueKey @Text "fst-key"+            sndKey       = valueKey @Text "snd-key"+            KVStore {..} = sqliteKVStore path+        maybeFst <- kvGetValue fstKey+        _        <- kvPutValue sndKey "foo"+        _        <- kvPutValue sndKey "bar"+        maybeSnd <- kvGetValue sndKey+        maybeFst `shouldBe` Nothing+        maybeSnd `shouldBe` Just "bar"+++  describe "In-memory store" $ do+    it "reads and writes values from/to store" $ do+      let fstKey = valueKey @Text "fst-key"+          sndKey = valueKey @Text "snd-key"+      KVStore {..} <- inMemoryKVStore+      maybeFst     <- kvGetValue fstKey+      _            <- kvPutValue sndKey "foo"+      _            <- kvPutValue sndKey "bar"+      maybeSnd     <- kvGetValue sndKey+      maybeFst `shouldBe` Nothing+      maybeSnd `shouldBe` Just "bar"+++  describe "ValueCodec type class" $ do+    it "has working instance for Text" $ do+      let sample = "The Cake is a Lie"+      decodeValue @Text (encodeValue sample) `shouldBe` Just sample++    it "has working instance for UTCTime" $ do+      sample <- getCurrentTime+      decodeValue @UTCTime (encodeValue sample) `shouldBe` Just sample+
test/Headroom/Meta/VersionSpec.hs view
@@ -15,14 +15,15 @@ spec = do   describe "Ord instance" $ do     it "correctly compare two values" $ do-      compare (Version 1 2 3 4) (Version 1 2 3 4) `shouldBe` EQ-      compare (Version 0 1 0 0) (Version 0 1 0 1) `shouldBe` LT-      compare (Version 1 1 0 0) (Version 0 1 0 1) `shouldBe` GT+      compare [pvp|1.2.3.4|] [pvp|1.2.3.4|] `shouldBe` EQ+      compare [pvp|0.1.0.0|] [pvp|0.1.0.1|] `shouldBe` LT+      compare [pvp|1.1.0.0|] [pvp|0.1.0.1|] `shouldBe` GT     describe "parseVersion" $ do     it "parses valid Version from Text" $ do-      parseVersion "0.1.2.3" `shouldBe` Just (Version 0 1 2 3)+      parseVersion "0.1.2.3" `shouldBe` Just [pvp|0.1.2.3|]+      parseVersion "v0.1.2.3" `shouldBe` Just [pvp|0.1.2.3|]      it "parses Nothing for invalid input" $ do       parseVersion "0.4" `shouldBe` Nothing@@ -30,12 +31,12 @@    describe "printVersion" $ do     it "pretty prints given version" $ do-      printVersion (Version 1 2 3 4) `shouldBe` "1.2.3.4"+      printVersion [pvp|1.2.3.4|] `shouldBe` "1.2.3.4"     describe "printVersionP" $ do     it "pretty prints given version (with 'v' prefix)" $ do-      printVersionP (Version 1 2 3 4) `shouldBe` "v1.2.3.4"+      printVersionP [pvp|1.2.3.4|] `shouldBe` "v1.2.3.4"     describe "pvp" $ do
test/Headroom/PostProcess/UpdateCopyrightSpec.hs view
@@ -56,8 +56,20 @@       let sample = "Copyright (c) 2020"       updateYears currYear sample `shouldBe` sample +    it "does nothing if year is higher than current year" $ do+      let sample = "Copyright (c) 2021"+      updateYears currYear sample `shouldBe` sample+     it "does nothing on up-to-date year range" $ do       let sample = "Copyright (c) 2018-2020"+      updateYears currYear sample `shouldBe` sample++    it "does nothing if second year range is higher than current year" $ do+      let sample = "Copyright (c) 2018-2021"+      updateYears currYear sample `shouldBe` sample++    it "does nothing if entire year range is higher than current year" $ do+      let sample = "Copyright (c) 2021-2023"       updateYears currYear sample `shouldBe` sample      it "updates outdated year" $ do
test/Headroom/PostProcessSpec.hs view
@@ -10,7 +10,7 @@   ) where -import           Headroom.Configuration.Types        ( PostProcessConfig(..)+import           Headroom.Config.Types               ( PostProcessConfig(..)                                                      , PostProcessConfigs(..)                                                      , UpdateCopyrightConfig(..)                                                      )
+ test/Headroom/UI/MessageSpec.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}++module Headroom.UI.MessageSpec+  ( spec+  )+where++import           Headroom.UI.Message+import           RIO+import           Test.Hspec++spec :: Spec+spec = do++  describe "Message" $ do+    it "properly displays info message" $ do+      textDisplay (messageInfo "info message") `shouldBe` "[i] info message"++    it "properly displays warn message" $ do+      textDisplay (messageWarn "warn message") `shouldBe` "[!] warn message"++    it "properly displays error message" $ do+      textDisplay (messageError "error message") `shouldBe` "[x] error message"
+ test/Headroom/UpdaterSpec.hs view
@@ -0,0 +1,162 @@+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE LambdaCase            #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NoImplicitPrelude     #-}+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE QuasiQuotes           #-}+{-# LANGUAGE RecordWildCards       #-}+{-# LANGUAGE TemplateHaskell       #-}+{-# LANGUAGE TypeApplications      #-}++module Headroom.UpdaterSpec+  ( spec+  )+where++import           Data.Aeson                          ( Value )+import qualified Data.Aeson                         as A+import           Data.String.Interpolate             ( i )+import           Data.Time                           ( UTCTime(..) )+import           Headroom.Config.Global              ( UpdaterConfig(..) )+import           Headroom.Data.Has                   ( Has(..) )+import           Headroom.Data.Lens                  ( suffixLenses+                                                     , suffixLensesFor+                                                     )+import           Headroom.IO.KVStore                 ( KVStore(..)+                                                     , inMemoryKVStore+                                                     , valueKey+                                                     )+import           Headroom.IO.Network                 ( Network(..)+                                                     , NetworkError(..)+                                                     )+import           Headroom.Meta                       ( buildVersion )+import           Headroom.Meta.Version               ( printVersionP+                                                     , pvp+                                                     )+import           Headroom.Updater+import           RIO+import qualified RIO.ByteString                     as B+import qualified RIO.ByteString.Lazy                as BL+import           RIO.FilePath                        ( (</>) )+import           RIO.Partial                         ( fromJust )+import           RIO.Time                            ( addDays+                                                     , getCurrentTime+                                                     )+import           Test.Hspec+++data TestEnv = TestEnv+  { envKVStore :: KVStore (RIO TestEnv)+  , envNetwork :: Network (RIO TestEnv)+  }++suffixLenses ''TestEnv+suffixLensesFor ["nDownloadContent"] ''Network++instance Has (KVStore (RIO TestEnv)) TestEnv where+  hasLens = envKVStoreL++instance Has (Network (RIO TestEnv)) TestEnv where+  hasLens = envNetworkL+++spec :: Spec+spec = do+  let testFile = "test-data" </> "updater" </> "github-resp.json"+      storeKey = valueKey @UTCTime "updater/last-check-date"++  describe "checkUpdates" $ do+    it "returns Nothing if current version is the latest" $ do+      store@KVStore {..} <- runRIO env0 inMemoryKVStore+      let json = [i|{"name": "#{printVersionP buildVersion}"}|]+          env =+            env0+              & (envKVStoreL .~ kvStore')+              & (envNetworkL . nDownloadContentL .~ nDownloadContent')+          nDownloadContent' = const . pure $ json+          updaterConfig'    = UpdaterConfig True 2+          kvStore'          = store+      actual             <- runRIO env (checkUpdates updaterConfig')+      maybeLastCheckDate <- runRIO env $ kvGetValue storeKey+      actual `shouldBe` Nothing+      maybeLastCheckDate `shouldSatisfy` isJust++    it "returns newer version if current version is outdated" $ do+      store@KVStore {..} <- runRIO env0 inMemoryKVStore+      let json = [i|{"name": "v999.0.0.0"}|]+          env =+            env0+              & (envKVStoreL .~ kvStore')+              & (envNetworkL . nDownloadContentL .~ nDownloadContent')+          nDownloadContent' = const . pure $ json+          updaterConfig'    = UpdaterConfig True 2+          kvStore'          = store+      actual             <- runRIO env (checkUpdates updaterConfig')+      maybeLastCheckDate <- runRIO env $ kvGetValue storeKey+      actual `shouldBe` Just [pvp|999.0.0.0|]+      maybeLastCheckDate `shouldSatisfy` isJust++    it "doesn't check for updates if still within check interval" $ do+      store@KVStore {..} <- runRIO env0 inMemoryKVStore+      oneDayAgo          <- addDays' (-1) <$> getCurrentTime+      let json = [i|{"name": "v999.0.0.0"}|]+          env =+            env0+              & (envKVStoreL .~ kvStore')+              & (envNetworkL . nDownloadContentL .~ nDownloadContent')+          nDownloadContent' = const . pure $ json+          updaterConfig'    = UpdaterConfig True 2+          kvStore'          = store+      actual <- runRIO env $ do+        kvPutValue storeKey oneDayAgo+        checkUpdates updaterConfig'+      actual `shouldBe` Nothing++    it "returns Nothing if checking for updates is disabled" $ do+      store@KVStore {..} <- runRIO env0 inMemoryKVStore+      let json = [i|{"name": "v999.0.0.0"}|]+          env =+            env0+              & (envKVStoreL .~ kvStore')+              & (envNetworkL . nDownloadContentL .~ nDownloadContent')+          nDownloadContent' = const . pure $ json+          updaterConfig'    = UpdaterConfig False 2+          kvStore'          = store+      actual             <- runRIO env (checkUpdates updaterConfig')+      maybeLastCheckDate <- runRIO env $ kvGetValue storeKey+      actual `shouldBe` Nothing+      maybeLastCheckDate `shouldBe` Nothing+++  describe "fetchLatestVersion" $ do+    it "gets latest version info" $ do+      raw <- B.readFile testFile+      let env = env0 & (envNetworkL . nDownloadContentL .~ nDownloadContent')+          nDownloadContent' = const . pure $ raw+      actual <- runRIO env fetchLatestVersion+      actual `shouldBe` [pvp|0.4.2.0|]++    it "returns error if version cannot be fetched" $ do+      let env = env0 & (envNetworkL . nDownloadContentL .~ nDownloadContent')+          nDownloadContent' = \uri -> throwM $ ConnectionFailure uri "error"+      runRIO env fetchLatestVersion `shouldThrow` \case+        (CannotDetectVersion _) -> True+++  describe "parseLatestVersion" $ do+    it "parses latest version from raw JSON input" $ do+      raw    <- BL.readFile testFile+      actual <- parseLatestVersion (fromJust . A.decode @Value $ raw)+      actual `shouldBe` [pvp|0.4.2.0|]+++env0 :: TestEnv+env0 = TestEnv+  { envKVStore = KVStore { kvGetValue = undefined, kvPutValue = undefined }+  , envNetwork = Network { nDownloadContent = undefined }+  }+++addDays' :: Integer -> UTCTime -> UTCTime+addDays' noOfDays (UTCTime day timeOfDay) =+  UTCTime (addDays noOfDays day) timeOfDay