diff options
Diffstat (limited to 'lib/Youri/Config.pm')
-rw-r--r-- | lib/Youri/Config.pm | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/lib/Youri/Config.pm b/lib/Youri/Config.pm new file mode 100644 index 0000000..3affa7a --- /dev/null +++ b/lib/Youri/Config.pm @@ -0,0 +1,202 @@ +# $Id: Config.pm 1709 2006-10-16 16:33:43Z warly $ +package Youri::Config; + +=head1 NAME + +Youri::Application - Youri application handler + +=head1 SYNOPSIS + + use Youri::Application; + + my $app = Youri::Application->new( + options => { + help => '|h!' + }, + directories => [ '/etc/youri', "$ENV{HOME}/.youri" ], + file => 'app.conf', + ); + + # get command line argument + my $foo = $app->get_arg('foo'); + + # get configuration file parameter + my $bar = $app->get_param('bar'); + +=head1 DESCRIPTION + +This class handle configuration for all YOURI applications. + +The command line specification is used to manage arguments through +Getopt::Long. Unless B<--config> argument is given, the list of directories is +then scanned for a file with given name, and halt as soon as it find one. If no +readable file is found, an exception is thrown. The file is then processed +through YAML::AppConfig. If parsing fails, an exception is thrown. + +=head1 CONFIGURATION FILE FORMAT + +=head2 SHARED KEYS + +In addition to the application-specific optional or mandatory parameters, all +YOURI applications support the following optional top-level parameters: + +=over + +=item B<includes> + +A list of additional configuration files. + +=item B<foo> + +An arbitrary variable, usable everywhere else in the file. + +=back + +=head2 PLUGIN DEFINITION + +All YOURI application heavily rely on plugins defined in their configuration +files. A plugin definition is composed from the following parameters: + +=over + +=item B<class> + +The class of this plugin. + +=item B<options> + +The options of this plugin. + +=back + +=head1 SEE ALSO + +YAML::AppConfig, Getopt::Long + +=cut + +use strict; +use warnings; +use YAML::AppConfig; +use Getopt::Long; +use File::Spec; +use Pod::Usage; +use Carp; + +sub new { + my ($class, %options) = @_; + + + # command line arguments + my $args = { + verbose => 0 + }; + my @args; + if ($options{args}) { + while (my ($arg, $spec) = each %{$options{args}}) { + push(@args, ($arg . $spec) => \$args->{$arg}); + } + } + push(@args, + 'config=s' => \$args->{config}, + 'h|help' => \$args->{help}, + 'v|verbose+' => \$args->{verbose} + ); + GetOptions(@args); + + if ($args->{help}) { + if (!@ARGV) { + # standard help, available immediatly + my $filename = (caller)[1]; + pod2usage( + -input => $filename, + -verbose => 0 + ); + } + } + + # config files parameters + + # find configuration file to use + my $main_file; + if ($args->{config}) { + if (! -f $args->{config}) { + croak "Non-existing file $args->{config}"; + } elsif (! -r $args->{config}) { + croak "Non-readable file $args->{config}"; + } else { + $main_file = $args->{config}; + } + } else { + foreach my $directory (@{$options{directories}}) { + my $file = "$directory/$options{file}"; + next unless -f $file && -r $file; + $main_file = $file; + last; + } + croak 'No config file found, aborting' unless $main_file; + } + + my $params; + eval { + $params = YAML::AppConfig->new(file => $main_file); + }; + if ($@) { + croak "Invalid configuration file $main_file, aborting"; + } + + # process inclusions + my $includes = $params->get('includes'); + if ($includes) { + foreach my $include_file (@{$includes}) { + # convert relative path to absolute ones + $include_file = File::Spec->rel2abs( + $include_file, (File::Spec->splitpath($main_file))[1] + ); + + if (! -f $include_file) { + warn "Non-existing file $include_file, skipping"; + } elsif (! -r $include_file) { + warn "Non-readable file $include_file, skipping"; + } else { + eval { + $params->merge(file => $include_file); + }; + if ($@) { + carp "Invalid included configuration file $include_file, skipping"; + } + } + } + } + + my $self = bless { + _args => $args, + _params => $params + }, $class; + + return $self; +} + +sub get_arg { + my ($self, $arg) = @_; + croak "Not a class method" unless ref $self; + + return $self->{_args}->{$arg}; +} + +sub get_param { + my ($self, $param) = @_; + croak "Not a class method" unless ref $self; + + return $self->{_params}->get($param); +} + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2002-2006, YOURI project + +This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. + +=cut + +1; |