File Coverage

blib/lib/PBib/Config.pm
Criterion Covered Total %
statement 143 162 88.2
branch 39 58 67.2
condition 8 14 57.1
subroutine 24 27 88.8
pod 9 14 64.2
total 223 275 81.0


line stmt bran cond sub pod time code
1             # --*-Perl-*--
2             # $Id: Config.pm 25 2005-09-17 21:45:54Z tandler $
3             #
4              
5             =head1 NAME
6              
7             PBib::Config - Configuration for PBib
8              
9             =head1 SYNOPSIS
10              
11             use PBib::Config;
12             $conf = new PBib::Config();
13              
14             =head1 DESCRIPTION
15              
16             Handle the configuration for PBib. It looks in cmd-line args,
17             environment, and at various places at config files.
18            
19             In fact, this module contains no code specific to PBib, so
20             you might be able to use it for your own applications as well.
21              
22             =cut
23              
24             package PBib::Config;
25 2     2   31243 use 5.006;
  2         8  
  2         77  
26 2     2   11 use strict;
  2         4  
  2         67  
27 2     2   9 use warnings;
  2         6  
  2         75  
28             #use English;
29              
30             # for debug:
31 2     2   2067 use Data::Dumper;
  2         11551  
  2         137  
32              
33             BEGIN {
34 2     2   14 use vars qw($Revision $VERSION);
  2         3  
  2         195  
35 2     2   4 my $major = 1; q$Revision: 25 $ =~ /: (\d+)/; $VERSION = sprintf("$major.%03d", $1);
  2         9  
  2         222  
36             }
37              
38             # superclass
39             #use YYYY;
40             #our @ISA;
41             #@ISA = qw(YYYY);
42              
43             # used standard modules
44             #use FileHandle;
45 2     2   2555 use Getopt::Long;
  2         27607  
  2         14  
46 2     2   2382 use Text::ParseWords;
  2         2807  
  2         137  
47 2     2   13 use File::Basename;
  2         4  
  2         212  
48 2     2   20 use File::Spec;
  2         3  
  2         40  
49 2     2   11 use Carp;
  2         4  
  2         119  
50              
51 2     2   2044 use FindBin qw($Bin);
  2         2376  
  2         227  
52             # use lib "$Bin/../lib";
53            
54             # used own modules
55 2     2   1641 use PBib::ConfigFile;
  2         7  
  2         4205  
