librnd - config lists

# The config system in librnd

## Lists and arrays

Non-scalar settings are arrays or lists. Arrays can be explicitly indexed The default policy is always overwrite.

There are three active policies: overwrite, prepend and append. When dealing with lists:

- step 1: the output list is reset to empty
- step 2: all sources that describe the list are sorted by priority
- step 3: sources are applied in order

Step 3 is straight-forward: if policy is overwrite, reset the output list and copy the source's list into the output list. If policy is prepend (or append), keep the current output list and prepend (or append) the list provided by the source.

In practice this means the user can replace, prepend or append ordered lists from various sources. A common example is setting the library search paths.

## examples

### simple overwrite

Config sources (ordered by priority):

role | priority | policy | content
--- | --- | --- | ---
system | 200 | overwrite | A,B,C
user | 400 | overwrite | (not defined)
project | 600 | overwrite | D,E

Merge iterations:

step | description | output list after executing this step | remarks
--- | --- | --- | ---
0. | reset the output | (empty) |
1. | apply system | A,B,C |
2. | apply user | A,B,C | "not defined" doesn't mean "empty", so the list is not deleted - no change
3. | apply project | D,E | replace the original output because of the overwrite policy

Example scenario: the project is restricted to local footprint libs; this setup makes sure no system or user configuration injects external footprint paths.

### empty overwrite

Config sources (ordered by priority):

role | priority | policy | content
--- | --- | --- | ---
system | 200 | overwrite | A,B,C
user | 400 | overwrite | (not defined)
project | 600 | overwrite | defined to be an empty list

Merge iterations:

step | description | output list after executing this step | remarks
--- | --- | --- | ---
0. | reset the output | (empty) |
1. | apply system | A,B,C |
2. | apply user | A,B,C | "not defined" doesn't mean "empty", so the list is not deleted - no change
3. | apply project | (empty) | replace the original output because of the overwrite policy

### prepend

Config sources (ordered by priority):

role | priority | policy | content
--- | --- | --- | ---
system | 200 | overwrite | A,B,C
user | 400 | prepend | (not defined)
project | 600 | prepend | D,E

Merge iterations:

step | description | output list after executing this step | remarks
--- | --- | --- | ---
0. | reset the output | (empty) |
1. | apply system | A,B,C |
2. | apply user | A,B,C | "not defined" doesn't mean "empty", so the list is not deleted - no change
3. | apply project | D,E,A,B,C |

Example scenario: the project has its own footprint libs with two paths; these should be searched before system and user paths, still, system path is also kept so stock footprints can be found.

This is better than hardwiring A,B,C in the project's list: A, B and C may depend on the installation on a given system. A project file has no idea about how the system is installed but it is assumed system installation and the system configuration file are consistent.

### append

Config sources (ordered by priority):

role | priority | policy | content
--- | --- | --- | ---
system | 200 | overwrite | A,B,C
user | 400 | append | (not defined)
project | 600 | append | D,E

Merge iterations:

step | description | output list after executing this step | remarks
--- | --- | --- | ---
0. | reset the output | (empty) |
1. | apply system | A,B,C |
2. | apply user | A,B,C | "not defined" doesn't mean "empty", so the list is not deleted - no change
3. | apply project | A,B,C,D,E |

Example scenario: the project has its own footprint libs with two paths; these should be searched after system and user paths. This means the local footprint lib has lower priority than the stock footprints. See system-dependent installation remarks in the previous point.

### prepend+append

Config sources (ordered by priority):

role | priority | policy | content
--- | --- | --- | ---
system | 200 | overwrite | A,B,C
user | 400 | prepend | X,Y,Z
project | 600 | append | D,E

Merge iterations:

step | description | output list after executing this step | remarks
--- | --- | --- | ---
0. | reset the output | (empty) |
1. | apply system | A,B,C |
2. | apply user | X,Y,Z,A,B,C |
3. | apply project | X,Y,Z,A,B,C,D,E |

### list and hlist

There are two kinds of lists: string list (simply called list) and hash-list (called hlist).

Each element of a hlist is a hash node in the lihata conf file. These hash nodes are opaque to the conf system and must be processed by the plugin that uses the hlist. Normal merging still works on hlists: opaque elements can be prepended or appended and the whole list can be overwritten.

Each element of a plain (string) list is a text node in the lihata conf file, which is stored as a string in the memory by the conf system.