Move killing the child into its own method and add a Win32-specific hack
[catagits/Catalyst-Devel.git] / lib / Catalyst / Restarter.pm
CommitLineData
8462f41e 1package Catalyst::Restarter;
2
3use Moose;
4
5use Catalyst::Watcher;
6use File::Spec;
7use FindBin;
8use namespace::clean -except => 'meta';
9
10has restart_sub => (
11 is => 'ro',
12 isa => 'CodeRef',
13 required => 1,
14);
15
16has _watcher => (
17 is => 'rw',
18 isa => 'Catalyst::Watcher',
19);
20
21has _child => (
22 is => 'rw',
23 isa => 'Int',
24);
25
26sub BUILD {
27 my $self = shift;
28 my $p = shift;
29
30 delete $p->{restart_sub};
31
32 # We could make this lazily, but this lets us check that we
33 # received valid arguments for the watcher up front.
34 $self->_watcher( Catalyst::Watcher->new( %{$p} ) );
35}
36
37sub run_and_watch {
38 my $self = shift;
39
40 $self->_fork_and_start;
41
42 return unless $self->_child;
43
44 $self->_restart_on_changes;
45}
46
47sub _fork_and_start {
48 my $self = shift;
49
50 if ( my $pid = fork ) {
51 $self->_child($pid);
52 }
53 else {
54 $self->restart_sub->();
55 }
56}
57
58sub _restart_on_changes {
59 my $self = shift;
60
61 my $watcher = $self->_watcher;
62
63 while (1) {
64 my @files = $watcher->find_changed_files
65 or next;
66
a82bd605 67 print STDERR "\n";
8462f41e 68 print STDERR "Saw changes to the following files:\n";
69 print STDERR " - $_->{file} ($_->{status})\n" for @files;
70 print STDERR "\n";
71 print STDERR "Attempting to restart the server\n\n";
72
02758cf8 73 $self->_kill_child;
8462f41e 74
75 $self->_fork_and_start;
76
77 return unless $self->_child;
78 }
79}
80
02758cf8 81sub _kill_child {
8462f41e 82 my $self = shift;
83
02758cf8 84 return unless $self->_child;
85
86 return unless kill 0, $self->_child;
87
88 local $SIG{CHLD} = 'IGNORE';
89 unless ( kill 'INT', $self->_child ) {
90 # The kill 0 thing does not work on Windows, but the restarter
91 # seems to work fine on Windows with this hack.
92 return if $^O eq 'MSWin32';
93 die "Cannot send INT signal to ", $self->_child, ": $!";
8462f41e 94 }
95}
96
02758cf8 97sub DEMOLISH {
98 my $self = shift;
99
100 $self->_kill_child;
101}
102
8462f41e 103__PACKAGE__->meta->make_immutable;
104
1051;
83d2d4a4 106
107__END__
108
109=head1 NAME
110
111Catalyst::Restarter - Uses Catalyst::Watcher to check for changed files and restart the server
112
113=head1 SYNOPSIS
114
115 my $watcher = Catalyst::Watcher->new(
116 directory => '/path/to/MyApp',
117 regex => '\.yml$|\.yaml$|\.conf|\.pm$',
118 interval => 3,
119 );
120
121 while (1) {
122 my @changed_files = $watcher->watch();
123 }
124
125=head1 DESCRIPTION
126
127This class monitors a directory of files for changes made to any file
128matching a regular expression. It correctly handles new files added to the
129application as well as files that are deleted.
130
131=head1 METHODS
132
133=head2 new ( directory => $path [, regex => $regex, delay => $delay ] )
134
135Creates a new Watcher object.
136
137=head2 find_changed_files
138
139Returns a list of files that have been added, deleted, or changed
140since the last time watch was called. Each element returned is a hash
141reference with two keys. The C<file> key contains the filename, and
142the C<status> key contains one of "modified", "added", or "deleted".
143
144=head1 SEE ALSO
145
146L<Catalyst>, L<Catalyst::Restarter>, <File::Modified>
147
148=head1 AUTHORS
149
150Catalyst Contributors, see Catalyst.pm
151
152=head1 COPYRIGHT
153
154This program is free software, you can redistribute it and/or modify
155it under the same terms as Perl itself.
156
157=cut