Skip to content

Commit

Permalink
Add Tapioca Addon gem RBI generation support
Browse files Browse the repository at this point in the history
To support gem RBI generation, we needed a way to detect changes in
Gemfile.lock. Currently, changes to this file cause the Ruby LSP to
restart, resulting in loss of access to any previous state information.

By running git diff on Gemfile.lock, we can detect changes to the file,
and trigger the gem RBI generation process.

Then we can parse the diff output to determine which gems have been
removed, added or modified, and either remove the corresponding RBI
files or trigger the RBI generation process for the gems.
  • Loading branch information
alexcrocha committed Nov 30, 2024
1 parent 01fffb8 commit 3ac24d3
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 0 deletions.
27 changes: 27 additions & 0 deletions lib/ruby_lsp/tapioca/addon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def initialize
@rails_runner_client = T.let(nil, T.nilable(RubyLsp::Rails::RunnerClient))
@index = T.let(nil, T.nilable(RubyIndexer::Index))
@file_checksums = T.let({}, T::Hash[String, String])
@lockfile_diff = T.let(nil, T.nilable(String))
@outgoing_queue = T.let(nil, T.nilable(Thread::Queue))
end

Expand All @@ -45,6 +46,8 @@ def activate(global_state, outgoing_queue)
@rails_runner_client = addon.rails_runner_client
@outgoing_queue << Notification.window_log_message("Activating Tapioca add-on v#{version}")
@rails_runner_client.register_server_addon(File.expand_path("server_addon.rb", __dir__))

generate_gem_rbis if git_repo? && lockfile_changed?
rescue IncompatibleApiError
# The requested version for the Rails add-on no longer matches. We need to upgrade and fix the breaking
# changes
Expand Down Expand Up @@ -127,6 +130,30 @@ def file_updated?(change, path)

false
end

sig { returns(T::Boolean) }
def git_repo?
Dir.exist?(".git")
end

sig { returns(T::Boolean) }
def lockfile_changed?
!fetch_lockfile_diff.empty?
end

sig { returns(String) }
def fetch_lockfile_diff
@lockfile_diff = %x(git diff HEAD Gemfile.lock).strip
end

sig { void }
def generate_gem_rbis
T.must(@rails_runner_client).delegate_notification(
server_addon_name: "Tapioca",
request_name: "gem",
diff: T.must(@lockfile_diff),
)
end
end
end
end
17 changes: 17 additions & 0 deletions lib/ruby_lsp/tapioca/server_addon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# frozen_string_literal: true

require "tapioca/internal"
require_relative "lockfile_diff_parser"

module RubyLsp
module Tapioca
Expand All @@ -16,6 +17,8 @@ def execute(request, params)
fork do
dsl(params)
end
when "gem"
gem(params)
end
end

Expand All @@ -25,6 +28,20 @@ def dsl(params)
load("tapioca/cli.rb") # Reload the CLI to reset thor defaults between requests
::Tapioca::Cli.start(["dsl", "--lsp_addon", "--workers=1"] + params[:constants])
end

def gem(params)
gem_changes = LockfileDiffParser.new(params[:diff])

removed_gems = gem_changes.removed_gems
added_or_modified_gems = gem_changes.added_or_modified_gems

if added_or_modified_gems.any?
load("tapioca/cli.rb") # Reload the CLI to reset thor defaults between requests
::Tapioca::Cli.start(["gem"] + added_or_modified_gems)
elsif removed_gems.any?
FileUtils.rm_f(Dir.glob("sorbet/rbi/gems/{#{removed_gems.join(",")}}@*.rbi"))
end
end
end
end
end

0 comments on commit 3ac24d3

Please sign in to comment.