package Apache::StatINC;
use strict;

$Apache::StatINC::VERSION = "1.07";

my %Stat = ($INC{"Apache/StatINC.pm"} => time);

sub handler {
    my $r = shift;
    my $do_undef = ref($r) && ((lc($r->dir_config("StatINC_UndefOnReload") ||
				   $r->dir_config("UndefOnReload")) || '') eq "on");
    my $DEBUG = ref($r) && (lc($r->dir_config("StatINCDebug") || '') eq "on");
    $DEBUG = $r->dir_config("StatINC_Debug") if ref($r) && $r->dir_config("StatINC_Debug");

    while(my($key,$file) = each %INC) {
	local $^W = 0;
	my $mtime = (stat $file)[9];
	# warn and skip the files with relative paths which can't be locate by applying @INC;
	warn("Apache::StatINC: Can't locate $file\n"),next unless defined $mtime and $mtime;
	unless(defined $Stat{$file}) { 
	    $Stat{$file} = $^T;
	}
        # if modified, reload the module
	if($mtime > $Stat{$file}) {
	    # make sure file's prefix is in @INC
	    my $found_in_inc;
	    for (@INC) {
	       if(index($file,$_) == 0) {
	          $found_in_inc = 1;
	          last;
	       }
	    }

            if(!$found_in_inc) {
               my $inc_dir = substr($file, 0, length($file)-length($key)-1);
               push @INC, $inc_dir;
	       warn "Apache::StatINC: process $$ adding $inc_dir to \@INC\n"
                   if $DEBUG > 0;
            }

	    if($do_undef and $key =~ /\.pm$/) {
		require Apache::Symbol;
		my $class = Apache::Symbol::file2class($key);
		$class->Apache::Symbol::undef_functions( undef, 1 );
	    }
	    delete $INC{$key};
	    eval{ require $key };
	    if ($@) {
               warn "Apache::StatINC: process $$ failed to reload $key. $@"
                  if $DEBUG > 0;
	    } else {
	       warn "Apache::StatINC: process $$ reloading $key.\n"
                  if $DEBUG > 0;
            }
	}
	$Stat{$file} = $mtime;
    }
    
    return 1;
}

1;

__END__

=head1 NAME

Apache::StatINC - Reload %INC files when updated on disk

=head1 SYNOPSIS

  #httpd.conf or some such
  #can be any Perl*Handler
  PerlInitHandler Apache::StatINC

=head1 DESCRIPTION

When Perl pulls a file via C<require>, it stores the filename in the
global hash C<%INC>.  The next time Perl tries to C<require> the same
file, it sees the file in C<%INC> and does not reload from disk.  This
module's handler iterates over C<%INC> and reloads the file if it has
changed on disk. 

Note that StatINC operates on the current context of C<@INC>.  
Which means, when called as a Perl*Handler it will not see C<@INC> paths
added or removed by Apache::Registry scripts, as the value of C<@INC> is
saved on server startup and restored to that value after each request.
In other words, if you want StatINC to work with modules that live in custom
C<@INC> paths, you should modify C<@INC> when the server is started.
Besides, 'use lib' in startup scripts, you can also set the B<PERL5LIB>
variable in the httpd's environment to include any non-standard 'lib' 
directories that you choose.  For example, you might use a
script called 'start_httpd' to start apache, and include a line like this:

        PERL5LIB=/usr/local/foo/myperllibs; export PERL5LIB

When you have problems with modules not being reloaded, please refer
to the following lines in 'perlmodlib':

"Always use B<-w>. Try to C<use strict;> (or C<use strict qw(...);>). 
Remember that you can add C<no strict qw(...);> to individual blocks 
of code that need less strictness. Always use B<-w>. Always use B<-w>! 
Follow the guidelines in the perlstyle(1) manual." 

Warnings when running under mod_perl is enabled with 'PerlWarn On' in
your httpd.conf.

It will most likely help you to find the problem. Really.

=head1 OPTIONS

=over 4

=item StatINC_UndefOnReload

Normally, StatINC will turn of warnings to avoid "Subroutine redefined" 
warnings when it reloads a file.  However, this does not disable the 
Perl mandatory warning when re-defining C<constant> subroutines 
(see perldoc perlsub).  With this option On, StatINC will invoke the 
B<Apache::Symbol> I<undef_functions> method to avoid these mandatory
warnings:

 PerlSetVar StatINC_UndefOnReload On

=item StatINC_Debug

You can make StatINC tell when it reloads a module by setting this
option to on.

 PerlSetVar StatINC_Debug 1

The only used debug level is currently 1. 

=back

=head1 SEE ALSO

mod_perl(3)

=head1 AUTHOR

Currently maintained by Ask Bjoern Hansen <ask@netcetera.dk>.
Written by Doug MacEachern.


