Cosmetic: removed trailing whitespace
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Engine / HTTP / Restarter / Watcher.pm
index 672ec08..8890646 100644 (file)
@@ -1,45 +1,42 @@
 package Catalyst::Engine::HTTP::Restarter::Watcher;
 
-use strict;
-use warnings;
-use base 'Class::Accessor::Fast';
+use Moose;
+with 'MooseX::Emulate::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
-      follow_symlinks
-      watch_list/
-);
-
-sub new {
-    my ( $class, %args ) = @_;
-
-    my $self = {%args};
-
-    bless $self, $class;
-
-    $self->_init;
-
-    return $self;
+use Moose::Util qw/find_meta/;
+use namespace::clean -except => 'meta';
+
+BEGIN {
+    # If we can detect stash changes, then we do magic
+    # to make their metaclass mutable (if they have one)
+    # so that restarting works as expected.
+    eval { require B::Hooks::OP::Check::StashChange; };
+    *DETECT_PACKAGE_COMPILATION = $@
+        ? sub () { 0 }
+        : sub () { 1 }
 }
 
-sub _init {
-    my $self = shift;
+has delay => (is => 'rw');
+has regex => (is => 'rw');
+has modified => (is => 'rw', builder => '_build_modified', lazy => 1);
+has directory => (is => 'rw');
+has watch_list => (is => 'rw', builder => '_build_watch_list', lazy => 1);
+has follow_symlinks => (is => 'rw');
 
-    my $watch_list = $self->_index_directory;
-    $self->watch_list($watch_list);
+sub _build_watch_list {
+    my ($self) = @_;
+    return $self->_index_directory;
+}
 
-    $self->modified(
-        File::Modified->new(
-            method => 'mtime',
-            files  => [ keys %{$watch_list} ],
-        )
+sub _build_modified {
+    my ($self) = @_;
+    return File::Modified->new(
+        method => 'mtime',
+        files  => [ keys %{ $self->watch_list } ],
     );
 }
 
@@ -48,7 +45,7 @@ sub watch {
 
     my @changes;
     my @changed_files;
-    
+
     my $delay = ( defined $self->delay ) ? $self->delay : 1;
 
     sleep $delay if $delay > 0;
@@ -134,7 +131,25 @@ sub _index_directory {
 sub _test {
     my ( $self, $file ) = @_;
 
-    delete $INC{$file};
+    my $id;
+    if (DETECT_PACKAGE_COMPILATION) {
+        $id = B::Hooks::OP::Check::StashChange::register(sub {
+            my ($new, $old) = @_;
+            my $meta = find_meta($new);
+            if ($meta) { # A little paranoia here - Moose::Meta::Role has neither of these methods.
+                my $is_immutable = $meta->can('is_immutable');
+                my $make_mutable = $meta->can('make_mutable');
+                $meta->$make_mutable() if $is_immutable && $make_mutable && $meta->$is_immutable();
+                eval { # Do not explode the watcher process if this fails.
+                    my $superclasses = $meta->can('superclasses');
+                    $meta->$superclasses('Moose::Object') if $superclasses;
+                };
+            }
+        });
+    }
+
+    local $Catalyst::__AM_RESTARTING = 1; # Hack to avoid C3 fail
+    delete $INC{$file}; # Remove from %INC so it will reload
     local $SIG{__WARN__} = sub { };
 
     open my $olderr, '>&STDERR';
@@ -142,6 +157,8 @@ sub _test {
     eval "require '$file'";
     open STDERR, '>&', $olderr;
 
+    B::Hooks::OP::Check::StashChange::unregister($id) if $id;
+
     return ($@) ? $@ : 0;
 }
 
@@ -160,7 +177,7 @@ files
         regex     => '\.yml$|\.yaml$|\.conf|\.pm$',
         delay     => 1,
     );
-    
+
     while (1) {
         my @changed_files = $watcher->watch();
     }
@@ -182,15 +199,24 @@ Creates a new Watcher object.
 Returns a list of files that have been added, deleted, or changed since the
 last time watch was called.
 
+=head2 DETECT_PACKAGE_COMPILATION
+
+Returns true if L<B::Hooks::OP::Check::StashChange> is installed and
+can be used to detect when files are compiled. This is used internally
+to make the L<Moose> metaclass of any class being reloaded immutable.
+
+If L<B::Hooks::OP::Check::StashChange> is not installed, then the
+restarter makes all application components immutable. This covers the
+simple case, but is less useful if you're using Moose in components
+outside Catalyst's namespaces, but inside your application directory.
+
 =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>
+Catalyst Contributors, see Catalyst.pm
 
 =head1 THANKS
 
@@ -198,7 +224,7 @@ 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
+This library is free software. You can redistribute it and/or modify it under
 the same terms as Perl itself.
 
 =cut