Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add launcher mode for gracefully handling missing dependencies #2751

Merged
merged 3 commits into from
Oct 23, 2024

Conversation

vinistock
Copy link
Member

Motivation

One of the biggest pain points of using the Ruby LSP is that we're tightly tied to the project's bundle. There are several reasons for why this is the case:

  • We need to be able to require the project's linter/formatter and all of its extensions
  • We need to be able to auto-detect and require add-ons
  • Add-ons need to be able to require code from the gems they are related to
  • We need to be able to auto-detect every dependency that has to be indexed for definition, completion, hover, signature help, workspace symbol and so on

Not being able to hook into the project's bundle would mean significant losses in terms of DX. However, this also means that if even a single gem failed to install, we are unable to launch the server - and that is also bad DX.

Even worse, bundle exec immediately exits the process if any gems are missing, which violates the LSP life cycle (the server needs to inform the editor about an initialization failure by printing a JSON back and the process should never exit prematurely).

This PR proposes a new way of launching the Ruby LSP, which should allow us to have a bit more control over missing dependencies.

Implementation

I recommend reviewing per commit.

  1. Started accepting the initialize request and a setup error as part of instantiating the server. This allows us report errors that occurred during Bundler.setup back to the user. It also allows us to read what is the workspace URI before invoking Bundler.setup, which allows us to fix the longstanding bug of not setting up the bundle in the right directory for editors that launch the server process outside of the workspace directory
  2. Added a new ruby-lsp-launcher executable. I will explain below the reason why we need this
  3. Added a new setting to control usage of the launcher in VS Code

Why do we need a new executable

We need to be able to:

  1. Set up the composed bundle with all of the dependencies we need
  2. Then control when Bundler.setup is invoked, so that we can fail gracefully and report errors back to the user

The problem is that when a gem's executable is invoked, you don't actually invoke the executable. You invoke Rubygems binstubs, which automatically activate all of the gem's dependencies.

That means that when ruby-lsp is executed, Rubygems will eagerly activate whatever latest versions of our dependencies are present. If the project's bundle is locked to any other version other than the ones eagerly activated, then Bundler.setup is guaranteed to fail complaining that another version of that gem has already been activated.

To work around this, we replace the current process with exec, invoking the ruby-lsp-launcher executable directly (without going through the Rubygems binstub) to avoid having our own dependencies eagerly activated and polluting the process before we had a chance to invoke Bundler.setup.

This approach means that no gems are activated until we finished setting up the composed bundle and manually invoke Bundler.setup ourselves, which ensures that no conflicts can occur and let's us handle the errors in an editor friendly way.

Automated Tests

I will follow up with some integration tests.

@vinistock vinistock added enhancement New feature or request server This pull request should be included in the server gem's release notes labels Oct 22, 2024
@vinistock vinistock self-assigned this Oct 22, 2024
@vinistock vinistock requested a review from a team as a code owner October 22, 2024 13:55
@vinistock vinistock force-pushed the vs-add-launcher-mode branch 2 times, most recently from b486b9f to 7bd9c3b Compare October 22, 2024 20:40
exe/ruby-lsp Outdated Show resolved Hide resolved
lib/ruby_lsp/base_server.rb Outdated Show resolved Hide resolved
exe/ruby-lsp-launcher Show resolved Hide resolved
exe/ruby-lsp-launcher Outdated Show resolved Hide resolved
exe/ruby-lsp-launcher Show resolved Hide resolved
lib/ruby_lsp/server.rb Show resolved Hide resolved
lib/ruby_lsp/server.rb Outdated Show resolved Hide resolved
exe/ruby-lsp Outdated Show resolved Hide resolved
@vinistock vinistock enabled auto-merge (squash) October 23, 2024 19:53
exe/ruby-lsp-launcher Show resolved Hide resolved
@vinistock vinistock merged commit 5ac10ef into main Oct 23, 2024
43 checks passed
@vinistock vinistock deleted the vs-add-launcher-mode branch October 23, 2024 20:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request server This pull request should be included in the server gem's release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants