Previous: Java, Up: Philosophy



4.14 Configuration

There is no real difference between a command line option and a configuration parameter. In a package, which has one or many commands, each command has several options. Some of the options are command specific others are inherited from the package. A third group of options is inherited from the siliconBrain frame (like the --help option). The options, which are inherited from the package are the configuration parameters.

The normal command specific options are specified in a command specification program (executable specification), which outputs the option description in xml or other formats. The package configuration parameters are simple the options of a command, with the same name as the package. Whether the command really exists or not does not matter. These options are generated into each command implementation as inherited options. So each configuration parameter can be overwritten by using an option.

So the first source of configuration are the command line parameters. In the option handling of each command, the second location of looking for options is the environment. For each option and thus for each configuration parameter too, there is a corresponding environment variable packageName_optionName.

Third place are executable configurations: files with the name packageName.configuration residing in certain directories (current, home, $PATH, etc). These programs (implemented in any language) output the option contents in XML format. This output is read by the standard option handling generated by siliconBrain. The list of directories can be configured by setting the environment variable siliconBrainConfigurationPath to a colon separated list of directories, with the entry "" being the $PATH. The default is .:~:/etc:$PATH for (current, home, $PATH, etc).

At the beginning I thought that the very last location for a configuration look up is the packages path. But I decided against this because it should be possible to just delete a package directory and then reinstall it. All configuration information should be kept. So there should be nothing changeable inside the package directory. always think of the package directory residing on a read only CD-ROM. The second reason is, that the normal case presumably is that with a new version of a package the old configuration should be taken. If this is not the wish, siliconBrainConfigurationPath can be used to handle different configurations.

An option will have the value, which has been found first. So command line arguments overwrite environment variables, overwrite the configuration in the current directory overwrites ..... Flag options are normally specified without a value (--myFlag). To be able to set an option to false even if it is configured to true in a subsequent configuration, it is possible to set a flag option explicitly to false: --myFlag=false or --no-myFlag. And for reasons of symmetry --myFlag=true is also allowed.

The --complete option avoids reading all stages every time. Whenever in the places to look the --complete option is set, the lookup in the subsequent places is suppressed. So for example, if yo specify --complete on the command line no further option or configuration lookup is performed.

In each package there is a generated program packageName.configurationReader, which does the standard option handling (reading command line arguments, reading environment variables, reading executable configuration output and each time stopping, if --complete is found). This program then does nothing than outputting the aggregated information in various format: xml, bash, environment, perl and others.

This can be included in other languages like (for bash)

     eval $(packageName.configurationReader $* -- --bash)

The configuration can be pumped into environment by:

     eval $(packageName.configurationReader -- --bashEnvironemnt)

where export statements are generated. The configurationReader always set the --complete option. So after executing the last example, all commands of that package, will stop after reading the environment. The above eval statement can for example be place in a .bashrc.

Before starting I thought, that the output of the executable configurations should be of the form:

     # comment
     key = value
     anotherKey = another value

rather than xml. The reason for that was, that it should be easy for other programs in arbitrary languages to read and process the configurations. Other languages include bash, emacs lisp and perl. Using xml would require to have an xml parser in any language. But for the reason to have a consistent and common option, environment and configuration handling I have invented the configurationReader. This handles options, environment and configurations and then outputs the result in a host language friendly way. This means that the configurations can output xml without having the need to process this xml in all different languages. On the other side to produce xml is far more easy than to parse it. The following example of a siliconBrain.configuration file is the so called trivial configuration implementation:

     #!/bin/bash
     
     cat <<EOF
     <siliconBrain>
        <publishTargetHost> siliconbrain.com </publishTargetHost>
        <publishTargetArchive> ftp/anon/pub </publishTargetArchive>
        <publishTargetWeb> www/htdocs </publishTargetWeb>
     </siliconBrain>
     EOF

With this concept we fulfill the following requirentments of a configuration environment:

There is an environment variable siliconBrainConfigurationPath with a colon separated list of directories, where to search for configurations.

The option specification, which describes the configuration parameters of a package is the same (not just equal) to the option specification of a command with the name of the package. So if the package packageName has a command packageName.command then the options of that command are the same as the configuration parameters of the package. This is intended for packages with a definite main command, which for example starts the server.

The configurationReader uses siliconBrainLib's xmlPrinter to output its information. This means, that it can do the output in various formats (for example xml). And it does it colorized in case of stdout being a tty. Also the configurationReader uses the short descriptions of the options to create comments in the generated output, so each option is described a little. Only those options (and with it configuration parameters (member that the configuration parameters are available as inherited command line options)) which have been specified somewhere are outputted. The rest is present just via its commented short description:

     ~/sandbox/siliconBrain> siliconBrain.configurationReader -- --xml
     
     <!-- siliconBrain main configuration.
        general datahandling application framework -->
     <siliconBrain>
     
        <!-- publishTargetHost (value) : IP address or domain name where package should be put to -->
        <publishTargetHost> siliconbrain.com </publishTargetHost>
     
        <!-- publishTargetArchive (value) : directory on the publishTargetHost, where the tar.gz should be put to. -->
        <publishTargetArchive> ftp/anon/pub </publishTargetArchive>
     
        <!-- publishTargetWeb (value) : directory on the publishTargetHost, where the HTMLilized sourcetree should be put to. -->
        <publishTargetWeb> www/htdocs </publishTargetWeb>
     
        <!-- help (flag ) : Print a short help message, listing the options. -->
     
        <!-- verbose (flag ) : Let this command talk to you a lot. -->
     
        <!-- version (flag ) : Display version information. -->
     
        <!-- output (value) : File to which output is written. -->
     
        <!-- complete (flag ) : Indicate completeness of specified options. No further lookup in configuration chain. -->
        <complete/>
     </siliconBrain>
     ~/sandbox/siliconBrain>

It is possible to chain configurations in a way: a user can write a configuration in her home directory, which calls a standard configuration and then uses sed or awk to manipulate some entries.

Be aware the the suffix .configuration does not indicate the format of the file, so that you can chose a certain editor or editing mode. Rather this suffix indicates, that it is an executable file, which, when called, outputs xml. In case that the configuration is implemented in c, the configuration file itself is not readable at all. In this case you need the source.

It is recommended to use siliconBrainLib's SiliconBrainPrinter aka xmlPrinter to write the sources of your configuration, if they tend to be a little complex. This is a c library of functions (also used by the configurationReader) to output xml. If you do, you are programming in c, you have all the possibilities of c and the resulting program outputs xml in color in a standardized inteted manner, and in other syntaxes (like perl or bash).

I have decided for an executable configuration to be able to use a real full blown programming language for writing the configuration. So in creating configurations you have all means of reusability, avoiding copied code, factor out common information, using loops, defining variables, commenting. On the other side you can read databases or other sources of information to support kind of dynamic configuration.

If you use xml as a language for sources, or to put it into other words, if you have xml files in cvs normally you corrupt a lot of programming rules. Mostly the “never copy code” rule. But xml is a perfect protocol language, a language used for programs to communicate with each other. By deciding for executable configurations, I have the advantages of full programming languages, with the advantages of xml as protocol.