Elektra  0.8.22
Plugin: yamlcpp

YAML CPP

Introduction

The YAML CPP plugin reads and writes configuration data via the yaml-cpp library.

Usage

You can mount this plugin via kdb mount:

sudo kdb mount config.yaml /examples/yamlcpp yamlcpp

. To unmount the plugin use kdb umount:

sudo kdb umount /examples/yamlcpp

. The following examples show how you can store and retrieve data via yamlcpp.

`` <h1>Mount yamlcpp plugin to cascading namespace/examples/yamlcpp` sudo kdb mount config.yaml /examples/yamlcpp yamlcpp

Manually add a mapping to the database

echo "πŸ”‘ : 🐳" > kdb file /examples/yamlcpp

Retrieve the value of the manually added key

kdb get /examples/yamlcpp/πŸ”‘ #> 🐳

Manually add syntactically incorrect data

echo "some key: @some value" >> kdb file /examples/yamlcpp kdb get "/examples/yamlcpp/some key"

STDERR: .*yaml-cpp: error at line 2, column 11: unknown token.*

ERROR: 10

RET: 5

Overwrite incorrect data

echo "πŸ”‘: value" > kdb file /examples/yamlcpp

Add some values via kdb set

kdb set /examples/yamlcpp/fleetwood mac kdb set /examples/yamlcpp/the chain

Retrieve the new values

kdb get /examples/yamlcpp/the #> chain kdb get /examples/yamlcpp/fleetwood #> mac

Undo modifications

kdb rm -r /examples/yamlcpp sudo kdb umount /examples/yamlcpp

## Arrays
YAML CPP provides basic support for Elektra’s array data type.

Mount yamlcpp plugin to cascading namespace /examples/yamlcpp

sudo kdb mount config.yaml /examples/yamlcpp yamlcpp

Manually add an array to the database

echo 'sunny:' > kdb file /examples/yamlcpp echo ' - Charlie' >> kdb file /examples/yamlcpp echo ' - Dee' >> kdb file /examples/yamlcpp

List the array entries

kdb ls /examples/yamlcpp #> user/examples/yamlcpp/sunny #> user/examples/yamlcpp/sunny/#0 #> user/examples/yamlcpp/sunny/#1

Read an array entry

kdb get user/examples/yamlcpp/sunny/#1 #> Dee

You can retrieve the last index of an array by reading the metakey array

kdb getmeta /examples/yamlcpp/sunny array

1

Extend the array

kdb set user/examples/yamlcpp/sunny/#2 Dennis kdb set user/examples/yamlcpp/sunny/#3 Frank kdb set user/examples/yamlcpp/sunny/#4 Mac

Retrieve the last array entry

kdb get user/examples/yamlcpp/sunny/$(kdb getmeta user/examples/yamlcpp/sunny array) #> Mac

Undo modifications to the key database

kdb rm -r /examples/yamlcpp sudo kdb umount /examples/yamlcpp

The plugin also supports nested arrays.

Mount yamlcpp plugin to cascading namespace /examples/yamlcpp

sudo kdb mount config.yaml /examples/yamlcpp yamlcpp

Add some key value pairs

kdb set /examples/yamlcpp/key value kdb set /examples/yamlcpp/array/#0 scalar kdb set /examples/yamlcpp/array/#1/key value kdb set /examples/yamlcpp/array/#1/πŸ”‘ πŸ™ˆ

kdb ls /examples/yamlcpp #> user/examples/yamlcpp/array #> user/examples/yamlcpp/array/#0 #> user/examples/yamlcpp/array/#1 #> user/examples/yamlcpp/array/#1/key #> user/examples/yamlcpp/array/#1/πŸ”‘ #> user/examples/yamlcpp/key

Retrieve part of an array value

kdb get /examples/yamlcpp/array/#1/key #> value

Since an array saves a list of values, an array parent

- which represent the array - does not store a value!

echo "/examples/yamlcpp/array: β€œ`kdb get /examples/yamlcpp/array`”" #> /examples/yamlcpp/array: β€œβ€ kdb get /examples/yamlcpp/array/#1 echo "/examples/yamlcpp/array/#1: β€œ`kdb get /examples/yamlcpp/array/#1`”" #> /examples/yamlcpp/array/#1: β€œβ€

Remove part of an array value

