File Coverage

blib/lib/App/watchdo.pm
Criterion Covered Total %
statement 33 83 39.7
branch 0 12 0.0
condition 0 6 0.0
subroutine 11 19 57.8
pod 4 4 100.0
total 48 124 38.7


line stmt bran cond sub pod time code
1             package App::watchdo;
2              
3             # Created on: 2015-03-07 08:21:28
4             # Create by: Ivan Wills
5             # $Id$
6             # $Revision$, $HeadURL$, $Date$
7             # $Revision$, $Source$, $Date$
8              
9 1     1   75538 use Moo;
  1         8253  
  1         3  
10 1     1   971 use warnings;
  1         2  
  1         22  
11 1     1   243 use version;
  1         1361  
  1         5  
12 1     1   61 use Carp;
  1         2  
  1         46  
13 1     1   318 use List::MoreUtils qw/uniq/;
  1         9195  
  1         7  
14 1     1   1144 use Data::Dumper qw/Dumper/;
  1         4997  
  1         74  
15 1     1   284 use English qw/ -no_match_vars /;
  1         2543  
  1         5  
16 1     1   1052 use AnyEvent;
  1         3955  
  1         44  
17 1     1   296 use AnyEvent::Loop;
  1         10616  
  1         31  
18 1     1   294 use AnyEvent::Filesys::Notify;
  1         136513  
  1         32  
19 1     1   526 use Path::Tiny;
  1         8129  
  1         650  
20              
21             our $VERSION = version->new('0.0.7');
22              
23             has [qw/dirs files git run done/] => ( is => 'rw' );
24             has changed => (
25             is => 'rw',
26             default => sub {[]},
27             );
28             has wait => (
29             is => 'rw',
30             default => 1,
31             );
32             has vcs => (
33             is => 'rw',
34             lazy => 1,
35             default => sub {
36             require VCS::Which;
37             return VCS::Which->new;
38             },
39             );
40              
41             sub watch {
42 0     0 1   my ($self) = @_;
43              
44             my $notify = AnyEvent::Filesys::Notify->new(
45             dirs => [ $self->get_dirs ],
46             cb => sub {
47 0     0     my @changed = @_;
48 0           $self->changed([ @{ $self->changed }, @changed ]);
  0            
49              
50 0 0         if ( ! $self->done ) {
51 0           $self->done( AE::timer $self->wait, 0, sub { $self->doit() } );
  0            
52             }
53             },
54 0           parse_events => 1,
55             );
56              
57 0           return AnyEvent::Loop::run();
58             }
59              
60             sub doit {
61 0     0 1   my ($self) = @_;
62 0           my %files = map { $_ => 1 } $self->get_files();
  0            
63 0           my %dirs = map { $_ => 1 } @{ $self->dirs() };
  0            
  0            
64 0           my %seen;
65              
66             my @monitored;
67 0           for my $changed (@{ $self->changed() }) {
  0            
68 0           my $path = $changed->path;
69 0 0 0       push @monitored, $changed if !$seen{$path}++ || $files{$path} || $dirs{$path};
      0        
70             }
71              
72 0           $self->run()->(@monitored);
73 0           $self->done(undef);
74 0           $self->changed([]);
75             }
76              
77             sub get_dirs {
78 0     0 1   my ($self) = @_;
79              
80             return uniq sort +(
81 0 0         @{ $self->dirs || [] },
82 0           map {path($_)->parent . ''}
  0            
83             $self->get_files,
84             );
85             }
86              
87             sub get_files {
88 0     0 1   my ($self) = @_;
89              
90 0           return ( $self->_files_from_fs, $self->_files_from_git );
91             }
92              
93             sub _files_from_fs {
94 0     0     my ($self) = @_;
95              
96 0 0         return map { -d $_ ? _recurse($_) : $_ }
97 0           @{ $self->files };
  0            
98             }
99              
100             sub _files_from_git {
101 0     0     my ($self) = @_;
102              
103 0 0         return if !$self->git;
104              
105 0           my $status = $self->vcs->status('.');
106             return (
107 0           map { chomp $_; $_ } ## no critic
  0            
108 0           map { @{ $status->{$_} } }
  0            
109 0           grep { $_ ne 'merge' }
110 0           keys %{ $status }
  0            
111             );
112             }
113              
114             sub _recurse {
115 0     0     my $dir = path(shift);
116 0           my @files;
117              
118 0           for my $child ($dir->children) {
119 0 0         if (-d $child) {
120 0           push @files, _recurse($child);
121             }
122             else {
123 0           push @files, $child;
124             }
125             }
126              
127 0           return @files;
128             }
129              
130             1;
131              
132             __DATA__
133              
134             =head1 NAME
135              
136             App::watchdo - Run a command when watched files change
137              
138             =head1 VERSION
139              
140             This documentation refers to App::watchdo version 0.0.7
141              
142             =head1 SYNOPSIS
143              
144             watch-do [option]
145             watch-do -w file1 [-w file2 ...] [--] cmd
146              
147             OPTIONS:
148             cmd Command to run when file changes
149             -w --watch[=]file File to be watched for changes
150             -g --git Use git to find what to watch (ie monitor files that git see have changed)
151              
152             -v --verbose Show more detailed option
153             --version Prints the version information
154             --help Prints this help information
155             --man Prints the full documentation for watch-do
156              
157             =head1 DESCRIPTION
158              
159             =head1 SUBROUTINES/METHODS
160              
161             =over 4
162              
163             =item C<doit ()>
164              
165             Runs the requested command when a file has changed
166              
167             =item C<get_dirs ()>
168              
169             Gets the unique list of directories to look in
170              
171             =item C<get_files ()>
172              
173             Gets all the files to be watched
174              
175             =item C<watch ()>
176              
177             Runs the event loop to watch for changes in files.
178              
179             =back
180              
181             =head1 ATTRIBUTES
182              
183             =over 4
184              
185             =item C<changed ()>
186              
187             =item C<done ()>
188              
189             =item C<dirs ()>
190              
191             =item C<files ()>
192              
193             =item C<git ()>
194              
195             =item C<run ()>
196              
197             =item C<wait ()>
198              
199             =back
200              
201             =head1 DIAGNOSTICS
202              
203             =head1 CONFIGURATION AND ENVIRONMENT
204              
205             =head1 DEPENDENCIES
206              
207             =head1 INCOMPATIBILITIES
208              
209             =head1 BUGS AND LIMITATIONS
210              
211             There are no known bugs in this module.
212              
213             Please report problems to Ivan Wills (ivan.wills@gmail.com).
214              
215             Patches are welcome.
216              
217             =head1 AUTHOR
218              
219             Ivan Wills - (ivan.wills@gmail.com)
220              
221             =head1 LICENSE AND COPYRIGHT
222              
223             Copyright (c) 2014-2016 Ivan Wills (14 Mullion Close, Hornsby Heights, NSW Australia 2077).
224             All rights reserved.
225              
226             This module is free software; you can redistribute it and/or modify it under
227             the same terms as Perl itself. See L<perlartistic>. This program is
228             distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
229             without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
230             PARTICULAR PURPOSE.
231              
232             =cut