Skip to content

Commit

Permalink
Make sure to run bundle install even when not altering the custom bundle
Browse files Browse the repository at this point in the history
  • Loading branch information
vinistock committed Jul 17, 2023
1 parent 71d3fcf commit 7d01600
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 26 deletions.
6 changes: 3 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ GEM
i18n (1.14.1)
concurrent-ruby (~> 1.0)
io-console (0.6.0)
irb (1.7.0)
reline (>= 0.3.0)
irb (1.7.4)
reline (>= 0.3.6)
json (2.6.3)
language_server-protocol (3.17.0.3)
loofah (2.21.3)
Expand Down Expand Up @@ -96,7 +96,7 @@ GEM
rdoc (6.5.0)
psych (>= 4.0.0)
regexp_parser (2.8.1)
reline (0.3.5)
reline (0.3.6)
io-console (~> 0.5)
rexml (3.2.5)
rubocop (1.54.2)
Expand Down
54 changes: 36 additions & 18 deletions lib/ruby_lsp/setup_bundler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,41 @@
# the Ruby LSP without including the gem in their application's Gemfile while at the same time giving us access to the
# exact locked versions of dependencies.

run_bundle_install = lambda do |dependencies, bundle_gemfile = nil|
# If the user has a custom bundle path configured, we need to ensure that we will use the absolute and not relative
# version of it when running `bundle install`. This is necessary to avoid installing the gems under the `.ruby-lsp`
# folder, which is not the user's intention. For example, if the path is configured as `vendor`, we want to install it
# in the top level `vendor` and not `.ruby-lsp/vendor`
path = Bundler.settings["path"]

command = +""
# Use the absolute `BUNDLE_PATH` to prevent accidentally creating unwanted folders under `.ruby-lsp`
command << "BUNDLE_PATH=#{File.expand_path(path, Dir.pwd)} " if path
command << "BUNDLE_GEMFILE=#{bundle_gemfile} " if bundle_gemfile

if dependencies["ruby-lsp"] && dependencies["debug"]
# Install gems using the custom bundle
command << "bundle install "
else
# If ruby-lsp or debug are not in the Gemfile, try to update them to the latest version
command << "bundle update "
command << "ruby-lsp " unless dependencies["ruby-lsp"]
command << "debug " unless dependencies["debug"]
end

# Redirect stdout to stderr to prevent going into an infinite loop. The extension might confuse stdout output with
# responses
command << "1>&2"

# Add bundle update
warn("Ruby LSP> Running bundle install for the custom bundle. This may take a while...")
system(command)
end

# Do not setup a custom bundle if we're working on the Ruby LSP, since it's already included by default
if Pathname.new(Dir.pwd).basename == "ruby-lsp"
if Pathname.new(Dir.pwd).basename.to_s == "ruby-lsp"
warn("Ruby LSP> Skipping custom bundle setup since we're working on the Ruby LSP itself")
run_bundle_install.call({})
return
end

Expand All @@ -30,6 +62,7 @@
# Do not setup a custom bundle if both `ruby-lsp` and `debug` are already in the Gemfile
if dependencies["ruby-lsp"] && dependencies["debug"]
warn("Ruby LSP> Skipping custom bundle setup since both `ruby-lsp` and `debug` are already in the Gemfile")
run_bundle_install.call(dependencies)
return
end

Expand Down Expand Up @@ -62,25 +95,10 @@
# updated, then we're ready to boot the server
if File.exist?(".ruby-lsp/Gemfile.lock") && File.stat(".ruby-lsp/Gemfile.lock").mtime > File.stat("Gemfile.lock").mtime
warn("Ruby LSP> Skipping custom bundle setup since .ruby-lsp/Gemfile.lock already exists and is up to date")
run_bundle_install.call(dependencies, ".ruby-lsp/Gemfile")
return
end

FileUtils.cp("Gemfile.lock", ".ruby-lsp/Gemfile.lock")

# If the user has a custom bundle path configured, we need to ensure that we will use the absolute and not relative
# version of it when running bundle install. This is necessary to avoid installing the gems under the `.ruby-lsp`
# folder, which is not the user's intention. For example, if path is configured as `vendor`, we want to install it in
# the top level `vendor` and not `.ruby-lsp/vendor`
path = Bundler.settings["path"]

