Solved Config file structure for hierarchies?

I'm trying to define a config file structure that can mostly be shared across operating systems and hostnames, but also supports exceptions when needed.

For example, the TOML below might work if I make the runtime code look up the keys hostname.<hostname>.server, os.<uname>.server, and server, and then use the value from the first key that exists.

That would give a default server value of 192.168.1.100, FreeBSD machines a server value of 10.0.0.100, and the host named Jupiter a server value of 10.0.0.1.

YAML:
[hostname]
  [#.jupiter]
    server = "10.0.0.1"

[os]
  [#.freebsd]
    server = "10.0.0.100"

server = "192.168.1.100"

It seems like this would work, but these things get complicated beyond the naive first-pass.

Can anyone recommend a good approach to this from their own experience so I don't have to make all of my own mistakes?

Everything is on the table here (maybe even an embedded interpreter). I'm writing in go if it matters.
 
Hmm, solving this as a general problem is hard. Sure, you could write lots of go code (which would be fun, I've heard good things about the language), but it would also be a lot of work (and testing effort).

Here's a simple solution, which I use for user-dependent config files (like .bashrc or .emacs) to make them OS-, host- and user-dependent: ifdef. The config files are written in source form, and look roughly like this:
Code:
#IFDEF FreeBSD
server = 1.2.3.4
#ELIF Darwin
server = 5.6.7.8
#ELSE
    #IF HOSTNAME = foo.example.com
    server = 9.8.7.6
    #ELSE
    server = 4.3.2.1
    #ENDIF
#ENDIF
I then build my actual config files in an INSTALL script, which first collects common things (OS name from the uname command, hostname, username...), and passes them to the unifdef program, which processes the above sources and creates the actual config file to be used. On OSes that provide unifdef, this only requires a script, and it's not even very complicated. On Linux, I have a miniature version of unifdef that I wrote (I think in Python or C, forget how I did it).

Big disadvantage: Every time you change the "source" of the config files, you have to remember to run the installer over them to convert them to the actual files that are being
 
You can have the same effect when using the C compiler with the correct flags, so only the preprocessor is run and the #file and #line statements are omitted.
 
ralphbsz Crivens Thanks, I can copy that approach with an embedded interpreter (like Emacs does with .el files).

bakul Thanks for the reference; I definitely want to write as little as possible from scratch.

For this application, I think the user config files would be 95% the same on all machines, so I would like to share the exact same file everywhere if possible.

Emacs uses the system-type (os) and system-name (hostname) functions to configure different hosts differently, and Ansible uses the hosts: and when: declarations to conditionally apply specific tasks, but I'm hoping to find examples of user-focused applications that handle this in a way that's easier to read.
 
Back
Top