CLI Usage

python-anyconfig contains a CLI frontend ‘anyconfig_cli’ to demonstrate the power of this library.

It can process config files in any formats supported in your environment and:

  • output merged/converted config outputs w/ modifications needed

  • output schema file for given inputs

  • merge/convert input config and extract part of the config

ssato@localhost% anyconfig_cli -h
Usage: anyconfig_cli [Options...] CONF_PATH_OR_PATTERN_0 [CONF_PATH_OR_PATTERN_1 ..]

Examples:
  anyconfig_cli --list  # -> Supported config types: configobj, ini, json, ...
  # Merge and/or convert input config to output config [file]
  anyconfig_cli -I yaml -O yaml /etc/xyz/conf.d/a.conf
  anyconfig_cli -I yaml '/etc/xyz/conf.d/*.conf' -o xyz.conf --otype json
  anyconfig_cli '/etc/xyz/conf.d/*.json' -o xyz.yml \
    --atype json -A '{"obsoletes": "sysdata", "conflicts": "sysdata-old"}'
  anyconfig_cli '/etc/xyz/conf.d/*.json' -o xyz.yml \
    -A obsoletes:sysdata;conflicts:sysdata-old
  anyconfig_cli /etc/foo.json /etc/foo/conf.d/x.json /etc/foo/conf.d/y.json
  anyconfig_cli '/etc/foo.d/*.json' -M noreplace
  # Get/set part of input config
  anyconfig_cli '/etc/foo.d/*.json' --get a.b.c
  anyconfig_cli '/etc/foo.d/*.json' --set a.b.c=1

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -o OUTPUT, --output=OUTPUT
                        Output file path
  -I ITYPE, --itype=ITYPE
                        Select type of Input config files from configobj, ini,
                        json, msgpack, xml, yaml [Automatically detected by
                        file ext]
  -O OTYPE, --otype=OTYPE
                        Select type of Output config files from configobj,
                        ini, json, msgpack, xml, yaml [Automatically detected
                        by file ext]
  -M MERGE, --merge=MERGE
                        Select strategy to merge multiple configs from
                        replace, noreplace, merge_dicts, merge_dicts_and_lists
                        [merge_dicts]
  -A ARGS, --args=ARGS  Argument configs to override
  --atype=ATYPE         Explicitly select type of argument to provide configs
                        from configobj, ini, json, msgpack, xml, yaml.  If
                        this option is not set, original parser is used: 'K:V'
                        will become {K: V}, 'K:V_0,V_1,..' will become {K:
                        [V_0, V_1, ...]}, and 'K_0:V_0;K_1:V_1' will become
                        {K_0: V_0, K_1: V_1} (where the tyep of K is str, type
                        of V is one of Int, str, etc.
  -x, --ignore-missing  Ignore missing input files
  -T, --template        Enable template config support
  -E, --env             Load configuration defaults from environment values
  -S SCHEMA, --schema=SCHEMA
                        Specify Schema file[s] path
  -s, --silent          Silent or quiet mode
  -q, --quiet           Same as --silent option
  -v, --verbose         Verbose mode

  List specific options:
    -L, --list          List supported config types

  Schema specific options:
    --validate          Only validate input files and do not output. You must
                        specify schema file with -S/--schema option.
    --gen-schema        Generate JSON schema for givne config file[s] and
                        output it instead of (merged) configuration.

  Get/set options:
    -Q QUERY, --query=QUERY
                        Query with JMESPath expression language. See
                        http://jmespath.org for more about JMESPath
                        expression. This option is not used with --get option
                        at the same time. Please note that python module to
                        support JMESPath expression
                        (https://pypi.python.org/pypi/jmespath/) is required
                        to use this option
    --get=GET           Specify key path to get part of config, for example, '
                        --get a.b.c' to config {'a': {'b': {'c': 0, 'd': 1}}}
                        gives 0 and '--get a.b' to the same config gives {'c':
                        0, 'd': 1}.
    --set=SET           Specify key path to set (update) part of config, for
                        example, '--set a.b.c=1' to a config {'a': {'b': {'c':
                        0, 'd': 1}}} gives {'a': {'b': {'c': 1, 'd': 1}}}.
ssato@localhost%

List supported config types (formats)

anyconfig_cli lists config types (formats) supported in your environment with -L/–list option:

$ anyconfig_cli -L
Supported config types: configobj, ini, json, msgpack, xml, yaml
$ anyconfig_cli --list
Supported config types: configobj, ini, json, msgpack, xml, yaml
$

Merge and/or convert input config

anyconfig_cli can process a config file or config files and output merged config in various formats it can support in your environment.

Here are some such examples.

  • single input config file, input type is automatically detected from the input file’s extension:

$ cat /tmp/a.yml
a: 1
b:
  c:
    - aaa
    - bbb
d:
  e:
    f: xyz
    g: true
$ anyconfig_cli -O json /tmp/a.yml
Loading: /tmp/a.yml
{"a": 1, "b": {"c": ["aaa", "bbb"]}, "d": {"e": {"g": true, "f": "xyz"}}}
  • single input config file with the input type and output option:

$ diff -u /tmp/a.{yml,conf}
$ anyconfig_cli -I yaml -O configobj /tmp/a.conf -o /tmp/a.ini --silent
$ cat /tmp/a.ini
a = 1
[b]
c = aaa, bbb
[d]
[[e]]
g = True
f = xyz
$
  • multiple input config files:

$ cat /tmp/b.yml
b:
  i:
    j: 123
d:
  e:
    g: hello, world
l: -1
$ anyconfig_cli /tmp/{a,b}.yml --silent
a: 1
b:
  c: [aaa, bbb]
  i: {j: 123}
d:
  e: {f: xyz, g: 'hello, world'}
l: -1

$
  • multiple input config files with merge strategy option:

$ anyconfig_cli /tmp/{a,b}.yml -M replace --silent
a: 1
b:
  i: {j: 123}
d:
  e: {g: 'hello, world'}
l: -1

$
  • multiple input config files with template option:

$ cat /tmp/c.yml
m: {{ d.e.g }}
n: {{ b.i.j }}
$ anyconfig_cli /tmp/{a,b,c}.yml --silent --template
a: 1
b:
  c: [aaa, bbb]
  i: {j: 123}
d:
  e: {f: xyz, g: 'hello, world'}
l: -1
m: hello, world
n: 123

$ ls /tmp/*.yml
/tmp/a.yml  /tmp/b.yml  /tmp/c.yml
$ # Same as the privious one but inputs are given in a glob pattern.
$ anyconfig_cli '/tmp/*.yml' --silent --template  # same as the privious one
a: 1
b:
  c: [aaa, bbb]
  i: {j: 123}
d:
  e: {f: xyz, g: 'hello, world'}
l: -1
m: hello, world
n: 123

$
  • Missing input config files:

$ ls /tmp/not-exist-file.yml
ls: cannot access /tmp/not-exist-file.yml: No such file or directory
$ anyconfig_cli --ignore-missing /tmp/not-exist-file.yml -s
{}

$ anyconfig_cli --ignore-missing /tmp/not-exist-file.yml -s -A "a: aaa"
No config type was given. Try to parse...
{a: aaa}

$ anyconfig_cli --ignore-missing /tmp/not-exist-file.yml -s -A "a: aaa; b: 123"
No config type was given. Try to parse...
{a: aaa, b: 123}

$

Schema generation and validation

anyconfig_cli can process input config file[s] and generate JSON schema file to validate the config like this:

  • An usage example of schema generation option –gen-schema of anyconfig_cli:

$ cat /tmp/a.yml
a: 1
b:
  c:
    - aaa
    - bbb
d:
  e:
    f: xyz
    g: true
$ anyconfig_cli --gen-schema /tmp/a.yml -s -o /tmp/a.schema.json
$ jq '.' /tmp/a.schema.json
{
  "properties": {
    "d": {
      "properties": {
        "e": {
          "properties": {
            "f": {
              "type": "string"
            },
            "g": {
              "type": "boolean"
            }
          },
          "type": "object"
        }
      },
      "type": "object"
    },
    "b": {
      "properties": {
        "c": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "type": "object"
    },
    "a": {
      "type": "integer"
    }
  },
  "type": "object"
}
$
  • and schema validation option –validate (and –schema) of anyconfig_cli:

$ anyconfig_cli -A 'a: aaa' --atype yaml /tmp/a.yml -o /tmp/a2.yml --silent
$ head -n 1 /tmp/a.yml
a: 1
$ head -n 1 /tmp/a2.yml
a: aaa
$ anyconfig_cli --validate --schema /tmp/a.schema.json /tmp/a.yml
Loading: /tmp/a.schema.json
Loading: /tmp/a.yml
Validation succeeds
$ anyconfig_cli --validate --schema /tmp/a.schema.json /tmp/a.yml -s; echo $?
0
$ anyconfig_cli --validate --schema /tmp/a.schema.json /tmp/a2.yml -s; echo $?
'aaa' is not of type u'integer'

Failed validating u'type' in schema[u'properties'][u'a']:
    {u'type': u'integer'}

On instance[u'a']:
    'aaa'
Validation failed1
$

Query/Get/set - extract or set part of input config

Here is usage examples of –get option of anyconfig_cli:

$ cat /tmp/a.yml
a: 1
b:
  c:
    - aaa
    - bbb
d:
  e:
    f: xyz
    g: true
$ anyconfig_cli /tmp/a.yml --get d.e.f --silent
xyz
$ anyconfig_cli /tmp/a.yml --get b.c --silent
['aaa', 'bbb']
$ anyconfig_cli /tmp/a.yml --query d.e.g --silent
True
$ anyconfig_cli /tmp/a.yml --query 'b.c[::-1]' --silent
['bbb', 'aaa']

and an usage example of –set option of anyconfig_cli with same input:

$ anyconfig_cli /tmp/a.yml --set "d.e.g=1000" --set "b.c=ccc," --silent
a: 1
b:
  c: [ccc]
d:
  e: {f: xyz, g: true}

$