diff --git a/lib/ruby_lsp/setup_bundler.rb b/lib/ruby_lsp/setup_bundler.rb index 99c10cf67..3be229cce 100644 --- a/lib/ruby_lsp/setup_bundler.rb +++ b/lib/ruby_lsp/setup_bundler.rb @@ -340,7 +340,7 @@ def update(env) Bundler::CLI::Update.new({ conservative: true }, gems).run correct_relative_remote_paths if @custom_lockfile.exist? - @needs_update_path.delete + @needs_update_path.delete if @needs_update_path.exist? @last_updated_path.write(Time.now.iso8601) env end diff --git a/test/setup_bundler_test.rb b/test/setup_bundler_test.rb index c8adcfd35..889525ac2 100644 --- a/test/setup_bundler_test.rb +++ b/test/setup_bundler_test.rb @@ -742,6 +742,45 @@ def test_invoke_cli_calls_bundler_directly_for_update end end + def test_update_does_not_fail_if_needs_update_path_was_deleted_by_concurrent_process + in_temp_dir do |dir| + File.write(File.join(dir, "Gemfile"), <<~GEMFILE) + source "https://rubygems.org" + gem "rdoc" + GEMFILE + + capture_subprocess_io do + Bundler.with_unbundled_env do + system("bundle install") + run_script(dir) + end + end + + capture_subprocess_io do + Bundler.with_unbundled_env do + needs_update_path = File.join(dir, ".ruby-lsp", "needs_update") + + # Simulate a concurrent process deleting the needs_update file during bundle update + mock_update = mock("update") + mock_update.expects(:run).with do + File.delete(needs_update_path) + true + end + require "bundler/cli/update" + Bundler::CLI::Update.expects(:new).with( + { conservative: true }, + ["ruby-lsp", "debug", "prism", "rbs"], + ).returns(mock_update) + + FileUtils.touch(needs_update_path) + RubyLsp::SetupBundler.new(dir, launcher: true).setup! + + refute_path_exists(File.join(dir, ".ruby-lsp", "install_error")) + end + end + end + end + def test_progress_is_printed_to_stderr in_temp_dir do |dir| File.write(File.join(dir, "Gemfile"), <<~GEMFILE)