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',
44 defined $ENV{CATALYST_RESTARTER}
45 ? $ENV{CATALYST_RESTARTER}
50 $subclass = 'Catalyst::Restarter::' . $subclass;
52 Catalyst::Utils::ensure_class_loaded($subclass);
61 delete $p->{start_sub};
63 $p->{filter} ||= qr/(?:\/|^)(?![.#_]).+(?:\.yml$|\.yaml$|\.conf|\.pm)$/;
65 my $app_root = abs_path( File::Spec->catdir( $FindBin::Bin, '..' ) );
67 # Monitor application root dir
68 $p->{directories} ||= $app_root;
70 # exclude t/, root/ and hidden dirs
72 File::Spec->catdir($app_root, 't'),
73 File::Spec->catdir($app_root, 'root'),
74 qr(/\.[^/]*/?$), # match hidden dirs
77 # keep filter regexp to make sure we don't restart on deleted
78 # files or directories where we can't check -d
79 $self->_filter( $p->{filter} );
81 # We could make this lazily, but this lets us check that we
82 # received valid arguments for the watcher up front.
83 $self->_watcher( File::ChangeNotify->instantiate_watcher( %{$p} ) );
89 $self->_fork_and_start;
91 return unless $self->_child;
93 $self->_restart_on_changes;
96 sub _restart_on_changes {
99 # We use this loop in order to avoid having _handle_events() call back
100 # into this method. We used to do that, and the end result was that stack
101 # traces became longer and longer with every restart. Using this loop, the
102 # portion of the stack trace that covers this code does not grow.
104 my @events = $self->_watcher->wait_for_events();
105 $self->_handle_events(@events);
114 # Filter out any events which are the creation / deletion of directories
115 # so that creating an empty directory won't cause a restart
116 for my $event (@events) {
117 my $path = $event->path();
118 my $type = $event->type();
119 if ( ( ( $type ne 'delete' && -f $path )
120 || ( $type eq 'delete' )
122 && ( $path =~ $self->_filter )
124 push @files, { path => $path, type => $type };
130 print STDERR "Saw changes to the following files:\n";
133 my $path = $f->{path};
134 my $type = $f->{type};
135 print STDERR " - $path ($type)\n";
139 print STDERR "Attempting to restart the server\n\n";
143 $self->_fork_and_start;
153 __PACKAGE__->meta->make_immutable;
161 Catalyst::Restarter - Uses File::ChangeNotify to check for changed files and restart the server
165 my $class = Catalyst::Restarter->pick_subclass;
167 my $restarter = $class->new(
168 directories => '/path/to/MyApp',
169 regex => '\.yml$|\.yaml$|\.conf|\.pm$',
170 start_sub => sub { ... }
173 $restarter->run_and_watch;
177 This is the base class for all restarters, and it also provide
178 functionality for picking an appropriate restarter subclass for a
181 This class uses L<File::ChangeNotify> to watch one or more directories
182 of files and restart the Catalyst server when any of those files
189 Returns the name of an appropriate subclass for the given platform.
191 =head2 new ( start_sub => sub { ... }, ... )
193 This method creates a new restarter object, but should be called on a
194 subclass, not this class.
196 The "start_sub" argument is required. This is a subroutine reference
197 that can be used to start the Catalyst server.
201 This method forks, starts the server in a child process, and then
202 watched for changed files in the parent. When files change, it kills
203 the child, forks again, and starts a new server.
207 L<Catalyst>, L<File::ChangeNotify>
211 Catalyst Contributors, see Catalyst.pm
215 This program is free software, you can redistribute it and/or modify
216 it under the same terms as Perl itself.