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