Commit 02f6afa2 authored by Aaron Crane's avatar Aaron Crane Committed by Dave Rolsky

Treat Inotify IN_MOVED_TO events as creations

Both the Default and KQueue watchers treat files being renamed into (or
within) a watched directory as a creation event. However, the Inotify
watcher was ignoring those events. Fix that.

Given a watcher on directory d/ with filter qr/\.txt\z/, this affects
the following operations:

  * Renaming other/file.txt to d/file.txt
  * Renaming d/file.txt-tmp to d/file.txt

The latter of those is particularly useful when a file is created with
a temporary name, then renamed into place. For example, that's what the
"spew" method on Path::Tiny instances does.

This change has been tested on both Mac OS (with KQueue) and Linux (with
Inotify).
parent cdb27946
{{$NEXT}}
- Fixed handling of the IN_MOVED_TO event for the Inotify watcher. This event
was being entirely ignored, but we should just treat it as a file creation
event. Fixed by Aaron Crane. PR #2.
0.27 2017-01-30
- Inflating File::ChangeNotify::Default::Watcher into a Moose object with
......
......@@ -127,7 +127,7 @@ sub _interesting_events {
!$old_map->{$path}{is_dir}
&& ( $old_map->{$path}{mtime} != $new_map->{$path}{mtime}
|| $old_map->{$path}{size} != $new_map->{$path}{size} )
) {
) {
push @interesting, $self->event_class()->new(
path => $path,
type => 'modify',
......
......@@ -115,7 +115,8 @@ sub _build_mask {
my $self = shift;
my $mask
= IN_MODIFY | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF;
= IN_MODIFY | IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF
| IN_MOVED_TO;
$mask |= IN_DONT_FOLLOW unless $self->follow_symlinks();
return $mask;
......@@ -201,7 +202,7 @@ sub _convert_event {
return $self->event_class()->new(
path => $event->fullname(),
type => (
$event->IN_CREATE() ? 'create'
$event->IN_CREATE() || $event->IN_MOVED_TO() ? 'create'
: $event->IN_MODIFY() ? 'modify'
: $event->IN_DELETE() ? 'delete'
: 'unknown'
......
......@@ -57,6 +57,7 @@ sub _shared_tests {
_multi_event_tests(@_);
_filter_tests(@_);
_dir_add_remove_tests(@_);
_create_and_rename_tests(@_);
}
sub _basic_tests {
......@@ -176,6 +177,48 @@ sub _multi_event_tests {
}
}
sub _create_and_rename_tests {
my $class = shift;
my $events_sub = shift;
my $dir = tempdir( CLEANUP => 1 );
my $watcher = $class->new(
directories => $dir,
follow_symlinks => 0,
filter => qr/\.txt/,
sleep_interval => 0,
);
my $path = "$dir/file.txt";
my $temp_path = "$dir/file.txt-tmp";
create_file($temp_path);
rename $temp_path, $path
or die "Cannot rename $temp_path to $path: $!";
my @events = $events_sub->($watcher);
# The filter matches the temporary file as well as the final file, but
# whether we get any events on the temporary file depends on the backend in
# use. (KQueue on Mac OS doesn't report events for the temporary, but
# Inotify on Linux does.) Changing the filter to match only the final file
# would work, but the test would then hang under a version of Inotify that
# isn't patched to treat IN_MOVED_TO as a 'create' event (because no events
# would ever match). So ignore events that aren't for the final file.
_is_events(
[ grep { $_->path eq $path } @events ],
[
{
path => $path,
type => 'create',
},
],
'single creation event on final file for create/rename',
) or diag( Dumper( \@events ) );
}
sub _filter_tests {
my $class = shift;
my $events_sub = shift;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment