2 # run_when_changed runs a command when a file (or files) is changed
3 # and is released under the terms of the GNU GPL version 3, or any
4 # later version, at your option. See the file README and COPYING for
6 # Copyright 2017 by Don Armstrong <don@donarmstrong.com>.
18 run_when_changed - runs a command when a file (or files) is changed
22 run_when_changed [file1] [command ...]
23 run_when_changed [file1] [filen] -- [command ...]
25 If only a single file is to be watched, the first argument is the
26 file, and all remaining arguments are the command. If multiple files
27 are to be watched, all arguments until the first -- argument are files
28 to be watched. If you wish to use a command containing -- and watch a
29 single file, -- must be the second argument.
33 run_when_changed file.Rnw make file.pdf;
35 run_when_changed file.Rnw file_2.Rnw -- make file.pdf;
41 push @USAGE_ERRORS,"You must provide at least a file and a command to run";
44 pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS;
46 my ($watch_files,$command) =
47 identify_files_and_command(@ARGV);
49 my $watching = set_up_file_watching($watch_files);
51 watch_and_run_command($watching,$command);
54 sub identify_files_and_command {
59 for my $i (0..$#arguments) {
60 if ($arguments[$i] eq '--') {
66 my @files = @arguments[0..$file_end];
67 my @command = @arguments[$command_start..$#arguments];
68 return (\@files,\@command);
71 sub set_up_file_watching {
73 my $watching = {files => $files};
74 my $inotify = new Linux::Inotify2
75 or die "Unable to create new inotify object: $!";
76 for my $file (@{$files}) {
77 my $watched_dir = dirname($file);
78 next if exists $watching->{dirs_watched}{$watched_dir};
79 $inotify->watch($watched_dir,
80 IN_CLOSE_WRITE|IN_MOVED_TO|IN_CREATE,
81 ) or die "Unable to watch file $file: $!";
82 $watching->{dirs_watched}{$watched_dir} = 1;
84 $watching->{inotify} = $inotify;
88 sub watch_and_run_command {
89 my ($watching,$command) = @_;
92 my @events = $watching->{inotify}->read;
93 for my $event (@events) {
95 for my $file (@{$watching->{files}}) {
96 if ($event->w->name eq dirname($file) and
97 $event->name eq basename($file)