From 1bb0f26b798b9a754828c021ddd54dc119abb3cb Mon Sep 17 00:00:00 2001 From: Cody Cutrer Date: Thu, 5 Oct 2023 10:19:59 -0600 Subject: [PATCH] fix double-sync if the preamble already exists, injecting the preamble would evaluate the gemfile, and recursively load the plugin (and plugins.rb). avoid the problems of that by only adding our hooks in multilock.rb, which will only be required once --- .rspec | 1 + .rspec-local | 1 - lib/bundler/multilock.rb | 30 ++++++++++++++++++++++++++++++ plugins.rb | 27 --------------------------- spec/bundler/multilock_spec.rb | 31 +++++++++++++++++++++++++++---- spec/spec_helper.rb | 2 ++ 6 files changed, 60 insertions(+), 32 deletions(-) create mode 100644 .rspec delete mode 100644 .rspec-local diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..c99d2e7 --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--require spec_helper diff --git a/.rspec-local b/.rspec-local deleted file mode 100644 index 4e1e0d2..0000000 --- a/.rspec-local +++ /dev/null @@ -1 +0,0 @@ ---color diff --git a/lib/bundler/multilock.rb b/lib/bundler/multilock.rb index b20007e..be9740f 100644 --- a/lib/bundler/multilock.rb +++ b/lib/bundler/multilock.rb @@ -146,6 +146,7 @@ def after_install_all(install: true) require "tempfile" require_relative "multilock/lockfile_generator" + Bundler.ui.debug("Syncing to alternate lockfiles") Bundler.ui.info "" default_lockfile_contents = Bundler.default_lockfile.read.freeze @@ -321,6 +322,8 @@ def loaded? # @!visibility private def inject_preamble + Bundler.ui.debug("Injecting multilock preamble") + minor_version = Gem::Version.new(::Bundler::Multilock::VERSION).segments[0..1].join(".") bundle_preamble1_match = %(plugin "bundler-multilock") bundle_preamble1 = <<~RUBY @@ -448,3 +451,30 @@ def write_lockfile(lockfile_definition, lockfile, install:, dependency_changes: end Bundler::Multilock.inject_preamble unless Bundler::Multilock.loaded? + +# this is terrible, but we can't prepend into these modules because we only load +# _inside_ of the CLI commands already running +if defined?(Bundler::CLI::Check) + require_relative "lib/bundler/multilock/check" + at_exit do + next unless $!.nil? + next if $!.is_a?(SystemExit) && !$!.success? + + next if Bundler::Multilock::Check.run + + Bundler.ui.warn("You can attempt to fix by running `bundle install`") + exit 1 + end +end +if defined?(Bundler::CLI::Lock) + at_exit do + next unless $!.nil? + next if $!.is_a?(SystemExit) && !$!.success? + + Bundler::Multilock.after_install_all(install: false) + end +end + +Bundler::Plugin.add_hook(Bundler::Plugin::Events::GEM_AFTER_INSTALL_ALL) do |_| + Bundler::Multilock.after_install_all +end diff --git a/plugins.rb b/plugins.rb index 35ae7a2..8630833 100644 --- a/plugins.rb +++ b/plugins.rb @@ -19,30 +19,3 @@ # require_relative "lib/bundler/multilock" - -# this is terrible, but we can't prepend into these modules because we only load -# _inside_ of the CLI commands already running -if defined?(Bundler::CLI::Check) - require_relative "lib/bundler/multilock/check" - at_exit do - next unless $!.nil? - next if $!.is_a?(SystemExit) && !$!.success? - - next if Bundler::Multilock::Check.run - - Bundler.ui.warn("You can attempt to fix by running `bundle install`") - exit 1 - end -end -if defined?(Bundler::CLI::Lock) - at_exit do - next unless $!.nil? - next if $!.is_a?(SystemExit) && !$!.success? - - Bundler::Multilock.after_install_all(install: false) - end -end - -Bundler::Plugin.add_hook(Bundler::Plugin::Events::GEM_AFTER_INSTALL_ALL) do |_| - Bundler::Multilock.after_install_all -end diff --git a/spec/bundler/multilock_spec.rb b/spec/bundler/multilock_spec.rb index c26219c..a9a5c86 100644 --- a/spec/bundler/multilock_spec.rb +++ b/spec/bundler/multilock_spec.rb @@ -192,7 +192,7 @@ gem "concurrent-ruby", "1.2.2" RUBY - create_local_gem("test_local", "") + create_local_gem("test_local") invoke_bundler("install") @@ -611,11 +611,32 @@ end end + it "only syncs once per lockfile" do + with_gemfile(<<~RUBY) do + gemspec + + lockfile("rails-7.0", default: true) do + gem "activesupport", "~> 7.0.0" + end + RUBY + create_local_gem("test", subdirectory: false) + invoke_bundler("install") + output = invoke_bundler("install", env: { "DEBUG" => "1" }) + + expect(output.split("\n").grep(/Syncing to alternate lockfiles/).length).to be 1 + end + end + private - def create_local_gem(name, content) - FileUtils.mkdir_p(name) - File.write("#{name}/#{name}.gemspec", <<~RUBY) + def create_local_gem(name, content = "", subdirectory: true) + if subdirectory + FileUtils.mkdir_p(name) + subdirectory = "#{name}/" + else + subdirectory = nil + end + File.write("#{subdirectory}#{name}.gemspec", <<~RUBY) Gem::Specification.new do |spec| spec.name = #{name.inspect} spec.version = "0.0.1" @@ -626,6 +647,8 @@ def create_local_gem(name, content) end RUBY + return unless subdirectory + File.write("#{name}/Gemfile", <<~RUBY) source "https://rubygems.org" diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b0af0ef..723ef9a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require "debug" + RSpec.configure do |config| config.expect_with :rspec do |c| c.max_formatted_output_length = nil