kdb rm /examples/yamlcpp/array/#1/key

kdb ls /examples/yamlcpp #> user/examples/yamlcpp/array #> user/examples/yamlcpp/array/#0 #> user/examples/yamlcpp/array/#1 #> user/examples/yamlcpp/array/#1/πŸ”‘ #> user/examples/yamlcpp/key

The plugin stores array keys using YAML sequences.

Since yaml-cpp stores keys in arbitrary order -

either key or array could be the β€œfirst” key -

we remove key before we retrieve the data. This way

we make sure that the output below will always look

the same.

kdb rm /examples/yamlcpp/key kdb file /examples/yamlcpp | xargs cat #> array: #> - scalar #> - πŸ”‘: πŸ™ˆ

Undo modifications to the key database

kdb rm -r /examples/yamlcpp sudo kdb umount /examples/yamlcpp

## Metadata
The plugin supports metadata. The example below shows how a basic `Key` including some metadata, looks inside the YAML configuration file:
```yaml
key without metadata: value
key with metadata:
!elektra/meta
- value2
- metakey: metavalue
empty metakey:
another metakey: another metavalue

. As we can see above the value containing metadata is marked by the tag handle !elektra/meta. The data type contains a list with two elements. The first element of this list specifies the value of the key, while the second element contains a map saving the metadata for the key. The data above represents the following key set in Elektra if we mount the file directly to the namespace user:

Name Value Metaname Metavalue
user/key without metadata value1 β€” β€”
user/key with metadata value2 metakey metavalue
empty metakey β€”
another metakey another metavalue

. The example below shows how we can read and write metadata using the yamlcpp plugin via kdb.

`` <h1>Mount yamlcpp plugin to cascading namespace/examples/yamlcpp` sudo kdb mount config.yaml user/examples/yamlcpp yamlcpp

Manually add a key including metadata to the database

echo "πŸ”‘: !elektra/meta [πŸ¦„, {comment: Unicorn}]" > kdb file user/examples/yamlcpp kdb lsmeta user/examples/yamlcpp/πŸ”‘ #> comment kdb getmeta user/examples/yamlcpp/πŸ”‘ comment #> Unicorn

Add a new key and add some metadata to the new key

kdb set user/examples/yamlcpp/brand new kdb setmeta user/examples/yamlcpp/brand comment "The Devil And God Are Raging Inside Me" kdb setmeta user/examples/yamlcpp/brand rationale "Because I Love It"

Retrieve metadata

kdb lsmeta user/examples/yamlcpp/brand #> comment #> rationale kdb getmeta user/examples/yamlcpp/brand rationale #> Because I Love It

Undo modifications to the key database

kdb rm -r user/examples/yamlcpp sudo kdb umount user/examples/yamlcpp

We can also invoke additional plugins that use metadata like `type`.

sudo kdb mount config.yaml /examples/yamlcpp yamlcpp type kdb set /examples/yamlcpp/typetest/number 21 kdb setmeta /examples/yamlcpp/typetest/number check/type short

kdb set /examples/yamlcpp/typetest/number "One"

RET: 5

STDERR: .*The type short failed to match for .*/number with string: One.*

ERROR: 52

kdb get /examples/yamlcpp/typetest/number #> 21

Undo modifications to the key database

kdb rm -r /examples/yamlcpp sudo kdb umount /examples/yamlcpp

