1 package Catalyst::Restarter;
5 use Cwd qw( abs_path );
6 use File::ChangeNotify;
10 use namespace::clean -except => 'meta';
26 isa => 'File::ChangeNotify::Watcher',
27 clearer => '_clear_watcher',
45 defined $ENV{CATALYST_RESTARTER}
46 ? $ENV{CATALYST_RESTARTER}
51 $subclass = 'Catalyst::Restarter::' . $subclass;
53 Catalyst::Utils::ensure_class_loaded($subclass);
62 delete $p->{start_sub};
64 $p->{filter} ||= qr/(?:\/|^)(?![.#_]).+(?:\.yml$|\.yaml$|\.conf|\.pm)$/;
66 my $app_root = abs_path( File::Spec->catdir( $FindBin::Bin, '..' ) );
68 # Monitor application root dir
69 $p->{directories} ||= $app_root;
71 # exclude t/, root/ and hidden dirs
73 File::Spec->catdir($app_root, 't'),
74 File::Spec->catdir($app_root, 'root'),
75 qr(/\.[^/]*/?$), # match hidden dirs
78 # keep filter regexp to make sure we don't restart on deleted
79 # files or directories where we can't check -d
80 $self->_filter( $p->{filter} );
82 # We could make this lazily, but this lets us check that we
83 # received valid arguments for the watcher up front.
84 $self->_watcher( File::ChangeNotify->instantiate_watcher( %{$p} ) );
90 $self->_fork_and_start;
92 return unless $self->_child;
94 $self->_restart_on_changes;
97 sub _restart_on_changes {
100 # We use this loop in order to avoid having _handle_events() call back
101 # into this method. We used to do that, and the end result was that stack
102 # traces became longer and longer with every restart. Using this loop, the
103 # portion of the stack trace that covers this code does not grow.
105 my @events = $self->_watcher->wait_for_events();
106 $self->_handle_events(@events);
115 # Filter out any events which are the creation / deletion of directories
116 # so that creating an empty directory won't cause a restart
117 for my $event (@events) {
118 my $path = $event->path();
119 my $type = $event->type();
120 if ( ( ( $type ne 'delete' && -f $path )
121 || ( $type eq 'delete' )
123 && ( $path =~ $self->_filter )
125 push @files, { path => $path, type => $type };
131 print STDERR "Saw changes to the following files:\n";
134 my $path = $f->{path};
135 my $type = $f->{type};
136 print STDERR " - $path ($type)\n";
140 print STDERR "Attempting to restart the server\n\n";
144 $self->_fork_and_start;
154 __PACKAGE__->meta->make_immutable;
162 Catalyst::Restarter - Uses File::ChangeNotify to check for changed files and restart the server
166 my $class = Catalyst::Restarter->pick_subclass;
168 my $restarter = $class->new(
169 directories => '/path/to/MyApp',
170 regex => '\.yml$|\.yaml$|\.conf|\.pm$',
171 start_sub => sub { ... }
174 $restarter->run_and_watch;
178 This is the base class for all restarters, and it also provide
179 functionality for picking an appropriate restarter subclass for a
182 This class uses L<File::ChangeNotify> to watch one or more directories
183 of files and restart the Catalyst server when any of those files
190 Returns the name of an appropriate subclass for the given platform.
192 =head2 new ( start_sub => sub { ... }, ... )
194 This method creates a new restarter object, but should be called on a
195 subclass, not this class.
197 The "start_sub" argument is required. This is a subroutine reference
198 that can be used to start the Catalyst server.
202 This method forks, starts the server in a child process, and then
203 watched for changed files in the parent. When files change, it kills
204 the child, forks again, and starts a new server.
208 L<Catalyst>, L<File::ChangeNotify>
212 Catalyst Contributors, see Catalyst.pm
216 This program is free software, you can redistribute it and/or modify
217 it under the same terms as Perl itself.