Skip to content

Commit 3ccc50d

Browse files
authored
Recover from uninstalled gems in launcher mode (#2975)
1 parent da2fbec commit 3ccc50d

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

lib/ruby_lsp/setup_bundler.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,16 +241,16 @@ def run_bundle_install(bundle_gemfile = @gemfile)
241241
env
242242
end
243243

244-
sig { params(env: T::Hash[String, String]).returns(T::Hash[String, String]) }
245-
def run_bundle_install_directly(env)
244+
sig { params(env: T::Hash[String, String], force_install: T::Boolean).returns(T::Hash[String, String]) }
245+
def run_bundle_install_directly(env, force_install: false)
246246
RubyVM::YJIT.enable if defined?(RubyVM::YJIT.enable)
247247

248248
# The ENV can only be merged after checking if an update is required because we depend on the original value of
249249
# ENV["BUNDLE_GEMFILE"], which gets overridden after the merge
250250
should_update = should_bundle_update?
251251
T.unsafe(ENV).merge!(env)
252252

253-
unless should_update
253+
unless should_update && !force_install
254254
Bundler::CLI::Install.new({}).run
255255
correct_relative_remote_paths if @custom_lockfile.exist?
256256
return env
@@ -265,6 +265,9 @@ def run_bundle_install_directly(env)
265265
correct_relative_remote_paths if @custom_lockfile.exist?
266266
@last_updated_path.write(Time.now.iso8601)
267267
env
268+
rescue Bundler::GemNotFound, Bundler::GitError
269+
# If a gem is not installed, skip the upgrade and try to install it with a single retry
270+
@retry ? env : run_bundle_install_directly(env, force_install: true)
268271
end
269272

270273
sig { params(env: T::Hash[String, String]).returns(T::Hash[String, String]) }

test/setup_bundler_test.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,41 @@ def test_is_resilient_to_gemfile_changes_in_the_middle_of_setup
823823
end
824824
end
825825

826+
def test_update_does_not_fail_if_gems_are_uninstalled
827+
Dir.mktmpdir do |dir|
828+
Dir.chdir(dir) do
829+
File.write(File.join(dir, "Gemfile"), <<~GEMFILE)
830+
source "https://rubygems.org"
831+
gem "rdoc"
832+
GEMFILE
833+
834+
capture_subprocess_io do
835+
Bundler.with_unbundled_env do
836+
system("bundle install")
837+
run_script(dir)
838+
839+
mock_update = mock("update")
840+
mock_update.expects(:run).raises(Bundler::GemNotFound.new("rdoc"))
841+
require "bundler/cli/update"
842+
Bundler::CLI::Update.expects(:new).with(
843+
{ conservative: true },
844+
["ruby-lsp", "debug", "prism"],
845+
).returns(mock_update)
846+
847+
mock_install = mock("install")
848+
mock_install.expects(:run)
849+
require "bundler/cli/install"
850+
Bundler::CLI::Install.expects(:new).with({}).returns(mock_install)
851+
852+
RubyLsp::SetupBundler.new(dir, launcher: true).setup!
853+
end
854+
end
855+
856+
refute_path_exists(File.join(".ruby-lsp", "install_error"))
857+
end
858+
end
859+
end
860+
826861
private
827862

828863
def with_default_external_encoding(encoding, &block)

0 commit comments

Comments
 (0)