#!/usr/bin/perl

use Linux::Inotify2;
my $inotify = new Linux::Inotify2();

if(!@ARGV || $ARGV[0] eq '--help') {
  print <<___
Watches update of a (collection of) directory(ies) and launch a command
every time a pattern is matched.

usage: inotifexec.pl <directory> [more directories ...] <pattern> <command>

      pattern:     a regular expression indicating which event triggers the
                   command. Events known are (accessed modified metafied 
                   closed(rw) closed(ro) opened moved-out moved-in +subfile
                   -subfile deleted)

      command:     a string that will be passed to a shell after % characters
                   are replaced with the filename

example: 
      inotifexec.pl . closed.rw. "md5sum '%' >>/tmp/sums"
      Will append the md5sum of every file copied/modified here. Moving files
      in, however, will not have any effect. "closed.rw.|moved\-in" would be 
      the correct expression for that, afaik.

missing feature:
      cannot recurse created directories.
      cannot filter based on filename or filetype unless you hack the script.
___
    ;

@flags=qw(accessed modified metafied closed(rw) closed(ro) opened moved-out moved-in +subfile -subfile deleted);

$|=1; # autoflush ...

$cmd = pop @ARGV;
$filter = pop @ARGV;

#all the remaining arguments are files or directories for which we watch events
foreach (@ARGV)
{
  $inotify->watch($_, IN_ALL_EVENTS);
}

while (1)
{
  # By default this will block until something is read
  my @events = $inotify->read();
  if (scalar(@events)==0)
  {
    print STDERR "read error: $!";
    last;
  }
  
  # well, let's see what we got. 
  foreach (@events)
  {
    # first some binary-to-text conversion: check out the manpage of inotify
    # for details...
    $msk=$_->mask;
    $op='';
    foreach(0..$#flags) {
      $op.=$flags[$_].' ' if ($msk & (1<<$_));
    }
    if ($op) {
      # now, let's see if the observed operation matches the regexp
      # given by the user, format the command and execute.
      $VERBOSE and printf STDERR "File: %s $op\n", $_->fullname;
      if ($op =~ /$filter/) {
	$runme = $cmd;
	$fname = $_->fullname;
	$runme =~ s/%/$fname/g;
	printf STDERR $runme;
	system $runme;
      }

    } else {
      printf STDERR "File: %s; Mask: %d\n", $_->fullname, $_->mask;
    }
  }
}

