The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Config::MyConfig2 is a flexible configuration file parser, that reads and writes Apache-Style configuration files, with global key/value pairs and directives <directive my_directive></directive>

It supports:

  • Configureable layout of configuration files, i.e. which keywords, which directives (if any), syntax checks for values

  • Flexible configurations, i.e. using tabs, spaces or = as delimiters between keywords and values

  • Apache Webserver style configuration directives: <directive my_directive>keywords & values</directive>

  • Keywords with multiple values, either as comma seperated list or as multiple keywords with the same name

  • Methods to gather loaded configuration values in Perl context, i.e. as hashtree, lists or single values

  • Ability to modify the configuration, after it has been loaded

  • Ability to store a modified configuration file back to disk

  • Full Perl OO access

SYNOPSIS

 my $myconfig = Config::MyConfig2->new (
        conffile => "my_configuration_file.cfg",
        );
 
 my $conftemplate;
 $conftemplate->{global}->{somenumber} = { required => 'true', type => 'single', match => '^\d+\.*\d*'};
 $conftemplate->{global}->{somestring} = { required => 'false', type => 'single', match => '^.+'};
 $conftemplate->{directive}->{foo} = { type => 'single', match => '^[true]|[false]$'};
 $conftemplate->{directive}->{bar} = { type => 'single', match => '^0|1$'};
 $conftemplate->{other_directive}->{far} = { type => 'list', match => '.+'};
 $conftemplate->{other_directive}->{boo} = { type => 'list', match => '.+'};
 
 $myconfig->SetupDirectives($conftemplate);
 
 my $config_hashtree = $myconfig->ReadConfig();
 
 my $global_value = $myconfig->GetGlobalValue('foo');
 
 $errmsg = $myconfig->SetDirectiveValue('directive_foo','identifier_baz','key_foobar','value_foo_bar_baz');
 
 $myconfig->WriteConfig('My new config file','some_file.cfg');
 

DESCRIPTION

This class provides methods to setup a configuration file template as well as to read and parse a configuration file, that matches to the template. The configuration can have Apache-Configuration style directives.

Furthermore, an existing configuration can be modified and written back to disk.

It supports...

  • Global keywords

     keyword        foo
     
  • keywords with lists in CSV (comma separated value) format

     keyword        foo, bar, boo, far
  • Directives with names and user-defined identifiers:

     <directive foo>
        keyword                     foo
        other_keyword       bar
     </directive>
    
     <other_directive bar>
       perl_program         hello_world.pl
       argument                     foobar
     </other_directive>

METHODS

new

Creates a new Config::MyConfig2 object

  my $myconfig = Config::MyConfig2->new (
        conffile => "my_configuration_file.cfg",
        );
  

SetupDirectives

  $myconfig->SetupDirectives($conftemplate);
  

Where $conftemplate is a hash tree data structure.

Global Values

Global values are key/value pairs, that are not living in a directive. This can be i.e.

animal = cow or animal cow

and would be templated like this:

  $tmpl->{global}->{animal} = { match => '.+', type => 'single'}

Allowed delimiters are spaces, tabs and =

Directive Values

Directive values are values, that are living within a directive. Each diretive has a name and an identifier, i.e.

<my_directive foo> bar 100 </my_directive>

The identifiers can freely be choosen by the user. The directive names are predifined in the template.

  $tmpl->{my_directive}->{bar} = {match => '.+', type = 'single'}

The keyword 'bar' would match for all directive name / directive identifier combinations with the directive 'name my_directive'.

Keyword Types

Keyword types can be:

single

A single item can only be defined once and appears as a scalar in the config hash tree.

foo bar

If gathered via GetGlobalValue or GetDirectiveValue, these items will be returned as an array reference.

multi

A multi item can be defined multiple times, either as a list of repeated keyword / value pairs or as a comma seperated list of values with one keyword

foo = 1 foo = 2 foo = 3

or

foo = 1, 2, 3

or, of course, something like this:

foo 1 ,2, 3

If gathered via GetGlobalValue or GetDirectiveValue, these items will be returned as an array reference.

Syntax Check / Match Operator

The match operator is a regex, where a supplied value in the configuration file is checked against. This enables the possibility of syntax checking configuration parameters.

