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 ...]
26 --debug, -d debugging level (Default 0)
27 --help, -h display this help
28 --man, -m display manual
30 If only a single file is to be watched, the first argument is the
31 file, and all remaining arguments are the command. If multiple files
32 are to be watched, all arguments until the first -- argument are files
33 to be watched. If you wish to use a command containing -- and watch a
34 single file, -- must be the second argument.
38 run_when_changed file.Rnw make file.pdf;
40 run_when_changed file.Rnw file_2.Rnw -- make file.pdf;
46 push @USAGE_ERRORS,"You must provide at least a file and a command to run";
49 pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS;
51 my ($watch_files,$command) =
52 identify_files_and_command(@ARGV);
54 my $watching = set_up_file_watching($watch_files);
56 watch_and_run_command($watching,$command);
59 sub identify_files_and_command {
64 for my $i (0..$#arguments) {
65 if ($arguments[$i] eq '--') {
71 my @files = @arguments[0..$file_end];
72 my @command = @arguments[$command_start..$#arguments];
73 return (\@files,\@command);
76 sub set_up_file_watching {
78 my $watching = {files => $files};
79 my $inotify = new Linux::Inotify2
80 or die "Unable to create new inotify object: $!";
81 for my $file (@{$files}) {
82 my $watched_dir = dirname($file);
83 next if exists $watching->{dirs_watched}{$watched_dir};
84 $inotify->watch($watched_dir,
85 IN_CLOSE_WRITE|IN_MOVED_TO|IN_CREATE,
86 ) or die "Unable to watch file $file: $!";
87 $watching->{dirs_watched}{$watched_dir} = 1;
89 $watching->{inotify} = $inotify;
93 sub watch_and_run_command {
94 my ($watching,$command) = @_;
97 my @events = $watching->{inotify}->read;
98 for my $event (@events) {
100 for my $file (@{$watching->{files}}) {
101 if ($event->w->name eq dirname($file) and
102 $event->name eq basename($file)