use strict;
use File::Dependencies;
my $d = File::Dependencies->new(Files=>['Import.cfg','Export.cfg']);
while (1) {
my (@changes) = $d->changed;
if (@changes) {
print "$_ was changed\n" for @changes;
$d->update();
};
sleep 60;
};
####
use strict;
use File::Dependencies;
my $files = File::Dependencies->new(Files=>[values %INC, $0]);
# We want to restart when any module was changed
exec $0, @ARGV if $files->changed();
##
##
package File::Dependencies;
#use 5.006; # shouldn't be necessary
use strict;
use warnings;
require Exporter;
our @ISA = qw(Exporter);
our $VERSION = '0.01';
sub new {
my ($class, %args) = @_;
my $method = $args{Method} || "MD5";
my $files = $args{Files} || [];
my $self = {
Defaultmethod => $method,
Files => {},
};
bless $self, $class;
$self->addfile($_) for @$files;
return $self;
};
sub adddependency {
my ($self,$filename,$method) = @_;
$method ||= $self->{Defaultmethod};
my $signatureclass = "Dependency::Signature::$method";
$self->{Files}->{$filename} = $signatureclass->new($filename);
};
sub addfile {
my ($self,@files) = @_;
$self->adddependency($_) for @files;
};
sub update {
my ($self) = @_;
$_->initialize() for values %{$self->{Files}};
};
sub changed {
my ($self) = @_;
return map {$_->{Filename}} grep {$_->changed()} (values %{$self->{Files}});
};
1;
{
package Dependency::Signature;
# This is a case where Python would be nicer. With Python, we could have (paraphrased)
# class Dependency::Signature;
# def initialize(self):
# self.hash = self.identificate()
# return self
# def signature(self):
# return MD5(self.filename)
# def changed(self):
# return self.hash != self.signature()
# and it would work as expected, (almost) regardless of the structure that is returned
# by self.signature(). This is some DWIMmery that I sometimes miss in Perl.
# For now, only string comparisions are allowed.
sub new {
my ($class,$filename) = @_;
my $self = {
Filename => $filename,
};
bless $self, $class;
$self->initialize();
return $self;
};
sub initialize {
my ($self) = @_;
$self->{Signature} = $self->signature();
return $self;
};
sub changed {
my ($self) = @_;
my $currsig = $self->signature();
# FIXME: Deep comparision of the two signatures instead of equality !
# And what's this about string comparisions anyway ?
if ((ref $currsig) or (ref $self->{Signature})) {
die "Implementation error in $self : changed() can't handle references (yet) !\n";
#return $currsig != $self->{Signature};
} else {
return $currsig ne $self->{Signature};
};
};
1;
};
{
package Dependency::Signature::mtime;
use base 'Dependency::Signature';
sub signature {
my ($self) = @_;
my @stat = stat $self->{Filename} or die "Couldn't stat '$self->{Filename}' : $!";
return $stat[9];
};
1;
};
{
package Dependency::Signature::MD5;
use base 'Dependency::Signature';
use vars qw( $fallback );
BEGIN {
eval "use Digest::MD5;";
if ($@) {
#print "Falling back on Dependency::Signature::mtime\n";
$fallback = 1;
};
};
# Fall back on simple mtime check unless MD5 is available :
sub new {
my ($class,$filename) = @_;
if ($fallback) {
return Dependency::Signature::mtime->new($filename);
} else {
return $class->SUPER::new($filename);
};
};
sub signature {
my ($self) = @_;
my $result;
if (-e $self->{Filename} and -r $self->{Filename}) {
local *F;
open F, $self->{Filename} or die "Couldn't read from file '$self->{Filename}' : $!";
$result = Digest::MD5->new()->addfile(*F)->b64digest();
close F;
};
return $result;
};
1;
};
1;
__END__
=head1 NAME
File::Dependencies - Perl extension for detection of changed files.
=head1 SYNOPSIS
use strict;
use File::Dependencies;
my $d = File::Dependencies->new(Files=>['Import.cfg','Export.cfg']);
while (1) {
my (@changes) = $d->changed;
if (@changes) {
print "$_ was changed\n" for @changes;
$d->update();
};
sleep 60;
};
Second example - a script that knows when any of its modules have changed :
use File::Dependencies;
my $files = File::Dependencies->new(Files=>[values %INC, $0]);
# We want to restart when any module was changed
exec $0, @ARGV if $files->changed();
=head1 DESCRIPTION
The Dependencies module is intended as a simple method for programs to detect
whether configuration files (or modules they rely on) have changed. There are
currently two methods of change detection implemented, C and C.
The C method will fall back to use timestamps if the C module
cannot be loaded.
=over 4
=item new %ARGS
Creates a new instance. The C<%ARGS> hash has two possible keys,
C, which denotes the method used for checking as default,
and C, which takes an array reference to the filenames to
watch.
=item adddependency filename, method
Adds a new file to watch. C is the method (or rather, the
subclass of C) to use to determine whether
a file has changed or not.
=item addfile LIST
Adds a list of files to watch. The method used for watching is t1he
default method as set in the constructor.
=item update
Updates all signatures to the current state. All pending changes
are discarded.
=item changed
Returns a list of the filenames whose files did change since
the construction or the last call to C (whichever last
occurred).
=back
=head2 Adding new methods for signatures
Adding a new signature method is as simple as creating a new subclass
of C. See C for a simple
example. There is one point of lazyness in the implementation of C,
the C method can only compare strings instead of arbitrary structures (yes,
there ARE things that are easier in Python than in Perl).
=head2 EXPORT
None by default.
=head1 AUTHOR
Max Maischein, Ecorion@informatik.uni-frankfurt.deE
=head1 SEE ALSO
L,L.
=cut
##
##
perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The
$d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider
($c = $d->accept())->get_request(); $c->send_response( new #in the
HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web