If a check fails, an errors is thrown.

ReadConfig

  $config_hash_tree = $self->ReadConfig()

Reads and parses the configuration file. Throws an error, if a parsing error (i.e. syntax error) occurs.

Returns the configuration as a hash_tree. See the example below.

GetDirectiveNames

Returns a list of all directive names as an array or an empty list, if no directive names have been found.

  @directives = $myconfig->GetDirectiveNames()

GetDirectiveIdentifiers

Expects the name of a pre-defined directive

Returns a list of all directive identifiers as an array or an empty list in case of identifiers have been found.

  @identifiers = $myconfig->GetDirectiveIdentifiers('my_directive')
  

GetConfigRef

Returns a hash reference to the configuration, which is a nested datastructure. You might want to use

   use Data::Dumper;
   print Dumper($config_reference)
   

to evaluate the details of this structure.

Because it is a reference, all modifications of this structure will also end up in configuration files, written with WriteConfig().

GetGlobalValue Expects the name of a valid keyword

Returns a global value as a scalar (type = single) or a reference to an array (type = multi)

  $value = $myconfig->GetGlobalValue('foo')
  $value_array_ref = $myconfig->GetGlobalValue('foo')

GetDirectiveName

Expects the name of a directive and a keyword

Returns a global value as a scalar (type = single) or a reference to an array (type = multi)

  $value = $myconfig->GetGlobalValue('my_directive','foo')
  $value_array_ref = $myconfig->GetGlobalValue('my_directive','foo')

GetDirectiveValue

Expects the name of a directive, directive identifier and a keyword.

Returns a directive value as a scalar (type = single) or a reference to an array (type = multi)

  $value = $myconfig->GetGlobalValue('my_directive','some_identifier','foo')
  $value_array_ref = $myconfig->GetGlobalValue('foo')

SetGlobalValue

Sets the value of a global keyword.

Expects a pre-defined global keyword and a value

Returns undef in case of success or an string with a error message. It uses the syntax-checker to verifiy if the global value meets the requirements of the checkng regex.

  $errmsg = $myconfig->SetGlobalValue('some_keyword','some_value')
  

If the keyword is of type 'multi', the passed value will be added to a list of values.

SetDirectiveValue

Sets the value of a keyword within a directive.

Expects a directive-name, directive identifier, keyword and a value.

Returns undef in case of success or an string with a error message. It uses the syntax-checker to verifiy if the global value meets the requirements of the checkng regex.

  $errmsg = $myconfig->SetGlobalValue('some_directive','some_identifier','some_keyword','some_value')

If the directive identifier doesn't exist, it will be created. If the keyword is of type 'multi', the passed value will be added to a list of values.

DeleteDirectiveIdentifier

 Deletes an identifier from a directive.
 
 Expects a directive name and directive identifier
 
 Returns the removed values or undef is no values for this directive/identifiehave been deleted. 

WriteConfig

Writes the (modified) configuration file back to disk.

Expects a name-string, that is shown in the configuration file header comments and a filename where the configuration should be saved to.

  $myconfig->WriteConfig('Foo Bars Configuration File','/tmp/foo.cfg'); 

error

Internal method, that is used to throw an error. The default behavior is to croack().

