Remove a useless newline
[catagits/Catalyst-Devel.git] / lib / Catalyst / Watcher / Inotify.pm
CommitLineData
7f564068 1package Catalyst::Watcher::Inotify;
2
3use Moose;
4
4b947012 5use File::Find;
7f564068 6use Linux::Inotify2;
7use namespace::clean -except => 'meta';
8
9extends 'Catalyst::Watcher';
10
11has _inotify => (
4b947012 12 is => 'rw',
13 isa => 'Linux::Inotify2',
14 default => sub { Linux::Inotify2->new },
15 init_arg => undef,
7f564068 16);
17
18has _mask => (
19 is => 'rw',
20 isa => 'Int',
21 lazy_build => 1,
22);
23
4b947012 24sub BUILD {
25 my $self = shift;
26
27 # If this is done via a lazy_build then the call to
28 # ->_add_directory ends up causing endless recursion when it calls
29 # ->_inotify itself.
30 $self->_add_directory($_) for @{ $self->directories };
31
32 return $self;
33}
34
7f564068 35sub watch {
36 my $self = shift;
37 my $restarter = shift;
38
39 my @events = $self->_wait_for_events;
40
41 $restarter->handle_changes( map { $self->_event_to_change($_) } @events );
42
43 return;
44}
45
46sub _wait_for_events {
47 my $self = shift;
48
4b947012 49 my $regex = $self->regex;
50
7f564068 51 while (1) {
52 # This is a blocking read, so it will not return until
53 # something happens. The restarter will end up calling ->watch
54 # again after handling the changes.
55 my @events = $self->_inotify->read;
56
57 my @interesting;
4b947012 58 for my $event (@events) {
59 if ( ( $event->IN_CREATE && $event->IN_ISDIR ) ) {
7f564068 60 $self->_add_directory( $event->fullname );
61 push @interesting, $event;
62 }
4b947012 63 elsif ( $event->IN_DELETE_SELF ) {
7f564068 64 $event->w->cancel;
65 push @interesting, $event;
66 }
4b947012 67 elsif ( $event->fullname =~ /$regex/ ) {
7f564068 68 push @interesting, $event;
69 }
70 }
71
72 return @interesting if @interesting;
73 }
74}
75
7f564068 76sub _build__mask {
77 my $self = shift;
78
79 my $mask = IN_MODIFY | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF;
80 $mask |= IN_DONT_FOLLOW unless $self->follow_symlinks;
81
82 return $mask;
83}
84
85sub _add_directory {
86 my $self = shift;
87 my $dir = shift;
88
89 finddepth(
90 {
91 wanted => sub {
92 my $path = File::Spec->rel2abs($File::Find::name);
93 return unless -d $path;
94
95 $self->_inotify->watch( $path, $self->_mask );
96 },
97 follow_fast => $self->follow_symlinks ? 1 : 0,
98 no_chdir => 1
99 },
4b947012 100 $dir
7f564068 101 );
102}
103
104sub _event_to_change {
105 my $self = shift;
106 my $event = shift;
107
4b947012 108 my %change = ( file => $event->fullname );
109 if ( $event->IN_CREATE ) {
7f564068 110 $change{status} = 'added';
111 }
4b947012 112 elsif ( $event->IN_MODIFY ) {
7f564068 113 $change{status} = 'modified';
114 }
4b947012 115 elsif ( $event->IN_DELETE ) {
7f564068 116 $change{status} = 'deleted';
117 }
118 else {
119 $change{status} = 'containing directory modified';
120 }
121
122 return \%change;
123}
124
125__PACKAGE__->meta->make_immutable;
126
1271;
128
129__END__
130
131=head1 NAME
132
133Catalyst::Watcher - Watch for changed application files
134
135=head1 SYNOPSIS
136
137 my $watcher = Catalyst::Watcher->new(
138 directory => '/path/to/MyApp',
139 regex => '\.yml$|\.yaml$|\.conf|\.pm$',
140 interval => 3,
141 );
142
143 while (1) {
144 my @changed_files = $watcher->watch();
145 }
146
147=head1 DESCRIPTION
148
149This class monitors a directory of files for changes made to any file
150matching a regular expression. It correctly handles new files added to the
151application as well as files that are deleted.
152
153=head1 METHODS
154
155=head2 new ( directory => $path [, regex => $regex, delay => $delay ] )
156
157Creates a new Watcher object.
158
159=head2 find_changed_files
160
161Returns a list of files that have been added, deleted, or changed
162since the last time watch was called. Each element returned is a hash
163reference with two keys. The C<file> key contains the filename, and
164the C<status> key contains one of "modified", "added", or "deleted".
165
166=head1 SEE ALSO
167
168L<Catalyst>, L<Catalyst::Restarter>, <File::Modified>
169
170=head1 AUTHORS
171
172Catalyst Contributors, see Catalyst.pm
173
174=head1 COPYRIGHT
175
176This program is free software, you can redistribute it and/or modify
177it under the same terms as Perl itself.
178
179=cut