ParseConfig - Perl module for parsing configuration files
use ParseConfig;
# Default processing ... search for cfg file in # ./.$0.rc, ~/cfg/$0.rc and ~/.$0.rc $cfg = new ParseConfig();
# Specify default cfg file $cfg = new ParseConfig(-defcfg=>"$ENV{XX_RUN_CONTROL}/globals.rc");
# To override cfg file defaults from environment $cfg = new ParseConfig(-useenv=>1);
# To dump values into a hash instead into 'true' vars: $config = {}; $cfg = new ParseConfig(-hash=>$config);
# Do the work: set-up vars with defaults, patch with cmdl opts $cfg->parse();
ParseConfig is a module for processing of configuration files which
define some variables to be exported into the callers
namespace(s). These variables can be optionally overriden from
environment variables and unconditionally from command line
arguments. Getopt::Long
is used for the last part.
NOTE: Defaults are set for all variables first. Only then the command line options are applied.
The idea is that you don't really want to declare globals inside your perl scripts and even less to provide them some default values that are of limited usefulness. Instead you define them in a config file.
The file is line based, each line has the form:
<command-line-option> <string-for-getopt> <namespace> <varname> <default>
Lines that match /^#/
or /^\s*$/
are skipped.
The namespace can be specified as . and it stands for main.
Eg (for my mkmenu script that generates ssh menus for windowmaker):
# Login name name =s main NAME "matevz" group =s main GROUP "f9base" # Terminal to spawn (think `$TERM -e ssh ...`) term =s main TERM "rxvt"
Then you can run it as 'mkmenu -name root'
.
Read the Getopt::Long manual
for explanation of the second
parameter. For void argument specification (which means bool), use
'b'
or 'bool'
. To suppress passing of this variable to
Getopt::Long
use 'x'
or 'exclude'
.
Will create new ParseConfig objects. Options can be set on
construction time using the hash syntax -option => value
or
later by assigning to a data member as in $cfg->{-option = value}
. This is the list of options:
Specifies the default location of the configuration file. Can be an array reference to specify several locations to search the file for. Some are predefined, but the ones given here are considered first. See BUILT-IN CONFIG FILE RULES for details. The file list is created on construction time so be careful if you modify the list by hand.
If set to non zero values of environment variables will take precedence over config file defaults. Command line options are still more potent. See ENVIRONMENT OVERRIDES.
If set to a hash reference the variables will be exported into it. See PARSING INTO A HASHREF.
If set to non zero ParseConfig will dump a moderate amount of info
during parse()
.
Adds <sub-ref> to the list of functions that are called after the
setting of the variables and patching from command line. Useful when
you need to create some compound variables. If -hash
is set, the
hash reference is passed to these functions as the only argument.
parse()
Does all the job: selects config file to be used, reads it, sets the default values and the calls GetOptions. After that the post functions are invoked.
Splits string into an array and calls parse()
, pretending that this
string was the actual command line.
I used this option to recreate certain variables (for job control and dbase insertion) from list of commands that were submitting jobs into the queuing system.
If you dont specify the default cfg file, ParseConfig searches for it in the following locations:
$base = `basename $0 .pl`; # can be set with -cfgbase=>'foo' `pwd`/${base}.rc `pwd`/.${base}.rc ~/cfg/${base}.rc ~/.${base}.rc
If you do specify the -defcfg
it is prepended to the above
list. The first found file is used. You can obtain it from
$cfg->{Config}
. Also, the program name can be obtained from
$cfg->{ProgName}
.
Will add additional variables enabling a user to fully specify the format of these locations when typical use-cases are gathered (perhaps /etc/... ?).
By creating symlinks to a master script you can have several config files for the same script and get different default behaviour.
If $ARGV[0]
of the script using ParseConfig is -cfg
, then
$ARGV[1]
is used as a configuration file and no other locations are
scanned.
ParseConfig::parse() dies if it can't find any of these files. It should croak.
So far all default values are eval-ed prior to assignment. Which means
you can use []
or {}
or sub{}
to get array/hash/closure
reference as a default value. Getopt::Long treats such variables
differently ... so read its manual to learn more. But, BEWARE, the
command line option arguments are NOT eval-ed. Bug Johan Vromans for
this option and then I'll do my part. Then would also add the eval
control on per-variable base into the config file.
You can as well instantiate an object ... decide for yourself ... it
doesn't sound like such a great idea to me. Getopt::Long
isn't too
keen of the idea either, so make sure to suppress passing an obj ref
to it.
One of the more obscene uses of this feature is to set the default to:
remap =s main REMAP do "$ENV{HOME}/.domain.remaps"
where the file .domain.remaps is, eg:
{ "some.domain:other.domain" => { "/u/atlas/matevz" => "/home/matevz", "/opt/agnes" => "/opt" } "foo.domain:some.domain" => { "/afs/cern.ch/user/m/matevz" => "/u/atlas/matevz" } }
This will make $REMAP
a hash ref to the above struct.
Of course you are not limited to a single statement ... but then use
;s
and know your eval. Don't use newlines or you'll confuse the
parser. If you're annoyed by that you/I can fix the parser to grog a
trailing \
as a continuation symbol.
If $cfg->{-useenv}
is true, then the defaults are taken from the
environment. The names of perl and environment variable must be the
same AND the env-var must be set (ie: defined $ENV{$VARNAME}
must
be true). The values of env vars are eval-ed, too. So take care.
This means you're asking for trouble if several variables in different namespaces have the same names. Or maybe not, if you know what you are doing.
Probably should set some additional flags that would mean do-not-eval
and never-override-from environment. Probably with some prefixes to
the default value or to the type of a command line option (like
{xs}=s
).
You're free to invoke ParseConfig
several times. As in:
# db options $o = new ParseConfig(-defcfg=>"$ENV{PRODDIR}/cfg/db.rc", -useenv=>1); $o->parse(); # Tape options $to = new ParseConfig(-defcfg=>"$ENV{PRODDIR}/cfg/tape_${OCEAN}.rc"); $to->parse();
When invoking the command make sure to use -- between options intended for different config file parsers.
By setting $cfg->{-hash} = <some-hash-ref>
you can redirect
parsing into this hash (instead of namespace globals). A non-main
namespace name induces an additional level of hashing.
Example:
Having a config file pcm.rc
simple =s . SIMPLE "blak" aref =s . AREF [] href =s Kazaan HREF {}
and perl script pcm.pl
#!/usr/bin/perl use ParseConfig; use Data::Dumper;
$XX = {}; my $cfg = new ParseConfig(-hash=>$XX); $cfg->parse(); print Dumper($XX);
The result of running
pcm.pl -aref pepe -aref lojz -href drek=shit -href joska=boob
is:
$VAR1 = { 'AREF' => [ 'pepe', 'lojz' ], 'Kazaan' => { 'HREF' => { 'drek' => 'shit', 'joska' => 'boob' } }, 'SIMPLE' => 'blak' };
Matevz Tadel <matevz.tadel@ijs.si>