diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb index 0af5c86497..064f888b7f 100644 --- a/lib/rdoc/rdoc.rb +++ b/lib/rdoc/rdoc.rb @@ -124,7 +124,7 @@ def gather_files(files) file_list = normalized_file_list files, true, @options.exclude - file_list = remove_unparseable(file_list) + file_list = remove_duplicate_files(remove_unparseable(file_list)) if file_list.count {|name, mtime| file_list[name] = @last_modified[name] unless mtime @@ -458,6 +458,13 @@ def remove_unparseable(files) end end + ## + # Removes duplicate canonical paths while preserving the first path found. + + def remove_duplicate_files(files) + files.uniq { |file,| File.realpath(file) }.to_h + end + ## # Generates documentation or a coverage report depending upon the settings # in +options+. diff --git a/lib/rdoc/server.rb b/lib/rdoc/server.rb index f3e13f6ab9..a5b4862f6b 100644 --- a/lib/rdoc/server.rb +++ b/lib/rdoc/server.rb @@ -399,7 +399,7 @@ def current_watch_files @options.files.empty? ? [@options.root.to_s] : @options.files, true, @options.exclude ) - @rdoc.remove_unparseable(file_list).keys | @rdoc.auto_discovered_rbs_signature_files + @rdoc.remove_duplicate_files(@rdoc.remove_unparseable(file_list)).keys | @rdoc.auto_discovered_rbs_signature_files end def file_changed?(file) diff --git a/test/rdoc/rdoc_rdoc_test.rb b/test/rdoc/rdoc_rdoc_test.rb index 7da44a9979..67f4b01f38 100644 --- a/test/rdoc/rdoc_rdoc_test.rb +++ b/test/rdoc/rdoc_rdoc_test.rb @@ -338,6 +338,22 @@ def test_gather_files assert_equal [a, b], @rdoc.gather_files([b, a, b]) end + def test_gather_files_deduplicates_symlinked_source_tree + temp_dir do |dir| + source_dir = File.join dir, 'gem' + symlink_dir = File.join dir, 'docs', 'gem' + FileUtils.mkdir_p [File.dirname(symlink_dir), source_dir] + source_file = File.join source_dir, 'example.rb' + FileUtils.touch source_file + FileUtils.ln_s '../gem', symlink_dir + omit 'directory symlinks are not supported' unless File.directory? symlink_dir + + assert_equal 1, @rdoc.gather_files([dir]).count { |file| File.identical?(source_file, file) } + end + rescue NotImplementedError, Errno::EACCES, Errno::EPERM + omit 'symlinks are not supported' + end + def test_handle_pipe $stdin = StringIO.new "hello" diff --git a/test/rdoc/rdoc_server_test.rb b/test/rdoc/rdoc_server_test.rb index 09dd626a4f..1a8a0f9909 100644 --- a/test/rdoc/rdoc_server_test.rb +++ b/test/rdoc/rdoc_server_test.rb @@ -126,4 +126,18 @@ def greet: () -> String greet = sample.find_method 'greet', false assert_equal ['() -> String'], greet.type_signature_lines end + + def test_current_watch_files_deduplicates_symlinked_source_tree + source_dir = File.join @dir, 'gem' + symlink_dir = File.join @dir, 'docs', 'gem' + FileUtils.mkdir_p [File.dirname(symlink_dir), source_dir] + source_file = File.join source_dir, 'example.rb' + FileUtils.touch source_file + FileUtils.ln_s '../gem', symlink_dir + omit 'directory symlinks are not supported' unless File.directory? symlink_dir + + assert_equal 1, @server.send(:current_watch_files).count { |file| File.identical?(source_file, file) } + rescue NotImplementedError, Errno::EACCES, Errno::EPERM + omit 'symlinks are not supported' + end end