Commit | Line | Data |
8462f41e |
1 | package Catalyst::Restarter; |
8462f41e |
2 | use Moose; |
3 | |
ffbcd711 |
4 | use Cwd qw( abs_path ); |
a13b99da |
5 | use File::ChangeNotify; |
ffbcd711 |
6 | use FindBin; |
cf042872 |
7 | use namespace::autoclean; |
8462f41e |
8 | |
b8e3feb1 |
9 | has start_sub => ( |
8462f41e |
10 | is => 'ro', |
11 | isa => 'CodeRef', |
12 | required => 1, |
13 | ); |
14 | |
15 | has _watcher => ( |
16 | is => 'rw', |
a13b99da |
17 | isa => 'File::ChangeNotify::Watcher', |
8462f41e |
18 | ); |
19 | |
20 | has _child => ( |
21 | is => 'rw', |
22 | isa => 'Int', |
23 | ); |
24 | |
2e9609df |
25 | sub pick_subclass { |
26 | my $class = shift; |
27 | |
28 | my $subclass; |
29 | $subclass = |
30 | defined $ENV{CATALYST_RESTARTER} |
31 | ? $ENV{CATALYST_RESTARTER} |
32 | : $^O eq 'MSWin32' |
33 | ? 'Win32' |
34 | : 'Forking'; |
35 | |
36 | $subclass = 'Catalyst::Restarter::' . $subclass; |
37 | |
38 | eval "use $subclass"; |
39 | die $@ if $@; |
40 | |
41 | return $subclass; |
42 | } |
43 | |
8462f41e |
44 | sub BUILD { |
45 | my $self = shift; |
46 | my $p = shift; |
47 | |
b8e3feb1 |
48 | delete $p->{start_sub}; |
8462f41e |
49 | |
a13b99da |
50 | $p->{filter} ||= qr/(?:\/|^)(?!\.\#).+(?:\.yml$|\.yaml$|\.conf|\.pm)$/; |
ffbcd711 |
51 | $p->{directories} ||= abs_path( File::Spec->catdir( $FindBin::Bin, '..' ) ); |
a13b99da |
52 | |
8462f41e |
53 | # We could make this lazily, but this lets us check that we |
54 | # received valid arguments for the watcher up front. |
a13b99da |
55 | $self->_watcher( File::ChangeNotify->instantiate_watcher( %{$p} ) ); |
8462f41e |
56 | } |
57 | |
58 | sub run_and_watch { |
59 | my $self = shift; |
60 | |
61 | $self->_fork_and_start; |
62 | |
63 | return unless $self->_child; |
64 | |
65 | $self->_restart_on_changes; |
66 | } |
67 | |
8462f41e |
68 | sub _restart_on_changes { |
69 | my $self = shift; |
70 | |
a13b99da |
71 | my @events = $self->_watcher->wait_for_events(); |
72 | $self->_handle_events(@events); |
7f564068 |
73 | } |
8462f41e |
74 | |
a13b99da |
75 | sub _handle_events { |
76 | my $self = shift; |
77 | my @events = @_; |
8462f41e |
78 | |
7f564068 |
79 | print STDERR "\n"; |
80 | print STDERR "Saw changes to the following files:\n"; |
a13b99da |
81 | |
82 | for my $event (@events) { |
83 | my $path = $event->path(); |
84 | my $type = $event->type(); |
85 | |
86 | print STDERR " - $path ($type)\n"; |
87 | } |
88 | |
7f564068 |
89 | print STDERR "\n"; |
90 | print STDERR "Attempting to restart the server\n\n"; |
8462f41e |
91 | |
7f564068 |
92 | $self->_kill_child; |
8462f41e |
93 | |
7f564068 |
94 | $self->_fork_and_start; |
8462f41e |
95 | |
7f564068 |
96 | $self->_restart_on_changes; |
8462f41e |
97 | } |
98 | |
02758cf8 |
99 | sub DEMOLISH { |
100 | my $self = shift; |
101 | |
102 | $self->_kill_child; |
103 | } |
104 | |
8462f41e |
105 | __PACKAGE__->meta->make_immutable; |
106 | |
107 | 1; |
83d2d4a4 |
108 | |
109 | __END__ |
110 | |
111 | =head1 NAME |
112 | |
b8e3feb1 |
113 | Catalyst::Restarter - Uses File::ChangeNotify to check for changed files and restart the server |
83d2d4a4 |
114 | |
115 | =head1 SYNOPSIS |
116 | |
36ff1319 |
117 | my $class = Catalyst::Restarter->pick_subclass; |
118 | |
119 | my $restarter = $class->new( |
b8e3feb1 |
120 | directories => '/path/to/MyApp', |
121 | regex => '\.yml$|\.yaml$|\.conf|\.pm$', |
122 | start_sub => sub { ... } |
83d2d4a4 |
123 | ); |
124 | |
b8e3feb1 |
125 | $restarter->run_and_watch; |
83d2d4a4 |
126 | |
127 | =head1 DESCRIPTION |
128 | |
36ff1319 |
129 | This is the base class for all restarters, and it also provide |
130 | functionality for picking an appropriate restarter subclass for a |
131 | given platform. |
132 | |
b8e3feb1 |
133 | This class uses L<File::ChangeNotify> to watch one or more directories |
134 | of files and restart the Catalyst server when any of those files |
135 | changes. |
83d2d4a4 |
136 | |
137 | =head1 METHODS |
138 | |
36ff1319 |
139 | =head2 pick_subclass |
140 | |
141 | Returns the name of an appropriate subclass for the given platform. |
142 | |
b8e3feb1 |
143 | =head2 new ( start_sub => sub { ... }, ... ) |
144 | |
36ff1319 |
145 | This method creates a new restarter object, but should be called on a |
146 | subclass, not this class. |
83d2d4a4 |
147 | |
b8e3feb1 |
148 | The "start_sub" argument is required. This is a subroutine reference |
149 | that can be used to start the Catalyst server. |
83d2d4a4 |
150 | |
b8e3feb1 |
151 | =head2 run_and_watch |
83d2d4a4 |
152 | |
b8e3feb1 |
153 | This method forks, starts the server in a child process, and then |
154 | watched for changed files in the parent. When files change, it kills |
155 | the child, forks again, and starts a new server. |
83d2d4a4 |
156 | |
157 | =head1 SEE ALSO |
158 | |
b8e3feb1 |
159 | L<Catalyst>, <File::ChangeNotify> |
83d2d4a4 |
160 | |
161 | =head1 AUTHORS |
162 | |
163 | Catalyst Contributors, see Catalyst.pm |
164 | |
165 | =head1 COPYRIGHT |
166 | |
167 | This program is free software, you can redistribute it and/or modify |
168 | it under the same terms as Perl itself. |
169 | |
170 | =cut |