56              
57             # module variables
58             #our($mmm);
59              
60              
61             =head1 METHODS
62              
63             =over
64              
65             =cut
66              
67             #
68             #
69             # constructor
70             #
71             #
72              
73             =item $conf = new PBib::Config(I)
74              
75             New creates a new Config object. Upon creation, it reads the standard
76             config from command-line, environment, site- and user-preferences.
77             Options:
78              
79             =over
80              
81             =item B
82              
83             If true, check @ARGV.
84              
85             =item B
86              
87             If true, check $ENV{'PBIB'};
88              
89             =item B
90              
91             If true, read site configuration file ("local.pbib") -- whereever it is found ...
92              
93             =item B
94              
95             If true, read user configuration file ("user.pbib") -- whereever it is found ...
96              
97             =item B
98              
99             Ref to a hash with the default configuration.
100            
101             =item B
102            
103             Be more verbose and keep the verbose flag within the options.
104              
105             =item B
106            
107             Be more quite and keep the quiet flag within the options.
108              
109             =back
110              
111             =cut
112            
113             my %attributes = qw(
114             argv 1 env 1 site 1 user 1 default 1 options 1
115             );
116              
117             sub new {
118 2     2 1 33 my $self = shift;
119 2         20 my $aConfig = {
120             argv => 1,
121             env => 1,
122             site => 1,
123             user => 1,
124             default => 1,
125             options => {},
126             };
127 2   33     22 my $class = ref($self) || $self;
128 2         7 $aConfig = bless $aConfig, $class;
129            
130             # special hack for test scripts to ensure defined configuration
131 2         20 my %argv = @_;
132 2         9 my $mode = $ENV{PBIB_CONFIG};
133 2 50       9 if( defined $mode ) {
134 0         0 foreach my $arg (split(/,/, $mode)) {
135 0         0 my ($attr, $val) = split(/=/, $arg);
136 0         0 $argv{$attr} = $val;
137             # print STDERR "$attr=$val\n";
138             }
139             }
140            
141             # process arguments
142 2         12 foreach my $attr (keys %argv) {
143 14 100       38 if( $attributes{$attr} ) {
144             # print STDERR "set attribute $attr=$argv{$attr}\n";
145 10         31 $aConfig->{$attr} = $argv{$attr};
146             } else {
147             # print STDERR "set option $attr=$argv{$attr}\n";
148 4         17 $aConfig->option($attr, $argv{$attr});
149             }
150             }
151             # print Dumper $aConfig;
152            
153             # load default, user, site, env, argv
154 2         12 $aConfig->load();
155 2         17 return $aConfig;
156             }
157              
158             #
159             #
160             # destructor
161             #
162             #
163              
164             #sub DESTROY ($) {
165             # my $self = shift;
166             #}
167              
168              
169              
170             #
171             #
172             # access methods
173             #
174             #
175              
176             # sub a { return shift->{'a'}; }
177             # sub b { my $self = shift; return $self->{'b'}; }
178              
179             =item $options = $conf->options(I)
180              
181             Return a hash ref with all options. If the optional filename is given, it
182             looks for additional options for this file by checking for a F
183             file in this directory and for a file with F<.pbib> as extension.
184             Options:
185              
186             =over
187              
188             =item file
189              
190             Look for additional options for this file in "$filename.pbib"
191              
192             =item dir
193              
194             Look in this dir for additional "local.pbib"
195              
196             =back
197              
198             =cut
199              
200             sub options {
201 47     47 1 460 my ($self) = shift;
202 47         86 my %args = @_;
203 47   50     144 my $options = $self->{'options'} || {};
204 47         72 my $file = $args{'file'};
205 47         64 my $dir = $args{'dir'};
206            
207             # load additional directory's configuration
208 47 50       106 if( $dir ) {
209 0         0 $options = merge_options($options,
210             $self->load_configfile("$dir/local.pbib", [$dir]));
211             }
212            
213             # load file configuration
214 47 100       93 if( $file ) {
215             # check if there's a config file in file's dir
216 2         124 my $fdir = dirname($file);
217 2         16 $options = merge_options($options,
218             $self->load_configfile("$fdir/local.pbib", [$dir, $fdir]));
219            
220 2         16 $options = merge_options($options,
221             $self->load_configfile("$file.pbib", [$dir, $fdir]));
222 2         25 $file =~ s/\.(\w+)$/\.pbib/;
223 2         104 $options = merge_options($options,
224             $self->load_configfile($file, [$dir, $fdir]));
225             }
226            
227 47         119 return $options;
228             }
229              
230             =item $option = $conf->option(I[, $new_val]);
231              
232             Return the option.
233            
234             If $new_val is given, the option is set to the new value and the old value is returned.
235              
236             =cut
237              
238             sub option {
239 44     44 1 703 my ($self, $name, $new_val) = @_;
240 44         136 my @path = split(/\./, $name);
241 44         253 my $options = $self->options();
242 44         59 my ($opt, $val, $last_opt);
243 44 50       120 if( ! @path ) {
244 0         0 croak("ERROR: No path given in access to $name");
245             # return undef;
246             }
247 44         132 while( $opt = shift @path ) {
248 46         138 $last_opt = $opt;
249 46 100       128 if( defined $options->{$opt} ) {
250 42         72 $val = $options->{$opt};
251 42 100       164 if( @path ) {
252 2         3 $options = $val;
253 2 50       10 if( ref $options ne 'HASH' ) {
254 0         0 croak("ERROR: Path too short in access to $name at $opt");
255             # return undef;
256             }
257             }
258             } else {
259             # print STDERR "WARNING: Option $opt not found in access to $name\n"; ## if it's undef that's alright!
260 4         7 $val = undef;
261 4 50       19 if( @path ) {
262             # create new hash for sub-options ...
263             # print STDERR "Add $opt to option path for $name\n";
264 0         0 $options = $val = $options->{$opt} = {};
265             }
266             }
267             }
268 44 100       95 if( defined $new_val ) {
269             # print "Set option $name(*.$last_opt) to $new_val\n";
270 4         10 $options->{$last_opt} = $new_val;
271             }
272 44         285 return $val;
273             }
274              
275             =item $options = $conf->setOptions($options);
276              
277             Overwrite the configuration stored internally.
278              
279             =cut
280              
281             sub setOptions {
282 0     0 1 0 my ($self, $options) = @_;
283 0         0 $self->{options} = $options;
284 0         0 return $options;
285             }
286              
287            
288             =item $verbose = $conf->beVerbose();
289            
290             If true, more verbose output should be produced.
291            
292             =cut
293            
294             sub beVerbose {
295 28     28 1 49 my ($self) = @_;
296 28         80 return $self->option('verbose');
297             }
298            
299             =item $quiet = $conf->beQuiet();
300            
301             If true, more quiet output should be produced.
302            
303             =cut
304            
305             sub beQuiet {
306 9     9 1 20 my ($self) = @_;
307 9         22 return $self->option('quiet');
308             }
309            
310              
311             #
312             #
313             # methods
314             #
315             #
316              
317             =item $options = $conf->load();
318              
319             load config, as specified in new(). It will overwrite the configuration
320             stored internally.
321              
322             =cut
323              
324             sub load {
325 2     2 1 7 my ($self) = @_;
326 2         6 my $options = $self->{options};
327            
328             # load defaults
329 2 50       9 if( $self->{default} ) {
330             # note: the default options have lower prio than args to
331             # the constructor
332 2         11 $options = merge_options(
333             $self->load_file("default.pbib"),
334             $options);
335             }
336            
337             # load site configuration
338 2 50       14 if( $self->{site} ) {
339 0         0 $options = merge_options($options,
340             $self->load_file("local.pbib"));
341             }
342            
343             # load user configuration
344 2 50       10 if( $self->{user} ) {
345 0         0 $options = merge_options($options,
346             $self->load_file("user.pbib"));
347             }
348            
349             # check environment
350 2 50       10 if( $self->{env} ) {
351 0         0 $options = merge_options($options,
352             $self->load_env());
353             }
354            
355             # parse ARGV
356 2 50       11 if( $self->{argv} ) {
357 0         0 $options = merge_options($options,
358             $self->load_argv());
359             }
360            
361 2         6 $self->{options} = $options;
362 2         8 return $options;
363             }
364              
365             sub load_argv {
366 0     0 0 0 my ($self) = @_;
367 0         0 return {};
368             }
369              
370             sub load_env {
371 0     0 0 0 my ($self) = @_;
372             # check environment
373             # if( defined $ENV{$pbib_env} ) {
374             # unshift(@ARGV, Text::ParseWords::shellwords($ENV{$pbib_env}));
375             # }
376 0         0 return {};
377             }
378              
379             =item SEARCH PATH for config files
380              
381             the following places are searched for all config files:
382              
383             =over
384              
385             =item the current directory ('.')
386              
387             =item $HOME
388            
389             If $HOME is set, pbib searches:
390             $ENV{HOME}/.pbib/styles
391             $ENV{HOME}/.pbib/conf
392             $ENV{HOME}/.pbib
393             $ENV{HOME}
394              
395             =item $PBIBSTYLES
396            
397             Can be a comma separated list.
398              
399             =item $PBIBCONFIG
400            
401             Can be a comma separated list.
402              
403             =item $PBIBPATH (separated by ',')
404              
405             if $PBIBPATH is undefined, it defaults to
406             /etc/pbib/styles,/etc/pbib/conf,/etc/pbib,/etc
407            
408             =item $APPDATA
409            
410             $APPDATA is supported for Windows XP. If set, pbib searches
411             $ENV{APPDATA}/PBib/styles
412             $ENV{APPDATA}/PBib/conf
413             $ENV{APPDATA}/PBib
414              
415             =item $PBIBDIR
416              
417             if $PBIBDIR is undefined, it defaults to the directory pbib
418             resides in (as detected by FindBin).
419            
420             =item all PBib/styles and PBib/conf in @INC
421            
422             Perl's include path @INC is searched for all subdirectories
423             PBib/styles and PBib/conf. This is where the an installed PBib
424             finds all the default configuration.
425              
426             =back
427              
428             B by using all these places for I config file, it is
429             possible for each user to overwrite the site's configuration if
430             necessary. Use with care!
431              
432             =cut
433              
434             our $PBIB_DIR = $ENV{'PBIBDIR'} || $Bin;
435             our @PBIB_PATH = split( /,/, $ENV{'PBIBPATH'} ||
436             '/etc/pbib/styles,/etc/pbib/conf,/etc/pbib,/etc' );
437             our @CONFIG_PATH = grep { defined($_) } (
438             '.',
439             $ENV{HOME} ? ( # for personal settings
440             "$ENV{HOME}/.pbib/styles",
441             "$ENV{HOME}/.pbib/conf",
442             "$ENV{HOME}/.pbib",
443             $ENV{HOME},
444             ) : (),
445             split( /,/, $ENV{'PBIBSTYLES'} || ''),
446             split( /,/, $ENV{'PBIBCONFIG'} || ''),
447             @PBIB_PATH,
448             $ENV{APPDATA} ? ( # for Windows XP
449             "$ENV{APPDATA}/PBib/styles",
450             "$ENV{APPDATA}/PBib/conf",
451             "$ENV{APPDATA}/PBib",
452             ) : (),
453             $PBIB_DIR,
454             map("$_/PBib/styles", @INC),
455             map("$_/PBib/conf", @INC),
456             );
457              
458             sub load_file {
459 2     2 0 6 my ($self, $filename, $path) = @_;
460 2 50       9 return unless $filename;
461 2         5 my $options = {};
462 2 50       31 my @config_path = ( ($path ? @$path : ()), @CONFIG_PATH );
463 2         6 @config_path = grep { defined($_) } @config_path; # remove undef from list
  68         115  
464 2 50       14 print STDERR "looking for $filename in path: @config_path\n" if $self->beVerbose();
465 2         8 foreach my $dir (@config_path) {
466             # print STDERR "$dir -->\n";
467 68         684 my $file = File::Spec->catfile($dir,$filename);
468             # print STDERR "$file ...?\n";
469 68 100       1556 if( -r $file ) {
470 6         30 $options = merge_options($options,
471             $self->load_configfile($file, \@config_path));
472             }
473             }
474 2         21 return $options;
475             }
476              
477             sub load_configfile {
478             # the filename should be absolute, don't search for it.
479 12     12 0 28 my ($self, $filename, $path) = @_;
480              
481 12 100       350 unless( -r $filename ) {
482 4 50       12 print STDERR "no config file $filename\n" if $self->beVerbose();
483 4         19 return;
484             }
485 8 50       30 print STDERR "read config from $filename\n" if $self->beVerbose();
486            
487 8         76 my @config_path = @CONFIG_PATH;
488             # print STDERR Dumper $path;
489 8 50       162 @config_path = (@$path, @config_path) if $path;
490 8         40 @config_path = grep { defined($_) } @config_path;
  480         721  
491             # print STDERR Dumper \@config_path;
492            
493 8         148 my $c = new PBib::ConfigFile(
494             -UseApacheInclude => 1,
495             -IncludeRelative => 1,
496             -AutoTrue => 1,
497             -ConfigFile => $filename,
498             -ConfigPath => \@config_path,
499             # caution: pass a copy to path to PBib::ConfigFile, it can be modified!
500             );
501 8         70 my %options = $c->getall();
502 8 50       46 $options{loaded_config_files} = [] unless $options{loaded_config_files};
503 8         12 push @{$options{loaded_config_files}}, $filename;
  8         22  
504              
505             # if includes are used, the options have to be merged. hm.
506 8         29 return compress_options(\%options);
507             }
508              
509             =item $options = $conf->merge($options);
510              
511              
512             =cut
513              
514             sub merge {
515 2     2 1 4 my ($self, $options) = @_;
516 2         4 return $self->{'options'} = merge_options($self->{'options'}, $options);
517             }
518              
519              
520             #
521             #
522             # class methods
523             #
524             #
525              
526             =back
527            
528             =head2 CLASS METHODS
529              
530             =over
531              
532             =item $hash_ref = merge_options(<>)
533              
534             Return an hash with all merged options entries. This also traverses
535             sub-entry hashs.
536              
537             Parameters that are no hash refs are ignored. Duplicate keys will
538             be overwritten depending on the order of parameters.
539              
540             =cut
541              
542             sub merge_options {
543 51     51 1 81 my $result = {};
544 51         60 my ($k, $v, $rv);
545            
546 51         84 foreach my $conf (@_) {
547             #print Dumper $conf;
548 98 50       204 next unless ref $conf eq 'HASH';
549 98         315 while( ($k, $v) = each %$conf) {
550             # print "$k\n";
551 666         915 $rv = $result->{$k};
552 666 100       1174 if( defined $rv ) {
553 283 100 66     686 if( ref $v eq 'HASH' &&
554             ref $rv eq 'HASH' ) {
555 35         72 $v = merge_options($rv, $v);
556             }
557             }
558 666         2057 $result->{$k} = $v;
559             }
560             }
561 51         229 return $result;
562             }
563              
564              
565             # internal method that is used if includes are used in
566             # config files
567             # merge all sub-configs, if an options points to a ref containing hashs only.
568              
569             sub compress_options {
570 62     62 0 74 my ($conf) = @_;
571 62         197 foreach my $opt (keys %$conf) {
572 458         556 my $val = $conf->{$opt};
573 458 50 66     868 if( ref($val) eq 'ARRAY' &&
      66        
574             @$val &&
575             ref($val->[0]) eq 'HASH' ) {
576 0         0 $conf->{$opt} = merge_options(@$val);
577             }
578 458 100       823 if( ref($val) eq 'HASH' ) {
579 54         88 $conf->{$opt} = compress_options($val);
580             }
581             }
582 62         464 return $conf;
583             }
584              
585             1;
586              
587             =back
588              
589             =head1 AUTHOR
590              
591             Peter Tandler
592              
593             =head1 SEE ALSO
594              
595             Module L
596              
597             =head1 HISTORY
598              
599             $Log: Config.pm,v $
600             Revision 1.7 2003/06/16 09:12:28 tandler
601             use default.pbib that contains config that was previously directly in the perl source
602              
603             Revision 1.6 2003/06/13 16:11:09 tandler
604             moved default local.pbib to "conf" folder
605              
606             Revision 1.5 2003/04/16 15:06:09 tandler
607             adapted to support search path for config files in patched Config::General
608              
609             Revision 1.4 2003/04/14 09:46:12 ptandler
610             new module ConfigFile that encapsulates Config::General
611              
612             Revision 1.3 2003/02/20 09:26:41 ptandler
613             added dirs to look for config files:
614             - $ENV{PBIBDIR} (if set instead of $Bin),
615             - $ENV{PBIBPATH} or /etc/pbib
616             - $ENV{PBIBSTYLES}
617             - $ENV{PBIBCONFIG}
618              
619             Revision 1.2 2003/01/14 11:08:15 ptandler
620             new config
621              
622             Revision 1.1 2002/11/11 12:00:51 peter
623             early stage ...
624              
625              
626             =cut