Академический Документы
Профессиональный Документы
Культура Документы
User Guide
**********
Overview
========
Coil files provide a very powerful tool for configuring large and
complex systems. Sets of values are organized into blocks called
"structs" which can refer to each other for specific values or inherit
all values. Values may be boolean, numbers, or strings. Strings may be
encoded in Unicode if the application supports it.
Text Format
===========
Data Types
----------
The basic format is a set of key, value pairs. They keys may contain:
``A-Z``, ``a-z``, ``0-9``, ``-``, and ``_``. Values may be any of the
following:
The key value pairs are represented by the syntax ``key: value`` similar
to that of Python :class:`dict` objects except there is no comma between
pairs. White space does not mater. For example this::
is_ok: True
description: "This is Coil"
is equivalent to::
Groups of these key, value pairs can be grouped into structs by using
``{ ..some data.. }``. For example::
config-a: {
is_ok: True
description: "This is config a"
}
config-b: {
is_ok: True
description: "This is config b"
}
Values may also be put inside a list using ``[ ..something.. ]``::
things: [ 1 2.3 "a string" ]
Note that structs may not appear inside of lists but nested lists are
allowed.
Inheritance
-----------
Structs can extends other structs: this means they inherit all
attributes from that struct. Extending is done with a special
attribute, @extends, with a value that is a path to another struct.
Paths can be relative, with a prefix of ".." meaning go up one level,
"..." go up two levels, etc., or absolute, starting from the special
location @root. In this example, y and z inherit from x and override
some of its attributes::
x: {a: 1 b: 2}
y: {
@extends: ..x # relative path
b: 3
}
z: {
@extends: @root.x # absolute path
b: 4
}
y: {a: 1 b: 3}
x: { a: {b: 1} }
y: {
@extends: ..x
a.b: 3
}
z: {
@extends: ..x
a: {
@extends: ..x.a
b: 3
}
}
x: { a: 1 }
y: { a: 2 b: 3}
z: {
@extends: ..x
@extends: ..y
}
is equivalent to::
x: { a: 1 }
y: { a: 2 b: 3}
z: { a: 1 b: 3}
Importing Files
---------------
Structs can import data from other files. The behavior is similar to
``@extends`` except the value is a string listing the path to another
file. If the file is relative it is assumed to be relative to the file
in which it appears, not the parsing program's current working
directory. For example, if the file "/home/joe/my.coil" wants to import
the contents of "/home/joe/test/example.coil" it could do::
If a specific struct is wanted rather than the whole file provide a list
of two strings that define the file name and the path::
Deletion
--------
base: {x: 1 y: 2}
sub: {
@extends: ..base
~x # sub now has no attribute "x"
}
base: {
sub: {
x: 1
y: 2
}
}
a: {
@extends: ..base
sub.z: 3
}
b: {
@extends: ..base
sub: {
z: 3
}
}
The first structure (``a``) adds a new attribute to ``sub``. The final
result will be::
a: {
sub: {
x: 1
y: 2
z: 3
}
}
On the other hand, ``b`` entirely replaces ``sub`` so the result will
be::
b: {
sub: {
z: 3
}
}
References
----------
a: 1
b: a
a: 1
b: 1
Note that for backwards compatibility the path may be prefixed with a
'=' character: ``b: =a``.
host1: "host1.somewhere.com"
host2: "host2.somewhere.com"
service1: { host: @root.host1 port: 1234 }
service2: { host: ..host2 port 3456 }
References are also allowed within strings by using ${name} similar to Bash or
Perl. For example::
foo: "zomg"
bar: "${foo}bbq"
sub: {
x: "foo is ${..foo}"
y: "foo is ${@root.foo}"
}
foo: "zomg"
bar: "zomgbbq"
sub: {
x: "foo is zomg"
y: "foo is zomg"
}
foo: {
@map: [1 2 "-blah"]
bar: {
this: "that"
}
}
The final expanded form will be copies of bar and the names are derived
from the values of the @map list::
foo: {
bar1: {
this: "that"
}
bar2: {
this: "that"
}
bar-blah: {
this: "that"
}
}
To actually make this useful @map will map sequences of values into the
sequence of generated structs. For example if we want to generate a list
of hosts::
foo: {
@map: [1 2]
host: {
type: "host"
}
name: ["hostname1" "hostname2"]
description: ["my host" "your host"]
}
The name and description lists become attributes inside of host::
foo: {
host1: {
type: "host"
name: "hostname1"
description: "my host"
}
host2: {
type: "host"
name: "hostname2"
description: "your host"]
}
}
The length of the lists to map in need to be the same length as the @map
list. Bash-like brace expansion is also supported in all of the lists.
Unlike bash if a sequence of numbers are being generated with .. and the
start and end values are zero padded the resulting values will also be
zero padded. So ["{1,2}" "{009..011}"] becomes [1 2 009 010 011]. It is
also possible to expand multiple structs in a single map::
foo: {
@map: ["{1..2}"]
host: {
type: "host"
name: "${username}-desktop"
}
user: {
type: "user"
}
username: ["bob" "sue"]
}
foo: {
host1: {
type: "host"
name: "bob-desktop"
username: "bob"
}
host2: {
type: "host"
name: "sue-desktop"
username: "sue"
}
user1: {
type: "user"
username: "bob"
}
user2: {
type: "user"
username: "sue"
}
}
Config Validation
=================
Currently the core Coil library has no ability to validate files beyond
the basic syntax. Formal schema validation is planned in the future but
for now it is up to the individual applications to validate that their
config is valid.
To at least check that the syntax is correct and view how your
inheritance rules actually play out there is a simple utility called
*coildump* which will read in a coil file, expand all references, and
print it out again. It is under *bin* in the source repository.
Editor Support
==============
To make editing easier Coil includes some helpers for Emacs and Vim. For
Emacs users grab *misc/coil.el* out of the source repository. For Vim copy
the *coil.vim* files under *misc/vim/ftdetect* and *misc/vim/syntax* to
*~/.vim/ftdetect* and *~/.vim/syntax*.