diff --git a/lib/bundler.rb b/lib/bundler.rb index f6ad7ccaef..0ddd2c7f88 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -602,6 +602,10 @@ EOF reset_rubygems! end + def reset_settings! + @settings = nil + end + def reset_paths! @bin_path = nil @bundler_major_version = nil diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index b4196621e5..e2dceb98d5 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -57,7 +57,7 @@ module Bundler custom_gemfile = options[:gemfile] || Bundler.settings[:gemfile] if custom_gemfile && !custom_gemfile.empty? Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", File.expand_path(custom_gemfile) - Bundler.reset_paths! + Bundler.reset_settings! end Bundler.settings.set_command_option_if_given :retry, options[:retry] @@ -134,7 +134,8 @@ module Bundler if Bundler.which("man") && man_path !~ %r{^file:/.+!/META-INF/jruby.home/.+} Kernel.exec "man #{man_page}" else - puts File.read("#{File.dirname(man_page)}/#{File.basename(man_page)}.ronn") + fallback_man_path = File.expand_path("../man", __FILE__) + puts File.read("#{fallback_man_path}/#{File.basename(man_page)}.ronn") end elsif command_path = Bundler.which("bundler-#{cli}") Kernel.exec(command_path, "--help") @@ -380,6 +381,8 @@ module Bundler "Make binstubs that can work without the Bundler runtime" method_option "all", :type => :boolean, :banner => "Install binstubs for all gems" + method_option "all-platforms", :type => :boolean, :default => false, :banner => + "Install binstubs for all platforms" def binstubs(*gems) require_relative "cli/binstubs" Binstubs.new(options, gems).run diff --git a/lib/bundler/cli/binstubs.rb b/lib/bundler/cli/binstubs.rb index 266396eedc..639c01ff39 100644 --- a/lib/bundler/cli/binstubs.rb +++ b/lib/bundler/cli/binstubs.rb @@ -16,7 +16,11 @@ module Bundler Bundler.settings.set_command_option_if_given :shebang, options["shebang"] installer = Installer.new(Bundler.root, Bundler.definition) - installer_opts = { :force => options[:force], :binstubs_cmd => true } + installer_opts = { + :force => options[:force], + :binstubs_cmd => true, + :all_platforms => options["all-platforms"], + } if options[:all] raise InvalidOption, "Cannot specify --all with specific gems" unless gems.empty? @@ -38,7 +42,7 @@ module Bundler if options[:standalone] next Bundler.ui.warn("Sorry, Bundler can only be run via RubyGems.") if gem_name == "bundler" Bundler.settings.temporary(:path => (Bundler.settings[:path] || Bundler.root)) do - installer.generate_standalone_bundler_executable_stubs(spec) + installer.generate_standalone_bundler_executable_stubs(spec, installer_opts) end else installer.generate_bundler_executable_stubs(spec, installer_opts) diff --git a/lib/bundler/cli/exec.rb b/lib/bundler/cli/exec.rb index 0412d3adb0..318d57fb06 100644 --- a/lib/bundler/cli/exec.rb +++ b/lib/bundler/cli/exec.rb @@ -63,10 +63,10 @@ module Bundler Kernel.load(file) rescue SystemExit, SignalException raise - rescue Exception => e # rubocop:disable Lint/RescueException + rescue Exception # rubocop:disable Lint/RescueException Bundler.ui.error "bundler: failed to load command: #{cmd} (#{file})" - backtrace = e.backtrace ? e.backtrace.take_while {|bt| !bt.start_with?(__FILE__) } : [] - abort "#{e.class}: #{e.message}\n #{backtrace.join("\n ")}" + Bundler::FriendlyErrors.disable! + raise end def process_title(file, args) diff --git a/lib/bundler/cli/outdated.rb b/lib/bundler/cli/outdated.rb index 109c5f417f..b8d9be20b6 100644 --- a/lib/bundler/cli/outdated.rb +++ b/lib/bundler/cli/outdated.rb @@ -76,8 +76,6 @@ module Bundler next unless gems.empty? || gems.include?(current_spec.name) active_spec = retrieve_active_spec(definition, current_spec) - next unless active_spec - next unless filter_options_patch.empty? || update_present_via_semver_portions(current_spec, active_spec, options) gem_outdated = Gem::Version.new(active_spec.version) > Gem::Version.new(current_spec.version) @@ -146,8 +144,6 @@ module Bundler end def retrieve_active_spec(definition, current_spec) - return unless current_spec.match_platform(Bundler.local_platform) - if strict active_spec = definition.find_resolved_spec(current_spec) else @@ -233,6 +229,8 @@ module Bundler end def update_present_via_semver_portions(current_spec, active_spec, options) + return false if active_spec.nil? + current_major = current_spec.version.segments.first active_major = active_spec.version.segments.first diff --git a/lib/bundler/compact_index_client/updater.rb b/lib/bundler/compact_index_client/updater.rb index 40232019bc..66d1735583 100644 --- a/lib/bundler/compact_index_client/updater.rb +++ b/lib/bundler/compact_index_client/updater.rb @@ -22,13 +22,13 @@ module Bundler def initialize(fetcher) @fetcher = fetcher - require "tmpdir" + require_relative "../vendored_tmpdir" end def update(local_path, remote_path, retrying = nil) headers = {} - Dir.mktmpdir("bundler-compact-index-") do |local_temp_dir| + Bundler::Dir.mktmpdir("bundler-compact-index-") do |local_temp_dir| local_temp_path = Pathname.new(local_temp_dir).join(local_path.basename) # first try to fetch any new bytes on the existing file @@ -66,8 +66,8 @@ module Bundler end end - response_etag = (response["ETag"] || "").gsub(%r{\AW/}, "") - if etag_for(local_temp_path) == response_etag + etag = (response["ETag"] || "").gsub(%r{\AW/}, "") + if etag.length.zero? || etag_for(local_temp_path) == etag SharedHelpers.filesystem_access(local_path) do FileUtils.mv(local_temp_path, local_path) end @@ -75,7 +75,7 @@ module Bundler end if retrying - raise MisMatchedChecksumError.new(remote_path, response_etag, etag_for(local_temp_path)) + raise MisMatchedChecksumError.new(remote_path, etag, etag_for(local_temp_path)) end update(local_path, remote_path, :retrying) diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 1a4b703aa5..4cf4f76084 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -118,7 +118,7 @@ module Bundler end @unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version) - add_platforms unless Bundler.frozen_bundle? + add_current_platform unless Bundler.frozen_bundle? converge_path_sources_to_gemspec_sources @path_changes = converge_paths @@ -547,17 +547,12 @@ module Bundler private - def add_platforms - (@dependencies.flat_map(&:expanded_platforms) + current_platforms).uniq.each do |platform| - add_platform(platform) - end + def add_current_platform + current_platforms.each {|platform| add_platform(platform) } end def current_platforms - [].tap do |platforms| - platforms << local_platform if Bundler.feature_flag.specific_platform? - platforms << generic_local_platform - end + [local_platform, generic_local_platform].uniq end def change_reason diff --git a/lib/bundler/env.rb b/lib/bundler/env.rb index 17624b4fe9..00d4ef2196 100644 --- a/lib/bundler/env.rb +++ b/lib/bundler/env.rb @@ -105,7 +105,7 @@ module Bundler out << [" User Home", Gem.user_home] out << [" User Path", Gem.user_dir] out << [" Bin Dir", Gem.bindir] - if defined?(OpenSSL) + if defined?(OpenSSL::SSL) out << ["OpenSSL"] out << [" Compiled", OpenSSL::OPENSSL_VERSION] if defined?(OpenSSL::OPENSSL_VERSION) out << [" Loaded", OpenSSL::OPENSSL_LIBRARY_VERSION] if defined?(OpenSSL::OPENSSL_LIBRARY_VERSION) diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb index fd76d9e5ba..a92ec8756d 100644 --- a/lib/bundler/feature_flag.rb +++ b/lib/bundler/feature_flag.rb @@ -41,7 +41,6 @@ module Bundler settings_flag(:plugins) { @bundler_version >= Gem::Version.new("1.14") } settings_flag(:print_only_version_number) { bundler_3_mode? } settings_flag(:setup_makes_kernel_gem_public) { !bundler_3_mode? } - settings_flag(:specific_platform) { bundler_3_mode? } settings_flag(:suppress_install_using_messages) { bundler_3_mode? } settings_flag(:unlock_source_unlocks_spec) { !bundler_3_mode? } settings_flag(:update_requires_all_flag) { bundler_4_mode? } diff --git a/lib/bundler/fetcher/index.rb b/lib/bundler/fetcher/index.rb index 7e07eaea7b..08b041897e 100644 --- a/lib/bundler/fetcher/index.rb +++ b/lib/bundler/fetcher/index.rb @@ -8,7 +8,7 @@ module Bundler class Index < Base def specs(_gem_names) Bundler.rubygems.fetch_all_remote_specs(remote) - rescue Gem::RemoteFetcher::FetchError, OpenSSL::SSL::SSLError, Net::HTTPFatalError => e + rescue Gem::RemoteFetcher::FetchError => e case e.message when /certificate verify failed/ raise CertificateFailureError.new(display_uri) @@ -19,8 +19,7 @@ module Bundler raise BadAuthenticationError, remote_uri if remote_uri.userinfo raise AuthenticationRequiredError, remote_uri else - Bundler.ui.trace e - raise HTTPError, "Could not fetch specs from #{display_uri}" + raise HTTPError, "Could not fetch specs from #{display_uri} due to underlying error <#{e.message}>" end end diff --git a/lib/bundler/friendly_errors.rb b/lib/bundler/friendly_errors.rb index 8273064699..5d0bb905bc 100644 --- a/lib/bundler/friendly_errors.rb +++ b/lib/bundler/friendly_errors.rb @@ -6,6 +6,18 @@ module Bundler module FriendlyErrors module_function + def enable! + @disabled = false + end + + def disabled? + @disabled + end + + def disable! + @disabled = true + end + def log_error(error) case error when YamlSyntaxError @@ -114,10 +126,13 @@ module Bundler end def self.with_friendly_errors + FriendlyErrors.enable! yield rescue SignalException raise rescue Exception => e # rubocop:disable Lint/RescueException + raise if FriendlyErrors.disabled? + FriendlyErrors.log_error(e) exit FriendlyErrors.exit_status(e) end diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb index fa48df738c..f26f542fde 100644 --- a/lib/bundler/index.rb +++ b/lib/bundler/index.rb @@ -195,7 +195,11 @@ module Bundler if base # allow all platforms when searching from a lockfile dependency.matches_spec?(spec) else - dependency.matches_spec?(spec) && Gem::Platform.match(spec.platform) + if Gem::Platform.respond_to? :match_spec? + dependency.matches_spec?(spec) && Gem::Platform.match_spec?(spec) + else + dependency.matches_spec?(spec) && Gem::Platform.match(spec.platform) + end end end diff --git a/lib/bundler/injector.rb b/lib/bundler/injector.rb index 02c3e6189f..e9aa13a357 100644 --- a/lib/bundler/injector.rb +++ b/lib/bundler/injector.rb @@ -179,11 +179,11 @@ module Bundler # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies. def remove_gems_from_gemfile(gems, gemfile_path) patterns = /gem\s+(['"])#{Regexp.union(gems)}\1|gem\s*\((['"])#{Regexp.union(gems)}\2\)/ - new_gemfile = [] multiline_removal = false IO.readlines(gemfile_path).each do |line| - if line.match(patterns) + match_data = line.match(patterns) + if match_data && is_not_within_comment?(line, match_data) multiline_removal = line.rstrip.end_with?(",") # skip lines which match the regex next @@ -207,6 +207,13 @@ module Bundler new_gemfile.join.chomp end + # @param [String] line Individual line of gemfile content. + # @param [MatchData] match_data Data about Regex match. + def is_not_within_comment?(line, match_data) + match_start_index = match_data.offset(0).first + !line[0..match_start_index].include?("#") + end + # @param [Array] gemfile Array of gemfile contents. # @param [String] block_name Name of block name to look for. def remove_nested_blocks(gemfile, block_name) diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb index e08cc9722b..048b0786a7 100644 --- a/lib/bundler/installer.rb +++ b/lib/bundler/installer.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require "erb" require "rubygems/dependency_installer" require_relative "worker" require_relative "installer/parallel_installer" @@ -136,6 +135,7 @@ module Bundler end mode = Bundler::WINDOWS ? "wb:UTF-8" : "w" + require "erb" content = if RUBY_VERSION >= "2.6" ERB.new(template, :trim_mode => "-").result(binding) else @@ -143,7 +143,7 @@ module Bundler end File.write(binstub_path, content, :mode => mode, :perm => 0o777 & ~File.umask) - if Bundler::WINDOWS + if Bundler::WINDOWS || options[:all_platforms] prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n" File.write("#{binstub_path}.cmd", prefix + content, :mode => mode) end @@ -164,7 +164,7 @@ module Bundler end end - def generate_standalone_bundler_executable_stubs(spec) + def generate_standalone_bundler_executable_stubs(spec, options = {}) # double-assignment to avoid warnings about variables that will be used by ERB bin_path = Bundler.bin_path unless path = Bundler.settings[:path] @@ -182,6 +182,7 @@ module Bundler executable_path = executable_path mode = Bundler::WINDOWS ? "wb:UTF-8" : "w" + require "erb" content = if RUBY_VERSION >= "2.6" ERB.new(template, :trim_mode => "-").result(binding) else @@ -189,7 +190,7 @@ module Bundler end File.write("#{bin_path}/#{executable}", content, :mode => mode, :perm => 0o755) - if Bundler::WINDOWS + if Bundler::WINDOWS || options[:all_platforms] prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n" File.write("#{bin_path}/#{executable}.cmd", prefix + content, :mode => mode) end @@ -243,6 +244,7 @@ module Bundler end end.flatten Bundler.rubygems.load_plugin_files(path_plugin_files) + Bundler.rubygems.load_env_plugins end def ensure_specs_are_compatible! @@ -297,7 +299,7 @@ module Bundler # returns whether or not a re-resolve was needed def resolve_if_needed(options) - if !@definition.unlocking? && !options["force"] && !options["all-platforms"] && !Bundler.settings[:inline] && Bundler.default_lockfile.file? + if !@definition.unlocking? && !options["force"] && !Bundler.settings[:inline] && Bundler.default_lockfile.file? return false if @definition.nothing_changed? && !@definition.missing_specs? end diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb index 546b8d9b09..22bf0f3f6f 100644 --- a/lib/bundler/lazy_specification.rb +++ b/lib/bundler/lazy_specification.rb @@ -79,19 +79,17 @@ module Bundler @specification = if source.is_a?(Source::Gemspec) && source.gemspec.name == name source.gemspec.tap {|s| s.source = source } else - search_object = Bundler.feature_flag.specific_platform? || Bundler.settings[:force_ruby_platform] ? self : Dependency.new(name, version) + search_object = if source.is_a?(Source::Path) + Dependency.new(name, version) + else + self + end platform_object = Gem::Platform.new(platform) candidates = source.specs.search(search_object) same_platform_candidates = candidates.select do |spec| MatchPlatform.platforms_match?(spec.platform, platform_object) end search = same_platform_candidates.last || candidates.last - if search && Gem::Platform.new(search.platform) != platform_object && !search.runtime_dependencies.-(dependencies.reject {|d| d.type == :development }).empty? - Bundler.ui.warn "Unable to use the platform-specific (#{search.platform}) version of #{name} (#{version}) " \ - "because it has different dependencies from the #{platform} version. " \ - "To use the platform-specific version of the gem, run `bundle config set --local specific_platform true` and install again." - search = source.specs.search(self).last - end search.dependencies = dependencies if search && (search.is_a?(RemoteSpecification) || search.is_a?(EndpointSpecification)) search end diff --git a/lib/bundler/man/.document b/lib/bundler/man/.document new file mode 100644 index 0000000000..fb66f13c33 --- /dev/null +++ b/lib/bundler/man/.document @@ -0,0 +1 @@ +# Ignore all files in this directory diff --git a/man/bundle-add.1.ronn b/lib/bundler/man/bundle-add.1.ronn similarity index 100% rename from man/bundle-add.1.ronn rename to lib/bundler/man/bundle-add.1.ronn diff --git a/man/bundle-binstubs.1.ronn b/lib/bundler/man/bundle-binstubs.1.ronn similarity index 100% rename from man/bundle-binstubs.1.ronn rename to lib/bundler/man/bundle-binstubs.1.ronn diff --git a/man/bundle-cache.1.ronn b/lib/bundler/man/bundle-cache.1.ronn similarity index 100% rename from man/bundle-cache.1.ronn rename to lib/bundler/man/bundle-cache.1.ronn diff --git a/man/bundle-check.1.ronn b/lib/bundler/man/bundle-check.1.ronn similarity index 100% rename from man/bundle-check.1.ronn rename to lib/bundler/man/bundle-check.1.ronn diff --git a/man/bundle-clean.1.ronn b/lib/bundler/man/bundle-clean.1.ronn similarity index 100% rename from man/bundle-clean.1.ronn rename to lib/bundler/man/bundle-clean.1.ronn diff --git a/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn similarity index 96% rename from man/bundle-config.1.ronn rename to lib/bundler/man/bundle-config.1.ronn index a0ff30cb15..462edf7844 100644 --- a/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -250,14 +250,6 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). be changed in the next major version. * `silence_root_warning` (`BUNDLE_SILENCE_ROOT_WARNING`): Silence the warning Bundler prints when installing gems as root. -* `specific_platform` (`BUNDLE_SPECIFIC_PLATFORM`): - Allow bundler to resolve for the specific running platform and store it in - the lockfile, instead of only using a generic platform. - A specific platform is the exact platform triple reported by - `Gem::Platform.local`, such as `x86_64-darwin-16` or `universal-java-1.8`. - On the other hand, generic platforms are those such as `ruby`, `mswin`, or - `java`. In this example, `x86_64-darwin-16` would map to `ruby` and - `universal-java-1.8` to `java`. * `ssl_ca_cert` (`BUNDLE_SSL_CA_CERT`): Path to a designated CA certificate file or folder containing multiple certificates for trusted CAs in PEM format. @@ -371,7 +363,7 @@ Or you can set the credentials as an environment variable like this: For gems with a git source with HTTP(S) URL you can specify credentials like so: - bundle config set --global https://github.com/bundler/bundler.git username:password + bundle config set --global https://github.com/rubygems/rubygems.git username:password Or you can set the credentials as an environment variable like so: diff --git a/man/bundle-doctor.1.ronn b/lib/bundler/man/bundle-doctor.1.ronn similarity index 100% rename from man/bundle-doctor.1.ronn rename to lib/bundler/man/bundle-doctor.1.ronn diff --git a/man/bundle-exec.1.ronn b/lib/bundler/man/bundle-exec.1.ronn similarity index 100% rename from man/bundle-exec.1.ronn rename to lib/bundler/man/bundle-exec.1.ronn diff --git a/man/bundle-gem.1.ronn b/lib/bundler/man/bundle-gem.1.ronn similarity index 100% rename from man/bundle-gem.1.ronn rename to lib/bundler/man/bundle-gem.1.ronn diff --git a/man/bundle-info.1.ronn b/lib/bundler/man/bundle-info.1.ronn similarity index 100% rename from man/bundle-info.1.ronn rename to lib/bundler/man/bundle-info.1.ronn diff --git a/man/bundle-init.1.ronn b/lib/bundler/man/bundle-init.1.ronn similarity index 100% rename from man/bundle-init.1.ronn rename to lib/bundler/man/bundle-init.1.ronn diff --git a/man/bundle-inject.1.ronn b/lib/bundler/man/bundle-inject.1.ronn similarity index 100% rename from man/bundle-inject.1.ronn rename to lib/bundler/man/bundle-inject.1.ronn diff --git a/man/bundle-install.1.ronn b/lib/bundler/man/bundle-install.1.ronn similarity index 99% rename from man/bundle-install.1.ronn rename to lib/bundler/man/bundle-install.1.ronn index 07aeb1da90..5ea777f1d4 100644 --- a/man/bundle-install.1.ronn +++ b/lib/bundler/man/bundle-install.1.ronn @@ -105,7 +105,7 @@ automatically and that requires `bundler` to silently remember them. Since * `--local`: Do not attempt to connect to `rubygems.org`. Instead, Bundler will use the - gems already present in Rubygems' cache or in `vendor/cache`. Note that if a + gems already present in Rubygems' cache or in `vendor/cache`. Note that if an appropriate platform-specific gem exists on `rubygems.org` it will not be found. diff --git a/man/bundle-list.1.ronn b/lib/bundler/man/bundle-list.1.ronn similarity index 100% rename from man/bundle-list.1.ronn rename to lib/bundler/man/bundle-list.1.ronn diff --git a/man/bundle-lock.1.ronn b/lib/bundler/man/bundle-lock.1.ronn similarity index 100% rename from man/bundle-lock.1.ronn rename to lib/bundler/man/bundle-lock.1.ronn diff --git a/man/bundle-open.1.ronn b/lib/bundler/man/bundle-open.1.ronn similarity index 100% rename from man/bundle-open.1.ronn rename to lib/bundler/man/bundle-open.1.ronn diff --git a/man/bundle-outdated.1.ronn b/lib/bundler/man/bundle-outdated.1.ronn similarity index 100% rename from man/bundle-outdated.1.ronn rename to lib/bundler/man/bundle-outdated.1.ronn diff --git a/man/bundle-platform.1.ronn b/lib/bundler/man/bundle-platform.1.ronn similarity index 100% rename from man/bundle-platform.1.ronn rename to lib/bundler/man/bundle-platform.1.ronn diff --git a/man/bundle-pristine.1.ronn b/lib/bundler/man/bundle-pristine.1.ronn similarity index 100% rename from man/bundle-pristine.1.ronn rename to lib/bundler/man/bundle-pristine.1.ronn diff --git a/man/bundle-remove.1.ronn b/lib/bundler/man/bundle-remove.1.ronn similarity index 100% rename from man/bundle-remove.1.ronn rename to lib/bundler/man/bundle-remove.1.ronn diff --git a/man/bundle-show.1.ronn b/lib/bundler/man/bundle-show.1.ronn similarity index 100% rename from man/bundle-show.1.ronn rename to lib/bundler/man/bundle-show.1.ronn diff --git a/man/bundle-update.1.ronn b/lib/bundler/man/bundle-update.1.ronn similarity index 100% rename from man/bundle-update.1.ronn rename to lib/bundler/man/bundle-update.1.ronn diff --git a/man/bundle-viz.1.ronn b/lib/bundler/man/bundle-viz.1.ronn similarity index 100% rename from man/bundle-viz.1.ronn rename to lib/bundler/man/bundle-viz.1.ronn diff --git a/man/bundle.1.ronn b/lib/bundler/man/bundle.1.ronn similarity index 100% rename from man/bundle.1.ronn rename to lib/bundler/man/bundle.1.ronn diff --git a/man/gemfile.5.ronn b/lib/bundler/man/gemfile.5.ronn similarity index 100% rename from man/gemfile.5.ronn rename to lib/bundler/man/gemfile.5.ronn diff --git a/lib/bundler/plugin/api/source.rb b/lib/bundler/plugin/api/source.rb index 56e97f4aa4..e1f0826874 100644 --- a/lib/bundler/plugin/api/source.rb +++ b/lib/bundler/plugin/api/source.rb @@ -260,7 +260,7 @@ module Bundler end def to_s - "plugin source for #{options[:type]} with uri #{uri}" + "plugin source for #{@type} with uri #{@uri}" end # Note: Do not override if you don't know what you are doing. diff --git a/lib/bundler/plugin/dsl.rb b/lib/bundler/plugin/dsl.rb index 4bfc8437e0..da751d1774 100644 --- a/lib/bundler/plugin/dsl.rb +++ b/lib/bundler/plugin/dsl.rb @@ -10,7 +10,7 @@ module Bundler # So that we don't have to override all there methods to dummy ones # explicitly. # They will be handled by method_missing - [:gemspec, :gem, :path, :install_if, :platforms, :env].each {|m| undef_method m } + [:gemspec, :gem, :install_if, :platforms, :env].each {|m| undef_method m } # This lists the plugins that was added automatically and not specified by # the user. diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 926c08c4c9..327c170fbe 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -158,9 +158,8 @@ module Bundler # spec group. sg_ruby = sg.copy_for(Gem::Platform::RUBY) selected_sgs << sg_ruby if sg_ruby - all_platforms = @platforms + [platform] - next if all_platforms.to_a == [Gem::Platform::RUBY] sg_all_platforms = nil + all_platforms = @platforms + [platform] self.class.sort_platforms(all_platforms).reverse_each do |other_platform| if sg_all_platforms.nil? sg_all_platforms = sg.copy_for(other_platform) @@ -302,7 +301,7 @@ module Bundler versions_with_platforms = specs.map {|s| [s.version, s.platform] } message = String.new("Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in #{source}#{cache_message}.\n") message << if versions_with_platforms.any? - "The source contains '#{name}' at: #{formatted_versions_with_platforms(versions_with_platforms)}" + "The source contains the following versions of '#{name}': #{formatted_versions_with_platforms(versions_with_platforms)}" else "The source does not contain any versions of '#{name}'" end diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb index 17402f16f2..9125a24172 100644 --- a/lib/bundler/rubygems_integration.rb +++ b/lib/bundler/rubygems_integration.rb @@ -227,6 +227,10 @@ module Bundler Gem.load_plugin_files(files) if Gem.respond_to?(:load_plugin_files) end + def load_env_plugins + Gem.load_env_plugins if Gem.respond_to?(:load_env_plugins) + end + def ui=(obj) Gem::DefaultUserInteraction.ui = obj end diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index 6ce81b5006..1c669491f6 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -42,7 +42,6 @@ module Bundler setup_makes_kernel_gem_public silence_deprecations silence_root_warning - specific_platform suppress_install_using_messages unlock_source_unlocks_spec update_requires_all_flag diff --git a/lib/bundler/source/git/git_proxy.rb b/lib/bundler/source/git/git_proxy.rb index 5dc1c8de32..7ac47044b3 100644 --- a/lib/bundler/source/git/git_proxy.rb +++ b/lib/bundler/source/git/git_proxy.rb @@ -118,7 +118,7 @@ module Bundler git_retry %(clone --no-checkout --quiet "#{path}" "#{destination}") File.chmod(((File.stat(destination).mode | 0o777) & ~File.umask), destination) rescue Errno::EEXIST => e - file_path = e.message[%r{.*?(/.*)}, 1] + file_path = e.message[%r{.*?((?:[a-zA-Z]:)?/.*)}, 1] raise GitError, "Bundler could not install a gem because it needs to " \ "create a directory, but a file exists - #{file_path}. Please delete " \ "this file and try again." diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index 46e023de87..aef854ce0c 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -100,6 +100,7 @@ module Bundler @specs.map do |s| next s unless s.is_a?(LazySpecification) s.source.dependency_names = names if s.source.respond_to?(:dependency_names=) + s.source.remote! spec = s.__materialize__ raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec spec diff --git a/lib/bundler/templates/newgem/README.md.tt b/lib/bundler/templates/newgem/README.md.tt index f81b85ca97..315bc745a3 100644 --- a/lib/bundler/templates/newgem/README.md.tt +++ b/lib/bundler/templates/newgem/README.md.tt @@ -33,7 +33,6 @@ To install this gem onto your local machine, run `bundle exec rake install`. To ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/<%= config[:github_username] %>/<%= config[:name] %>.<% if config[:coc] %> This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/master/CODE_OF_CONDUCT.md).<% end %> - <% if config[:mit] -%> ## License diff --git a/lib/bundler/templates/newgem/lib/newgem.rb.tt b/lib/bundler/templates/newgem/lib/newgem.rb.tt index a182b964be..caf6e32f4a 100644 --- a/lib/bundler/templates/newgem/lib/newgem.rb.tt +++ b/lib/bundler/templates/newgem/lib/newgem.rb.tt @@ -1,8 +1,8 @@ # frozen_string_literal: true -require "<%= config[:namespaced_path] %>/version" +require_relative "<%= File.basename(config[:namespaced_path]) %>/version" <%- if config[:ext] -%> -require "<%= config[:namespaced_path] %>/<%= config[:underscored_name] %>" +require_relative "<%= File.basename(config[:namespaced_path]) %>/<%= config[:underscored_name] %>" <%- end -%> <%- config[:constant_array].each_with_index do |c, i| -%> diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt index 5b34f64346..97c3b6c5ab 100644 --- a/lib/bundler/templates/newgem/newgem.gemspec.tt +++ b/lib/bundler/templates/newgem/newgem.gemspec.tt @@ -33,4 +33,10 @@ Gem::Specification.new do |spec| <%- if config[:ext] -%> spec.extensions = ["ext/<%= config[:underscored_name] %>/extconf.rb"] <%- end -%> + + # Uncomment to register a new dependency of your gem + # spec.add_dependency "example-gem", "~> 1.0" + + # For more information and examples about making a new gem, checkout our + # guide at: https://bundler.io/guides/creating_gem.html end diff --git a/lib/bundler/uri_credentials_filter.rb b/lib/bundler/uri_credentials_filter.rb index 3f49254e71..ccfaf0bc5d 100644 --- a/lib/bundler/uri_credentials_filter.rb +++ b/lib/bundler/uri_credentials_filter.rb @@ -8,6 +8,8 @@ module Bundler return uri_to_anonymize if uri_to_anonymize.nil? uri = uri_to_anonymize.dup if uri.is_a?(String) + return uri if File.exist?(uri) + require_relative "vendored_uri" uri = Bundler::URI(uri) end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo.rb b/lib/bundler/vendor/molinillo/lib/molinillo.rb index baedefe98b..a52b96deaf 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require_relative 'molinillo/compatibility' require_relative 'molinillo/gem_metadata' require_relative 'molinillo/errors' require_relative 'molinillo/resolver' diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb b/lib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb deleted file mode 100644 index 3eba8e4083..0000000000 --- a/lib/bundler/vendor/molinillo/lib/molinillo/compatibility.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -module Bundler::Molinillo - # Hacks needed for old Ruby versions. - module Compatibility - module_function - - if [].respond_to?(:flat_map) - # Flat map - # @param [Enumerable] enum an enumerable object - # @block the block to flat-map with - # @return The enum, flat-mapped - def flat_map(enum, &blk) - enum.flat_map(&blk) - end - else - # Flat map - # @param [Enumerable] enum an enumerable object - # @block the block to flat-map with - # @return The enum, flat-mapped - def flat_map(enum, &blk) - enum.map(&blk).flatten(1) - end - end - end -end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb index 31578bb5bf..d1d7045daf 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb @@ -124,6 +124,7 @@ module Bundler::Molinillo dot.join("\n") end + # @param [DependencyGraph] other # @return [Boolean] whether the two dependency graphs are equal, determined # by a recursive traversal of each {#root_vertices} and its # {Vertex#successors} @@ -190,7 +191,7 @@ module Bundler::Molinillo # @return [Edge] the added edge def add_edge(origin, destination, requirement) if destination.path_to?(origin) - raise CircularDependencyError.new([origin, destination]) + raise CircularDependencyError.new(path(destination, origin)) end add_edge_no_circular(origin, destination, requirement) end @@ -219,5 +220,37 @@ module Bundler::Molinillo def add_edge_no_circular(origin, destination, requirement) log.add_edge_no_circular(self, origin.name, destination.name, requirement) end + + # Returns the path between two vertices + # @raise [ArgumentError] if there is no path between the vertices + # @param [Vertex] from + # @param [Vertex] to + # @return [Array] the shortest path from `from` to `to` + def path(from, to) + distances = Hash.new(vertices.size + 1) + distances[from.name] = 0 + predecessors = {} + each do |vertex| + vertex.successors.each do |successor| + if distances[successor.name] > distances[vertex.name] + 1 + distances[successor.name] = distances[vertex.name] + 1 + predecessors[successor] = vertex + end + end + end + + path = [to] + while before = predecessors[to] + path << before + to = before + break if to == from + end + + unless path.last.equal?(from) + raise ArgumentError, "There is no path from #{from.name} to #{to.name}" + end + + path.reverse + end end end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb index fccfc78cc7..5b5da3e4f9 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb @@ -14,11 +14,11 @@ module Bundler::Molinillo end # (see Action#up) - def up(_graph) + def up(graph) end # (see Action#down) - def down(_graph) + def down(graph) end # @!group Tag diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb b/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb index 89c7c324d5..4d64d21072 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb @@ -65,7 +65,7 @@ module Bundler::Molinillo # @param [SpecificationProvider] specification_provider see {#specification_provider} def initialize(conflicts, specification_provider) pairs = [] - Compatibility.flat_map(conflicts.values.flatten, &:requirements).each do |conflicting| + conflicts.values.flat_map(&:requirements).each do |conflicting| conflicting.each do |source, conflict_requirements| conflict_requirements.each do |c| pairs << [c, source] diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb b/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb index 73f8fbf2ac..e13a781a50 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb @@ -2,5 +2,5 @@ module Bundler::Molinillo # The version of Bundler::Molinillo. - VERSION = '0.6.6'.freeze + VERSION = '0.7.0'.freeze end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb b/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb index acf7777414..26b8bc745c 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb @@ -207,7 +207,7 @@ module Bundler::Molinillo def start_resolution @started_at = Time.now - handle_missing_or_push_dependency_state(initial_state) + push_initial_state debug { "Starting resolution (#{@started_at})\nUser-requested dependencies: #{original_requested}" } resolver_ui.before_resolution @@ -273,10 +273,10 @@ module Bundler::Molinillo states.last end - # Creates the initial state for the resolution, based upon the + # Creates and pushes the initial state for the resolution, based upon the # {#requested} dependencies - # @return [DependencyState] the initial state for the resolution - def initial_state + # @return [void] + def push_initial_state graph = DependencyGraph.new.tap do |dg| original_requested.each do |requested| vertex = dg.add_vertex(name_for(requested), nil, true) @@ -285,18 +285,7 @@ module Bundler::Molinillo dg.tag(:initial_state) end - requirements = sort_dependencies(original_requested, graph, {}) - initial_requirement = requirements.shift - DependencyState.new( - initial_requirement && name_for(initial_requirement), - requirements, - graph, - initial_requirement, - possibilities_for_requirement(initial_requirement, graph), - 0, - {}, - [] - ) + push_state_for_requirements(original_requested, true, graph) end # Unwinds the states stack because a conflict has been encountered @@ -361,7 +350,7 @@ module Bundler::Molinillo current_detail end - # @param [Array] array of requirements that combine to create a conflict + # @param [Array] binding_requirements array of requirements that combine to create a conflict # @return [Array] array of UnwindDetails that have a chance # of resolving the passed requirements def unwind_options_for_requirements(binding_requirements) @@ -429,7 +418,7 @@ module Bundler::Molinillo end # @param [DependencyState] state - # @param [Array] array of requirements + # @param [Array] binding_requirements array of requirements # @return [Boolean] whether or not the given state has any possibilities # that could satisfy the given requirements def conflict_fixing_possibilities?(state, binding_requirements) @@ -444,7 +433,8 @@ module Bundler::Molinillo # Filter's a state's possibilities to remove any that would not fix the # conflict we've just rewound from - # @param [UnwindDetails] details of the conflict just unwound from + # @param [UnwindDetails] unwind_details details of the conflict just + # unwound from # @return [void] def filter_possibilities_after_unwind(unwind_details) return unless state && !state.possibilities.empty? @@ -458,7 +448,7 @@ module Bundler::Molinillo # Filter's a state's possibilities to remove any that would not satisfy # the requirements in the conflict we've just rewound from - # @param [UnwindDetails] details of the conflict just unwound from + # @param [UnwindDetails] unwind_details details of the conflict just unwound from # @return [void] def filter_possibilities_for_primary_unwind(unwind_details) unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index } @@ -491,7 +481,7 @@ module Bundler::Molinillo # Filter's a state's possibilities to remove any that would (eventually) # create a requirement in the conflict we've just rewound from - # @param [UnwindDetails] details of the conflict just unwound from + # @param [UnwindDetails] unwind_details details of the conflict just unwound from # @return [void] def filter_possibilities_for_parent_unwind(unwind_details) unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index } @@ -500,7 +490,7 @@ module Bundler::Molinillo primary_unwinds = unwinds_to_state.select(&:unwinding_to_primary_requirement?).uniq parent_unwinds = unwinds_to_state.uniq - primary_unwinds - allowed_possibility_sets = Compatibility.flat_map(primary_unwinds) do |unwind| + allowed_possibility_sets = primary_unwinds.flat_map do |unwind| states[unwind.state_index].possibilities.select do |possibility_set| possibility_set.possibilities.any? do |poss| possibility_satisfies_requirements?(poss, unwind.conflicting_requirements) @@ -508,7 +498,7 @@ module Bundler::Molinillo end end - requirements_to_avoid = Compatibility.flat_map(parent_unwinds, &:sub_dependencies_to_avoid) + requirements_to_avoid = parent_unwinds.flat_map(&:sub_dependencies_to_avoid) state.possibilities.reject! do |possibility_set| !allowed_possibility_sets.include?(possibility_set) && @@ -524,12 +514,12 @@ module Bundler::Molinillo possible_binding_requirements = conflict.requirements.values.flatten(1).uniq - # When there’s a `CircularDependency` error the conflicting requirement - # (the one causing the circular) won’t be `conflict.requirement` - # (which won’t be for the right state, because we won’t have created it, - # because it’s circular). - # We need to make sure we have that requirement in the conflict’s list, - # otherwise we won’t be able to unwind properly, so we just return all + # When there's a `CircularDependency` error the conflicting requirement + # (the one causing the circular) won't be `conflict.requirement` + # (which won't be for the right state, because we won't have created it, + # because it's circular). + # We need to make sure we have that requirement in the conflict's list, + # otherwise we won't be able to unwind properly, so we just return all # the requirements for the conflict. return possible_binding_requirements if conflict.underlying_error @@ -558,8 +548,8 @@ module Bundler::Molinillo end # @param [Object] requirement we wish to check - # @param [Array] array of requirements - # @param [Array] array of possibilities the requirements will be used to filter + # @param [Array] possible_binding_requirements array of requirements + # @param [Array] possibilities array of possibilities the requirements will be used to filter # @return [Boolean] whether or not the given requirement is required to filter # out all elements of the array of possibilities. def binding_requirement_in_set?(requirement, possible_binding_requirements, possibilities) @@ -568,6 +558,7 @@ module Bundler::Molinillo end end + # @param [Object] requirement # @return [Object] the requirement that led to `requirement` being added # to the list of requirements. def parent_of(requirement) @@ -577,6 +568,7 @@ module Bundler::Molinillo parent_state.requirement end + # @param [String] name # @return [Object] the requirement that led to a version of a possibility # with the given name being activated. def requirement_for_existing_name(name) @@ -585,6 +577,7 @@ module Bundler::Molinillo states.find { |s| s.name == name }.requirement end + # @param [Object] requirement # @return [ResolutionState] the state whose `requirement` is the given # `requirement`. def find_state_for(requirement) @@ -592,6 +585,7 @@ module Bundler::Molinillo states.find { |i| requirement == i.requirement } end + # @param [Object] underlying_error # @return [Conflict] a {Conflict} that reflects the failure to activate # the {#possibility} in conjunction with the current {#state} def create_conflict(underlying_error = nil) @@ -628,6 +622,7 @@ module Bundler::Molinillo vertex.requirements.map { |r| requirement_tree_for(r) } end + # @param [Object] requirement # @return [Array] the list of requirements that led to # `requirement` being required. def requirement_tree_for(requirement) @@ -673,9 +668,8 @@ module Bundler::Molinillo attempt_to_filter_existing_spec(existing_vertex) else latest = possibility.latest_version - # use reject!(!satisfied) for 1.8.7 compatibility - possibility.possibilities.reject! do |possibility| - !requirement_satisfied_by?(requirement, activated, possibility) + possibility.possibilities.select! do |possibility| + requirement_satisfied_by?(requirement, activated, possibility) end if possibility.latest_version.nil? # ensure there's a possibility for better error messages @@ -705,7 +699,7 @@ module Bundler::Molinillo # Generates a filtered version of the existing vertex's `PossibilitySet` using the # current state's `requirement` - # @param [Object] existing vertex + # @param [Object] vertex existing vertex # @return [PossibilitySet] filtered possibility set def filtered_possibility_set(vertex) PossibilitySet.new(vertex.payload.dependencies, vertex.payload.possibilities & possibility.possibilities) @@ -730,7 +724,7 @@ module Bundler::Molinillo end # Requires the dependencies that the recently activated spec has - # @param [Object] activated_possibility the PossibilitySet that has just been + # @param [Object] possibility_set the PossibilitySet that has just been # activated # @return [void] def require_nested_dependencies_for(possibility_set) @@ -749,6 +743,8 @@ module Bundler::Molinillo # Pushes a new {DependencyState} that encapsulates both existing and new # requirements # @param [Array] new_requirements + # @param [Boolean] requires_sort + # @param [Object] new_activated # @return [void] def push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated) new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts) if requires_sort @@ -767,7 +763,8 @@ module Bundler::Molinillo # Checks a proposed requirement with any existing locked requirement # before generating an array of possibilities for it. - # @param [Object] the proposed requirement + # @param [Object] requirement the proposed requirement + # @param [Object] activated # @return [Array] possibilities def possibilities_for_requirement(requirement, activated = self.activated) return [] unless requirement @@ -778,7 +775,8 @@ module Bundler::Molinillo group_possibilities(search_for(requirement)) end - # @param [Object] the proposed requirement + # @param [Object] requirement the proposed requirement + # @param [Object] activated # @return [Array] possibility set containing only the locked requirement, if any def locked_requirement_possibility_set(requirement, activated = self.activated) all_possibilities = search_for(requirement) @@ -797,8 +795,8 @@ module Bundler::Molinillo # Build an array of PossibilitySets, with each element representing a group of # dependency versions that all have the same sub-dependency version constraints # and are contiguous. - # @param [Array] an array of possibilities - # @return [Array] an array of possibility sets + # @param [Array] possibilities an array of possibilities + # @return [Array] an array of possibility sets def group_possibilities(possibilities) possibility_sets = [] current_possibility_set = nil diff --git a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb index 847479a0af..d0ab956faf 100644 --- a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +++ b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb @@ -3,6 +3,8 @@ require_relative '../../../../uri/lib/uri' require 'cgi' # for escaping require_relative '../../../../connection_pool/lib/connection_pool' +autoload :OpenSSL, 'openssl' + ## # Persistent connections for Net::HTTP # @@ -147,14 +149,9 @@ class Bundler::Persistent::Net::HTTP::Persistent EPOCH = Time.at 0 # :nodoc: ## - # Is OpenSSL available? + # Is OpenSSL available? This test works with autoload - HAVE_OPENSSL = begin # :nodoc: - require 'openssl' - true - rescue LoadError - false - end + HAVE_OPENSSL = defined? OpenSSL::SSL # :nodoc: ## # The default connection pool size is 1/4 the allowed open files diff --git a/lib/bundler/vendor/tmpdir/lib/tmpdir.rb b/lib/bundler/vendor/tmpdir/lib/tmpdir.rb new file mode 100644 index 0000000000..a00496687c --- /dev/null +++ b/lib/bundler/vendor/tmpdir/lib/tmpdir.rb @@ -0,0 +1,154 @@ +# frozen_string_literal: true +# +# tmpdir - retrieve temporary directory path +# +# $Id$ +# + +require_relative '../../fileutils/lib/fileutils' +begin + require 'etc.so' +rescue LoadError # rescue LoadError for miniruby +end + +class Bundler::Dir < Dir + + @systmpdir ||= defined?(Etc.systmpdir) ? Etc.systmpdir : '/tmp' + + ## + # Returns the operating system's temporary file path. + + def self.tmpdir + tmp = nil + ['TMPDIR', 'TMP', 'TEMP', ['system temporary path', @systmpdir], ['/tmp']*2, ['.']*2].each do |name, dir = ENV[name]| + next if !dir + dir = File.expand_path(dir) + stat = File.stat(dir) rescue next + case + when !stat.directory? + warn "#{name} is not a directory: #{dir}" + when !stat.writable? + warn "#{name} is not writable: #{dir}" + when stat.world_writable? && !stat.sticky? + warn "#{name} is world-writable: #{dir}" + else + tmp = dir + break + end + end + raise ArgumentError, "could not find a temporary directory" unless tmp + tmp + end + + # Bundler::Dir.mktmpdir creates a temporary directory. + # + # The directory is created with 0700 permission. + # Application should not change the permission to make the temporary directory accessible from other users. + # + # The prefix and suffix of the name of the directory is specified by + # the optional first argument, prefix_suffix. + # - If it is not specified or nil, "d" is used as the prefix and no suffix is used. + # - If it is a string, it is used as the prefix and no suffix is used. + # - If it is an array, first element is used as the prefix and second element is used as a suffix. + # + # Bundler::Dir.mktmpdir {|dir| dir is ".../d..." } + # Bundler::Dir.mktmpdir("foo") {|dir| dir is ".../foo..." } + # Bundler::Dir.mktmpdir(["foo", "bar"]) {|dir| dir is ".../foo...bar" } + # + # The directory is created under Bundler::Dir.tmpdir or + # the optional second argument tmpdir if non-nil value is given. + # + # Bundler::Dir.mktmpdir {|dir| dir is "#{Bundler::Dir.tmpdir}/d..." } + # Bundler::Dir.mktmpdir(nil, "/var/tmp") {|dir| dir is "/var/tmp/d..." } + # + # If a block is given, + # it is yielded with the path of the directory. + # The directory and its contents are removed + # using Bundler::FileUtils.remove_entry before Bundler::Dir.mktmpdir returns. + # The value of the block is returned. + # + # Bundler::Dir.mktmpdir {|dir| + # # use the directory... + # open("#{dir}/foo", "w") { ... } + # } + # + # If a block is not given, + # The path of the directory is returned. + # In this case, Bundler::Dir.mktmpdir doesn't remove the directory. + # + # dir = Bundler::Dir.mktmpdir + # begin + # # use the directory... + # open("#{dir}/foo", "w") { ... } + # ensure + # # remove the directory. + # Bundler::FileUtils.remove_entry dir + # end + # + def self.mktmpdir(prefix_suffix=nil, *rest, **options) + base = nil + path = Tmpname.create(prefix_suffix || "d", *rest, **options) {|p, _, _, d| + base = d + mkdir(p, 0700) + } + if block_given? + begin + yield path.dup + ensure + unless base + stat = File.stat(File.dirname(path)) + if stat.world_writable? and !stat.sticky? + raise ArgumentError, "parent directory is world writable but not sticky" + end + end + Bundler::FileUtils.remove_entry path + end + else + path + end + end + + module Tmpname # :nodoc: + module_function + + def tmpdir + Bundler::Dir.tmpdir + end + + UNUSABLE_CHARS = [File::SEPARATOR, File::ALT_SEPARATOR, File::PATH_SEPARATOR, ":"].uniq.join("").freeze + + class << (RANDOM = Random.new) + MAX = 36**6 # < 0x100000000 + def next + rand(MAX).to_s(36) + end + end + private_constant :RANDOM + + def create(basename, tmpdir=nil, max_try: nil, **opts) + origdir = tmpdir + tmpdir ||= tmpdir() + n = nil + prefix, suffix = basename + prefix = (String.try_convert(prefix) or + raise ArgumentError, "unexpected prefix: #{prefix.inspect}") + prefix = prefix.delete(UNUSABLE_CHARS) + suffix &&= (String.try_convert(suffix) or + raise ArgumentError, "unexpected suffix: #{suffix.inspect}") + suffix &&= suffix.delete(UNUSABLE_CHARS) + begin + t = Time.now.strftime("%Y%m%d") + path = "#{prefix}#{t}-#{$$}-#{RANDOM.next}"\ + "#{n ? %[-#{n}] : ''}#{suffix||''}" + path = File.join(tmpdir, path) + yield(path, n, opts, origdir) + rescue Errno::EEXIST + n ||= 0 + n += 1 + retry if !max_try or n < max_try + raise "cannot generate temporary name using `#{basename}' under `#{tmpdir}'" + end + path + end + end +end diff --git a/lib/bundler/vendored_tmpdir.rb b/lib/bundler/vendored_tmpdir.rb new file mode 100644 index 0000000000..43b4fa75fe --- /dev/null +++ b/lib/bundler/vendored_tmpdir.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +module Bundler; end +require_relative "vendor/tmpdir/lib/tmpdir" diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index 4b2b0ec3c1..c865621acb 100644 --- a/lib/bundler/version.rb +++ b/lib/bundler/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module Bundler - VERSION = "2.2.0.rc.2".freeze + VERSION = "2.2.0".freeze def self.bundler_major_version @bundler_major_version ||= VERSION.split(".").first.to_i diff --git a/man/bundle-add.1 b/man/bundle-add.1 index 486c249719..985d3be8b1 100644 --- a/man/bundle-add.1 +++ b/man/bundle-add.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-ADD" "1" "October 2020" "" "" +.TH "BUNDLE\-ADD" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install diff --git a/man/bundle-binstubs.1 b/man/bundle-binstubs.1 index 782a464c16..75d6b98c96 100644 --- a/man/bundle-binstubs.1 +++ b/man/bundle-binstubs.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-BINSTUBS" "1" "October 2020" "" "" +.TH "BUNDLE\-BINSTUBS" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems diff --git a/man/bundle-cache.1 b/man/bundle-cache.1 index f840893f96..313359d78f 100644 --- a/man/bundle-cache.1 +++ b/man/bundle-cache.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CACHE" "1" "October 2020" "" "" +.TH "BUNDLE\-CACHE" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application diff --git a/man/bundle-check.1 b/man/bundle-check.1 index 4c7bc3f329..3f1a4bc329 100644 --- a/man/bundle-check.1 +++ b/man/bundle-check.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CHECK" "1" "October 2020" "" "" +.TH "BUNDLE\-CHECK" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems diff --git a/man/bundle-clean.1 b/man/bundle-clean.1 index dd1682a48b..1c111ae906 100644 --- a/man/bundle-clean.1 +++ b/man/bundle-clean.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CLEAN" "1" "October 2020" "" "" +.TH "BUNDLE\-CLEAN" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory diff --git a/man/bundle-config.1 b/man/bundle-config.1 index d989aaeb86..39b32e7496 100644 --- a/man/bundle-config.1 +++ b/man/bundle-config.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CONFIG" "1" "October 2020" "" "" +.TH "BUNDLE\-CONFIG" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-config\fR \- Set bundler configuration options @@ -262,9 +262,6 @@ The following is a list of all configuration keys and their purpose\. You can le \fBsilence_root_warning\fR (\fBBUNDLE_SILENCE_ROOT_WARNING\fR): Silence the warning Bundler prints when installing gems as root\. . .IP "\(bu" 4 -\fBspecific_platform\fR (\fBBUNDLE_SPECIFIC_PLATFORM\fR): Allow bundler to resolve for the specific running platform and store it in the lockfile, instead of only using a generic platform\. A specific platform is the exact platform triple reported by \fBGem::Platform\.local\fR, such as \fBx86_64\-darwin\-16\fR or \fBuniversal\-java\-1\.8\fR\. On the other hand, generic platforms are those such as \fBruby\fR, \fBmswin\fR, or \fBjava\fR\. In this example, \fBx86_64\-darwin\-16\fR would map to \fBruby\fR and \fBuniversal\-java\-1\.8\fR to \fBjava\fR\. -. -.IP "\(bu" 4 \fBssl_ca_cert\fR (\fBBUNDLE_SSL_CA_CERT\fR): Path to a designated CA certificate file or folder containing multiple certificates for trusted CAs in PEM format\. . .IP "\(bu" 4 @@ -441,7 +438,7 @@ For gems with a git source with HTTP(S) URL you can specify credentials like so: . .nf -bundle config set \-\-global https://github\.com/bundler/bundler\.git username:password +bundle config set \-\-global https://github\.com/rubygems/rubygems\.git username:password . .fi . diff --git a/man/bundle-doctor.1 b/man/bundle-doctor.1 index 82f0fc6fba..39841c8032 100644 --- a/man/bundle-doctor.1 +++ b/man/bundle-doctor.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-DOCTOR" "1" "October 2020" "" "" +.TH "BUNDLE\-DOCTOR" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-doctor\fR \- Checks the bundle for common problems diff --git a/man/bundle-exec.1 b/man/bundle-exec.1 index 4dc42bed28..b8c1b308c3 100644 --- a/man/bundle-exec.1 +++ b/man/bundle-exec.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-EXEC" "1" "October 2020" "" "" +.TH "BUNDLE\-EXEC" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-exec\fR \- Execute a command in the context of the bundle diff --git a/man/bundle-gem.1 b/man/bundle-gem.1 index 124df739cc..65c35615c5 100644 --- a/man/bundle-gem.1 +++ b/man/bundle-gem.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-GEM" "1" "October 2020" "" "" +.TH "BUNDLE\-GEM" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem diff --git a/man/bundle-info.1 b/man/bundle-info.1 index 2d860d51ab..b20396d273 100644 --- a/man/bundle-info.1 +++ b/man/bundle-info.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INFO" "1" "October 2020" "" "" +.TH "BUNDLE\-INFO" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-info\fR \- Show information for the given gem in your bundle diff --git a/man/bundle-init.1 b/man/bundle-init.1 index c21e269071..b6714730c4 100644 --- a/man/bundle-init.1 +++ b/man/bundle-init.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INIT" "1" "October 2020" "" "" +.TH "BUNDLE\-INIT" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-init\fR \- Generates a Gemfile into the current working directory diff --git a/man/bundle-inject.1 b/man/bundle-inject.1 index 20bcbba735..9704eba89b 100644 --- a/man/bundle-inject.1 +++ b/man/bundle-inject.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INJECT" "1" "October 2020" "" "" +.TH "BUNDLE\-INJECT" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile diff --git a/man/bundle-install.1 b/man/bundle-install.1 index 0abd1a31e2..7c34f37cdd 100644 --- a/man/bundle-install.1 +++ b/man/bundle-install.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INSTALL" "1" "October 2020" "" "" +.TH "BUNDLE\-INSTALL" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-install\fR \- Install the dependencies specified in your Gemfile @@ -67,7 +67,7 @@ The maximum number of parallel download and install jobs\. The default is \fB1\f . .TP \fB\-\-local\fR -Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems\' cache or in \fBvendor/cache\fR\. Note that if a appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\. +Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems\' cache or in \fBvendor/cache\fR\. Note that if an appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\. . .TP \fB\-\-no\-cache\fR diff --git a/man/bundle-list.1 b/man/bundle-list.1 index ebedb62b38..d758e61a49 100644 --- a/man/bundle-list.1 +++ b/man/bundle-list.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LIST" "1" "October 2020" "" "" +.TH "BUNDLE\-LIST" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-list\fR \- List all the gems in the bundle diff --git a/man/bundle-lock.1 b/man/bundle-lock.1 index 350f1b3daa..a70043df00 100644 --- a/man/bundle-lock.1 +++ b/man/bundle-lock.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LOCK" "1" "October 2020" "" "" +.TH "BUNDLE\-LOCK" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-lock\fR \- Creates / Updates a lockfile without installing diff --git a/man/bundle-open.1 b/man/bundle-open.1 index 9986d5004c..631280c969 100644 --- a/man/bundle-open.1 +++ b/man/bundle-open.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OPEN" "1" "October 2020" "" "" +.TH "BUNDLE\-OPEN" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-open\fR \- Opens the source directory for a gem in your bundle diff --git a/man/bundle-outdated.1 b/man/bundle-outdated.1 index 3fc3cdc601..66cfe1a5f7 100644 --- a/man/bundle-outdated.1 +++ b/man/bundle-outdated.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OUTDATED" "1" "October 2020" "" "" +.TH "BUNDLE\-OUTDATED" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-outdated\fR \- List installed gems with newer versions available diff --git a/man/bundle-platform.1 b/man/bundle-platform.1 index b4c521e0c1..9fda7cb92c 100644 --- a/man/bundle-platform.1 +++ b/man/bundle-platform.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PLATFORM" "1" "October 2020" "" "" +.TH "BUNDLE\-PLATFORM" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-platform\fR \- Displays platform compatibility information diff --git a/man/bundle-pristine.1 b/man/bundle-pristine.1 index 0a1790655e..4561081746 100644 --- a/man/bundle-pristine.1 +++ b/man/bundle-pristine.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PRISTINE" "1" "October 2020" "" "" +.TH "BUNDLE\-PRISTINE" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-pristine\fR \- Restores installed gems to their pristine condition diff --git a/man/bundle-remove.1 b/man/bundle-remove.1 index ee24f676a6..b649f62673 100644 --- a/man/bundle-remove.1 +++ b/man/bundle-remove.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-REMOVE" "1" "October 2020" "" "" +.TH "BUNDLE\-REMOVE" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-remove\fR \- Removes gems from the Gemfile diff --git a/man/bundle-show.1 b/man/bundle-show.1 index f83c810ffe..1b0608f75a 100644 --- a/man/bundle-show.1 +++ b/man/bundle-show.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-SHOW" "1" "October 2020" "" "" +.TH "BUNDLE\-SHOW" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem diff --git a/man/bundle-update.1 b/man/bundle-update.1 index 002f2e69b9..f9922f6618 100644 --- a/man/bundle-update.1 +++ b/man/bundle-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-UPDATE" "1" "October 2020" "" "" +.TH "BUNDLE\-UPDATE" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-update\fR \- Update your gems to the latest available versions diff --git a/man/bundle-viz.1 b/man/bundle-viz.1 index cb2fcde537..2f68f644bf 100644 --- a/man/bundle-viz.1 +++ b/man/bundle-viz.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-VIZ" "1" "October 2020" "" "" +.TH "BUNDLE\-VIZ" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile diff --git a/man/bundle.1 b/man/bundle.1 index 86d0aec497..232752e914 100644 --- a/man/bundle.1 +++ b/man/bundle.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE" "1" "October 2020" "" "" +.TH "BUNDLE" "1" "November 2020" "" "" . .SH "NAME" \fBbundle\fR \- Ruby Dependency Management diff --git a/man/gemfile.5 b/man/gemfile.5 index 401487c688..f501db2b66 100644 --- a/man/gemfile.5 +++ b/man/gemfile.5 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "GEMFILE" "5" "October 2020" "" "" +.TH "GEMFILE" "5" "November 2020" "" "" . .SH "NAME" \fBGemfile\fR \- A format for describing gem dependencies for Ruby programs diff --git a/spec/bundler/bundler/cli_spec.rb b/spec/bundler/bundler/cli_spec.rb index 50e2a698eb..8e4f9e6d36 100644 --- a/spec/bundler/bundler/cli_spec.rb +++ b/spec/bundler/bundler/cli_spec.rb @@ -32,49 +32,49 @@ RSpec.describe "bundle executable" do it "aliases e to exec" do bundle "e --help" - expect(out).to include("BUNDLE-EXEC") + expect(out).to include("bundle-exec") end it "aliases ex to exec" do bundle "ex --help" - expect(out).to include("BUNDLE-EXEC") + expect(out).to include("bundle-exec") end it "aliases exe to exec" do bundle "exe --help" - expect(out).to include("BUNDLE-EXEC") + expect(out).to include("bundle-exec") end it "aliases c to check" do bundle "c --help" - expect(out).to include("BUNDLE-CHECK") + expect(out).to include("bundle-check") end it "aliases i to install" do bundle "i --help" - expect(out).to include("BUNDLE-INSTALL") + expect(out).to include("bundle-install") end it "aliases ls to list" do bundle "ls --help" - expect(out).to include("BUNDLE-LIST") + expect(out).to include("bundle-list") end it "aliases package to cache" do bundle "package --help" - expect(out).to include("BUNDLE-CACHE") + expect(out).to include("bundle-cache") end it "aliases pack to cache" do bundle "pack --help" - expect(out).to include("BUNDLE-CACHE") + expect(out).to include("bundle-cache") end end diff --git a/spec/bundler/bundler/compact_index_client/updater_spec.rb b/spec/bundler/bundler/compact_index_client/updater_spec.rb index 26159dccd8..acb312edb3 100644 --- a/spec/bundler/bundler/compact_index_client/updater_spec.rb +++ b/spec/bundler/bundler/compact_index_client/updater_spec.rb @@ -3,28 +3,25 @@ require "net/http" require "bundler/compact_index_client" require "bundler/compact_index_client/updater" +require "tmpdir" RSpec.describe Bundler::CompactIndexClient::Updater do let(:fetcher) { double(:fetcher) } - let(:local_path) { Pathname("/tmp/localpath") } + let(:local_path) { Pathname.new Dir.mktmpdir("localpath") } let(:remote_path) { double(:remote_path) } let!(:updater) { described_class.new(fetcher) } context "when the ETag header is missing" do # Regression test for https://github.com/rubygems/bundler/issues/5463 + let(:response) { double(:response, :body => "abc123") } - let(:response) { double(:response, :body => "") } + it "treats the response as an update" do + expect(response).to receive(:[]).with("Content-Encoding") { "" } + expect(response).to receive(:[]).with("ETag") { nil } + expect(fetcher).to receive(:call) { response } - it "MisMatchedChecksumError is raised" do - # Twice: #update retries on failure - expect(response).to receive(:[]).with("Content-Encoding").twice { "" } - expect(response).to receive(:[]).with("ETag").twice { nil } - expect(fetcher).to receive(:call).twice { response } - - expect do - updater.update(local_path, remote_path) - end.to raise_error(Bundler::CompactIndexClient::Updater::MisMatchedChecksumError) + updater.update(local_path, remote_path) end end @@ -43,7 +40,8 @@ RSpec.describe Bundler::CompactIndexClient::Updater do context "when bundler doesn't have permissions on Dir.tmpdir" do it "Errno::EACCES is raised" do - allow(Dir).to receive(:mktmpdir) { raise Errno::EACCES } + local_path # create local path before stubbing mktmpdir + allow(Bundler::Dir).to receive(:mktmpdir) { raise Errno::EACCES } expect do updater.update(local_path, remote_path) diff --git a/spec/bundler/bundler/env_spec.rb b/spec/bundler/bundler/env_spec.rb index e900963350..ac65c34b0d 100644 --- a/spec/bundler/bundler/env_spec.rb +++ b/spec/bundler/bundler/env_spec.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require "openssl" require "bundler/settings" RSpec.describe Bundler::Env do diff --git a/spec/bundler/bundler/fetcher/index_spec.rb b/spec/bundler/bundler/fetcher/index_spec.rb index 5ecd7d9e05..b8ce46321e 100644 --- a/spec/bundler/bundler/fetcher/index_spec.rb +++ b/spec/bundler/bundler/fetcher/index_spec.rb @@ -17,100 +17,81 @@ RSpec.describe Bundler::Fetcher::Index do end context "error handling" do - shared_examples_for "the error is properly handled" do - let(:remote_uri) { Bundler::URI("http://remote-uri.org") } + let(:remote_uri) { Bundler::URI("http://remote-uri.org") } + before do + allow(rubygems).to receive(:fetch_all_remote_specs) { raise Gem::RemoteFetcher::FetchError.new(error_message, display_uri) } + allow(subject).to receive(:remote_uri).and_return(remote_uri) + end + + context "when certificate verify failed" do + let(:error_message) { "certificate verify failed" } + + it "should raise a Bundler::Fetcher::CertificateFailureError" do + expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::CertificateFailureError, + %r{Could not verify the SSL certificate for http://sample_uri.com}) + end + end + + context "when a 401 response occurs" do + let(:error_message) { "401" } + before do - allow(subject).to receive(:remote_uri).and_return(remote_uri) + allow(remote_uri).to receive(:userinfo).and_return(userinfo) end - context "when certificate verify failed" do - let(:error_message) { "certificate verify failed" } + context "and there was userinfo" do + let(:userinfo) { double(:userinfo) } - it "should raise a Bundler::Fetcher::CertificateFailureError" do - expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::CertificateFailureError, - %r{Could not verify the SSL certificate for http://sample_uri.com}) + it "should raise a Bundler::Fetcher::BadAuthenticationError" do + expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::BadAuthenticationError, + %r{Bad username or password for http://remote-uri.org}) end end - context "when a 401 response occurs" do - let(:error_message) { "401" } + context "and there was no userinfo" do + let(:userinfo) { nil } - before do - allow(remote_uri).to receive(:userinfo).and_return(userinfo) - end - - context "and there was userinfo" do - let(:userinfo) { double(:userinfo) } - - it "should raise a Bundler::Fetcher::BadAuthenticationError" do - expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::BadAuthenticationError, - %r{Bad username or password for http://remote-uri.org}) - end - end - - context "and there was no userinfo" do - let(:userinfo) { nil } - - it "should raise a Bundler::Fetcher::AuthenticationRequiredError" do - expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::AuthenticationRequiredError, - %r{Authentication is required for http://remote-uri.org}) - end - end - end - - context "when a 403 response occurs" do - let(:error_message) { "403" } - - before do - allow(remote_uri).to receive(:userinfo).and_return(userinfo) - end - - context "and there was userinfo" do - let(:userinfo) { double(:userinfo) } - - it "should raise a Bundler::Fetcher::BadAuthenticationError" do - expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::BadAuthenticationError, - %r{Bad username or password for http://remote-uri.org}) - end - end - - context "and there was no userinfo" do - let(:userinfo) { nil } - - it "should raise a Bundler::Fetcher::AuthenticationRequiredError" do - expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::AuthenticationRequiredError, - %r{Authentication is required for http://remote-uri.org}) - end - end - end - - context "any other message is returned" do - let(:error_message) { "You get an error, you get an error!" } - - before { allow(Bundler).to receive(:ui).and_return(double(:trace => nil)) } - - it "should raise a Bundler::HTTPError" do - expect { subject.specs(gem_names) }.to raise_error(Bundler::HTTPError, "Could not fetch specs from http://sample_uri.com") + it "should raise a Bundler::Fetcher::AuthenticationRequiredError" do + expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::AuthenticationRequiredError, + %r{Authentication is required for http://remote-uri.org}) end end end - context "when a Gem::RemoteFetcher::FetchError occurs" do - before { allow(rubygems).to receive(:fetch_all_remote_specs) { raise Gem::RemoteFetcher::FetchError.new(error_message, nil) } } + context "when a 403 response occurs" do + let(:error_message) { "403" } - it_behaves_like "the error is properly handled" + before do + allow(remote_uri).to receive(:userinfo).and_return(userinfo) + end + + context "and there was userinfo" do + let(:userinfo) { double(:userinfo) } + + it "should raise a Bundler::Fetcher::BadAuthenticationError" do + expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::BadAuthenticationError, + %r{Bad username or password for http://remote-uri.org}) + end + end + + context "and there was no userinfo" do + let(:userinfo) { nil } + + it "should raise a Bundler::Fetcher::AuthenticationRequiredError" do + expect { subject.specs(gem_names) }.to raise_error(Bundler::Fetcher::AuthenticationRequiredError, + %r{Authentication is required for http://remote-uri.org}) + end + end end - context "when a OpenSSL::SSL::SSLError occurs" do - before { allow(rubygems).to receive(:fetch_all_remote_specs) { raise OpenSSL::SSL::SSLError.new(error_message) } } + context "any other message is returned" do + let(:error_message) { "You get an error, you get an error!" } - it_behaves_like "the error is properly handled" - end + before { allow(Bundler).to receive(:ui).and_return(double(:trace => nil)) } - context "when a Net::HTTPFatalError occurs" do - before { allow(rubygems).to receive(:fetch_all_remote_specs) { raise Net::HTTPFatalError.new(error_message, 404) } } - - it_behaves_like "the error is properly handled" + it "should raise a Bundler::HTTPError" do + expect { subject.specs(gem_names) }.to raise_error(Bundler::HTTPError, "Could not fetch specs from http://sample_uri.com due to underlying error ") + end end end end diff --git a/spec/bundler/bundler/plugin/api/source_spec.rb b/spec/bundler/bundler/plugin/api/source_spec.rb index 2c50ff56a4..428ceb220a 100644 --- a/spec/bundler/bundler/plugin/api/source_spec.rb +++ b/spec/bundler/bundler/plugin/api/source_spec.rb @@ -79,4 +79,10 @@ RSpec.describe Bundler::Plugin::API::Source do end end end + + describe "to_s" do + it "returns the string with type and uri" do + expect(source.to_s).to eq("plugin source for spec_type with uri uri://to/test") + end + end end diff --git a/spec/bundler/bundler/source/git/git_proxy_spec.rb b/spec/bundler/bundler/source/git/git_proxy_spec.rb index 169d7234b4..4744e0cd4c 100644 --- a/spec/bundler/bundler/source/git/git_proxy_spec.rb +++ b/spec/bundler/bundler/source/git/git_proxy_spec.rb @@ -2,7 +2,7 @@ RSpec.describe Bundler::Source::Git::GitProxy do let(:path) { Pathname("path") } - let(:uri) { "https://github.com/bundler/bundler.git" } + let(:uri) { "https://github.com/rubygems/rubygems.git" } let(:ref) { "HEAD" } let(:revision) { nil } let(:git_source) { nil } @@ -11,20 +11,20 @@ RSpec.describe Bundler::Source::Git::GitProxy do context "with configured credentials" do it "adds username and password to URI" do Bundler.settings.temporary(uri => "u:p") do - expect(subject).to receive(:git_retry).with(match("https://u:p@github.com/bundler/bundler.git")) + expect(subject).to receive(:git_retry).with(match("https://u:p@github.com/rubygems/rubygems.git")) subject.checkout end end it "adds username and password to URI for host" do Bundler.settings.temporary("github.com" => "u:p") do - expect(subject).to receive(:git_retry).with(match("https://u:p@github.com/bundler/bundler.git")) + expect(subject).to receive(:git_retry).with(match("https://u:p@github.com/rubygems/rubygems.git")) subject.checkout end end it "does not add username and password to mismatched URI" do - Bundler.settings.temporary("https://u:p@github.com/bundler/bundler-mismatch.git" => "u:p") do + Bundler.settings.temporary("https://u:p@github.com/rubygems/rubygems-mismatch.git" => "u:p") do expect(subject).to receive(:git_retry).with(match(uri)) subject.checkout end @@ -32,7 +32,7 @@ RSpec.describe Bundler::Source::Git::GitProxy do it "keeps original userinfo" do Bundler.settings.temporary("github.com" => "u:p") do - original = "https://orig:info@github.com/bundler/bundler.git" + original = "https://orig:info@github.com/rubygems/rubygems.git" subject = described_class.new(Pathname("path"), original, "HEAD") expect(subject).to receive(:git_retry).with(match(original)) subject.checkout diff --git a/spec/bundler/cache/gems_spec.rb b/spec/bundler/cache/gems_spec.rb index 2b5ba733f0..161ec64218 100644 --- a/spec/bundler/cache/gems_spec.rb +++ b/spec/bundler/cache/gems_spec.rb @@ -197,7 +197,12 @@ RSpec.describe "bundle cache" do end it "adds and removes when gems are updated" do - update_repo2 + update_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + end + bundle "update", :all => true expect(cached_gem("rack-1.2")).to exist expect(cached_gem("rack-1.0.0")).not_to exist diff --git a/spec/bundler/commands/binstubs_spec.rb b/spec/bundler/commands/binstubs_spec.rb index 632c521caa..3b177b32ea 100644 --- a/spec/bundler/commands/binstubs_spec.rb +++ b/spec/bundler/commands/binstubs_spec.rb @@ -51,6 +51,18 @@ RSpec.describe "bundle binstubs " do expect(bundled_app("bin/rake")).to exist end + it "allows installing binstubs for all platforms" do + install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem "rack" + G + + bundle "binstubs rack --all-platforms" + + expect(bundled_app("bin/rackup")).to exist + expect(bundled_app("bin/rackup.cmd")).to exist + end + it "displays an error when used without any gem" do install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" @@ -96,6 +108,10 @@ RSpec.describe "bundle binstubs " do before do pristine_system_gems "bundler-#{system_bundler_version}" build_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + build_gem "prints_loaded_gems", "1.0" do |s| s.executables = "print_loaded_gems" s.bindir = "exe" @@ -262,7 +278,7 @@ RSpec.describe "bundle binstubs " do end it "sets correct permissions for binstubs" do - skip "https://github.com/rubygems/bundler/issues/6895" if Gem.win_platform? + skip "https://github.com/rubygems/rubygems/issues/3352" if Gem.win_platform? with_umask(0o002) do install_gemfile <<-G @@ -352,6 +368,14 @@ RSpec.describe "bundle binstubs " do expect(bundled_app("foo/rackup")).to exist end end + + context "when specified --all-platforms option" do + it "generates standalone binstubs for all platforms" do + bundle "binstubs rack --standalone --all-platforms" + expect(bundled_app("bin/rackup")).to exist + expect(bundled_app("bin/rackup.cmd")).to exist + end + end end context "when the bin already exists" do @@ -417,8 +441,14 @@ RSpec.describe "bundle binstubs " do end it "works if the gem has development dependencies" do + build_repo2 do + build_gem "with_development_dependency" do |s| + s.add_development_dependency "activesupport", "= 2.3.5" + end + end + install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "with_development_dependency" G diff --git a/spec/bundler/commands/check_spec.rb b/spec/bundler/commands/check_spec.rb index dd69172677..5a746591b3 100644 --- a/spec/bundler/commands/check_spec.rb +++ b/spec/bundler/commands/check_spec.rb @@ -71,13 +71,19 @@ RSpec.describe "bundle check" do end it "prints a generic message if you changed your lockfile" do + build_repo2 do + build_gem "rails_pinned_to_old_activesupport" do |s| + s.add_dependency "activesupport", "= 1.2.3" + end + end + install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem 'rails' G gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "rails" gem "rails_pinned_to_old_activesupport" G diff --git a/spec/bundler/commands/clean_spec.rb b/spec/bundler/commands/clean_spec.rb index bd8e7f16c7..7c43aaabc4 100644 --- a/spec/bundler/commands/clean_spec.rb +++ b/spec/bundler/commands/clean_spec.rb @@ -603,8 +603,7 @@ RSpec.describe "bundle clean" do it "when using --force on system gems, it doesn't remove binaries" do bundle "config set path.system true" - build_repo2 - update_repo2 do + build_repo2 do build_gem "bindir" do |s| s.bindir = "exe" s.executables = "foo" @@ -640,7 +639,7 @@ RSpec.describe "bundle clean" do end end - realworld_system_gems "fiddle" + realworld_system_gems "fiddle --version 1.0.0" install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" diff --git a/spec/bundler/commands/console_spec.rb b/spec/bundler/commands/console_spec.rb index 3092184f45..6f1e96261e 100644 --- a/spec/bundler/commands/console_spec.rb +++ b/spec/bundler/commands/console_spec.rb @@ -2,8 +2,43 @@ RSpec.describe "bundle console", :bundler => "< 3", :readline => true do before :each do + build_repo2 do + # A minimal fake pry console + build_gem "pry" do |s| + s.write "lib/pry.rb", <<-RUBY + class Pry + class << self + def toplevel_binding + unless defined?(@toplevel_binding) && @toplevel_binding + TOPLEVEL_BINDING.eval %{ + def self.__pry__; binding; end + Pry.instance_variable_set(:@toplevel_binding, __pry__) + class << self; undef __pry__; end + } + end + @toplevel_binding.eval('private') + @toplevel_binding + end + + def __pry__ + while line = gets + begin + puts eval(line, toplevel_binding).inspect.sub(/^"(.*)"$/, '=> \\1') + rescue Exception => e + puts "\#{e.class}: \#{e.message}" + puts e.backtrace.first + end + end + end + alias start __pry__ + end + end + RUBY + end + end + install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "rack" gem "activesupport", :group => :test gem "rack_middleware", :group => :development @@ -28,7 +63,7 @@ RSpec.describe "bundle console", :bundler => "< 3", :readline => true do it "starts another REPL if configured as such" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "pry" G bundle "config set console pry" @@ -87,7 +122,7 @@ RSpec.describe "bundle console", :bundler => "< 3", :readline => true do it "performs an automatic bundle install" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "rack" gem "activesupport", :group => :test gem "rack_middleware", :group => :development diff --git a/spec/bundler/commands/exec_spec.rb b/spec/bundler/commands/exec_spec.rb index fbce4b7bc1..4c34964053 100644 --- a/spec/bundler/commands/exec_spec.rb +++ b/spec/bundler/commands/exec_spec.rb @@ -68,7 +68,7 @@ RSpec.describe "bundle exec" do end it "respects custom process title when loading through ruby" do - skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform? + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? script_that_changes_its_own_title_and_checks_if_picked_up_by_ps_unix_utility = <<~'RUBY' Process.setproctitle("1-2-3-4-5-6-7") @@ -93,7 +93,7 @@ RSpec.describe "bundle exec" do end it "handles --keep-file-descriptors" do - skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform? + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? require "tempfile" @@ -126,7 +126,7 @@ RSpec.describe "bundle exec" do end it "can run a command named --verbose" do - skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform? + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? install_gemfile 'gem "rack"' File.open(bundled_app("--verbose"), "w") do |f| @@ -286,7 +286,7 @@ RSpec.describe "bundle exec" do end it "does not duplicate already exec'ed RUBYOPT" do - skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform? + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? install_gemfile <<-G gem "rack" @@ -304,7 +304,7 @@ RSpec.describe "bundle exec" do end it "does not duplicate already exec'ed RUBYLIB" do - skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform? + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? install_gemfile <<-G gem "rack" @@ -357,7 +357,7 @@ RSpec.describe "bundle exec" do bundle "config set clean false" # want to keep the rackup binstub install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "with_license" + gem "foo" G [true, false].each do |l| bundle "config set disable_exec_load #{l}" @@ -373,7 +373,7 @@ RSpec.describe "bundle exec" do each_prefix.call("exec") do |exec| describe "when #{exec} is used" do before(:each) do - skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform? + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? install_gemfile <<-G gem "rack" @@ -588,7 +588,7 @@ RSpec.describe "bundle exec" do describe "with gems bundled for deployment" do it "works when calling bundler from another script" do - skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform? + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? gemfile <<-G module Monkey @@ -644,7 +644,7 @@ RSpec.describe "bundle exec" do shared_examples_for "it runs" do it "like a normally executed executable" do - skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform? + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? subject expect(exitstatus).to eq(exit_code) @@ -698,15 +698,23 @@ RSpec.describe "bundle exec" do let(:exit_code) { 1 } let(:expected_err) do "bundler: failed to load command: #{path} (#{path})" \ - "\nRuntimeError: ERROR\n #{path}:10:in `'" + "\n#{path}:10:in `': ERROR (RuntimeError)" + end + + it "runs like a normally executed executable" do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + + subject + expect(exitstatus).to eq(exit_code) + expect(err).to start_with(expected_err) + expect(out).to eq(expected) end - it_behaves_like "it runs" end context "the executable raises an error without a backtrace" do let(:executable) { super() << "\nclass Err < Exception\ndef backtrace; end;\nend\nraise Err" } let(:exit_code) { 1 } - let(:expected_err) { "bundler: failed to load command: #{path} (#{path})\nErr: Err" } + let(:expected_err) { "bundler: failed to load command: #{path} (#{path})\n#{system_gem_path("bin/bundle")}: Err (Err)" } let(:expected) { super() } it_behaves_like "it runs" @@ -747,7 +755,7 @@ RSpec.describe "bundle exec" do let(:expected) { "" } let(:expected_err) { <<-EOS.strip } \e[31mCould not find gem 'rack (= 2)' in locally installed gems. -The source contains 'rack' at: 1.0.0\e[0m +The source contains the following versions of 'rack': 1.0.0\e[0m \e[33mRun `bundle install` to install missing gems.\e[0m EOS @@ -825,7 +833,7 @@ __FILE__: #{path.to_s.inspect} RUBY it "receives the signal" do - skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform? + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? bundle("exec #{path}") do |_, o, thr| o.gets # Consumes 'Started' and ensures that thread has started @@ -848,7 +856,7 @@ __FILE__: #{path.to_s.inspect} RUBY it "makes sure no unexpected signals are restored to DEFAULT" do - skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform? + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? test_signals.each do |n| Signal.trap(n, "IGNORE") @@ -865,6 +873,8 @@ __FILE__: #{path.to_s.inspect} context "nested bundle exec" do context "when bundle in a local path" do before do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + gemfile <<-G source "#{file_uri_for(gem_repo1)}" gem "rack" @@ -874,8 +884,6 @@ __FILE__: #{path.to_s.inspect} end it "correctly shells out" do - skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform? - file = bundled_app("file_that_bundle_execs.rb") create_file(file, <<-RUBY) #!#{Gem.ruby} @@ -887,12 +895,55 @@ __FILE__: #{path.to_s.inspect} end end + context "when Kernel.require uses extra monkeypatches" do + before do + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? + + install_gemfile "" + end + + it "does not undo the monkeypatches" do + karafka = bundled_app("bin/karafka") + create_file(karafka, <<~RUBY) + #!#{Gem.ruby} + + module Kernel + module_function + + alias_method :require_before_extra_monkeypatches, :require + + def require(path) + puts "requiring \#{path} used the monkeypatch" + + require_before_extra_monkeypatches(path) + end + end + + Bundler.setup(:default) + + require "foo" + RUBY + karafka.chmod(0o777) + + foreman = bundled_app("bin/foreman") + create_file(foreman, <<~RUBY) + #!#{Gem.ruby} + + puts `bundle exec bin/karafka` + RUBY + foreman.chmod(0o777) + + bundle "exec #{foreman}" + expect(out).to eq("requiring foo used the monkeypatch") + end + end + context "with a system gem that shadows a default gem" do let(:openssl_version) { "99.9.9" } let(:expected) { ruby "gem 'openssl', '< 999999'; require 'openssl'; puts OpenSSL::VERSION", :artifice => nil, :raise_on_error => false } it "only leaves the default gem in the stdlib available" do - skip "https://github.com/rubygems/bundler/issues/6898" if Gem.win_platform? + skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform? skip "openssl isn't a default gem" if expected.empty? install_gemfile "" # must happen before installing the broken system gem diff --git a/spec/bundler/commands/fund_spec.rb b/spec/bundler/commands/fund_spec.rb index ee3aff3a29..5a0c5411da 100644 --- a/spec/bundler/commands/fund_spec.rb +++ b/spec/bundler/commands/fund_spec.rb @@ -1,24 +1,51 @@ # frozen_string_literal: true RSpec.describe "bundle fund" do + before do + build_repo2 do + build_gem "has_funding_and_other_metadata" do |s| + s.metadata = { + "bug_tracker_uri" => "https://example.com/user/bestgemever/issues", + "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md", + "documentation_uri" => "https://www.example.info/gems/bestgemever/0.0.1", + "homepage_uri" => "https://bestgemever.example.io", + "mailing_list_uri" => "https://groups.example.com/bestgemever", + "funding_uri" => "https://example.com/has_funding_and_other_metadata/funding", + "source_code_uri" => "https://example.com/user/bestgemever", + "wiki_uri" => "https://example.com/user/bestgemever/wiki", + } + end + + build_gem "has_funding", "1.2.3" do |s| + s.metadata = { + "funding_uri" => "https://example.com/has_funding/funding", + } + end + + build_gem "gem_with_dependent_funding", "1.0" do |s| + s.add_dependency "has_funding" + end + end + end + it "prints fund information for all gems in the bundle" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem 'has_metadata' + source "#{file_uri_for(gem_repo2)}" + gem 'has_funding_and_other_metadata' gem 'has_funding' gem 'rack-obama' G bundle "fund" - expect(out).to include("* has_metadata (1.0)\n Funding: https://example.com/has_metadata/funding") + expect(out).to include("* has_funding_and_other_metadata (1.0)\n Funding: https://example.com/has_funding_and_other_metadata/funding") expect(out).to include("* has_funding (1.2.3)\n Funding: https://example.com/has_funding/funding") expect(out).to_not include("rack-obama") end it "does not consider fund information for gem dependencies" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem 'gem_with_dependent_funding' G @@ -30,7 +57,7 @@ RSpec.describe "bundle fund" do it "prints message if none of the gems have fund information" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem 'rack-obama' G @@ -42,13 +69,13 @@ RSpec.describe "bundle fund" do describe "with --group option" do it "prints fund message for only specified group gems" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem 'has_metadata', :group => :development + source "#{file_uri_for(gem_repo2)}" + gem 'has_funding_and_other_metadata', :group => :development gem 'has_funding' G bundle "fund --group development" - expect(out).to include("* has_metadata (1.0)\n Funding: https://example.com/has_metadata/funding") + expect(out).to include("* has_funding_and_other_metadata (1.0)\n Funding: https://example.com/has_funding_and_other_metadata/funding") expect(out).to_not include("* has_funding (1.2.3)\n Funding: https://example.com/has_funding/funding") end end diff --git a/spec/bundler/commands/info_spec.rb b/spec/bundler/commands/info_spec.rb index eec9c773bc..6bc07ea399 100644 --- a/spec/bundler/commands/info_spec.rb +++ b/spec/bundler/commands/info_spec.rb @@ -3,8 +3,22 @@ RSpec.describe "bundle info" do context "with a standard Gemfile" do before do + build_repo2 do + build_gem "has_metadata" do |s| + s.metadata = { + "bug_tracker_uri" => "https://example.com/user/bestgemever/issues", + "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md", + "documentation_uri" => "https://www.example.info/gems/bestgemever/0.0.1", + "homepage_uri" => "https://bestgemever.example.io", + "mailing_list_uri" => "https://groups.example.com/bestgemever", + "source_code_uri" => "https://example.com/user/bestgemever", + "wiki_uri" => "https://example.com/user/bestgemever/wiki", + } + end + end + install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "rails" gem "has_metadata" G @@ -66,7 +80,6 @@ RSpec.describe "bundle info" do \tHomepage: http://example.com \tDocumentation: https://www.example.info/gems/bestgemever/0.0.1 \tSource Code: https://example.com/user/bestgemever -\tFunding: https://example.com/has_metadata/funding \tWiki: https://example.com/user/bestgemever/wiki \tChangelog: https://example.com/user/bestgemever/CHANGELOG.md \tBug Tracker: https://example.com/user/bestgemever/issues diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb index d1b8585114..a8b174a547 100644 --- a/spec/bundler/commands/install_spec.rb +++ b/spec/bundler/commands/install_spec.rb @@ -141,8 +141,14 @@ RSpec.describe "bundle install with gem sources" do end it "does not install the development dependency" do + build_repo2 do + build_gem "with_development_dependency" do |s| + s.add_development_dependency "activesupport", "= 2.3.5" + end + end + install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "with_development_dependency" G @@ -216,6 +222,18 @@ RSpec.describe "bundle install with gem sources" do expect(the_bundle).to include_gems "rack 1.0.0", "activesupport 2.3.5" end + it "loads env plugins" do + plugin_msg = "hello from an env plugin!" + create_file "plugins/rubygems_plugin.rb", "puts '#{plugin_msg}'" + rubylib = ENV["RUBYLIB"].to_s.split(File::PATH_SEPARATOR).unshift(bundled_app("plugins").to_s).join(File::PATH_SEPARATOR) + install_gemfile <<-G, :env => { "RUBYLIB" => rubylib } + source "#{file_uri_for(gem_repo1)}" + gem "rack" + G + + expect(last_command.stdboth).to include(plugin_msg) + end + describe "with a gem that installs multiple platforms" do it "installs gems for the local platform as first choice" do skip "version is 1.0, not 1.0.0" if Gem.win_platform? @@ -294,8 +312,11 @@ RSpec.describe "bundle install with gem sources" do end it "finds gems in multiple sources", :bundler => "< 3" do - build_repo2 - update_repo2 + build_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + end install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" diff --git a/spec/bundler/commands/licenses_spec.rb b/spec/bundler/commands/licenses_spec.rb index d4fa02d0a7..a203984890 100644 --- a/spec/bundler/commands/licenses_spec.rb +++ b/spec/bundler/commands/licenses_spec.rb @@ -2,8 +2,14 @@ RSpec.describe "bundle licenses" do before :each do + build_repo2 do + build_gem "with_license" do |s| + s.license = "MIT" + end + end + install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "rails" gem "with_license" G @@ -18,7 +24,7 @@ RSpec.describe "bundle licenses" do it "performs an automatic bundle install" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "rails" gem "with_license" gem "foo" diff --git a/spec/bundler/commands/list_spec.rb b/spec/bundler/commands/list_spec.rb index ed3edad163..66930ded75 100644 --- a/spec/bundler/commands/list_spec.rb +++ b/spec/bundler/commands/list_spec.rb @@ -117,6 +117,10 @@ RSpec.describe "bundle list" do context "with paths option" do before do build_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + build_gem "bar" end diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb index c97358c62d..cc56c34952 100644 --- a/spec/bundler/commands/lock_spec.rb +++ b/spec/bundler/commands/lock_spec.rb @@ -15,7 +15,7 @@ RSpec.describe "bundle lock" do gemfile <<-G source "#{file_uri_for(repo)}" gem "rails" - gem "with_license" + gem "weakling" gem "foo" G @@ -40,7 +40,7 @@ RSpec.describe "bundle lock" do activeresource (= 2.3.2) rake (= 13.0.1) rake (13.0.1) - with_license (1.0) + weakling (0.0.3) PLATFORMS #{lockfile_platforms} @@ -48,7 +48,7 @@ RSpec.describe "bundle lock" do DEPENDENCIES foo rails - with_license + weakling BUNDLED WITH #{Bundler::VERSION} diff --git a/spec/bundler/commands/newgem_spec.rb b/spec/bundler/commands/newgem_spec.rb index beee2b0fdc..421ffa80c6 100644 --- a/spec/bundler/commands/newgem_spec.rb +++ b/spec/bundler/commands/newgem_spec.rb @@ -14,6 +14,7 @@ RSpec.describe "bundle gem" do prepare_gemspec(bundled_app(gem_name, "#{gem_name}.gemspec")) rubocop_version = RUBY_VERSION > "2.4" ? "0.90.0" : "0.80.1" gems = ["minitest", "rake", "rake-compiler", "rspec", "rubocop -v #{rubocop_version}", "test-unit"] + gems.unshift "parallel -v 1.19.2" if RUBY_VERSION < "2.5" gems += ["rubocop-ast -v 0.4.0"] if rubocop_version == "0.90.0" path = Bundler.feature_flag.default_install_uses_path? ? local_gem_path(:base => bundled_app(gem_name)) : system_gem_path realworld_system_gems gems, :path => path @@ -423,7 +424,7 @@ RSpec.describe "bundle gem" do it "requires the version file" do bundle "gem #{gem_name}" - expect(bundled_app("#{gem_name}/lib/#{require_path}.rb").read).to match(%r{require "#{require_path}/version"}) + expect(bundled_app("#{gem_name}/lib/#{require_path}.rb").read).to match(%r{require_relative "#{require_relative_path}/version"}) end it "creates a base error class" do @@ -910,6 +911,8 @@ RSpec.describe "bundle gem" do let(:require_path) { "test_gem" } + let(:require_relative_path) { "test_gem" } + let(:flags) { nil } it "does not nest constants" do @@ -963,6 +966,8 @@ RSpec.describe "bundle gem" do let(:require_path) { "test/gem" } + let(:require_relative_path) { "gem" } + it "nests constants so they work" do bundle "gem #{gem_name}" expect(bundled_app("#{gem_name}/lib/#{require_path}/version.rb").read).to match(/module Test\n module Gem/) diff --git a/spec/bundler/commands/remove_spec.rb b/spec/bundler/commands/remove_spec.rb index bee4490a8d..46c42fea10 100644 --- a/spec/bundler/commands/remove_spec.rb +++ b/spec/bundler/commands/remove_spec.rb @@ -83,7 +83,7 @@ RSpec.describe "bundle remove" do end end - describe "remove mutiple gems from gemfile" do + describe "remove multiple gems from gemfile" do context "when all gems are present in gemfile" do it "shows success fir all removed gems" do gemfile <<-G @@ -210,7 +210,7 @@ RSpec.describe "bundle remove" do end end - context "when the gem belongs to mutiple groups" do + context "when the gem belongs to multiple groups" do it "removes the groups" do gemfile <<-G source "#{file_uri_for(gem_repo1)}" @@ -616,4 +616,84 @@ RSpec.describe "bundle remove" do expect(out).to include("foo could not be removed.") end end + + describe "with comments that mention gems" do + context "when comment is a separate line comment" do + it "does not remove the line comment" do + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + + # gem "rack" might be used in the future + gem "rack" + G + + bundle "remove rack" + + expect(out).to include("rack was removed.") + gemfile_should_be <<-G + source "#{file_uri_for(gem_repo1)}" + + # gem "rack" might be used in the future + G + end + end + + context "when gem specified for removal has an inline comment" do + it "removes the inline comment" do + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + + gem "rack" # this can be removed + G + + bundle "remove rack" + + expect(out).to include("rack was removed.") + gemfile_should_be <<-G + source "#{file_uri_for(gem_repo1)}" + G + end + end + + context "when gem specified for removal is mentioned in other gem's comment" do + it "does not remove other gem" do + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem "puma" # implements interface provided by gem "rack" + + gem "rack" + G + + bundle "remove rack" + + expect(out).to_not include("puma was removed.") + expect(out).to include("rack was removed.") + gemfile_should_be <<-G + source "#{file_uri_for(gem_repo1)}" + gem "puma" # implements interface provided by gem "rack" + G + end + end + + context "when gem specified for removal has a comment that mentions other gem" do + it "does not remove other gem" do + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem "puma" # implements interface provided by gem "rack" + + gem "rack" + G + + bundle "remove puma" + + expect(out).to include("puma was removed.") + expect(out).to_not include("rack was removed.") + gemfile_should_be <<-G + source "#{file_uri_for(gem_repo1)}" + + gem "rack" + G + end + end + end end diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb index 5ab932e5d7..b8de6507f6 100644 --- a/spec/bundler/commands/update_spec.rb +++ b/spec/bundler/commands/update_spec.rb @@ -15,6 +15,10 @@ RSpec.describe "bundle update" do describe "with no arguments", :bundler => "< 3" do it "updates the entire bundle" do update_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + build_gem "activesupport", "3.0" end @@ -38,6 +42,10 @@ RSpec.describe "bundle update" do describe "with --all", :bundler => "3" do it "updates the entire bundle" do update_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + build_gem "activesupport", "3.0" end @@ -103,6 +111,10 @@ RSpec.describe "bundle update" do describe "with a top level dependency" do it "unlocks all child dependencies that are unrelated to other locked dependencies" do update_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + build_gem "activesupport", "3.0" end @@ -124,7 +136,12 @@ RSpec.describe "bundle update" do describe "with a child dependency" do it "should update the child dependency" do - update_repo2 + update_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + end + bundle "update rack" expect(the_bundle).to include_gems "rack 1.2" end @@ -217,6 +234,10 @@ RSpec.describe "bundle update" do gem "rack" G update_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + build_gem "activesupport", "3.0" end bundle "update --group development" @@ -269,6 +290,10 @@ RSpec.describe "bundle update" do gem "rack" G update_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + build_gem "activesupport", "3.0" end bundle "update --group development" @@ -446,6 +471,10 @@ RSpec.describe "bundle update in more complicated situations" do G update_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + build_gem "thin", "2.0" do |s| s.add_dependency "rack" end diff --git a/spec/bundler/install/bundler_spec.rb b/spec/bundler/install/bundler_spec.rb index e5352ab6a2..af1ff7225a 100644 --- a/spec/bundler/install/bundler_spec.rb +++ b/spec/bundler/install/bundler_spec.rb @@ -54,6 +54,12 @@ RSpec.describe "bundle install" do end it "works for gems with multiple versions in its dependencies" do + build_repo2 do + build_gem "multiple_versioned_deps" do |s| + s.add_dependency "weakling", ">= 0.0.1", "< 0.1" + end + end + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" @@ -93,6 +99,12 @@ RSpec.describe "bundle install" do it "causes a conflict if child dependencies conflict" do bundle "config set force_ruby_platform true" + update_repo2 do + build_gem "rails_pinned_to_old_activesupport" do |s| + s.add_dependency "activesupport", "= 1.2.3" + end + end + install_gemfile <<-G, :raise_on_error => false source "#{file_uri_for(gem_repo2)}" gem "activemerchant" @@ -114,6 +126,12 @@ RSpec.describe "bundle install" do it "causes a conflict if a child dependency conflicts with the Gemfile" do bundle "config set force_ruby_platform true" + update_repo2 do + build_gem "rails_pinned_to_old_activesupport" do |s| + s.add_dependency "activesupport", "= 1.2.3" + end + end + install_gemfile <<-G, :raise_on_error => false source "#{file_uri_for(gem_repo2)}" gem "rails_pinned_to_old_activesupport" @@ -132,6 +150,12 @@ RSpec.describe "bundle install" do end it "does not cause a conflict if new dependencies in the Gemfile require older dependencies than the lockfile" do + update_repo2 do + build_gem "rails_pinned_to_old_activesupport" do |s| + s.add_dependency "activesupport", "= 1.2.3" + end + end + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" gem 'rails', "2.3.2" diff --git a/spec/bundler/install/deploy_spec.rb b/spec/bundler/install/deploy_spec.rb index 441daabe72..357f4512f1 100644 --- a/spec/bundler/install/deploy_spec.rb +++ b/spec/bundler/install/deploy_spec.rb @@ -361,10 +361,7 @@ RSpec.describe "install in deployment or frozen mode" do bundle "config --local deployment true" bundle :install, :raise_on_error => false expect(err).to include("deployment mode") - # The drive letter of the Windows environment is fragile value in GitHub Actions - unless Gem.win_platform? - expect(err).to include("You have deleted from the Gemfile:\n* source: #{lib_path("rack-1.0")} (at master@#{revision_for(lib_path("rack-1.0"))[0..6]}") - end + expect(err).to include("You have deleted from the Gemfile:\n* source: #{lib_path("rack-1.0")} (at master@#{revision_for(lib_path("rack-1.0"))[0..6]}") expect(err).not_to include("You have added to the Gemfile") expect(err).not_to include("You have changed in the Gemfile") end @@ -388,10 +385,7 @@ RSpec.describe "install in deployment or frozen mode" do bundle "config --local deployment true" bundle :install, :raise_on_error => false expect(err).to include("deployment mode") - # The drive letter of the Windows environment is fragile value in GitHub Actions - unless Gem.win_platform? - expect(err).to include("You have changed in the Gemfile:\n* rack from `no specified source` to `#{lib_path("rack")} (at master@#{revision_for(lib_path("rack"))[0..6]})`") - end + expect(err).to include("You have changed in the Gemfile:\n* rack from `no specified source` to `#{lib_path("rack")} (at master@#{revision_for(lib_path("rack"))[0..6]})`") expect(err).not_to include("You have added to the Gemfile") expect(err).not_to include("You have deleted from the Gemfile") end diff --git a/spec/bundler/install/gemfile/gemspec_spec.rb b/spec/bundler/install/gemfile/gemspec_spec.rb index 8e13ac05a9..7a95a8abde 100644 --- a/spec/bundler/install/gemfile/gemspec_spec.rb +++ b/spec/bundler/install/gemfile/gemspec_spec.rb @@ -422,8 +422,6 @@ RSpec.describe "bundle install from an existing gemspec" do end end - bundle "config specific_platform false" - %w[ruby jruby].each do |platform| simulate_platform(platform) do install_gemfile <<-G diff --git a/spec/bundler/install/gemfile/git_spec.rb b/spec/bundler/install/gemfile/git_spec.rb index a70fb18c45..7850fad8d0 100644 --- a/spec/bundler/install/gemfile/git_spec.rb +++ b/spec/bundler/install/gemfile/git_spec.rb @@ -30,11 +30,15 @@ RSpec.describe "bundle install with git sources" do expect(Dir["#{default_bundle_path}/cache/bundler/git/foo-1.0-*"]).to have_attributes :size => 1 end - it "caches the git repo globally" do + it "caches the git repo globally and properly uses the cached repo on the next invocation" do simulate_new_machine bundle "config set global_gem_cache true" bundle :install expect(Dir["#{home}/.bundle/cache/git/foo-1.0-*"]).to have_attributes :size => 1 + + bundle "install --verbose" + expect(err).to be_empty + expect(out).to include("Using foo 1.0 from #{lib_path("foo")}") end it "caches the evaluated gemspec" do @@ -83,7 +87,7 @@ RSpec.describe "bundle install with git sources" do gem "foo", "1.1", :git => "#{lib_path("foo-1.0")}" G - expect(err).to include("The source contains 'foo' at: 1.0") + expect(err).to include("The source contains the following versions of 'foo': 1.0") end it "complains with version and platform if pinned specs don't exist in the git repo" do @@ -99,7 +103,7 @@ RSpec.describe "bundle install with git sources" do end G - expect(err).to include("The source contains 'only_java' at: 1.0 java") + expect(err).to include("The source contains the following versions of 'only_java': 1.0 java") end it "complains with multiple versions and platforms if pinned specs don't exist in the git repo" do @@ -120,7 +124,7 @@ RSpec.describe "bundle install with git sources" do end G - expect(err).to include("The source contains 'only_java' at: 1.0 java, 1.1 java") + expect(err).to include("The source contains the following versions of 'only_java': 1.0 java, 1.1 java") end it "still works after moving the application directory" do @@ -933,8 +937,6 @@ RSpec.describe "bundle install with git sources" do end it "prints a friendly error if a file blocks the git repo" do - skip "drive letter is not detected correctly in error message" if Gem.win_platform? - build_git "foo" FileUtils.mkdir_p(default_bundle_path) diff --git a/spec/bundler/install/gemfile/path_spec.rb b/spec/bundler/install/gemfile/path_spec.rb index 07722d09dd..f19fe39721 100644 --- a/spec/bundler/install/gemfile/path_spec.rb +++ b/spec/bundler/install/gemfile/path_spec.rb @@ -718,11 +718,11 @@ RSpec.describe "bundle install with explicit source paths" do expect(bar_file).not_to be_file build_lib "foo" do |s| - s.write("lib/rubygems_plugin.rb", "FileUtils.touch('#{foo_file}')") + s.write("lib/rubygems_plugin.rb", "require 'fileutils'; FileUtils.touch('#{foo_file}')") end build_git "bar" do |s| - s.write("lib/rubygems_plugin.rb", "FileUtils.touch('#{bar_file}')") + s.write("lib/rubygems_plugin.rb", "require 'fileutils'; FileUtils.touch('#{bar_file}')") end install_gemfile <<-G diff --git a/spec/bundler/install/gemfile/platform_spec.rb b/spec/bundler/install/gemfile/platform_spec.rb index 41b95481cb..46fc393fe9 100644 --- a/spec/bundler/install/gemfile/platform_spec.rb +++ b/spec/bundler/install/gemfile/platform_spec.rb @@ -255,32 +255,6 @@ RSpec.describe "bundle install across platforms" do expect(the_bundle).to include_gems "nokogiri 1.4.2 JAVA", "weakling 0.0.3" end - it "works with gems that have extra platform-specific runtime dependencies", :bundler => "< 3" do - simulate_platform x64_mac - - update_repo2 do - build_gem "facter", "2.4.6" - build_gem "facter", "2.4.6" do |s| - s.platform = "universal-darwin" - s.add_runtime_dependency "CFPropertyList" - end - build_gem "CFPropertyList" - end - - install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - - gem "facter" - G - - expect(err).to include "Unable to use the platform-specific (universal-darwin) version of facter (2.4.6) " \ - "because it has different dependencies from the ruby version. " \ - "To use the platform-specific version of the gem, run `bundle config set --local specific_platform true` and install again." - - expect(the_bundle).to include_gem "facter 2.4.6" - expect(the_bundle).not_to include_gem "CFPropertyList" - end - it "works with gems with platform-specific dependency having different requirements order" do simulate_platform x64_mac @@ -430,7 +404,7 @@ RSpec.describe "bundle install with platform conditionals" do expect(out).not_to match(/Could not find gem 'some_gem/) end - it "resolves all platforms by default and without warning messages" do + it "does not print a warning when a dependency is unused on a platform different from the current one" do simulate_platform "ruby" gemfile <<-G @@ -447,14 +421,9 @@ RSpec.describe "bundle install with platform conditionals" do GEM remote: #{file_uri_for(gem_repo1)}/ specs: - rack (1.0.0) PLATFORMS - java ruby - x64-mingw32 - x86-mingw32 - x86-mswin32 DEPENDENCIES rack @@ -469,13 +438,21 @@ RSpec.describe "when a gem has no architecture" do it "still installs correctly" do simulate_platform mswin + build_repo2 do + # The rcov gem is platform mswin32, but has no arch + build_gem "rcov" do |s| + s.platform = Gem::Platform.new([nil, "mswin32", nil]) + s.write "lib/rcov.rb", "RCOV = '1.0.0'" + end + end + gemfile <<-G # Try to install gem with nil arch source "http://localgemserver.test/" gem "rcov" G - bundle :install, :artifice => "windows" + bundle :install, :artifice => "windows", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } expect(the_bundle).to include_gems "rcov 1.0.0" end end diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index be41857043..655f91dd69 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -597,6 +597,10 @@ RSpec.describe "bundle install with gems on multiple sources" do G build_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + build_gem "bar" end diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb index 959ffbf615..82492e78cb 100644 --- a/spec/bundler/install/gemfile/specific_platform_spec.rb +++ b/spec/bundler/install/gemfile/specific_platform_spec.rb @@ -1,9 +1,134 @@ # frozen_string_literal: true -RSpec.describe "bundle install with specific_platform enabled" do - before do - bundle "config set specific_platform true" +RSpec.describe "bundle install with specific platforms" do + let(:google_protobuf) { <<-G } + source "#{file_uri_for(gem_repo2)}" + gem "google-protobuf" + G + context "when on a darwin machine" do + before { simulate_platform "x86_64-darwin-15" } + + it "locks to both the specific darwin platform and ruby" do + setup_multiplatform_gem + install_gemfile(google_protobuf) + allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) + expect(the_bundle.locked_gems.platforms).to eq([pl("ruby"), pl("x86_64-darwin-15")]) + expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin") + expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[ + google-protobuf-3.0.0.alpha.5.0.5.1 + google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin + ]) + end + + it "caches both the universal-darwin and ruby gems when --all-platforms is passed and properly picks them up on further bundler invocations" do + setup_multiplatform_gem + gemfile(google_protobuf) + bundle "cache --all-platforms" + expect([cached_gem("google-protobuf-3.0.0.alpha.5.0.5.1"), cached_gem("google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin")]). + to all(exist) + + bundle "install --verbose" + expect(err).to be_empty + end + + it "caches both the universal-darwin and ruby gems when cache_all_platforms is configured and properly picks them up on further bundler invocations" do + setup_multiplatform_gem + gemfile(google_protobuf) + bundle "config set --local cache_all_platforms true" + bundle "cache" + expect([cached_gem("google-protobuf-3.0.0.alpha.5.0.5.1"), cached_gem("google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin")]). + to all(exist) + + bundle "install --verbose" + expect(err).to be_empty + end + + it "caches multiplatform git gems with a single gemspec when --all-platforms is passed" do + git = build_git "pg_array_parser", "1.0" + + gemfile <<-G + gem "pg_array_parser", :git => "#{lib_path("pg_array_parser-1.0")}" + G + + lockfile <<-L + GIT + remote: #{lib_path("pg_array_parser-1.0")} + revision: #{git.ref_for("master")} + specs: + pg_array_parser (1.0-java) + pg_array_parser (1.0) + + GEM + specs: + + PLATFORMS + java + #{lockfile_platforms} + + DEPENDENCIES + pg_array_parser! + + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle "config set --local cache_all true" + bundle "cache --all-platforms" + + expect(err).to be_empty + end + + it "uses the platform-specific gem with extra dependencies" do + setup_multiplatform_gem_with_different_dependencies_per_platform + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem "facter" + G + allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) + + expect(the_bundle.locked_gems.platforms).to eq([pl("ruby"), pl("x86_64-darwin-15")]) + expect(the_bundle).to include_gems("facter 2.4.6 universal-darwin", "CFPropertyList 1.0") + expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(["CFPropertyList-1.0", + "facter-2.4.6", + "facter-2.4.6-universal-darwin"]) + end + + context "when adding a platform via lock --add_platform" do + before do + allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) + end + + it "adds the foreign platform" do + setup_multiplatform_gem + install_gemfile(google_protobuf) + bundle "lock --add-platform=#{x64_mingw}" + + expect(the_bundle.locked_gems.platforms).to eq([rb, x64_mingw, pl("x86_64-darwin-15")]) + expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[ + google-protobuf-3.0.0.alpha.5.0.5.1 + google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin + google-protobuf-3.0.0.alpha.5.0.5.1-x64-mingw32 + ]) + end + + it "falls back on plain ruby when that version doesnt have a platform-specific gem" do + setup_multiplatform_gem + install_gemfile(google_protobuf) + bundle "lock --add-platform=#{java}" + + expect(the_bundle.locked_gems.platforms).to eq([java, rb, pl("x86_64-darwin-15")]) + expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[ + google-protobuf-3.0.0.alpha.5.0.5.1 + google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin + ]) + end + end + end + + private + + def setup_multiplatform_gem build_repo2 do build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x86_64-linux" } @@ -38,7 +163,11 @@ RSpec.describe "bundle install with specific_platform enabled" do build_gem("google-protobuf", "3.0.0.alpha.2.0") build_gem("google-protobuf", "3.0.0.alpha.1.1") build_gem("google-protobuf", "3.0.0.alpha.1.0") + end + end + def setup_multiplatform_gem_with_different_dependencies_per_platform + build_repo2 do build_gem("facter", "2.4.6") build_gem("facter", "2.4.6") do |s| s.platform = "universal-darwin" @@ -47,74 +176,4 @@ RSpec.describe "bundle install with specific_platform enabled" do build_gem("CFPropertyList") end end - - let(:google_protobuf) { <<-G } - source "#{file_uri_for(gem_repo2)}" - gem "google-protobuf" - G - - context "when on a darwin machine" do - before { simulate_platform "x86_64-darwin-15" } - - it "locks to both the specific darwin platform and ruby" do - install_gemfile(google_protobuf) - allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) - expect(the_bundle.locked_gems.platforms).to eq([pl("ruby"), pl("x86_64-darwin-15")]) - expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin") - expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[ - google-protobuf-3.0.0.alpha.5.0.5.1 - google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin - ]) - end - - it "caches both the universal-darwin and ruby gems when --all-platforms is passed" do - gemfile(google_protobuf) - bundle "package --all-platforms" - expect([cached_gem("google-protobuf-3.0.0.alpha.5.0.5.1"), cached_gem("google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin")]). - to all(exist) - end - - it "uses the platform-specific gem with extra dependencies" do - install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gem "facter" - G - allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) - - expect(the_bundle.locked_gems.platforms).to eq([pl("ruby"), pl("x86_64-darwin-15")]) - expect(the_bundle).to include_gems("facter 2.4.6 universal-darwin", "CFPropertyList 1.0") - expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(["CFPropertyList-1.0", - "facter-2.4.6", - "facter-2.4.6-universal-darwin"]) - end - - context "when adding a platform via lock --add_platform" do - before do - allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) - end - - it "adds the foreign platform" do - install_gemfile(google_protobuf) - bundle "lock --add-platform=#{x64_mingw}" - - expect(the_bundle.locked_gems.platforms).to eq([rb, x64_mingw, pl("x86_64-darwin-15")]) - expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[ - google-protobuf-3.0.0.alpha.5.0.5.1 - google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin - google-protobuf-3.0.0.alpha.5.0.5.1-x64-mingw32 - ]) - end - - it "falls back on plain ruby when that version doesnt have a platform-specific gem" do - install_gemfile(google_protobuf) - bundle "lock --add-platform=#{java}" - - expect(the_bundle.locked_gems.platforms).to eq([java, rb, pl("x86_64-darwin-15")]) - expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[ - google-protobuf-3.0.0.alpha.5.0.5.1 - google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin - ]) - end - end - end end diff --git a/spec/bundler/install/gems/compact_index_spec.rb b/spec/bundler/install/gems/compact_index_spec.rb index 5ef3f38fe7..b5fca9c6ad 100644 --- a/spec/bundler/install/gems/compact_index_spec.rb +++ b/spec/bundler/install/gems/compact_index_spec.rb @@ -138,19 +138,6 @@ RSpec.describe "compact index api" do expect(the_bundle).to include_gems("foo 1.0") end - it "falls back when the API errors out" do - simulate_platform mswin - - gemfile <<-G - source "#{source_uri}" - gem "rcov" - G - - bundle :install, :artifice => "windows" - expect(out).to include("Fetching source index from #{source_uri}") - expect(the_bundle).to include_gems "rcov 1.0.0" - end - it "falls back when the API URL returns 403 Forbidden" do gemfile <<-G source "#{source_uri}" @@ -258,14 +245,37 @@ The checksum of /versions does not match the checksum provided by the server! So end it "does not double check for gems that are only installed locally" do - system_gems %w[rack-1.0.0 thin-1.0 net_a-1.0] + build_repo2 do + build_gem "net_a" do |s| + s.add_dependency "net_b" + s.add_dependency "net_build_extensions" + end + + build_gem "net_b" + + build_gem "net_build_extensions" do |s| + s.add_dependency "rake" + s.extensions << "Rakefile" + s.write "Rakefile", <<-RUBY + task :default do + path = File.expand_path("../lib", __FILE__) + FileUtils.mkdir_p(path) + File.open("\#{path}/net_build_extensions.rb", "w") do |f| + f.puts "NET_BUILD_EXTENSIONS = 'YES'" + end + end + RUBY + end + end + + system_gems %w[rack-1.0.0 thin-1.0 net_a-1.0], :gem_repo => gem_repo2 bundle "config set --local path.system true" ENV["BUNDLER_SPEC_ALL_REQUESTS"] = strip_whitespace(<<-EOS).strip #{source_uri}/versions #{source_uri}/info/rack EOS - install_gemfile <<-G, :artifice => "compact_index", :verbose => true + install_gemfile <<-G, :artifice => "compact_index", :verbose => true, :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } source "#{source_uri}" gem "rack" G @@ -499,13 +509,19 @@ The checksum of /versions does not match the checksum provided by the server! So end it "does not refetch if the only unmet dependency is bundler" do + build_repo2 do + build_gem "bundler_dep" do |s| + s.add_dependency "bundler" + end + end + gemfile <<-G source "#{source_uri}" gem "bundler_dep" G - bundle :install, :artifice => "compact_index" + bundle :install, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } expect(out).to include("Fetching gem metadata from #{source_uri}") end @@ -598,27 +614,6 @@ The checksum of /versions does not match the checksum provided by the server! So expect(the_bundle).to include_gems "rack 1.0.0" end - it "strips http basic authentication creds for modern index" do - gemfile <<-G - source "#{basic_auth_source_uri}" - gem "rack" - G - - bundle :install, :artifice => "endopint_marshal_fail_basic_authentication" - expect(out).not_to include("#{user}:#{password}") - expect(the_bundle).to include_gems "rack 1.0.0" - end - - it "strips http basic auth creds when it can't reach the server" do - gemfile <<-G - source "#{basic_auth_source_uri}" - gem "rack" - G - - bundle :install, :artifice => "endpoint_500", :raise_on_error => false - expect(out).not_to include("#{user}:#{password}") - end - it "strips http basic auth creds when warning about ambiguous sources", :bundler => "< 3" 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 e92669e97c..5e0be89995 100644 --- a/spec/bundler/install/gems/dependency_api_spec.rb +++ b/spec/bundler/install/gems/dependency_api_spec.rb @@ -121,12 +121,20 @@ RSpec.describe "gemcutter's dependency API" do it "falls back when the API errors out" do simulate_platform mswin + build_repo2 do + # The rcov gem is platform mswin32, but has no arch + build_gem "rcov" do |s| + s.platform = Gem::Platform.new([nil, "mswin32", nil]) + s.write "lib/rcov.rb", "RCOV = '1.0.0'" + end + end + gemfile <<-G source "#{source_uri}" gem "rcov" G - bundle :install, :artifice => "windows" + bundle :install, :artifice => "windows", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } expect(out).to include("Fetching source index from #{source_uri}") expect(the_bundle).to include_gems "rcov 1.0.0" end @@ -473,13 +481,19 @@ RSpec.describe "gemcutter's dependency API" do end it "does not refetch if the only unmet dependency is bundler" do + build_repo2 do + build_gem "bundler_dep" do |s| + s.add_dependency "bundler" + end + end + gemfile <<-G source "#{source_uri}" gem "bundler_dep" G - bundle :install, :artifice => "endpoint" + bundle :install, :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } expect(out).to include("Fetching gem metadata from #{source_uri}") end @@ -578,7 +592,7 @@ RSpec.describe "gemcutter's dependency API" do gem "rack" G - bundle :install, :artifice => "endopint_marshal_fail_basic_authentication" + bundle :install, :artifice => "endpoint_marshal_fail_basic_authentication" expect(out).not_to include("#{user}:#{password}") expect(the_bundle).to include_gems "rack 1.0.0" end diff --git a/spec/bundler/install/gems/flex_spec.rb b/spec/bundler/install/gems/flex_spec.rb index 858c40c07c..7ab0ded26d 100644 --- a/spec/bundler/install/gems/flex_spec.rb +++ b/spec/bundler/install/gems/flex_spec.rb @@ -166,8 +166,7 @@ RSpec.describe "bundle flex_install" do expect(the_bundle).to include_gems "rack_middleware 1.0", "rack 0.9.1" - build_repo2 - update_repo2 do + build_repo2 do build_gem "rack-obama", "2.0" do |s| s.add_dependency "rack", "=1.2" end diff --git a/spec/bundler/install/gems/fund_spec.rb b/spec/bundler/install/gems/fund_spec.rb index 57e7c3aed3..f521b0296f 100644 --- a/spec/bundler/install/gems/fund_spec.rb +++ b/spec/bundler/install/gems/fund_spec.rb @@ -2,11 +2,38 @@ RSpec.describe "bundle install" do context "with gem sources" do + before do + build_repo2 do + build_gem "has_funding_and_other_metadata" do |s| + s.metadata = { + "bug_tracker_uri" => "https://example.com/user/bestgemever/issues", + "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md", + "documentation_uri" => "https://www.example.info/gems/bestgemever/0.0.1", + "homepage_uri" => "https://bestgemever.example.io", + "mailing_list_uri" => "https://groups.example.com/bestgemever", + "funding_uri" => "https://example.com/has_funding_and_other_metadata/funding", + "source_code_uri" => "https://example.com/user/bestgemever", + "wiki_uri" => "https://example.com/user/bestgemever/wiki", + } + end + + build_gem "has_funding", "1.2.3" do |s| + s.metadata = { + "funding_uri" => "https://example.com/has_funding/funding", + } + end + + build_gem "gem_with_dependent_funding", "1.0" do |s| + s.add_dependency "has_funding" + end + end + end + context "when gems include a fund URI" do it "displays the plural fund message after installing" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem 'has_metadata' + source "#{file_uri_for(gem_repo2)}" + gem 'has_funding_and_other_metadata' gem 'has_funding' gem 'rack-obama' G @@ -16,7 +43,7 @@ RSpec.describe "bundle install" do it "displays the singular fund message after installing" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem 'has_funding' gem 'rack-obama' G @@ -28,7 +55,7 @@ RSpec.describe "bundle install" do context "when gems do not include fund messages" do it "does not display any fund messages" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "activesupport" G @@ -39,7 +66,7 @@ RSpec.describe "bundle install" do context "when a dependency includes a fund message" do it "does not display the fund message" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem 'gem_with_dependent_funding' G diff --git a/spec/bundler/install/gems/resolving_spec.rb b/spec/bundler/install/gems/resolving_spec.rb index f621b01366..1c01ce588b 100644 --- a/spec/bundler/install/gems/resolving_spec.rb +++ b/spec/bundler/install/gems/resolving_spec.rb @@ -1,9 +1,46 @@ # frozen_string_literal: true RSpec.describe "bundle install with install-time dependencies" do + before do + build_repo2 do + # Test complicated gem dependencies for install + build_gem "net_a" do |s| + s.add_dependency "net_b" + s.add_dependency "net_build_extensions" + end + + build_gem "net_b" + + build_gem "net_build_extensions" do |s| + s.add_dependency "rake" + s.extensions << "Rakefile" + s.write "Rakefile", <<-RUBY + task :default do + path = File.expand_path("../lib", __FILE__) + FileUtils.mkdir_p(path) + File.open("\#{path}/net_build_extensions.rb", "w") do |f| + f.puts "NET_BUILD_EXTENSIONS = 'YES'" + end + end + RUBY + end + + build_gem "net_c" do |s| + s.add_dependency "net_a" + s.add_dependency "net_d" + end + + build_gem "net_d" + + build_gem "net_e" do |s| + s.add_dependency "net_d" + end + end + end + it "installs gems with implicit rake dependencies" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "with_implicit_rake_dep" gem "another_implicit_rake_dep" gem "rake" @@ -43,7 +80,7 @@ RSpec.describe "bundle install with install-time dependencies" do describe "with crazy rubygem plugin stuff" do it "installs plugins" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "net_b" G @@ -52,7 +89,7 @@ RSpec.describe "bundle install with install-time dependencies" do it "installs plugins depended on by other plugins" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "net_a" G @@ -61,7 +98,7 @@ RSpec.describe "bundle install with install-time dependencies" do it "installs multiple levels of dependencies" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "net_c" gem "net_e" G @@ -72,7 +109,7 @@ RSpec.describe "bundle install with install-time dependencies" do context "with ENV['BUNDLER_DEBUG_RESOLVER'] set" do it "produces debug output" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "net_c" gem "net_e" G @@ -86,7 +123,7 @@ RSpec.describe "bundle install with install-time dependencies" do context "with ENV['DEBUG_RESOLVER'] set" do it "produces debug output" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "net_c" gem "net_e" G @@ -100,7 +137,7 @@ RSpec.describe "bundle install with install-time dependencies" do context "with ENV['DEBUG_RESOLVER_TREE'] set" do it "produces debug output" do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "net_c" gem "net_e" G @@ -126,6 +163,10 @@ RSpec.describe "bundle install with install-time dependencies" do it "installs the older version" do build_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + build_gem "rack", "9001.0.0" do |s| s.required_ruby_version = "> 9000" end @@ -198,13 +239,7 @@ RSpec.describe "bundle install with install-time dependencies" do let(:ruby_requirement) { %("#{RUBY_VERSION}") } let(:error_message_requirement) { "~> #{RUBY_VERSION}.0" } - let(:error_message_platform) do - if Bundler.feature_flag.specific_platform? - " #{Bundler.local_platform}" - else - "" - end - end + let(:error_message_platform) { " #{Bundler.local_platform}" } shared_examples_for "ruby version conflicts" do it "raises an error during resolution" do diff --git a/spec/bundler/install/prereleases_spec.rb b/spec/bundler/install/prereleases_spec.rb index fb01220ed7..c3f968ad70 100644 --- a/spec/bundler/install/prereleases_spec.rb +++ b/spec/bundler/install/prereleases_spec.rb @@ -1,10 +1,19 @@ # frozen_string_literal: true RSpec.describe "bundle install" do + before do + build_repo2 do + build_gem "not_released", "1.0.pre" + + build_gem "has_prerelease", "1.0" + build_gem "has_prerelease", "1.1.pre" + end + end + describe "when prerelease gems are available" do it "finds prereleases" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "not_released" G expect(the_bundle).to include_gems "not_released 1.0.pre" @@ -12,7 +21,7 @@ RSpec.describe "bundle install" do it "uses regular releases if available" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "has_prerelease" G expect(the_bundle).to include_gems "has_prerelease 1.0" @@ -20,7 +29,7 @@ RSpec.describe "bundle install" do it "uses prereleases if requested" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "has_prerelease", "1.1.pre" G expect(the_bundle).to include_gems "has_prerelease 1.1.pre" diff --git a/spec/bundler/lock/lockfile_spec.rb b/spec/bundler/lock/lockfile_spec.rb index d26dc789cc..941cbd13e0 100644 --- a/spec/bundler/lock/lockfile_spec.rb +++ b/spec/bundler/lock/lockfile_spec.rb @@ -3,16 +3,28 @@ RSpec.describe "the lockfile format" do include Bundler::GemHelpers + before do + build_repo2 do + # Capistrano did this (at least until version 2.5.10) + # RubyGems 2.2 doesn't allow the specifying of a dependency twice + # See https://github.com/rubygems/rubygems/commit/03dbac93a3396a80db258d9bc63500333c25bd2f + build_gem "double_deps", "1.0", :skip_validation => true do |s| + s.add_dependency "net-ssh", ">= 1.0.0" + s.add_dependency "net-ssh" + end + end + end + it "generates a simple lockfile for a single source, gem" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "rack" G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -37,7 +49,7 @@ RSpec.describe "the lockfile format" do specs: GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -53,14 +65,14 @@ RSpec.describe "the lockfile format" do L install_gemfile <<-G, :env => { "BUNDLER_VERSION" => Bundler::VERSION } - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "rack" G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -80,7 +92,7 @@ RSpec.describe "the lockfile format" do lockfile <<-L GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -95,14 +107,14 @@ RSpec.describe "the lockfile format" do L install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "rack" G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -120,7 +132,7 @@ RSpec.describe "the lockfile format" do it "updates the lockfile's bundler version if not present" do lockfile <<-L GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -132,14 +144,14 @@ RSpec.describe "the lockfile format" do L install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "rack", "> 0" G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -160,7 +172,7 @@ RSpec.describe "the lockfile format" do lockfile <<-L GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -175,7 +187,7 @@ RSpec.describe "the lockfile format" do L install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "rack" G @@ -189,7 +201,7 @@ RSpec.describe "the lockfile format" do lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -212,7 +224,7 @@ RSpec.describe "the lockfile format" do lockfile <<-L GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -227,7 +239,7 @@ RSpec.describe "the lockfile format" do L install_gemfile <<-G, :env => { "BUNDLER_VERSION" => Bundler::VERSION } - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack" G @@ -239,7 +251,7 @@ RSpec.describe "the lockfile format" do lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -256,14 +268,14 @@ RSpec.describe "the lockfile format" do it "generates a simple lockfile for a single source, gem with dependencies" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack-obama" G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) rack-obama (1.0) @@ -282,14 +294,14 @@ RSpec.describe "the lockfile format" do it "generates a simple lockfile for a single source, gem with a version requirement" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack-obama", ">= 1.0" G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) rack-obama (1.0) @@ -380,13 +392,13 @@ RSpec.describe "the lockfile format" do it "generates lockfiles with multiple requirements" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "net-sftp" G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: net-sftp (1.1.1) net-ssh (>= 1.0.0, < 1.99.0) @@ -405,34 +417,6 @@ RSpec.describe "the lockfile format" do expect(the_bundle).to include_gems "net-sftp 1.1.1", "net-ssh 1.0.0" end - it "generates a simple lockfile for a single pinned source, gem with a version requirement", :bundler => "< 3" do - git = build_git "foo" - - install_gemfile <<-G - gem "foo", :git => "#{lib_path("foo-1.0")}" - G - - lockfile_should_be <<-G - GIT - remote: #{lib_path("foo-1.0")} - revision: #{git.ref_for("master")} - specs: - foo (1.0) - - GEM - specs: - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - foo! - - BUNDLED WITH - #{Bundler::VERSION} - G - end - it "generates a simple lockfile for a single pinned source, gem with a version requirement" do git = build_git "foo" @@ -465,7 +449,7 @@ RSpec.describe "the lockfile format" do build_lib "omg", :path => lib_path("omg") gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" platforms :#{not_local_tag} do gem "omg", :path => "#{lib_path("omg")}" @@ -481,7 +465,7 @@ RSpec.describe "the lockfile format" do specs: GEM - remote: #{file_uri_for(gem_repo1)}// + remote: #{file_uri_for(gem_repo2)}// specs: rack (1.0.0) @@ -653,7 +637,7 @@ RSpec.describe "the lockfile format" do bar = build_git "bar" install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack" gem "foo", :path => "#{lib_path("foo-1.0")}" @@ -673,7 +657,7 @@ RSpec.describe "the lockfile format" do foo (1.0) GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -692,7 +676,7 @@ RSpec.describe "the lockfile format" do it "lists gems alphabetically" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "thin" gem "actionpack" @@ -701,7 +685,7 @@ RSpec.describe "the lockfile format" do lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: actionpack (2.3.2) activesupport (= 2.3.2) @@ -727,14 +711,14 @@ RSpec.describe "the lockfile format" do it "orders dependencies' dependencies in alphabetical order" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rails" G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: actionmailer (2.3.2) activesupport (= 2.3.2) @@ -766,13 +750,13 @@ RSpec.describe "the lockfile format" do it "orders dependencies by version" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem 'double_deps' G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: double_deps (1.0) net-ssh @@ -792,14 +776,14 @@ RSpec.describe "the lockfile format" do it "does not add the :require option to the lockfile" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack-obama", ">= 1.0", :require => "rack/obama" G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) rack-obama (1.0) @@ -818,14 +802,14 @@ RSpec.describe "the lockfile format" do it "does not add the :group option to the lockfile" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack-obama", ">= 1.0", :group => :test G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) rack-obama (1.0) @@ -956,10 +940,10 @@ RSpec.describe "the lockfile format" do G end - it "keeps existing platforms in the lockfile", :bundler => "< 3" do + it "keeps existing platforms in the lockfile" do lockfile <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -974,103 +958,30 @@ RSpec.describe "the lockfile format" do G install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack" G - lockfile_should_be <<-G - GEM - remote: #{file_uri_for(gem_repo1)}/ - specs: - rack (1.0.0) - - PLATFORMS - java - #{generic_local_platform} - - DEPENDENCIES - rack - - BUNDLED WITH - #{Bundler::VERSION} - G - end - - it "keeps existing platforms in the lockfile", :bundler => "3" do - lockfile <<-G - GEM - remote: #{file_uri_for(gem_repo1)}/ - specs: - rack (1.0.0) - - PLATFORMS - java - - DEPENDENCIES - rack - - BUNDLED WITH - #{Bundler::VERSION} - G - - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" - - gem "rack" - G - - lockfile_should_be <<-G - GEM - remote: #{file_uri_for(gem_repo1)}/ - specs: - rack (1.0.0) - - PLATFORMS - java - #{generic_local_platform} - #{specific_local_platform} - - DEPENDENCIES - rack - - BUNDLED WITH - #{Bundler::VERSION} - G - end - - it "persists the spec's platform to the lockfile", :bundler => "< 3" do - build_repo2 do - build_gem "platform_specific", "1.0" do |s| - s.platform = Gem::Platform.new("universal-java-16") - end - end - - simulate_platform "universal-java-16" - - install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gem "platform_specific" - G - lockfile_should_be <<-G GEM remote: #{file_uri_for(gem_repo2)}/ specs: - platform_specific (1.0-java) + rack (1.0.0) PLATFORMS java + #{lockfile_platforms} DEPENDENCIES - platform_specific + rack BUNDLED WITH #{Bundler::VERSION} G end - it "persists the spec's platform and specific platform to the lockfile", :bundler => "3" do + it "persists the spec's platform and specific platform to the lockfile" do build_repo2 do build_gem "platform_specific", "1.0" do |s| s.platform = Gem::Platform.new("universal-java-16") @@ -1105,19 +1016,19 @@ RSpec.describe "the lockfile format" do it "does not add duplicate gems" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack" G install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack" gem "activesupport" G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: activesupport (2.3.5) rack (1.0.0) @@ -1136,14 +1047,14 @@ RSpec.describe "the lockfile format" do it "does not add duplicate dependencies" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack" gem "rack" G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -1160,14 +1071,14 @@ RSpec.describe "the lockfile format" do it "does not add duplicate dependencies with versions" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack", "1.0" gem "rack", "1.0" G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -1184,14 +1095,14 @@ RSpec.describe "the lockfile format" do it "does not add duplicate dependencies in different groups" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack", "1.0", :group => :one gem "rack", "1.0", :group => :two G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (1.0.0) @@ -1208,7 +1119,7 @@ RSpec.describe "the lockfile format" do it "raises if two different versions are used" do install_gemfile <<-G, :raise_on_error => false - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack", "1.0" gem "rack", "1.1" G @@ -1219,7 +1130,7 @@ RSpec.describe "the lockfile format" do it "raises if two different sources are used" do install_gemfile <<-G, :raise_on_error => false - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack" gem "rack", :git => "git://hubz.com" G @@ -1230,13 +1141,13 @@ RSpec.describe "the lockfile format" do it "works correctly with multiple version dependencies" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack", "> 0.9", "< 1.0" G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (0.9.1) @@ -1253,14 +1164,14 @@ RSpec.describe "the lockfile format" do it "captures the Ruby version in the lockfile" do install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" ruby '#{RUBY_VERSION}' gem "rack", "> 0.9", "< 1.0" G lockfile_should_be <<-G GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack (0.9.1) @@ -1289,7 +1200,7 @@ RSpec.describe "the lockfile format" do revision = revision_for(lib_path("omg")) gemfile <<-G - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "omg", :git => "#{lib_path("omg")}", :branch => 'master' G @@ -1314,7 +1225,7 @@ RSpec.describe "the lockfile format" do omg (1.0) GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: PLATFORMS @@ -1341,7 +1252,7 @@ RSpec.describe "the lockfile format" do omg (1.0) GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: PLATFORMS @@ -1358,7 +1269,7 @@ RSpec.describe "the lockfile format" do it "raises a helpful error message when the lockfile is missing deps" do lockfile <<-L GEM - remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo2)}/ specs: rack_middleware (1.0) @@ -1370,7 +1281,7 @@ RSpec.describe "the lockfile format" do L install_gemfile <<-G, :raise_on_error => false - source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo2)}" gem "rack_middleware" G @@ -1400,7 +1311,11 @@ RSpec.describe "the lockfile format" do context "during updates" do it "preserves Gemfile.lock \\n line endings" do - update_repo2 + update_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + end expect { bundle "update", :all => true }.to change { File.mtime(bundled_app_lock) } expect(File.read(bundled_app_lock)).not_to match("\r\n") @@ -1410,7 +1325,12 @@ RSpec.describe "the lockfile format" do it "preserves Gemfile.lock \\n\\r line endings" do skip "needs to be adapted" if Gem.win_platform? - update_repo2 + update_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + end + win_lock = File.read(bundled_app_lock).gsub(/\n/, "\r\n") File.open(bundled_app_lock, "wb") {|f| f.puts(win_lock) } set_lockfile_mtime_to_known_value @@ -1449,7 +1369,7 @@ RSpec.describe "the lockfile format" do it "refuses to install if Gemfile.lock contains conflict markers" do lockfile <<-L GEM - remote: #{file_uri_for(gem_repo1)}// + remote: #{file_uri_for(gem_repo2)}// specs: <<<<<<< rack (1.0.0) @@ -1468,7 +1388,7 @@ RSpec.describe "the lockfile format" do L install_gemfile <<-G, :raise_on_error => false - source "#{file_uri_for(gem_repo1)}/" + source "#{file_uri_for(gem_repo2)}/" gem "rack" G diff --git a/spec/bundler/other/platform_spec.rb b/spec/bundler/other/platform_spec.rb index a8fd4d51fb..eb3539b412 100644 --- a/spec/bundler/other/platform_spec.rb +++ b/spec/bundler/other/platform_spec.rb @@ -496,6 +496,10 @@ G #{ruby_version_correct} G update_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + build_gem "activesupport", "3.0" end @@ -512,6 +516,10 @@ G #{ruby_version_correct_engineless} G update_repo2 do + build_gem "rack", "1.2" do |s| + s.executables = "rackup" + end + build_gem "activesupport", "3.0" end diff --git a/spec/bundler/plugins/install_spec.rb b/spec/bundler/plugins/install_spec.rb index a91175c616..370973ad1a 100644 --- a/spec/bundler/plugins/install_spec.rb +++ b/spec/bundler/plugins/install_spec.rb @@ -208,6 +208,19 @@ RSpec.describe "bundler plugin install" do plugin_should_be_installed("ga-plugin") end + it "accepts path sources" do + build_lib "ga-plugin" do |s| + s.write "plugins.rb" + end + + install_gemfile <<-G + plugin 'ga-plugin', :path => "#{lib_path("ga-plugin-1.0")}" + G + + expect(out).to include("Installed plugin ga-plugin") + plugin_should_be_installed("ga-plugin") + end + context "in deployment mode" do it "installs plugins" do install_gemfile <<-G diff --git a/spec/bundler/plugins/source/example_spec.rb b/spec/bundler/plugins/source/example_spec.rb index 60ed051ec3..03a377ac93 100644 --- a/spec/bundler/plugins/source/example_spec.rb +++ b/spec/bundler/plugins/source/example_spec.rb @@ -33,6 +33,7 @@ RSpec.describe "real source plugins" do def install(spec, opts) mkdir_p(install_path.parent) + require 'fileutils' FileUtils.cp_r(path, install_path) spec_path = install_path.join("\#{spec.full_name}.gemspec") @@ -66,32 +67,7 @@ RSpec.describe "real source plugins" do expect(the_bundle).to include_gems("a-path-gem 1.0") end - it "writes to lock file", :bundler => "< 3" do - bundle "install" - - lockfile_should_be <<-G - PLUGIN SOURCE - remote: #{lib_path("a-path-gem-1.0")} - type: mpath - specs: - a-path-gem (1.0) - - GEM - remote: #{file_uri_for(gem_repo2)}/ - specs: - - PLATFORMS - #{generic_local_platform} - - DEPENDENCIES - a-path-gem! - - BUNDLED WITH - #{Bundler::VERSION} - G - end - - it "writes to lock file", :bundler => "3" do + it "writes to lock file" do bundle "install" lockfile_should_be <<-G @@ -362,34 +338,7 @@ RSpec.describe "real source plugins" do expect(the_bundle).to include_gems("ma-gitp-gem 1.0") end - it "writes to lock file", :bundler => "< 3" do - revision = revision_for(lib_path("ma-gitp-gem-1.0")) - bundle "install" - - lockfile_should_be <<-G - PLUGIN SOURCE - remote: #{file_uri_for(lib_path("ma-gitp-gem-1.0"))} - type: gitp - revision: #{revision} - specs: - ma-gitp-gem (1.0) - - GEM - remote: #{file_uri_for(gem_repo2)}/ - specs: - - PLATFORMS - #{generic_local_platform} - - DEPENDENCIES - ma-gitp-gem! - - BUNDLED WITH - #{Bundler::VERSION} - G - end - - it "writes to lock file", :bundler => "3" do + it "writes to lock file" do revision = revision_for(lib_path("ma-gitp-gem-1.0")) bundle "install" diff --git a/spec/bundler/quality_spec.rb b/spec/bundler/quality_spec.rb index b0647b7663..808f0502a4 100644 --- a/spec/bundler/quality_spec.rb +++ b/spec/bundler/quality_spec.rb @@ -190,7 +190,7 @@ RSpec.describe "The library itself" do line.scan(/Bundler\.settings\[:#{key_pattern}\]/).flatten.each {|s| all_settings[s] << "referenced at `#{filename}:#{number.succ}`" } end end - documented_settings = File.read("man/bundle-config.1.ronn")[/LIST OF AVAILABLE KEYS.*/m].scan(/^\* `#{key_pattern}`/).flatten + documented_settings = File.read("lib/bundler/man/bundle-config.1.ronn")[/LIST OF AVAILABLE KEYS.*/m].scan(/^\* `#{key_pattern}`/).flatten documented_settings.each do |s| all_settings.delete(s) @@ -249,7 +249,7 @@ RSpec.describe "The library itself" do end it "does not use require internally, but require_relative" do - exempt = %r{templates/|vendor/} + exempt = %r{templates/|man/|vendor/} all_bad_requires = [] lib_tracked_files.each do |filename| next if filename =~ exempt diff --git a/spec/bundler/realworld/mirror_probe_spec.rb b/spec/bundler/realworld/mirror_probe_spec.rb index 626092c7eb..a2b5c89150 100644 --- a/spec/bundler/realworld/mirror_probe_spec.rb +++ b/spec/bundler/realworld/mirror_probe_spec.rb @@ -74,10 +74,10 @@ RSpec.describe "fetching dependencies with a not available mirror", :realworld = bundle :install, :artifice => nil, :raise_on_error => false expect(out).to include("Fetching source index from #{mirror}") - expect(err).to include("Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from #{mirror}") - expect(err).to include("Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from #{mirror}") - expect(err).to include("Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}") - expect(err).to include("Could not fetch specs from #{mirror}") + expect(err).to include("Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error ") + expect(err).to include("Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error ") + expect(err).to include("Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error ") + expect(err).to include("Could not fetch specs from #{mirror}/ due to underlying error ") end it "prints each error and warning on a new line" do @@ -90,10 +90,10 @@ RSpec.describe "fetching dependencies with a not available mirror", :realworld = expect(out).to include "Fetching source index from #{mirror}/" expect(err).to include <<-EOS.strip -Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ -Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ -Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ -Could not fetch specs from #{mirror}/ +Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error +Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error +Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error +Could not fetch specs from #{mirror}/ due to underlying error EOS end end @@ -112,10 +112,10 @@ Could not fetch specs from #{mirror}/ bundle :install, :artifice => nil, :raise_on_error => false expect(out).to include("Fetching source index from #{mirror}") - expect(err).to include("Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from #{mirror}") - expect(err).to include("Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from #{mirror}") - expect(err).to include("Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}") - expect(err).to include("Could not fetch specs from #{mirror}") + expect(err).to include("Retrying fetcher due to error (2/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error ") + expect(err).to include("Retrying fetcher due to error (3/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error ") + expect(err).to include("Retrying fetcher due to error (4/4): Bundler::HTTPError Could not fetch specs from #{mirror}/ due to underlying error ") + expect(err).to include("Could not fetch specs from #{mirror}/ due to underlying error ") end end @@ -138,7 +138,7 @@ Could not fetch specs from #{mirror}/ end def setup_mirror - mirror_port = find_unused_port - @mirror_uri = "http://#{host}:#{mirror_port}" + @mirror_port = find_unused_port + @mirror_uri = "http://#{host}:#{@mirror_port}" end end diff --git a/spec/bundler/runtime/inline_spec.rb b/spec/bundler/runtime/inline_spec.rb index 1ba50c0e97..fadf3eb989 100644 --- a/spec/bundler/runtime/inline_spec.rb +++ b/spec/bundler/runtime/inline_spec.rb @@ -369,4 +369,34 @@ RSpec.describe "bundler/inline#gemfile" do expect(out).to eq("WIN") expect(err).to be_empty end + + it "when requiring fileutils after does not show redefinition warnings" do + dependency_installer_loads_fileutils = ruby "require 'rubygems/dependency_installer'; puts $LOADED_FEATURES.grep(/fileutils/)", :raise_on_error => false + skip "does not work if rubygems/dependency_installer loads fileutils, which happens until rubygems 3.2.0" unless dependency_installer_loads_fileutils.empty? + + skip "does not work on ruby 3.0 because it changes the path to look for default gems, tsort is a default gem there, and we can't install it either like we do with fiddle because it doesn't yet exist" unless RUBY_VERSION < "3.0.0" + + Dir.mkdir tmp("path_without_gemfile") + + default_fileutils_version = ruby "gem 'fileutils', '< 999999'; require 'fileutils'; puts FileUtils::VERSION", :raise_on_error => false + skip "fileutils isn't a default gem" if default_fileutils_version.empty? + + realworld_system_gems "fileutils --version 1.4.1" + + realworld_system_gems "fiddle" # not sure why, but this is needed on Windows to boot rubygems succesfully + + realworld_system_gems "timeout uri" # this spec uses net/http which requires these default gems + + script <<-RUBY, :dir => tmp("path_without_gemfile"), :env => { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s } + require "bundler/inline" + + gemfile(true) do + source "#{file_uri_for(gem_repo2)}" + end + + require "fileutils" + RUBY + + expect(err).to eq("The Gemfile specifies no dependencies") + end end diff --git a/spec/bundler/runtime/setup_spec.rb b/spec/bundler/runtime/setup_spec.rb index 8424e02de1..6b47878944 100644 --- a/spec/bundler/runtime/setup_spec.rb +++ b/spec/bundler/runtime/setup_spec.rb @@ -1233,6 +1233,9 @@ end end << "bundler" exempts << "fiddle" if Gem.win_platform? && Gem::Version.new(Gem::VERSION) >= Gem::Version.new("2.7") exempts << "uri" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7") + exempts << "pathname" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0") + exempts << "set" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0") + exempts << "tsort" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0") exempts end @@ -1313,7 +1316,7 @@ end expect(out).to eq("The Gemfile's dependencies are satisfied") end - # bundler respects paths specified directly in RUBYLIB or RUBYOPT, and + # bundler respects paths specified direclty in RUBYLIB or RUBYOPT, and # that happens when running ruby from the ruby-core setup. To # workaround, we manually remove those for these tests when they would # override the default gem. diff --git a/spec/bundler/support/artifice/endopint_marshal_fail_basic_authentication.rb b/spec/bundler/support/artifice/endpoint_marshal_fail_basic_authentication.rb similarity index 100% rename from spec/bundler/support/artifice/endopint_marshal_fail_basic_authentication.rb rename to spec/bundler/support/artifice/endpoint_marshal_fail_basic_authentication.rb diff --git a/spec/bundler/support/builders.rb b/spec/bundler/support/builders.rb index a1770759a9..02a2c0f659 100644 --- a/spec/bundler/support/builders.rb +++ b/spec/bundler/support/builders.rb @@ -76,14 +76,6 @@ module Spec s.add_dependency "activesupport", ">= 2.0.0" end - build_gem "rails_pinned_to_old_activesupport" do |s| - s.add_dependency "activesupport", "= 1.2.3" - end - - build_gem "missing_dep" do |s| - s.add_dependency "not_here" - end - build_gem "rspec", "1.2.7", :no_default => true do |s| s.write "lib/spec.rb", "SPEC = '1.2.7'" end @@ -158,23 +150,6 @@ module Spec build_gem "duradura", "7.0" - build_gem "multiple_versioned_deps" do |s| - s.add_dependency "weakling", ">= 0.0.1", "< 0.1" - end - - build_gem "not_released", "1.0.pre" - - build_gem "has_prerelease", "1.0" - build_gem "has_prerelease", "1.1.pre" - - build_gem "with_development_dependency" do |s| - s.add_development_dependency "activesupport", "= 2.3.5" - end - - build_gem "with_license" do |s| - s.license = "MIT" - end - build_gem "with_implicit_rake_dep" do |s| s.extensions << "Rakefile" s.write "Rakefile", <<-RUBY @@ -215,10 +190,6 @@ module Spec s.write "lib/rubygems_plugin.rb", "require 'bundler/omg' ; puts 'FAIL'" end - build_gem "bundler_dep" do |s| - s.add_dependency "bundler" - end - # The yard gem iterates over Gem.source_index looking for plugins build_gem "yard" do |s| s.write "lib/yard.rb", <<-Y @@ -228,115 +199,12 @@ module Spec Y end - # The rcov gem is platform mswin32, but has no arch - build_gem "rcov" do |s| - s.platform = Gem::Platform.new([nil, "mswin32", nil]) - s.write "lib/rcov.rb", "RCOV = '1.0.0'" - end - build_gem "net-ssh" build_gem "net-sftp", "1.1.1" do |s| s.add_dependency "net-ssh", ">= 1.0.0", "< 1.99.0" end - # Test complicated gem dependencies for install - build_gem "net_a" do |s| - s.add_dependency "net_b" - s.add_dependency "net_build_extensions" - end - - build_gem "net_b" - - build_gem "net_build_extensions" do |s| - s.add_dependency "rake" - s.extensions << "Rakefile" - s.write "Rakefile", <<-RUBY - task :default do - path = File.expand_path("../lib", __FILE__) - FileUtils.mkdir_p(path) - File.open("\#{path}/net_build_extensions.rb", "w") do |f| - f.puts "NET_BUILD_EXTENSIONS = 'YES'" - end - end - RUBY - end - - build_gem "net_c" do |s| - s.add_dependency "net_a" - s.add_dependency "net_d" - end - - build_gem "net_d" - - build_gem "net_e" do |s| - s.add_dependency "net_d" - end - - # Capistrano did this (at least until version 2.5.10) - # RubyGems 2.2 doesn't allow the specifying of a dependency twice - # See https://github.com/rubygems/rubygems/commit/03dbac93a3396a80db258d9bc63500333c25bd2f - build_gem "double_deps", "1.0", :skip_validation => true do |s| - s.add_dependency "net-ssh", ">= 1.0.0" - s.add_dependency "net-ssh" - end - build_gem "foo" - - # A minimal fake pry console - build_gem "pry" do |s| - s.write "lib/pry.rb", <<-RUBY - class Pry - class << self - def toplevel_binding - unless defined?(@toplevel_binding) && @toplevel_binding - TOPLEVEL_BINDING.eval %{ - def self.__pry__; binding; end - Pry.instance_variable_set(:@toplevel_binding, __pry__) - class << self; undef __pry__; end - } - end - @toplevel_binding.eval('private') - @toplevel_binding - end - - def __pry__ - while line = gets - begin - puts eval(line, toplevel_binding).inspect.sub(/^"(.*)"$/, '=> \\1') - rescue Exception => e - puts "\#{e.class}: \#{e.message}" - puts e.backtrace.first - end - end - end - alias start __pry__ - end - end - RUBY - end - - build_gem "has_metadata" do |s| - s.metadata = { - "bug_tracker_uri" => "https://example.com/user/bestgemever/issues", - "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md", - "documentation_uri" => "https://www.example.info/gems/bestgemever/0.0.1", - "homepage_uri" => "https://bestgemever.example.io", - "mailing_list_uri" => "https://groups.example.com/bestgemever", - "funding_uri" => "https://example.com/has_metadata/funding", - "source_code_uri" => "https://example.com/user/bestgemever", - "wiki_uri" => "https://example.com/user/bestgemever/wiki", - } - end - - build_gem "has_funding", "1.2.3" do |s| - s.metadata = { - "funding_uri" => "https://example.com/has_funding/funding", - } - end - - build_gem "gem_with_dependent_funding", "1.0" do |s| - s.add_dependency "has_funding" - end end end @@ -366,9 +234,6 @@ module Spec def update_repo2 update_repo gem_repo2 do - build_gem "rack", "1.2" do |s| - s.executables = "rackup" - end yield if block_given? end end @@ -658,6 +523,7 @@ module Spec file = Pathname.new(path).join(file) FileUtils.mkdir_p(file.dirname) File.open(file, "w") {|f| f.puts source } + File.chmod("+x", file) if @spec.executables.map {|exe| "#{@spec.bindir}/#{exe}" }.include?(file) end path end diff --git a/spec/bundler/support/platforms.rb b/spec/bundler/support/platforms.rb index a6ebd7510f..ab203919e7 100644 --- a/spec/bundler/support/platforms.rb +++ b/spec/bundler/support/platforms.rb @@ -94,11 +94,7 @@ module Spec end def local_platforms - if Bundler.feature_flag.specific_platform? - [local, specific_local_platform] - else - [local] - end + [local, specific_local_platform].uniq end end end diff --git a/spec/bundler/update/gems/fund_spec.rb b/spec/bundler/update/gems/fund_spec.rb index 6d7075b424..0dfe63d36d 100644 --- a/spec/bundler/update/gems/fund_spec.rb +++ b/spec/bundler/update/gems/fund_spec.rb @@ -2,9 +2,30 @@ RSpec.describe "bundle update" do before do + build_repo2 do + build_gem "has_funding_and_other_metadata" do |s| + s.metadata = { + "bug_tracker_uri" => "https://example.com/user/bestgemever/issues", + "changelog_uri" => "https://example.com/user/bestgemever/CHANGELOG.md", + "documentation_uri" => "https://www.example.info/gems/bestgemever/0.0.1", + "homepage_uri" => "https://bestgemever.example.io", + "mailing_list_uri" => "https://groups.example.com/bestgemever", + "funding_uri" => "https://example.com/has_funding_and_other_metadata/funding", + "source_code_uri" => "https://example.com/user/bestgemever", + "wiki_uri" => "https://example.com/user/bestgemever/wiki", + } + end + + build_gem "has_funding", "1.2.3" do |s| + s.metadata = { + "funding_uri" => "https://example.com/has_funding/funding", + } + end + end + gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem 'has_metadata' + source "#{file_uri_for(gem_repo2)}" + gem 'has_funding_and_other_metadata' gem 'has_funding', '< 2.0' G @@ -14,8 +35,8 @@ RSpec.describe "bundle update" do context "when listed gems are updated" do before do gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem 'has_metadata' + source "#{file_uri_for(gem_repo2)}" + gem 'has_funding_and_other_metadata' gem 'has_funding' G