| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Data.Configifier
Contents
- 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
config types
Construction of config records (cons for record fields).
Constructors
| a :*> b infixr 6 |
Construction of config record fields.
Add descriptive text to record field for documentation.
data ConfigCode k Source
Constructors
| 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.
Equations
| 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.
Equations
| NoDesc a = a |
Transformers' Identity is not in Typeable, so we roll our
own. It's also less work to write.
Constructors
| Id a |
sources
Constructors
| YamlString SBS | |
| YamlFile FilePath | |
| ShellEnv [(String, String)] | |
| CommandLine [String] |
data ConfigFile Source
Instances
Instances
data CommandLine Source
Instances
tagged values
Constructors
| Tagged | |
Fields
| |
Constructors
| TaggedM | |
Fields
| |
Instances
| Eq (ToConfig cfg Maybe) => Eq (TaggedM cfg) | |
| Show (ToConfig cfg Maybe) => Show (TaggedM cfg) | |
| ToJSON a => ToJSON (TaggedM (Type * a)) | instance ToJSON Type |
| ((~) * t (ToConfig cfg Maybe), (~) * (ToConfig (Option * cfg) Maybe) (MaybeO t''), ToJSON (TaggedM cfg)) => ToJSON (TaggedM (Option * cfg)) | instance ToJSON Option |
| ((~) * t (ToConfig cfg Maybe), ToJSON (TaggedM cfg)) => ToJSON (TaggedM (List * cfg)) | instance ToJSON List |
| ((~) * (ToConfig (Descr * cfg s) Maybe) (ToConfig cfg Maybe), ToJSON (TaggedM cfg)) => ToJSON (TaggedM (Descr * cfg s)) | |
| (ToJSON (TaggedM cfg), KnownSymbol s) => ToJSON (TaggedM (Label * s cfg)) | instance ToJSON Label |
| ((~) * t1 (ToConfig cfg1 Maybe), ToJSON (TaggedM cfg1), (~) * t2 (ToConfig cfg2 Maybe), ToJSON (TaggedM cfg2)) => ToJSON (TaggedM (Record * cfg1 cfg2)) | instance ToJSON Record |
| FromJSON a => FromJSON (TaggedM (Type * a)) | instance FromJSON Type |
| FromJSON (TaggedM cfg) => FromJSON (TaggedM (Option * cfg)) | instance ParseJSON Option |
| FromJSON (TaggedM cfg) => FromJSON (TaggedM (List * cfg)) | instance ParseJSON List |
| ((~) * (ToConfig (Descr * cfg s) Maybe) (ToConfig cfg Maybe), FromJSON (TaggedM cfg)) => FromJSON (TaggedM (Descr * cfg s)) | |
| (FromJSON (TaggedM cfg), KnownSymbol s) => FromJSON (TaggedM (Label * s cfg)) |
|
| (FromJSON (TaggedM cfg1), FromJSON (TaggedM cfg2)) => FromJSON (TaggedM (Record * cfg1 cfg2)) | instance FromJSON Record |
| Monoid (TaggedM a) => Monoid (TaggedM (Option * a)) | |
| Monoid (TaggedM (List * a)) | 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.) |
| ((~) * (ToConfig (Descr * a s) Maybe) (ToConfig a Maybe), (~) * (ToConfig a Maybe) (Maybe a'), Monoid (TaggedM a)) => Monoid (TaggedM (Descr * a s)) | |
| Monoid (TaggedM (Label * s (Type * a))) | There is no |
| Monoid (TaggedM a) => Monoid (TaggedM (Label * s a)) | If one of two configs is |
| (Monoid (TaggedM a), Monoid (TaggedM b)) => Monoid (TaggedM (Record * a b)) |
results and errors
Constructors
| InvalidYamlString | |
Fields | |
| InvalidYamlFile | |
Fields | |
| ShellEnvNil | |
| ShellEnvNoParse | |
Fields | |
| CommandLinePrimitiveParseError String | |
| CommandLinePrimitiveOtherError Error | |
| FreezeIncomplete | |
Fields | |
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.
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
Instances
| (Typeable * a, FromJSON (TaggedM (Type * a))) => HasParseShellEnv (Type * a) | |
| HasParseShellEnv a => HasParseShellEnv (Option * a) | |
| HasParseShellEnv a => HasParseShellEnv (List * a) | 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.) |
| ((~) * (ToConfig (Descr * cfg s) Maybe) (ToConfig cfg Maybe), HasParseShellEnv cfg) => HasParseShellEnv (Descr * cfg s) | |
| (KnownSymbol path, HasParseShellEnv a) => HasParseShellEnv (Label * path a) | 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 '_'.) |
| (HasParseShellEnv a, HasParseShellEnv b) => HasParseShellEnv (Record * a b) |
cli
class HasParseCommandLine cfg where Source
Instances
| HasParseShellEnv cfg => HasParseCommandLine cfg |
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.
type family ToVal a p :: Maybe * Source
Map ConfgCode types to the types of config values.
Equations
| ToVal (Record a b) [] = Just (ToConfig (Record a b) Id) | |
| ToVal (Record a b) ps = OrElse (ToVal a ps) (ToVal b ps) | |
| ToVal (Label p a) (p : ps) = ToVal a ps | |
| ToVal (Descr a s) ps = ToVal a ps | |
| ToVal (Option a) ps = ToValueMaybe (ToVal a ps) | |
| ToVal a [] = Just (ToConfig a Id) | |
| ToVal a (p : ps) = Nothing |
options
type family ToValueMaybe a :: Maybe * Source
Equations
| ToValueMaybe (Just x) = Just (Maybe x) | |
| ToValueMaybe Nothing = Nothing |
toValueMaybe :: CMaybe a -> CMaybe (ToValueMaybe a) Source
class NothingValue a where Source
Methods
nothingValue :: Proxy a -> CMaybe (ToValueMaybe a) Source
Instances
| NothingValue (Nothing *) | |
| NothingValue (Just * x) |
cfg traversal
Instances
| Sel' cfg ps => Sel cfg ps | |
| ((~) (ConfigCode *) cfg (Option * cfg'), NothingValue (ToVal cfg' ps), Sel cfg' ps) => Sel (Option * cfg') ps | |
| ((~) (ConfigCode *) cfg (Descr * cfg' s), Sel cfg' ps, (~) * (ToConfig (Descr * cfg' s) Id) (ToConfig cfg' Id)) => Sel (Descr * cfg' s) ps | |
| Sel (Record * cfg' cfg'') ([] Symbol) | |
| ((~) (ConfigCode *) cfg (Label * p cfg'), Sel cfg' ps, KnownSymbol p) => Sel (Label * p cfg') ((:) Symbol p ps) | |
| ((~) (ConfigCode *) cfg (Record * cfg' cfg''), Sel cfg' ((:) Symbol p ps), Sel cfg'' ((:) Symbol p ps)) => Sel (Record * cfg' cfg'') ((:) Symbol p ps) |
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
Instances
| Freeze (Type * c) | |
| ((~) * (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) | FIXME: if a non-optional part of an optional sub-config is
missing, the |
| Freeze c => Freeze (List * c) | |
| ((~) * (ToConfig (Descr * t s) Maybe) (ToConfig t Maybe), (~) * (ToConfig (Descr * t s) Id) (ToConfig t Id), Freeze t) => Freeze (Descr * t s) | |
| (KnownSymbol s, Freeze t) => Freeze (Label * s t) | |
| (Freeze a, Freeze b) => Freeze (Record * a b) |
class CanonicalizePartial a where Source
Partials are constructed with every Nothing spelled out,
resulting in deep skeletons of Nothings. CanonicalizePartial
replaces those with single Nothings at their tops.
Instances
| CanonicalizePartial (Type * a) | |
| ((~) (ConfigCode *) cfg (Option * cfg'), CanonicalizePartial cfg') => CanonicalizePartial (Option * cfg') | |
| ((~) (ConfigCode *) cfg (List * cfg'), CanonicalizePartial cfg') => CanonicalizePartial (List * cfg') | |
| ((~) (ConfigCode *) cfg (Descr * cfg' s), CanonicalizePartial cfg') => CanonicalizePartial (Descr * cfg' s) | |
| ((~) (ConfigCode *) cfg (Label * s cfg'), CanonicalizePartial cfg') => CanonicalizePartial (Label * s cfg') | |
| (CanonicalizePartial cfg, CanonicalizePartial cfg') => CanonicalizePartial (Record * cfg cfg') |
docs
docs :: (HasToDoc a, HasRenderDoc ConfigFile, HasRenderDoc ShellEnv, HasRenderDoc CommandLine) => Proxy a -> ST Source
Instances
| Typeable * a => HasToDoc (Type * a) | |
| HasToDoc a => HasToDoc (Option * a) | |
| HasToDoc a => HasToDoc (List * a) | |
| (HasToDoc a, KnownSymbol path, KnownSymbol descr) => HasToDoc (Descr * (Label * path a) descr) | |
| (KnownSymbol path, HasToDoc a) => HasToDoc (Label * path a) | |
| (HasToDoc a, HasToDoc b) => HasToDoc (Record * a b) |
class HasRenderDoc t where Source
Instances