File Coverage

blib/lib/Plack/Loader/Restarter.pm
Criterion Covered Total %
statement 21 62 33.8
branch 2 16 12.5
condition 6 6 100.0
subroutine 7 14 50.0
pod 0 5 0.0
total 36 103 34.9


line stmt bran cond sub pod time code
1             package Plack::Loader::Restarter;
2 1     1   449 use strict;
  1         8  
  1         30  
3 1     1   5 use warnings;
  1         2  
  1         28  
4 1     1   455 use parent qw(Plack::Loader);
  1         365  
  1         6  
5 1     1   46 use Plack::Util;
  1         2  
  1         20  
6 1     1   5 use Try::Tiny;
  1         4  
  1         709  
7              
8             sub new {
9 1     1 0 139 my($class, $runner) = @_;
10 1         6 bless { watch => [] }, $class;
11             }
12              
13             sub preload_app {
14 0     0 0 0 my($self, $builder) = @_;
15 0         0 $self->{builder} = $builder;
16             }
17              
18             sub watch {
19 0     0 0 0 my($self, @dir) = @_;
20 0         0 push @{$self->{watch}}, @dir;
  0         0  
21             }
22              
23             sub _fork_and_start {
24 0     0   0 my($self, $server) = @_;
25              
26 0         0 delete $self->{pid}; # re-init in case it's a restart
27              
28 0         0 my $pid = fork;
29 0 0       0 die "Can't fork: $!" unless defined $pid;
30              
31 0 0       0 if ($pid == 0) { # child
32 0         0 return $server->run($self->{builder}->());
33             } else {
34 0         0 $self->{pid} = $pid;
35             }
36             }
37              
38             sub _kill_child {
39 0     0   0 my $self = shift;
40              
41 0 0       0 my $pid = $self->{pid} or return;
42 0         0 warn "Killing the existing server (pid:$pid)\n";
43 0         0 kill 'TERM' => $pid;
44 0         0 waitpid($pid, 0);
45             }
46              
47             sub valid_file {
48 23     23 0 5870 my($self, $file) = @_;
49              
50             # vim temporary file is 4913 to 5036
51             # http://www.mail-archive.com/vim_dev@googlegroups.com/msg07518.html
52 23 100 100     133 if ( $file->{path} =~ m{(\d+)$} && $1 >= 4913 && $1 <= 5036) {
      100        
53 2         10 return 0;
54             }
55 21         156 $file->{path} !~ m!^\.(?:git|svn)[/\\]|\.(?:bak|swp|swpx|swx)$|~$|_flymake\.p[lm]$|\.#!;
56             }
57              
58             sub run {
59 0     0 0   my($self, $server) = @_;
60              
61 0           $self->_fork_and_start($server);
62 0 0         return unless $self->{pid};
63              
64 0           require Filesys::Notify::Simple;
65 0           my $watcher = Filesys::Notify::Simple->new($self->{watch});
66 0           warn "Watching @{$self->{watch}} for file updates.\n";
  0            
67 0     0     local $SIG{TERM} = sub { $self->_kill_child; exit(0); };
  0            
  0            
68              
69 0           while (1) {
70 0           my @restart;
71              
72             # this is blocking
73             $watcher->wait(sub {
74 0     0     my @events = @_;
75 0           @events = grep $self->valid_file($_), @events;
76 0 0         return unless @events;
77              
78 0           @restart = @events;
79 0           });
80              
81 0 0         next unless @restart;
82              
83 0           for my $ev (@restart) {
84 0           warn "-- $ev->{path} updated.\n";
85             }
86              
87 0           $self->_kill_child;
88 0           warn "Successfully killed! Restarting the new server process.\n";
89 0           $self->_fork_and_start($server);
90 0 0         return unless $self->{pid};
91             }
92             }
93              
94             1;
95              
96             __END__