diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb index 79344314fe4950..3f9432db3a810d 100644 --- a/lib/bundler/cli/gem.rb +++ b/lib/bundler/cli/gem.rb @@ -288,7 +288,7 @@ def run open_editor(options["edit"], target.join("#{name}.gemspec")) if options[:edit] Bundler.ui.info "\nGem '#{name}' was successfully created. " \ - "For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html" + "For more information on making a RubyGem visit https://guides.rubygems.org/make-your-own-gem/" end private diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index 626f0811d24962..8835ae75bd9e92 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -154,9 +154,15 @@ The path to the lockfile that bundler should use\. By default, Bundler adds \fB\ \fBlockfile_checksums\fR (\fBBUNDLE_LOCKFILE_CHECKSUMS\fR) Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources\. Defaults to true\. .TP +\fBno_build_extension\fR (\fBBUNDLE_NO_BUILD_EXTENSION\fR) +Whether Bundler should skip building native extensions during installation\. When set, gems are installed without compiling their C extensions\. To build extensions later, unset this setting and run \fBbundle pristine \fR\. +.TP \fBno_install\fR (\fBBUNDLE_NO_INSTALL\fR) Whether \fBbundle package\fR should skip installing gems\. .TP +\fBno_install_plugin\fR (\fBBUNDLE_NO_INSTALL_PLUGIN\fR) +Whether Bundler should skip installing RubyGems plugins during installation\. When set, plugin files are not written to the plugins directory\. To install plugins later, unset this setting and run \fBbundle pristine \fR\. +.TP \fBno_prune\fR (\fBBUNDLE_NO_PRUNE\fR) Whether Bundler should leave outdated gems unpruned when caching\. .TP diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index c01e836f96b5a6..9657e7414514ef 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -200,8 +200,16 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). Gemfile to disable lockfile creation entirely (see gemfile(5)). * `lockfile_checksums` (`BUNDLE_LOCKFILE_CHECKSUMS`): Whether Bundler should include a checksums section in new lockfiles, to protect from compromised gem sources. Defaults to true. +* `no_build_extension` (`BUNDLE_NO_BUILD_EXTENSION`): + Whether Bundler should skip building native extensions during installation. + When set, gems are installed without compiling their C extensions. + To build extensions later, unset this setting and run `bundle pristine `. * `no_install` (`BUNDLE_NO_INSTALL`): Whether `bundle package` should skip installing gems. +* `no_install_plugin` (`BUNDLE_NO_INSTALL_PLUGIN`): + Whether Bundler should skip installing RubyGems plugins during installation. + When set, plugin files are not written to the plugins directory. + To install plugins later, unset this setting and run `bundle pristine `. * `no_prune` (`BUNDLE_NO_PRUNE`): Whether Bundler should leave outdated gems unpruned when caching. * `only` (`BUNDLE_ONLY`): diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb index 12405869787360..e4dd2d95afa3db 100644 --- a/lib/bundler/rubygems_gem_installer.rb +++ b/lib/bundler/rubygems_gem_installer.rb @@ -27,7 +27,11 @@ def install extract_files end - build_extensions if spec.extensions.any? + if options[:build_extension] == false + warn_skipped_extensions + elsif spec.extensions.any? + build_extensions + end write_build_info_file run_post_build_hooks @@ -35,7 +39,12 @@ def install generate_bin end - generate_plugins + if options[:install_plugin] == false + remove_stale_plugins + warn_skipped_plugins + else + generate_plugins + end write_spec @@ -80,6 +89,20 @@ def generate_plugins end end + def warn_skipped_extensions + return if spec.extensions.empty? + + Bundler.ui.warn "#{spec.full_name} contains native extensions that were not built.\n" \ + "To build extensions, unset no_build_extension and run `bundle pristine #{spec.name}`." + end + + def warn_skipped_plugins + return if spec.plugins.empty? + + Bundler.ui.warn "#{spec.full_name} contains plugins that were not installed.\n" \ + "To install plugins, unset no_install_plugin and run `bundle pristine #{spec.name}`." + end + if Bundler.rubygems.provides?("< 3.5.19") def generate_bin_script(filename, bindir) bin_script_path = File.join bindir, formatted_program_filename(filename) diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index 120a3202afd5dc..95b48da31e927a 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -30,7 +30,9 @@ class Settings init_gems_rb inline lockfile_checksums + no_build_extension no_install + no_install_plugin no_prune path.system plugins diff --git a/lib/bundler/source/path/installer.rb b/lib/bundler/source/path/installer.rb index 0af28fe7707126..39765e5da22970 100644 --- a/lib/bundler/source/path/installer.rb +++ b/lib/bundler/source/path/installer.rb @@ -24,7 +24,7 @@ def initialize(spec, options = {}) def post_install run_hooks(:pre_install) - unless @disable_extensions + unless @disable_extensions || Bundler.settings[:no_build_extension] build_extensions run_hooks(:post_build) end diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index cee5196f3082c9..b5c3b9169d1649 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -533,7 +533,9 @@ def rubygems_gem_installer(spec, options) wrappers: true, env_shebang: true, build_args: options[:build_args], - bundler_extension_cache_path: extension_cache_path(spec) + bundler_extension_cache_path: extension_cache_path(spec), + build_extension: Bundler.settings[:no_build_extension] ? false : nil, + install_plugin: Bundler.settings[:no_install_plugin] ? false : nil ) @gem_installers_mutex.synchronize { @gem_installers[spec.name] ||= installer } end diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt index fabb308043c9c4..b81ecec624af0a 100644 --- a/lib/bundler/templates/newgem/newgem.gemspec.tt +++ b/lib/bundler/templates/newgem/newgem.gemspec.tt @@ -54,5 +54,5 @@ Gem::Specification.new do |spec| <%- end -%> # For more information and examples about making a new gem, check out our - # guide at: https://bundler.io/guides/creating_gem.html + # guide at: https://guides.rubygems.org/make-your-own-gem/ end diff --git a/lib/ipaddr.rb b/lib/ipaddr.rb index 6b67d7eec6706a..cc550898d2876d 100644 --- a/lib/ipaddr.rb +++ b/lib/ipaddr.rb @@ -293,7 +293,7 @@ def loopback? @addr & 0xff000000 == 0x7f000000 # 127.0.0.1/8 when Socket::AF_INET6 @addr == 1 || # ::1 - (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && ( + (@addr >> 32 == 0xffff && ( @addr & 0xff000000 == 0x7f000000 # ::ffff:127.0.0.1/8 )) else @@ -314,10 +314,10 @@ def private? @addr & 0xffff0000 == 0xc0a80000 # 192.168.0.0/16 when Socket::AF_INET6 @addr & 0xfe00_0000_0000_0000_0000_0000_0000_0000 == 0xfc00_0000_0000_0000_0000_0000_0000_0000 || - (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && ( + (@addr >> 32 == 0xffff && ( @addr & 0xff000000 == 0x0a000000 || # ::ffff:10.0.0.0/8 - @addr & 0xfff00000 == 0xac100000 || # ::ffff::172.16.0.0/12 - @addr & 0xffff0000 == 0xc0a80000 # ::ffff::192.168.0.0/16 + @addr & 0xfff00000 == 0xac100000 || # ::ffff:172.16.0.0/12 + @addr & 0xffff0000 == 0xc0a80000 # ::ffff:192.168.0.0/16 )) else raise AddressFamilyError, "unsupported address family" @@ -335,7 +335,7 @@ def link_local? @addr & 0xffff0000 == 0xa9fe0000 # 169.254.0.0/16 when Socket::AF_INET6 @addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000 || # fe80::/10 - (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && ( + (@addr >> 32 == 0xffff && ( @addr & 0xffff0000 == 0xa9fe0000 # ::ffff:169.254.0.0/16 )) else diff --git a/lib/prism/translation/ripper.rb b/lib/prism/translation/ripper.rb index b066f3e3accd21..00506d650e21a8 100644 --- a/lib/prism/translation/ripper.rb +++ b/lib/prism/translation/ripper.rb @@ -704,6 +704,8 @@ def visit_array_node(node) previous = element end + visit_words_sep(opening_loc, node.elements.last, node.closing_loc) + bounds(node.closing_loc) on_tstring_end(node.closing) when /^%i/ @@ -723,6 +725,8 @@ def visit_array_node(node) previous = element end + visit_words_sep(opening_loc, node.elements.last, node.closing_loc) + bounds(node.closing_loc) on_tstring_end(node.closing) when /^%W/ @@ -760,6 +764,8 @@ def visit_array_node(node) previous = element end + visit_words_sep(opening_loc, node.elements.last, node.closing_loc) + bounds(node.closing_loc) on_tstring_end(node.closing) when /^%I/ @@ -797,6 +803,8 @@ def visit_array_node(node) previous = element end + visit_words_sep(opening_loc, node.elements.last, node.closing_loc) + bounds(node.closing_loc) on_tstring_end(node.closing) else @@ -813,15 +821,21 @@ def visit_array_node(node) on_array(elements) end - # Dispatch a words_sep event that contains the space between the elements + # Dispatch words_sep events that contains the whitespace between the elements # of list literals. private def visit_words_sep(opening_loc, previous, current) - end_offset = (previous.nil? ? opening_loc : previous.location).end_offset - start_offset = current.location.start_offset - - if end_offset != start_offset - bounds(current.location.copy(start_offset: end_offset)) - on_words_sep(source.byteslice(end_offset...start_offset)) + start_offset = (previous.nil? ? opening_loc : previous.location).end_offset + end_offset = current.start_offset + length = end_offset - start_offset + + if length > 0 + whitespace = source.byteslice(start_offset, length) + current_offset = start_offset + whitespace.each_line do |part| + bounds(opening_loc.copy(start_offset: current_offset, length: part.bytesize)) + on_words_sep(part) + current_offset += part.bytesize + end end end diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb index 6a6dfa5c2031ba..c842714d9580f4 100644 --- a/lib/rubygems/dependency_installer.rb +++ b/lib/rubygems/dependency_installer.rb @@ -88,6 +88,8 @@ def initialize(options = {}) @dir_mode = options[:dir_mode] @data_mode = options[:data_mode] @prog_mode = options[:prog_mode] + @build_extension = options[:build_extension] + @install_plugin = options[:install_plugin] # Indicates that we should not try to update any deps unless # we absolutely must. @@ -169,6 +171,8 @@ def install(dep_or_name, version = Gem::Requirement.default) dir_mode: @dir_mode, data_mode: @data_mode, prog_mode: @prog_mode, + build_extension: @build_extension, + install_plugin: @install_plugin, } options[:install_dir] = @install_dir if @only_install_dir diff --git a/lib/rubygems/install_update_options.rb b/lib/rubygems/install_update_options.rb index 66cb5c049bcc03..e8859cadaf159d 100644 --- a/lib/rubygems/install_update_options.rb +++ b/lib/rubygems/install_update_options.rb @@ -192,6 +192,18 @@ def add_install_update_options "rbconfig.rb for the deployment target platform") do |v, _o| Gem.set_target_rbconfig(v) end + + add_option(:"Install/Update", "--[no-]build-extension", + "Build native extensions during installation.", + "Defaults to true") do |v, _o| + options[:build_extension] = v + end + + add_option(:"Install/Update", "--[no-]install-plugin", + "Install plugins during installation.", + "Defaults to true") do |v, _o| + options[:install_plugin] = v + end end ## diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 914e413677312a..15d6aac0fd1ba0 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -287,7 +287,12 @@ def install run_post_build_hooks generate_bin - generate_plugins + if options[:install_plugin] == false + remove_stale_plugins + warn_skipped_plugins + else + generate_plugins + end write_spec write_cache_file @@ -298,7 +303,7 @@ def install Gem::Specification.add_spec(spec) unless @install_dir - load_plugin + load_plugin unless options[:install_plugin] == false run_post_install_hooks @@ -804,11 +809,37 @@ def windows_stub_script(bindir, bin_file_name) # configure scripts and rakefiles or mkrf_conf files. def build_extensions + if options[:build_extension] == false + warn_skipped_extensions + return + end + builder = Gem::Ext::Builder.new spec, build_args, Gem.target_rbconfig, build_jobs builder.build_extensions end + def warn_skipped_extensions # :nodoc: + return if spec.extensions.empty? + + alert_warning "#{spec.full_name} contains native extensions that were not built.\n" \ + "To build extensions, run: gem pristine #{spec.name} --extensions" + end + + def warn_skipped_plugins # :nodoc: + return if spec.plugins.empty? + + alert_warning "#{spec.full_name} contains plugins that were not installed.\n" \ + "To install plugins, run: gem pristine #{spec.name} --only-plugins" + end + + def remove_stale_plugins # :nodoc: + return unless spec.plugins.empty? + + ensure_writable_dir @plugins_dir + remove_plugins_for(spec, @plugins_dir) + end + ## # Reads the file index and extracts each file into the gem directory. # @@ -990,9 +1021,10 @@ def load_plugin # are loaded at the same time. return unless specs.size == 1 - plugin_files = spec.plugins.map do |plugin| - File.join(@plugins_dir, "#{spec.name}_plugin#{File.extname(plugin)}") + plugin_files = spec.plugins.filter_map do |plugin| + path = File.join(@plugins_dir, "#{spec.name}_plugin#{File.extname(plugin)}") + path if File.exist?(path) end - Gem.load_plugin_files(plugin_files) + Gem.load_plugin_files(plugin_files) unless plugin_files.empty? end end diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb index 5a855fdb104026..dbebd1af0c377e 100644 --- a/lib/rubygems/request_set.rb +++ b/lib/rubygems/request_set.rb @@ -182,7 +182,7 @@ def install(options, &block) # :yields: request, installer # Install requested gems after they have been downloaded sorted_requests.each do |req| if req.installed? && @always_install.none? {|spec| spec == req.spec.spec } - req.spec.spec.build_extensions + req.spec.spec.build_extensions unless options[:build_extension] == false yield req, nil if block_given? next end diff --git a/spec/bundler/install/gems/no_build_extension_spec.rb b/spec/bundler/install/gems/no_build_extension_spec.rb new file mode 100644 index 00000000000000..31f01704339a34 --- /dev/null +++ b/spec/bundler/install/gems/no_build_extension_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +RSpec.describe "bundle install with --no-build-extension" do + before do + build_repo2 do + build_gem "with_extension" do |s| + s.extensions << "Rakefile" + s.write "Rakefile", <<-RUBY + task :default do + path = File.expand_path("lib", __dir__) + FileUtils.mkdir_p(path) + File.open("\#{path}/with_extension.rb", "w") do |f| + f.puts "WITH_EXTENSION = 'YES'" + end + end + RUBY + end + end + end + + it "skips building native extensions and warns when no_build_extension is set" do + bundle_config "no_build_extension true" + + gemfile <<-G + source "https://gem.repo2" + gem "with_extension" + gem "rake" + G + + bundle :install + + build_complete = default_bundle_path("extensions").join( + Gem::Platform.local.to_s, + Gem.extension_api_version.to_s, + "with_extension-1.0", + "gem.build_complete" + ) + expect(build_complete).not_to exist + expect(err).to include("with_extension-1.0 contains native extensions that were not built") + expect(err).to include("unset no_build_extension and run `bundle pristine with_extension`") + end + + it "builds native extensions by default" do + gemfile <<-G + source "https://gem.repo2" + gem "with_extension" + gem "rake" + G + + bundle :install + + expect(out).to include("Installing with_extension 1.0 with native extensions") + end +end diff --git a/spec/bundler/install/gems/no_install_plugin_spec.rb b/spec/bundler/install/gems/no_install_plugin_spec.rb new file mode 100644 index 00000000000000..e040e6b813e83b --- /dev/null +++ b/spec/bundler/install/gems/no_install_plugin_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +RSpec.describe "bundle install with --no-install-plugin" do + before do + build_repo2 do + build_gem "with_plugin", "1.0" do |s| + s.write "lib/rubygems_plugin.rb", "# plugin code" + end + + build_gem "with_plugin", "2.0" + end + end + + let(:plugin_path) { default_bundle_path("plugins", "with_plugin_plugin.rb") } + + it "does not generate the plugin wrapper and warns when no_install_plugin is set" do + bundle_config "no_install_plugin true" + + install_gemfile <<-G + source "https://gem.repo2" + gem "with_plugin", "1.0" + G + + expect(plugin_path).not_to exist + expect(err).to include("with_plugin-1.0 contains plugins that were not installed") + expect(err).to include("unset no_install_plugin and run `bundle pristine with_plugin`") + end + + it "removes a stale plugin wrapper from a prior version when no_install_plugin is set" do + install_gemfile <<-G + source "https://gem.repo2" + gem "with_plugin", "1.0" + G + expect(plugin_path).to exist + + bundle_config "no_install_plugin true" + install_gemfile <<-G + source "https://gem.repo2" + gem "with_plugin", "2.0" + G + + expect(plugin_path).not_to exist + end + + it "generates the plugin wrapper by default" do + install_gemfile <<-G + source "https://gem.repo2" + gem "with_plugin", "1.0" + G + + expect(plugin_path).to exist + end +end diff --git a/spec/bundler/support/windows_tag_group.rb b/spec/bundler/support/windows_tag_group.rb index f1a78f23e8d37e..b91deb7ed3e6f2 100644 --- a/spec/bundler/support/windows_tag_group.rb +++ b/spec/bundler/support/windows_tag_group.rb @@ -187,6 +187,8 @@ module WindowsTagGroup "spec/bundler/digest_spec.rb", "spec/bundler/fetcher/gem_remote_fetcher_spec.rb", "spec/bundler/uri_normalizer_spec.rb", + "spec/install/gems/no_build_extension_spec.rb", + "spec/install/gems/no_install_plugin_spec.rb", ], }.freeze end diff --git a/test/prism/ruby/ripper_test.rb b/test/prism/ruby/ripper_test.rb index 61065e3ffc1808..cdb8375f96a38c 100644 --- a/test/prism/ruby/ripper_test.rb +++ b/test/prism/ruby/ripper_test.rb @@ -101,6 +101,7 @@ class RipperTest < TestCase "seattlerb/messy_op_asgn_lineno.txt", "seattlerb/op_asgn_primary_colon_const_command_call.txt", "seattlerb/parse_pattern_076.txt", + "seattlerb/pct_w_heredoc_interp_nested.txt", "tilde_heredocs.txt", "unparser/corpus/literal/assignment.txt", "unparser/corpus/literal/pattern.txt", @@ -138,11 +139,11 @@ def test_lex_ignored_missing_heredoc_end end end - UNSUPPORTED_EVENTS = %i[comma ignored_nl label_end nl semicolon sp words_sep ignored_sp] + UNSUPPORTED_EVENTS = %i[comma ignored_nl label_end nl semicolon sp ignored_sp] # Events that are currently not emitted SUPPORTED_EVENTS = Translation::Ripper::EVENTS - UNSUPPORTED_EVENTS # Events that assert against their line/column - CHECK_LOCATION_EVENTS = %i[kw op lbrace rbrace lbracket rbracket lparen rparen] + CHECK_LOCATION_EVENTS = %i[kw op lbrace rbrace lbracket rbracket lparen rparen words_sep] module Events attr_reader :events diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb index f20771c5f02e0e..4cdc9479f722fa 100644 --- a/test/rubygems/test_gem_installer.rb +++ b/test/rubygems/test_gem_installer.rb @@ -2442,6 +2442,136 @@ def test_gem_attribute assert_kind_of(String, installer.gem) end + def test_install_no_build_extension + installer = util_setup_installer + + gemdir = File.join @gemhome, "gems", @spec.full_name + + installer.options[:build_extension] = false + + use_ui @ui do + installer.install + end + + assert_path_exist gemdir + assert_path_not_exist File.join(@spec.extension_dir, "gem.build_complete") + assert_match "contains native extensions that were not built", @ui.error + assert_match "gem pristine #{@spec.name} --extensions", @ui.error + end + + def test_install_no_build_extension_without_extensions + spec = quick_gem "b", 2 + + util_build_gem spec + + installer = util_installer spec, @gemhome + installer.options[:build_extension] = false + + use_ui @ui do + installer.install + end + + refute_match "contains native extensions", @ui.error + end + + def test_install_no_install_plugin + installer = util_setup_installer do |spec| + write_file File.join(@tempdir, "lib", "rubygems_plugin.rb") do |io| + io.write "# do nothing" + end + + spec.files += %w[lib/rubygems_plugin.rb] + end + + installer.options[:install_plugin] = false + + build_rake_in do + use_ui @ui do + installer.install + end + end + + plugin_path = File.join Gem.plugindir, "a_plugin.rb" + refute File.exist?(plugin_path), "plugin must not be written when --no-install-plugin" + assert_match "contains plugins that were not installed", @ui.error + assert_match "gem pristine #{@spec.name} --only-plugins", @ui.error + end + + def test_install_no_install_plugin_skips_load_plugin + installer = util_setup_installer do |spec| + write_file File.join(@tempdir, "lib", "rubygems_plugin.rb") do |io| + io.write "$no_install_plugin_test_loaded = true" + end + + spec.files += %w[lib/rubygems_plugin.rb] + end + + # Simulate a pre-existing plugin wrapper from a previous install + FileUtils.mkdir_p Gem.plugindir + plugin_path = File.join Gem.plugindir, "a_plugin.rb" + File.write(plugin_path, "require_relative '../../gems/#{@spec.full_name}/lib/rubygems_plugin'") + + installer.options[:install_plugin] = false + + build_rake_in do + use_ui @ui do + installer.install + end + end + + refute defined?($no_install_plugin_test_loaded) && $no_install_plugin_test_loaded, + "plugin must not be loaded when --no-install-plugin" + ensure + $no_install_plugin_test_loaded = nil + end + + def test_install_no_install_plugin_without_plugins + installer = util_setup_installer + + installer.options[:install_plugin] = false + + build_rake_in do + use_ui @ui do + installer.install + end + end + + refute_match "contains plugins", @ui.error + end + + def test_install_no_install_plugin_removes_stale_wrappers + # First install a version with a plugin + installer = util_setup_installer do |spec| + write_file File.join(@tempdir, "lib", "rubygems_plugin.rb") do |io| + io.write "# plugin code" + end + + spec.files += %w[lib/rubygems_plugin.rb] + end + + build_rake_in do + use_ui @ui do + installer.install + end + end + + plugin_path = File.join Gem.plugindir, "a_plugin.rb" + assert File.exist?(plugin_path), "plugin wrapper should exist after first install" + + # Now install a new version without plugins, using --no-install-plugin + spec2 = quick_gem "a", 3 + util_build_gem spec2 + + installer2 = util_installer spec2, @gemhome + installer2.options[:install_plugin] = false + + use_ui @ui do + installer2.install + end + + refute File.exist?(plugin_path), "stale plugin wrapper must be removed" + end + private def util_execless diff --git a/test/rubygems/test_gem_resolver_git_specification.rb b/test/rubygems/test_gem_resolver_git_specification.rb index 621333d3bf51fd..e03c61e27ddc23 100644 --- a/test/rubygems/test_gem_resolver_git_specification.rb +++ b/test/rubygems/test_gem_resolver_git_specification.rb @@ -97,6 +97,44 @@ def test_install_extension assert_path_exist File.join git_spec.spec.extension_dir, "b.rb" end + def test_install_no_build_extension + pend if Gem.java_platform? + pend "terminates on mswin" if vc_windows? && ruby_repo? + name, _, repository, = git_gem "a", 1 do |s| + s.extensions << "ext/extconf.rb" + end + + Dir.chdir "git/a" do + FileUtils.mkdir_p "ext/lib" + + File.open "ext/extconf.rb", "w" do |io| + io.puts 'require "mkmf"' + io.puts 'create_makefile "a"' + end + + FileUtils.touch "ext/lib/b.rb" + + system @git, "add", "ext/extconf.rb" + system @git, "add", "ext/lib/b.rb" + + system @git, "commit", "--quiet", "-m", "Add extension files" + end + + source = Gem::Source::Git.new name, repository, nil, true + + spec = source.specs.first + + git_spec = Gem::Resolver::GitSpecification.new @set, spec, source + + use_ui @ui do + git_spec.install(build_extension: false) + end + + assert_path_not_exist File.join(git_spec.spec.extension_dir, "b.rb") + assert_match "contains native extensions that were not built", @ui.error + assert_match "gem pristine #{git_spec.spec.name} --extensions", @ui.error + end + def test_install_installed git_gem "a", 1 diff --git a/test/test_ipaddr.rb b/test/test_ipaddr.rb index 4b7229fc17b686..c00626e3a76b93 100644 --- a/test/test_ipaddr.rb +++ b/test/test_ipaddr.rb @@ -533,6 +533,9 @@ def test_loopback? assert_equal(false, IPAddr.new('::ffff:0.0.0.0').loopback?) assert_equal(false, IPAddr.new('::ffff:192.168.2.0').loopback?) assert_equal(false, IPAddr.new('::ffff:255.0.0.0').loopback?) + + # Global unicast addresses with 0xffff in group 5 must not be mistaken for ::ffff:127.x.x.x + assert_equal(false, IPAddr.new('2001:db8:1:1:0:ffff:7f00:1').loopback?) end def test_private? @@ -583,6 +586,10 @@ def test_private? assert_equal(false, IPAddr.new('::ffff:192.169.0.0').private?) assert_equal(false, IPAddr.new('::ffff:169.254.0.1').private?) + + # Global unicast addresses with 0xffff in group 5 must not be mistaken for ::ffff:10/172.16/192.168.x + assert_equal(false, IPAddr.new('2001:718:1404:c8:0:ffff:ac19:c80e').private?) + assert_equal(false, IPAddr.new('2001:db8:1:1:0:ffff:c0a8:1').private?) end def test_link_local? @@ -609,6 +616,9 @@ def test_link_local? assert_equal(true, IPAddr.new('::ffff:169.254.1.1').link_local?) assert_equal(true, IPAddr.new('::ffff:169.254.254.255').link_local?) + + # Global unicast addresses with 0xffff in group 5 must not be mistaken for ::ffff:169.254.x.x + assert_equal(false, IPAddr.new('2001:db8:1:1:0:ffff:a9fe:101').link_local?) end def test_hash