From 0b78a916bbf5d3f6a4ec1d9e063d80032f619f5e Mon Sep 17 00:00:00 2001 From: Thomas von Dein Date: Sat, 10 Oct 2009 16:40:22 +0000 Subject: [PATCH] 2.34 - fixed rt.cpan.org#27271 - removed output file from manifest. - fixed rt.cpan.org#27225 - clear vars off the stack if entering a new block, so old vars get not re-used. - fixed rt.cpan.org#27110 - re-implemented support for arrayref as -String parameter. - fixed rt.cpan.org#24155 - relative include bug fixed. - applied patch by GWYN, (see fixed rt.cpan.org#27622) which allows the same file included multiple times. there is no loop detection if turned on. new option introduced: -IncludeAgain => 1 (default turned off). - added support for -IncludeAgain to directory include code too. - the directory globbing code used slashes to join directory and file names. changed this to use catfile() instead. git-svn-id: http://dev.catalyst.perl.org/repos/Config-General/trunk@60 be1acefe-a474-0410-9a34-9b3221f2030f --- Changelog | 25 +++++++++++ General.pm | 97 ++++++++++++++++++++++++++++++++++++------- MANIFEST | 7 ++-- README | 2 +- t/apache-include.conf | 6 +++ t/dual-include.conf | 6 +++ t/included.conf | 1 + t/run.t | 31 +++++++++++++- 8 files changed, 153 insertions(+), 22 deletions(-) create mode 100644 t/apache-include.conf create mode 100644 t/dual-include.conf create mode 100644 t/included.conf diff --git a/Changelog b/Changelog index 761594f..265e1f8 100644 --- a/Changelog +++ b/Changelog @@ -1,3 +1,28 @@ + 2.34 + - fixed rt.cpan.org#27271 - removed output file from + manifest. + + - fixed rt.cpan.org#27225 - clear vars off the stack + if entering a new block, so old vars get not re-used. + + - fixed rt.cpan.org#27110 - re-implemented support + for arrayref as -String parameter. + + - fixed rt.cpan.org#24155 - relative include bug fixed. + + - applied patch by GWYN, (see fixed rt.cpan.org#27622) + which allows the same file included multiple times. + there is no loop detection if turned on. new option + introduced: -IncludeAgain => 1 (default turned off). + + - added support for -IncludeAgain to directory include + code too. + + - the directory globbing code used slashes to join + directory and file names. changed this to use catfile() + instead. + + 2.33 - fixed rt.cpan.org#26333 - just return $con if env var is undefined. diff --git a/General.pm b/General.pm index 6a88819..48f89bf 100644 --- a/General.pm +++ b/General.pm @@ -32,7 +32,7 @@ use Carp::Heavy; use Carp; use Exporter; -$Config::General::VERSION = 2.33; +$Config::General::VERSION = 2.34; use vars qw(@ISA @EXPORT_OK); use base qw(Exporter); @@ -57,6 +57,7 @@ sub new { IncludeRelative => 0, IncludeDirectories => 0, IncludeGlob => 0, + IncludeAgain => 0, AutoLaunder => 0, AutoTrue => 0, AutoTrueFlags => { @@ -292,6 +293,11 @@ sub _prepare { } delete $conf{-String}; } + # re-implement arrayref support, removed after 2.22 as _read were + # re-organized + elsif(ref(\$conf{-String}) eq 'ARRAY') { + $self->{StringContent} = join '\n', @{$conf{-String}}; + } else { croak "Parameter -String must be a SCALAR!\n"; } @@ -387,8 +393,16 @@ sub _open { # # open the config file, or expand a directory or glob # - my($this, $configfile) = @_; - my $fh; + my($this, $basefile, $basepath) = @_; + my($fh, $configfile); + + if($basepath) { + # if this doesn't work we can still try later the global config path to use + $configfile = catfile($basepath, $basefile); + } + else { + $configfile = $basefile; + } if ($this->{IncludeGlob} and $configfile =~ /[*?\[\{\\]/) { # Something like: *.conf (or maybe dir/*.conf) was included; expand it and @@ -413,8 +427,8 @@ sub _open { if (defined $this->{ConfigPath}) { # try to find the file within ConfigPath foreach my $dir (@{$this->{ConfigPath}}) { - if( -e catfile($dir, $configfile) ) { - $configfile = catfile($dir, $configfile); + if( -e catfile($dir, $basefile) ) { + $configfile = catfile($dir, $basefile); $found = 1; last; # found it } @@ -422,7 +436,7 @@ sub _open { } if (!$found) { my $path_message = defined $this->{ConfigPath} ? q( within ConfigPath: ) . join(q(.), @{$this->{ConfigPath}}) : q(); - croak qq{The file "$configfile" does not exist$path_message!}; + croak qq{The file "$basefile" does not exist$path_message!}; } } @@ -436,21 +450,26 @@ sub _open { # A directory was included; include all the files inside that directory in ASCII order local *INCLUDEDIR; opendir INCLUDEDIR, $configfile or croak "Could not open directory $configfile!($!)\n"; - my @files = sort grep { -f "$configfile/$_" } "$configfile/$_", readdir INCLUDEDIR; + my @files = sort grep { -f catfile($configfile, $_) } catfile($configfile, $_), readdir INCLUDEDIR; closedir INCLUDEDIR; local $this->{CurrentConfigFilePath} = $configfile; for (@files) { - if (! $this->{files}->{"$configfile/$_"}) { - $fh = IO::File->new( "$configfile/$_", 'r') or croak "Could not open $configfile/$_!($!)\n"; - $this->{files}->{"$configfile/$_"} = 1; + my $file = catfile($configfile, $_); + if (! exists $this->{files}->{$file} or $this->{IncludeAgain} ) { + # support re-read if used urged us to do so, otherwise ignore the file + $fh = IO::File->new( $file, 'r') or croak "Could not open $file!($!)\n"; + $this->{files}->{"$file"} = 1; $this->_read($fh); } + else { + warn "File $file already loaded. Use -IncludeAgain to load it again.\n"; + } } } elsif (-e _) { - if (exists $this->{files}->{$configfile} ) { + if (exists $this->{files}->{$configfile} and not $this->{IncludeAgain}) { # do not read the same file twice, just return - # FIXME: should we croak here, when some "debugging" is enabled? + warn "File $configfile already loaded. Use -IncludeAgain to load it again.\n"; return; } else { @@ -651,7 +670,7 @@ sub _read { $incl_file = $1; if ( $this->{IncludeRelative} && $path && !file_name_is_absolute($incl_file) ) { # include the file from within location of $this->{configfile} - $this->_open( catfile($path, $incl_file) ); + $this->_open( $incl_file, $path ); } else { # include the file from within pwd, or absolute @@ -726,6 +745,11 @@ sub _parse { } } if ($this->{InterPolateVars}) { + # Clear everything from the next level + # rt:27225 + if (defined $this->{stack} and defined $this->{stack}->{$this->{level} + 1}) { + $this->{stack}->{$this->{level} + 1} = {}; + } # interpolate block(name), add "<" and ">" to the key, because # it is sure that such keys does not exist otherwise. $block = $this->_interpolate("<$block>", $block); @@ -1378,6 +1402,19 @@ with standard file patterns, * will not match dot-files, so <> is often more desirable than including a directory with B<-IncludeDirectories>. +=item B<-IncludeAgain> + +If set to a true value, you will be able to include a sub-configfile +multiple times. With the default, false, you will get a warning about +duplicate includes and only the first include will succeed. + +Reincluding a configfile can be useful if it contains data that you want to +be present in multiple places in the data tree. See the example under +L. + +Note, however, that there is currently no check for include recursion. + + =item B<-ConfigPath> As mentioned above, you can use this variable to specify a search path for relative @@ -2164,6 +2201,34 @@ Include statements can be case insensitive (added in version 1.25). Include statements will be ignored within C-Comments and here-documents. +By default, a config file will only be included the first time it is +referenced. If you wish to include a file in multiple places, set +B to true. But be warned: this may lead to infinite loops, +so make sure, you're not including the same file from within itself! + +Example: + + # main.cfg + + class=Some::Class + + include printers.cfg + + # ... + + + class=Another::Class + + include printers.cfg + + # ... + + +Now C will be include in both the C and C objects. + +You will have to be careful to not recursively include a file. Behaviour +in this case is undefined. + =head1 COMMENTS @@ -2232,7 +2297,7 @@ allowed to the B method of the standard interface. Example: - use Config::General; + use Config::General qw(ParseConfig); my %config = ParseConfig(-ConfigFile => "rcfile", -AutoTrue => 1); @@ -2243,7 +2308,7 @@ to a hash structure. Example: - use Config::General; + use Config::General qw(SaveConfig); .. SaveConfig("rcfile", \%some_hash); @@ -2256,7 +2321,7 @@ method B does. Example: - use Config::General; + use Config::General qw(ParseConfig SaveConfigString); my %config = ParseConfig(-ConfigFile => "rcfile"); .. # change %config something my $content = SaveConfigString(\%config); diff --git a/MANIFEST b/MANIFEST index f094e1f..a549b33 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,10 +1,7 @@ General/Extended.pm General/Interpolated.pm -t/sub1/sub2/sub3/cfg.sub3.orig t/sub1/sub2/sub3/cfg.sub3 -t/sub1/sub2/cfg.sub2.orig t/sub1/sub2/cfg.sub2 -t/sub1/sub2/cfg.sub2b.orig t/sub1/sub2/cfg.sub2b t/sub1/cfg.sub1 t/sub1/cfg.sub1b @@ -26,8 +23,10 @@ t/cfg.20.a t/cfg.20.b t/cfg.20.c t/run.t -t/test.rc.out t/cfg.34 +t/included.conf +t/dual-include.conf +t/apache-include.conf MANIFEST example.cfg Makefile.PL diff --git a/README b/README index fdf1e1a..df55fe1 100644 --- a/README +++ b/README @@ -104,4 +104,4 @@ AUTHOR VERSION - 2.33 + 2.34 diff --git a/t/apache-include.conf b/t/apache-include.conf new file mode 100644 index 0000000..824338b --- /dev/null +++ b/t/apache-include.conf @@ -0,0 +1,6 @@ + + include t/included.conf + + + include t/included.conf + diff --git a/t/dual-include.conf b/t/dual-include.conf new file mode 100644 index 0000000..a608b7a --- /dev/null +++ b/t/dual-include.conf @@ -0,0 +1,6 @@ + + <> + + + <> + diff --git a/t/included.conf b/t/included.conf new file mode 100644 index 0000000..23e6b6c --- /dev/null +++ b/t/included.conf @@ -0,0 +1 @@ +honk=bonk diff --git a/t/run.t b/t/run.t index 21f9223..1e0eece 100644 --- a/t/run.t +++ b/t/run.t @@ -8,7 +8,7 @@ use Data::Dumper; -use Test::More tests => 35; +use Test::More tests => 38; #use Test::More qw(no_plan); ### 1 @@ -394,3 +394,32 @@ my %expect35 = ( 'var2' => 'beta' ); is_deeply(\%conf35, \%expect35, "Using -SplitPolicy and custom -SplitDelimiter"); + + + +### Include both +my $conf36 = Config::General->new( -ConfigFile => "t/dual-include.conf", + -IncludeAgain => 1 ); +my %C36 = $conf36->getall; +is_deeply( \%C36, { bit => { one => { honk=>'bonk' }, + two => { honk=>'bonk' } + } }, "Included twice" ); + + +### Include once +diag "\nPlease ignore the following message about IncludeAgain"; +my $conf37 = Config::General->new( "t/dual-include.conf" ); +my %C37 = $conf37->getall; +is_deeply( \%C37, { bit => { one => { honk=>'bonk' }, + two => {} + } }, "Included once-only" ); + + +### apache-style Include +my $conf38 = Config::General->new( -ConfigFile => "t/apache-include.conf", + -IncludeAgain => 1, + -UseApacheInclude => 1 ); +my %C38 = $conf38->getall; +is_deeply( \%C38, { bit => { one => { honk=>'bonk' }, + two => { honk=>'bonk' } + } }, "Apache-style include" );