diff options
author | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2023-02-01 12:05:19 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-02-01 12:05:19 +0900 |
commit | f4e6e78410136100ef5f285136a66df8d6004a61 (patch) | |
tree | ed1f754dbe1c4b37e3736265a99122e7a12c3b5b /lib | |
parent | 40e0b1e123503805c16a2a9aafae0a5c302c20d1 (diff) |
Merge RubyGems 3.4.6 and Bundler 2.4.6 (#7214)
Merge RubyGems-3.4.6 and Bundler-2.4.6
Diffstat (limited to 'lib')
-rw-r--r-- | lib/bundler/cli/binstubs.rb | 6 | ||||
-rw-r--r-- | lib/bundler/inline.rb | 14 | ||||
-rw-r--r-- | lib/bundler/installer/standalone.rb | 18 | ||||
-rw-r--r-- | lib/bundler/rubygems_integration.rb | 12 | ||||
-rw-r--r-- | lib/bundler/version.rb | 2 | ||||
-rw-r--r-- | lib/rubygems.rb | 12 | ||||
-rw-r--r-- | lib/rubygems/core_ext/kernel_require.rb | 222 | ||||
-rw-r--r-- | lib/rubygems/ext/builder.rb | 3 | ||||
-rw-r--r-- | lib/rubygems/ext/cargo_builder.rb | 218 | ||||
-rw-r--r-- | lib/rubygems/specification_policy.rb | 2 |
10 files changed, 286 insertions, 223 deletions
diff --git a/lib/bundler/cli/binstubs.rb b/lib/bundler/cli/binstubs.rb index 639c01ff39..88d071571f 100644 --- a/lib/bundler/cli/binstubs.rb +++ b/lib/bundler/cli/binstubs.rb @@ -40,7 +40,11 @@ module Bundler end if options[:standalone] - next Bundler.ui.warn("Sorry, Bundler can only be run via RubyGems.") if gem_name == "bundler" + if gem_name == "bundler" + Bundler.ui.warn("Sorry, Bundler can only be run via RubyGems.") unless options[:all] + next + end + Bundler.settings.temporary(:path => (Bundler.settings[:path] || Bundler.root)) do installer.generate_standalone_bundler_executable_stubs(spec, installer_opts) end diff --git a/lib/bundler/inline.rb b/lib/bundler/inline.rb index 6664d3ebc4..5c184f67a1 100644 --- a/lib/bundler/inline.rb +++ b/lib/bundler/inline.rb @@ -31,6 +31,7 @@ # def gemfile(install = false, options = {}, &gemfile) require_relative "../bundler" + Bundler.reset! opts = options.dup ui = opts.delete(:ui) { Bundler::UI::Shell.new } @@ -38,9 +39,8 @@ def gemfile(install = false, options = {}, &gemfile) Bundler.ui = ui raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty? - begin + Bundler.with_unbundled_env do Bundler.instance_variable_set(:@bundle_path, Pathname.new(Gem.dir)) - old_gemfile = ENV["BUNDLE_GEMFILE"] Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile" Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins? @@ -65,11 +65,9 @@ def gemfile(install = false, options = {}, &gemfile) runtime = Bundler::Runtime.new(nil, definition) runtime.setup.require end - ensure - if old_gemfile - ENV["BUNDLE_GEMFILE"] = old_gemfile - else - ENV["BUNDLE_GEMFILE"] = "" - end + end + + if ENV["BUNDLE_GEMFILE"].nil? + ENV["BUNDLE_GEMFILE"] = "" end end diff --git a/lib/bundler/installer/standalone.rb b/lib/bundler/installer/standalone.rb index 2756626f8a..2efef61648 100644 --- a/lib/bundler/installer/standalone.rb +++ b/lib/bundler/installer/standalone.rb @@ -84,13 +84,17 @@ module Bundler def reverse_rubygems_kernel_mixin <<~END - kernel = (class << ::Kernel; self; end) - [kernel, ::Kernel].each do |k| - if k.private_method_defined?(:gem_original_require) - private_require = k.private_method_defined?(:require) - k.send(:remove_method, :require) - k.send(:define_method, :require, k.instance_method(:gem_original_require)) - k.send(:private, :require) if private_require + if Gem.respond_to?(:discover_gems_on_require=) + Gem.discover_gems_on_require = false + else + kernel = (class << ::Kernel; self; end) + [kernel, ::Kernel].each do |k| + if k.private_method_defined?(:gem_original_require) + private_require = k.private_method_defined?(:require) + k.send(:remove_method, :require) + k.send(:define_method, :require, k.instance_method(:gem_original_require)) + k.send(:private, :require) if private_require + end end end END diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb index d14075c96b..3857948511 100644 --- a/lib/bundler/rubygems_integration.rb +++ b/lib/bundler/rubygems_integration.rb @@ -227,10 +227,14 @@ module Bundler def reverse_rubygems_kernel_mixin # Disable rubygems' gem activation system - kernel = (class << ::Kernel; self; end) - [kernel, ::Kernel].each do |k| - if k.private_method_defined?(:gem_original_require) - redefine_method(k, :require, k.instance_method(:gem_original_require)) + if Gem.respond_to?(:discover_gems_on_require=) + Gem.discover_gems_on_require = false + else + kernel = (class << ::Kernel; self; end) + [kernel, ::Kernel].each do |k| + if k.private_method_defined?(:gem_original_require) + redefine_method(k, :require, k.instance_method(:gem_original_require)) + end end end end diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index 2aba18e298..d3bd162e48 100644 --- a/lib/bundler/version.rb +++ b/lib/bundler/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module Bundler - VERSION = "2.4.5".freeze + VERSION = "2.4.6".freeze def self.bundler_major_version @bundler_major_version ||= VERSION.split(".").first.to_i diff --git a/lib/rubygems.rb b/lib/rubygems.rb index 520fd4951b..26b0b1da7e 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -8,7 +8,7 @@ require "rbconfig" module Gem - VERSION = "3.4.5".freeze + VERSION = "3.4.6".freeze end # Must be first since it unloads the prelude from 1.9.2 @@ -181,6 +181,8 @@ module Gem @default_source_date_epoch = nil + @discover_gems_on_require = true + ## # Try to activate a gem containing +path+. Returns true if # activation succeeded or wasn't needed because it was already @@ -1163,9 +1165,17 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} # RubyGems distributors (like operating system package managers) can # disable RubyGems update by setting this to error message printed to # end-users on gem update --system instead of actual update. + attr_accessor :disable_system_update_message ## + # Whether RubyGems should enhance builtin `require` to automatically + # check whether the path required is present in installed gems, and + # automatically activate them and add them to `$LOAD_PATH`. + + attr_accessor :discover_gems_on_require + + ## # Hash of loaded Gem::Specification keyed by name attr_reader :loaded_specs diff --git a/lib/rubygems/core_ext/kernel_require.rb b/lib/rubygems/core_ext/kernel_require.rb index b92d6f9965..6dcc4a06e4 100644 --- a/lib/rubygems/core_ext/kernel_require.rb +++ b/lib/rubygems/core_ext/kernel_require.rb @@ -34,137 +34,141 @@ module Kernel # that file has already been loaded is preserved. def require(path) # :doc: - if RUBYGEMS_ACTIVATION_MONITOR.respond_to?(:mon_owned?) - monitor_owned = RUBYGEMS_ACTIVATION_MONITOR.mon_owned? - end - RUBYGEMS_ACTIVATION_MONITOR.enter - - path = path.to_path if path.respond_to? :to_path - - if spec = Gem.find_unresolved_default_spec(path) - # Ensure -I beats a default gem - resolved_path = begin - rp = nil - load_path_check_index = Gem.load_path_insert_index - Gem.activated_gem_paths - Gem.suffixes.each do |s| - $LOAD_PATH[0...load_path_check_index].each do |lp| - safe_lp = lp.dup.tap(&Gem::UNTAINT) - begin - if File.symlink? safe_lp # for backward compatibility - next + return gem_original_require(path) unless Gem.discover_gems_on_require + + begin + if RUBYGEMS_ACTIVATION_MONITOR.respond_to?(:mon_owned?) + monitor_owned = RUBYGEMS_ACTIVATION_MONITOR.mon_owned? + end + RUBYGEMS_ACTIVATION_MONITOR.enter + + path = path.to_path if path.respond_to? :to_path + + if spec = Gem.find_unresolved_default_spec(path) + # Ensure -I beats a default gem + resolved_path = begin + rp = nil + load_path_check_index = Gem.load_path_insert_index - Gem.activated_gem_paths + Gem.suffixes.each do |s| + $LOAD_PATH[0...load_path_check_index].each do |lp| + safe_lp = lp.dup.tap(&Gem::UNTAINT) + begin + if File.symlink? safe_lp # for backward compatibility + next + end + rescue SecurityError + RUBYGEMS_ACTIVATION_MONITOR.exit + raise end - rescue SecurityError - RUBYGEMS_ACTIVATION_MONITOR.exit - raise - end - full_path = File.expand_path(File.join(safe_lp, "#{path}#{s}")) - if File.file?(full_path) - rp = full_path - break + full_path = File.expand_path(File.join(safe_lp, "#{path}#{s}")) + if File.file?(full_path) + rp = full_path + break + end end + break if rp end - break if rp + rp end - rp + + begin + Kernel.send(:gem, spec.name, Gem::Requirement.default_prerelease) + rescue Exception + RUBYGEMS_ACTIVATION_MONITOR.exit + raise + end unless resolved_path end - begin - Kernel.send(:gem, spec.name, Gem::Requirement.default_prerelease) - rescue Exception - RUBYGEMS_ACTIVATION_MONITOR.exit - raise - end unless resolved_path - end + # If there are no unresolved deps, then we can use just try + # normal require handle loading a gem from the rescue below. - # If there are no unresolved deps, then we can use just try - # normal require handle loading a gem from the rescue below. + if Gem::Specification.unresolved_deps.empty? + RUBYGEMS_ACTIVATION_MONITOR.exit + return gem_original_require(path) + end - if Gem::Specification.unresolved_deps.empty? - RUBYGEMS_ACTIVATION_MONITOR.exit - return gem_original_require(path) - end + # If +path+ is for a gem that has already been loaded, don't + # bother trying to find it in an unresolved gem, just go straight + # to normal require. + #-- + # TODO request access to the C implementation of this to speed up RubyGems - # If +path+ is for a gem that has already been loaded, don't - # bother trying to find it in an unresolved gem, just go straight - # to normal require. - #-- - # TODO request access to the C implementation of this to speed up RubyGems + if Gem::Specification.find_active_stub_by_path(path) + RUBYGEMS_ACTIVATION_MONITOR.exit + return gem_original_require(path) + end - if Gem::Specification.find_active_stub_by_path(path) - RUBYGEMS_ACTIVATION_MONITOR.exit - return gem_original_require(path) - end + # Attempt to find +path+ in any unresolved gems... + + found_specs = Gem::Specification.find_in_unresolved path + + # If there are no directly unresolved gems, then try and find +path+ + # in any gems that are available via the currently unresolved gems. + # For example, given: + # + # a => b => c => d + # + # If a and b are currently active with c being unresolved and d.rb is + # requested, then find_in_unresolved_tree will find d.rb in d because + # it's a dependency of c. + # + if found_specs.empty? + found_specs = Gem::Specification.find_in_unresolved_tree path + + found_specs.each do |found_spec| + found_spec.activate + end - # Attempt to find +path+ in any unresolved gems... - - found_specs = Gem::Specification.find_in_unresolved path - - # If there are no directly unresolved gems, then try and find +path+ - # in any gems that are available via the currently unresolved gems. - # For example, given: - # - # a => b => c => d - # - # If a and b are currently active with c being unresolved and d.rb is - # requested, then find_in_unresolved_tree will find d.rb in d because - # it's a dependency of c. - # - if found_specs.empty? - found_specs = Gem::Specification.find_in_unresolved_tree path - - found_specs.each do |found_spec| - found_spec.activate - end + # We found +path+ directly in an unresolved gem. Now we figure out, of + # the possible found specs, which one we should activate. + else - # We found +path+ directly in an unresolved gem. Now we figure out, of - # the possible found specs, which one we should activate. - else + # Check that all the found specs are just different + # versions of the same gem + names = found_specs.map(&:name).uniq - # Check that all the found specs are just different - # versions of the same gem - names = found_specs.map(&:name).uniq + if names.size > 1 + RUBYGEMS_ACTIVATION_MONITOR.exit + raise Gem::LoadError, "#{path} found in multiple gems: #{names.join ', '}" + end - if names.size > 1 - RUBYGEMS_ACTIVATION_MONITOR.exit - raise Gem::LoadError, "#{path} found in multiple gems: #{names.join ', '}" - end + # Ok, now find a gem that has no conflicts, starting + # at the highest version. + valid = found_specs.find {|s| !s.has_conflicts? } - # Ok, now find a gem that has no conflicts, starting - # at the highest version. - valid = found_specs.find {|s| !s.has_conflicts? } + unless valid + le = Gem::LoadError.new "unable to find a version of '#{names.first}' to activate" + le.name = names.first + RUBYGEMS_ACTIVATION_MONITOR.exit + raise le + end - unless valid - le = Gem::LoadError.new "unable to find a version of '#{names.first}' to activate" - le.name = names.first - RUBYGEMS_ACTIVATION_MONITOR.exit - raise le + valid.activate end - valid.activate - end - - RUBYGEMS_ACTIVATION_MONITOR.exit - return gem_original_require(path) - rescue LoadError => load_error - if load_error.path == path - RUBYGEMS_ACTIVATION_MONITOR.enter + RUBYGEMS_ACTIVATION_MONITOR.exit + return gem_original_require(path) + rescue LoadError => load_error + if load_error.path == path + RUBYGEMS_ACTIVATION_MONITOR.enter + + begin + require_again = Gem.try_activate(path) + ensure + RUBYGEMS_ACTIVATION_MONITOR.exit + end - begin - require_again = Gem.try_activate(path) - ensure - RUBYGEMS_ACTIVATION_MONITOR.exit + return gem_original_require(path) if require_again end - return gem_original_require(path) if require_again - end - - raise load_error - ensure - if RUBYGEMS_ACTIVATION_MONITOR.respond_to?(:mon_owned?) - if monitor_owned != (ow = RUBYGEMS_ACTIVATION_MONITOR.mon_owned?) - STDERR.puts [$$, Thread.current, $!, $!.backtrace].inspect if $! - raise "CRITICAL: RUBYGEMS_ACTIVATION_MONITOR.owned?: before #{monitor_owned} -> after #{ow}" + raise load_error + ensure + if RUBYGEMS_ACTIVATION_MONITOR.respond_to?(:mon_owned?) + if monitor_owned != (ow = RUBYGEMS_ACTIVATION_MONITOR.mon_owned?) + STDERR.puts [$$, Thread.current, $!, $!.backtrace].inspect if $! + raise "CRITICAL: RUBYGEMS_ACTIVATION_MONITOR.owned?: before #{monitor_owned} -> after #{ow}" + end end end end diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb index 98d354183c..7fb8958d7f 100644 --- a/lib/rubygems/ext/builder.rb +++ b/lib/rubygems/ext/builder.rb @@ -131,8 +131,7 @@ class Gem::Ext::Builder when /CMakeLists.txt/ then Gem::Ext::CmakeBuilder when /Cargo.toml/ then - # We use the spec name here to ensure we invoke the correct init function later - Gem::Ext::CargoBuilder.new(@spec) + Gem::Ext::CargoBuilder.new else build_error("No builder for extension '#{extension}'") end diff --git a/lib/rubygems/ext/cargo_builder.rb b/lib/rubygems/ext/cargo_builder.rb index 60ab5544fe..022aabf481 100644 --- a/lib/rubygems/ext/cargo_builder.rb +++ b/lib/rubygems/ext/cargo_builder.rb @@ -6,30 +6,60 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder attr_accessor :spec, :runner, :profile - def initialize(spec) + def initialize require_relative "../command" require_relative "cargo_builder/link_flag_converter" - @spec = spec @runner = self.class.method(:run) @profile = :release end - def build(_extension, dest_path, results, args = [], lib_dir = nil, cargo_dir = Dir.pwd) + def build(extension, dest_path, results, args = [], lib_dir = nil, cargo_dir = Dir.pwd) + require "tempfile" require "fileutils" - require "shellwords" - build_crate(dest_path, results, args, cargo_dir) - validate_cargo_build!(dest_path) - rename_cdylib_for_ruby_compatibility(dest_path) - finalize_directory(dest_path, lib_dir, cargo_dir) - results - end + # Where's the Cargo.toml of the crate we're building + cargo_toml = File.join(cargo_dir, "Cargo.toml") + # What's the crate's name + crate_name = cargo_crate_name(cargo_dir, cargo_toml, results) + + begin + # Create a tmp dir to do the build in + tmp_dest = Dir.mktmpdir(".gem.", cargo_dir) + + # Run the build + cmd = cargo_command(cargo_toml, tmp_dest, args, crate_name) + runner.call(cmd, results, "cargo", cargo_dir, build_env) + + # Where do we expect Cargo to write the compiled library + dylib_path = cargo_dylib_path(tmp_dest, crate_name) - def build_crate(dest_path, results, args, cargo_dir) - env = build_env - cmd = cargo_command(cargo_dir, dest_path, args) - runner.call cmd, results, "cargo", cargo_dir, env + # Helpful error if we didn't find the compiled library + raise DylibNotFoundError, tmp_dest unless File.exist?(dylib_path) + + # Cargo and Ruby differ on how the library should be named, rename from + # what Cargo outputs to what Ruby expects + dlext_name = "#{crate_name}.#{makefile_config("DLEXT")}" + dlext_path = File.join(File.dirname(dylib_path), dlext_name) + FileUtils.cp(dylib_path, dlext_path) + + nesting = extension_nesting(extension) + + # TODO: remove in RubyGems 4 + if Gem.install_extension_in_lib && lib_dir + nested_lib_dir = File.join(lib_dir, nesting) + FileUtils.mkdir_p nested_lib_dir + FileUtils.cp_r dlext_path, nested_lib_dir, remove_destination: true + end + + # move to final destination + nested_dest_path = File.join(dest_path, nesting) + FileUtils.mkdir_p nested_dest_path + FileUtils.cp_r dlext_path, nested_dest_path, remove_destination: true + ensure + # clean up intermediary build artifacts + FileUtils.rm_rf tmp_dest if tmp_dest + end results end @@ -42,39 +72,59 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder build_env end - def cargo_command(cargo_dir, dest_path, args = []) - manifest = File.join(cargo_dir, "Cargo.toml") - cargo = ENV.fetch("CARGO", "cargo") + def cargo_command(cargo_toml, dest_path, args = [], crate_name = nil) + require "shellwords" cmd = [] cmd += [cargo, "rustc"] cmd += ["--crate-type", "cdylib"] cmd += ["--target", ENV["CARGO_BUILD_TARGET"]] if ENV["CARGO_BUILD_TARGET"] cmd += ["--target-dir", dest_path] - cmd += ["--manifest-path", manifest] + cmd += ["--manifest-path", cargo_toml] cmd += ["--lib"] cmd += ["--profile", profile.to_s] cmd += ["--locked"] cmd += Gem::Command.build_args cmd += args cmd += ["--"] - cmd += [*cargo_rustc_args(dest_path)] + cmd += [*cargo_rustc_args(dest_path, crate_name)] cmd end private + def cargo + ENV.fetch("CARGO", "cargo") + end + + # returns the directory nesting of the extension, ignoring the first part, so + # "ext/foo/bar/Cargo.toml" becomes "foo/bar" + def extension_nesting(extension) + parts = extension.to_s.split(Regexp.union([File::SEPARATOR, File::ALT_SEPARATOR].compact)) + + parts = parts.each_with_object([]) do |segment, final| + next if segment == "." + if segment == ".." + raise Gem::InstallError, "extension outside of gem root" if final.empty? + next final.pop + end + final << segment + end + + File.join(parts[1...-1]) + end + def rb_config_env result = {} RbConfig::CONFIG.each {|k, v| result["RBCONFIG_#{k}"] = v } result end - def cargo_rustc_args(dest_dir) + def cargo_rustc_args(dest_dir, crate_name) [ *linker_args, *mkmf_libpath, - *rustc_dynamic_linker_flags(dest_dir), + *rustc_dynamic_linker_flags(dest_dir, crate_name), *rustc_lib_flags(dest_dir), *platform_specific_rustc_args(dest_dir), ] @@ -134,42 +184,70 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder makefile_config("ENABLE_SHARED") == "no" end - # Ruby expects the dylib to follow a file name convention for loading - def rename_cdylib_for_ruby_compatibility(dest_path) - new_path = final_extension_path(dest_path) - FileUtils.cp(cargo_dylib_path(dest_path), new_path) - new_path + def cargo_dylib_path(dest_path, crate_name) + prefix = so_ext == "dll" ? "" : "lib" + path_parts = [dest_path] + path_parts << ENV["CARGO_BUILD_TARGET"] if ENV["CARGO_BUILD_TARGET"] + path_parts += ["release", "#{prefix}#{crate_name}.#{so_ext}"] + File.join(*path_parts) end - def validate_cargo_build!(dir) - dylib_path = cargo_dylib_path(dir) + def cargo_crate_name(cargo_dir, manifest_path, results) + require "open3" + Gem.load_yaml - raise DylibNotFoundError, dir unless File.exist?(dylib_path) + output, status = + begin + Open3.capture2e(cargo, "metadata", "--no-deps", "--format-version", "1", :chdir => cargo_dir) + rescue => error + raise Gem::InstallError, "cargo metadata failed #{error.message}" + end - dylib_path - end + unless status.success? + if Gem.configuration.really_verbose + puts output + else + results << output + end - def final_extension_path(dest_path) - dylib_path = cargo_dylib_path(dest_path) - dlext_name = "#{spec.name}.#{makefile_config("DLEXT")}" - dylib_path.gsub(File.basename(dylib_path), dlext_name) - end + exit_reason = + if status.exited? + ", exit code #{status.exitstatus}" + elsif status.signaled? + ", uncaught signal #{status.termsig}" + end - def cargo_dylib_path(dest_path) - prefix = so_ext == "dll" ? "" : "lib" - path_parts = [dest_path] - path_parts << ENV["CARGO_BUILD_TARGET"] if ENV["CARGO_BUILD_TARGET"] - path_parts += ["release", "#{prefix}#{cargo_crate_name}.#{so_ext}"] - File.join(*path_parts) + raise Gem::InstallError, "cargo metadata failed#{exit_reason}" + end + + # cargo metadata output is specified as json, but with the + # --format-version 1 option the output is compatible with YAML, so we can + # avoid the json dependency + metadata = Gem::SafeYAML.safe_load(output) + package = metadata["packages"].find {|pkg| normalize_path(pkg["manifest_path"]) == manifest_path } + unless package + found = metadata["packages"].map {|md| "#{md["name"]} at #{md["manifest_path"]}" } + raise Gem::InstallError, <<-EOF +failed to determine cargo package name + +looking for: #{manifest_path} + +found: +#{found.join("\n")} +EOF + end + package["name"].tr("-", "_") end - def cargo_crate_name - spec.metadata.fetch("cargo_crate_name", spec.name).tr("-", "_") + def normalize_path(path) + return path unless File::ALT_SEPARATOR + + path.tr(File::ALT_SEPARATOR, File::SEPARATOR) end - def rustc_dynamic_linker_flags(dest_dir) + def rustc_dynamic_linker_flags(dest_dir, crate_name) split_flags("DLDFLAGS") - .map {|arg| maybe_resolve_ldflag_variable(arg, dest_dir) } + .map {|arg| maybe_resolve_ldflag_variable(arg, dest_dir, crate_name) } .compact .flat_map {|arg| ldflag_to_link_modifier(arg) } end @@ -204,7 +282,7 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder end # Interpolate substitution vars in the arg (i.e. $(DEFFILE)) - def maybe_resolve_ldflag_variable(input_arg, dest_dir) + def maybe_resolve_ldflag_variable(input_arg, dest_dir, crate_name) var_matches = input_arg.match(/\$\((\w+)\)/) return input_arg unless var_matches @@ -217,19 +295,19 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder # On windows, it is assumed that mkmf has setup an exports file for the # extension, so we have to to create one ourselves. when "DEFFILE" - write_deffile(dest_dir) + write_deffile(dest_dir, crate_name) else RbConfig::CONFIG[var_name] end end - def write_deffile(dest_dir) - deffile_path = File.join(dest_dir, "#{spec.name}-#{RbConfig::CONFIG["arch"]}.def") + def write_deffile(dest_dir, crate_name) + deffile_path = File.join(dest_dir, "#{crate_name}-#{RbConfig::CONFIG["arch"]}.def") export_prefix = makefile_config("EXPORT_PREFIX") || "" File.open(deffile_path, "w") do |f| f.puts "EXPORTS" - f.puts "#{export_prefix.strip}Init_#{spec.name}" + f.puts "#{export_prefix.strip}Init_#{crate_name}" end deffile_path @@ -264,44 +342,6 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder RbConfig.expand(val.dup) end - # Copied from ExtConfBuilder - def finalize_directory(dest_path, lib_dir, extension_dir) - require "fileutils" - require "tempfile" - - ext_path = final_extension_path(dest_path) - - begin - tmp_dest = Dir.mktmpdir(".gem.", extension_dir) - - # Some versions of `mktmpdir` return absolute paths, which will break make - # if the paths contain spaces. - # - # As such, we convert to a relative path. - tmp_dest_relative = get_relative_path(tmp_dest.clone, extension_dir) - - full_tmp_dest = File.join(extension_dir, tmp_dest_relative) - - # TODO: remove in RubyGems 4 - if Gem.install_extension_in_lib && lib_dir - FileUtils.mkdir_p lib_dir - FileUtils.cp_r ext_path, lib_dir, remove_destination: true - end - - FileUtils::Entry_.new(full_tmp_dest).traverse do |ent| - destent = ent.class.new(dest_path, ent.rel) - destent.exist? || FileUtils.mv(ent.path, destent.path) - end - ensure - FileUtils.rm_rf tmp_dest if tmp_dest - end - end - - def get_relative_path(path, base) - path[0..base.length - 1] = "." if path.start_with?(base) - path - end - # Error raised when no cdylib artifact was created class DylibNotFoundError < StandardError def initialize(dir) diff --git a/lib/rubygems/specification_policy.rb b/lib/rubygems/specification_policy.rb index f01a6cd743..6f4d79cdcf 100644 --- a/lib/rubygems/specification_policy.rb +++ b/lib/rubygems/specification_policy.rb @@ -466,7 +466,7 @@ http://spdx.org/licenses or '#{Gem::Licenses::NONSTANDARD}' for a nonstandard li def validate_rust_extensions(builder) # :nodoc: rust_extension = @specification.extensions.any? {|s| builder.builder_for(s).is_a? Gem::Ext::CargoBuilder } - missing_cargo_lock = !@specification.files.include?("Cargo.lock") + missing_cargo_lock = !@specification.files.any? {|f| f.end_with?("Cargo.lock") } error <<-ERROR if rust_extension && missing_cargo_lock You have specified rust based extension, but Cargo.lock is not part of the gem files. Please run `cargo generate-lockfile` or any other command to generate Cargo.lock and ensure it is added to your gem files section in gemspec. |