Rewrote restarter to use the soon-to-be-on-CPAN File::ChangeNotify
Dave Rolsky [Thu, 7 May 2009 23:06:08 +0000 (23:06 +0000)]
Makefile.PL
lib/Catalyst/Helper.pm
lib/Catalyst/Restarter.pm
lib/Catalyst/Watcher.pm [deleted file]
lib/Catalyst/Watcher/FileModified.pm [deleted file]
lib/Catalyst/Watcher/Inotify.pm [deleted file]

index 5e8acfd..067bc20 100644 (file)
@@ -9,6 +9,7 @@ requires 'Catalyst::Plugin::Static::Simple' => '0.16';
 requires 'Catalyst::Plugin::ConfigLoader';
 requires 'Class::Accessor::Fast';
 requires 'Config::General'; # as of 1.07, we use .conf and not .yaml
+requires 'File::ChangeNotify';
 requires 'File::Copy::Recursive';
 requires 'Module::Install' => '0.64';
 requires 'parent'; # as of 1.04
index 27accf4..34b2b72 100644 (file)
@@ -1034,9 +1034,9 @@ if ( $restart ) {
         if $follow_symlinks;
     $args{directories} = $watch_directory
         if defined $watch_directory;
-    $args{interval} = $check_interval
+    $args{sleep_interval} = $check_interval
         if defined $check_interval;
-    $args{regex} = qr/$file_regex/
+    $args{filter} = qr/$file_regex/
         if defined $file_regex;
 
     my $restarter = Catalyst::Restarter->new(
index e35731b..93dbfa7 100644 (file)
@@ -2,7 +2,7 @@ package Catalyst::Restarter;
 
 use Moose;
 
-use Catalyst::Watcher;
+use File::ChangeNotify;
 use namespace::clean -except => 'meta';
 
 has restart_sub => (
@@ -13,7 +13,7 @@ has restart_sub => (
 
 has _watcher => (
     is  => 'rw',
-    isa => 'Catalyst::Watcher',
+    isa => 'File::ChangeNotify::Watcher',
 );
 
 has _child => (
@@ -27,9 +27,11 @@ sub BUILD {
 
     delete $p->{restart_sub};
 
+    $p->{filter} ||= qr/(?:\/|^)(?!\.\#).+(?:\.yml$|\.yaml$|\.conf|\.pm)$/;
+
     # We could make this lazily, but this lets us check that we
     # received valid arguments for the watcher up front.
-    $self->_watcher( Catalyst::Watcher->instantiate_subclass( %{$p} ) );
+    $self->_watcher( File::ChangeNotify->instantiate_watcher( %{$p} ) );
 }
 
 sub run_and_watch {
@@ -56,16 +58,24 @@ sub _fork_and_start {
 sub _restart_on_changes {
     my $self = shift;
 
-    $self->_watcher->watch($self);
+    my @events = $self->_watcher->wait_for_events();
+    $self->_handle_events(@events);
 }
 
-sub handle_changes {
-    my $self  = shift;
-    my @files = @_;
+sub _handle_events {
+    my $self   = shift;
+    my @events = @_;
 
     print STDERR "\n";
     print STDERR "Saw changes to the following files:\n";
-    print STDERR " - $_->{file} ($_->{status})\n" for @files;
+
+    for my $event (@events) {
+        my $path = $event->path();
+        my $type = $event->type();
+
+        print STDERR " - $path ($type)\n";
+    }
+
     print STDERR "\n";
     print STDERR "Attempting to restart the server\n\n";
 
diff --git a/lib/Catalyst/Watcher.pm b/lib/Catalyst/Watcher.pm
deleted file mode 100644 (file)
index f267866..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-package Catalyst::Watcher;
-
-use Moose;
-use Moose::Util::TypeConstraints;
-
-use Cwd qw( abs_path );
-use File::Spec;
-use FindBin;
-use namespace::clean -except => 'meta';
-
-has regex => (
-    is      => 'ro',
-    isa     => 'RegexpRef',
-    default => sub { qr/(?:\/|^)(?!\.\#).+(?:\.yml|\.yaml|\.conf|\.pm)$/ },
-);
-
-my $dir = subtype
-       as 'Str'
-    => where { -d $_ }
-    => message { "$_ is not a valid directory" };
-
-my $array_of_dirs = subtype
-       as 'ArrayRef[Str]',
-    => where { map { -d } @{$_} }
-    => message { "@{$_} is not a list of valid directories" };
-
-coerce $array_of_dirs
-    => from $dir
-    => via { [ $_ ] };
-
-has directories => (
-    is      => 'ro',
-    isa     => $array_of_dirs,
-    default => sub { [ abs_path( File::Spec->catdir( $FindBin::Bin, '..' ) ) ] },
-    coerce  => 1,
-);
-
-has follow_symlinks => (
-    is      => 'ro',
-    isa     => 'Bool',
-    default => 0,
-);
-
-sub instantiate_subclass {
-    my $class = shift;
-
-    if ( eval { require Catalyst::Watcher::Inotify; 1; } ) {
-        return Catalyst::Watcher::Inotify->new(@_);
-    }
-    else {
-        die $@ if $@ && $@ !~ /Can't locate/;
-        require Catalyst::Watcher::FileModified;
-        return Catalyst::Watcher::FileModified->new(@_);
-    }
-}
-
-__PACKAGE__->meta->make_immutable;
-
-1;
diff --git a/lib/Catalyst/Watcher/FileModified.pm b/lib/Catalyst/Watcher/FileModified.pm
deleted file mode 100644 (file)
index 4a25874..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-package Catalyst::Watcher::FileModified;
-
-use Moose;
-
-use File::Find;
-use File::Modified;
-use File::Spec;
-use Time::HiRes qw/sleep/;
-use namespace::clean -except => 'meta';
-
-extends 'Catalyst::Watcher';
-
-has interval => (
-    is      => 'ro',
-    isa     => 'Int',
-    default => 1,
-);
-
-has _watched_files => (
-    is         => 'ro',
-    isa        => 'HashRef[Str]',
-    lazy_build => 1,
-    clearer    => '_clear_watched_files',
-);
-
-has _modified => (
-    is         => 'rw',
-    isa        => 'File::Modified',
-    lazy_build => 1,
-    clearer    => '_clear_modified',
-);
-
-
-sub _build__watched_files {
-    my $self = shift;
-
-    my $regex = $self->regex;
-
-    my %list;
-    finddepth(
-        {
-            wanted => sub {
-                my $path = File::Spec->rel2abs($File::Find::name);
-                return unless $path =~ /$regex/;
-                return unless -f $path;
-
-                $list{$path} = 1;
-
-                # also watch the directory for changes
-                my $cur_dir = File::Spec->rel2abs($File::Find::dir);
-                $cur_dir =~ s{/script/..}{};
-                $list{$cur_dir} = 1;
-            },
-            follow_fast => $self->follow_symlinks ? 1 : 0,
-            no_chdir    => 1
-        },
-        @{ $self->directories }
-    );
-
-    return \%list;
-}
-
-sub _build__modified {
-    my $self = shift;
-
-    return File::Modified->new(
-        method => 'mtime',
-        files  => [ keys %{ $self->_watched_files } ],
-    );
-}
-
-sub watch {
-    my $self      = shift;
-    my $restarter = shift;
-
-    while (1) {
-        sleep $self->interval if $self->interval > 0;
-
-        my @changes = $self->_changed_files;
-
-        next unless @changes;
-
-        $restarter->handle_changes(@changes);
-
-        last;
-    }
-}
-
-sub _changed_files {
-    my $self = shift;
-
-    my @changes;
-
-    eval {
-        @changes = map { { file => $_, status => 'modified' } }
-            grep { -f $_ } $self->_modified->changed;
-    };
-
-    if ($@) {
-        # File::Modified will die if a file is deleted.
-        die unless $@ =~ /stat '(.+)'/;
-
-        push @changes, {
-            file   => $1 || 'unknown file',
-            status => 'deleted',
-        };
-
-        $self->_clear_watched_files;
-        $self->_clear_modified;
-    }
-    else {
-        $self->_modified->update;
-
-        my $old_watch = $self->_watched_files;
-
-        $self->_clear_watched_files;
-
-        my $new_watch = $self->_watched_files;
-
-        my @new_files = grep { !defined $old_watch->{$_} }
-            grep {-f}
-            keys %{$new_watch};
-
-        if (@new_files) {
-            $self->_clear_modified;
-            push @changes, map { { file => $_, status => 'added' } } @new_files;
-        }
-    }
-
-    return @changes;
-}
-
-__PACKAGE__->meta->make_immutable;
-
-1;
-
-__END__
-
-=head1 NAME
-
-Catalyst::Watcher::FileModified - Watch for changed application files using File::Modified
-
-=head1 SYNOPSIS
-
-    my $watcher = Catalyst::Watcher::FileModified->new(
-        directories => '/path/to/MyApp',
-        regex       => '\.yml$|\.yaml$|\.conf|\.pm$',
-    );
-
-    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 find_changed_files
-
-Returns a list of files that have been added, deleted, or changed
-since the last time watch was called. Each element returned is a hash
-reference with two keys. The C<file> key contains the filename, and
-the C<status> key contains one of "modified", "added", or "deleted".
-
-=head1 SEE ALSO
-
-L<Catalyst>, L<Catalyst::Watcher>, L<Catalyst::Restarter>,
-<File::Modified>
-
-=head1 AUTHORS
-
-Catalyst Contributors, see Catalyst.pm
-
-=head1 COPYRIGHT
-
-This program is free software, you can redistribute it and/or modify
-it under the same terms as Perl itself.
-
-=cut
diff --git a/lib/Catalyst/Watcher/Inotify.pm b/lib/Catalyst/Watcher/Inotify.pm
deleted file mode 100644 (file)
index 3e4e61a..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-package Catalyst::Watcher::Inotify;
-
-use Moose;
-
-use File::Find;
-use Linux::Inotify2;
-use namespace::clean -except => 'meta';
-
-extends 'Catalyst::Watcher';
-
-has _inotify => (
-    is       => 'rw',
-    isa      => 'Linux::Inotify2',
-    default  => sub { Linux::Inotify2->new },
-    init_arg => undef,
-);
-
-has _mask => (
-    is         => 'rw',
-    isa        => 'Int',
-    lazy_build => 1,
-);
-
-sub BUILD {
-    my $self = shift;
-
-    # If this is done via a lazy_build then the call to
-    # ->_add_directory ends up causing endless recursion when it calls
-    # ->_inotify itself.
-    $self->_add_directory($_) for @{ $self->directories };
-
-    return $self;
-}
-
-sub watch {
-    my $self      = shift;
-    my $restarter = shift;
-
-    my @events = $self->_wait_for_events;
-
-    $restarter->handle_changes( map { $self->_event_to_change($_) } @events );
-
-    return;
-}
-
-sub _wait_for_events {
-    my $self = shift;
-
-    my $regex = $self->regex;
-
-    while (1) {
-        # This is a blocking read, so it will not return until
-        # something happens. The restarter will end up calling ->watch
-        # again after handling the changes.
-        my @events = $self->_inotify->read;
-
-        my @interesting;
-        for my $event (@events) {
-            if ( $event->IN_CREATE && $event->IN_ISDIR ) {
-                $self->_add_directory( $event->fullname );
-                push @interesting, $event;
-            }
-            elsif ( $event->IN_DELETE_SELF
-                    || $event->fullname =~ /$regex/ ) {
-                push @interesting, $event;
-            }
-        }
-
-        return @interesting if @interesting;
-    }
-}
-
-sub _build__mask {
-    my $self = shift;
-
-    my $mask = IN_MODIFY | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF;
-    $mask |= IN_DONT_FOLLOW unless $self->follow_symlinks;
-
-    return $mask;
-}
-
-sub _add_directory {
-    my $self = shift;
-    my $dir  = shift;
-
-    finddepth(
-        {
-            wanted => sub {
-                my $path = File::Spec->rel2abs($File::Find::name);
-                return unless -d $path;
-
-                $self->_inotify->watch( $path, $self->_mask );
-            },
-            follow_fast => $self->follow_symlinks ? 1 : 0,
-            no_chdir    => 1
-        },
-        $dir
-    );
-}
-
-sub _event_to_change {
-    my $self  = shift;
-    my $event = shift;
-
-    my %change = ( file => $event->fullname );
-    if ( $event->IN_CREATE ) {
-        $change{status} = 'added';
-    }
-    elsif ( $event->IN_MODIFY ) {
-        $change{status} = 'modified';
-    }
-    elsif ( $event->IN_DELETE ) {
-        $change{status} = 'deleted';
-    }
-    else {
-        $change{status} = 'containing directory modified';
-    }
-
-    return \%change;
-}
-
-__PACKAGE__->meta->make_immutable;
-
-1;
-
-__END__
-
-=head1 NAME
-
-Catalyst::Watcher - Watch for changed application files
-
-=head1 SYNOPSIS
-
-    my $watcher = Catalyst::Watcher->new(
-        directory => '/path/to/MyApp',
-        regex     => '\.yml$|\.yaml$|\.conf|\.pm$',
-        interval  => 3,
-    );
-
-    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 find_changed_files
-
-Returns a list of files that have been added, deleted, or changed
-since the last time watch was called. Each element returned is a hash
-reference with two keys. The C<file> key contains the filename, and
-the C<status> key contains one of "modified", "added", or "deleted".
-
-=head1 SEE ALSO
-
-L<Catalyst>, L<Catalyst::Restarter>, <File::Modified>
-
-=head1 AUTHORS
-
-Catalyst Contributors, see Catalyst.pm
-
-=head1 COPYRIGHT
-
-This program is free software, you can redistribute it and/or modify
-it under the same terms as Perl itself.
-
-=cut