App-filewatch

 view release on metacpan or  search on metacpan

bin/file-watch  view on Meta::CPAN

my %watch;
my $inotify;

main();
exit 0;

sub main {

    Getopt::Long::Configure('bundling');
    GetOptions(
        \%option,
        'dir|d!',
        'type|t=s@',
        'report|r',
        'command|cmd|c=s',
        'verbose|v+',
        'man',
        'help',
        'version',
    ) or pod2usage(2);

    if ( $option{'version'} ) {
        print "$name Version = $VERSION\n";
        exit 1;
    }
    elsif ( $option{'man'} ) {
        pod2usage( -verbose => 2 );
    }
    elsif ( $option{'help'} ) {
        pod2usage( -verbose => 1 );
    }

    # do stuff here
    my @files = map { path($_) } @ARGV ? @ARGV : ('.');
    my $tc = File::TypeCategories->new();
    $inotify = Linux::Inotify2->new;

    while ( my $file = shift @files ) {
        next if !$tc->file_ok($file);

        if ( -d $file ) {
            push @files, $file->children;
            next if !$option{dir};
        }

        warn "$file\n" if $option{verbose};
        watch($file);
    }

    if ( $option{type} && @{ $option{type} } == 1 && $option{type}[0] eq 'ALL' ) {
        $option{type} = $types;
    }
    else {
        $option{type} ||= ['IN_MODIFY', 'IN_MOVE_SELF'];
    }

    if ( $option{report} ) {
        $SIG{INT} = \&report;
    }

    my $refresh = AE::timer(1, 1, sub { report('changes'); });

    AnyEvent::Loop::run;

    return;
}

sub watch {
    my ($file) = @_;

    warn "The file '$file' no longer exists!\n" if !-e $file;

    $watch{$file} = {
        notify => scalar $inotify->watch( $file, Linux::Inotify2::IN_ALL_EVENTS(), \&changed ),
        ae     => scalar AE::io $inotify->fileno, 0, sub { $inotify->poll },
    };

    return;
}

my @refresh;
my %changed;
my %changes;
sub changed {
    my ($evt) = @_;
    my $file = $evt->{w}{name};

    $changed{$file}{time} = time;
    $changed{$file}{types} = {
        %{ $changed{$file}{types} || {} },
        map { $_ => 1 } grep { $evt->$_() } @$types
    };

    $changes{$file}{time} = time;
    $changes{$file}{types} = {
        %{ $changes{$file}{types} || {} },
        map { $_ => 1 }
        grep { $evt->$_() }
        @{ $option{type} }
    };

    push @refresh, AE::timer(1, 0, sub { watch($file); });

    return;
}

sub report {
    my $changes = shift;

    my %change = $changes eq 'changes' ? %changes : %changed;
    my $files_changed = keys %change;

    if ( $option{verbose} ) {
        for my $file ( sort keys %change ) {
            print "$file\t", ( join ', ', sort keys %{ $change{$file}{types} } ), "\n";
        }
    }

    if ($changes eq 'changes') {
        if ($option{command} && $files_changed) {
            local $ENV{CHANGED} = join ':', sort keys %change;
            system $option{command};
        }
        %changes = ();

        return;
    }

    exit;
}

__DATA__

=head1 NAME

file-watch - Watch files and directories for changes

=head1 VERSION

This documentation refers to file-watch version 0.005

=head1 SYNOPSIS

   file-watch [option] [file(s)]

 OPTIONS:
  -d --dir      Check directories
     --no-dir   Don't check directories (Default)
  -t --type[=]str
                Specify the type of file events to listen for, more than
                one event can be specified.
                 - IN_ACCESS
                 - IN_MODIFY
                 - IN_ATTRIB
                 - IN_CLOSE_WRITE
                 - IN_CLOSE_NOWRITE
                 - IN_OPEN
                 - IN_ALL_EVENTS
                 - IN_MOVED_FROM
                 - IN_MOVED_TO
                 - IN_CREATE
                 - IN_DELETE



( run in 2.869 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )