From the beginning of the Elektra Initiative, Elektra aimed at avoiding hard coded information in the application and to make the application's configuration more transparent. While avoiding any paths to files was reality from the first released Elektra version, now also hard coding default values, fallback mechanisms and even Elektra’s paths to keys can be avoided.
Elektra 0.8.11 introduces a so-called specification for the
application's configuration. It is located below its own namespace
spec
(next to user and system).
Once the base path is known, the user can find out all Elektra paths used by an application, using:
kdb ls spec/basepath
Keys in spec
allow us to specify which keys are read by the application,
which fallback it might have and which is the default value using
metadata. The implementation of these features happened in ksLookup
.
When cascading keys (those starting with /
) are used following features
are now available (in the metadata of respective spec
-keys):
override/#
: use these keys in favor of the key itself (note that
#
is the syntax for arrays, e.g. #0
for the first element,
#_10
for the 11th and so on)namespace/#
: instead of using all namespaces in the predefined order,
one can specify which namespaces should be searched in which orderfallback/#
: when no key was found in any of the (specified) namespaces
the fallback
-keys will be searcheddefault
: this value will be used if nothing else was foundThis technique does not only give you the obvious advantages, but also provides complete transparency how a program will fetch a configuration value. In practice that means that:
kdb get "/sw/app/#0/promise"
will give you the exact same value as the application uses when it
lookups the key promise
. Many if
s and hard coded values are avoided,
we simply fetch and lookup the configuration by following code:
Key *parentKey = keyNew("/sw/app/#0", KEY_CASCADING_NAME, KEY_END);
kdbGet(kdb, ks, parentKey);
ksLookupByName(ks, "/sw/app/#0/promise", 0);
We see in that example that only Elektra paths are hard coded in the application. But those can be found out easily, completely without looking in the source code. The technique is simple: append a logger plugin and the KDB base path is printed to:
What we do not see in the program above are the default values and
fallbacks. They are only present in the so specification (namespace spec
).
Luckily, the specification are key-value pairs, too. So we do not have
to learn something new, e.g. using the ni plugin we can specify:
[promise]
default=20
fallback/#0=/somewhere/else
namespace/#0=user
spec/sw/app/#0
we specify, that
for the key /sw/app/#0/promise
only the namespace user
should be
used./somewhere/else
is present, we will use
this key instead. The fallback
technique is very powerful: it allows
us to have (recursive) links between applications. In the example above,
the application is tricked in receiving e.g. the key user/somewhere/else
when promise
was not available.20
will be used as default, even if no configuration file
is found.Note that the fallback, override and cascading works on key level, and not like most other systems have implemented, on configuration file level.
The specification gives the namespaces clearer semantics and purpose. Key names starting with a namespace are connected to a configuration source. E.g. keys starting with:
user
are keys from the home directory of the current usersystem
are keys from the /etc
directory of the current systemspec
are keys from the specification directory (configurable
with KDB_DB_SPEC
, typically /usr/share/elektra/specification
)When a key name starts with an /
it means that it is looked up by
specification. Such a cascading key is not really present in the keyset
(except when a default value was found). They are neither received
nor stored by kdbGet
and kdbSet
.
Applications shall only lookup using cascading keys (starting with /
).
If no specification is present, cascading of all namespaces is used as before.
Elektra will (always) continue to work for applications that do not have a specification. We strongly encourage you, however, to write such a specification, because:
For a tutorial how to actually elektrify an application and for more background to Elektra, read this document.
For a full list of proposed and implemented metadata, read this document.
As it turned out the concept of very granular merge strategies was hard to understand for users of the three-way merging framework that emerged in the last year's GSoC. While this granularity is desirable for flexibility, we additionally wanted something easy to use. For that reason merge configurations were introduced. These are simply preconfigured configurations for a merger that arrange required strategies for the most common merging scenarios. Especially they make sure that meta merging is handled correctly.
Have a look at the changes in the example /src/libs/tools/examples/merging.cpp for an glimpse of the simplifications.
A big thanks to Felix Berlakovich!
The header files will be installed to /usr/include/elektra/merging, but they are subject to be changed in the future (e.g. as they did in this release).
From the merging improvements some minor incompatibility happened in
kdb import
. Not all merging strategies that worked in 0.8.10 work
anymore. Luckily, now its much simpler to choose the strategies.
The main API kdb.h has two added lines. First a new method was added:
ssize_t keyAddName(Key *key, const char *addName);
This method is already used heavily in many parts. Contrary to keySetBaseName
and
keyAddBaseName
it allows us to extend the path with more than one Element at once,
i.e. /
are not escaped.
The other new line is the new enum value KEY_FLAGS
.
This feature allows bindings to use any flags in keyNew without actually
building up variable argument lists. (Thanks to Manuel Mausz)
As always, API+ABI is stable and compatible.
Many new functions are proposed and can be found in the doxygen documentation and in kdbproposal.h.
Noteworthy is the method keyGetNamespace
which allows us to query all
namespaces. Since this release we changed every occurrence of namespaces
(except documentation) with switch-statements around keyGetNamespace
.
This allows us to add new more namespaces more easily. (Although its
currently not planned to add further namespaces.)
Finally, a bunch of new lookup options were added, which might not be useful for the public API (they allow us to disable the specification-aware features mentioned in the beginning).
The concept that backends have a name (other than their mountpoint) is now gone. Backends will simply be named with their escaped mountpath below system/elektra/mountpoints without any confusing additional name.
Unmounting still works with the mountpath.
Removing this concept makes Elektra easier to understand and it also
removes some bugs. E.g. having mountpoints which do not differ except
having a _
instead of a /
would have caused problems with the
automatic name generation of Elektra 0.8.10.
Old mountpoints need to be removed with their 0.8.10 name
(_
instead of /
).
Additionally, the so-called directory keys were also removed.
Elektra was and still is completely key-value based. The /
separator
is only used for mountpoints.
The plugin fstab is also improved: Slashes in mountpoints are
escaped properly with the internal escaping engine of keyAddBaseName()
(i.e. without any problematic /
replacements).
getDirName() was removed from C++, gi-lua, gi-python2, gi-python3, swig-lua, swig-python2 and swig-python3. It was never present in C and did not fit well with keyBaseName() (which returns an unescaped name, which is not possible for the dirname). (Thanks to Manuel Mausz)
While empty (=invalid) names are still accepted as parentName to kdbGet
and kdbSet
for compatibility reasons, but the parentKey
Key *parentKey = keyNew("/", KEY_END);
should be used instead (if you want to get or store everything). They have identical behavior, except that invalid names (that cannot be distinguished from empty names) will produce a warning. In the next major version invalid parentNames will produce an error.
It is now enforced that before a kdbSet() on a specific path a kdbGet() on that path needs to be done. This was always documented that way and is the only way to correctly detect conflicts, updates and missing configuration files. Error #107 will be reported on violations.
Additionally, the handling with missing files was improved. Empty keysets for a mountpoint now will remove a file. Such an empty file is always up-to-date. Removing files has the same atomicity guarantees as other operations.
The concurrency behavior is at a very high level: as expected many processes with many threads can each concurrently write to the key database, without any inconsistent states: This is noted here because Elektra works on standard configuration files without any guarding processes.
Filesystem problems, e.g. permission, now always lead to the same errors (#9, #75, #109, #110), regardless of the storage plugin.
Raffael Pancheri was very busy and did a lot of stabilizing work:
The gui is already used and the remaining small bugs (see github) are going to be fixed soon. One of the highlights is undo for nearly every action, so nothing prevents you from trying it out!
A huge thanks to Raffael Pancheri for his contributions. His thesis can be found at here.
kdb getmeta
reports errorcode if key, but no meta was foundksLookup
now will also work if a key of the keyset is used as
search-key (aliasing problem fixed by dup() on namelock)$RANDOM
)CMAKE_DL_LIBS
(thanks to Manuel Mausz)add_plugin
(thanks to Ian Donnelly for most of the work)keyName
methodssystem/elektra/mountpoints
itself was always created and a
left-over on a freshly installed system after the unit tests run the
first time. The physical presence of the key is now irrelevant and
it won't be created automatically.kdb list-tools
is now advertised in kdb --help
With 471 files changed, 27978 insertions(+), 11512 deletions(-) this release is huge. With 773 commits over four month much more changes happened which did not find their place in these release notes, even though the notes are much less detailed than usual.
Thanks for all contributions that are not enlisted here!
For any questions and comments, please contact the Mailing List or elektra@markus-raab.org.
You can download the release from here
This release tarball now is also available signed by me using gpg
already built API documentation can be found here
Subscribe to the new RSS feed to always get the release notifications.
For more information, see https://www.libelektra.org
Best regards, Markus