pax_global_header00006660000000000000000000000064116402246340014514gustar00rootroot0000000000000052 comment=9f1ecc59ea06b8d70f06cde523e9622d23edb066 perl-Filesys-Notify-Simple-0.08/000075500000000000000000000000001164022463400165145ustar00rootroot00000000000000perl-Filesys-Notify-Simple-0.08/.gitignore000064400000000000000000000000451164022463400205030ustar00rootroot00000000000000META.yml Makefile inc/ pm_to_blib *~ perl-Filesys-Notify-Simple-0.08/.shipit000064400000000000000000000001651164022463400200170ustar00rootroot00000000000000steps = FindVersion, ChangeVersion, CheckChangeLog, DistTest, Commit, Tag, MakeDist, UploadCPAN git.push_to = origin perl-Filesys-Notify-Simple-0.08/Changes000064400000000000000000000015251164022463400200120ustar00rootroot00000000000000Revision history for Perl extension Filesys::Notify::Simple 0.08 Mon Sep 26 18:40:06 PDT 2011 - Added KQueue support for FreeBSD 0.07 Thu Jan 13 11:32:09 PST 2011 - Don't die when there's a symlink poiting to something already processed (clkao) 0.06 Mon Mar 29 17:21:58 PDT 2010 - Fixed it so ->wait won't die if one of the given directory doesn't exist, on platforms like Win32. 0.05 Sun Nov 29 14:42:13 JST 2009 - Fixed fails with Win32 (charsbar++) 0.04 Fri Oct 23 23:16:13 PDT 2009 - Upgrade Test::SharedFork in inc/ 0.03 Fri Oct 23 01:21:13 PDT 2009 - Fixed a bug where sub directory is not being monitored with Inotify2 (Thanks to kazeburo) 0.02 Thu Oct 22 13:25:18 PDT 2009 - Added Test::SharedFork to inc/ 0.01 Wed Oct 21 01:42:58 2009 - original version perl-Filesys-Notify-Simple-0.08/MANIFEST000064400000000000000000000015151164022463400176470ustar00rootroot00000000000000.gitignore Changes inc/Module/Install.pm inc/Module/Install/AuthorTests.pm inc/Module/Install/Base.pm inc/Module/Install/Can.pm inc/Module/Install/Fetch.pm inc/Module/Install/Include.pm inc/Module/Install/Makefile.pm inc/Module/Install/Metadata.pm inc/Module/Install/ReadmeFromPod.pm inc/Module/Install/Repository.pm inc/Module/Install/TestBase.pm inc/Module/Install/Win32.pm inc/Module/Install/WriteAll.pm inc/Spiffy.pm inc/Test/Base.pm inc/Test/Base/Filter.pm inc/Test/Builder.pm inc/Test/Builder/Module.pm inc/Test/More.pm inc/Test/SharedFork.pm inc/Test/SharedFork/Array.pm inc/Test/SharedFork/Scalar.pm inc/Test/SharedFork/Store.pm lib/Filesys/Notify/Simple.pm Makefile.PL MANIFEST This list of files META.yml README t/00_compile.t t/non_existent_path.t t/rm_create.t t/x/.placeholder xt/perlcritic.t xt/pod.t xt/podspell.t xt/synopsis.t perl-Filesys-Notify-Simple-0.08/MANIFEST.SKIP000064400000000000000000000001731164022463400204130ustar00rootroot00000000000000\bRCS\b \bCVS\b \.svn/ \.git/ ^MANIFEST\. ^Makefile$ ~$ \.old$ ^blib/ ^pm_to_blib ^MakeMaker-\d \.gz$ \.cvsignore \.shipit perl-Filesys-Notify-Simple-0.08/Makefile.PL000064400000000000000000000004411164022463400204650ustar00rootroot00000000000000use inc::Module::Install; name 'Filesys-Notify-Simple'; all_from 'lib/Filesys/Notify/Simple.pm'; readme_from 'lib/Filesys/Notify/Simple.pm'; build_requires 'Test::More'; test_requires 'Test::SharedFork'; use_test_base; auto_include_deps; author_tests('xt'); auto_set_repository; WriteAll; perl-Filesys-Notify-Simple-0.08/README000064400000000000000000000024211164022463400173730ustar00rootroot00000000000000NAME Filesys::Notify::Simple - Simple and dumb file system watcher SYNOPSIS use Filesys::Notify::Simple; my $watcher = Filesys::Notify::Simple->new([ "." ]); $watcher->wait(sub { for my $event (@_) { $event->{path} # full path of the file updated } }); DESCRIPTION Filesys::Notify::Simple is a simple but unified interface to get notifications of changes to a given filesystem path. It utilizes inotify2 on Linux and fsevents on OS X if they're installed, with a fallback to the full directory scan if they're not available. There are some limitations in this module. If you don't like it, use File::ChangeNotify. * There is no file name based filter. Do it in your own code. * You can not get types of events (created, updated, deleted). * Currently "wait" method blocks. In return, this module doesn't depend on any non-core modules. Platform specific optimizations with Linux::Inotify2 and Mac::FSEvents are truely optional. AUTHOR Tatsuhiko Miyagawa LICENSE This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. SEE ALSO File::ChangeNotify Mac::FSEvents Linux::Inotify2 perl-Filesys-Notify-Simple-0.08/lib/000075500000000000000000000000001164022463400172625ustar00rootroot00000000000000perl-Filesys-Notify-Simple-0.08/lib/Filesys/000075500000000000000000000000001164022463400207005ustar00rootroot00000000000000perl-Filesys-Notify-Simple-0.08/lib/Filesys/Notify/000075500000000000000000000000001164022463400221505ustar00rootroot00000000000000perl-Filesys-Notify-Simple-0.08/lib/Filesys/Notify/Simple.pm000064400000000000000000000132351164022463400237430ustar00rootroot00000000000000package Filesys::Notify::Simple; use strict; use 5.008_001; our $VERSION = '0.08'; use Carp (); use Cwd; use constant NO_OPT => $ENV{PERL_FNS_NO_OPT}; sub new { my($class, $path) = @_; unless (ref $path eq 'ARRAY') { Carp::croak('Usage: Filesys::Notify::Simple->new([ $path1, $path2 ])'); } my $self = bless { paths => $path }, $class; $self->init; $self; } sub wait { my($self, $cb) = @_; $self->{watcher} ||= $self->{watcher_cb}->(@{$self->{paths}}); $self->{watcher}->($cb); } sub init { my $self = shift; local $@; if ($^O eq 'linux' && !NO_OPT && eval { require Linux::Inotify2; 1 }) { $self->{watcher_cb} = \&wait_inotify2; } elsif ($^O eq 'darwin' && !NO_OPT && eval { require Mac::FSEvents; 1 }) { $self->{watcher_cb} = \&wait_fsevents; } elsif ($^O eq 'freebsd' && !NO_OPT && eval { require Filesys::Notify::KQueue; 1 }) { $self->{watcher_cb} = \&wait_kqueue; } else { $self->{watcher_cb} = \&wait_timer; } } sub wait_inotify2 { my @path = @_; Linux::Inotify2->import; my $inotify = Linux::Inotify2->new; my $fs = _full_scan(@path); for my $path (keys %$fs) { $inotify->watch($path, &IN_MODIFY|&IN_CREATE|&IN_DELETE|&IN_DELETE_SELF|&IN_MOVE_SELF); } return sub { my $cb = shift; $inotify->blocking(1); my @events = $inotify->read; $cb->(map { +{ path => $_->fullname } } @events); }; } sub wait_fsevents { require IO::Select; my @path = @_; my $fs = _full_scan(@path); my $sel = IO::Select->new; my %events; for my $path (@path) { my $fsevents = Mac::FSEvents->new({ path => $path, latency => 1 }); my $fh = $fsevents->watch; $sel->add($fh); $events{fileno $fh} = $fsevents; } return sub { my $cb = shift; my @ready = $sel->can_read; my @events; for my $fh (@ready) { my $fsevents = $events{fileno $fh}; my %uniq; my @path = grep !$uniq{$_}++, map { $_->path } $fsevents->read_events; my $new_fs = _full_scan(@path); my $old_fs = +{ map { ($_ => $fs->{$_}) } keys %$new_fs }; _compare_fs($old_fs, $new_fs, sub { push @events, { path => $_[0] } }); $fs->{$_} = $new_fs->{$_} for keys %$new_fs; last if @events; } $cb->(@events); }; } sub wait_kqueue { my @path = @_; my $kqueue = Filesys::Notify::KQueue->new( path => \@path ); return sub { $kqueue->wait(shift) }; } sub wait_timer { my @path = @_; my $fs = _full_scan(@path); return sub { my $cb = shift; my @events; while (1) { sleep 2; my $new_fs = _full_scan(@path); _compare_fs($fs, $new_fs, sub { push @events, { path => $_[0] } }); $fs = $new_fs; last if @events; }; $cb->(@events); }; } sub _compare_fs { my($old, $new, $cb) = @_; for my $dir (keys %$old) { for my $path (keys %{$old->{$dir}}) { if (!exists $new->{$dir}{$path}) { $cb->($path); # deleted } elsif (!$new->{$dir}{$path}{is_dir} && ( $old->{$dir}{$path}{mtime} != $new->{$dir}{$path}{mtime} || $old->{$dir}{$path}{size} != $new->{$dir}{$path}{size})) { $cb->($path); # updated } } } for my $dir (keys %$new) { for my $path (sort grep { !exists $old->{$dir}{$_} } keys %{$new->{$dir}}) { $cb->($path); # new } } } sub _full_scan { my @path = @_; require File::Find; my %map; for my $path (@path) { my $fp = eval { Cwd::realpath($path) } or next; File::Find::finddepth({ wanted => sub { my $fullname = $File::Find::fullname || File::Spec->rel2abs($File::Find::name); $map{Cwd::realpath($File::Find::dir)}{$fullname} = _stat($fullname); }, follow_fast => 1, follow_skip => 2, no_chdir => 1, }, @path); # remove root entry delete $map{$fp}{$fp}; } return \%map; } sub _stat { my $path = shift; my @stat = stat $path; return { path => $path, mtime => $stat[9], size => $stat[7], is_dir => -d _ }; } 1; __END__ =encoding utf-8 =for stopwords =head1 NAME Filesys::Notify::Simple - Simple and dumb file system watcher =head1 SYNOPSIS use Filesys::Notify::Simple; my $watcher = Filesys::Notify::Simple->new([ "." ]); $watcher->wait(sub { for my $event (@_) { $event->{path} # full path of the file updated } }); =head1 DESCRIPTION Filesys::Notify::Simple is a simple but unified interface to get notifications of changes to a given filesystem path. It utilizes inotify2 on Linux and fsevents on OS X if they're installed, with a fallback to the full directory scan if they're not available. There are some limitations in this module. If you don't like it, use L. =over 4 =item * There is no file name based filter. Do it in your own code. =item * You can not get types of events (created, updated, deleted). =item * Currently C method blocks. =back In return, this module doesn't depend on any non-core modules. Platform specific optimizations with L and L are truely optional. =head1 AUTHOR Tatsuhiko Miyagawa Emiyagawa@bulknews.netE =head1 LICENSE This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L L L =cut perl-Filesys-Notify-Simple-0.08/t/000075500000000000000000000000001164022463400167575ustar00rootroot00000000000000perl-Filesys-Notify-Simple-0.08/t/00_compile.t000064400000000000000000000001231164022463400210670ustar00rootroot00000000000000use strict; use Test::More tests => 1; BEGIN { use_ok 'Filesys::Notify::Simple' } perl-Filesys-Notify-Simple-0.08/t/non_existent_path.t000064400000000000000000000004221164022463400226730ustar00rootroot00000000000000use strict; use Test::More; $ENV{PERL_FNS_NO_OPT} = 1; require Filesys::Notify::Simple; my $fs = Filesys::Notify::Simple->new(["/xxx/nonexistent"]); eval { $SIG{ALRM} = sub { die "Alarm\n" }; alarm 1; $fs->wait(sub {}); }; is $@, "Alarm\n"; done_testing; perl-Filesys-Notify-Simple-0.08/t/rm_create.t000064400000000000000000000012331164022463400211040ustar00rootroot00000000000000use strict; use Filesys::Notify::Simple; use Test::More; use Test::SharedFork; use FindBin; plan tests => 2; my $w = Filesys::Notify::Simple->new([ "lib", "t" ]); my $pid = fork; if ($pid == 0) { Test::SharedFork->child; sleep 3; my $test_file = "$FindBin::Bin/x/rm_create.data"; open my $out, ">", $test_file; print $out "foo" . time; close $out; sleep 3; unlink $test_file; } elsif ($pid != 0) { Test::SharedFork->parent; my $event; for (1..2) { alarm 10; $w->wait(sub { $event = shift }); # create like $event->{path}, qr/rm_create\.data/; } waitpid $pid, 0; } else { die $!; } perl-Filesys-Notify-Simple-0.08/t/x/000075500000000000000000000000001164022463400172265ustar00rootroot00000000000000perl-Filesys-Notify-Simple-0.08/t/x/.placeholder000064400000000000000000000000001164022463400214770ustar00rootroot00000000000000perl-Filesys-Notify-Simple-0.08/xt/000075500000000000000000000000001164022463400171475ustar00rootroot00000000000000perl-Filesys-Notify-Simple-0.08/xt/perlcritic.t000064400000000000000000000002231164022463400214710ustar00rootroot00000000000000use strict; use Test::More; eval q{ use Test::Perl::Critic }; plan skip_all => "Test::Perl::Critic is not installed." if $@; all_critic_ok("lib"); perl-Filesys-Notify-Simple-0.08/xt/pod.t000064400000000000000000000002011164022463400201070ustar00rootroot00000000000000use Test::More; eval "use Test::Pod 1.00"; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; all_pod_files_ok(); perl-Filesys-Notify-Simple-0.08/xt/podspell.t000064400000000000000000000003421164022463400211550ustar00rootroot00000000000000use Test::More; eval q{ use Test::Spelling }; plan skip_all => "Test::Spelling is not installed." if $@; add_stopwords(); set_spell_cmd("aspell -l en list"); all_pod_files_spelling_ok('lib'); __DATA__ Tatsuhiko Miyagawa perl-Filesys-Notify-Simple-0.08/xt/synopsis.t000064400000000000000000000001601164022463400212200ustar00rootroot00000000000000use Test::More; eval "use Test::Synopsis"; plan skip_all => "Test::Synopsis required" if $@; all_synopsis_ok();