Skip to content

Commit 923ef23

Browse files
committed
Add Tapioca Addon gem RBI generation support
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 creating a snapshot of Gemfile.lock, we can persist data across server restarts. Upon restart, we parse both the snapshot and current Gemfile.lock using Bundler::LockfileParser. If differences are found, we extract the relevant gem names and specifications, allowing us to trigger the gem RBI generation.
1 parent c3a7376 commit 923ef23

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

lib/ruby_lsp/tapioca/addon.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ module Tapioca
1919
class Addon < ::RubyLsp::Addon
2020
extend T::Sig
2121

22+
GEMFILE_LOCK_SNAPSHOT = "tmp/tapioca/.gemfile_lock_snapshot"
23+
2224
sig { void }
2325
def initialize
2426
super
@@ -44,6 +46,8 @@ def activate(global_state, outgoing_queue)
4446
@rails_runner_client = addon.rails_runner_client
4547
outgoing_queue << Notification.window_log_message("Activating Tapioca add-on v#{version}")
4648
@rails_runner_client.register_server_addon(File.expand_path("server_addon.rb", __dir__))
49+
50+
check_gemfile_changes
4751
rescue IncompatibleApiError
4852
# The requested version for the Rails add-on no longer matches. We need to upgrade and fix the breaking
4953
# changes
@@ -106,6 +110,32 @@ def workspace_did_change_watched_files(changes)
106110
constants: constants,
107111
)
108112
end
113+
114+
private
115+
116+
sig { void }
117+
def check_gemfile_changes
118+
current_lockfile = File.read("Gemfile.lock")
119+
snapshot_lockfile = File.read(GEMFILE_LOCK_SNAPSHOT) if File.exist?(GEMFILE_LOCK_SNAPSHOT)
120+
121+
unless snapshot_lockfile
122+
$stdout.puts("Creating initial Gemfile.lock snapshot at #{GEMFILE_LOCK_SNAPSHOT}")
123+
FileUtils.mkdir_p(File.dirname(GEMFILE_LOCK_SNAPSHOT))
124+
File.write(GEMFILE_LOCK_SNAPSHOT, current_lockfile)
125+
return
126+
end
127+
128+
return if current_lockfile == snapshot_lockfile
129+
130+
T.must(@rails_runner_client).delegate_notification(
131+
server_addon_name: "Tapioca",
132+
request_name: "gem",
133+
snapshot_lockfile: snapshot_lockfile,
134+
current_lockfile: current_lockfile,
135+
)
136+
137+
File.write(GEMFILE_LOCK_SNAPSHOT, current_lockfile)
138+
end
109139
end
110140
end
111141
end

lib/ruby_lsp/tapioca/server_addon.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ def execute(request, params)
1414
case request
1515
when "dsl"
1616
dsl(params)
17+
when "gem"
18+
gem(params)
1719
end
1820
end
1921

@@ -23,6 +25,34 @@ def dsl(params)
2325
load("tapioca/cli.rb") # Reload the CLI to reset thor defaults between requests
2426
::Tapioca::Cli.start(["dsl", "--lsp_addon", "--workers=1"] + params[:constants])
2527
end
28+
29+
def gem(params)
30+
snapshot_specs = parse_lockfile(params[:snapshot_lockfile])
31+
current_specs = parse_lockfile(params[:current_lockfile])
32+
33+
removed_gems = snapshot_specs.keys - current_specs.keys
34+
changed_gems = current_specs.select { |name, version| snapshot_specs[name] != version }.keys
35+
36+
return $stdout.puts("No gem changes detected") if removed_gems.empty? && changed_gems.empty?
37+
38+
if removed_gems.any?
39+
$stdout.puts("Removing RBIs for deleted gems: #{removed_gems.join(", ")}")
40+
FileUtils.rm_f(Dir.glob("sorbet/rbi/gems/{#{removed_gems.join(",")}}@*.rbi"))
41+
end
42+
43+
if changed_gems.any?
44+
$stdout.puts("Generating RBIs for changed gems: #{changed_gems.join(", ")}")
45+
46+
load("tapioca/cli.rb") # Reload the CLI to reset thor defaults between requests
47+
::Tapioca::Cli.start(["gem"] + changed_gems)
48+
end
49+
end
50+
51+
def parse_lockfile(content)
52+
return {} if content.to_s.empty?
53+
54+
Bundler::LockfileParser.new(content).specs.to_h { |spec| [spec.name, spec.version.to_s] }
55+
end
2656
end
2757
end
2858
end

0 commit comments

Comments
 (0)