views:

484

answers:

3

If I have a greenfield project, what is the best practice Perl based configuration module to use?

There will be a Catalyst app and some command line scripts. They should share the same configuration.

Some features I think I want ...

Hierarchical Configurations to cleanly maintain different development and live settings.

I'd like to define "global" configurations once (eg, results_per_page => 20), have those inherited but override-able by my dev/live configs.

Global:
  results_per_page: 20
  db_dsn: DBI:mysql;
  db_name: my_app
Dev:
  inherit_from: Global
  db_user: dev
  db_pass: dev
Dev_New_Feature_Branch:
  inherit_from: Dev
  db_name: my_app_new_feature
Live:
  inherit_from: Global
  db_user: live
  db_pass: secure

When I deploy a project to a new server, or branch/fork/copy it somewhere new (eg, a new development instance), I want to (one time only) set which configuration set/file to use, and then all future updates are automatic.

I'd envisage this could be achieved with a symlink:

git clone example.com:/var/git/my_project . # or any equiv vcs
cd my_project/etc
ln -s live.config to_use.config

Then in the future

git pull # or any equiv vcs

I'd also like something that akin to FindBin, so that my configs can either use absolute paths, or relative to the current deployment. Given

/home/me/development/project/
  bin
  lib
  etc/config

where /home/me/development/project/etc/config contains:

tmpl_dir: templates/

when my perl code looks up the tmpl_dir configuration it'll get:

/home/me/development/project/templates/

But on the live deployment:

/var/www/project/
  bin
  lib
  etc/config

The same code would magically return

/var/www/project/templates/

Absolute values in the config should be honoured, so that:

apache_config: /etc/apache2/httpd.conf

would return "/etc/apache2/httpd.conf" in all cases.

Rather than a FindBin style approach, an alternative might be to allow configuration values to be defined in terms of other configuration values?

tmpl_dir: $base_dir/templates

I'd also like a pony ;)

+7  A: 

Catalyst::Plugin::ConfigLoader supports multiple overriding config files. If your Catalyst app is called MyApp, then it has three levels of override: 1) MyApp.pm can have a __PACKAGE__->config(...) directive, 2) it next looks for MyApp.yml in the main directory of the app, 3) it looks for MyApp_local.yml. Each level may override settings in each other level.

In a Catalyst app I built, I put all of my immutable settings in MyApp.pm, my debug settings in MyApp.yml, and my production settings in MyApp_<servertype>.yml and then symlinked MyApp_local.yml to point at MyApp_<servertype>.yml on each deployed server (they were all a little different...).

That way, all of my config was in SVN and I just needed one ln -s step to manually config a server.

Chris Dolan
+2  A: 

Perl Best Practices warns against exactly what you want. It states that config files should be simple and avoid the sort of baroque features you desire. It goes on to recommend three modules (none of which are Core Perl): Config::General, Config::Std, and Config::Tiny.

The general rational behind this is that the editing of config files tends to be done by non-programmers and the more complicated you make your config files, the more likely they will screw them up.

All of that said, you might take a look at YAML. It provides a full featured, human readable*, serialization format. I believe the currently recommend parser in Perl is YAML::XS. If you do go this route I would suggest writing a configuration tool for end users to use instead of having them edit the files directly.

ETA: Based on Chris Dolan's answer it sounds like YAML is the way to go for you since Catalyst is already using it (.yml is the de facto extension for YAML files).

* I have heard complaints that blind people may have difficulty with it

Chas. Owens
A: 

YAML is hateful for config - it's not non-programmer friendly partly because yaml in pod is by definition broken as they're both white-space dependent in different ways. This addresses the main problem with Config::General. I've written some quite complicated config files with C::G in the past and it really keeps out of your way in terms of syntax requirements etc. Other than that, Chris' advice seems on the money.

singingfish