X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst%2FEngine%2FHTTP%2FRestarter%2FWatcher.pm;h=ab0a1fc6945cff7b002cd78559c098533d8b6c50;hb=932d28e84f0aa267670f43866ba67ca38af2f2a4;hp=3062dc6f5ee7f6292eec0bdfe20501ef2f303f24;hpb=b5ecfcf07b8ffe7e9984f0279c8781ce51c6ac6a;p=catagits%2FCatalyst-Runtime.git diff --git a/lib/Catalyst/Engine/HTTP/Restarter/Watcher.pm b/lib/Catalyst/Engine/HTTP/Restarter/Watcher.pm index 3062dc6..ab0a1fc 100644 --- a/lib/Catalyst/Engine/HTTP/Restarter/Watcher.pm +++ b/lib/Catalyst/Engine/HTTP/Restarter/Watcher.pm @@ -1,44 +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 - 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 } ], ); } @@ -47,8 +45,10 @@ sub watch { my @changes; my @changed_files; + + my $delay = ( defined $self->delay ) ? $self->delay : 1; - sleep $self->delay || 1; + sleep $delay if $delay > 0; eval { @changes = $self->modified->changed }; if ($@) { @@ -100,7 +100,9 @@ sub watch { sub _index_directory { my $self = shift; - my $dir = $self->directory || die "No directory specified"; + my $dir = $self->directory; + die "No directory specified" if !$dir or ref($dir) && !@{$dir}; + my $regex = $self->regex || '\.pm$'; my %list; @@ -118,9 +120,10 @@ sub _index_directory { $cur_dir =~ s{/script/..}{}; $list{$cur_dir} = 1; }, + follow_fast => $self->follow_symlinks ? 1 : 0, no_chdir => 1 }, - $dir + ref $dir eq 'ARRAY' ? @{$dir} : $dir ); return \%list; } @@ -128,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'; @@ -136,6 +157,8 @@ sub _test { eval "require '$file'"; open STDERR, '>&', $olderr; + B::Hooks::OP::Check::StashChange::unregister($id) if $id; + return ($@) ? $@ : 0; } @@ -151,7 +174,7 @@ files my $watcher = Catalyst::Engine::HTTP::Restarter::Watcher->new( directory => '/path/to/MyApp', - regex => '\.yml$|\.yaml$|\.pm$', + regex => '\.yml$|\.yaml$|\.conf|\.pm$', delay => 1, ); @@ -176,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 is installed and +can be used to detect when files are compiled. This is used internally +to make the L metaclass of any class being reloaded immutable. + +If L 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, L, L =head1 AUTHORS -Sebastian Riedel, - -Andy Grundman, +Catalyst Contributors, see Catalyst.pm =head1 THANKS