diff options
| author | Edouard CHIN <chin.edouard@gmail.com> | 2025-08-12 20:33:03 -0400 |
|---|---|---|
| committer | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2025-09-03 23:38:37 +0900 |
| commit | 50d4622637b73715d20c5112f38d6fae0109c78f (patch) | |
| tree | 55020395124d880814178699998631c0def04c96 | |
| parent | 3b6c82ca4f6ee915e670c5be2342b10ed99c5844 (diff) | |
[rubygems/rubygems] Fix `bundle lock` regression when using `update` and `lockfile` flags:
- Ref #8917
- ### Problem
Prior to Bundler 2.5.6, running
`bundle lock --update foo --lockfile Gemfile_bumped.lock` would
update only the foo gem and write the lockfile to the
`Gemfile_bumped.lock`.
In Bundler 2.5.6 and above running the same command, updates
absolutely all gems.
This change is related to #7047
### Solution
We decided to expose the `write_lock` method rather than going
through a complex deprecation cycle of the `lock` method.
This commit applies the same business logic as prios to 2.5.6 where,
we build the definition using the existing lockfile, make changes to
the definition and dump it into the desired lockfile.
https://github.com/rubygems/rubygems/commit/c88f00c41d
| -rw-r--r-- | lib/bundler/cli/lock.rb | 10 | ||||
| -rw-r--r-- | lib/bundler/definition.rb | 76 | ||||
| -rw-r--r-- | spec/bundler/commands/lock_spec.rb | 38 |
3 files changed, 81 insertions, 43 deletions
diff --git a/lib/bundler/cli/lock.rb b/lib/bundler/cli/lock.rb index b60c82e3a1..2f78868936 100644 --- a/lib/bundler/cli/lock.rb +++ b/lib/bundler/cli/lock.rb @@ -35,11 +35,8 @@ module Bundler update = { bundler: bundler } end - file = options[:lockfile] - file = file ? Pathname.new(file).expand_path : Bundler.default_lockfile - Bundler.settings.temporary(frozen: false) do - definition = Bundler.definition(update, file) + definition = Bundler.definition(update, Bundler.default_lockfile) definition.add_checksums if options["add-checksums"] Bundler::CLI::Common.configure_gem_version_promoter(definition, options) if options[:update] @@ -71,8 +68,11 @@ module Bundler if print puts definition.to_lock else + file = options[:lockfile] + file = file ? Pathname.new(file).expand_path : Bundler.default_lockfile + puts "Writing lockfile to #{file}" - definition.lock + definition.write_lock(file, false) end end diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 52f9c6e125..6cbaa9c396 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -373,6 +373,44 @@ module Bundler write_lock(target_lockfile, preserve_unknown_sections) end + def write_lock(file, preserve_unknown_sections) + return if Definition.no_lock || file.nil? + + contents = to_lock + + # Convert to \r\n if the existing lock has them + # i.e., Windows with `git config core.autocrlf=true` + contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match?("\r\n") + + if @locked_bundler_version + locked_major = @locked_bundler_version.segments.first + current_major = bundler_version_to_lock.segments.first + + updating_major = locked_major < current_major + end + + preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler)) + + if File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections) + return if Bundler.frozen_bundle? + SharedHelpers.filesystem_access(file) { FileUtils.touch(file) } + return + end + + if Bundler.frozen_bundle? + Bundler.ui.error "Cannot write a changed lockfile while frozen." + return + end + + begin + SharedHelpers.filesystem_access(file) do |p| + File.open(p, "wb") {|f| f.puts(contents) } + end + rescue ReadOnlyFileSystemError + raise ProductionError, lockfile_changes_summary("file system is read-only") + end + end + def locked_ruby_version return unless ruby_version if @unlocking_ruby || !@locked_ruby_version @@ -574,44 +612,6 @@ module Bundler lockfile && File.exist?(lockfile) end - def write_lock(file, preserve_unknown_sections) - return if Definition.no_lock || file.nil? - - contents = to_lock - - # Convert to \r\n if the existing lock has them - # i.e., Windows with `git config core.autocrlf=true` - contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match?("\r\n") - - if @locked_bundler_version - locked_major = @locked_bundler_version.segments.first - current_major = bundler_version_to_lock.segments.first - - updating_major = locked_major < current_major - end - - preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler)) - - if File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections) - return if Bundler.frozen_bundle? - SharedHelpers.filesystem_access(file) { FileUtils.touch(file) } - return - end - - if Bundler.frozen_bundle? - Bundler.ui.error "Cannot write a changed lockfile while frozen." - return - end - - begin - SharedHelpers.filesystem_access(file) do |p| - File.open(p, "wb") {|f| f.puts(contents) } - end - rescue ReadOnlyFileSystemError - raise ProductionError, lockfile_changes_summary("file system is read-only") - end - end - def resolver @resolver ||= new_resolver(resolution_base) end diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb index 19c1a5ca8b..5a31d1733a 100644 --- a/spec/bundler/commands/lock_spec.rb +++ b/spec/bundler/commands/lock_spec.rb @@ -311,6 +311,44 @@ RSpec.describe "bundle lock" do expect { read_lockfile }.to raise_error(Errno::ENOENT) end + it "updates a specific gem and write to a custom location" do + build_repo4 do + build_gem "uri", %w[1.0.2 1.0.3] + build_gem "warning", %w[1.4.0 1.5.0] + end + + gemfile <<~G + source "https://gem.repo4" + + gem "uri" + gem "warning" + G + + lockfile <<~L + GEM + remote: https://gem.repo4 + specs: + uri (1.0.2) + warning (1.4.0) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + uri + warning + + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle "lock --update uri --lockfile=lock" + + lockfile_content = read_lockfile("lock") + expect(lockfile_content).to include("uri (1.0.3)") + expect(lockfile_content).to include("warning (1.4.0)") + end + it "writes to custom location using --lockfile when a default lockfile is present" do gemfile_with_rails_weakling_and_foo_from_repo4 |