EXAMPLE

  • Configuration file for a backup script: backup.cfg

     --- snip ---
     #
     # Config file
     #
     
     #
     # ---- Global Section ----
     #
     
     # Path to the rsync programm
     rsync           /usr/bin/rsync
     # Path to sendmail
     sendmail        /usr/sbin/sendmail
     # Path to the tar utility
     tar             /bin/tar
     # Path to ssh command
     # If not specified, rsh will be used 
     ssh             /usr/bin/ssh
     # Debuglevel, range (0..2)
     debuglevel      1
     
     #
     # ---- Backup Directives ----
     #
      
     <backup server-system>
            hostname        localhost
            backupschedule  Mon, Wed, Fri
            archiveschedule Sun
            archivemaxdays  60
            add  /
            excl /home, /proc, /sys, /dev, /mnt, /media
     </backup>
     
     <backup server-home>
            hostname        localhost
            backupschedule  Mon, Wed, Fri
            archiveschedule Sun
            archivemaxdays  30
            add  /home
     </backup>
     
     --- snap ---
  • Setup procedure in perl context

     #!/usr/bin/perl
     
     use Config::MyConfig2;
     use strict;
     use Data::Dumper;
     
     my $myconfig = Config::MyConfig2->new(
            conffile => "backup.cfg"
     );
     
     my $conftemplate;
     $conftemplate->{global}->{rsync} = { required => 'true', type => 'single', match => '.+' };
     $conftemplate->{global}->{sendmail} = { required => 'true', type => 'single', match => '.+' };
     $conftemplate->{global}->{tar} = { required => 'true', type => 'single', match => '.+' };
     $conftemplate->{global}->{ssh} = { required => 'true', type => 'single', match => '.+' };
     $conftemplate->{global}->{rsync} = { required => 'true', type => 'single', match => '.+' };
     $conftemplate->{global}->{debuglevel} = { required => 'true', type => 'single', match => '^\d$' };
     
     $conftemplate->{backup}->{hostname} = { required => 'true', type => 'single', match => '^[a-zA-Z0-9\.]+$' };
     $conftemplate->{backup}->{backupschedule} = { required => 'true', type => 'list', match => '^[Mon]|[Tue]|[Wed]|[Thu]|[Fri]|[Sat]|[Sun]$' };
     $conftemplate->{backup}->{archiveschedule} = { required => 'true', type => 'list', match => '^[Mon]|[Tue]|[Wed]|[Thu]|[Fri]|[Sat]|[Sun]$' };
     $conftemplate->{backup}->{archivemaxdays} = { required => 'true', type => 'list', match => '^\d+$' };
     $conftemplate->{backup}->{add} = { required => 'true', type => 'list', match => '.+' };
     $conftemplate->{backup}->{excl} = { required => 'false', type => 'list', match => '.+' };
     
     $myconfig->SetupDirectives($conftemplate);
     
     my $config = $myconfig->ReadConfig();
     
     print Dumper (\$config);
  • Results in the following hash structure

     $VAR1 = \{
                'global' => {
                              'tar' => '/bin/tar',
                              'sendmail' => '/usr/sbin/sendmail',
                              'rsync' => '/usr/bin/rsync',
                              'ssh' => '/usr/bin/ssh',
                              'debuglevel' => '1'
                            },
                'backup' => {
                              'server-home' => {
                                                 'archivemaxdays' => [
                                                                       '30'
                                                                     ],
                                                 'add' => [
                                                            '/home'
                                                          ],
                                                 'archiveschedule' => [
                                                                        'Sun'
                                                                      ],
                                                 'hostname' => 'localhost',
                                                 'backupschedule' => [
                                                                       'Mon',
                                                                       'Wed',
                                                                       'Fri'
                                                                     ]
                                               },
                              'server-system' => {
                                                   'excl' => [
                                                               '/home',
                                                               '/proc',
                                                               '/sys',
                                                               '/dev',
                                                               '/mnt',
                                                               '/media'
                                                             ],
                                                   'archivemaxdays' => [
                                                                         '60'
                                                                       ],
                                                   'add' => [
                                                              '/'
                                                            ],
                                                   'archiveschedule' => [
                                                                          'Sun'
                                                                        ],
                                                   'hostname' => 'localhost',
                                                   'backupschedule' => [
                                                                         'Mon',
                                                                         'Wed',
                                                                         'Fri'
                                                                       ]
                                                 }
                            }
              };

A more advanced example can be found in the included example program myconfig-demo.pl.

NOTES

Config::MyConfig2.pm supports my DebugHelper.pm class, which provides excellent debugging and error handling methods.

 $mycfg = Config::MyConfig2->new(
        conffile = "foo.cfg",
        dh = $reference_to_debughelper_class
        );
        

If you don't like, that MyConfig croaks if an error (i.e. syntax error in a configuration file) occurs, you may use MyConfig with eval:

  eval { $myconfig->ReadConfig() }
  if ($@) ... do something

AUTHOR

Markus Guertler, <markus at guertler.org>

BUGS

Please report any bugs or feature requests to bug-myconfig2 at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Config::MyConfig2. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Config::MyConfig2

You can also look for information at:

ACKNOWLEDGEMENTS

LICENSE AND COPYRIGHT

Copyright 2013 Markus Guertler.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.