# This file documents the revision history for Perl extension Catalyst.
- - Naive implementation of making packages mutable before restarting so
- that restarter works with native Moose apps using immutable (t0m)
+ - Non-naive implementation of making mutable on restart using
+ B::Hooks::OP::Check::StashChange if installed (t0m)
+ - Tests for this (t0m)
+ - Naive implementation of making all components mutable in the
+ forked restart watcher process so native Moose apps using
+ immutable restart correctly. (t0m)
- Tests for this (t0m)
- Bump Moose dependency to 0.70 so that we avoid nasty surprises
with is_class_loaded and perl 5.80 when you Moosify MyApp.pm (t0m)
requires 'Text::Balanced'; # core in 5.8.x but mentioned for completeness
requires 'MRO::Compat';
+recommends 'B::Hooks::OP::Check::StashChange';
+
test_requires 'Class::Data::Inheritable';
test_requires 'Test::MockObject';
use File::Modified;
use File::Spec;
use Time::HiRes qw/sleep/;
+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 }
+}
has delay => (is => 'rw');
has regex => (is => 'rw');
has watch_list => (is => 'rw');
has follow_symlinks => (is => 'rw');
-no Moose;
-
sub BUILD {
- shift->_init;
+ shift->_init;
}
sub _init {
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) {
+ $meta->make_mutable if $meta->is_immutable;
+ }
+ });
+ }
+
+ delete $INC{$file}; # Remove from %INC so it will reload
local $SIG{__WARN__} = sub { };
open my $olderr, '>&STDERR';
eval "require '$file'";
open STDERR, '>&', $olderr;
+ B::Hooks::OP::Check::StashChange::unregister($id) if $id;
+
return ($@) ? $@ : 0;
}
--- /dev/null
+package TestApp::Controller::Immutable::HardToReload;
+use Moose;
+BEGIN { extends 'Catalyst::Controller' }
+no Moose;
+__PACKAGE__->meta->make_immutable;
+
+package # Standard PAUSE hiding technique
+ TestApp::Controller::Immutable::HardToReload::PAUSEHide;
+use Moose;
+BEGIN { extends 'Catalyst::Controller' }
+no Moose;
+__PACKAGE__->meta->make_immutable;
+
+# Not an inner package
+package TestApp::Controller::Immutable2;
+use Moose;
+BEGIN { extends 'Catalyst::Controller' }
+no Moose;
+__PACKAGE__->meta->make_immutable;
+
+# Not even in the app namespace
+package Frobnitz;
+use Moose;
+BEGIN { extends 'Catalyst::Controller' }
+no Moose;
+__PACKAGE__->meta->make_immutable;
use LWP::Simple;
use IO::Socket;
use IPC::Open3;
+use Catalyst::Engine::HTTP::Restarter::Watcher;
use Time::HiRes qw/sleep/;
eval "use Catalyst::Devel 1.0;";
"$FindBin::Bin/../t/tmp/TestApp/lib/TestApp/Controller/Immutable.pm",
);
+push(@files, "$FindBin::Bin/../t/tmp/TestApp/lib/TestApp/Controller/Immutable/HardToReload.pm")
+ if Catalyst::Engine::HTTP::Restarter::Watcher::DETECT_PACKAGE_COMPILATION();
+
# change some files and make sure the server restarts itself
NON_ERROR_RESTART:
for ( 1 .. 20 ) {