]> git.donarmstrong.com Git - bin.git/commitdiff
switch to perl version of run when changed
authorDon Armstrong <don@donarmstrong.com>
Mon, 29 May 2017 22:10:06 +0000 (17:10 -0500)
committerDon Armstrong <don@donarmstrong.com>
Mon, 29 May 2017 22:10:06 +0000 (17:10 -0500)
run_when_changed

index 8ad3a27fbdce180b37f38fa61a12f2ea379afe98..0fbcf575cf47658969e6ce44ecfcc21c51395b47 100755 (executable)
-#!/bin/sh
-
-WATCH_FULL_FILE="$1"
-shift 1;
-
-if ! [ -e "$WATCH_FULL_FILE" ]; then
-    echo "No such file or directory $WATCH_FULL_FILE";
-fi;
-
-WATCH_DIR=`dirname "$WATCH_FULL_FILE"`
-WATCH_FILE=`basename "$WATCH_FULL_FILE"`
-
-if which inotifywait > /dev/null 2>&1; then
-    inotifywait -m -e close_write,moved_to,create $WATCH_DIR |
-        while read -r directory events filename; do
-            if [ "x$filename" = "x$WATCH_FILE" ]; then
-                ( exec "$@" );
-            fi;
-        done;
-else
-    CURR_TIME=$(stat -c '%Y' "$WATCH_FULL_FILE");
-    while sleep 1; do
-        NEW_TIME=$(stat -c '%Y' "$WATCH_FULL_FILE");
-        if [ "x$NEW_TIME" != "x$CURR_TIME" ]; then
-            CURR_TIME=$NEW_TIME
-            ( exec "$@" );
-        fi;
-    done;
-fi;
+#!/usr/bin/perl
+# run_when_changed runs a command when a file (or files) is changed
+# and is released under the terms of the GNU GPL version 3, or any
+# later version, at your option. See the file README and COPYING for
+# more information.
+# Copyright 2017 by Don Armstrong <don@donarmstrong.com>.
+
+
+use warnings;
+use strict;
+
+use Pod::Usage;
+use Linux::Inotify2;
+use File::Basename;
+
+=head1 NAME
+
+run_when_changed - runs a command when a file (or files) is changed
+
+=head1 SYNOPSIS
+
+ run_when_changed [file1] [command ...]
+ run_when_changed [file1] [filen] -- [command ...]
+
+ Options:
+   --debug, -d debugging level (Default 0)
+   --help, -h display this help
+   --man, -m display manual
+
+If only a single file is to be watched, the first argument is the
+file, and all remaining arguments are the command. If multiple files
+are to be watched, all arguments until the first -- argument are files
+to be watched. If you wish to use a command containing -- and watch a
+single file, -- must be the second argument.
+
+=head1 EXAMPLES
+
+     run_when_changed file.Rnw make file.pdf;
+
+     run_when_changed file.Rnw file_2.Rnw -- make file.pdf;
+
+=cut
+
+my @USAGE_ERRORS;
+if (@ARGV < 2) {
+    push @USAGE_ERRORS,"You must provide at least a file and a command to run";
+}
+
+pod2usage(join("\n",@USAGE_ERRORS)) if @USAGE_ERRORS;
+
+my ($watch_files,$command) =
+    identify_files_and_command(@ARGV);
+
+my $watching = set_up_file_watching($watch_files);
+
+watch_and_run_command($watching,$command);
+
+
+sub identify_files_and_command {
+    my (@arguments) = @_;
+
+    my $file_end=0;
+    my $command_start=1;
+    for my $i (0..$#arguments) {
+        if ($arguments[$i] eq '--') {
+            $file_end=$i-1;
+            $command_start=$i+1;
+            last;
+        }
+    }
+    my @files = @arguments[0..$file_end];
+    my @command = @arguments[$command_start..$#arguments];
+    return (\@files,\@command);
+}
+
+sub set_up_file_watching {
+    my ($files) = @_;
+    my $watching = {files => $files};
+    my $inotify = new Linux::Inotify2
+        or die "Unable to create new inotify object: $!";
+    for my $file (@{$files}) {
+        my $watched_dir = dirname($file);
+        next if exists $watching->{dirs_watched}{$watched_dir};
+        $inotify->watch($watched_dir,
+                        IN_CLOSE_WRITE|IN_MOVED_TO|IN_CREATE,
+                       ) or die "Unable to watch file $file: $!";
+        $watching->{dirs_watched}{$watched_dir} = 1;
+    }
+    $watching->{inotify} = $inotify;
+    return $watching;
+}
+
+sub watch_and_run_command {
+    my ($watching,$command) = @_;
+
+    while () {
+        my @events = $watching->{inotify}->read;
+        for my $event (@events) {
+            my $run_command = 0;
+            for my $file (@{$watching->{files}}) {
+                if ($event->w->name eq dirname($file) and
+                    $event->name eq basename($file)
+                   ) {
+                    $run_command = 1;
+                }
+            }
+            if ($run_command) {
+                system(@{$command});
+            }
+        }
+    }
+}
+__END__