--- /dev/null
+package Catalyst::Engine::HTTP::Restarter::Watcher;
+
+use strict;
+use warnings;
+use base 'Class::Accessor::Fast';
+use File::Find;
+use File::Modified;
+use File::Spec;
+use Time::HiRes qw/sleep/;
+
+__PACKAGE__->mk_accessors( qw/delay
+ directory
+ modified
+ regex
+ watch_list/ );
+
+sub new {
+ my ( $class, %args ) = @_;
+
+ my $self = { %args };
+
+ bless $self, $class;
+
+ $self->_init;
+
+ return $self;
+}
+
+sub _init {
+ my $self = shift;
+
+ my $watch_list = $self->_index_directory;
+ $self->watch_list( $watch_list );
+
+ $self->modified(
+ File::Modified->new(
+ method => 'mtime',
+ files => [ keys %{$watch_list} ],
+ )
+ );
+}
+
+sub watch {
+ my $self = shift;
+
+ my @changes;
+ my @changed_files;
+
+ sleep $self->delay || 1;
+
+ eval { @changes = $self->modified->changed };
+ if ( $@ ) {
+ # File::Modified will die if a file is deleted.
+ my ($deleted_file) = $@ =~ /stat '(.+)'/;
+ push @changed_files, $deleted_file || 'unknown file';
+ }
+
+ if ( @changes ) {
+ # update all mtime information
+ $self->modified->update;
+
+ # check if any files were changed
+ @changed_files = grep { -f $_ } @changes;
+
+ # Check if only directories were changed. This means
+ # a new file was created.
+ unless ( @changed_files ) {
+ # re-index to find new files
+ my $new_watch = $self->_index_directory;
+
+ # look through the new list for new files
+ my $old_watch = $self->watch_list;
+ @changed_files = grep { ! defined $old_watch->{$_} }
+ keys %{ $new_watch };
+
+ return unless @changed_files;
+ }
+
+ # Test modified pm's
+ for my $file ( @changed_files ) {
+ next unless $file =~ /\.pm$/;
+ if ( my $error = $self->_test($file) ) {
+ print STDERR
+ qq/File "$file" modified, not restarting\n\n/;
+ print STDERR '*' x 80, "\n";
+ print STDERR $error;
+ print STDERR '*' x 80, "\n";
+ return;
+ }
+ }
+ }
+
+ return @changed_files;
+}
+
+sub _index_directory {
+ my $self = shift;
+
+ my $dir = $self->directory || die "No directory specified";
+ my $regex = $self->regex || '\.pm$';
+ my %list;
+
+ finddepth(
+ {
+ wanted => sub {
+ my $file = File::Spec->rel2abs($File::Find::name);
+ return unless $file =~ /$regex/;
+ return unless -f $file;
+ $file =~ s{/script/..}{};
+ $list{$file} = 1;
+
+ # also watch the directory for changes
+ my $cur_dir = File::Spec->rel2abs($File::Find::dir);
+ $cur_dir =~ s{/script/..}{};
+ $list{$cur_dir} = 1;
+ },
+ no_chdir => 1
+ },
+ $dir
+ );
+ return \%list;
+}
+
+sub _test {
+ my ( $self, $file ) = @_;
+
+ delete $INC{$file};
+ local $SIG{__WARN__} = sub { };
+
+ open my $olderr, '>&STDERR';
+ open STDERR, '>', File::Spec->devnull;
+ eval "require '$file'";
+ open STDERR, '>&', $olderr;
+
+ return ($@) ? $@ : 0;
+}
+
+1;
+__END__
+
+=head1 NAME
+
+Catalyst::Engine::HTTP::Restarter::Watcher - Watch for changed application
+files
+
+=head1 SYNOPSIS
+
+ my $watcher = Catalyst::Engine::HTTP::Restarter::Watcher->new(
+ directory => '/path/to/MyApp',
+ regex => '\.yml$|\.yaml$|\.pm$',
+ delay => 1,
+ );
+
+ while (1) {
+ my @changed_files = $watcher->watch();
+ }
+
+=head1 DESCRIPTION
+
+This class monitors a directory of files for changes made to any file
+matching a regular expression. It correctly handles new files added to the
+application as well as files that are deleted.
+
+=head1 METHODS
+
+=head2 new ( directory => $path [, regex => $regex, delay => $delay ] )
+
+Creates a new Watcher object.
+
+=head2 watch
+
+Returns a list of files that have been added, deleted, or changed since the
+last time watch was called.
+
+=head1 SEE ALSO
+
+L<Catalyst>, L<Catalyst::Engine::HTTP::Restarter>, L<File::Modified>
+
+=head1 AUTHORS
+
+Sebastian Riedel, <sri@cpan.org>
+
+Andy Grundman, <andy@hybridized.org>
+
+=head1 THANKS
+
+Many parts are ripped out of C<HTTP::Server::Simple> by Jesse Vincent.
+
+=head1 COPYRIGHT
+
+This program is free software, you can redistribute it and/or modify it under
+the same terms as Perl itself.
+
+=cut