Actions: | Security

AllGoodBits.org

Navigation: Home | Services | Tools | Articles | Other

A Simple Pattern for Configuration in Perl

In order to be flexible and provide more widely applicable functionality, code should be configurable, right? But ask perl programmers how best to pass configuration data to their programs and you'll likely get many different answers.

Here is an example of a very simple pattern that allows specification of configuration data at the level of:

The priority is CLI > file > built-in.

I originally wrote this for handling config for connecting to a database, which explains the example. Obviously, this pattern is not only pertinent for database config data.

There are various reasons why I have chosen to write it this way; I'm sure there are also various reasons why this is _not_ a good solution for certain needs.

One aspect that I like is that I can be granular about the configuration data; in the config file, I can separate by stanza heading, '[database]', and since each stanza hash is separate, I can give different parts of the config to different parts of my code. Minor, but it helps my keep things cleaner and simpler in my mind.

I'm using 2 non-core perl modules, both of which are likely available in your distribution's software repositories: Config::Tiny and Hash::Merge. Use your distro's package repositories unless you have a good reason not to; and even then consider packaging into a local repository.

#!/usr/bin/env perl

use strict;
use warnings;

use Config::Tiny;
use Getopt::Long;
use Hash::Merge qw( merge );

my %dbconfig_defaults = (
  dbtype => 'Pg',   # This should be the name of the DBD; probably one of :'Pg','MySQL','SQLite'
  dbhost => 'localhost',   # Encourage a unix domain socket connection
  dbname => 'example_db',
  dbuser => 'example_user',
  dbpass => 'GuessMeEasily',
  );

my $config = Config::Tiny->new;
$config = Config::Tiny->read( '/etc/myconfig.conf');

my(%dbconfig_cli,$otherconfig_cli);
GetOptions(
  "dbtype=s" => $dbconfig_cli{'dbtype'},
  "dbhost=s" => $dbconfig_cli{'dbhost'},
  "dbname=s" => $dbconfig_cli{'dbname'},
  "dbuser=s" => $dbconfig_cli{'dbuser'},
  "dbpass=s" => $dbconfig_cli{'dbpass'},

  "dbport=i" => $dbconfig_cli{'dbport'},

  "help|h"      => $otherconfig_cli{'help'},
  "verbose|v"   => $otherconfig_cli{'verbose'},
  );

my %db_config = %{ merge(\%dbconfig_cli, $config->{'database'}) };
%db_config = %{ merge(\%dbconfig,\%dbconfig_defaults) };

I can list all the configuration items that are in the file's stanza called 'section' with:

keys(%{$config->{'section'}})

For reference, here is a configuration file which replicates the behaviour of the built-in defaults:

[database]
dbtype=Pg
dbhost=localhost
dbport=5432
dbuser=example_user
dbpass=GuessMeEasily
dbname=example_db