command = +""
# Use the absolute `BUNDLE_PATH` to prevent accidentally creating unwanted folders under `.ruby-lsp`
command << "BUNDLE_PATH=#{File.expand_path(path, Dir.pwd)} " if path
# Install gems using the custom bundle
command << "BUNDLE_GEMFILE=.ruby-lsp/Gemfile bundle install "
# Redirect stdout to stderr to prevent going into an infinite loop. The extension might confuse stdout output with
# responses
command << "1>&2"

warn("Ruby LSP> Running bundle install for the custom bundle. This may take a while...")
system(command)
run_bundle_install.call(dependencies, ".ruby-lsp/Gemfile")
33 changes: 28 additions & 5 deletions test/setup_bundler_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,22 @@

class SetupBundlerTest < Minitest::Test
def test_does_nothing_when_running_in_the_ruby_lsp
Object.any_instance.expects(:system).with(bundle_install_command)
run_script
refute_path_exists(".ruby-lsp")
end

def test_does_nothing_if_both_ruby_lsp_and_debug_are_in_the_bundle
Pathname.any_instance.expects(:basename).returns("fake_project")
Object.any_instance.expects(:system).with(bundle_install_command(update: false))
Bundler::LockfileParser.any_instance.expects(:dependencies).returns({ "ruby-lsp" => true, "debug" => true })
run_script
refute_path_exists(".ruby-lsp")
end

def test_creates_custom_bundle
Object.any_instance.expects(:system).with(bundle_install_command)
Pathname.any_instance.expects(:basename).returns("fake_project")
Object.any_instance.expects(:system).with(bundle_install_command(".ruby-lsp/Gemfile"))
Bundler::LockfileParser.any_instance.expects(:dependencies).returns({})
run_script

Expand All @@ -30,7 +34,8 @@ def test_creates_custom_bundle
end

def test_copies_gemfile_lock_when_modified
Object.any_instance.expects(:system).with(bundle_install_command)
Pathname.any_instance.expects(:basename).returns("fake_project")
Object.any_instance.expects(:system).with(bundle_install_command(".ruby-lsp/Gemfile"))
Bundler::LockfileParser.any_instance.expects(:dependencies).returns({})
FileUtils.mkdir(".ruby-lsp")
FileUtils.touch(".ruby-lsp/Gemfile.lock")
Expand All @@ -45,9 +50,22 @@ def test_copies_gemfile_lock_when_modified
FileUtils.rm_r(".ruby-lsp")
end

def test_does_not_copy_gemfile_lock_when_not_modified
Pathname.any_instance.expects(:basename).returns("fake_project")
Object.any_instance.expects(:system).with(bundle_install_command(".ruby-lsp/Gemfile"))
Bundler::LockfileParser.any_instance.expects(:dependencies).returns({})
FileUtils.mkdir(".ruby-lsp")
FileUtils.cp("Gemfile.lock", ".ruby-lsp/Gemfile.lock")

run_script
ensure
FileUtils.rm_r(".ruby-lsp")
end

def test_uses_absolute_bundle_path_for_bundle_install
Pathname.any_instance.expects(:basename).returns("fake_project")
Bundler.settings.set_global("path", "vendor/bundle")
Object.any_instance.expects(:system).with(bundle_install_command)
Object.any_instance.expects(:system).with(bundle_install_command(".ruby-lsp/Gemfile"))
Bundler::LockfileParser.any_instance.expects(:dependencies).returns({})
run_script
ensure
Expand All @@ -67,12 +85,17 @@ def run_script
$LOADED_FEATURES.delete(path)
end

def bundle_install_command
def bundle_install_command(bundle_gemfile = nil, update: true)
path = Bundler.settings["path"]

command = +""
command << "BUNDLE_PATH=#{File.expand_path(path, Dir.pwd)} " if path
command << "BUNDLE_GEMFILE=.ruby-lsp/Gemfile bundle install "
command << "BUNDLE_GEMFILE=#{bundle_gemfile} " if bundle_gemfile
command << if update
"bundle update ruby-lsp debug "
else
"bundle install "
end
command << "1>&2"
end
end

0 comments on commit 7d01600

Please sign in to comment.