File tree Expand file tree Collapse file tree 3 files changed +63
-6
lines changed Expand file tree Collapse file tree 3 files changed +63
-6
lines changed Original file line number Diff line number Diff line change @@ -162,6 +162,33 @@ def assert_not_stale
162
162
watcher . add './foobar'
163
163
assert watcher . files . empty?
164
164
end
165
+
166
+ test "add symlink" do
167
+ File . write ( "#{ dir } /bar" , "bar" )
168
+ File . symlink ( "#{ dir } /bar" , "#{ dir } /foo" )
169
+ watcher . add './foo'
170
+ assert_equal [ "#{ dir } /bar" ] , watcher . files . to_a
171
+ end
172
+
173
+ test "add dangling symlink" do
174
+ File . symlink ( "#{ dir } /bar" , "#{ dir } /foo" )
175
+ watcher . add './foo'
176
+ assert watcher . files . empty?
177
+ end
178
+
179
+ test "add directory with dangling symlink" do
180
+ subdir = "#{ @dir } /subdir"
181
+ FileUtils . mkdir ( subdir )
182
+ File . symlink ( "dangling" , "#{ subdir } /foo" )
183
+
184
+ watcher . add subdir
185
+ assert_not_stale
186
+
187
+ # Adding a new file should mark as stale despite the dangling symlink.
188
+ File . write ( "#{ subdir } /new-file" , "new" )
189
+ watcher . check_stale
190
+ assert_stale
191
+ end
165
192
end
166
193
end
167
194
end
Original file line number Diff line number Diff line change @@ -48,14 +48,30 @@ def add(*items)
48
48
end
49
49
end
50
50
51
- items = items . select ( &:exist? )
51
+ items = items . select do |item |
52
+ if item . symlink?
53
+ item . readlink . exist? . tap do |exists |
54
+ if !exists
55
+ debug { "add: ignoring dangling symlink: #{ item . inspect } -> #{ item . readlink . inspect } " }
56
+ end
57
+ end
58
+ else
59
+ item . exist?
60
+ end
61
+ end
52
62
53
63
synchronize {
54
64
items . each do |item |
55
65
if item . directory?
56
66
directories << item . realpath . to_s
57
67
else
58
- files << item . realpath . to_s
68
+ begin
69
+ files << item . realpath . to_s
70
+ rescue Errno ::ENOENT
71
+ # Race condition. Ignore symlinks whose target was removed
72
+ # since the check above, or are deeply chained.
73
+ debug { "add: ignoring now-dangling symlink: #{ item . inspect } -> #{ item . readlink . inspect } " }
74
+ end
59
75
end
60
76
end
61
77
Original file line number Diff line number Diff line change @@ -64,10 +64,24 @@ def subjects_changed
64
64
private
65
65
66
66
def compute_mtime
67
- expanded_files . map { |f | File . mtime ( f ) . to_f } . max || 0
68
- rescue Errno ::ENOENT
69
- # if a file does no longer exist, the watcher is always stale.
70
- Float ::MAX
67
+ expanded_files . map do |f |
68
+ # Get the mtime of symlink targets. Ignore dangling symlinks.
69
+ if File . symlink? ( f )
70
+ begin
71
+ File . mtime ( f )
72
+ rescue Errno ::ENOENT
73
+ 0
74
+ end
75
+ # If a file no longer exists, treat it as changed.
76
+ else
77
+ begin
78
+ File . mtime ( f )
79
+ rescue Errno ::ENOENT
80
+ debug { "compute_mtime: no longer exists: #{ f } " }
81
+ Float ::MAX
82
+ end
83
+ end . to_f
84
+ end . max || 0
71
85
end
72
86
73
87
def expanded_files
You can’t perform that action at this time.
0 commit comments