## Binary Data
YAML CPP also supports [base64](https://tools.ietf.org/html/rfc4648) encoded data via the [Base64](@ref src_plugins_base64_README_md) plugin.

Mount YAML CPP plugin at cascading namespace /examples/binary

sudo kdb mount test.yaml /examples/binary yamlcpp

Manually add binary data

echo 'bin: !!binary aGk=' > kdb file /examples/binary

Base 64 decodes the data aGk= to hi and stores the value in binary form.

The command kdb get prints the data as hexadecimal byte values.

kdb get /examples/binary/bin #>

We can use ruby to convert the hexadecimal value returned by kdb get

to its ASCII representation. If you use bash or fish as shell then

printf kdb get /examples/binary/bin # Bash

or

printf (kdb get /examples/binary/bin) # fish

should work too.

ruby -e "print ARGV[0].split('\x')[1..-1].map { |byte| byte.to_i(16).chr }.join" kdb get /examples/binary/bin #> hi

Add a string value to the database

kdb set /examples/binary/text mate

Base 64 does not modify textual values

kdb get /examples/binary/text #> mate

The Base 64 plugin re-encodes binary data before YAML CPP stores the key set. Hence the

configuration file contains the value aGk= even after YAML CPP wrote a new configuration.

grep -q 'bin: !.* aGk=' kdb file user/examples/binary

RET: 0

Undo modifications to the database

kdb rm -r /examples/binary sudo kdb umount /examples/binary

## Dependencies
This plugin requires [yaml-cpp][]. On a Debian based OS the package for the library is called `libyaml-cpp-dev` . On macOS you can install the package `yaml-cpp` via [HomeBrew](https://brew.sh).
## Limitations
### Leaf Values
One of the limitations of this plugin is, that it only supports values inside [leaf nodes](https://github.com/ElektraInitiative/libelektra/issues/106). Let us look at an example to show what that means. The YAML file below:
```yaml
root:
subtree: πŸ‚
below root: leaf
level 1:
level 2:
level 3: 🍁

stores all of the values (πŸ‚, leaf and 🍁) in the leaves of the mapping. The drawing below makes this situation a little bit clearer.

Tree

The key set that this plugin creates using the data above looks like this (assuming we mount the plugin to user/examples/yamlcpp):

Name Value
user/examples/yamlcpp/level
user/examples/yamlcpp/level 1/level 2
user/examples/yamlcpp/level 1/level 2/level 3 🍁
user/examples/yamlcpp/root
user/examples/yamlcpp/root/below root leaf
user/examples/yamlcpp/root/subtree πŸ‚

. Now why is this plugin unable to store values outside leaf nodes? For example, why can we not store a value inside user/examples/yamlcpp/level 1/level 2? To answer this question we need to look at the YAML representation:

level 1:
level 2:
level 3: 🍁

. In a naive approach we might just try to add a value e.g. πŸ™ˆ right next to level 2:

level 1:
level 2: πŸ™ˆ
level 3: 🍁

. This however would be not correct, since then the YAML node level 2 would contain both a scalar value (πŸ™ˆ) and a mapping ({ level 3: 🍁 }). We could solve this dilemma using a list:

level 1:
level 2:
- πŸ™ˆ
- level 3: 🍁

. However, if we use this approach we are not able to support Elektra’s array type properly.

Directory Values

To overcome the limitation described above, the YAML CPP plugin requires the Directory Value plugin. This plugin converts the value of a non-leaf node to a leaf node with the name ___dirdata. For example, let us assume we have the following key set:

directory = Directory Data
directory/file = Leaf Data

. The Directory Value plugin will convert the key set in the set (write) direction to

directory =
directory/___dirdata = Directory Data
directory/file = Leaf Data

. Consequently the YAML plugin will store the key set as

directory:
___dirdata = Directory Data
file = Leaf Data

. A user of the YAML plugin will not notice this feature unless he edits the configuration file by hand, as the following example shows:

`` <h1>Mount YAML CPP plugin atuser/examples/yamlcpp` sudo kdb mount test.yaml user/examples/yamlcpp yamlcpp

kdb set user/examples/yamlcpp/directory 'Directory Data' kdb setmeta user/examples/yamlcpp/directory comment 'Directory Metadata' kdb set user/examples/yamlcpp/directory/file 'Leaf Data'

kdb ls user/examples/yamlcpp/directory #> user/examples/yamlcpp/directory #> user/examples/yamlcpp/directory/file

kdb get user/examples/yamlcpp/directory #> Directory Data kdb getmeta user/examples/yamlcpp/directory comment #> Directory Metadata kdb get user/examples/yamlcpp/directory/file #> Leaf Data

Undo modifications to the database

kdb rm -r user/examples/yamlcpp sudo kdb umount user/examples/yamlcpp

.
### Other Limitations
- Saving a **single scalar value** directly below the mountpoint does not work
- Adding and removing keys does remove **comments** inside the configuration file
- The plugin currently lacks proper **type support** for scalars.
- If Elektra uses YAML CPP as **default storage** plugin, multiple tests of the test suite fail. However, if you mount YAML CPP at `/`:

kdb mount default.yaml / yamlcpp ```

all tests should work correctly. The problem here is that Elektra does not load additional required plugins (infos/needs) for a default storage plugin.