Skip to content

Commit

Permalink
Try timeout
Browse files Browse the repository at this point in the history
  • Loading branch information
vinistock committed Oct 26, 2024
1 parent 9d5301e commit b951442
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 22 deletions.
15 changes: 10 additions & 5 deletions exe/ruby-lsp-launcher
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@ locked_bundler_version_file = File.join(".ruby-lsp", "locked_bundler_version")
# Compose the Ruby LSP bundle in a forked process so that we can require gems without polluting the main process
# `$LOAD_PATH` and `Gem.loaded_specs`. Windows doesn't support forking, so we need a separate path to support it
pid = if Gem.win_platform?
load_path = $LOAD_PATH.map do |path|
"-I#{path}"
end.join(" ")

Process.spawn(
ENV.to_hash,
Gem.ruby,
load_path,
File.expand_path("../lib/ruby_lsp/scripts/compose_bundle_windows.rb", __dir__),
raw_initialize,
)
Expand All @@ -50,6 +54,7 @@ begin

require "bundler"
Bundler.ui.level = :silent
original_load_path = $LOAD_PATH.dup

# The composed bundle logic informs the main process about which Gemfile to setup Bundler with
if File.exist?(bundle_gemfile_file)
Expand All @@ -61,11 +66,11 @@ rescue StandardError => e
# features in a degraded mode. We simply save the error so that we can report to the user that certain gems might be
# missing, but we respect the LSP life cycle
setup_error = e
$stderr.puts("Failed to set up composed Bundle\n#{e.full_message}")

# If we failed to set up the bundle, the minimum we need is to have our own dependencies activated so that we can
# require the gems the LSP depends on. If even that fails, then there's no way we can continue to run the language
# server
Gem::Specification.find_by_name("ruby-lsp").activate
# One of the first steps of Bundler.setup is to clear the $LOAD_PATH. If Bundler.setup fails, we need to restore the
# original $LOAD_PATH so that we can still require the Ruby LSP server in degraded mode
$LOAD_PATH.replace(original_load_path)
end

error_path = File.join(".ruby-lsp", "install_error")
Expand Down
31 changes: 14 additions & 17 deletions test/integration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,6 @@ def test_launch_mode_with_no_gemfile_and_bundle_path
Bundler.with_unbundled_env do
system("bundle config --local path #{File.join("vendor", "bundle")}")
assert_path_exists(File.join(dir, ".bundle", "config"))
end

Bundler.with_unbundled_env do
launch(dir)
end
end
Expand All @@ -151,16 +148,11 @@ def test_launch_mode_with_no_gemfile_and_bundle_path
private

def launch(workspace_path)
load_path = $-I.map do |p|
"-I#{File.expand_path(p)}"
load_path = $LOAD_PATH.map do |path|
"-I#{path}"
end.join(" ")

stdin, stdout, stderr, wait_thr = T.unsafe(Open3).popen3(
ENV.to_hash,
Gem.ruby,
load_path,
File.join(@root, "exe", "ruby-lsp-launcher"),
)
stdin, stdout, stderr, wait_thr = Open3.popen3(Gem.ruby, load_path, File.join(@root, "exe", "ruby-lsp-launcher"))
stdin.sync = true
stdin.binmode
stdout.sync = true
Expand All @@ -180,14 +172,19 @@ def launch(workspace_path)
send_message(stdin, { id: 2, method: "shutdown" })
send_message(stdin, { method: "exit" })

begin
Process.wait(wait_thr.pid)
rescue Errno::ECHILD
nil
# Wait until the process exits
wait_thr.join

# If the child process failed, it is really difficult to diagnose what's happening unless we read what was printed
# to stderr
unless T.unsafe(wait_thr.value).success?
require "timeout"

Timeout.timeout(5) do
flunk("Process failed\n#{stderr.read}")
end
end

wait_thr.join
refute_predicate(wait_thr, :alive?)
assert_path_exists(File.join(workspace_path, ".ruby-lsp", "bundle_gemfile"))
assert_path_exists(File.join(workspace_path, ".ruby-lsp", "Gemfile"))
assert_path_exists(File.join(workspace_path, ".ruby-lsp", "Gemfile.lock"))
Expand Down

0 comments on commit b951442

Please sign in to comment.