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
162162 watcher . add './foobar'
163163 assert watcher . files . empty?
164164 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
165192 end
166193 end
167194end
Original file line number Diff line number Diff line change @@ -48,14 +48,30 @@ def add(*items)
4848 end
4949 end
5050
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
5262
5363 synchronize {
5464 items . each do |item |
5565 if item . directory?
5666 directories << item . realpath . to_s
5767 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
5975 end
6076 end
6177
Original file line number Diff line number Diff line change @@ -64,10 +64,24 @@ def subjects_changed
6464 private
6565
6666 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
7185 end
7286
7387 def expanded_files
You can’t perform that action at this time.
0 commit comments