Portability | portable |
---|---|
Stability | experimental |
Maintainer | Bryan O'Sullivan <bos@serpentine.com> |
Safe Haskell | None |
A simple (yet powerful) library for working with configuration files.
- data Worth a
- autoReload :: AutoConfig -> [Worth FilePath] -> IO (Config, ThreadId)
- autoReloadGroups :: AutoConfig -> [(Name, Worth FilePath)] -> IO (Config, ThreadId)
- autoConfig :: AutoConfig
- empty :: Config
- lookup :: Configured a => Config -> Name -> IO (Maybe a)
- lookupDefault :: Configured a => a -> Config -> Name -> IO a
- require :: Configured a => Config -> Name -> IO a
- prefix :: Text -> Pattern
- exact :: Text -> Pattern
- subscribe :: Config -> Pattern -> ChangeHandler -> IO ()
- load :: [Worth FilePath] -> IO Config
- loadGroups :: [(Name, Worth FilePath)] -> IO Config
- reload :: Config -> IO ()
- subconfig :: Name -> Config -> Config
- addToConfig :: [Worth FilePath] -> Config -> IO ()
- addGroupsToConfig :: [(Name, Worth FilePath)] -> Config -> IO ()
- display :: Config -> IO ()
- getMap :: Config -> IO (HashMap Name Value)
Configuration file format
A configuration file consists of a series of directives and
comments, encoded in UTF-8. A comment begins with a "#
"
character, and continues to the end of a line.
Files and directives are processed from first to last, top to bottom.
Binding a name to a value
A binding associates a name with a value.
my_string = "hi mom! \u2603" your-int-33 = 33 his_bool = on HerList = [1, "foo", off]
A name must begin with a Unicode letter, which is followed by zero
or more of a Unicode alphanumeric code point, hyphen "-
", or
underscore "_
".
Bindings are created or overwritten in the order in which they are encountered. It is legitimate for a name to be bound multiple times, in which case the last value wins.
a = 1 a = true # value of a is now true, not 1
Value types
The configuration file format supports the following data types:
- Booleans, represented as
on
oroff
,true
orfalse
. These are case sensitive, so do not try to useTrue
instead oftrue
! - Integers, represented in base 10.
- Unicode strings, represented as text (possibly containing escape sequences) surrounded by double quotes.
- Heterogeneous lists of values, represented as an opening square
bracket "
[
", followed by a series of comma-separated values, ending with a closing square bracket "]
".
The following escape sequences are recognised in a text string:
-
\n
- newline -
\r
- carriage return -
\t
- horizontal tab -
\\
- backslash -
\"
- double quote -
\u
xxxx - Unicode character from the basic multilingual plane, encoded as four hexadecimal digits -
\u
xxxx\u
xxxx - Unicode character from an astral plane, as two hexadecimal-encoded UTF-16 surrogates
String interpolation
Strings support interpolation, so that you can dynamically construct a string based on data in your configuration or the OS environment.
If a string value contains the special sequence "$(foo)
" (for
any name foo
), then the name foo
will be looked up in the
configuration data and its value substituted. If that name cannot
be found, it will be looked up in the OS environment.
For security reasons, it is an error for a string interpolation fragment to contain a name that cannot be found in either the current configuration or the environment.
To represent a single literal "$
" character in a string, double
it: "$$
".
Grouping directives
It is possible to group a number of directives together under a single prefix:
my-group { a = 1 # groups support nesting nested { b = "yay!" } }
The name of a group is used as a prefix for the items in the
group. For instance, the value of "a
" above can be retrieved
using lookup
by supplying the name "my-group.a
", and "b
"
will be named "my-group.nested.b
".
Importing files
To import the contents of another configuration file, use the
import
directive.
import "$(HOME)/etc/myapp.cfg"
Absolute paths are imported as is. Relative paths are resolved with
respect to the file they are imported from. It is an error for an
import
directive to name a file that does not exist, cannot be read,
or contains errors.
If an import
appears inside a group, the group's naming prefix
will be applied to all of the names imported from the given
configuration file.
Supposing we have a file named "foo.cfg
":
bar = 1
And another file that imports it into a group:
hi { import "foo.cfg" }
This will result in a value named "hi.bar
".
Types
Loading configuration data
:: AutoConfig | Directions for when to reload and how to handle errors. |
-> [Worth FilePath] | Configuration files to load. |
-> IO (Config, ThreadId) |
Load a Config
from the given FilePath
s, and start a reload
thread.
At intervals, a thread checks for modifications to both the
original files and any files they refer to in import
directives,
and reloads the Config
if any files have been modified.
If the initial attempt to load the configuration files fails, an
exception is thrown. If the initial load succeeds, but a
subsequent attempt fails, the onError
handler is invoked.
File names have any environment variables expanded prior to the
first time they are opened, so you can specify a file name such as
"$(HOME)/myapp.cfg"
.
autoReloadGroups :: AutoConfig -> [(Name, Worth FilePath)] -> IO (Config, ThreadId)Source
autoConfig :: AutoConfigSource
Defaults for automatic Config
reloading when using
autoReload
. The interval
is one second, while the onError
action ignores its argument and does nothing.
Lookup functions
Look up a name in the given Config
. If a binding exists, and
the value can be converted to the desired type, return it,
otherwise return the default value.
Notification of configuration changes
To more efficiently support an application's need to dynamically
reconfigure, a subsystem may ask to be notified when a
configuration property is changed as a result of a reload, using
the subscribe
action.
prefix :: Text -> PatternSource
A pattern that matches on a prefix of a property name. Given
"foo"
, this will match "foo.bar"
, but not "foo"
or
"foobar"
.
subscribe :: Config -> Pattern -> ChangeHandler -> IO ()Source
Subscribe for notifications. The given action will be invoked when any change occurs to a configuration property matching the supplied pattern.
Low-level loading functions
load :: [Worth FilePath] -> IO ConfigSource
Create a Config
from the contents of the named files. Throws an
exception on error, such as if files do not exist or contain errors.
File names have any environment variables expanded prior to the
first time they are opened, so you can specify a file name such as
"$(HOME)/myapp.cfg"
.
loadGroups :: [(Name, Worth FilePath)] -> IO ConfigSource
Create a Config
from the contents of the named files, placing them
into named prefixes. If a prefix is non-empty, it should end in a
dot.
addToConfig :: [Worth FilePath] -> Config -> IO ()Source
Add additional files to a Config
, causing it to be reloaded to add
their contents.
addGroupsToConfig :: [(Name, Worth FilePath)] -> Config -> IO ()Source
Add additional files to named groups in a Config
, causing it to be
reloaded to add their contents. If the prefixes are non-empty, they should
end in dots.