configuration-tools 0.2.5 → 0.2.6
raw patch · 8 files changed
+360/−82 lines, 8 filesdep +case-insensitivesetup-changedPVP ok
version bump matches the API change (PVP)
Dependencies added: case-insensitive
API changes (from Hackage documentation)
+ Configuration.Utils: boolOption :: Mod OptionFields Bool -> Parser Bool
+ Configuration.Utils: boolReader :: (Eq a, Show a, FoldCase a, IsString a, IsString e, Monoid e) => a -> Either e Bool
+ Configuration.Utils: eitherReadP :: Text -> ReadP a -> Text -> Either Text a
+ Configuration.Utils: fileOption :: Mod OptionFields String -> Parser FilePath
+ Configuration.Utils: maybeOption :: a -> Bool -> (a -> a) -> Maybe a -> Maybe a
Files
- CHANGELOG.md +14/−0
- README.md +48/−24
- Setup.hs +84/−25
- configuration-tools.cabal +3/−2
- constraints +20/−18
- src/Configuration/Utils.hs +167/−11
- src/Configuration/Utils/Internal.hs +14/−0
- src/Configuration/Utils/Setup.hs +10/−2
CHANGELOG.md view
@@ -1,3 +1,17 @@+0.2.6+=====++* For git repositories include also light-weight (non-annotated) tags+ in the version description.++* Added new function `boolReader`, `boolOption`, `fileOption`, and+ `eitherReadP` to `Utils`.++* Added new function `maybeOption` and improved documentation about+ `Maybe` config values.++* Included optimisation level into long info.+ 0.2.5 =====
README.md view
@@ -281,7 +281,13 @@ Optional Configuration Values ----------------------------- -For configuration values of type `Maybe a`, though being sum types, we provide+For simple `Maybe` values the standard `FromJSON` instance from the aeson+package can be used along with the `..:` operator. When defining command line+option parsers with `.::` and `%::` all options are optional. When an option is+not present on the command line the default value is used. For `Maybe` values+it is therefore enough to wrap the parsed value into `Just`.++For configuration values of type `Maybe a` where `a` is a record type we provide an orphan[^1] `FromJSON` instance of the form ~~~{.haskell}@@ -290,14 +296,18 @@ that has the following behavior: -If the parsed configuration value is 'Null' the resulting function constantly+If the parsed configuration value is `Null` the resulting function constantly returns `Nothing`. Otherwise -* the function does an pointwise update using the `FromJSON` instance for- `a -> a` when applied to `Just a` and-* the function uses the `FromJSON` instance for `a` to return the parsed `a`- value when applied to 'Nothing'.+* If the parsed configuration value is `Null` the result is `Nothing`.+* If the parsed configuration value is not `Null` then the result is+ an update function that + * updates the given default value if this value is `Just x` or+ * is a constant function that returns the value that is parsed+ from the configuration using the `FromJSON` instance for the+ configuration type.+ The `FromJSON a` instance may either require that the parsed configuration fully specifies the value of `a` (and raise a failure otherwise) or the `FromJSON a` instance may do an pointwise update of a hardcoded default value based on@@ -317,6 +327,9 @@ is an issue for you, please let me know. In that case we can define a new type for optional configuration values. +The function `maybeOption` is provided for defining command line parser for+`Maybe` record values.+ Package and Build Information ============================= @@ -411,7 +424,7 @@ `examples/Trivial.hs` from this package: ~~~{.shell}-trivial-0.2.3 (package configuration-tools-0.2.3 revision 83634a3)+trivial-0.2.6 (package configuration-tools-0.2.6 revision 2cc860c) Copyright (c) 2014 AlephCloud, Inc. Author: Lars Kuhtz <lars@alephcloud.com>@@ -419,11 +432,12 @@ Homepage: https://github.com/alephcloud/hs-configuration-tools Build with: ghc-7.8.3 (x86_64-osx) Build flags:+Optimisation: normal Dependencies:- Cabal-1.20.0.1 [BSD3, 2003-2006, Isaac Jones 2005-2011, Duncan Coutts]- MonadRandom-0.1.13 [OtherLicense]- aeson-0.7.0.6 [BSD3, (c) 2011-2014 Bryan O'Sullivan (c) 2011 MailRank, Inc.]+ Cabal-1.20.0.2 [BSD3, 2003-2006, Isaac Jones 2005-2011, Duncan Coutts]+ MonadRandom-0.3 [OtherLicense]+ aeson-0.8.0.0 [BSD3, (c) 2011-2014 Bryan O'Sullivan (c) 2011 MailRank, Inc.] ansi-terminal-0.6.1.1 [BSD3] ansi-wl-pprint-0.6.7.1 [BSD3] array-0.5.0.0 [BSD3]@@ -433,15 +447,16 @@ bifunctors-4.1.1.1 [BSD3, Copyright (C) 2008-2013 Edward A. Kmett] rts-1.0 [BSD3] bytestring-0.10.4.0 [BSD3, Copyright (c) Don Stewart 2005-2009, (c) Duncan Coutts 2006-2013, (c) David Roundy 2003-2005, (c) Jasper Van der Jeugt 2010, (c) Simon Meier 2010-2013.]- comonad-4.2 [BSD3, Copyright (C) 2008-2013 Edward A. Kmett, Copyright (C) 2004-2008 Dave Menendez]- conduit-1.1.6 [MIT]+ case-insensitive-1.2.0.0 [BSD3, 2011 Bas van Dijk]+ comonad-4.2.2 [BSD3, Copyright (C) 2008-2014 Edward A. Kmett, Copyright (C) 2004-2008 Dave Menendez]+ conduit-1.2.0.2 [MIT] containers-0.5.5.1 [BSD3]- contravariant-0.6 [BSD3, Copyright (C) 2007-2014 Edward A. Kmett]+ contravariant-1.2 [BSD3, Copyright (C) 2007-2014 Edward A. Kmett] deepseq-1.3.0.2 [BSD3] directory-1.2.1.0 [BSD3] distributive-0.4.4 [BSD3, Copyright (C) 2011-2014 Edward A. Kmett] dlist-0.7.1 [BSD3, 2006-2009 Don Stewart, 2013 Sean Leather]- either-4.3.0.1 [BSD3, Copyright (C) 2008-2014 Edward A. Kmett]+ either-4.3.1 [BSD3, Copyright (C) 2008-2014 Edward A. Kmett] errors-1.4.7 [BSD3, 2012, 2013 Gabriel Gonzalez] exceptions-0.6.1 [BSD3, Copyright (C) 2013-2014 Edward A. Kmett Copyright (C) 2012 Google Inc.] filepath-1.3.0.2 [BSD3]@@ -450,36 +465,37 @@ hashable-1.2.2.0 [BSD3] integer-gmp-0.5.1.0 [BSD3] lifted-base-0.2.3.0 [BSD3, (c) 2011-2012 Bas van Dijk, Anders Kaseorg]- mmorph-1.0.3 [BSD3, 2013 Gabriel Gonzalez]+ mmorph-1.0.4 [BSD3, 2013 Gabriel Gonzalez] monad-control-0.3.3.0 [BSD3, (c) 2011 Bas van Dijk, Anders Kaseorg]- mtl-2.1.3.1 [BSD3]+ mtl-2.2.1 [BSD3] nats-0.2 [BSD3, Copyright (C) 2011-2014 Edward A. Kmett] old-locale-1.0.0.6 [BSD3]- optparse-applicative-0.9.0 [BSD3, (c) 2012 Paolo Capriotti <p.capriotti@gmail.com>]+ optparse-applicative-0.11.0.1 [BSD3, (c) 2012-2014 Paolo Capriotti <paolo@capriotti.io>] prelude-extras-0.4 [BSD3, Copyright (C) 2011-2014 Edward A. Kmett] pretty-1.1.1.1 [BSD3] primitive-0.5.3.0 [BSD3, (c) Roman Leshchinskiy 2009-2012] process-1.2.0.0 [BSD3]- profunctors-4.0.4 [BSD3, Copyright (C) 2011-2014 Edward A. Kmett]+ profunctors-4.2.0.1 [BSD3, Copyright (C) 2011-2014 Edward A. Kmett] random-1.0.1.1 [BSD3]- resourcet-1.1.2.2 [BSD3]+ resourcet-1.1.2.3 [BSD3] safe-0.3.6 [BSD3, Neil Mitchell 2007-2014] scientific-0.3.3.0 [BSD3]- semigroupoids-4.0.2.1 [BSD3, Copyright (C) 2011-2013 Edward A. Kmett]- semigroups-0.15.1 [BSD3, Copyright (C) 2011-2014 Edward A. Kmett]+ semigroupoids-4.2 [BSD3, Copyright (C) 2011-2013 Edward A. Kmett]+ semigroups-0.15.3 [BSD3, Copyright (C) 2011-2014 Edward A. Kmett]+ stm-2.4.3 [BSD3] syb-0.4.2 [BSD3] tagged-0.7.2 [BSD3, 2009-2013 Edward A. Kmett] template-haskell-2.9.0.0 [BSD3] text-1.1.1.3 [BSD3, 2009-2011 Bryan O'Sullivan, 2008-2009 Tom Harper] time-1.4.2 [BSD3]- transformers-0.3.0.0 [BSD3]- transformers-base-0.4.2 [BSD3, 2011 Mikhail Vorozhtsov <mikhail.vorozhtsov@gmail.com>, Bas van Dijk <v.dijk.bas@gmail.com>]+ transformers-0.4.1.0 [BSD3]+ transformers-base-0.4.3 [BSD3, 2011 Mikhail Vorozhtsov <mikhail.vorozhtsov@gmail.com>, Bas van Dijk <v.dijk.bas@gmail.com>] transformers-compat-0.3.3.4 [BSD3, Copyright (C) 2012 Edward A. Kmett] unix-2.7.0.1 [BSD3] unordered-containers-0.2.5.0 [BSD3, 2010-2014 Johan Tibell 2010 Edward Z. Yang] vector-0.10.11.0 [BSD3, (c) Roman Leshchinskiy 2008-2012] void-0.6.1 [BSD3, Copyright (C) 2008-2013 Edward A. Kmett]- yaml-0.8.8.4 [BSD3]+ yaml-0.8.9.1 [BSD3] ~~~ Configuration Types for HTTP Services and Clients@@ -540,3 +556,11 @@ * Include default values in help message. +* Use 'helpDoc' to highlight "meta-options", like options that enable+ optional configuration values through usage of the `maybeOption`+ function.++* Add functionality optparse-applicative that allows to group options.++* Raise parser error for sub-ordinate "maybe" options when not enabled+ the respective optional value is not enabled.
Setup.hs view
@@ -26,7 +26,7 @@ -- -- = Usage as Setup Script ----- There are two ways how this module can be used:+-- There are three ways how this module can be used: -- -- 1. Copy the code of this module into a file called @Setup.hs@ in the root -- directory of your package.@@ -38,7 +38,18 @@ -- > -- > import Configuration.Utils.Setup ----- With both methods the field @Build-Type@ in the package description (cabal) file+-- 3. For usage within a more complex @Setup.hs@ script you shall import this+-- module qualified and use the 'mkPkgInfoModules' function. For example:+--+-- > module Main (main) where+-- >+-- > import qualified Configuration.Utils.Setup as ConfTools+-- >+-- > main :: IO ()+-- > main = defaultMainWithHooks (ConfTools.mkPkgInfoModules simpleUserHooks)+-- >+--+-- With all methods the field @Build-Type@ in the package description (cabal) file -- must be set to @Custom@: -- -- > Build-Type: Custom@@ -90,7 +101,10 @@ -- [@--license@] -- prints the text of the lincense of the application and exits. ---module Main (main) where+module Main+( main+, mkPkgInfoModules+) where import Distribution.PackageDescription import Distribution.Simple@@ -116,18 +130,52 @@ import System.Directory (doesFileExist, doesDirectoryExist, createDirectoryIfMissing) import System.Exit (ExitCode(ExitSuccess)) +-- | Include this function when your setup doesn't contain any+-- extra functionality.+-- main :: IO ()-main = defaultMainWithHooks simpleUserHooks- { postConf = mkPkgInfoModules+main = defaultMainWithHooks (mkPkgInfoModules simpleUserHooks)++-- | Modifies the given record of hooks by adding functionality that+-- creates a package info module for each component of the cabal package.+--+-- This function is intended for usage in more complex @Setup.hs@ scripts.+-- If your setup doesn't contain any other function you can just import+-- the 'main' function from this module.+--+-- The modules are created in the /autogen/ build directory where also the+-- @Path_@ module is created by cabal's simple build setup. This is usually the+-- directory @.\/dist\/build\/autogen@.+--+-- For a library component the module is named just @PkgInfo@. For all other+-- components the module is named @PkgInfo_COMPONENT_NAME@ where+-- @COMPONENT_NAME@ is the name of the component with @-@ characters replaced by+-- @_@.+--+mkPkgInfoModules+ :: UserHooks+ -> UserHooks+mkPkgInfoModules hooks = hooks+ { postConf = mkPkgInfoModulesPostConf (postConf hooks) }++mkPkgInfoModulesPostConf+ :: (Args -> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO ())+ -> Args+ -> ConfigFlags+ -> PackageDescription+ -> LocalBuildInfo+ -> IO ()+mkPkgInfoModulesPostConf hook args flags pkgDesc bInfo = do+ mkModules+ hook args flags pkgDesc bInfo where- mkPkgInfoModules _ _ pkgDesc bInfo = mapM_ f . map (\(a,_,_) -> a) $ componentsConfigs bInfo- where- f cname = case cname of- CLibName -> updatePkgInfoModule Nothing pkgDesc bInfo- CExeName s -> updatePkgInfoModule (Just s) pkgDesc bInfo- CTestName s -> updatePkgInfoModule (Just s) pkgDesc bInfo- CBenchName s -> updatePkgInfoModule (Just s) pkgDesc bInfo+ mkModules = mapM_ (f . \(a,_,_) -> a) $ componentsConfigs bInfo+ f cname = case cname of+ CLibName -> updatePkgInfoModule Nothing pkgDesc bInfo+ CExeName s -> updatePkgInfoModule (Just s) pkgDesc bInfo+ CTestName s -> updatePkgInfoModule (Just s) pkgDesc bInfo+ CBenchName s -> updatePkgInfoModule (Just s) pkgDesc bInfo pkgInfoModuleName :: Maybe String -> String pkgInfoModuleName Nothing = "PkgInfo"@@ -144,13 +192,16 @@ where f = reverse . dropWhile isSpace getVCS :: IO (Maybe RepoType)-getVCS = do+getVCS = doesDirectoryExist ".hg" >>= \x0 -> if x0 then return (Just Mercurial)- else doesDirectoryExist ".git" >>= \x1 -> if x1- then return (Just Git)- else return Nothing+ else doesDirectoryExist ".git" >>= \x1 -> return $ if x1+ then Just Git+ else Nothing +flagNameStr :: FlagName -> String+flagNameStr (FlagName s) = s+ pkgInfoModule :: Maybe String -> PackageDescription -> LocalBuildInfo -> IO B.ByteString pkgInfoModule cName pkgDesc bInfo = do (tag, revision, branch) <- getVCS >>= \x -> case x of@@ -160,11 +211,11 @@ let vcsBranch = if branch == "default" || branch == "master" then "" else branch vcsVersion = intercalate "-" . filter (/= "") $ [tag, revision, vcsBranch]- flags = map fst . filter snd . configConfigurationsFlags . configFlags $ bInfo+ flags = map (flagNameStr . fst) . filter snd . configConfigurationsFlags . configFlags $ bInfo licenseString <- licenseFilesText pkgDesc - return $ B.intercalate "\n" $+ return $ B.intercalate "\n" [ "{-# LANGUAGE OverloadedStrings #-}" , "{-# LANGUAGE RankNTypes #-}" , ""@@ -197,6 +248,9 @@ , " flags :: IsString a => [a]" , " flags = " <> (pack . show) flags , ""+ , " optimisation :: IsString a => a"+ , " optimisation = \"" <> (displayOptimisationLevel . withOptimization) bInfo <> "\""+ , "" , " arch :: IsString a => a" , " arch = \"" <> (pack . display . hostPlatform) bInfo <> "\"" , ""@@ -244,7 +298,8 @@ , " <> \"License: \" <> license <> \"\\n\"" , " <> \"Homepage: \" <> homepage <> \"\\n\"" , " <> \"Build with: \" <> compiler <> \" (\" <> arch <> \")\" <> \"\\n\""- , " <> \"Build flags: \" <> mconcat (map (\\x -> \" \" <> x) flags) <> \"\\n\\n\""+ , " <> \"Build flags: \" <> mconcat (map (\\x -> \" \" <> x) flags) <> \"\\n\""+ , " <> \"Optimisation: \" <> optimisation <> \"\\n\\n\"" , " <> \"Dependencies:\\n\" <> mconcat (map (\\x -> \" \" <> x <> \"\\n\") dependenciesWithLicenses)" , "" , " pkgInfo :: (Monoid a, IsString a) => (a, a, a, a)"@@ -256,6 +311,10 @@ , " )" , "" ]+ where+ displayOptimisationLevel NoOptimisation = "none"+ displayOptimisationLevel NormalOptimisation = "normal"+ displayOptimisationLevel MaximumOptimisation = "maximum" updatePkgInfoModule :: Maybe String -> PackageDescription -> LocalBuildInfo -> IO () updatePkgInfoModule cName pkgDesc bInfo = do@@ -281,20 +340,20 @@ hgInfo :: IO (String, String, String) hgInfo = do- tag <- fmap trim $ readProcess "hg" ["id", "-r", "max(ancestors(\".\") and tag())", "-t"] ""- rev <- fmap trim $ readProcess "hg" ["id", "-i"] ""- branch <- fmap trim $ readProcess "hg" ["id", "-b"] ""+ tag <- trim <$> readProcess "hg" ["id", "-r", "max(ancestors(\".\") and tag())", "-t"] ""+ rev <- trim <$> readProcess "hg" ["id", "-i"] ""+ branch <- trim <$> readProcess "hg" ["id", "-b"] "" return (tag, rev, branch) gitInfo :: IO (String, String, String) gitInfo = do tag <- do- (exitCode, out, _err) <- readProcessWithExitCode "git" ["describe", "--exact-match", "--abbrev=0"] ""+ (exitCode, out, _err) <- readProcessWithExitCode "git" ["describe", "--exact-match", "--tags", "--abbrev=0"] "" case exitCode of ExitSuccess -> return $ trim out _ -> return ""- rev <- fmap trim $ readProcess "git" ["rev-parse", "--short", "HEAD"] ""- branch <- fmap trim $ readProcess "git" ["rev-parse", "--abbrev-ref", "HEAD"] ""+ rev <- trim <$> readProcess "git" ["rev-parse", "--short", "HEAD"] ""+ branch <- trim <$> readProcess "git" ["rev-parse", "--abbrev-ref", "HEAD"] "" return (tag, rev, branch) noVcsInfo :: IO (String, String, String)
configuration-tools.cabal view
@@ -3,7 +3,7 @@ -- ------------------------------------------------------ -- Name: configuration-tools-Version: 0.2.5+Version: 0.2.6 Synopsis: Tools for specifying and parsing configurations description: Tools for specifying and parsing configurations@@ -54,7 +54,7 @@ source-repository this type: git location: https://github.com/alephcloud/hs-configuration-tools.git- tag: 0.2.5+ tag: 0.2.6 Library hs-source-dirs: src@@ -76,6 +76,7 @@ base >= 4.6 && < 5.0, base-unicode-symbols >= 0.2.2.4, bytestring >= 0.10.0.2,+ case-insensitive >= 1.2, directory >= 1.2.1.0, errors >= 1.4.3, optparse-applicative >= 0.8.1,
constraints view
@@ -1,6 +1,6 @@-constraints: Cabal ==1.20.0.1,- MonadRandom ==0.1.13,- aeson ==0.7.0.6,+constraints: Cabal ==1.20.0.2,+ MonadRandom ==0.3,+ aeson ==0.8.0.0, ansi-terminal ==0.6.1.1, ansi-wl-pprint ==0.6.7.1, array ==0.5.0.0,@@ -9,16 +9,17 @@ base-unicode-symbols ==0.2.2.4, bifunctors ==4.1.1.1, bytestring ==0.10.4.0,- comonad ==4.2,- conduit ==1.1.6,- configuration-tools ==0.2.5,+ case-insensitive ==1.2.0.0,+ comonad ==4.2.2,+ conduit ==1.2.0.2,+ configuration-tools ==0.2.6, containers ==0.5.5.1,- contravariant ==0.6,+ contravariant ==1.2, deepseq ==1.3.0.2, directory ==1.2.1.0, distributive ==0.4.4, dlist ==0.7.1,- either ==4.3.0.1,+ either ==4.3.1, errors ==1.4.7, exceptions ==0.6.1, filepath ==1.3.0.2,@@ -27,34 +28,35 @@ hashable ==1.2.2.0, integer-gmp ==0.5.1.0, lifted-base ==0.2.3.0,- mmorph ==1.0.3,+ mmorph ==1.0.4, monad-control ==0.3.3.0,- mtl ==2.1.3.1,+ mtl ==2.2.1, nats ==0.2, old-locale ==1.0.0.6,- optparse-applicative ==0.10.0,+ optparse-applicative ==0.11.0.1, prelude-extras ==0.4, pretty ==1.1.1.1, primitive ==0.5.3.0, process ==1.2.0.0,- profunctors ==4.0.4,+ profunctors ==4.2.0.1, random ==1.0.1.1,- resourcet ==1.1.2.2,+ resourcet ==1.1.2.3, rts ==1.0, safe ==0.3.6, scientific ==0.3.3.0,- semigroupoids ==4.0.2.1,- semigroups ==0.15.1,+ semigroupoids ==4.2,+ semigroups ==0.15.3,+ stm ==2.4.3, syb ==0.4.2, tagged ==0.7.2, template-haskell ==2.9.0.0, text ==1.1.1.3, time ==1.4.2,- transformers ==0.3.0.0,- transformers-base ==0.4.2,+ transformers ==0.4.1.0,+ transformers-base ==0.4.3, transformers-compat ==0.3.3.4, unix ==2.7.0.1, unordered-containers ==0.2.5.0, vector ==0.10.11.0, void ==0.6.1,- yaml ==0.8.8.4+ yaml ==0.8.9.1
src/Configuration/Utils.hs view
@@ -67,12 +67,19 @@ , MParser , (.::) , (%::)+, boolReader+, boolOption+, fileOption+, eitherReadP+, module Options.Applicative -- * Parsing of Configuration Files with Default Values , setProperty , (..:) , (%.:)+, module Data.Aeson +-- * Command Line Option Parsing -- * Misc Utils , (%) , (×)@@ -87,11 +94,13 @@ , Lens -- * Configuration of Optional Values--- $maybe --- * Reexports-, module Data.Aeson-, module Options.Applicative+-- * Simple Maybe Values+-- $simplemaybe++-- ** Record Maybe Values+-- $recordmaybe+, maybeOption ) where import Configuration.Utils.Internal@@ -102,10 +111,12 @@ import Data.Aeson.Types (Parser) import qualified Data.ByteString.Char8 as B8 import Data.Char+import qualified Data.CaseInsensitive as CI import qualified Data.HashMap.Strict as H import Data.Maybe import Data.Monoid import Data.Monoid.Unicode+import Data.String import qualified Data.Text as T import qualified Data.Yaml as Yaml @@ -121,6 +132,8 @@ import System.IO.Unsafe (unsafePerformIO) +import qualified Text.ParserCombinators.ReadP as P+ -- -------------------------------------------------------------------------- -- -- Useful Operators @@ -390,6 +403,54 @@ {-# INLINE (%.:) #-} -- -------------------------------------------------------------------------- --+-- Command Line Option Parsing++boolReader+ ∷ (Eq a, Show a, CI.FoldCase a, IsString a, IsString e, Monoid e)+ ⇒ a+ → Either e Bool+boolReader x = case CI.mk x of+ "true" → Right True+ "false" → Right False+ _ → Left $ "failed to read Boolean value " <> fromString (show x)+ <> ". Expected either \"true\" or \"false\""++boolOption+ ∷ O.Mod O.OptionFields Bool+ → O.Parser Bool+#if MIN_VERSION_optparse_applicative(0,10,0)+boolOption mods = O.option (O.eitherReader boolReader)+ % O.metavar "TRUE|FALSE"+ <> O.completeWith ["true", "false", "TRUE", "FALSE", "True", "False"]+ <> mods+#else+boolOption mods = O.nullOption+ % metavar "TRUE|FALSE"+ <> O.completeWith ["true", "false", "TRUE", "FALSE", "True", "False"]+ <> O.eitherReader boolReader+ <> mods+#endif++fileOption+ ∷ O.Mod O.OptionFields String+ → O.Parser FilePath+fileOption mods = O.strOption+ % O.metavar "FILE"+ <> O.action "file"+ <> mods++eitherReadP+ ∷ T.Text+ → P.ReadP a+ → T.Text+ → Either T.Text a+eitherReadP label p s =+ case [ x | (x,"") ← P.readP_to_S p (T.unpack s) ] of+ [x] → Right x+ [] → Left $ "eitherReadP: no parse for " <> label <> " of " <> s+ _ → Left $ "eitherReadP: ambigous parse for " <> label <> " of " <> s++-- -------------------------------------------------------------------------- -- -- Main Configuration data ProgramInfo α = ProgramInfo@@ -653,17 +714,12 @@ -- -------------------------------------------------------------------------- -- -- Configuration of Optional Values --- $maybe+-- $simplemaybe -- Optional configuration values are supposed to be encoded by wrapping -- the respective type with 'Maybe'. -- -- For simple values the standard 'FromJSON' instance from the aeson--- package can be used with the along with the '..:' operator.------ When defining command line option parsers with '.::' and '%::' all--- options are optional. When an option is not present on the command--- line the default value is used. For 'Maybe' values it is therefore--- enough to wrap the parsed value into 'Just'.+-- package can be used along with the '..:' operator. -- -- > data LogConfig = LogConfig -- > { _logLevel ∷ !Int@@ -689,6 +745,12 @@ -- > , "LogConfig" .= _logFile config -- > ] -- >+--+-- When defining command line option parsers with '.::' and '%::' all+-- options are optional. When an option is not present on the command+-- line the default value is used. For 'Maybe' values it is therefore+-- enough to wrap the parsed value into 'Just'.+-- -- > pLogConfig ∷ MParser LogConfig -- > pLogConfig = id -- > #if MIN_VERSION_optparse-applicative(0,10,0)@@ -704,6 +766,9 @@ -- > % metavar "FILENAME" -- > % help "log file name" --++-- $recordmaybe+-- -- For product-type (record) 'Maybe' values the following orphan 'FromJSON' -- instance is provided: --@@ -761,4 +826,95 @@ where f g _ Nothing = Just g f _ g (Just x) = Just (g x)++-- | Commandline parser for record 'Maybe' values+--+-- == Example:+--+-- > data Setting = Setting+-- > { _setA :: !Int+-- > , _setB :: !String+-- > }+-- > deriving (Show, Read, Eq, Ord, Typeable)+-- >+-- > $(makeLenses ''Setting)+-- >+-- > defaultSetting :: Setting+-- > defaultSetting = Setting+-- > { _setA = 0+-- > , _setB = 1+-- > }+-- >+-- > instance ToJSON Setting where+-- > toJSON setting = object+-- > [ "a" .= _setA setting+-- > , "b" .= _setB setting+-- > ]+-- >+-- > instance FromJSON (Setting -> Setting) where+-- > parseJSON = withObject "Setting" $ \o -> id+-- > <$< setA ..: "a" % o+-- > <*< setB ..: "b" % o+-- >+-- > instance FromJSON Setting where+-- > parseJSON v = parseJSON v <*> pure defaultSetting+-- >+-- > pSetting :: MParser Setting+-- > pSetting = id+-- > <$< setA .:: option auto+-- > % short 'a'+-- > <> metavar "INT"+-- > <> help "set a"+-- > <*< setB .:: option auto+-- > % short 'b'+-- > <> metavar "INT"+-- > <> help "set b"+-- >+-- > -- | Use 'Setting' as 'Maybe' in a configuration:+-- > --+-- > data Config = Config+-- > { _maybeSetting :: !(Maybe Setting)+-- > }+-- > deriving (Show, Read, Eq, Ord, Typeable)+-- >+-- > $(makeLenses ''Config)+-- >+-- > defaultConfig :: Config+-- > defaultConfig = Config+-- > { _maybeSetting = defaultSetting+-- > }+-- >+-- > instance ToJSON Config where+-- > toJSON config = object+-- > [ "setting" .= maybeSetting+-- > ]+-- >+-- > instance FromJSON (Config -> Config) where+-- > parseJSON = withObject "Config" $ \o -> id+-- > <$< maybeSetting %.: "setting" % o+-- >+-- > pConfig :: MParser Config+-- > pConfig = id+-- > <$< maybeSetting %:: (maybeOption defaultSetting+-- > <$> pEnableSetting+-- > <*> pSetting)+-- > where+-- > pEnableSetting = boolOption+-- > % long "setting-enable"+-- > <> value False+-- > <> help "Enable configuration flags for setting"+--+maybeOption+ :: a+ -- ^ default value that is used if base configuration is 'Nothing'+ -> Bool+ -- ^ whether to enable this parser or not (usually is a boolean option parser)+ -> (a -> a)+ -- ^ update function (usually given as applicative 'MParser a')+ -> Maybe a+ -- ^ the base value that is updated (usually the result of parsing the configuraton file)+ -> Maybe a+maybeOption _ False _ Nothing = Nothing -- not enabled+maybeOption defA True update Nothing = Just $ update defA -- disabled in config file but enabled by command line+maybeOption _ _ update (Just val) = Just $ update val -- enabled by config file and possibly by command line
src/Configuration/Utils/Internal.hs view
@@ -28,24 +28,38 @@ -- | This is the same type as the type from the lens library with the same name. --+-- In case it is already import from the lens package this should be hidden+-- from the import.+-- type Lens σ τ α β = Functor φ ⇒ (α → φ β) → σ → φ τ -- | This is the same type as the type from the lens library with the same name. --+-- In case it is already import from the lens package this should be hidden+-- from the import.+-- type Lens' σ α = Lens σ σ α α lens ∷ (σ → α) → (σ → β → τ) → Lens σ τ α β lens getter setter lGetter s = setter s `fmap` lGetter (getter s)+{-# INLINE lens #-} over ∷ ((α → Identity α) → β → Identity β) → (α → α) → β → β over s f = runIdentity . s (Identity . f)+{-# INLINE over #-} set ∷ ((α → Identity α) → β → Identity β) → α → β → β set s a = runIdentity . s (const $ Identity a)+{-# INLINE set #-} -- | This is the same type as the type from the lens library with the same name. --+-- In case it is already import from the lens package this should be hidden+-- from the import.+-- type Iso' β α = (Profunctor π, Functor φ) ⇒ π α (φ α) → π β (φ β) iso ∷ (β → α) → (α → β) → Iso' β α iso f g = dimap f (fmap g)+{-# INLINE iso #-}+
src/Configuration/Utils/Setup.hs view
@@ -248,6 +248,9 @@ , " flags :: IsString a => [a]" , " flags = " <> (pack . show) flags , ""+ , " optimisation :: IsString a => a"+ , " optimisation = \"" <> (displayOptimisationLevel . withOptimization) bInfo <> "\""+ , "" , " arch :: IsString a => a" , " arch = \"" <> (pack . display . hostPlatform) bInfo <> "\"" , ""@@ -295,7 +298,8 @@ , " <> \"License: \" <> license <> \"\\n\"" , " <> \"Homepage: \" <> homepage <> \"\\n\"" , " <> \"Build with: \" <> compiler <> \" (\" <> arch <> \")\" <> \"\\n\""- , " <> \"Build flags: \" <> mconcat (map (\\x -> \" \" <> x) flags) <> \"\\n\\n\""+ , " <> \"Build flags: \" <> mconcat (map (\\x -> \" \" <> x) flags) <> \"\\n\""+ , " <> \"Optimisation: \" <> optimisation <> \"\\n\\n\"" , " <> \"Dependencies:\\n\" <> mconcat (map (\\x -> \" \" <> x <> \"\\n\") dependenciesWithLicenses)" , "" , " pkgInfo :: (Monoid a, IsString a) => (a, a, a, a)"@@ -307,6 +311,10 @@ , " )" , "" ]+ where+ displayOptimisationLevel NoOptimisation = "none"+ displayOptimisationLevel NormalOptimisation = "normal"+ displayOptimisationLevel MaximumOptimisation = "maximum" updatePkgInfoModule :: Maybe String -> PackageDescription -> LocalBuildInfo -> IO () updatePkgInfoModule cName pkgDesc bInfo = do@@ -340,7 +348,7 @@ gitInfo :: IO (String, String, String) gitInfo = do tag <- do- (exitCode, out, _err) <- readProcessWithExitCode "git" ["describe", "--exact-match", "--abbrev=0"] ""+ (exitCode, out, _err) <- readProcessWithExitCode "git" ["describe", "--exact-match", "--tags", "--abbrev=0"] "" case exitCode of ExitSuccess -> return $ trim out _ -> return ""