1 package Catalyst::Restarter;
5 use Cwd qw( abs_path );
6 use File::ChangeNotify;
9 use Catalyst::Utils qw/ ensure_class_loaded /;
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 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' && $path =~ $self->_filter ) )
122 push @files, { path => $path, type => $type };
128 print STDERR "Saw changes to the following files:\n";
131 my $path = $f->{path};
132 my $type = $f->{type};
133 print STDERR " - $path ($type)\n";
137 print STDERR "Attempting to restart the server\n\n";
141 $self->_fork_and_start;
151 __PACKAGE__->meta->make_immutable;
159 Catalyst::Restarter - Uses File::ChangeNotify to check for changed files and restart the server
163 my $class = Catalyst::Restarter->pick_subclass;
165 my $restarter = $class->new(
166 directories => '/path/to/MyApp',
167 regex => '\.yml$|\.yaml$|\.conf|\.pm$',
168 start_sub => sub { ... }
171 $restarter->run_and_watch;
175 This is the base class for all restarters, and it also provide
176 functionality for picking an appropriate restarter subclass for a
179 This class uses L<File::ChangeNotify> to watch one or more directories
180 of files and restart the Catalyst server when any of those files
187 Returns the name of an appropriate subclass for the given platform.
189 =head2 new ( start_sub => sub { ... }, ... )
191 This method creates a new restarter object, but should be called on a
192 subclass, not this class.
194 The "start_sub" argument is required. This is a subroutine reference
195 that can be used to start the Catalyst server.
199 This method forks, starts the server in a child process, and then
200 watched for changed files in the parent. When files change, it kills
201 the child, forks again, and starts a new server.
205 L<Catalyst>, L<File::ChangeNotify>
209 Catalyst Contributors, see Catalyst.pm
213 This program is free software, you can redistribute it and/or modify
214 it under the same terms as Perl itself.