Safe Haskell | None |
---|---|
Language | Haskell2010 |
- data a :*> b = a :*> b
- data s :> t
- data a :>: s
- data ConfigCode k
- = Record (ConfigCode k) (ConfigCode k)
- | Label Symbol (ConfigCode k)
- | Descr (ConfigCode k) Symbol
- | List (ConfigCode k)
- | Option (ConfigCode k)
- | Type k
- type family ToConfigCode a :: ConfigCode *
- type family NoDesc a :: ConfigCode *
- type family ToConfig a f :: *
- data MaybeO a
- data Id a = Id a
- data Source
- = YamlString SBS
- | YamlFile FilePath
- | ShellEnv [(String, String)]
- | CommandLine [String]
- data ConfigFile
- data ShellEnv
- data CommandLine
- data Tagged cfg = Tagged {
- fromTagged :: ToConfig cfg Id
- data TaggedM cfg = TaggedM {
- fromTaggedM :: ToConfig cfg Maybe
- data Error
- configify :: forall cfg tm. (tm ~ TaggedM cfg, Show tm, Monoid tm, Freeze cfg, FromJSON tm, HasParseShellEnv cfg, HasParseCommandLine cfg, CanonicalizePartial cfg) => [Source] -> IO (Tagged cfg)
- configifyWithDefault :: forall cfg tm. (tm ~ TaggedM cfg, Show tm, Monoid tm, Freeze cfg, FromJSON tm, HasParseShellEnv cfg, HasParseCommandLine cfg, CanonicalizePartial cfg) => tm -> [Source] -> IO (Tagged cfg)
- defaultSources :: [FilePath] -> IO [Source]
- withShellEnvPrefix :: Env -> IO Env
- readUserConfigFiles :: [Source] -> [Source]
- withShellEnvPrefix' :: String -> Env -> Env
- parseConfigFile :: FromJSON (TaggedM cfg) => SBS -> Either Error (TaggedM cfg)
- parseConfigFileWithIncludes :: FromJSON (TaggedM cfg) => FilePath -> IO (Either Error (TaggedM cfg))
- renderConfigFile :: (Freeze cfg, t ~ Tagged cfg, ToJSON (TaggedM cfg)) => t -> SBS
- type Env = [(String, String)]
- class HasParseShellEnv cfg where
- parseShellEnv :: Env -> Either Error (TaggedM cfg)
- type Args = [String]
- class HasParseCommandLine cfg where
- parseCommandLine :: [String] -> Either Error (TaggedM cfg)
- primitiveParseCommandLine :: HasParseShellEnv cfg => [String] -> Either Error (TaggedM cfg)
- parseArgs :: Args -> Either String Env
- popArg :: Args -> Either String ((String, String), Args)
- parseArgsWithEqSign :: String -> Either String (String, String)
- parseArgsWithSpace :: String -> String -> Either String (String, String)
- parseArgName :: String -> String
- (>>.) :: forall cfg ps r. (Sel cfg ps, ToValE cfg ps ~ Done r) => Tagged cfg -> Proxy ps -> r
- type family ToVal a p :: Maybe *
- type family OrElse x y :: Maybe k
- data CMaybe a where
- orElse :: CMaybe a -> CMaybe b -> CMaybe (OrElse a b)
- type family ToValueMaybe a :: Maybe *
- toValueMaybe :: CMaybe a -> CMaybe (ToValueMaybe a)
- class NothingValue a where
- nothingValue :: Proxy a -> CMaybe (ToValueMaybe a)
- class Sel cfg ps where
- class Sel' cfg ps where
- type ToValE a p = ToExc (LookupFailed a p) (ToVal a p)
- data Exc a b
- data LookupFailed a p
- type family ToExc a x :: Exc k l
- merge :: forall cfg tm ti. (tm ~ TaggedM cfg, ti ~ Tagged cfg, Freeze cfg, Monoid tm, CanonicalizePartial cfg) => [tm] -> Either Error ti
- freeze :: forall cfg tm ti. (tm ~ TaggedM cfg, ti ~ Tagged cfg, Freeze cfg) => tm -> Either Error ti
- thaw :: forall cfg tm ti. (tm ~ TaggedM cfg, ti ~ Tagged cfg, Freeze cfg) => ti -> tm
- class Freeze c where
- class CanonicalizePartial a where
- canonicalizePartial :: TaggedM a -> TaggedM a
- emptyPartial :: TaggedM a -> Bool
- docs :: (HasToDoc a, HasRenderDoc ConfigFile, HasRenderDoc ShellEnv, HasRenderDoc CommandLine) => Proxy a -> ST
- data Doc
- data DocOptional
- concatDoc :: Doc -> Doc -> Doc
- class HasToDoc a where
- class HasRenderDoc t where
- cfgify :: QuasiQuoter
config types
Construction of config records (cons
for record fields).
a :*> b infixr 6 |
data ConfigCode k Source
Record (ConfigCode k) (ConfigCode k) infixr 6 | |
Label Symbol (ConfigCode k) | |
Descr (ConfigCode k) Symbol | |
List (ConfigCode k) | |
Option (ConfigCode k) | |
Type k |
type family ToConfigCode a :: ConfigCode * Source
Map user-provided config type to ConfigCode
types.
ToConfigCode (a :*> b) = Record (ToConfigCode a) (ToConfigCode b) | |
ToConfigCode (s :> a) = Label s (ToConfigCode a) | |
ToConfigCode (a :>: s) = Descr (ToConfigCode a) s | |
ToConfigCode [a] = List (ToConfigCode a) | |
ToConfigCode (Maybe a) = Option (ToConfigCode a) | |
ToConfigCode a = Type a |
type family NoDesc a :: ConfigCode * Source
Deprecated: use of NoDesc is redundant and can be dropped without replacement.
NoDesc a = a |
sources
tagged values
Tagged | |
|
TaggedM | |
|
Eq (ToConfig cfg Maybe) => Eq (TaggedM cfg) Source | |
Show (ToConfig cfg Maybe) => Show (TaggedM cfg) Source | |
((~) * t1 (ToConfig cfg1 Maybe), ToJSON (TaggedM cfg1), (~) * t2 (ToConfig cfg2 Maybe), ToJSON (TaggedM cfg2)) => ToJSON (TaggedM (Record * cfg1 cfg2)) Source | instance ToJSON Record |
(ToJSON (TaggedM cfg), KnownSymbol s) => ToJSON (TaggedM (Label * s cfg)) Source | instance ToJSON Label |
((~) * (ToConfig (Descr * cfg s) Maybe) (ToConfig cfg Maybe), ToJSON (TaggedM cfg)) => ToJSON (TaggedM (Descr * cfg s)) Source | |
((~) * t (ToConfig cfg Maybe), ToJSON (TaggedM cfg)) => ToJSON (TaggedM (List * cfg)) Source | instance ToJSON List |
((~) * t (ToConfig cfg Maybe), (~) * (ToConfig (Option * cfg) Maybe) (MaybeO t''), ToJSON (TaggedM cfg)) => ToJSON (TaggedM (Option * cfg)) Source | instance ToJSON Option |
ToJSON a => ToJSON (TaggedM (Type * a)) Source | instance ToJSON Type |
(FromJSON (TaggedM cfg1), FromJSON (TaggedM cfg2)) => FromJSON (TaggedM (Record * cfg1 cfg2)) Source | instance FromJSON Record |
(FromJSON (TaggedM cfg), KnownSymbol s) => FromJSON (TaggedM (Label * s cfg)) Source |
|
((~) * (ToConfig (Descr * cfg s) Maybe) (ToConfig cfg Maybe), FromJSON (TaggedM cfg)) => FromJSON (TaggedM (Descr * cfg s)) Source | |
FromJSON (TaggedM cfg) => FromJSON (TaggedM (List * cfg)) Source | instance ParseJSON List |
FromJSON (TaggedM cfg) => FromJSON (TaggedM (Option * cfg)) Source | instance ParseJSON Option |
FromJSON a => FromJSON (TaggedM (Type * a)) Source | instance FromJSON Type |
(Monoid (TaggedM a), Monoid (TaggedM b)) => Monoid (TaggedM (Record * a b)) Source | |
Monoid (TaggedM (Label * s (Type * a))) Source | There is no |
Monoid (TaggedM a) => Monoid (TaggedM (Label * s a)) Source | If one of two configs is |
((~) * (ToConfig (Descr * a s) Maybe) (ToConfig a Maybe), (~) * (ToConfig a Maybe) (Maybe a'), Monoid (TaggedM a)) => Monoid (TaggedM (Descr * a s)) Source | |
Monoid (TaggedM (List * a)) Source | Lists are initialized empty by default. Append overwrites left values with right values. (If we tried to append list elements recursively, there would be awkward questions about matching list lengths.) |
Monoid (TaggedM a) => Monoid (TaggedM (Option * a)) Source |
results and errors
the main function
configify :: forall cfg tm. (tm ~ TaggedM cfg, Show tm, Monoid tm, Freeze cfg, FromJSON tm, HasParseShellEnv cfg, HasParseCommandLine cfg, CanonicalizePartial cfg) => [Source] -> IO (Tagged cfg) Source
configifyWithDefault :: forall cfg tm. (tm ~ TaggedM cfg, Show tm, Monoid tm, Freeze cfg, FromJSON tm, HasParseShellEnv cfg, HasParseCommandLine cfg, CanonicalizePartial cfg) => tm -> [Source] -> IO (Tagged cfg) Source
IO
defaultSources :: [FilePath] -> IO [Source] Source
From a list of config file paths, construct a source list that
(1) reads those files allowing for recursive includes; then (2)
processes shell environment variables (with getProgName
as
prefix), and finally (3) processes command line args, turning
--config
arguments into further recursive config file loads.
File path arguments are optiona; config paths to non-existent files are silently dropped.
withShellEnvPrefix :: Env -> IO Env Source
Require that all shell env variables start with executable name.
(This is just a call to requireShellEnvPrefix'
with the result of
progName
.)
corner cases
readUserConfigFiles :: [Source] -> [Source] Source
Handle `--config=<FILE>`, `--config FILE`: split up
CommandLine
source on each of these, and inject a
YamlFile
source with the resp. file name.
withShellEnvPrefix' :: String -> Env -> Env Source
Require prefix for shell env variables. This function will chop off the given prefix of all env entries, and filter all entries that do not have this prefix.
yaml / json
parseConfigFileWithIncludes :: FromJSON (TaggedM cfg) => FilePath -> IO (Either Error (TaggedM cfg)) Source
See Data.Yaml.Include.
shell env
class HasParseShellEnv cfg where Source
HasParseShellEnv a => HasParseShellEnv (List * a) Source | You can provide a list value via the shell environment by providing a single element. This element will be put into a list implicitly. (A more general approach that allows for yaml-encoded list values in shell variables is more tricky to design, implement, and use: If you have a list of sub-configs and don't want the entire sub-config to be yaml-encoded, but use a longer shell variable name to go further down to deeper sub-configs, there is a lot of ambiguity. It may be possible to resolve that at run-time, but it's more tricky.) |
HasParseShellEnv a => HasParseShellEnv (Option * a) Source | |
(Typeable * a, FromJSON (TaggedM (Type * a))) => HasParseShellEnv (Type * a) Source | |
(HasParseShellEnv a, HasParseShellEnv b) => HasParseShellEnv (Record * a b) Source | |
(KnownSymbol path, HasParseShellEnv a) => HasParseShellEnv (Label * path a) Source | The paths into the recursive structure of the config file are concatenated to shell variable names with separating '_'. (It is still ok to have '_' in your config path names. This parser chops off complete matching names, whether they contain '_' or not, and only then worries about trailing '_'.) |
((~) * (ToConfig (Descr * cfg s) Maybe) (ToConfig cfg Maybe), HasParseShellEnv cfg) => HasParseShellEnv (Descr * cfg s) Source |
cli
class HasParseCommandLine cfg where Source
HasParseShellEnv cfg => HasParseCommandLine cfg Source |
primitiveParseCommandLine :: HasParseShellEnv cfg => [String] -> Either Error (TaggedM cfg) Source
Very basic first approach: read --(key)(=|s+)(value)
;
construct shell env from keys and names, and use parseShellEnv
on
the command line. If it doesn't like the syntax used in the
command line, it will crash. I hope for this to get much fancier
in the future.
parseArgName :: String -> String Source
accessing config values
(>>.) :: forall cfg ps r. (Sel cfg ps, ToValE cfg ps ~ Done r) => Tagged cfg -> Proxy ps -> r infix 7 Source
Map a Tagged
config value and a type-level path to the part of
the config value the path points to. Trigger an informative type
error if path does not exist.
options
type family ToValueMaybe a :: Maybe * Source
ToValueMaybe (Just x) = Just (Maybe x) | |
ToValueMaybe Nothing = Nothing |
toValueMaybe :: CMaybe a -> CMaybe (ToValueMaybe a) Source
class NothingValue a where Source
nothingValue :: Proxy a -> CMaybe (ToValueMaybe a) Source
NothingValue (Nothing *) Source | |
NothingValue (Just * x) Source |
cfg traversal
Sel' cfg ps => Sel cfg ps Source | |
((~) (ConfigCode *) cfg (Option * cfg'), NothingValue (ToVal cfg' ps), Sel cfg' ps) => Sel (Option * cfg') ps Source | |
((~) (ConfigCode *) cfg (Descr * cfg' s), Sel cfg' ps, (~) * (ToConfig (Descr * cfg' s) Id) (ToConfig cfg' Id)) => Sel (Descr * cfg' s) ps Source | |
Sel (Record * cfg' cfg'') ([] Symbol) Source | |
((~) (ConfigCode *) cfg (Record * cfg' cfg''), Sel cfg' ((:) Symbol p ps), Sel cfg'' ((:) Symbol p ps)) => Sel (Record * cfg' cfg'') ((:) Symbol p ps) Source | |
((~) (ConfigCode *) cfg (Label * p cfg'), Sel cfg' ps, KnownSymbol p) => Sel (Label * p cfg') ((:) Symbol p ps) Source |
static lookup error handling
type ToValE a p = ToExc (LookupFailed a p) (ToVal a p) Source
data LookupFailed a p Source
merge configs
merge :: forall cfg tm ti. (tm ~ TaggedM cfg, ti ~ Tagged cfg, Freeze cfg, Monoid tm, CanonicalizePartial cfg) => [tm] -> Either Error ti Source
freeze :: forall cfg tm ti. (tm ~ TaggedM cfg, ti ~ Tagged cfg, Freeze cfg) => tm -> Either Error ti Source
Freeze c => Freeze (List * c) Source | |
((~) * (ToConfig (Option * c) Maybe) (MaybeO tm), (~) * (ToConfig (Option * c) Id) (MaybeO ti), (~) * tm (ToConfig c Maybe), (~) * ti (ToConfig c Id), Freeze c) => Freeze (Option * c) Source | FIXME: if a non-optional part of an optional sub-config is
missing, the |
Freeze (Type * c) Source | |
(Freeze a, Freeze b) => Freeze (Record * a b) Source | |
(KnownSymbol s, Freeze t) => Freeze (Label * s t) Source | |
((~) * (ToConfig (Descr * t s) Maybe) (ToConfig t Maybe), (~) * (ToConfig (Descr * t s) Id) (ToConfig t Id), Freeze t) => Freeze (Descr * t s) Source |
class CanonicalizePartial a where Source
Partials are constructed with every Nothing
spelled out,
resulting in deep skeletons of Nothing
s. CanonicalizePartial
replaces those with single Nothing
s at their tops.
canonicalizePartial :: TaggedM a -> TaggedM a Source
emptyPartial :: TaggedM a -> Bool Source
((~) (ConfigCode *) cfg (List * cfg'), CanonicalizePartial cfg') => CanonicalizePartial (List * cfg') Source | |
((~) (ConfigCode *) cfg (Option * cfg'), CanonicalizePartial cfg') => CanonicalizePartial (Option * cfg') Source | |
CanonicalizePartial (Type * a) Source | |
(CanonicalizePartial cfg, CanonicalizePartial cfg') => CanonicalizePartial (Record * cfg cfg') Source | |
((~) (ConfigCode *) cfg (Label * s cfg'), CanonicalizePartial cfg') => CanonicalizePartial (Label * s cfg') Source | |
((~) (ConfigCode *) cfg (Descr * cfg' s), CanonicalizePartial cfg') => CanonicalizePartial (Descr * cfg' s) Source |
docs
docs :: (HasToDoc a, HasRenderDoc ConfigFile, HasRenderDoc ShellEnv, HasRenderDoc CommandLine) => Proxy a -> ST Source
data DocOptional Source
HasToDoc a => HasToDoc (List * a) Source | |
HasToDoc a => HasToDoc (Option * a) Source | |
Typeable * a => HasToDoc (Type * a) Source | |
(HasToDoc a, HasToDoc b) => HasToDoc (Record * a b) Source | |
(KnownSymbol path, HasToDoc a) => HasToDoc (Label * path a) Source | |
(HasToDoc a, KnownSymbol path, KnownSymbol descr) => HasToDoc (Descr * (Label * path a) descr) Source |
class HasRenderDoc t where Source
template haskell
QuasiQuoter for config files.