From ca9c0f91311e01625e10272798ff2cc831bbee60 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 11 Sep 2025 17:27:02 +0900 Subject: [PATCH 01/18] [rubygems/rubygems] Use File#chmod rather than FileUtils.chmod We already have the open file descriptor, so we can avoid the overhead of resolving the filepath (as well as the overhead inside `FileUtils`) by just calling `chmod` on the file descriptor itself. https://github.com/rubygems/rubygems/commit/60c14bbeee --- lib/rubygems/package.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb index c855423ed764de..99be691ec7f7ea 100644 --- a/lib/rubygems/package.rb +++ b/lib/rubygems/package.rb @@ -451,8 +451,14 @@ def extract_tar_gz(io, destination_dir, pattern = "*") # :nodoc: end if entry.file? - File.open(destination, "wb") {|out| copy_stream(entry, out) } - FileUtils.chmod file_mode(entry.header.mode) & ~File.umask, destination + File.open(destination, "wb") do |out| + copy_stream(entry, out) + # Flush needs to happen before chmod because there could be data + # in the IO buffer that needs to be written, and that could be + # written after the chmod (on close) which would mess up the perms + out.flush + out.chmod file_mode(entry.header.mode) & ~File.umask + end end verbose destination From a71b339477a291a93fc9f83266eaad3423df6acc Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 12 Sep 2025 16:29:51 +0900 Subject: [PATCH 02/18] [rubygems/rubygems] Pass the file size to IO.copy_stream When extracting tar files, the tar header actually knows the exact size of the file we need to extract. Before this commit, we would read the file from the tar file until it returned `nil`. We can be a little more efficient when copying by passing the size to copy_stream https://github.com/rubygems/rubygems/commit/8927533b0a --- lib/rubygems/package.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb index 99be691ec7f7ea..08730402062f93 100644 --- a/lib/rubygems/package.rb +++ b/lib/rubygems/package.rb @@ -267,7 +267,7 @@ def add_files(tar) # :nodoc: tar.add_file_simple file, stat.mode, stat.size do |dst_io| File.open file, "rb" do |src_io| - copy_stream(src_io, dst_io) + copy_stream(src_io, dst_io, stat.size) end end end @@ -452,7 +452,7 @@ def extract_tar_gz(io, destination_dir, pattern = "*") # :nodoc: if entry.file? File.open(destination, "wb") do |out| - copy_stream(entry, out) + copy_stream(entry, out, entry.size) # Flush needs to happen before chmod because there could be data # in the IO buffer that needs to be written, and that could be # written after the chmod (on close) which would mess up the perms @@ -721,12 +721,12 @@ def verify_gz(entry) # :nodoc: end if RUBY_ENGINE == "truffleruby" - def copy_stream(src, dst) # :nodoc: - dst.write src.read + def copy_stream(src, dst, size) # :nodoc: + dst.write src.read(size) end else - def copy_stream(src, dst) # :nodoc: - IO.copy_stream(src, dst) + def copy_stream(src, dst, size) # :nodoc: + IO.copy_stream(src, dst, size) end end From 9b45a25c4897b0e9565dad9fa7a0765b68732679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= <2887858+deivid-rodriguez@users.noreply.github.com> Date: Tue, 9 Sep 2025 19:18:31 +0200 Subject: [PATCH 03/18] [rubygems/rubygems] Fix `rubocop` config removal message In Bundler 4, configuration will no longer be updated. https://github.com/rubygems/rubygems/commit/33a4718d7a --- lib/bundler/cli/gem.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb index 5b71d71c67133b..b63617d53604c3 100644 --- a/lib/bundler/cli/gem.rb +++ b/lib/bundler/cli/gem.rb @@ -431,7 +431,7 @@ def deprecated_rubocop_option elsif !Bundler.settings["gem.rubocop"].nil? Bundler::SharedHelpers.major_deprecation 2, "config gem.rubocop is deprecated; we've updated your config to use gem.linter instead", - removed_message: "config gem.rubocop has been removed; we've updated your config to use gem.linter instead" + removed_message: "config gem.rubocop has been removed; use gem.linter instead" Bundler.settings["gem.rubocop"] ? "rubocop" : false end end From 1c7fd141f911d97d1f5a2737d0a36cb608100bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= <2887858+deivid-rodriguez@users.noreply.github.com> Date: Tue, 9 Sep 2025 19:19:15 +0200 Subject: [PATCH 04/18] [rubygems/rubygems] Fix `--no-rubocop` deprecation message https://github.com/rubygems/rubygems/commit/2c16b0e11e --- lib/bundler/cli/gem.rb | 4 ++-- spec/bundler/other/major_deprecation_spec.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb index b63617d53604c3..71207bc5da7548 100644 --- a/lib/bundler/cli/gem.rb +++ b/lib/bundler/cli/gem.rb @@ -424,8 +424,8 @@ def deprecated_rubocop_option "rubocop" else Bundler::SharedHelpers.major_deprecation 2, - "--no-rubocop is deprecated, use --linter", - removed_message: "--no-rubocop has been removed, use --linter" + "--no-rubocop is deprecated, use --no-linter", + removed_message: "--no-rubocop has been removed, use --no-linter" false end elsif !Bundler.settings["gem.rubocop"].nil? diff --git a/spec/bundler/other/major_deprecation_spec.rb b/spec/bundler/other/major_deprecation_spec.rb index 65fcd43c393dfa..0a8d1d112eb336 100644 --- a/spec/bundler/other/major_deprecation_spec.rb +++ b/spec/bundler/other/major_deprecation_spec.rb @@ -735,7 +735,7 @@ it "prints a deprecation warning" do expect(deprecations).to include \ - "--no-rubocop is deprecated, use --linter" + "--no-rubocop is deprecated, use --no-linter" end end From 190a235464398c5b8f556cbf221bfaec8680e3b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= <2887858+deivid-rodriguez@users.noreply.github.com> Date: Tue, 9 Sep 2025 19:19:23 +0200 Subject: [PATCH 05/18] [rubygems/rubygems] Complete rubocop flags and settings removal If the CLI flags are used, we abort early as usual. As per the settings, I decided to ignore them. We've been migrating them automatically to the new name for a long time and we don't yet have a standard way to deprecate and remove settings (we should probably use the existing setting validators). So I think it's fine for now to do what we normally do (ignore the setting). https://github.com/rubygems/rubygems/commit/8311de6e69 --- lib/bundler/cli.rb | 6 +- lib/bundler/cli/gem.rb | 22 ----- lib/bundler/man/bundle-gem.1 | 3 - lib/bundler/man/bundle-gem.1.ronn | 3 - spec/bundler/commands/newgem_spec.rb | 99 -------------------- spec/bundler/other/major_deprecation_spec.rb | 36 ++----- 6 files changed, 12 insertions(+), 157 deletions(-) diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index e59265e8b2ed13..8151de713ae1f7 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -525,7 +525,7 @@ def viz method_option :ext, type: :string, banner: "Generate the boilerplate for C extension code.", enum: EXTENSIONS method_option :git, type: :boolean, default: true, banner: "Initialize a git repo inside your library." method_option :mit, type: :boolean, banner: "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`." - method_option :rubocop, type: :boolean, banner: "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`." + method_option :rubocop, type: :boolean, banner: "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true` (removed)." method_option :changelog, type: :boolean, banner: "Generate changelog file. Set a default with `bundle config set --global gem.changelog true`." method_option :test, type: :string, lazy_default: Bundler.settings["gem.test"] || "", aliases: "-t", banner: "Use the specified test framework for your library", enum: %w[rspec minitest test-unit], desc: "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`." method_option :ci, type: :string, lazy_default: Bundler.settings["gem.ci"] || "", enum: %w[github gitlab circle], banner: "Generate CI configuration, either GitHub Actions, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|gitlab|circle)`" @@ -535,6 +535,10 @@ def viz def gem(name) require_relative "cli/gem" + + raise InvalidOption, "--rubocop has been removed, use --linter=rubocop" if ARGV.include?("--rubocop") + raise InvalidOption, "--no-rubocop has been removed, use --no-linter" if ARGV.include?("--no-rubocop") + cmd_args = args + [self] cmd_args.unshift(options) diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb index 71207bc5da7548..56d23d9e9fc293 100644 --- a/lib/bundler/cli/gem.rb +++ b/lib/bundler/cli/gem.rb @@ -382,7 +382,6 @@ def ask_and_set_ci def ask_and_set_linter return if skip?(:linter) linter_template = options[:linter] || Bundler.settings["gem.linter"] - linter_template = deprecated_rubocop_option if linter_template.nil? if linter_template.to_s.empty? Bundler.ui.info "\nDo you want to add a code linter and formatter to your gem? " \ @@ -415,27 +414,6 @@ def ask_and_set_linter linter_template end - def deprecated_rubocop_option - if !options[:rubocop].nil? - if options[:rubocop] - Bundler::SharedHelpers.major_deprecation 2, - "--rubocop is deprecated, use --linter=rubocop", - removed_message: "--rubocop has been removed, use --linter=rubocop" - "rubocop" - else - Bundler::SharedHelpers.major_deprecation 2, - "--no-rubocop is deprecated, use --no-linter", - removed_message: "--no-rubocop has been removed, use --no-linter" - false - end - elsif !Bundler.settings["gem.rubocop"].nil? - Bundler::SharedHelpers.major_deprecation 2, - "config gem.rubocop is deprecated; we've updated your config to use gem.linter instead", - removed_message: "config gem.rubocop has been removed; use gem.linter instead" - Bundler.settings["gem.rubocop"] ? "rubocop" : false - end - end - def bundler_dependency_version v = Gem::Version.new(Bundler::VERSION) req = v.segments[0..1] diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1 index 884badb584ebd2..670a69d67e317b 100644 --- a/lib/bundler/man/bundle-gem.1 +++ b/lib/bundler/man/bundle-gem.1 @@ -92,9 +92,6 @@ When Bundler is unconfigured, an interactive prompt will be displayed and the an \fB\-\-no\-linter\fR Do not add a linter (overrides \fB\-\-linter\fR specified in the global config)\. .TP -\fB\-\-rubocop\fR -Add rubocop to the generated Rakefile and gemspec\. Set a default with \fBbundle config set \-\-global gem\.rubocop true\fR\. -.TP \fB\-\-edit=EDIT\fR, \fB\-e=EDIT\fR Open the resulting GEM_NAME\.gemspec in EDIT, or the default editor if not specified\. The default is \fB$BUNDLER_EDITOR\fR, \fB$VISUAL\fR, or \fB$EDITOR\fR\. .TP diff --git a/lib/bundler/man/bundle-gem.1.ronn b/lib/bundler/man/bundle-gem.1.ronn index b1327aa3422b86..b71bde9f6506f1 100644 --- a/lib/bundler/man/bundle-gem.1.ronn +++ b/lib/bundler/man/bundle-gem.1.ronn @@ -135,9 +135,6 @@ configuration file using the following names: * `--no-linter`: Do not add a linter (overrides `--linter` specified in the global config). -* `--rubocop`: - Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`. - * `--edit=EDIT`, `-e=EDIT`: Open the resulting GEM_NAME.gemspec in EDIT, or the default editor if not specified. The default is `$BUNDLER_EDITOR`, `$VISUAL`, or `$EDITOR`. diff --git a/spec/bundler/commands/newgem_spec.rb b/spec/bundler/commands/newgem_spec.rb index 40bc1c3ff48641..0b13344f994154 100644 --- a/spec/bundler/commands/newgem_spec.rb +++ b/spec/bundler/commands/newgem_spec.rb @@ -175,75 +175,6 @@ def ignore_paths end end - shared_examples_for "--rubocop flag" do - context "is deprecated" do - before do - global_config "BUNDLE_GEM__LINTER" => nil - bundle "gem #{gem_name} --rubocop" - end - - it "generates a gem skeleton with rubocop" do - gem_skeleton_assertions - expect(bundled_app("#{gem_name}/Rakefile")).to read_as( - include("# frozen_string_literal: true"). - and(include('require "rubocop/rake_task"'). - and(include("RuboCop::RakeTask.new"). - and(match(/default:.+:rubocop/)))) - ) - end - - it "includes rubocop in generated Gemfile" do - allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) - builder = Bundler::Dsl.new - builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile")) - builder.dependencies - rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" } - expect(rubocop_dep).not_to be_nil - end - - it "generates a default .rubocop.yml" do - expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist - end - - it "includes .rubocop.yml into ignore list" do - expect(ignore_paths).to include(".rubocop.yml") - end - end - end - - shared_examples_for "--no-rubocop flag" do - context "is deprecated" do - define_negated_matcher :exclude, :include - - before do - bundle "gem #{gem_name} --no-rubocop" - end - - it "generates a gem skeleton without rubocop" do - gem_skeleton_assertions - expect(bundled_app("#{gem_name}/Rakefile")).to read_as(exclude("rubocop")) - expect(bundled_app("#{gem_name}/#{gem_name}.gemspec")).to read_as(exclude("rubocop")) - end - - it "does not include rubocop in generated Gemfile" do - allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) - builder = Bundler::Dsl.new - builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile")) - builder.dependencies - rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" } - expect(rubocop_dep).to be_nil - end - - it "doesn't generate a default .rubocop.yml" do - expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist - end - - it "does not add .rubocop.yml into ignore list" do - expect(ignore_paths).not_to include(".rubocop.yml") - end - end - end - shared_examples_for "--linter=rubocop flag" do before do bundle "gem #{gem_name} --linter=rubocop" @@ -1335,32 +1266,6 @@ def create_temporary_dir(dir) end end - context "gem.rubocop setting set to true" do - before do - global_config "BUNDLE_GEM__LINTER" => nil - bundle "config set gem.rubocop true" - bundle "gem #{gem_name}" - end - - it "generates rubocop config" do - expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist - end - - it "includes .rubocop.yml into ignore list" do - expect(ignore_paths).to include(".rubocop.yml") - end - - it "unsets gem.rubocop" do - bundle "config gem.rubocop" - expect(out).to include("You have not configured a value for `gem.rubocop`") - end - - it "sets gem.linter=rubocop instead" do - bundle "config gem.linter" - expect(out).to match(/Set for the current user .*: "rubocop"/) - end - end - context "gem.linter set to rubocop and --linter with no arguments" do before do bundle "config set gem.linter rubocop" @@ -1558,8 +1463,6 @@ def create_temporary_dir(dir) it_behaves_like "--linter=rubocop flag" it_behaves_like "--linter=standard flag" it_behaves_like "--no-linter flag" - it_behaves_like "--rubocop flag" - it_behaves_like "--no-rubocop flag" end context "with rubocop option in bundle config settings set to false" do @@ -1569,8 +1472,6 @@ def create_temporary_dir(dir) it_behaves_like "--linter=rubocop flag" it_behaves_like "--linter=standard flag" it_behaves_like "--no-linter flag" - it_behaves_like "--rubocop flag" - it_behaves_like "--no-rubocop flag" end context "with linter option in bundle config settings set to rubocop" do diff --git a/spec/bundler/other/major_deprecation_spec.rb b/spec/bundler/other/major_deprecation_spec.rb index 0a8d1d112eb336..bf0fca5ddd6baa 100644 --- a/spec/bundler/other/major_deprecation_spec.rb +++ b/spec/bundler/other/major_deprecation_spec.rb @@ -711,7 +711,7 @@ pending "fails with a helpful message", bundler: "4" end - describe "deprecating rubocop" do + describe "removing rubocop" do before do global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__CHANGELOG" => "false" @@ -722,9 +722,9 @@ bundle "gem my_new_gem --rubocop", raise_on_error: false end - it "prints a deprecation warning" do - expect(deprecations).to include \ - "--rubocop is deprecated, use --linter=rubocop" + it "prints an error" do + expect(err).to include \ + "--rubocop has been removed, use --linter=rubocop" end end @@ -733,31 +733,9 @@ bundle "gem my_new_gem --no-rubocop", raise_on_error: false end - it "prints a deprecation warning" do - expect(deprecations).to include \ - "--no-rubocop is deprecated, use --no-linter" - end - end - - context "bundle gem with gem.rubocop set to true" do - before do - bundle "gem my_new_gem", env: { "BUNDLE_GEM__RUBOCOP" => "true" }, raise_on_error: false - end - - it "prints a deprecation warning" do - expect(deprecations).to include \ - "config gem.rubocop is deprecated; we've updated your config to use gem.linter instead" - end - end - - context "bundle gem with gem.rubocop set to false" do - before do - bundle "gem my_new_gem", env: { "BUNDLE_GEM__RUBOCOP" => "false" }, raise_on_error: false - end - - it "prints a deprecation warning" do - expect(deprecations).to include \ - "config gem.rubocop is deprecated; we've updated your config to use gem.linter instead" + it "prints an error" do + expect(err).to include \ + "--no-rubocop has been removed, use --no-linter" end end end From 6b0af3135264351d0bbaaf5cf6b207a9c84b6e76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= <2887858+deivid-rodriguez@users.noreply.github.com> Date: Tue, 9 Sep 2025 19:18:54 +0200 Subject: [PATCH 06/18] [rubygems/rubygems] Remove `allow_offline_install` setting And let the feature always be enabled, so I'm not sure why we'd need this configurable. https://github.com/rubygems/rubygems/commit/5a27f0c1e3 --- lib/bundler/feature_flag.rb | 1 - lib/bundler/fetcher/compact_index.rb | 2 +- lib/bundler/man/bundle-config.1 | 3 --- lib/bundler/man/bundle-config.1.ronn | 2 -- lib/bundler/settings.rb | 1 - lib/bundler/source/git.rb | 1 - spec/bundler/install/allow_offline_install_spec.rb | 6 +----- 7 files changed, 2 insertions(+), 14 deletions(-) diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb index ec61dd521184c6..73e6ddcc68beb5 100644 --- a/lib/bundler/feature_flag.rb +++ b/lib/bundler/feature_flag.rb @@ -27,7 +27,6 @@ def self.settings_method(name, key, &default) (1..10).each {|v| define_method("bundler_#{v}_mode?") { @major_version >= v } } - settings_flag(:allow_offline_install) { bundler_4_mode? } settings_flag(:cache_all) { bundler_4_mode? } settings_flag(:global_gem_cache) { bundler_5_mode? } settings_flag(:lockfile_checksums) { bundler_4_mode? } diff --git a/lib/bundler/fetcher/compact_index.rb b/lib/bundler/fetcher/compact_index.rb index 6c82d570114cde..52168111fea775 100644 --- a/lib/bundler/fetcher/compact_index.rb +++ b/lib/bundler/fetcher/compact_index.rb @@ -110,7 +110,7 @@ def client_fetcher def call(path, headers) fetcher.downloader.fetch(fetcher.fetch_uri + path, headers) rescue NetworkDownError => e - raise unless Bundler.feature_flag.allow_offline_install? && headers["If-None-Match"] + raise unless headers["If-None-Match"] ui.warn "Using the cached data for the new index because of a network error: #{e}" Gem::Net::HTTPNotModified.new(nil, nil, nil) end diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index e3ce81155ca2e1..b7276daa89195a 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -70,9 +70,6 @@ Any periods in the configuration keys must be replaced with two underscores when .SH "LIST OF AVAILABLE KEYS" The following is a list of all configuration keys and their purpose\. You can learn more about their operation in bundle install(1) \fIbundle\-install\.1\.html\fR\. .TP -\fBallow_offline_install\fR (\fBBUNDLE_ALLOW_OFFLINE_INSTALL\fR) -Allow Bundler to use cached data when installing without network access\. -.TP \fBauto_install\fR (\fBBUNDLE_AUTO_INSTALL\fR) Automatically run \fBbundle install\fR when gems are missing\. .TP diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index b2f0f462f83c8f..18260c6c931f09 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -106,8 +106,6 @@ the environment variable `BUNDLE_LOCAL__RACK`. The following is a list of all configuration keys and their purpose. You can learn more about their operation in [bundle install(1)](bundle-install.1.html). -* `allow_offline_install` (`BUNDLE_ALLOW_OFFLINE_INSTALL`): - Allow Bundler to use cached data when installing without network access. * `auto_install` (`BUNDLE_AUTO_INSTALL`): Automatically run `bundle install` when gems are missing. * `bin` (`BUNDLE_BIN`): diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index cefbf0b1f0691e..ecc3ee8080a239 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -7,7 +7,6 @@ class Settings autoload :Validator, File.expand_path("settings/validator", __dir__) BOOL_KEYS = %w[ - allow_offline_install auto_install cache_all cache_all_platforms diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb index d57944ee1244d9..ddea7714a16f5d 100644 --- a/lib/bundler/source/git.rb +++ b/lib/bundler/source/git.rb @@ -416,7 +416,6 @@ def git_proxy def fetch git_proxy.checkout rescue GitError => e - raise unless Bundler.feature_flag.allow_offline_install? Bundler.ui.warn "Using cached git data because of network errors:\n#{e}" end diff --git a/spec/bundler/install/allow_offline_install_spec.rb b/spec/bundler/install/allow_offline_install_spec.rb index abe6009c08e4d3..4889dbc943551a 100644 --- a/spec/bundler/install/allow_offline_install_spec.rb +++ b/spec/bundler/install/allow_offline_install_spec.rb @@ -1,10 +1,6 @@ # frozen_string_literal: true -RSpec.describe "bundle install with :allow_offline_install" do - before do - bundle "config set allow_offline_install true" - end - +RSpec.describe "bundle install allows offline install" do context "with no cached data locally" do it "still installs" do install_gemfile <<-G, artifice: "compact_index" From 12aa9e7457458245c9452ca5f786f6191742edf2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 13 Sep 2025 07:34:53 +0900 Subject: [PATCH 07/18] [rubygems/rubygems] Use `IO.copy_stream` with IO object directly Before this patch we would use `IO.copy_stream` with the tar entry object rather than just straight to the IO. That means every time copy_stream wanted data, we would have to proxy the call. The reason we did this is because every tar entry object _shares_ the same IO object, and previous to https://github.com/rubygems/rubygems/commit/8927533b0a47 we would call `IO.copy_stream` _without_ a size. Without passing a size, copy_stream will just read until there is nothing left to read, so these proxy object emulate finding "the end of the file" (where "end of file" means "end of tar chunk"). Without emulating this "end of file" behavior, copy_stream would just keep reading past the end of the tar chunk. However, now that we're passing the size to copy_stream, we can bypass the proxy object overhead and just use the IO object directly because copy_stream knows exactly the number of bytes it needs to read and will stop when it reaches the goal. https://github.com/rubygems/rubygems/commit/857002c135 --- lib/rubygems/package.rb | 2 +- lib/rubygems/package/tar_reader.rb | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb index 08730402062f93..a8eba81ea06f4a 100644 --- a/lib/rubygems/package.rb +++ b/lib/rubygems/package.rb @@ -452,7 +452,7 @@ def extract_tar_gz(io, destination_dir, pattern = "*") # :nodoc: if entry.file? File.open(destination, "wb") do |out| - copy_stream(entry, out, entry.size) + copy_stream(tar.io, out, entry.size) # Flush needs to happen before chmod because there could be data # in the IO buffer that needs to be written, and that could be # written after the chmod (on close) which would mess up the perms diff --git a/lib/rubygems/package/tar_reader.rb b/lib/rubygems/package/tar_reader.rb index 25f9b2f9450a95..b66a8a62bc9f75 100644 --- a/lib/rubygems/package/tar_reader.rb +++ b/lib/rubygems/package/tar_reader.rb @@ -30,6 +30,8 @@ def self.new(io) nil end + attr_reader :io # :nodoc: + ## # Creates a new tar file reader on +io+ which needs to respond to #pos, # #eof?, #read, #getc and #pos= From 0a5a0eeab45fb2db176b681159b328b3fdf95408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= <2887858+deivid-rodriguez@users.noreply.github.com> Date: Wed, 10 Sep 2025 10:32:26 +0200 Subject: [PATCH 08/18] [rubygems/rubygems] Handle locked sources more simillarly to locked specs https://github.com/rubygems/rubygems/commit/0a2f5ed717 --- lib/bundler/definition.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index e177b6e39673c7..bd424609c9968c 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -107,6 +107,7 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti @locked_ruby_version = @locked_gems.ruby_version @locked_deps = @locked_gems.dependencies @originally_locked_specs = SpecSet.new(@locked_gems.specs) + @originally_locked_sources = @locked_gems.sources @locked_checksums = @locked_gems.checksums if @unlocking_all @@ -114,7 +115,7 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti @locked_sources = [] else @locked_specs = @originally_locked_specs - @locked_sources = @locked_gems.sources + @locked_sources = @originally_locked_sources end else @locked_gems = nil @@ -123,8 +124,9 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti @platforms = [] @locked_deps = {} @locked_specs = SpecSet.new([]) - @originally_locked_specs = @locked_specs @locked_sources = [] + @originally_locked_specs = @locked_specs + @originally_locked_sources = @locked_sources @locked_checksums = Bundler.feature_flag.lockfile_checksums? end @@ -954,7 +956,7 @@ def converge_sources sources.all_sources.each do |source| # has to be done separately, because we want to keep the locked checksum # store for a source, even when doing a full update - if @locked_checksums && @locked_gems && locked_source = @locked_gems.sources.find {|s| s == source && !s.equal?(source) } + if @locked_checksums && @locked_gems && locked_source = @originally_locked_sources.find {|s| s == source && !s.equal?(source) } source.checksum_store.merge!(locked_source.checksum_store) end # If the source is unlockable and the current command allows an unlock of @@ -1137,7 +1139,7 @@ def lockfiles_equal?(current, proposed, preserve_unknown_sections) end def additional_base_requirements_to_prevent_downgrades(resolution_base) - return resolution_base unless @locked_gems && !sources.expired_sources?(@locked_gems.sources) + return resolution_base unless @locked_gems && !sources.expired_sources?(@originally_locked_sources) @originally_locked_specs.each do |locked_spec| next if locked_spec.source.is_a?(Source::Path) || locked_spec.source_changed? From 26f9911c7190d5343fb775f54fc2472cd6fe632b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= <2887858+deivid-rodriguez@users.noreply.github.com> Date: Wed, 10 Sep 2025 10:43:30 +0200 Subject: [PATCH 09/18] [rubygems/rubygems] Multisource checks are only relevant when there's a lockfile https://github.com/rubygems/rubygems/commit/4c110d3289 --- lib/bundler/definition.rb | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index bd424609c9968c..dbfed9f67f428a 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -117,6 +117,19 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti @locked_specs = @originally_locked_specs @locked_sources = @originally_locked_sources end + + locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } + @multisource_allowed = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes? && Bundler.frozen_bundle? + + if @multisource_allowed + unless sources.aggregate_global_source? + msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure." + + Bundler::SharedHelpers.major_deprecation 2, msg + end + + @sources.merged_gem_lockfile_sections!(locked_gem_sources.first) + end else @locked_gems = nil @locked_platforms = [] @@ -130,19 +143,6 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti @locked_checksums = Bundler.feature_flag.lockfile_checksums? end - locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } - @multisource_allowed = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes? && Bundler.frozen_bundle? - - if @multisource_allowed - unless sources.aggregate_global_source? - msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure." - - Bundler::SharedHelpers.major_deprecation 2, msg - end - - @sources.merged_gem_lockfile_sections!(locked_gem_sources.first) - end - @unlocking_ruby ||= if @ruby_version && locked_ruby_version_object @ruby_version.diff(locked_ruby_version_object) end From 9878060181d2592c26dce0c314a8b4b6e4826646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= <2887858+deivid-rodriguez@users.noreply.github.com> Date: Wed, 10 Sep 2025 10:55:06 +0200 Subject: [PATCH 10/18] [rubygems/rubygems] Simplify an edge case of not adding lower bound requirements https://github.com/rubygems/rubygems/commit/1bc5e74281 --- lib/bundler/definition.rb | 8 ++++---- lib/bundler/source_list.rb | 21 +-------------------- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index dbfed9f67f428a..ab488e046b0ac8 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -118,10 +118,10 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti @locked_sources = @originally_locked_sources end - locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } - @multisource_allowed = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes? && Bundler.frozen_bundle? + locked_gem_sources = @originally_locked_sources.select {|s| s.is_a?(Source::Rubygems) } + @multisource_lockfile = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes? - if @multisource_allowed + if @multisource_lockfile && Bundler.frozen_bundle? unless sources.aggregate_global_source? msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure." @@ -1139,7 +1139,7 @@ def lockfiles_equal?(current, proposed, preserve_unknown_sections) end def additional_base_requirements_to_prevent_downgrades(resolution_base) - return resolution_base unless @locked_gems && !sources.expired_sources?(@originally_locked_sources) + return resolution_base unless @locked_gems && !@multisource_lockfile @originally_locked_specs.each do |locked_spec| next if locked_spec.source.is_a?(Source::Path) || locked_spec.source_changed? diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb index 2f16281045a5e8..70b74f6a91cf32 100644 --- a/lib/bundler/source_list.rb +++ b/lib/bundler/source_list.rb @@ -129,16 +129,7 @@ def replace_sources!(replacement_sources) @rubygems_sources, @path_sources, @git_sources, @plugin_sources = map_sources(replacement_sources) @global_rubygems_source = global_replacement_source(replacement_sources) - different_sources?(lock_sources, replacement_sources) - end - - # Returns true if there are changes - def expired_sources?(replacement_sources) - return false if replacement_sources.empty? - - lock_sources = dup_with_replaced_sources(replacement_sources).lock_sources - - different_sources?(lock_sources, replacement_sources) + !equivalent_sources?(lock_sources, replacement_sources) end def prefer_local! @@ -165,12 +156,6 @@ def remote! private - def dup_with_replaced_sources(replacement_sources) - new_source_list = dup - new_source_list.replace_sources!(replacement_sources) - new_source_list - end - def map_sources(replacement_sources) rubygems = @rubygems_sources.map do |source| replace_rubygems_source(replacement_sources, source) @@ -224,10 +209,6 @@ def replace_path_source(replacement_sources, gemfile_source) end end - def different_sources?(lock_sources, replacement_sources) - !equivalent_sources?(lock_sources, replacement_sources) - end - def rubygems_aggregate_class Source::Rubygems end From 6adcc5596884619e386d5412e94ef4443868b94f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= <2887858+deivid-rodriguez@users.noreply.github.com> Date: Tue, 9 Sep 2025 19:18:42 +0200 Subject: [PATCH 11/18] [rubygems/rubygems] Completely remove multisources support https://github.com/rubygems/rubygems/commit/8f9d6c54a1 --- lib/bundler/cli/install.rb | 16 - lib/bundler/definition.rb | 16 +- lib/bundler/dsl.rb | 22 +- lib/bundler/errors.rb | 5 - lib/bundler/index.rb | 7 - lib/bundler/installer.rb | 6 - lib/bundler/source/rubygems.rb | 13 - lib/bundler/source_list.rb | 24 +- lib/bundler/source_map.rb | 7 +- spec/bundler/bundler/definition_spec.rb | 4 - spec/bundler/commands/install_spec.rb | 18 - spec/bundler/commands/outdated_spec.rb | 66 -- spec/bundler/commands/update_spec.rb | 62 -- spec/bundler/install/gemfile/sources_spec.rb | 908 ------------------ .../install/gems/compact_index_spec.rb | 73 +- .../install/gems/dependency_api_spec.rb | 92 +- spec/bundler/other/major_deprecation_spec.rb | 67 +- 17 files changed, 73 insertions(+), 1333 deletions(-) diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb index a676e2d6f1f573..c4063f808ab64f 100644 --- a/lib/bundler/cli/install.rb +++ b/lib/bundler/cli/install.rb @@ -69,8 +69,6 @@ def run Bundler::CLI::Common.output_post_install_messages installer.post_install_messages - warn_ambiguous_gems - if CLI::Common.clean_after_install? require_relative "clean" Bundler::CLI::Clean.new(options).run @@ -126,19 +124,5 @@ def normalize_settings options[:force] = options[:redownload] if options[:redownload] end - - def warn_ambiguous_gems - # TODO: remove this when we drop Bundler 1.x support - Installer.ambiguous_gems.to_a.each do |name, installed_from_uri, *also_found_in_uris| - Bundler.ui.warn "Warning: the gem '#{name}' was found in multiple sources." - Bundler.ui.warn "Installed from: #{installed_from_uri}" - Bundler.ui.warn "Also found in:" - also_found_in_uris.each {|uri| Bundler.ui.warn " * #{uri}" } - Bundler.ui.warn "You should add a source requirement to restrict this gem to your preferred source." - Bundler.ui.warn "For example:" - Bundler.ui.warn " gem '#{name}', :source => '#{installed_from_uri}'" - Bundler.ui.warn "Then uninstall the gem '#{name}' (or delete all bundled gems) and then install again." - end - end end end diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index ab488e046b0ac8..32dd13399ec597 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -119,16 +119,12 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti end locked_gem_sources = @originally_locked_sources.select {|s| s.is_a?(Source::Rubygems) } - @multisource_lockfile = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes? + multisource_lockfile = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes? - if @multisource_lockfile && Bundler.frozen_bundle? - unless sources.aggregate_global_source? - msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure." + if multisource_lockfile + msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure." - Bundler::SharedHelpers.major_deprecation 2, msg - end - - @sources.merged_gem_lockfile_sections!(locked_gem_sources.first) + Bundler::SharedHelpers.feature_removed! msg end else @locked_gems = nil @@ -765,7 +761,7 @@ def start_resolution end def precompute_source_requirements_for_indirect_dependencies? - sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source? + sources.non_global_rubygems_sources.all?(&:dependency_api_available?) end def current_platform_locked? @@ -1139,7 +1135,7 @@ def lockfiles_equal?(current, proposed, preserve_unknown_sections) end def additional_base_requirements_to_prevent_downgrades(resolution_base) - return resolution_base unless @locked_gems && !@multisource_lockfile + return resolution_base unless @locked_gems @originally_locked_specs.each do |locked_spec| next if locked_spec.source.is_a?(Source::Path) || locked_spec.source_changed? diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb index 0e36f52269abfa..3bf5dbc1153cf7 100644 --- a/lib/bundler/dsl.rb +++ b/lib/bundler/dsl.rb @@ -521,24 +521,10 @@ def check_rubygems_source_safety end def multiple_global_source_warning - if Bundler.feature_flag.bundler_4_mode? - msg = "This Gemfile contains multiple global sources. " \ - "Each source after the first must include a block to indicate which gems " \ - "should come from that source" - raise GemfileEvalError, msg - else - message = - "Your Gemfile contains multiple global sources. " \ - "Using `source` more than once without a block is a security risk, and " \ - "may result in installing unexpected gems. To resolve this warning, use " \ - "a block to indicate which gems should come from the secondary source." - removed_message = - "Your Gemfile contains multiple global sources. " \ - "Using `source` more than once without a block is a security risk, and " \ - "may result in installing unexpected gems. To resolve this error, use " \ - "a block to indicate which gems should come from the secondary source." - Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message - end + msg = "This Gemfile contains multiple global sources. " \ + "Each source after the first must include a block to indicate which gems " \ + "should come from that source" + raise GemfileEvalError, msg end class DSLError < GemfileError diff --git a/lib/bundler/errors.rb b/lib/bundler/errors.rb index 28da892d31d5ac..8cd1336356079e 100644 --- a/lib/bundler/errors.rb +++ b/lib/bundler/errors.rb @@ -77,11 +77,6 @@ def message def mismatch_resolution_instructions removable, remote = [@existing, @checksum].partition(&:removable?) case removable.size - when 0 - msg = +"Mismatched checksums each have an authoritative source:\n" - msg << " 1. #{@existing.sources.reject(&:removable?).map(&:to_s).join(" and ")}\n" - msg << " 2. #{@checksum.sources.reject(&:removable?).map(&:to_s).join(" and ")}\n" - msg << "You may need to alter your Gemfile sources to resolve this issue.\n" when 1 msg = +"If you trust #{remote.first.sources.first}, to resolve this issue you can:\n" msg << removable.first.removal_instructions diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb index d591b34cc7f5e5..9aef2dfa1218c5 100644 --- a/lib/bundler/index.rb +++ b/lib/bundler/index.rb @@ -46,13 +46,6 @@ def empty? true end - def search_all(name, &blk) - return enum_for(:search_all, name) unless blk - specs_by_name(name).each(&blk) - @duplicates[name]&.each(&blk) - @sources.each {|source| source.search_all(name, &blk) } - end - # Search this index's specs, and any source indexes that this index knows # about, returning all of the results. def search(query) diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb index d41740a411249f..c5fd75431f41e6 100644 --- a/lib/bundler/installer.rb +++ b/lib/bundler/installer.rb @@ -7,12 +7,6 @@ module Bundler class Installer - class << self - attr_accessor :ambiguous_gems - - Installer.ambiguous_gems = [] - end - attr_reader :post_install_messages, :definition # Begins the installation process for Bundler. diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index 19800e9c585cd5..fdc3a77b248072 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -168,12 +168,6 @@ def install(spec, options = {}) return nil # no post-install message end - if spec.remote - # Check for this spec from other sources - uris = [spec.remote, *remotes_for_spec(spec)].map(&:anonymized_uri).uniq - Installer.ambiguous_gems << [spec.name, *uris] if uris.length > 1 - end - path = fetch_gem_if_possible(spec, options[:previous_spec]) raise GemNotFound, "Could not find #{spec.file_name} for installation" unless path @@ -332,13 +326,6 @@ def credless_remotes remotes.map(&method(:remove_auth)) end - def remotes_for_spec(spec) - specs.search_all(spec.name).inject([]) do |uris, s| - uris << s.remote if s.remote - uris - end - end - def cached_gem(spec) global_cache_path = download_cache_path(spec) caches << global_cache_path if global_cache_path diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb index 70b74f6a91cf32..6dba3f35e8f288 100644 --- a/lib/bundler/source_list.rb +++ b/lib/bundler/source_list.rb @@ -21,19 +21,9 @@ def initialize @rubygems_sources = [] @metadata_source = Source::Metadata.new - @merged_gem_lockfile_sections = false @local_mode = true end - def merged_gem_lockfile_sections? - @merged_gem_lockfile_sections - end - - def merged_gem_lockfile_sections!(replacement_source) - @merged_gem_lockfile_sections = true - @global_rubygems_source = replacement_source - end - def aggregate_global_source? global_rubygems_source.multiple_remotes? end @@ -90,10 +80,6 @@ def non_global_rubygems_sources @rubygems_sources end - def rubygems_remotes - rubygems_sources.flat_map(&:remotes).uniq - end - def all_sources path_sources + git_sources + plugin_sources + rubygems_sources + [metadata_source] end @@ -115,11 +101,7 @@ def lock_other_sources end def lock_rubygems_sources - if merged_gem_lockfile_sections? - [combine_rubygems_sources] - else - rubygems_sources.sort_by(&:identifier) - end + rubygems_sources.sort_by(&:identifier) end # Returns true if there are changes @@ -228,10 +210,6 @@ def source_list_for(source) end end - def combine_rubygems_sources - Source::Rubygems.new("remotes" => rubygems_remotes) - end - def warn_on_git_protocol(source) return if Bundler.settings["git.allow_insecure"] diff --git a/lib/bundler/source_map.rb b/lib/bundler/source_map.rb index a8e12d08c325df..cb88caf1bd1124 100644 --- a/lib/bundler/source_map.rb +++ b/lib/bundler/source_map.rb @@ -23,15 +23,12 @@ def all_requirements if previous_source.nil? requirements[indirect_dependency_name] = source else - no_ambiguous_sources = Bundler.feature_flag.bundler_4_mode? - msg = ["The gem '#{indirect_dependency_name}' was found in multiple relevant sources."] msg.concat [previous_source, source].map {|s| " * #{s}" }.sort - msg << "You #{no_ambiguous_sources ? :must : :should} add this gem to the source block for the source you wish it to be installed from." + msg << "You must add this gem to the source block for the source you wish it to be installed from." msg = msg.join("\n") - raise SecurityError, msg if no_ambiguous_sources - Bundler.ui.warn "Warning: #{msg}" + raise SecurityError, msg end end diff --git a/spec/bundler/bundler/definition_spec.rb b/spec/bundler/bundler/definition_spec.rb index 8f796877fda30c..67fc51e86af008 100644 --- a/spec/bundler/bundler/definition_spec.rb +++ b/spec/bundler/bundler/definition_spec.rb @@ -299,10 +299,6 @@ def path_sources [] end - def rubygems_remotes - [] - end - def replace_sources!(arg) nil end diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb index ae2e84766a63cc..65903b3e780024 100644 --- a/spec/bundler/commands/install_spec.rb +++ b/spec/bundler/commands/install_spec.rb @@ -342,24 +342,6 @@ end end - it "finds gems in multiple sources" do - build_repo2 do - build_gem "myrack", "1.2" do |s| - s.executables = "myrackup" - end - end - - install_gemfile <<-G, artifice: "compact_index_extra" - source "https://gemserver.test" - source "https://gemserver.test/extra" - - gem "activesupport", "1.2.3" - gem "myrack", "1.2" - G - - expect(the_bundle).to include_gems "myrack 1.2", "activesupport 1.2.3" - end - it "gives useful errors if no global sources are set, and gems not installed locally, with and without a lockfile" do install_gemfile <<-G, raise_on_error: false gem "myrack" diff --git a/spec/bundler/commands/outdated_spec.rb b/spec/bundler/commands/outdated_spec.rb index c7d285cd369593..3eeac7f624b6f2 100644 --- a/spec/bundler/commands/outdated_spec.rb +++ b/spec/bundler/commands/outdated_spec.rb @@ -151,72 +151,6 @@ end end - describe "with multiple, duplicated sources, with lockfile in old format" do - before do - build_repo2 do - build_gem "dotenv", "2.7.6" - - build_gem "oj", "3.11.3" - build_gem "oj", "3.11.5" - - build_gem "vcr", "6.0.0" - end - - build_repo3 do - build_gem "pkg-gem-flowbyte-with-dep", "1.0.0" do |s| - s.add_dependency "oj" - end - end - - gemfile <<~G - source "https://gem.repo2" - - gem "dotenv" - - source "https://gem.repo3" do - gem 'pkg-gem-flowbyte-with-dep' - end - - gem "vcr",source: "https://gem.repo2" - G - - lockfile <<~L - GEM - remote: https://gem.repo2/ - remote: https://gem.repo3/ - specs: - dotenv (2.7.6) - oj (3.11.3) - pkg-gem-flowbyte-with-dep (1.0.0) - oj - vcr (6.0.0) - - PLATFORMS - #{local_platform} - - DEPENDENCIES - dotenv - pkg-gem-flowbyte-with-dep! - vcr! - - BUNDLED WITH - #{Bundler::VERSION} - L - end - - it "works" do - bundle :install, artifice: "compact_index" - bundle :outdated, artifice: "compact_index", raise_on_error: false - - expected_output = <<~TABLE - Gem Current Latest Requested Groups - oj 3.11.3 3.11.5 - TABLE - - expect(out).to include(expected_output.strip) - end - end - describe "with --group option" do before do build_repo2 do diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb index ef856edf3799aa..f81c5578841dca 100644 --- a/spec/bundler/commands/update_spec.rb +++ b/spec/bundler/commands/update_spec.rb @@ -1078,68 +1078,6 @@ L end end - - context "with multiple, duplicated sources, with lockfile in old format" do - before do - build_repo2 do - build_gem "dotenv", "2.7.6" - - build_gem "oj", "3.11.3" - build_gem "oj", "3.11.5" - - build_gem "vcr", "6.0.0" - end - - build_repo3 do - build_gem "pkg-gem-flowbyte-with-dep", "1.0.0" do |s| - s.add_dependency "oj" - end - end - - gemfile <<~G - source "https://gem.repo2" - - gem "dotenv" - - source "https://gem.repo3" do - gem 'pkg-gem-flowbyte-with-dep' - end - - gem "vcr",source: "https://gem.repo2" - G - - lockfile <<~L - GEM - remote: https://gem.repo2/ - remote: https://gem.repo3/ - specs: - dotenv (2.7.6) - oj (3.11.3) - pkg-gem-flowbyte-with-dep (1.0.0) - oj - vcr (6.0.0) - - PLATFORMS - #{local_platform} - - DEPENDENCIES - dotenv - pkg-gem-flowbyte-with-dep! - vcr! - - BUNDLED WITH - #{Bundler::VERSION} - L - end - - it "works" do - bundle :install, artifice: "compact_index" - bundle "update oj", artifice: "compact_index" - - expect(out).to include("Bundle updated!") - expect(the_bundle).to include_gems "oj 3.11.5" - end - end end RSpec.describe "bundle update in more complicated situations" do diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index 406d881541adf0..c2a0905d215128 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -4,153 +4,6 @@ # repo1 is built automatically before all of the specs run # it contains myrack-obama 1.0.0 and myrack 0.9.1 & 1.0.0 amongst other gems - context "without source affinity" do - before do - # Oh no! Someone evil is trying to hijack myrack :( - # need this to be broken to check for correct source ordering - build_repo3 do - build_gem "myrack", repo3_myrack_version do |s| - s.write "lib/myrack.rb", "MYRACK = 'FAIL'" - end - end - end - - context "with multiple toplevel sources" do - let(:repo3_myrack_version) { "1.0.0" } - - before do - gemfile <<-G - source "https://gem.repo3" - source "https://gem.repo1" - gem "myrack-obama" - gem "myrack" - G - end - - it "refuses to install mismatched checksum because one gem has been tampered with" do - lockfile <<~L - GEM - remote: https://gem.repo3/ - remote: https://gem.repo1/ - specs: - myrack (1.0.0) - - PLATFORMS - #{local_platform} - - DEPENDENCIES - depends_on_myrack! - - BUNDLED WITH - #{Bundler::VERSION} - L - - bundle :install, artifice: "compact_index", raise_on_error: false - - expect(exitstatus).to eq(37) - expect(err).to eq <<~E.strip - [DEPRECATED] Your Gemfile contains multiple global sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source. - Bundler found mismatched checksums. This is a potential security risk. - #{checksum_to_lock(gem_repo1, "myrack", "1.0.0")} - from the API at https://gem.repo1/ - #{checksum_to_lock(gem_repo3, "myrack", "1.0.0")} - from the API at https://gem.repo3/ - - Mismatched checksums each have an authoritative source: - 1. the API at https://gem.repo1/ - 2. the API at https://gem.repo3/ - You may need to alter your Gemfile sources to resolve this issue. - - To ignore checksum security warnings, disable checksum validation with - `bundle config set --local disable_checksum_validation true` - E - end - - context "when checksum validation is disabled" do - before do - bundle "config set --local disable_checksum_validation true" - end - - it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first" do - bundle :install, artifice: "compact_index" - - expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.") - expect(err).to include("Installed from: https://gem.repo1") - expect(the_bundle).to include_gems("myrack-obama 1.0.0", "myrack 1.0.0", source: "remote1") - end - - it "does not use the full index unnecessarily" do - bundle :install, artifice: "compact_index", verbose: true - - expect(out).to include("https://gem.repo1/versions") - expect(out).to include("https://gem.repo3/versions") - expect(out).not_to include("https://gem.repo1/quick/Marshal.4.8/") - expect(out).not_to include("https://gem.repo3/quick/Marshal.4.8/") - end - - it "fails", bundler: "4" do - bundle :install, artifice: "compact_index", raise_on_error: false - expect(err).to include("Each source after the first must include a block") - expect(exitstatus).to eq(4) - end - end - end - - context "when different versions of the same gem are in multiple sources" do - let(:repo3_myrack_version) { "1.2" } - - before do - gemfile <<-G - source "https://gem.repo3" - source "https://gem.repo1" - gem "myrack-obama" - gem "myrack", "1.0.0" # force it to install the working version in repo1 - G - end - - it "warns about ambiguous gems, but installs anyway" do - bundle :install, artifice: "compact_index" - expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.") - expect(err).to include("Installed from: https://gem.repo1") - expect(the_bundle).to include_gems("myrack-obama 1.0.0", "myrack 1.0.0", source: "remote1") - end - - it "fails", bundler: "4" do - bundle :install, artifice: "compact_index", raise_on_error: false - expect(err).to include("Each source after the first must include a block") - expect(exitstatus).to eq(4) - end - end - end - - context "without source affinity, and a stdlib gem present in one of the sources", :ruby_repo do - let(:default_json_version) { ruby "gem 'json'; require 'json'; puts JSON::VERSION" } - - before do - build_repo2 do - build_gem "json", default_json_version - end - - build_repo4 do - build_gem "foo" do |s| - s.add_dependency "json", default_json_version - end - end - - gemfile <<-G - source "https://gem.repo2" - source "https://gem.repo4" - - gem "foo" - G - end - - it "works in standalone mode" do - gem_checksum = checksum_digest(gem_repo4, "foo", "1.0") - bundle "install --standalone", artifice: "compact_index", env: { "BUNDLER_SPEC_FOO_CHECKSUM" => gem_checksum } - end - end - context "with source affinity" do context "with sources given by a block" do before do @@ -313,189 +166,6 @@ expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0") end end - - context "and in yet another source" do - before do - gemfile <<-G - source "https://gem.repo1" - source "https://gem.repo2" - source "https://gem.repo3" do - gem "depends_on_myrack" - end - G - end - - it "fails when the two sources don't have the same checksum" do - bundle :install, artifice: "compact_index", raise_on_error: false - - expect(err).to eq(<<~E.strip) - [DEPRECATED] Your Gemfile contains multiple global sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source. - Bundler found mismatched checksums. This is a potential security risk. - #{checksum_to_lock(gem_repo2, "myrack", "1.0.0")} - from the API at https://gem.repo2/ - #{checksum_to_lock(gem_repo1, "myrack", "1.0.0")} - from the API at https://gem.repo1/ - - Mismatched checksums each have an authoritative source: - 1. the API at https://gem.repo2/ - 2. the API at https://gem.repo1/ - You may need to alter your Gemfile sources to resolve this issue. - - To ignore checksum security warnings, disable checksum validation with - `bundle config set --local disable_checksum_validation true` - E - expect(exitstatus).to eq(37) - end - - it "fails when the two sources agree, but the local gem calculates a different checksum" do - myrack_checksum = "c0ffee11" * 8 - bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_MYRACK_CHECKSUM" => myrack_checksum }, raise_on_error: false - - expect(err).to eq(<<~E.strip) - [DEPRECATED] Your Gemfile contains multiple global sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source. - Bundler found mismatched checksums. This is a potential security risk. - myrack (1.0.0) sha256=#{myrack_checksum} - from the API at https://gem.repo2/ - and the API at https://gem.repo1/ - #{checksum_to_lock(gem_repo2, "myrack", "1.0.0")} - from the gem at #{default_bundle_path("cache", "myrack-1.0.0.gem")} - - If you trust the API at https://gem.repo2/, to resolve this issue you can: - 1. remove the gem at #{default_bundle_path("cache", "myrack-1.0.0.gem")} - 2. run `bundle install` - - To ignore checksum security warnings, disable checksum validation with - `bundle config set --local disable_checksum_validation true` - E - expect(exitstatus).to eq(37) - end - - it "installs from the other source and warns about ambiguous gems when the sources have the same checksum" do - gem_checksum = checksum_digest(gem_repo2, "myrack", "1.0.0") - bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_MYRACK_CHECKSUM" => gem_checksum, "DEBUG" => "1" } - - expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.") - expect(err).to include("Installed from: https://gem.repo2") - - checksums = checksums_section_when_enabled do |c| - c.checksum gem_repo3, "depends_on_myrack", "1.0.1" - c.checksum gem_repo2, "myrack", "1.0.0" - end - - expect(lockfile).to eq <<~L - GEM - remote: https://gem.repo1/ - remote: https://gem.repo2/ - specs: - myrack (1.0.0) - - GEM - remote: https://gem.repo3/ - specs: - depends_on_myrack (1.0.1) - myrack - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - depends_on_myrack! - #{checksums} - BUNDLED WITH - #{Bundler::VERSION} - L - - previous_lockfile = lockfile - expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0") - expect(lockfile).to eq(previous_lockfile) - end - - it "installs from the other source and warns about ambiguous gems when checksum validation is disabled" do - bundle "config set --local disable_checksum_validation true" - bundle :install, artifice: "compact_index" - - expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.") - expect(err).to include("Installed from: https://gem.repo2") - - checksums = checksums_section_when_enabled do |c| - c.no_checksum "depends_on_myrack", "1.0.1" - c.no_checksum "myrack", "1.0.0" - end - - expect(lockfile).to eq <<~L - GEM - remote: https://gem.repo1/ - remote: https://gem.repo2/ - specs: - myrack (1.0.0) - - GEM - remote: https://gem.repo3/ - specs: - depends_on_myrack (1.0.1) - myrack - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - depends_on_myrack! - #{checksums} - BUNDLED WITH - #{Bundler::VERSION} - L - - previous_lockfile = lockfile - expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0") - expect(lockfile).to eq(previous_lockfile) - end - - it "fails", bundler: "4" do - bundle :install, artifice: "compact_index", raise_on_error: false - expect(err).to include("Each source after the first must include a block") - expect(exitstatus).to eq(4) - end - end - - context "and only the dependency is pinned" do - before do - # need this to be broken to check for correct source ordering - build_repo gem_repo2 do - build_gem "myrack", "1.0.0" do |s| - s.write "lib/myrack.rb", "MYRACK = 'FAIL'" - end - end - - gemfile <<-G - source "https://gem.repo3" # contains depends_on_myrack - source "https://gem.repo2" # contains broken myrack - - gem "depends_on_myrack" # installed from gem_repo3 - gem "myrack", :source => "https://gem.repo1" - G - end - - it "installs the dependency from the pinned source without warning" do - bundle :install, artifice: "compact_index" - - expect(err).not_to include("Warning: the gem 'myrack' was found in multiple sources.") - expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0") - - # In https://github.com/rubygems/bundler/issues/3585 this failed - # when there is already a lockfile, and the gems are missing, so try again - system_gems [] - bundle :install, artifice: "compact_index" - - expect(err).not_to include("Warning: the gem 'myrack' was found in multiple sources.") - expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0") - end - - it "fails", bundler: "4" do - bundle :install, artifice: "compact_index", raise_on_error: false - expect(err).to include("Each source after the first must include a block") - expect(exitstatus).to eq(4) - end - end end context "when a top-level gem can only be found in an scoped source" do @@ -524,39 +194,6 @@ end end - context "when an indirect dependency can't be found in the aggregate rubygems source" do - before do - build_repo2 - - build_repo3 do - build_gem "depends_on_missing", "1.0.1" do |s| - s.add_dependency "missing" - end - end - - gemfile <<-G - source "https://gem.repo2" - - source "https://gem.repo3" - - gem "depends_on_missing" - G - end - - it "fails" do - bundle :install, artifice: "compact_index", raise_on_error: false - expect(err).to end_with <<~E.strip - Could not find compatible versions - - Because every version of depends_on_missing depends on missing >= 0 - and missing >= 0 could not be found in any of the sources, - depends_on_missing cannot be used. - So, because Gemfile depends on depends_on_missing >= 0, - version solving has failed. - E - end - end - context "when a top-level gem has an indirect dependency" do before do build_repo gem_repo2 do @@ -714,337 +351,6 @@ end end - context "when the lockfile has aggregated rubygems sources and newer versions of dependencies are available" do - before do - build_repo gem_repo2 do - build_gem "activesupport", "6.0.3.4" do |s| - s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2" - s.add_dependency "i18n", ">= 0.7", "< 2" - s.add_dependency "minitest", "~> 5.1" - s.add_dependency "tzinfo", "~> 1.1" - s.add_dependency "zeitwerk", "~> 2.2", ">= 2.2.2" - end - - build_gem "activesupport", "6.1.2.1" do |s| - s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2" - s.add_dependency "i18n", ">= 1.6", "< 2" - s.add_dependency "minitest", ">= 5.1" - s.add_dependency "tzinfo", "~> 2.0" - s.add_dependency "zeitwerk", "~> 2.3" - end - - build_gem "concurrent-ruby", "1.1.8" - build_gem "concurrent-ruby", "1.1.9" - build_gem "connection_pool", "2.2.3" - - build_gem "i18n", "1.8.9" do |s| - s.add_dependency "concurrent-ruby", "~> 1.0" - end - - build_gem "minitest", "5.14.3" - build_gem "myrack", "2.2.3" - build_gem "redis", "4.2.5" - - build_gem "sidekiq", "6.1.3" do |s| - s.add_dependency "connection_pool", ">= 2.2.2" - s.add_dependency "myrack", "~> 2.0" - s.add_dependency "redis", ">= 4.2.0" - end - - build_gem "thread_safe", "0.3.6" - - build_gem "tzinfo", "1.2.9" do |s| - s.add_dependency "thread_safe", "~> 0.1" - end - - build_gem "tzinfo", "2.0.4" do |s| - s.add_dependency "concurrent-ruby", "~> 1.0" - end - - build_gem "zeitwerk", "2.4.2" - end - - build_repo3 do - build_gem "sidekiq-pro", "5.2.1" do |s| - s.add_dependency "connection_pool", ">= 2.2.3" - s.add_dependency "sidekiq", ">= 6.1.0" - end - end - - gemfile <<-G - # frozen_string_literal: true - - source "https://gem.repo2" - - gem "activesupport" - - source "https://gem.repo3" do - gem "sidekiq-pro" - end - G - - @locked_checksums = checksums_section_when_enabled do |c| - c.checksum gem_repo2, "activesupport", "6.0.3.4" - c.checksum gem_repo2, "concurrent-ruby", "1.1.8" - c.checksum gem_repo2, "connection_pool", "2.2.3" - c.checksum gem_repo2, "i18n", "1.8.9" - c.checksum gem_repo2, "minitest", "5.14.3" - c.checksum gem_repo2, "myrack", "2.2.3" - c.checksum gem_repo2, "redis", "4.2.5" - c.checksum gem_repo2, "sidekiq", "6.1.3" - c.checksum gem_repo3, "sidekiq-pro", "5.2.1" - c.checksum gem_repo2, "thread_safe", "0.3.6" - c.checksum gem_repo2, "tzinfo", "1.2.9" - c.checksum gem_repo2, "zeitwerk", "2.4.2" - end - - lockfile <<~L - GEM - remote: https://gem.repo2/ - remote: https://gem.repo3/ - specs: - activesupport (6.0.3.4) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) - concurrent-ruby (1.1.8) - connection_pool (2.2.3) - i18n (1.8.9) - concurrent-ruby (~> 1.0) - minitest (5.14.3) - myrack (2.2.3) - redis (4.2.5) - sidekiq (6.1.3) - connection_pool (>= 2.2.2) - myrack (~> 2.0) - redis (>= 4.2.0) - sidekiq-pro (5.2.1) - connection_pool (>= 2.2.3) - sidekiq (>= 6.1.0) - thread_safe (0.3.6) - tzinfo (1.2.9) - thread_safe (~> 0.1) - zeitwerk (2.4.2) - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - activesupport - sidekiq-pro! - #{@locked_checksums} - BUNDLED WITH - #{Bundler::VERSION} - L - end - - it "does not install newer versions but updates the lockfile format when running bundle install in non frozen mode, and doesn't warn" do - bundle :install, artifice: "compact_index" - expect(err).to be_empty - - expect(the_bundle).to include_gems("activesupport 6.0.3.4") - expect(the_bundle).not_to include_gems("activesupport 6.1.2.1") - expect(the_bundle).to include_gems("tzinfo 1.2.9") - expect(the_bundle).not_to include_gems("tzinfo 2.0.4") - expect(the_bundle).to include_gems("concurrent-ruby 1.1.8") - expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.9") - - expect(lockfile).to eq <<~L - GEM - remote: https://gem.repo2/ - specs: - activesupport (6.0.3.4) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) - concurrent-ruby (1.1.8) - connection_pool (2.2.3) - i18n (1.8.9) - concurrent-ruby (~> 1.0) - minitest (5.14.3) - myrack (2.2.3) - redis (4.2.5) - sidekiq (6.1.3) - connection_pool (>= 2.2.2) - myrack (~> 2.0) - redis (>= 4.2.0) - thread_safe (0.3.6) - tzinfo (1.2.9) - thread_safe (~> 0.1) - zeitwerk (2.4.2) - - GEM - remote: https://gem.repo3/ - specs: - sidekiq-pro (5.2.1) - connection_pool (>= 2.2.3) - sidekiq (>= 6.1.0) - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - activesupport - sidekiq-pro! - #{@locked_checksums} - BUNDLED WITH - #{Bundler::VERSION} - L - end - - it "does not install newer versions or generate lockfile changes when running bundle install in frozen mode, and warns" do - initial_lockfile = lockfile - - bundle "config set --local frozen true" - bundle :install, artifice: "compact_index" - - expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") - - expect(the_bundle).to include_gems("activesupport 6.0.3.4") - expect(the_bundle).not_to include_gems("activesupport 6.1.2.1") - expect(the_bundle).to include_gems("tzinfo 1.2.9") - expect(the_bundle).not_to include_gems("tzinfo 2.0.4") - expect(the_bundle).to include_gems("concurrent-ruby 1.1.8") - expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.9") - - expect(lockfile).to eq(initial_lockfile) - end - - it "fails when running bundle install in frozen mode", bundler: "4" do - initial_lockfile = lockfile - - bundle "config set --local frozen true" - bundle :install, artifice: "compact_index", raise_on_error: false - - expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") - - expect(lockfile).to eq(initial_lockfile) - end - - it "splits sections and upgrades gems when running bundle update, and doesn't warn" do - bundle "update --all", artifice: "compact_index" - expect(err).to be_empty - - expect(the_bundle).not_to include_gems("activesupport 6.0.3.4") - expect(the_bundle).to include_gems("activesupport 6.1.2.1") - @locked_checksums.checksum gem_repo2, "activesupport", "6.1.2.1" - - expect(the_bundle).not_to include_gems("tzinfo 1.2.9") - expect(the_bundle).to include_gems("tzinfo 2.0.4") - @locked_checksums.checksum gem_repo2, "tzinfo", "2.0.4" - @locked_checksums.delete "thread_safe" - - expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8") - expect(the_bundle).to include_gems("concurrent-ruby 1.1.9") - @locked_checksums.checksum gem_repo2, "concurrent-ruby", "1.1.9" - - expect(lockfile).to eq <<~L - GEM - remote: https://gem.repo2/ - specs: - activesupport (6.1.2.1) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 1.6, < 2) - minitest (>= 5.1) - tzinfo (~> 2.0) - zeitwerk (~> 2.3) - concurrent-ruby (1.1.9) - connection_pool (2.2.3) - i18n (1.8.9) - concurrent-ruby (~> 1.0) - minitest (5.14.3) - myrack (2.2.3) - redis (4.2.5) - sidekiq (6.1.3) - connection_pool (>= 2.2.2) - myrack (~> 2.0) - redis (>= 4.2.0) - tzinfo (2.0.4) - concurrent-ruby (~> 1.0) - zeitwerk (2.4.2) - - GEM - remote: https://gem.repo3/ - specs: - sidekiq-pro (5.2.1) - connection_pool (>= 2.2.3) - sidekiq (>= 6.1.0) - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - activesupport - sidekiq-pro! - #{@locked_checksums} - BUNDLED WITH - #{Bundler::VERSION} - L - end - - it "upgrades the lockfile format and upgrades the requested gem when running bundle update with an argument" do - bundle "update concurrent-ruby", artifice: "compact_index" - expect(err).to be_empty - - expect(the_bundle).to include_gems("activesupport 6.0.3.4") - expect(the_bundle).not_to include_gems("activesupport 6.1.2.1") - expect(the_bundle).to include_gems("tzinfo 1.2.9") - expect(the_bundle).not_to include_gems("tzinfo 2.0.4") - expect(the_bundle).to include_gems("concurrent-ruby 1.1.9") - expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8") - - @locked_checksums.checksum gem_repo2, "concurrent-ruby", "1.1.9" - - expect(lockfile).to eq <<~L - GEM - remote: https://gem.repo2/ - specs: - activesupport (6.0.3.4) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) - concurrent-ruby (1.1.9) - connection_pool (2.2.3) - i18n (1.8.9) - concurrent-ruby (~> 1.0) - minitest (5.14.3) - myrack (2.2.3) - redis (4.2.5) - sidekiq (6.1.3) - connection_pool (>= 2.2.2) - myrack (~> 2.0) - redis (>= 4.2.0) - thread_safe (0.3.6) - tzinfo (1.2.9) - thread_safe (~> 0.1) - zeitwerk (2.4.2) - - GEM - remote: https://gem.repo3/ - specs: - sidekiq-pro (5.2.1) - connection_pool (>= 2.2.3) - sidekiq (>= 6.1.0) - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - activesupport - sidekiq-pro! - #{@locked_checksums} - BUNDLED WITH - #{Bundler::VERSION} - L - end - end - context "when a top-level gem has an indirect dependency present in the default source, but with a different version from the one resolved" do before do build_lib "activesupport", "7.0.0.alpha", path: lib_path("rails/activesupport") @@ -1207,112 +513,6 @@ end end - context "with a lockfile with aggregated rubygems sources" do - let(:aggregate_gem_section_lockfile) do - <<~L - GEM - remote: https://gem.repo1/ - remote: https://gem.repo3/ - specs: - myrack (0.9.1) - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - myrack! - - BUNDLED WITH - #{Bundler::VERSION} - L - end - - let(:split_gem_section_lockfile) do - <<~L - GEM - remote: https://gem.repo1/ - specs: - - GEM - remote: https://gem.repo3/ - specs: - myrack (0.9.1) - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - myrack! - - BUNDLED WITH - #{Bundler::VERSION} - L - end - - before do - build_repo3 do - build_gem "myrack", "0.9.1" - end - - gemfile <<-G - source "https://gem.repo1" - source "https://gem.repo3" do - gem 'myrack' - end - G - - lockfile aggregate_gem_section_lockfile - end - - it "installs the existing lockfile but prints a warning when checksum validation is disabled" do - bundle "config set --local deployment true" - bundle "config set --local disable_checksum_validation true" - - bundle "install", artifice: "compact_index" - - expect(lockfile).to eq(aggregate_gem_section_lockfile) - expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") - expect(the_bundle).to include_gems("myrack 0.9.1", source: "remote3") - end - - it "prints a checksum warning when the checksums from both sources do not match" do - bundle "config set --local deployment true" - - bundle "install", artifice: "compact_index", raise_on_error: false - - api_checksum1 = checksum_digest(gem_repo1, "myrack", "0.9.1") - api_checksum3 = checksum_digest(gem_repo3, "myrack", "0.9.1") - - expect(exitstatus).to eq(37) - expect(err).to eq(<<~E.strip) - [DEPRECATED] Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure. - Bundler found mismatched checksums. This is a potential security risk. - myrack (0.9.1) sha256=#{api_checksum3} - from the API at https://gem.repo3/ - myrack (0.9.1) sha256=#{api_checksum1} - from the API at https://gem.repo1/ - - Mismatched checksums each have an authoritative source: - 1. the API at https://gem.repo3/ - 2. the API at https://gem.repo1/ - You may need to alter your Gemfile sources to resolve this issue. - - To ignore checksum security warnings, disable checksum validation with - `bundle config set --local disable_checksum_validation true` - E - end - - it "refuses to install the existing lockfile and prints an error", bundler: "4" do - bundle "config set --local deployment true" - - bundle "install", artifice: "compact_index", raise_on_error: false - - expect(lockfile).to eq(aggregate_gem_section_lockfile) - expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") - expect(out).to be_empty - end - end - context "with a path gem in the same Gemfile" do before do build_lib "foo" @@ -1584,37 +784,6 @@ end context "when an indirect dependency is available from multiple ambiguous sources" do - it "succeeds but warns, suggesting a source block" do - build_repo4 do - build_gem "depends_on_myrack" do |s| - s.add_dependency "myrack" - end - build_gem "myrack" - end - - install_gemfile <<-G, artifice: "compact_index_extra_api", raise_on_error: false - source "https://global.source" - - source "https://scoped.source/extra" do - gem "depends_on_myrack" - end - - source "https://scoped.source" do - gem "thin" - end - G - expect(err).to eq <<~EOS.strip - Warning: The gem 'myrack' was found in multiple relevant sources. - * rubygems repository https://scoped.source/ - * rubygems repository https://scoped.source/extra/ - You should add this gem to the source block for the source you wish it to be installed from. - EOS - expect(last_command).to be_success - expect(the_bundle).to be_locked - end - end - - context "when an indirect dependency is available from multiple ambiguous sources", bundler: "4" do it "raises, suggesting a source block" do build_repo4 do build_gem "depends_on_myrack" do |s| @@ -1645,83 +814,6 @@ end end - context "when upgrading a lockfile suffering from dependency confusion" do - before do - build_repo4 do - build_gem "mime-types", "3.0.0" - end - - build_repo2 do - build_gem "capybara", "2.5.0" do |s| - s.add_dependency "mime-types", ">= 1.16" - end - - build_gem "mime-types", "3.3.1" - end - - gemfile <<~G - source "https://gem.repo2" - - gem "capybara", "~> 2.5.0" - - source "https://gem.repo4" do - gem "mime-types", "~> 3.0" - end - G - - lockfile <<-L - GEM - remote: https://gem.repo2/ - remote: https://gem.repo4/ - specs: - capybara (2.5.0) - mime-types (>= 1.16) - mime-types (3.3.1) - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - capybara (~> 2.5.0) - mime-types (~> 3.0)! - - CHECKSUMS - L - end - - it "upgrades the lockfile correctly" do - bundle "lock --update", artifice: "compact_index" - - checksums = checksums_section_when_enabled do |c| - c.checksum gem_repo2, "capybara", "2.5.0" - c.checksum gem_repo4, "mime-types", "3.0.0" - end - - expect(lockfile).to eq <<~L - GEM - remote: https://gem.repo2/ - specs: - capybara (2.5.0) - mime-types (>= 1.16) - - GEM - remote: https://gem.repo4/ - specs: - mime-types (3.0.0) - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - capybara (~> 2.5.0) - mime-types (~> 3.0)! - #{checksums} - BUNDLED WITH - #{Bundler::VERSION} - L - end - end - context "when default source includes old gems with nil required_ruby_version" do before do build_repo2 do diff --git a/spec/bundler/install/gems/compact_index_spec.rb b/spec/bundler/install/gems/compact_index_spec.rb index 3e4b18a188e8cc..64c59d4826f357 100644 --- a/spec/bundler/install/gems/compact_index_spec.rb +++ b/spec/bundler/install/gems/compact_index_spec.rb @@ -324,24 +324,6 @@ def require(*args) FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end - gemfile <<-G - source "#{source_uri}" - source "#{source_uri}/extra" - gem "back_deps" - G - - bundle :install, artifice: "compact_index_extra" - expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0" - end - - it "fetches again when more dependencies are found in subsequent sources with source blocks" do - build_repo2 do - build_gem "back_deps" do |s| - s.add_dependency "foo" - end - FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] - end - install_gemfile <<-G, artifice: "compact_index_extra", verbose: true source "#{source_uri}" source "#{source_uri}/extra" do @@ -375,11 +357,13 @@ def require(*args) expect(the_bundle).to include_gems "myrack 1.2" end - it "considers all possible versions of dependencies from all api gem sources" do - # In this scenario, the gem "somegem" only exists in repo4. It depends on specific version of activesupport that - # exists only in repo1. There happens also be a version of activesupport in repo4, but not the one that version 1.0.0 - # of somegem wants. This test makes sure that bundler actually finds version 1.2.3 of active support in the other - # repo and installs it. + it "resolves indirect dependencies to the most scoped source that includes them" do + # In this scenario, the gem "somegem" only exists in repo4. It depends on + # specific version of activesupport that exists only in repo1. There + # happens also be a version of activesupport in repo4, but not the one that + # version 1.0.0 of somegem wants. This test makes sure that bundler tries to + # use the version in the most scoped source, even if not compatible, and + # gives a resolution error build_repo4 do build_gem "activesupport", "1.2.0" build_gem "somegem", "1.0.0" do |s| @@ -389,14 +373,14 @@ def require(*args) gemfile <<-G source "#{source_uri}" - source "#{source_uri}/extra" - gem 'somegem', '1.0.0' + source "#{source_uri}/extra" do + gem 'somegem', '1.0.0' + end G - bundle :install, artifice: "compact_index_extra_api" + bundle :install, artifice: "compact_index_extra_api", raise_on_error: false - expect(the_bundle).to include_gems "somegem 1.0.0" - expect(the_bundle).to include_gems "activesupport 1.2.3" + expect(err).to include("Could not find compatible versions") end it "prints API output properly with back deps" do @@ -479,26 +463,6 @@ def require(*args) FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end - gemfile <<-G - source "#{source_uri}" - source "#{source_uri}/extra" - gem "back_deps" - G - - bundle :install, artifice: "compact_index_extra" - bundle "config --set local deployment true" - bundle :install, artifice: "compact_index_extra" - expect(the_bundle).to include_gems "back_deps 1.0" - end - - it "fetches again when more dependencies are found in subsequent sources using deployment mode with blocks" do - build_repo2 do - build_gem "back_deps" do |s| - s.add_dependency "foo" - end - FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] - end - gemfile <<-G source "#{source_uri}" source "#{source_uri}/extra" do @@ -583,19 +547,6 @@ def require(*args) expect(the_bundle).to include_gems "myrack 1.0.0" end - it "strips http basic auth creds when warning about ambiguous sources" do - gemfile <<-G - source "#{basic_auth_source_uri}" - source "#{file_uri_for(gem_repo1)}" - gem "myrack" - G - - bundle :install, artifice: "compact_index_basic_authentication" - expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.") - expect(err).not_to include("#{user}:#{password}") - expect(the_bundle).to include_gems "myrack 1.0.0" - end - it "does not pass the user / password to different hosts on redirect" do gemfile <<-G source "#{basic_auth_source_uri}" diff --git a/spec/bundler/install/gems/dependency_api_spec.rb b/spec/bundler/install/gems/dependency_api_spec.rb index 012e2d3995b4a2..1650df3dfb6ae6 100644 --- a/spec/bundler/install/gems/dependency_api_spec.rb +++ b/spec/bundler/install/gems/dependency_api_spec.rb @@ -262,24 +262,6 @@ def require(*args) FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end - gemfile <<-G - source "#{source_uri}" - source "#{source_uri}/extra" - gem "back_deps" - G - - bundle :install, artifice: "endpoint_extra" - expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0" - end - - it "fetches again when more dependencies are found in subsequent sources using blocks" do - build_repo2 do - build_gem "back_deps" do |s| - s.add_dependency "foo" - end - FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] - end - gemfile <<-G source "#{source_uri}" source "#{source_uri}/extra" do @@ -313,11 +295,13 @@ def require(*args) expect(the_bundle).to include_gems "myrack 1.2" end - it "considers all possible versions of dependencies from all api gem sources" do - # In this scenario, the gem "somegem" only exists in repo4. It depends on specific version of activesupport that - # exists only in repo1. There happens also be a version of activesupport in repo4, but not the one that version 1.0.0 - # of somegem wants. This test makes sure that bundler actually finds version 1.2.3 of active support in the other - # repo and installs it. + it "resolves indirect dependencies to the most scoped source that includes them" do + # In this scenario, the gem "somegem" only exists in repo4. It depends on + # specific version of activesupport that exists only in repo1. There + # happens also be a version of activesupport in repo4, but not the one that + # version 1.0.0 of somegem wants. This test makes sure that bundler tries to + # use the version in the most scoped source, even if not compatible, and + # gives a resolution error build_repo4 do build_gem "activesupport", "1.2.0" build_gem "somegem", "1.0.0" do |s| @@ -327,14 +311,14 @@ def require(*args) gemfile <<-G source "#{source_uri}" - source "#{source_uri}/extra" - gem 'somegem', '1.0.0' + source "#{source_uri}/extra" do + gem 'somegem', '1.0.0' + end G - bundle :install, artifice: "endpoint_extra_api" + bundle :install, artifice: "compact_index_extra_api", raise_on_error: false - expect(the_bundle).to include_gems "somegem 1.0.0" - expect(the_bundle).to include_gems "activesupport 1.2.3" + expect(err).to include("Could not find compatible versions") end it "prints API output properly with back deps" do @@ -368,25 +352,6 @@ def require(*args) FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end - install_gemfile <<-G, artifice: "endpoint_extra_missing" - source "#{source_uri}" - source "#{source_uri}/extra" - gem "back_deps" - G - - expect(the_bundle).to include_gems "back_deps 1.0" - end - - it "does not fetch every spec when doing back deps using blocks" do - build_repo2 do - build_gem "back_deps" do |s| - s.add_dependency "foo" - end - build_gem "missing" - - FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] - end - install_gemfile <<-G, artifice: "endpoint_extra_missing" source "#{source_uri}" source "#{source_uri}/extra" do @@ -405,26 +370,6 @@ def require(*args) FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] end - gemfile <<-G - source "#{source_uri}" - source "#{source_uri}/extra" - gem "back_deps" - G - - bundle :install, artifice: "endpoint_extra" - bundle "config set --local deployment true" - bundle :install, artifice: "endpoint_extra" - expect(the_bundle).to include_gems "back_deps 1.0" - end - - it "fetches again when more dependencies are found in subsequent sources using deployment mode with blocks" do - build_repo2 do - build_gem "back_deps" do |s| - s.add_dependency "foo" - end - FileUtils.rm_r Dir[gem_repo2("gems/foo-*.gem")] - end - gemfile <<-G source "#{source_uri}" source "#{source_uri}/extra" do @@ -546,19 +491,6 @@ def require(*args) expect(out).not_to include("#{user}:#{password}") end - it "strips http basic auth creds when warning about ambiguous sources" do - gemfile <<-G - source "#{basic_auth_source_uri}" - source "#{file_uri_for(gem_repo1)}" - gem "myrack" - G - - bundle :install, artifice: "endpoint_basic_authentication" - expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.") - expect(err).not_to include("#{user}:#{password}") - expect(the_bundle).to include_gems "myrack 1.0.0" - end - it "does not pass the user / password to different hosts on redirect" do gemfile <<-G source "#{basic_auth_source_uri}" diff --git a/spec/bundler/other/major_deprecation_spec.rb b/spec/bundler/other/major_deprecation_spec.rb index bf0fca5ddd6baa..e9d62bc3b87df5 100644 --- a/spec/bundler/other/major_deprecation_spec.rb +++ b/spec/bundler/other/major_deprecation_spec.rb @@ -484,53 +484,62 @@ context "bundle install with multiple sources" do before do - install_gemfile <<-G + install_gemfile <<-G, raise_on_error: false source "https://gem.repo3" source "https://gem.repo1" G end - it "shows a deprecation" do - expect(deprecations).to include( - "Your Gemfile contains multiple global sources. " \ - "Using `source` more than once without a block is a security risk, and " \ - "may result in installing unexpected gems. To resolve this warning, use " \ - "a block to indicate which gems should come from the secondary source." + it "fails with a helpful error" do + expect(err).to include( + "This Gemfile contains multiple global sources. " \ + "Each source after the first must include a block to indicate which gems " \ + "should come from that source" ) end it "doesn't show lockfile deprecations if there's a lockfile" do - bundle "install" + lockfile <<~L + GEM + remote: https://gem.repo3/ + remote: https://gem.repo1/ + specs: + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES - expect(deprecations).to include( - "Your Gemfile contains multiple global sources. " \ - "Using `source` more than once without a block is a security risk, and " \ - "may result in installing unexpected gems. To resolve this warning, use " \ - "a block to indicate which gems should come from the secondary source." + BUNDLED WITH + #{Bundler::VERSION} + L + bundle "install", raise_on_error: false + + expect(err).to include( + "This Gemfile contains multiple global sources. " \ + "Each source after the first must include a block to indicate which gems " \ + "should come from that source" ) - expect(deprecations).not_to include( + expect(err).not_to include( "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. " \ "Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure." ) bundle "config set --local frozen true" - bundle "install" + bundle "install", raise_on_error: false - expect(deprecations).to include( - "Your Gemfile contains multiple global sources. " \ - "Using `source` more than once without a block is a security risk, and " \ - "may result in installing unexpected gems. To resolve this warning, use " \ - "a block to indicate which gems should come from the secondary source." + expect(err).to include( + "This Gemfile contains multiple global sources. " \ + "Each source after the first must include a block to indicate which gems " \ + "should come from that source" ) - expect(deprecations).not_to include( + expect(err).not_to include( "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. " \ "Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure." ) end - - pending "fails with a helpful error", bundler: "4" end - context "bundle install in frozen mode with a lockfile with a single rubygems section with multiple remotes" do + context "bundle install with a lockfile with a single rubygems section with multiple remotes" do before do build_repo3 do build_gem "myrack", "0.9.1" @@ -559,17 +568,13 @@ BUNDLED WITH #{Bundler::VERSION} L - - bundle "config set --local frozen true" end - it "shows a deprecation" do - bundle "install" + it "shows an error" do + bundle "install", raise_on_error: false - expect(deprecations).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure.") + expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure.") end - - pending "fails with a helpful error", bundler: "4" end context "when Bundler.setup is run in a ruby script" do From db027afebd3ee8ef3fd70ffea2ef7756f48003ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= <2887858+deivid-rodriguez@users.noreply.github.com> Date: Tue, 9 Sep 2025 19:19:01 +0200 Subject: [PATCH 12/18] [rubygems/rubygems] Remove aggregate source mentions It's a term from times with multiple remote sources, let's move on :) https://github.com/rubygems/rubygems/commit/6439b8944e --- lib/bundler/plugin/source_list.rb | 2 +- lib/bundler/source_list.rb | 4 ++-- spec/bundler/bundler/source_list_spec.rb | 26 ++++++++++++------------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/bundler/plugin/source_list.rb b/lib/bundler/plugin/source_list.rb index 746996de5548ac..d929ade29e7ee4 100644 --- a/lib/bundler/plugin/source_list.rb +++ b/lib/bundler/plugin/source_list.rb @@ -23,7 +23,7 @@ def all_sources private - def rubygems_aggregate_class + def source_class Plugin::Installer::Rubygems end end diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb index 6dba3f35e8f288..38fa0972e64ebc 100644 --- a/lib/bundler/source_list.rb +++ b/lib/bundler/source_list.rb @@ -9,7 +9,7 @@ class SourceList :metadata_source def global_rubygems_source - @global_rubygems_source ||= rubygems_aggregate_class.new("allow_local" => true) + @global_rubygems_source ||= source_class.new("allow_local" => true) end def initialize @@ -191,7 +191,7 @@ def replace_path_source(replacement_sources, gemfile_source) end end - def rubygems_aggregate_class + def source_class Source::Rubygems end diff --git a/spec/bundler/bundler/source_list_spec.rb b/spec/bundler/bundler/source_list_spec.rb index 13453cb2a33a0d..6e0be6c92fccb3 100644 --- a/spec/bundler/bundler/source_list_spec.rb +++ b/spec/bundler/bundler/source_list_spec.rb @@ -11,7 +11,7 @@ subject(:source_list) { Bundler::SourceList.new } - let(:rubygems_aggregate) { Bundler::Source::Rubygems.new } + let(:global_rubygems_source) { Bundler::Source::Rubygems.new } let(:metadata_source) { Bundler::Source::Metadata.new } describe "adding sources" do @@ -118,11 +118,11 @@ describe "#add_global_rubygems_remote" do let!(:returned_source) { source_list.add_global_rubygems_remote("https://rubygems.org/") } - it "returns the aggregate rubygems source" do + it "returns the global rubygems source" do expect(returned_source).to be_instance_of(Bundler::Source::Rubygems) end - it "adds the provided remote to the beginning of the aggregate source" do + it "adds the provided remote to the beginning of the global source" do source_list.add_global_rubygems_remote("https://othersource.org") expect(returned_source.remotes).to eq [ Gem::URI("https://othersource.org/"), @@ -156,21 +156,21 @@ end describe "#all_sources" do - it "includes the aggregate rubygems source when rubygems sources have been added" do + it "includes the global rubygems source when rubygems sources have been added" do source_list.add_git_source("uri" => "git://host/path.git") source_list.add_rubygems_source("remotes" => ["https://rubygems.org"]) source_list.add_path_source("path" => "/path/to/gem") source_list.add_plugin_source("new_source", "uri" => "https://some.url/a") - expect(source_list.all_sources).to include rubygems_aggregate + expect(source_list.all_sources).to include global_rubygems_source end - it "includes the aggregate rubygems source when no rubygems sources have been added" do + it "includes the global rubygems source when no rubygems sources have been added" do source_list.add_git_source("uri" => "git://host/path.git") source_list.add_path_source("path" => "/path/to/gem") source_list.add_plugin_source("new_source", "uri" => "https://some.url/a") - expect(source_list.all_sources).to include rubygems_aggregate + expect(source_list.all_sources).to include global_rubygems_source end it "returns sources of the same type in the reverse order that they were added" do @@ -204,7 +204,7 @@ Bundler::Source::Rubygems.new("remotes" => ["https://third-rubygems.org"]), Bundler::Source::Rubygems.new("remotes" => ["https://fourth-rubygems.org"]), Bundler::Source::Rubygems.new("remotes" => ["https://fifth-rubygems.org"]), - rubygems_aggregate, + global_rubygems_source, metadata_source, ] end @@ -297,19 +297,19 @@ end describe "#rubygems_sources" do - it "includes the aggregate rubygems source when rubygems sources have been added" do + it "includes the global rubygems source when rubygems sources have been added" do source_list.add_git_source("uri" => "git://host/path.git") source_list.add_rubygems_source("remotes" => ["https://rubygems.org"]) source_list.add_path_source("path" => "/path/to/gem") - expect(source_list.rubygems_sources).to include rubygems_aggregate + expect(source_list.rubygems_sources).to include global_rubygems_source end - it "returns only the aggregate rubygems source when no rubygems sources have been added" do + it "returns only the global rubygems source when no rubygems sources have been added" do source_list.add_git_source("uri" => "git://host/path.git") source_list.add_path_source("path" => "/path/to/gem") - expect(source_list.rubygems_sources).to eq [rubygems_aggregate] + expect(source_list.rubygems_sources).to eq [global_rubygems_source] end it "returns rubygems sources in the reverse order that they were added" do @@ -331,7 +331,7 @@ Bundler::Source::Rubygems.new("remotes" => ["https://third-rubygems.org"]), Bundler::Source::Rubygems.new("remotes" => ["https://fourth-rubygems.org"]), Bundler::Source::Rubygems.new("remotes" => ["https://fifth-rubygems.org"]), - rubygems_aggregate, + global_rubygems_source, ] end end From 1213adfe5526d65cce81a9fb127074130c8faea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Barri=C3=A9?= Date: Mon, 15 Sep 2025 16:26:43 +0200 Subject: [PATCH 13/18] [ruby/json] Better handle missing ostruct In the Ruby test suite, this test class is causing trouble because ostruct is not available. Having an autoload for JSON::GenericObject but causing it not to define the constant causes a warning. See https://github.com/ruby/json/commit/0dc1cd407e77 and https://github.com/ruby/json/commit/caa5d8cdd748 in ruby. We can skip defining the test class entirely instead when ostruct is not available. https://github.com/ruby/json/commit/6f6a4cdfd7 --- test/json/json_generic_object_test.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/json/json_generic_object_test.rb b/test/json/json_generic_object_test.rb index 995d57edafe2dd..71d105976d0cfa 100644 --- a/test/json/json_generic_object_test.rb +++ b/test/json/json_generic_object_test.rb @@ -1,8 +1,14 @@ # frozen_string_literal: true require_relative 'test_helper' -class JSONGenericObjectTest < Test::Unit::TestCase +# ostruct is required to test JSON::GenericObject +begin + require "ostruct" +rescue LoadError + return +end +class JSONGenericObjectTest < Test::Unit::TestCase def setup if defined?(JSON::GenericObject) @go = JSON::GenericObject[ :a => 1, :b => 2 ] From 971174054a26be0a4becbe7c67a7cc980158abf2 Mon Sep 17 00:00:00 2001 From: Jun Aruga Date: Thu, 4 Sep 2025 18:59:42 +0100 Subject: [PATCH 14/18] Add a macro to manage the condition of no-inline version rb_current_ec Add the macro `RB_THREAD_CURRENT_EC_NOINLINE` to manage the condition to use no-inline version rb_current_ec for a better maintainability. Note that the `vm_core.h` includes the `THREAD_IMPL_H` by the `#include THREAD_IMPL_H`. The `THREAD_IMPL_H` can be `thread_none.h`, `thread_pthread.h` or `thread_win32.h` according to the `tool/m4/ruby_thread.m4` creating the `THREAD_IMPL_H`. The change in this commit only defining the `RB_THREAD_CURRENT_EC_NOINLINE` in the `thread_pthread.h` is okay in this situation. Because in the `thread_none.h` case, the thread feature is not used at all, including Thread-Local Storage (TLS), and in the `thread_win32.h` case, the `RB_THREAD_LOCAL_SPECIFIER` is not defined. In the `thread_pthread.h` case, the `RB_THREAD_LOCAL_SPECIFIER` is defined in the `configure.ac`. In the `thread_none.h` case, the `RB_THREAD_LOCAL_SPECIFIER` is defined in the `thread_none.h`. --- thread_pthread.h | 8 ++++++-- vm.c | 2 +- vm_core.h | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/thread_pthread.h b/thread_pthread.h index 20a3876759c713..d635948c4bbb7c 100644 --- a/thread_pthread.h +++ b/thread_pthread.h @@ -17,6 +17,11 @@ #define RB_NATIVETHREAD_LOCK_INIT PTHREAD_MUTEX_INITIALIZER #define RB_NATIVETHREAD_COND_INIT PTHREAD_COND_INITIALIZER +// TLS can not be accessed across .so on arm64 and perhaps ppc64le too. +#if defined(__arm64__) || defined(__aarch64__) || defined(__powerpc64__) +# define RB_THREAD_CURRENT_EC_NOINLINE +#endif + // this data should be protected by timer_th.waiting_lock struct rb_thread_sched_waiting { enum thread_sched_waiting_flag { @@ -133,8 +138,7 @@ struct rb_thread_sched { #ifdef RB_THREAD_LOCAL_SPECIFIER NOINLINE(void rb_current_ec_set(struct rb_execution_context_struct *)); - # if defined(__arm64__) || defined(__aarch64__) || defined(__powerpc64__) - // TLS can not be accessed across .so on arm64 and perhaps ppc64le too. + # ifdef RB_THREAD_CURRENT_EC_NOINLINE NOINLINE(struct rb_execution_context_struct *rb_current_ec(void)); # else RUBY_EXTERN RB_THREAD_LOCAL_SPECIFIER struct rb_execution_context_struct *ruby_current_ec; diff --git a/vm.c b/vm.c index e97619cc14b1c3..da92c5bd009f83 100644 --- a/vm.c +++ b/vm.c @@ -594,7 +594,7 @@ rb_current_ec_set(rb_execution_context_t *ec) } -#if defined(__arm64__) || defined(__aarch64__) || defined(__powerpc64__) +#ifdef RB_THREAD_CURRENT_EC_NOINLINE rb_execution_context_t * rb_current_ec(void) { diff --git a/vm_core.h b/vm_core.h index 1d02298c6cd439..9156b7286891a7 100644 --- a/vm_core.h +++ b/vm_core.h @@ -1999,7 +1999,7 @@ static inline rb_execution_context_t * rb_current_execution_context(bool expect_ec) { #ifdef RB_THREAD_LOCAL_SPECIFIER - #if defined(__arm64__) || defined(__aarch64__) || defined(__powerpc64__) + #ifdef RB_THREAD_CURRENT_EC_NOINLINE rb_execution_context_t * volatile ec = rb_current_ec(); #else rb_execution_context_t * volatile ec = ruby_current_ec; From a2849239db9a92c3cde75724f92688e230718cc6 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 16 Sep 2025 17:20:46 +0900 Subject: [PATCH 15/18] Expect `git -C ` to work This option is available since git 1.8.5 that was released in 2013. --- common.mk | 12 +++++++---- defs/gmake.mk | 50 ++++++++++++++++++++++---------------------- template/Makefile.in | 3 +-- win32/Makefile.sub | 6 +++--- 4 files changed, 37 insertions(+), 34 deletions(-) diff --git a/common.mk b/common.mk index ef7eb6ab58ca1e..0f157c4d56566b 100644 --- a/common.mk +++ b/common.mk @@ -44,6 +44,10 @@ RUBYLIB = $(PATH_SEPARATOR) RUBYOPT = - RUN_OPTS = --disable-gems +GIT_IN_SRC = $(GIT) -C $(srcdir) +GIT_LOG = $(GIT_IN_SRC) log +GIT_LOG_FORMAT = $(GIT_LOG) --pretty=format: + # GITPULLOPTIONS = --no-tags PRISM_SRCDIR = $(srcdir)/prism @@ -1514,8 +1518,8 @@ update-bundled_gems: PHONY $(tooldir)/update-bundled_gems.rb \ "$(srcdir)/gems/bundled_gems" | \ $(IFCHANGE) "$(srcdir)/gems/bundled_gems" - - $(GIT) -C "$(srcdir)" diff --no-ext-diff --ignore-submodules --exit-code || \ - $(GIT) -C "$(srcdir)" commit -m "Update bundled_gems" gems/bundled_gems + $(GIT_IN_SRC) diff --no-ext-diff --ignore-submodules --exit-code || \ + $(GIT_IN_SRC) commit -m "Update bundled_gems" gems/bundled_gems PRECHECK_BUNDLED_GEMS = yes test-bundled-gems-precheck: $(TEST_RUNNABLE)-test-bundled-gems-precheck @@ -1899,8 +1903,8 @@ nightly: yesterday $(DOT_WAIT) install yesterday: rewindable rewindable: - $(GIT) -C $(srcdir) status --porcelain - $(GIT) -C $(srcdir) diff --quiet + $(GIT_IN_SRC) status --porcelain + $(GIT_IN_SRC) diff --quiet HELP_EXTRA_TASKS = "" diff --git a/defs/gmake.mk b/defs/gmake.mk index 795320ce2d20aa..1173a147a2a118 100644 --- a/defs/gmake.mk +++ b/defs/gmake.mk @@ -220,8 +220,8 @@ post-commit: $(if $(DOT_WAIT),,do-commit) GITHUB_RUBY_URL = https://github.com/ruby/ruby PR = -COMMIT_GPG_SIGN = $(shell $(GIT) -C "$(srcdir)" config commit.gpgsign) -REMOTE_GITHUB_URL = $(shell $(GIT) -C "$(srcdir)" config remote.github.url) +COMMIT_GPG_SIGN = $(shell $(GIT_IN_SRC) config commit.gpgsign) +REMOTE_GITHUB_URL = $(shell $(GIT_IN_SRC) config remote.github.url) COMMITS_NOTES = commits .PHONY: fetch-github @@ -236,19 +236,19 @@ define fetch-github $(eval REMOTE_GITHUB_URL := $(REMOTE_GITHUB_URL)) $(if $(REMOTE_GITHUB_URL),, echo adding $(GITHUB_RUBY_URL) as remote github - $(GIT) -C "$(srcdir)" remote add github $(GITHUB_RUBY_URL) - $(GIT) -C "$(srcdir)" config --add remote.github.fetch +refs/notes/$(COMMITS_NOTES):refs/notes/$(COMMITS_NOTES) + $(GIT_IN_SRC) remote add github $(GITHUB_RUBY_URL) + $(GIT_IN_SRC) config --add remote.github.fetch +refs/notes/$(COMMITS_NOTES):refs/notes/$(COMMITS_NOTES) $(eval REMOTE_GITHUB_URL := $(GITHUB_RUBY_URL)) ) - $(if $(shell $(GIT) -C "$(srcdir)" rev-parse "github/pull/$(1)/head" -- 2> /dev/null), - $(GIT) -C "$(srcdir)" branch -f "gh-$(1)" "github/pull/$(1)/head", - $(GIT) -C "$(srcdir)" fetch -f github "pull/$(1)/head:gh-$(1)" + $(if $(shell $(GIT_IN_SRC) rev-parse "github/pull/$(1)/head" -- 2> /dev/null), + $(GIT_IN_SRC) branch -f "gh-$(1)" "github/pull/$(1)/head", + $(GIT_IN_SRC) fetch -f github "pull/$(1)/head:gh-$(1)" ) endef .PHONY: checkout-github checkout-github: fetch-github - $(GIT) -C "$(srcdir)" checkout "gh-$(PR)" + $(GIT_IN_SRC) checkout "gh-$(PR)" .PHONY: update-github update-github: fetch-github @@ -261,25 +261,25 @@ update-github: fetch-github $(eval PR_BRANCH := $(word 2,$(PULL_REQUEST_FORK_BRANCH))) $(eval GITHUB_UPDATE_WORKTREE := $(shell mktemp -d "$(srcdir)/gh-$(PR)-XXXXXX")) - $(GIT) -C "$(srcdir)" worktree add $(notdir $(GITHUB_UPDATE_WORKTREE)) "gh-$(PR)" + $(GIT_IN_SRC) worktree add $(notdir $(GITHUB_UPDATE_WORKTREE)) "gh-$(PR)" $(GIT) -C "$(GITHUB_UPDATE_WORKTREE)" merge master --no-edit @$(BASERUBY) -e 'print "Are you sure to push this to PR=$(PR)? [Y/n]: "; exit(gets.chomp != "n")' - $(GIT) -C "$(srcdir)" remote add fork-$(PR) git@github.com:$(FORK_REPO).git + $(GIT_IN_SRC) remote add fork-$(PR) git@github.com:$(FORK_REPO).git $(GIT) -C "$(GITHUB_UPDATE_WORKTREE)" push fork-$(PR) gh-$(PR):$(PR_BRANCH) - $(GIT) -C "$(srcdir)" remote rm fork-$(PR) - $(GIT) -C "$(srcdir)" worktree remove $(notdir $(GITHUB_UPDATE_WORKTREE)) - $(GIT) -C "$(srcdir)" branch -D gh-$(PR) + $(GIT_IN_SRC) remote rm fork-$(PR) + $(GIT_IN_SRC) worktree remove $(notdir $(GITHUB_UPDATE_WORKTREE)) + $(GIT_IN_SRC) branch -D gh-$(PR) .PHONY: pull-github pull-github: fetch-github $(call pull-github,$(PR)) define pull-github - $(eval GITHUB_MERGE_BASE := $(shell $(GIT) -C "$(srcdir)" log -1 --format=format:%H)) - $(eval GITHUB_MERGE_BRANCH := $(shell $(GIT) -C "$(srcdir)" symbolic-ref --short HEAD)) + $(eval GITHUB_MERGE_BASE := $(shell $(GIT_LOG_FORMAT):%H -1) + $(eval GITHUB_MERGE_BRANCH := $(shell $(GIT_IN_SRC) symbolic-ref --short HEAD)) $(eval GITHUB_MERGE_WORKTREE := $(shell mktemp -d "$(srcdir)/gh-$(1)-XXXXXX")) - $(GIT) -C "$(srcdir)" worktree prune - $(GIT) -C "$(srcdir)" worktree add $(notdir $(GITHUB_MERGE_WORKTREE)) "gh-$(1)" + $(GIT_IN_SRC) worktree prune + $(GIT_IN_SRC) worktree add $(notdir $(GITHUB_MERGE_WORKTREE)) "gh-$(1)" $(GIT) -C "$(GITHUB_MERGE_WORKTREE)" rebase $(GITHUB_MERGE_BRANCH) $(eval COMMIT_GPG_SIGN := $(COMMIT_GPG_SIGN)) $(if $(filter true,$(COMMIT_GPG_SIGN)), \ @@ -294,7 +294,7 @@ fetch-github-%: .PHONY: checkout-github-% checkout-github-%: fetch-github-% - $(GIT) -C "$(srcdir)" checkout "gh-$*" + $(GIT_IN_SRC) checkout "gh-$*" .PHONY: pr-% pull-github-% pr-% pull-github-%: fetch-github-% @@ -433,7 +433,7 @@ ifneq ($(DOT_WAIT),) endif ifeq ($(HAVE_GIT),yes) -REVISION_LATEST := $(shell $(CHDIR) $(srcdir) && $(GIT) log -1 --format=%H 2>/dev/null) +REVISION_LATEST := $(shell $(GIT_LOG_FORMAT)%H -1 2>/dev/null) else REVISION_LATEST := update endif @@ -495,7 +495,7 @@ endif update-deps: $(eval update_deps := $(shell date +update-deps-%Y%m%d)) $(eval deps_dir := $(shell mktemp -d)/$(update_deps)) - $(eval GIT_DIR := $(shell $(GIT) -C $(srcdir) rev-parse --absolute-git-dir)) + $(eval GIT_DIR := $(shell $(GIT_IN_SRC) rev-parse --absolute-git-dir)) $(GIT) --git-dir=$(GIT_DIR) worktree add $(deps_dir) cp $(tooldir)/config.guess $(tooldir)/config.sub $(deps_dir)/tool [ -f config.status ] && cp config.status $(deps_dir) @@ -543,13 +543,13 @@ matz: up $(eval NEW := $(MAJOR).$(MINOR).0) $(eval message := Development of $(NEW) started.) $(eval files := include/ruby/version.h include/ruby/internal/abi.h) - $(GIT) -C $(srcdir) mv -f NEWS.md doc/NEWS/NEWS-$(OLD).md - $(GIT) -C $(srcdir) commit -m "[DOC] Flush NEWS.md" + $(GIT_IN_SRC) mv -f NEWS.md doc/NEWS/NEWS-$(OLD).md + $(GIT_IN_SRC) commit -m "[DOC] Flush NEWS.md" sed -i~ \ -e "s/^\(#define RUBY_API_VERSION_MINOR\) .*/\1 $(MINOR)/" \ -e "s/^\(#define RUBY_ABI_VERSION\) .*/\1 0/" \ $(files:%=$(srcdir)/%) - $(GIT) -C $(srcdir) add $(files) + $(GIT_IN_SRC) add $(files) $(BASERUBY) -C $(srcdir) -p -00 \ -e 'BEGIN {old, new = ARGV.shift(2); STDOUT.reopen("NEWS.md")}' \ -e 'case $$.' \ @@ -559,8 +559,8 @@ matz: up -e 'next if /^[\[ *]/ =~ $$_' \ -e '$$_.sub!(/\n{2,}\z/, "\n\n")' \ $(OLD) $(NEW) doc/NEWS/NEWS-$(OLD).md - $(GIT) -C $(srcdir) add NEWS.md - $(GIT) -C $(srcdir) commit -m "$(message)" + $(GIT_IN_SRC) add NEWS.md + $(GIT_IN_SRC) commit -m "$(message)" tags: $(MAKE) GIT="$(GIT)" -C "$(srcdir)" -f defs/tags.mk diff --git a/template/Makefile.in b/template/Makefile.in index 68d4240c4b56fa..bf5281e0df8498 100644 --- a/template/Makefile.in +++ b/template/Makefile.in @@ -748,5 +748,4 @@ yes-test-syntax-suggest: $(PREPARE_SYNTAX_SUGGEST) no-test-syntax-suggest: yesterday: - $(GIT) -C $(srcdir) reset --hard \ - `$(GIT) -C $(srcdir) log -1 --before=00:00+0900 --format=%H` + $(GIT_IN_SRC) reset --hard `$(GIT_LOG_FORMAT):%H -1 --before=00:00+0900` diff --git a/win32/Makefile.sub b/win32/Makefile.sub index c91c05584e6331..180dfbb8feb7f4 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -1336,7 +1336,7 @@ $(RCFILES): $(RBCONFIG) $(srcdir)/revision.h $(srcdir)/win32/resource.rb update-benchmark-driver: $(GIT) clone https://github.com/benchmark-driver/benchmark-driver $(srcdir)/benchmark/benchmark-driver || \ - $(GIT) -C $(srcdir)/benchmark/benchmark-driver pull origin master + $(GIT_IN_SRC)/benchmark/benchmark-driver pull origin master $(ruby_pc): $(RBCONFIG) @$(BOOTSTRAPRUBY) $(tooldir)/expand-config.rb \ @@ -1507,5 +1507,5 @@ exts: rubyspec-capiext yesterday: for /f "usebackq" %H in \ - (`$(GIT) -C $(srcdir) log -1 "--before=00:00+0900" "--format=%H"`) do \ - $(GIT) -C $(srcdir) reset --hard %%H + (`$(GIT_LOG_FORMAT):%H -1 "--before=00:00+0900"`) do \ + $(GIT_IN_SRC) reset --hard %%H From 5480a9c34457fc93a913cecddf361e0531ee1f26 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 16 Sep 2025 17:38:23 +0900 Subject: [PATCH 16/18] Reject git command that does not accept `-C` option --- configure.ac | 10 ++++++++-- win32/Makefile.sub | 5 +++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 8cb30429dcddca..2d1c99bfb66702 100644 --- a/configure.ac +++ b/configure.ac @@ -107,10 +107,16 @@ HAVE_GIT=yes AC_ARG_WITH(git, AS_HELP_STRING([--without-git], [never use git]), [AS_CASE([$withval], - [no], [GIT=never-use HAVE_GIT=no], + [no], [HAVE_GIT=no], [yes], [], [GIT=$withval])]) -AS_IF([test x"$HAVE_GIT" = xyes], [command -v "$GIT" > /dev/null || HAVE_GIT=no]) +{ + test x"$HAVE_GIT" = xyes && + command -v "$GIT" > /dev/null && + # git 1.8.4 fails with `-C` as unknown option, but git 1.8.5 + # succeeds and exits by `--version`. + $GIT -C . --version > /dev/null 2>&1 +} || HAVE_GIT=no GIT=never-use AC_SUBST(GIT) AC_SUBST(HAVE_GIT) diff --git a/win32/Makefile.sub b/win32/Makefile.sub index 180dfbb8feb7f4..89d1ac4c929925 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -506,17 +506,18 @@ VPATH = $(arch_hdrdir)/ruby;$(hdrdir)/ruby;$(srcdir);$(srcdir)/missing;$(win_src !ifndef GIT GIT = git !endif +GIT_TO_CHECK_C_OPTION = -C . --version >nul 2>&1 !if "$(HAVE_GIT)" == "yes" || "$(HAVE_GIT)" == "no" !else if "$(GIT)" == "" HAVE_GIT = no !else if [for %I in ($(GIT)) do @if not "%~xI" == "" exit 1] -! if [for %I in ($(GIT)) do @if not "%~$$PATH:I" == "" exit 1] +! if [%I $(GIT_TO_CHECK_C_OPTION)] == 0 HAVE_GIT = yes ! else HAVE_GIT = no ! endif !else -! if [for %x in (%PATHEXT:;= %) do @for %I in ($(GIT)%x) do @if not "%~$$PATH:I" == "" exit 1] +! if [for %x in (%PATHEXT:;= %) do @($(GIT)%x $(GIT_TO_CHECK_C_OPTION) && exit 0)] == 0 HAVE_GIT = yes ! else HAVE_GIT = no From a6a5fe322289c6daf1b1a8a96f4f244ed1f0e814 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 16 Sep 2025 20:28:16 +0900 Subject: [PATCH 17/18] Suppress verification messages `log.showSignature` configuration and `--no-show-signature` option was added at git 2.10.0. --- common.mk | 2 +- configure.ac | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/common.mk b/common.mk index 0f157c4d56566b..1b68736a18e398 100644 --- a/common.mk +++ b/common.mk @@ -45,7 +45,7 @@ RUBYOPT = - RUN_OPTS = --disable-gems GIT_IN_SRC = $(GIT) -C $(srcdir) -GIT_LOG = $(GIT_IN_SRC) log +GIT_LOG = $(GIT_IN_SRC) log --no-show-signature GIT_LOG_FORMAT = $(GIT_LOG) --pretty=format: # GITPULLOPTIONS = --no-tags diff --git a/configure.ac b/configure.ac index 2d1c99bfb66702..da5afc00185f95 100644 --- a/configure.ac +++ b/configure.ac @@ -113,9 +113,11 @@ AC_ARG_WITH(git, { test x"$HAVE_GIT" = xyes && command -v "$GIT" > /dev/null && - # git 1.8.4 fails with `-C` as unknown option, but git 1.8.5 - # succeeds and exits by `--version`. - $GIT -C . --version > /dev/null 2>&1 + # `git -C`: 1.8.5 + # `git log --no-show-signature`: 2.10.0 + AS_CASE([`$GIT -C . --version 2> /dev/null | sed 's/.* //'`], + [0.*|1.*|2.@<:@0-9@:>@.*], [false], + [true]) } || HAVE_GIT=no GIT=never-use AC_SUBST(GIT) AC_SUBST(HAVE_GIT) From 809dfb861ef0599c2572f10236aaf25c2093f6af Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Mon, 15 Sep 2025 11:24:23 -0400 Subject: [PATCH 18/18] Don't export rb_imemo_new Nothing needs rb_imemo_new exported anymore. --- internal/imemo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/imemo.h b/internal/imemo.h index eee3dd71854a8e..3b91ef4b818f93 100644 --- a/internal/imemo.h +++ b/internal/imemo.h @@ -131,6 +131,7 @@ struct MEMO { #ifndef RUBY_RUBYPARSER_H typedef struct rb_imemo_tmpbuf_struct rb_imemo_tmpbuf_t; #endif +VALUE rb_imemo_new(enum imemo_type type, VALUE v0, size_t size); VALUE rb_imemo_tmpbuf_new(void); struct vm_ifunc *rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int max_argc); static inline enum imemo_type imemo_type(VALUE imemo); @@ -147,7 +148,6 @@ void rb_imemo_mark_and_move(VALUE obj, bool reference_updating); void rb_imemo_free(VALUE obj); RUBY_SYMBOL_EXPORT_BEGIN -VALUE rb_imemo_new(enum imemo_type type, VALUE v0, size_t size); const char *rb_imemo_name(enum imemo_type type); RUBY_SYMBOL_EXPORT_END