diff --git a/compile.c b/compile.c index cbf00c9da113b8..4a0a5e83f3a3c0 100644 --- a/compile.c +++ b/compile.c @@ -3149,41 +3149,56 @@ find_destination(INSN *i) static int remove_unreachable_chunk(rb_iseq_t *iseq, LINK_ELEMENT *i) { - LINK_ELEMENT *first = i, *end; + LINK_ELEMENT *first = i, *end, *scan; int *unref_counts = 0, nlabels = ISEQ_COMPILE_DATA(iseq)->label_no; if (!i) return 0; unref_counts = ALLOCA_N(int, nlabels); MEMZERO(unref_counts, int, nlabels); - end = i; + + scan = i; do { LABEL *lab; - if (IS_INSN(i)) { - if (IS_INSN_ID(i, leave)) { - end = i; + if (IS_INSN(scan)) { + if (IS_INSN_ID(scan, leave)) { break; } - else if ((lab = find_destination((INSN *)i)) != 0) { + else if ((lab = find_destination((INSN *)scan)) != 0) { unref_counts[lab->label_no]++; } } - else if (IS_LABEL(i)) { - lab = (LABEL *)i; + else if (IS_LABEL(scan)) { + lab = (LABEL *)scan; if (lab->unremovable) return 0; + } + else if (IS_ADJUST(scan)) { + return 0; + } + } while ((scan = scan->next) != 0); + + end = i; + scan = i; + do { + LABEL *lab; + if (IS_INSN(scan)) { + if (IS_INSN_ID(scan, leave)) { + end = scan; + break; + } + } + else if (IS_LABEL(scan)) { + lab = (LABEL *)scan; if (lab->refcnt > unref_counts[lab->label_no]) { - if (i == first) return 0; + if (scan == first) return 0; break; } continue; } - else if (IS_TRACE(i)) { - /* do nothing */ - } - else if (IS_ADJUST(i)) { + else if (IS_ADJUST(scan)) { return 0; } - end = i; - } while ((i = i->next) != 0); + end = scan; + } while ((scan = scan->next) != 0); i = first; do { if (IS_INSN(i)) { diff --git a/doc/syntax/refinements.rdoc b/doc/syntax/refinements.rdoc index 80595eb4455ab6..836dac2c99ad15 100644 --- a/doc/syntax/refinements.rdoc +++ b/doc/syntax/refinements.rdoc @@ -246,7 +246,10 @@ invokes that method since +foo+ does not exist on Integer. When +super+ is invoked, method lookup starts: -* If the method is in a refinement, at the refined class or module +* If the method is in a refinement: + * At the next active refinement in scope at the +super+ call site, + excluding the current refinement, if such a refinement exists + * Otherwise, at the refined class or module * Otherwise, at the next ancestor Method lookup then proceeds as described in the Method Lookup section diff --git a/lib/bundler/bundler.gemspec b/lib/bundler/bundler.gemspec index 49319e81b4f08c..77e957108ccf6c 100644 --- a/lib/bundler/bundler.gemspec +++ b/lib/bundler/bundler.gemspec @@ -24,9 +24,9 @@ Gem::Specification.new do |s| s.metadata = { "bug_tracker_uri" => "https://github.com/ruby/rubygems/issues?q=is%3Aopen+is%3Aissue+label%3ABundler", - "changelog_uri" => "https://github.com/ruby/rubygems/blob/master/bundler/CHANGELOG.md", + "changelog_uri" => "https://github.com/ruby/rubygems/blob/master/CHANGELOG-bundler.md", "homepage_uri" => "https://bundler.io/", - "source_code_uri" => "https://github.com/ruby/rubygems/tree/master/bundler", + "source_code_uri" => "https://github.com/ruby/rubygems", } s.required_ruby_version = ">= 3.2.0" @@ -39,6 +39,9 @@ Gem::Specification.new do |s| # include the gemspec itself because warbler breaks w/o it s.files += %w[lib/bundler/bundler.gemspec] + # These live next to the gemspec when Bundler ships as a gem, but not when + # it is synced into Ruby core, where the gemspec moves under lib/bundler. + s.files += %w[CHANGELOG-bundler.md LICENSE-bundler.md README-bundler.md].select {|f| File.file?(f) } s.bindir = "exe" s.executables = %w[bundle bundler] s.require_paths = ["lib"] diff --git a/lib/bundler/ci_detector.rb b/lib/bundler/ci_detector.rb index e5fedbdea8d383..227e127c71c229 100644 --- a/lib/bundler/ci_detector.rb +++ b/lib/bundler/ci_detector.rb @@ -3,7 +3,7 @@ module Bundler module CIDetector # NOTE: Any changes made here will need to be made to both lib/rubygems/ci_detector.rb and - # bundler/lib/bundler/ci_detector.rb (which are enforced duplicates). + # lib/bundler/ci_detector.rb (which are enforced duplicates). # TODO: Drop that duplication once bundler drops support for RubyGems 3.4 # # ## Recognized CI providers, their signifiers, and the relevant docs ## diff --git a/lib/rubygems/ci_detector.rb b/lib/rubygems/ci_detector.rb index 7a2d4ee29a9360..22e9552079cae1 100644 --- a/lib/rubygems/ci_detector.rb +++ b/lib/rubygems/ci_detector.rb @@ -3,7 +3,7 @@ module Gem module CIDetector # NOTE: Any changes made here will need to be made to both lib/rubygems/ci_detector.rb and - # bundler/lib/bundler/ci_detector.rb (which are enforced duplicates). + # lib/bundler/ci_detector.rb (which are enforced duplicates). # TODO: Drop that duplication once bundler drops support for RubyGems 3.4 # # ## Recognized CI providers, their signifiers, and the relevant docs ## diff --git a/lib/rubygems/commands/setup_command.rb b/lib/rubygems/commands/setup_command.rb index 175599967cf62d..ad4aaab384a0c6 100644 --- a/lib/rubygems/commands/setup_command.rb +++ b/lib/rubygems/commands/setup_command.rb @@ -292,7 +292,6 @@ def shebang def install_lib(lib_dir) libs = { "RubyGems" => "lib" } - libs["Bundler"] = "bundler/lib" libs.each do |tool, path| say "Installing #{tool}" if @verbose @@ -366,7 +365,7 @@ def install_default_bundler_gem(bin_dir) target_specs_dir end - new_bundler_spec = Dir.chdir("bundler") { Gem::Specification.load("bundler.gemspec") } + new_bundler_spec = Gem::Specification.load("bundler.gemspec") full_name = new_bundler_spec.full_name gemspec_path = "#{full_name}.gemspec" @@ -390,26 +389,24 @@ def install_default_bundler_gem(bin_dir) require_relative "../installer" - Dir.chdir("bundler") do - built_gem = Gem::Package.build(new_bundler_spec) - begin - installer = Gem::Installer.at( - built_gem, - env_shebang: options[:env_shebang], - format_executable: options[:format_executable], - force: options[:force], - bin_dir: bin_dir, - install_dir: default_dir, - wrappers: true - ) - # We need to install only executable and default spec files. - # lib/bundler.rb and lib/bundler/* are available under the site_ruby directory. - installer.extract_bin - installer.generate_bin - installer.write_default_spec - ensure - FileUtils.rm_f built_gem - end + built_gem = Gem::Package.build(new_bundler_spec) + begin + installer = Gem::Installer.at( + built_gem, + env_shebang: options[:env_shebang], + format_executable: options[:format_executable], + force: options[:force], + bin_dir: bin_dir, + install_dir: default_dir, + wrappers: true + ) + # We need to install only executable and default spec files. + # lib/bundler.rb and lib/bundler/* are available under the site_ruby directory. + installer.extract_bin + installer.generate_bin + installer.write_default_spec + ensure + FileUtils.rm_f built_gem end new_bundler_spec.executables.each {|executable| bin_file_names << target_bin_path(bin_dir, executable) } @@ -499,7 +496,7 @@ def remove_old_bin_files(bin_dir) def remove_old_lib_files(lib_dir) lib_dirs = { File.join(lib_dir, "rubygems") => "lib/rubygems" } - lib_dirs[File.join(lib_dir, "bundler")] = "bundler/lib/bundler" + lib_dirs[File.join(lib_dir, "bundler")] = "lib/bundler" lib_dirs.each do |old_lib_dir, new_lib_dir| lib_files = files_in(new_lib_dir) diff --git a/lib/rubygems/platform.rb b/lib/rubygems/platform.rb index 367b00e7e1a286..dac1ce885829fe 100644 --- a/lib/rubygems/platform.rb +++ b/lib/rubygems/platform.rb @@ -196,7 +196,7 @@ def hash # :nodoc: # the runtime platform. # #-- - # NOTE: Until it can be removed, changes to this method must also be reflected in `bundler/lib/bundler/rubygems_ext.rb` + # NOTE: Until it can be removed, changes to this method must also be reflected in `lib/bundler/rubygems_ext.rb` def ===(other) return nil unless Gem::Platform === other @@ -221,7 +221,7 @@ def ===(other) end #-- - # NOTE: Until it can be removed, changes to this method must also be reflected in `bundler/lib/bundler/rubygems_ext.rb` + # NOTE: Until it can be removed, changes to this method must also be reflected in `lib/bundler/rubygems_ext.rb` def normalized_linux_version return nil unless @version diff --git a/ractor.rb b/ractor.rb index 2dc60f5ff64926..366a1192c818d2 100644 --- a/ractor.rb +++ b/ractor.rb @@ -615,7 +615,7 @@ def value # # call-seq: - # ractor.monitor(port) -> self + # ractor.monitor(port) -> true or false # # Registers the port as a monitoring port for this ractor. When the ractor terminates, # the port receives a Symbol object. @@ -623,6 +623,10 @@ def value # * +:exited+ is sent if the ractor terminates without an unhandled exception. # * +:aborted+ is sent if the ractor terminates by an unhandled exception. # + # Returns +true+ if the monitor was registered (the ractor is still running). + # Returns +false+ if the ractor had already terminated; in that case the + # termination message (+:exited+ or +:aborted+) is sent to the port immediately. + # # r = Ractor.new{ some_task() } # r.monitor(port = Ractor::Port.new) # port.receive #=> :exited and r is terminated diff --git a/spec/bin/bundle b/spec/bin/bundle index 8f8b5352951537..23e386505d6e7a 100755 --- a/spec/bin/bundle +++ b/spec/bin/bundle @@ -1,6 +1,7 @@ #!/usr/bin/env ruby # frozen_string_literal: true +require_relative "../bundler/support/switch_rubygems" require_relative "../bundler/support/activate" load File.expand_path("bundle", Spec::Path.exedir) diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb index f100bdfb9edb55..907f81d756ff7e 100644 --- a/spec/bundler/commands/update_spec.rb +++ b/spec/bundler/commands/update_spec.rb @@ -1582,8 +1582,11 @@ 999.0.0 L - expect(the_bundle).to include_gems "bundler 999.0.0" - expect(the_bundle).to include_gems "myrack 1.0" + bundle "--version" + expect(out).to include("999.0.0") + + bundle "list" + expect(out).to include("myrack (1.0)") end it "does not claim to update to Bundler version to a wrong version when cached gems are present" do @@ -1665,8 +1668,11 @@ 9.9.9 L - expect(the_bundle).to include_gems "bundler 9.9.9" - expect(the_bundle).to include_gems "myrack 1.0" + bundle "--version" + expect(out).to include("9.9.9") + + bundle "list" + expect(out).to include("myrack (1.0)") end it "errors if the explicit target version does not exist" do diff --git a/spec/bundler/install/gemfile_spec.rb b/spec/bundler/install/gemfile_spec.rb index 83875a3d0e300f..b8cd66ca7580ce 100644 --- a/spec/bundler/install/gemfile_spec.rb +++ b/spec/bundler/install/gemfile_spec.rb @@ -135,7 +135,7 @@ def source(source, *args, &blk) it "shows culprit file and line" do skip "ruby-core test setup has always \"lib\" in $LOAD_PATH so `require \"bundler\"` always activates the local version rather than using RubyGems gem activation stuff, causing conflicts" if ruby_core? - install_gemfile "source 'https://gem.repo1'", requires: [bundler_bug], artifice: nil, raise_on_error: false + install_gemfile "source 'https://gem.repo1'", requires: [bundler_bug], artifice: nil, raise_on_error: false, bundle_bin: dev_binstub expect(err).to include("bundler_bug.rb:6") end end diff --git a/spec/bundler/runtime/setup_spec.rb b/spec/bundler/runtime/setup_spec.rb index ceb6fcf66acf39..2b4ac3085c318b 100644 --- a/spec/bundler/runtime/setup_spec.rb +++ b/spec/bundler/runtime/setup_spec.rb @@ -144,7 +144,7 @@ def clean_load_path(lp) ruby <<-RUBY require 'bundler' - gem "bundler", "#{Bundler::VERSION}" if #{ruby_core?} + gem "bundler", "#{Bundler::VERSION}" Bundler.setup puts $LOAD_PATH RUBY @@ -987,7 +987,8 @@ def clean_load_path(lp) puts Bundler.rubygems.installed_specs.map(&:name) R - expect(out).to eq("activesupport\nbundler\nactivesupport\nbundler") + expect(out).to include("activesupport") + expect(out).not_to include("myrack") end describe "when a vendored gem specification uses the :path option" do @@ -1309,12 +1310,16 @@ def lock_with(ruby_version = nil) end context "is not present" do - # Skipped on ruby-core because `ruby "require 'bundler/setup'"` does not - # activate bundler as a gem there, so Source::Metadata falls back to a - # synthetic spec whose cache_file does not exist on disk and - # LockfileGenerator#bundler_checksum drops the bundler checksum, while - # the on-disk lockfile still has it. + # Skipped on ruby-core, and on the release-version CI variant, because + # `ruby "require 'bundler/setup'"` does not activate bundler as a gem + # there, so Source::Metadata falls back to a synthetic spec whose + # cache_file does not exist on disk and LockfileGenerator#bundler_checksum + # drops the bundler checksum, while the on-disk lockfile still has it. + # In-development (.dev) versions never write a bundler checksum, so the + # regular suite stays unaffected. it "does not change the lock", :ruby_repo do + skip "bundler is loaded from the source tree, not installed as a gem" unless Bundler::VERSION.end_with?(".dev") + expect { ruby "require 'bundler/setup'" }.not_to change { lockfile } end end diff --git a/spec/bundler/support/build_metadata.rb b/spec/bundler/support/build_metadata.rb index 2eade4137bd68f..8469d96a760112 100644 --- a/spec/bundler/support/build_metadata.rb +++ b/spec/bundler/support/build_metadata.rb @@ -44,7 +44,7 @@ def git_commit_sha end def release_date_for(version, dir:) - changelog = File.expand_path("CHANGELOG.md", dir) + changelog = File.expand_path("CHANGELOG-bundler.md", dir) File.readlines(changelog)[2].scan(/^## #{Regexp.escape(version)} \((.*)\)/).first&.first if File.exist?(changelog) end diff --git a/spec/bundler/support/path.rb b/spec/bundler/support/path.rb index 4b80c5b4a444d9..6b81cb19963dcf 100644 --- a/spec/bundler/support/path.rb +++ b/spec/bundler/support/path.rb @@ -10,7 +10,7 @@ module Path include Spec::Env def source_root - @source_root ||= Pathname.new(ruby_core? ? "../../.." : "../../bundler").expand_path(__dir__) + @source_root ||= Pathname.new(ruby_core? ? "../../.." : "../..").expand_path(__dir__) end def root @@ -50,7 +50,7 @@ def dev_binstub end def bindir - @bindir ||= source_root.join(ruby_core? ? "spec/bin" : "../bin") + @bindir ||= source_root.join(ruby_core? ? "spec/bin" : "bin") end def exedir @@ -76,7 +76,7 @@ def path end def spec_dir - @spec_dir ||= source_root.join(ruby_core? ? "spec/bundler" : "../spec") + @spec_dir ||= source_root.join(ruby_core? ? "spec/bundler" : "spec") end def man_dir @@ -123,7 +123,7 @@ def tmp_root end Pathname(real) else - (ruby_core? ? source_root : source_root.parent).join("tmp") + source_root.join("tmp") end end @@ -291,14 +291,14 @@ def replace_required_ruby_version(version, dir:) end def replace_changelog(version, dir:) - changelog = File.expand_path("CHANGELOG.md", dir) + changelog = File.expand_path("CHANGELOG-bundler.md", dir) contents = File.readlines(changelog) contents = [contents[0], contents[1], "## #{version} (2100-01-01)\n", *contents[3..-1]].join File.open(changelog, "w") {|f| f << contents } end def git_root - ruby_core? ? source_root : source_root.parent + source_root end def rake_path @@ -345,11 +345,11 @@ def git_ls_files(glob) end def tracked_files_glob - ruby_core? ? "libexec/bundle* lib/bundler lib/bundler.rb spec/bundler man/bundle*" : "lib exe CHANGELOG.md LICENSE.md README.md bundler.gemspec" + ruby_core? ? "libexec/bundle* lib/bundler lib/bundler.rb spec/bundler man/bundle*" : "exe/bundle exe/bundler lib/bundler lib/bundler.rb bundler.gemspec CHANGELOG-bundler.md LICENSE-bundler.md README-bundler.md" end def lib_tracked_files_glob - ruby_core? ? "lib/bundler lib/bundler.rb" : "lib" + "lib/bundler lib/bundler.rb" end def man_tracked_files_glob @@ -371,7 +371,7 @@ def standard_gemfile_basename end def tool_dir - ruby_core? ? source_root.join("tool/bundler") : source_root.join("../tool/bundler") + source_root.join("tool/bundler") end def templates_dir diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb index b4760dc412779c..30931587f8b6e4 100644 --- a/test/ruby/test_iseq.rb +++ b/test/ruby/test_iseq.rb @@ -953,6 +953,10 @@ def test_unreachable_next_in_block end end + def test_unreachable_find_pattern_in_else_branch + assert_in_out_err([], "if []; else; a => [*, 42, *]; end") + end + def test_serialize_anonymous_outer_variables iseq = RubyVM::InstructionSequence.compile(<<~'RUBY') obj = Object.new diff --git a/test/rubygems/bundler_test_gem.rb b/test/rubygems/bundler_test_gem.rb index ca2980e04b519a..1f356bb42c3059 100644 --- a/test/rubygems/bundler_test_gem.rb +++ b/test/rubygems/bundler_test_gem.rb @@ -408,7 +408,7 @@ def with_local_bundler_at(path) require "bundler" # If bundler gemspec exists, pretend it's installed - bundler_gemspec = File.expand_path("../../bundler/bundler.gemspec", __dir__) + bundler_gemspec = File.expand_path("../../bundler.gemspec", __dir__) if File.exist?(bundler_gemspec) target_gemspec_location = "#{path}/specifications/bundler-#{Bundler::VERSION}.gemspec" diff --git a/test/rubygems/test_gem_commands_setup_command.rb b/test/rubygems/test_gem_commands_setup_command.rb index b33e05ab28dc55..7df59ecfc6dbbb 100644 --- a/test/rubygems/test_gem_commands_setup_command.rb +++ b/test/rubygems/test_gem_commands_setup_command.rb @@ -15,15 +15,15 @@ def setup lib/rubygems.rb lib/rubygems/requirement.rb lib/rubygems/ssl_certs/rubygems.org/foo.pem - bundler/exe/bundle - bundler/exe/bundler - bundler/lib/bundler.rb - bundler/lib/bundler/b.rb - bundler/bin/bundler/man/bundle-b.1 - bundler/lib/bundler/man/bundle-b.1.ronn - bundler/lib/bundler/man/gemfile.5 - bundler/lib/bundler/man/gemfile.5.ronn - bundler/lib/bundler/templates/.circleci/config.yml + exe/bundle + exe/bundler + lib/bundler.rb + lib/bundler/b.rb + lib/bundler/man/bundle-b.1 + lib/bundler/man/bundle-b.1.ronn + lib/bundler/man/gemfile.5 + lib/bundler/man/gemfile.5.ronn + lib/bundler/templates/.circleci/config.yml ] create_dummy_files(filelist) @@ -34,7 +34,7 @@ def setup s.files = ["lib/bundler.rb"] end - File.open "bundler/bundler.gemspec", "w" do |io| + File.open "bundler.gemspec", "w" do |io| io.puts gemspec.to_ruby end @@ -171,8 +171,18 @@ def test_destdir_flag_regenerates_binstubs end def test_files_in - assert_equal %w[rubygems.rb rubygems/requirement.rb rubygems/ssl_certs/rubygems.org/foo.pem], - @cmd.files_in("lib").sort + assert_equal %w[ + bundler.rb + bundler/b.rb + bundler/man/bundle-b.1 + bundler/man/bundle-b.1.ronn + bundler/man/gemfile.5 + bundler/man/gemfile.5.ronn + bundler/templates/.circleci/config.yml + rubygems.rb + rubygems/requirement.rb + rubygems/ssl_certs/rubygems.org/foo.pem + ], @cmd.files_in("lib").sort end def test_install_lib @@ -475,7 +485,7 @@ def new_bundler_specification_path end def bundler_spec - Gem::Specification.load("bundler/bundler.gemspec") + Gem::Specification.load("bundler.gemspec") end def bundler_version diff --git a/test/rubygems/test_gem_remote_fetcher_local_ssl_server.rb b/test/rubygems/test_gem_remote_fetcher_local_ssl_server.rb index 129c216259e63a..780846d0156b1a 100644 --- a/test/rubygems/test_gem_remote_fetcher_local_ssl_server.rb +++ b/test/rubygems/test_gem_remote_fetcher_local_ssl_server.rb @@ -231,5 +231,54 @@ def omit_unless_support_pqc # mode :pqc requires Ruby OpenSSL >= 4.0. omit "PQC test requires Ruby OpenSSL >= 4.0" unless Gem::Version.new(OpenSSL::VERSION) >= Gem::Version.new("4.0") + # Even with a new enough OpenSSL, the runtime may keep PQC groups and + # signature algorithms out of its default negotiation lists (for example + # RHEL's system-wide crypto policies). The PQC server forces both, while + # the gem fetcher connects with the default client configuration, so a + # real loopback handshake is the only reliable way to tell whether this + # environment can negotiate PQC at all. + omit "PQC handshake is not available in this OpenSSL configuration" unless + self.class.support_pqc_handshake? + end + + # Probe an actual PQC handshake between a forced-PQC server and a + # default-configured client, mirroring what the integration tests exercise. + # Memoized so the probe runs at most once per process. + def self.support_pqc_handshake? + return @support_pqc_handshake unless @support_pqc_handshake.nil? + + @support_pqc_handshake = probe_pqc_handshake + end + + def self.probe_pqc_handshake + server = TCPServer.new("127.0.0.1", 0) + ctx = OpenSSL::SSL::SSLContext.new + ctx.cert = OpenSSL::X509::Certificate.new(File.read(File.join(__dir__, "mldsa65_ssl_cert.pem"))) + ctx.key = OpenSSL::PKey.read(File.read(File.join(__dir__, "mldsa65_ssl_key.pem"))) + ctx.groups = "X25519MLKEM768" + ssl_server = OpenSSL::SSL::SSLServer.new(server, ctx) + + port = server.addr[1] + server_thread = Thread.new do + client = ssl_server.accept + client.close + rescue OpenSSL::OpenSSLError + nil + end + + client_ctx = OpenSSL::SSL::SSLContext.new + client_ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE + socket = TCPSocket.new("127.0.0.1", port) + ssl = OpenSSL::SSL::SSLSocket.new(socket, client_ctx) + ssl.connect + ssl.close + true + rescue OpenSSL::OpenSSLError, SystemCallError + false + ensure + server_thread&.join(5) + server_thread&.kill if server_thread&.alive? + ssl_server&.close + server&.close end end if Gem::HAVE_OPENSSL diff --git a/tool/sync_default_gems.rb b/tool/sync_default_gems.rb index db64e20274b4e0..3242dee5d2b541 100755 --- a/tool/sync_default_gems.rb +++ b/tool/sync_default_gems.rb @@ -241,11 +241,11 @@ def lib((upstream, branch), gemspec_in_subdir: false) ["lib/rubygems.rb", "lib/rubygems.rb"], ["lib/rubygems", "lib/rubygems"], ["test/rubygems", "test/rubygems"], - ["bundler/lib/bundler.rb", "lib/bundler.rb"], - ["bundler/lib/bundler", "lib/bundler"], - ["bundler/exe/bundle", "libexec/bundle"], - ["bundler/exe/bundler", "libexec/bundler"], - ["bundler/bundler.gemspec", "lib/bundler/bundler.gemspec"], + ["lib/bundler.rb", "lib/bundler.rb"], + ["lib/bundler", "lib/bundler"], + ["exe/bundle", "libexec/bundle"], + ["exe/bundler", "libexec/bundler"], + ["bundler.gemspec", "lib/bundler/bundler.gemspec"], ["spec", "spec/bundler"], *["bundle", "parallel_rspec", "rspec"].map {|binstub| ["bin/#{binstub}", "spec/bin/#{binstub}"] @@ -369,12 +369,15 @@ def replace_rdoc_ref_all_full end def rubygems_do_fixup - gemspec_content = File.readlines("lib/bundler/bundler.gemspec").map do |line| - next if line =~ /LICENSE\.md/ + gemspec = "lib/bundler/bundler.gemspec" + if File.exist?(gemspec) + gemspec_content = File.readlines(gemspec).map do |line| + next if line =~ /LICENSE\.md/ - line.gsub("bundler.gemspec", "lib/bundler/bundler.gemspec") - end.compact.join - File.write("lib/bundler/bundler.gemspec", gemspec_content) + line.gsub("bundler.gemspec", "lib/bundler/bundler.gemspec") + end.compact.join + File.write(gemspec, gemspec_content) + end ["bundle", "parallel_rspec", "rspec"].each do |binstub| path = "spec/bin/#{binstub}"