diff options
33 files changed, 618 insertions, 425 deletions
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 3c25149d33..9178f0126f 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -106,6 +106,19 @@ module Bundler @locked_platforms = [] end + @locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } + @disable_multisource = !Bundler.frozen_bundle? || @locked_gem_sources.none? {|s| s.remotes.size > 1 } + + unless @disable_multisource + msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. " \ + "You should regenerate your lockfile in a non frozen environment." + + Bundler::SharedHelpers.major_deprecation 2, msg + + @sources.allow_multisource! + @locked_gem_sources.each(&:allow_multisource!) + end + @unlock[:gems] ||= [] @unlock[:sources] ||= [] @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object @@ -145,6 +158,14 @@ module Bundler end end + def disable_multisource? + @disable_multisource + end + + def allow_multisource! + @disable_multisource = false + end + def resolve_with_cache! raise "Specs already loaded" if @specs sources.cached! @@ -264,7 +285,7 @@ module Bundler # Run a resolve against the locally available gems Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}") expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, @remote) - Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) + Resolver.resolve(expanded_dependencies, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) end end end @@ -530,6 +551,9 @@ module Bundler attr_reader :sources private :sources + attr_reader :locked_gem_sources + private :locked_gem_sources + def nothing_changed? !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@locked_specs_incomplete_for_platform end @@ -654,21 +678,20 @@ module Bundler end def converge_rubygems_sources - return false if Bundler.feature_flag.disable_multisource? + return false if disable_multisource? - changes = false + return false if locked_gem_sources.empty? - # Get the RubyGems sources from the Gemfile.lock - locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } # Get the RubyGems remotes from the Gemfile actual_remotes = sources.rubygems_remotes + return false if actual_remotes.empty? + + changes = false # If there is a RubyGems source in both - if !locked_gem_sources.empty? && !actual_remotes.empty? - locked_gem_sources.each do |locked_gem| - # Merge the remotes from the Gemfile into the Gemfile.lock - changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes]) - end + locked_gem_sources.each do |locked_gem| + # Merge the remotes from the Gemfile into the Gemfile.lock + changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes]) end changes @@ -893,30 +916,18 @@ module Bundler # Record the specs available in each gem's source, so that those # specs will be available later when the resolver knows where to # look for that gemspec (or its dependencies) - default = sources.default_source - source_requirements = { :default => default } - default = nil unless Bundler.feature_flag.disable_multisource? - dependencies.each do |dep| - next unless source = dep.source || default - source_requirements[dep.name] = source - end + source_requirements = { :default => sources.default_source }.merge(dependency_source_requirements) metadata_dependencies.each do |dep| source_requirements[dep.name] = sources.metadata_source end + source_requirements[:global] = index unless disable_multisource? source_requirements[:default_bundler] = source_requirements["bundler"] || source_requirements[:default] source_requirements["bundler"] = sources.metadata_source # needs to come last to override source_requirements end def pinned_spec_names(skip = nil) - pinned_names = [] - default = Bundler.feature_flag.disable_multisource? && sources.default_source - @dependencies.each do |dep| - next unless dep_source = dep.source || default - next if dep_source == skip - pinned_names << dep.name - end - pinned_names + dependency_source_requirements.reject {|_, source| source == skip }.keys end def requested_groups @@ -973,5 +984,18 @@ module Bundler Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes) end + + def dependency_source_requirements + @dependency_source_requirements ||= begin + source_requirements = {} + default = disable_multisource? && sources.default_source + dependencies.each do |dep| + dep_source = dep.source || default + next unless dep_source + source_requirements[dep.name] = dep_source + end + source_requirements + end + end end end diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb index 1cc7908b8a..ef5aaf669b 100644 --- a/lib/bundler/dsl.rb +++ b/lib/bundler/dsl.rb @@ -24,6 +24,9 @@ module Bundler def initialize @source = nil @sources = SourceList.new + + @global_rubygems_sources = [] + @git_sources = {} @dependencies = [] @groups = [] @@ -45,6 +48,7 @@ module Bundler @gemfiles << expanded_gemfile_path contents ||= Bundler.read_file(@gemfile.to_s) instance_eval(contents.dup.tap{|x| x.untaint if RUBY_VERSION < "2.7" }, gemfile.to_s, 1) + check_primary_source_safety rescue Exception => e # rubocop:disable Lint/RescueException message = "There was an error " \ "#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} " \ @@ -164,8 +168,7 @@ module Bundler elsif block_given? with_source(@sources.add_rubygems_source("remotes" => source), &blk) else - check_primary_source_safety(@sources) - @sources.global_rubygems_source = source + @global_rubygems_sources << source end end @@ -183,24 +186,14 @@ module Bundler end def path(path, options = {}, &blk) - unless block_given? - msg = "You can no longer specify a path source by itself. Instead, \n" \ - "either use the :path option on a gem, or specify the gems that \n" \ - "bundler should find in the path source by passing a block to \n" \ - "the path method, like: \n\n" \ - " path 'dir/containing/rails' do\n" \ - " gem 'rails'\n" \ - " end\n\n" - - raise DeprecatedError, msg if Bundler.feature_flag.disable_multisource? - SharedHelpers.major_deprecation(2, msg.strip) - end - source_options = normalize_hash(options).merge( "path" => Pathname.new(path), "root_path" => gemfile_root, "gemspec" => gemspecs.find {|g| g.name == options["name"] } ) + + source_options["global"] = true unless block_given? + source = @sources.add_path_source(source_options) with_source(source, &blk) end @@ -279,6 +272,11 @@ module Bundler raise GemfileError, "Undefined local variable or method `#{name}' for Gemfile" end + def check_primary_source_safety + check_path_source_safety + check_rubygems_source_safety + end + private def add_git_sources @@ -440,25 +438,40 @@ repo_name ||= user_name end end - def check_primary_source_safety(source_list) - return if source_list.rubygems_primary_remotes.empty? && source_list.global_rubygems_source.nil? + def check_path_source_safety + return if @sources.global_path_source.nil? + + msg = "You can no longer specify a path source by itself. Instead, \n" \ + "either use the :path option on a gem, or specify the gems that \n" \ + "bundler should find in the path source by passing a block to \n" \ + "the path method, like: \n\n" \ + " path 'dir/containing/rails' do\n" \ + " gem 'rails'\n" \ + " end\n\n" - if Bundler.feature_flag.disable_multisource? + SharedHelpers.major_deprecation(2, msg.strip) + end + + def check_rubygems_source_safety + if @global_rubygems_sources.size <= 1 + @sources.global_rubygems_source = @global_rubygems_sources.first + return + end + + @global_rubygems_sources.each do |source| + @sources.add_rubygems_remote(source) + end + + if Bundler.feature_flag.bundler_3_mode? msg = "This Gemfile contains multiple primary sources. " \ "Each source after the first must include a block to indicate which gems " \ "should come from that source" - unless Bundler.feature_flag.bundler_2_mode? - msg += ". To downgrade this error to a warning, run " \ - "`bundle config unset disable_multisource`" - end raise GemfileEvalError, msg else Bundler::SharedHelpers.major_deprecation 2, "Your Gemfile contains multiple primary sources. " \ "Using `source` more than once without a block is a security risk, and " \ "may result in installing unexpected gems. To resolve this warning, use " \ - "a block to indicate which gems should come from the secondary source. " \ - "To upgrade this warning to an error, run `bundle config set --local " \ - "disable_multisource true`." + "a block to indicate which gems should come from the secondary source." end end diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb index a1b443b042..9b7172fa35 100644 --- a/lib/bundler/feature_flag.rb +++ b/lib/bundler/feature_flag.rb @@ -32,7 +32,6 @@ module Bundler settings_flag(:cache_all) { bundler_3_mode? } settings_flag(:default_install_uses_path) { bundler_3_mode? } settings_flag(:deployment_means_frozen) { bundler_3_mode? } - settings_flag(:disable_multisource) { bundler_3_mode? } settings_flag(:forget_cli_options) { bundler_3_mode? } settings_flag(:global_gem_cache) { bundler_3_mode? } settings_flag(:only_update_to_newer_versions) { bundler_3_mode? } diff --git a/lib/bundler/inline.rb b/lib/bundler/inline.rb index 59211193d4..02da06cee9 100644 --- a/lib/bundler/inline.rb +++ b/lib/bundler/inline.rb @@ -50,6 +50,7 @@ def gemfile(install = false, options = {}, &gemfile) Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins? builder = Bundler::Dsl.new builder.instance_eval(&gemfile) + builder.check_primary_source_safety Bundler.settings.temporary(:frozen => false) do definition = builder.to_definition(nil, true) diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb index f836737621..058d353bbe 100644 --- a/lib/bundler/lockfile_parser.rb +++ b/lib/bundler/lockfile_parser.rb @@ -64,8 +64,6 @@ module Bundler @state = nil @specs = {} - @rubygems_aggregate = Source::Rubygems.new - if lockfile.match(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/) raise LockfileError, "Your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} contains merge conflicts.\n" \ "Run `git checkout HEAD -- #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` first to get a clean lock." @@ -89,7 +87,6 @@ module Bundler send("parse_#{@state}", line) end end - @sources << @rubygems_aggregate unless Bundler.feature_flag.disable_multisource? @specs = @specs.values.sort_by(&:identifier) warn_for_outdated_bundler_version rescue ArgumentError => e @@ -134,16 +131,19 @@ module Bundler @sources << @current_source end when GEM - if Bundler.feature_flag.disable_multisource? + source_remotes = Array(@opts["remote"]) + + if source_remotes.size == 1 @opts["remotes"] = @opts.delete("remote") @current_source = TYPES[@type].from_lock(@opts) - @sources << @current_source else - Array(@opts["remote"]).each do |url| - @rubygems_aggregate.add_remote(url) + source_remotes.each do |url| + rubygems_aggregate.add_remote(url) end - @current_source = @rubygems_aggregate + @current_source = rubygems_aggregate end + + @sources << @current_source when PLUGIN @current_source = Plugin.source_from_lock(@opts) @sources << @current_source @@ -245,5 +245,9 @@ module Bundler def parse_ruby(line) @ruby_version = line.strip end + + def rubygems_aggregate + @rubygems_aggregate ||= Source::Rubygems.new + end end end diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index 7a4a16c43e..da628a7dcc 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -56,9 +56,6 @@ Executing \fBbundle config unset \-\-local <name> <value>\fR will delete the con .P Executing bundle with the \fBBUNDLE_IGNORE_CONFIG\fR environment variable set will cause it to ignore all configuration\. . -.P -Executing \fBbundle config set \-\-local disable_multisource true\fR upgrades the warning about the Gemfile containing multiple primary sources to an error\. Executing \fBbundle config unset disable_multisource\fR downgrades this error to a warning\. -. .SH "REMEMBERING OPTIONS" Flags passed to \fBbundle install\fR or the Bundler runtime, such as \fB\-\-path foo\fR or \fB\-\-without production\fR, are remembered between commands and saved to your local application\'s configuration (normally, \fB\./\.bundle/config\fR)\. . @@ -184,9 +181,6 @@ The following is a list of all configuration keys and their purpose\. You can le \fBdisable_local_revision_check\fR (\fBBUNDLE_DISABLE_LOCAL_REVISION_CHECK\fR): Allow Bundler to use a local git override without checking if the revision present in the lockfile is present in the repository\. . .IP "\(bu" 4 -\fBdisable_multisource\fR (\fBBUNDLE_DISABLE_MULTISOURCE\fR): When set, Gemfiles containing multiple sources will produce errors instead of warnings\. Use \fBbundle config unset disable_multisource\fR to unset\. -. -.IP "\(bu" 4 \fBdisable_shared_gems\fR (\fBBUNDLE_DISABLE_SHARED_GEMS\fR): Stop Bundler from accessing gems installed to RubyGems\' normal location\. . .IP "\(bu" 4 @@ -211,10 +205,10 @@ The following is a list of all configuration keys and their purpose\. You can le \fBignore_messages\fR (\fBBUNDLE_IGNORE_MESSAGES\fR): When set, no post install messages will be printed\. To silence a single gem, use dot notation like \fBignore_messages\.httparty true\fR\. . .IP "\(bu" 4 -\fBinit_gems_rb\fR (\fBBUNDLE_INIT_GEMS_RB\fR) Generate a \fBgems\.rb\fR instead of a \fBGemfile\fR when running \fBbundle init\fR\. +\fBinit_gems_rb\fR (\fBBUNDLE_INIT_GEMS_RB\fR): Generate a \fBgems\.rb\fR instead of a \fBGemfile\fR when running \fBbundle init\fR\. . .IP "\(bu" 4 -\fBjobs\fR (\fBBUNDLE_JOBS\fR): The number of gems Bundler can install in parallel\. Defaults to 1\. +\fBjobs\fR (\fBBUNDLE_JOBS\fR): The number of gems Bundler can install in parallel\. Defaults to 1 on Windows, and to the the number of processors on other platforms\. . .IP "\(bu" 4 \fBno_install\fR (\fBBUNDLE_NO_INSTALL\fR): Whether \fBbundle package\fR should skip installing gems\. @@ -241,7 +235,7 @@ The following is a list of all configuration keys and their purpose\. You can le \fBprefer_patch\fR (BUNDLE_PREFER_PATCH): Prefer updating only to next patch version during updates\. Makes \fBbundle update\fR calls equivalent to \fBbundler update \-\-patch\fR\. . .IP "\(bu" 4 -\fBprint_only_version_number\fR (\fBBUNDLE_PRINT_ONLY_VERSION_NUMBER\fR) Print only version number from \fBbundler \-\-version\fR\. +\fBprint_only_version_number\fR (\fBBUNDLE_PRINT_ONLY_VERSION_NUMBER\fR): Print only version number from \fBbundler \-\-version\fR\. . .IP "\(bu" 4 \fBredirect\fR (\fBBUNDLE_REDIRECT\fR): The number of redirects allowed for network requests\. Defaults to \fB5\fR\. @@ -283,7 +277,7 @@ The following is a list of all configuration keys and their purpose\. You can le \fBunlock_source_unlocks_spec\fR (\fBBUNDLE_UNLOCK_SOURCE_UNLOCKS_SPEC\fR): Whether running \fBbundle update \-\-source NAME\fR unlocks a gem with the given name\. Defaults to \fBtrue\fR\. . .IP "\(bu" 4 -\fBupdate_requires_all_flag\fR (\fBBUNDLE_UPDATE_REQUIRES_ALL_FLAG\fR) Require passing \fB\-\-all\fR to \fBbundle update\fR when everything should be updated, and disallow passing no options to \fBbundle update\fR\. +\fBupdate_requires_all_flag\fR (\fBBUNDLE_UPDATE_REQUIRES_ALL_FLAG\fR): Require passing \fB\-\-all\fR to \fBbundle update\fR when everything should be updated, and disallow passing no options to \fBbundle update\fR\. . .IP "\(bu" 4 \fBuser_agent\fR (\fBBUNDLE_USER_AGENT\fR): The custom user agent fragment Bundler includes in API requests\. diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index b3c4e59a78..81d0603e8b 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -47,10 +47,6 @@ configuration only from the local application. Executing bundle with the `BUNDLE_IGNORE_CONFIG` environment variable set will cause it to ignore all configuration. -Executing `bundle config set --local disable_multisource true` upgrades the warning about -the Gemfile containing multiple primary sources to an error. Executing `bundle -config unset disable_multisource` downgrades this error to a warning. - ## REMEMBERING OPTIONS Flags passed to `bundle install` or the Bundler runtime, such as `--path foo` or @@ -178,10 +174,6 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). * `disable_local_revision_check` (`BUNDLE_DISABLE_LOCAL_REVISION_CHECK`): Allow Bundler to use a local git override without checking if the revision present in the lockfile is present in the repository. -* `disable_multisource` (`BUNDLE_DISABLE_MULTISOURCE`): - When set, Gemfiles containing multiple sources will produce errors - instead of warnings. - Use `bundle config unset disable_multisource` to unset. * `disable_shared_gems` (`BUNDLE_DISABLE_SHARED_GEMS`): Stop Bundler from accessing gems installed to RubyGems' normal location. * `disable_version_check` (`BUNDLE_DISABLE_VERSION_CHECK`): @@ -206,13 +198,14 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). * `global_gem_cache` (`BUNDLE_GLOBAL_GEM_CACHE`): Whether Bundler should cache all gems globally, rather than locally to the installing Ruby installation. -* `ignore_messages` (`BUNDLE_IGNORE_MESSAGES`): When set, no post install - messages will be printed. To silence a single gem, use dot notation like - `ignore_messages.httparty true`. -* `init_gems_rb` (`BUNDLE_INIT_GEMS_RB`) +* `ignore_messages` (`BUNDLE_IGNORE_MESSAGES`): + When set, no post install messages will be printed. To silence a single gem, + use dot notation like `ignore_messages.httparty true`. +* `init_gems_rb` (`BUNDLE_INIT_GEMS_RB`): Generate a `gems.rb` instead of a `Gemfile` when running `bundle init`. * `jobs` (`BUNDLE_JOBS`): - The number of gems Bundler can install in parallel. Defaults to 1. + The number of gems Bundler can install in parallel. Defaults to 1 on Windows, + and to the the number of processors on other platforms. * `no_install` (`BUNDLE_NO_INSTALL`): Whether `bundle package` should skip installing gems. * `no_prune` (`BUNDLE_NO_PRUNE`): @@ -233,7 +226,7 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). Enable Bundler's experimental plugin system. * `prefer_patch` (BUNDLE_PREFER_PATCH): Prefer updating only to next patch version during updates. Makes `bundle update` calls equivalent to `bundler update --patch`. -* `print_only_version_number` (`BUNDLE_PRINT_ONLY_VERSION_NUMBER`) +* `print_only_version_number` (`BUNDLE_PRINT_ONLY_VERSION_NUMBER`): Print only version number from `bundler --version`. * `redirect` (`BUNDLE_REDIRECT`): The number of redirects allowed for network requests. Defaults to `5`. @@ -269,7 +262,7 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). * `unlock_source_unlocks_spec` (`BUNDLE_UNLOCK_SOURCE_UNLOCKS_SPEC`): Whether running `bundle update --source NAME` unlocks a gem with the given name. Defaults to `true`. -* `update_requires_all_flag` (`BUNDLE_UPDATE_REQUIRES_ALL_FLAG`) +* `update_requires_all_flag` (`BUNDLE_UPDATE_REQUIRES_ALL_FLAG`): Require passing `--all` to `bundle update` when everything should be updated, and disallow passing no options to `bundle update`. * `user_agent` (`BUNDLE_USER_AGENT`): diff --git a/lib/bundler/plugin.rb b/lib/bundler/plugin.rb index da3f468da5..dddb468582 100644 --- a/lib/bundler/plugin.rb +++ b/lib/bundler/plugin.rb @@ -105,6 +105,7 @@ module Bundler else builder.eval_gemfile(gemfile) end + builder.check_primary_source_safety definition = builder.to_definition(nil, true) return if definition.dependencies.empty? diff --git a/lib/bundler/plugin/installer.rb b/lib/bundler/plugin/installer.rb index 26cec4f18c..73198aec04 100644 --- a/lib/bundler/plugin/installer.rb +++ b/lib/bundler/plugin/installer.rb @@ -16,15 +16,13 @@ module Bundler version = options[:version] || [">= 0"] - Bundler.settings.temporary(:disable_multisource => false) do - if options[:git] - install_git(names, version, options) - elsif options[:local_git] - install_local_git(names, version, options) - else - sources = options[:source] || Bundler.rubygems.sources - install_rubygems(names, version, sources) - end + if options[:git] + install_git(names, version, options) + elsif options[:local_git] + install_local_git(names, version, options) + else + sources = options[:source] || Bundler.rubygems.sources + install_rubygems(names, version, sources) end end @@ -84,6 +82,7 @@ module Bundler deps = names.map {|name| Dependency.new name, version } definition = Definition.new(nil, deps, source_list, true) + definition.allow_multisource! install_definition(definition) end diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 0f17ba3afb..0c11c83b72 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -17,15 +17,14 @@ module Bundler # ==== Returns # <GemBundle>,nil:: If the list of dependencies can be resolved, a # collection of gemspecs is returned. Otherwise, nil is returned. - def self.resolve(requirements, index, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil) + def self.resolve(requirements, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil) base = SpecSet.new(base) unless base.is_a?(SpecSet) - resolver = new(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) + resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) result = resolver.start(requirements) SpecSet.new(result) end - def initialize(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) - @index = index + def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) @source_requirements = source_requirements @base = base @resolver = Molinillo::Resolver.new(self, self) @@ -36,14 +35,14 @@ module Bundler @base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true) end additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) } - @platforms = platforms + @platforms = platforms.reject {|p| p != Gem::Platform::RUBY && (platforms - [p]).any? {|pl| generic(pl) == p } } @resolving_only_for_ruby = platforms == [Gem::Platform::RUBY] @gem_version_promoter = gem_version_promoter @use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major? - @lockfile_uses_separate_rubygems_sources = Bundler.feature_flag.disable_multisource? + @no_aggregate_global_source = @source_requirements[:global].nil? @variant_specific_names = [] - @generic_names = [] + @generic_names = ["Ruby\0", "RubyGems\0"] end def start(requirements) @@ -125,8 +124,7 @@ module Bundler dependency = dependency_proxy.dep name = dependency.name search_result = @search_for[dependency_proxy] ||= begin - index = index_for(dependency) - results = index.search(dependency, @base[name]) + results = results_for(dependency, @base[name]) if vertex = @base_dg.vertex_named(name) locked_requirement = vertex.payload.requirement @@ -195,23 +193,26 @@ module Bundler search_result end - def index_for(dependency) + def index_for(dependency, base) source = @source_requirements[dependency.name] if source source.specs - elsif @lockfile_uses_separate_rubygems_sources - Index.build do |idx| - if dependency.all_sources - dependency.all_sources.each {|s| idx.add_source(s.specs) if s } - else - idx.add_source @source_requirements[:default].specs - end + elsif @no_aggregate_global_source + dependency.all_sources.find(-> { Index.new }) do |s| + idx = s.specs + results = idx.search(dependency, base) + next if results.empty? || results == base + return idx end else - @index + @source_requirements[:global] end end + def results_for(dependency, base) + index_for(dependency, base).search(dependency, base) + end + def name_for(dependency) dependency.name end @@ -238,11 +239,13 @@ module Bundler def relevant_sources_for_vertex(vertex) if vertex.root? - [@source_requirements[vertex.name]] - elsif @lockfile_uses_separate_rubygems_sources + [@source_requirements[vertex.name]].compact + elsif @no_aggregate_global_source vertex.recursive_predecessors.map do |v| @source_requirements[v.name] - end << @source_requirements[:default] + end.compact << @source_requirements[:default] + else + [] end end @@ -283,7 +286,7 @@ module Bundler if (base = @base[dependency.name]) && !base.empty? dependency.requirement.satisfied_by?(base.first.version) ? 0 : 1 else - all = index_for(dependency).search(dependency.name).size + all = index_for(dependency, base).search(dependency.name).size if all <= 1 all - 1_000_000 @@ -326,7 +329,7 @@ module Bundler "The source does not contain any versions of '#{name}'" end else - message = "Could not find gem '#{requirement}' in any of the gem sources " \ + message = "Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in any of the gem sources " \ "listed in your Gemfile#{cache_message}." end raise GemNotFound, message @@ -411,14 +414,8 @@ module Bundler relevant_sources = if conflict.requirement.source [conflict.requirement.source] - elsif conflict.requirement.all_sources - conflict.requirement.all_sources - elsif @lockfile_uses_separate_rubygems_sources - # every conflict should have an explicit group of sources when we - # enforce strict pinning - raise "no source set for #{conflict}" else - [] + conflict.requirement.all_sources end.compact.map(&:to_s).uniq.sort metadata_requirement = name.end_with?("\0") @@ -455,7 +452,8 @@ module Bundler def validate_resolved_specs!(resolved_specs) resolved_specs.each do |v| name = v.name - next unless sources = relevant_sources_for_vertex(v) + sources = relevant_sources_for_vertex(v) + next unless sources.any? sources.compact! if default_index = sources.index(@source_requirements[:default]) sources.delete_at(default_index) @@ -464,14 +462,12 @@ module Bundler sources.uniq! next if sources.size <= 1 - multisource_disabled = Bundler.feature_flag.disable_multisource? - msg = ["The gem '#{name}' was found in multiple relevant sources."] msg.concat sources.map {|s| " * #{s}" }.sort - msg << "You #{multisource_disabled ? :must : :should} add this gem to the source block for the source you wish it to be installed from." + msg << "You #{@no_aggregate_global_source ? :must : :should} add this gem to the source block for the source you wish it to be installed from." msg = msg.join("\n") - raise SecurityError, msg if multisource_disabled + raise SecurityError, msg if @no_aggregate_global_source Bundler.ui.warn "Warning: #{msg}" end end diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index 749e4eb60e..ceb2fde32c 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -20,7 +20,6 @@ module Bundler disable_exec_load disable_local_branch_check disable_local_revision_check - disable_multisource disable_shared_gems disable_version_check force_ruby_platform diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index 5b89b1645d..1b4bccadb8 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -21,6 +21,7 @@ module Bundler @allow_remote = false @allow_cached = false @caches = [cache_path, *Bundler.rubygems.gem_cache] + @disable_multisource = true Array(options["remotes"] || []).reverse_each {|r| add_remote(r) } end @@ -49,8 +50,16 @@ module Bundler o.is_a?(Rubygems) && (o.credless_remotes - credless_remotes).empty? end + def disable_multisource? + @disable_multisource + end + + def allow_multisource! + @disable_multisource = false + end + def can_lock?(spec) - return super if Bundler.feature_flag.disable_multisource? + return super if disable_multisource? spec.source.is_a?(Rubygems) end diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb index 436891256d..4ba6415448 100644 --- a/lib/bundler/source_list.rb +++ b/lib/bundler/source_list.rb @@ -5,24 +5,41 @@ module Bundler attr_reader :path_sources, :git_sources, :plugin_sources, - :global_rubygems_source, - :metadata_source + :global_path_source, + :metadata_source, + :disable_multisource + + def global_rubygems_source + @global_rubygems_source ||= rubygems_aggregate_class.new + end def initialize @path_sources = [] @git_sources = [] @plugin_sources = [] @global_rubygems_source = nil - @rubygems_aggregate = rubygems_aggregate_class.new + @global_path_source = nil @rubygems_sources = [] @metadata_source = Source::Metadata.new + @disable_multisource = true + end + + def disable_multisource? + @disable_multisource + end + + def allow_multisource! + rubygems_sources.map(&:allow_multisource!) + @disable_multisource = false end def add_path_source(options = {}) if options["gemspec"] add_source_to_list Source::Gemspec.new(options), path_sources else - add_source_to_list Source::Path.new(options), path_sources + path_source = add_source_to_list Source::Path.new(options), path_sources + @global_path_source ||= path_source if options["global"] + path_source end end @@ -41,24 +58,20 @@ module Bundler end def global_rubygems_source=(uri) - if Bundler.feature_flag.disable_multisource? - @global_rubygems_source ||= rubygems_aggregate_class.new("remotes" => uri) - end - add_rubygems_remote(uri) + @global_rubygems_source ||= rubygems_aggregate_class.new("remotes" => uri) end def add_rubygems_remote(uri) - return if Bundler.feature_flag.disable_multisource? - @rubygems_aggregate.add_remote(uri) - @rubygems_aggregate + global_rubygems_source.add_remote(uri) + global_rubygems_source end def default_source - global_rubygems_source || @rubygems_aggregate + global_path_source || global_rubygems_source end def rubygems_sources - @rubygems_sources + [default_source] + @rubygems_sources + [global_rubygems_source] end def rubygems_remotes @@ -75,7 +88,7 @@ module Bundler def lock_sources lock_sources = (path_sources + git_sources + plugin_sources).sort_by(&:to_s) - if Bundler.feature_flag.disable_multisource? + if disable_multisource? lock_sources + rubygems_sources.sort_by(&:to_s) else lock_sources << combine_rubygems_sources @@ -92,9 +105,9 @@ module Bundler end end - replacement_rubygems = !Bundler.feature_flag.disable_multisource? && + replacement_rubygems = !disable_multisource? && replacement_sources.detect {|s| s.is_a?(Source::Rubygems) } - @rubygems_aggregate = replacement_rubygems if replacement_rubygems + @global_rubygems_source = replacement_rubygems if replacement_rubygems return true if !equal_sources?(lock_sources, replacement_sources) && !equivalent_sources?(lock_sources, replacement_sources) return true if replacement_rubygems && rubygems_remotes.sort_by(&:to_s) != replacement_rubygems.remotes.sort_by(&:to_s) @@ -110,10 +123,6 @@ module Bundler all_sources.each(&:remote!) end - def rubygems_primary_remotes - @rubygems_aggregate.remotes - end - private def rubygems_aggregate_class @@ -136,7 +145,9 @@ module Bundler end def combine_rubygems_sources - Source::Rubygems.new("remotes" => rubygems_remotes) + aggregate_source = Source::Rubygems.new("remotes" => rubygems_remotes) + aggregate_source.allow_multisource! unless disable_multisource? + aggregate_source end def warn_on_git_protocol(source) diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index f9569c8f78..0ddfa668cd 100644 --- a/lib/bundler/version.rb +++ b/lib/bundler/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module Bundler - VERSION = "2.2.9".freeze + VERSION = "2.2.10".freeze def self.bundler_major_version @bundler_major_version ||= VERSION.split(".").first.to_i diff --git a/lib/rubygems.rb b/lib/rubygems.rb index 41b1353e1f..22fe0366b2 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -8,7 +8,7 @@ require 'rbconfig' module Gem - VERSION = "3.2.9".freeze + VERSION = "3.2.10".freeze end # Must be first since it unloads the prelude from 1.9.2 diff --git a/lib/rubygems/command.rb b/lib/rubygems/command.rb index bf55ce3205..9f935e6285 100644 --- a/lib/rubygems/command.rb +++ b/lib/rubygems/command.rb @@ -634,6 +634,7 @@ RubyGems is a package manager for Ruby. gem install rake gem list --local gem build package.gemspec + gem push package-0.0.1.gem gem help install Further help: diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 73062afe53..6b569032ba 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -666,6 +666,9 @@ class Gem::Specification < Gem::BasicSpecification # # # Only prereleases or final releases after 2.6.0.preview2 # spec.required_ruby_version = '> 2.6.0.preview2' + # + # # This gem will work with 2.3.0 or greater, including major version 3, but lesser than 4.0.0 + # spec.required_ruby_version = '>= 2.3', '< 4' def required_ruby_version=(req) @required_ruby_version = Gem::Requirement.create req diff --git a/spec/bundler/bundler/dsl_spec.rb b/spec/bundler/bundler/dsl_spec.rb index ff87b57886..a47dd6e399 100644 --- a/spec/bundler/bundler/dsl_spec.rb +++ b/spec/bundler/bundler/dsl_spec.rb @@ -25,7 +25,7 @@ RSpec.describe Bundler::Dsl do expect { subject.git_source(:example) }.to raise_error(Bundler::InvalidOption) end - context "default hosts", :bundler => "2" do + context "default hosts", :bundler => "< 3" do it "converts :github to URI using https" do subject.gem("sparks", :github => "indirect/sparks") github_uri = "https://github.com/indirect/sparks.git" @@ -195,19 +195,6 @@ RSpec.describe Bundler::Dsl do # gem 'spree_api' # gem 'spree_backend' # end - describe "#github", :bundler => "< 3" do - it "from github" do - spree_gems = %w[spree_core spree_api spree_backend] - subject.github "spree" do - spree_gems.each {|spree_gem| subject.send :gem, spree_gem } - end - - subject.dependencies.each do |d| - expect(d.source.uri).to eq("https://github.com/spree/spree.git") - end - end - end - describe "#github" do it "from github" do spree_gems = %w[spree_core spree_api spree_backend] diff --git a/spec/bundler/bundler/plugin_spec.rb b/spec/bundler/bundler/plugin_spec.rb index 8c95723bcc..d18896895e 100644 --- a/spec/bundler/bundler/plugin_spec.rb +++ b/spec/bundler/bundler/plugin_spec.rb @@ -112,6 +112,7 @@ RSpec.describe Bundler::Plugin do before do allow(Plugin::DSL).to receive(:new) { builder } allow(builder).to receive(:eval_gemfile).with(gemfile) + allow(builder).to receive(:check_primary_source_safety) allow(builder).to receive(:to_definition) { definition } allow(builder).to receive(:inferred_plugins) { [] } end diff --git a/spec/bundler/bundler/source_list_spec.rb b/spec/bundler/bundler/source_list_spec.rb index 3a0691b959..0c40ba8a77 100644 --- a/spec/bundler/bundler/source_list_spec.rb +++ b/spec/bundler/bundler/source_list_spec.rb @@ -372,26 +372,7 @@ RSpec.describe Bundler::SourceList do source_list.add_git_source("uri" => "git://first-git.org/path.git") end - it "combines the rubygems sources into a single instance, removing duplicate remotes from the end", :bundler => "< 3" do - expect(source_list.lock_sources).to eq [ - Bundler::Source::Git.new("uri" => "git://first-git.org/path.git"), - Bundler::Source::Git.new("uri" => "git://second-git.org/path.git"), - Bundler::Source::Git.new("uri" => "git://third-git.org/path.git"), - ASourcePlugin.new("uri" => "https://second-plugin.org/random"), - ASourcePlugin.new("uri" => "https://third-bar.org/foo"), - Bundler::Source::Path.new("path" => "/first/path/to/gem"), - Bundler::Source::Path.new("path" => "/second/path/to/gem"), - Bundler::Source::Path.new("path" => "/third/path/to/gem"), - Bundler::Source::Rubygems.new("remotes" => [ - "https://duplicate-rubygems.org", - "https://first-rubygems.org", - "https://second-rubygems.org", - "https://third-rubygems.org", - ]), - ] - end - - it "returns all sources, without combining rubygems sources", :bundler => "3" do + it "returns all sources, without combining rubygems sources" do expect(source_list.lock_sources).to eq [ Bundler::Source::Git.new("uri" => "git://first-git.org/path.git"), Bundler::Source::Git.new("uri" => "git://second-git.org/path.git"), diff --git a/spec/bundler/commands/exec_spec.rb b/spec/bundler/commands/exec_spec.rb index 5d43586116..bb4091ef98 100644 --- a/spec/bundler/commands/exec_spec.rb +++ b/spec/bundler/commands/exec_spec.rb @@ -762,7 +762,8 @@ RSpec.describe "bundle exec" do let(:exit_code) { Bundler::GemNotFound.new.status_code } let(:expected) { "" } let(:expected_err) { <<-EOS.strip } -\e[31mCould not find gem 'rack (= 2)' in any of the gem sources listed in your Gemfile.\e[0m +\e[31mCould not find gem 'rack (= 2)' in locally installed gems. +The source contains the following versions of 'rack': 0.9.1, 1.0.0\e[0m \e[33mRun `bundle install` to install missing gems.\e[0m EOS diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb index 44bde4a9b8..7724170a63 100644 --- a/spec/bundler/commands/lock_spec.rb +++ b/spec/bundler/commands/lock_spec.rb @@ -491,6 +491,51 @@ RSpec.describe "bundle lock" do end end + it "does not conflict on ruby requirements when adding new platforms" do + next_minor = Gem.ruby_version.segments[0..1].map.with_index {|s, i| i == 1 ? s + 1 : s }.join(".") + + build_repo4 do + build_gem "raygun-apm", "1.0.78" do |s| + s.platform = "x86_64-linux" + s.required_ruby_version = "< #{next_minor}.dev" + end + + build_gem "raygun-apm", "1.0.78" do |s| + s.platform = "universal-darwin" + s.required_ruby_version = "< #{next_minor}.dev" + end + + build_gem "raygun-apm", "1.0.78" do |s| + s.platform = "x64-mingw32" + s.required_ruby_version = "< #{next_minor}.dev" + end + end + + gemfile <<-G + source "https://localgemserver.test" + + gem "raygun-apm" + G + + lockfile <<-L + GEM + remote: https://localgemserver.test/ + specs: + raygun-apm (1.0.78-universal-darwin) + + PLATFORMS + x86_64-darwin-19 + + DEPENDENCIES + raygun-apm + + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle "lock --add-platform x86_64-linux", :artifice => :compact_index, :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + end + context "when an update is available" do let(:repo) { gem_repo2 } diff --git a/spec/bundler/commands/post_bundle_message_spec.rb b/spec/bundler/commands/post_bundle_message_spec.rb index 2c965f0ddd..3f81808980 100644 --- a/spec/bundler/commands/post_bundle_message_spec.rb +++ b/spec/bundler/commands/post_bundle_message_spec.rb @@ -113,16 +113,7 @@ RSpec.describe "post bundle message" do bundle "config set force_ruby_platform true" end - it "should report a helpful error message", :bundler => "< 3" do - install_gemfile <<-G, :raise_on_error => false - source "#{file_uri_for(gem_repo1)}" - gem "rack" - gem "not-a-gem", :group => :development - G - expect(err).to include("Could not find gem 'not-a-gem' in any of the gem sources listed in your Gemfile.") - end - - it "should report a helpful error message", :bundler => "3" do + it "should report a helpful error message" do install_gemfile <<-G, :raise_on_error => false source "#{file_uri_for(gem_repo1)}" gem "rack" diff --git a/spec/bundler/install/gemfile/gemspec_spec.rb b/spec/bundler/install/gemfile/gemspec_spec.rb index 7a95a8abde..4001df26da 100644 --- a/spec/bundler/install/gemfile/gemspec_spec.rb +++ b/spec/bundler/install/gemfile/gemspec_spec.rb @@ -422,14 +422,13 @@ RSpec.describe "bundle install from an existing gemspec" do end end - %w[ruby jruby].each do |platform| - simulate_platform(platform) do - install_gemfile <<-G - source "#{file_uri_for(gem_repo2)}" - gemspec - G - end - end + gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gemspec + G + + simulate_platform("ruby") { bundle "install" } + simulate_platform("jruby") { bundle "install" } end context "on ruby" do diff --git a/spec/bundler/install/gemfile/platform_spec.rb b/spec/bundler/install/gemfile/platform_spec.rb index 8ab59abeeb..9b4bbba016 100644 --- a/spec/bundler/install/gemfile/platform_spec.rb +++ b/spec/bundler/install/gemfile/platform_spec.rb @@ -88,14 +88,15 @@ RSpec.describe "bundle install across platforms" do simulate_new_machine simulate_platform "ruby" - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - - gem "nokogiri" - G + bundle "install" expect(the_bundle).to include_gems "nokogiri 1.4.2" expect(the_bundle).not_to include_gems "weakling" + + simulate_platform "java" + bundle "install" + + expect(the_bundle).to include_gems "nokogiri 1.4.2 JAVA", "weakling 0.0.3" end it "does not keep unneeded platforms for gems that are used" do @@ -241,20 +242,6 @@ RSpec.describe "bundle install across platforms" do end end - it "works the other way with gems that have different dependencies" do - simulate_platform "ruby" - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - - gem "nokogiri" - G - - simulate_platform "java" - bundle "install" - - expect(the_bundle).to include_gems "nokogiri 1.4.2 JAVA", "weakling 0.0.3" - end - it "works with gems with platform-specific dependency having different requirements order" do simulate_platform x64_mac diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index 655f91dd69..e40ae84c59 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -27,7 +27,7 @@ RSpec.describe "bundle install with gems on multiple sources" do G end - it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first", :bundler => "2" do + it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first", :bundler => "< 3" do bundle :install expect(err).to include("Warning: the gem 'rack' was found in multiple sources.") @@ -54,7 +54,7 @@ RSpec.describe "bundle install with gems on multiple sources" do G end - it "warns about ambiguous gems, but installs anyway", :bundler => "2" do + it "warns about ambiguous gems, but installs anyway", :bundler => "< 3" do bundle :install expect(err).to include("Warning: the gem 'rack' was found in multiple sources.") expect(err).to include("Installed from: #{file_uri_for(gem_repo1)}") @@ -96,7 +96,7 @@ RSpec.describe "bundle install with gems on multiple sources" do it "installs the gems without any warning" do bundle :install - expect(out).not_to include("Warning") + expect(err).not_to include("Warning") expect(the_bundle).to include_gems("rack-obama 1.0.0") expect(the_bundle).to include_gems("rack 1.0.0", :source => "remote1") end @@ -128,7 +128,7 @@ RSpec.describe "bundle install with gems on multiple sources" do end end - gemfile <<-G + install_gemfile <<-G source "#{file_uri_for(gem_repo3)}" gem "rack-obama" # should come from repo3! gem "rack", :source => "#{file_uri_for(gem_repo1)}" @@ -136,8 +136,7 @@ RSpec.describe "bundle install with gems on multiple sources" do end it "installs the gems without any warning" do - bundle :install - expect(out).not_to include("Warning") + expect(err).not_to include("Warning") expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0") end end @@ -173,8 +172,8 @@ RSpec.describe "bundle install with gems on multiple sources" do it "installs from the same source without any warning" do bundle :install - expect(out).not_to include("Warning") - expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") + expect(err).not_to include("Warning") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3") end end @@ -188,27 +187,38 @@ RSpec.describe "bundle install with gems on multiple sources" do end end - context "when disable_multisource is set" do - before do - bundle "config set disable_multisource true" - end + it "installs from the same source without any warning" do + bundle :install - it "installs from the same source without any warning" do - bundle :install + expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3") - expect(out).not_to include("Warning: the gem 'rack' was found in multiple sources.") - expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") - expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") + # In https://github.com/bundler/bundler/issues/3585 this failed + # when there is already a lock file, and the gems are missing, so try again + system_gems [] + bundle :install - # when there is already a lock file, and the gems are missing, so try again - system_gems [] - bundle :install + expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3") + end + end - expect(out).not_to include("Warning: the gem 'rack' was found in multiple sources.") - expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") - expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") + context "and in another source with a higher version" do + before do + # need this to be broken to check for correct source ordering + build_repo gem_repo2 do + build_gem "rack", "1.0.1" do |s| + s.write "lib/rack.rb", "RACK = 'FAIL'" + end end end + + it "installs from the same source without any warning" do + bundle :install + + expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3") + end end end @@ -222,7 +232,7 @@ RSpec.describe "bundle install with gems on multiple sources" do context "and not in any other sources" do before do - gemfile <<-G + install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" source "#{file_uri_for(gem_repo3)}" do gem "depends_on_rack" @@ -231,8 +241,7 @@ RSpec.describe "bundle install with gems on multiple sources" do end it "installs from the other source without any warning" do - bundle :install - expect(out).not_to include("Warning") + expect(err).not_to include("Warning") expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") end end @@ -248,7 +257,7 @@ RSpec.describe "bundle install with gems on multiple sources" do G end - it "installs from the other source and warns about ambiguous gems", :bundler => "2" do + it "installs from the other source and warns about ambiguous gems", :bundler => "< 3" do bundle :install expect(err).to include("Warning: the gem 'rack' was found in multiple sources.") expect(err).to include("Installed from: #{file_uri_for(gem_repo2)}") @@ -280,7 +289,7 @@ RSpec.describe "bundle install with gems on multiple sources" do G end - it "installs the dependency from the pinned source without warning", :bundler => "2" do + it "installs the dependency from the pinned source without warning", :bundler => "< 3" do bundle :install expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") @@ -305,80 +314,74 @@ RSpec.describe "bundle install with gems on multiple sources" do end context "when a top-level gem has an indirect dependency" do - context "when disable_multisource is set" do - before do - bundle "config set disable_multisource true" - end - - before do - build_repo gem_repo2 do - build_gem "depends_on_rack", "1.0.1" do |s| - s.add_dependency "rack" - end - end - - build_repo gem_repo3 do - build_gem "unrelated_gem", "1.0.0" + before do + build_repo gem_repo2 do + build_gem "depends_on_rack", "1.0.1" do |s| + s.add_dependency "rack" end + end - gemfile <<-G - source "#{file_uri_for(gem_repo2)}" + build_repo gem_repo3 do + build_gem "unrelated_gem", "1.0.0" + end - gem "depends_on_rack" + gemfile <<-G + source "#{file_uri_for(gem_repo2)}" - source "#{file_uri_for(gem_repo3)}" do - gem "unrelated_gem" - end - G - end + gem "depends_on_rack" - context "and the dependency is only in the top-level source" do - before do - update_repo gem_repo2 do - build_gem "rack", "1.0.0" - end + source "#{file_uri_for(gem_repo3)}" do + gem "unrelated_gem" end + G + end - it "installs all gems without warning" do - bundle :install - expect(err).not_to include("Warning") - expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0") + context "and the dependency is only in the top-level source" do + before do + update_repo gem_repo2 do + build_gem "rack", "1.0.0" end end - context "and the dependency is only in a pinned source" do - before do - update_repo gem_repo3 do - build_gem "rack", "1.0.0" do |s| - s.write "lib/rack.rb", "RACK = 'FAIL'" - end + it "installs all gems without warning" do + bundle :install + expect(err).not_to include("Warning") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0") + end + end + + context "and the dependency is only in a pinned source" do + before do + update_repo gem_repo3 do + build_gem "rack", "1.0.0" do |s| + s.write "lib/rack.rb", "RACK = 'FAIL'" end end + end - it "does not find the dependency" do - bundle :install, :raise_on_error => false - expect(err).to include("Could not find gem 'rack', which is required by gem 'depends_on_rack', in any of the relevant sources") - end + it "does not find the dependency" do + bundle :install, :raise_on_error => false + expect(err).to include("Could not find gem 'rack', which is required by gem 'depends_on_rack', in any of the relevant sources") end + end - context "and the dependency is in both the top-level and a pinned source" do - before do - update_repo gem_repo2 do - build_gem "rack", "1.0.0" - end + context "and the dependency is in both the top-level and a pinned source" do + before do + update_repo gem_repo2 do + build_gem "rack", "1.0.0" + end - update_repo gem_repo3 do - build_gem "rack", "1.0.0" do |s| - s.write "lib/rack.rb", "RACK = 'FAIL'" - end + update_repo gem_repo3 do + build_gem "rack", "1.0.0" do |s| + s.write "lib/rack.rb", "RACK = 'FAIL'" end end + end - it "installs the dependency from the top-level source without warning" do - bundle :install - expect(err).not_to include("Warning") - expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0") - end + it "installs the dependency from the top-level source without warning" do + bundle :install + expect(err).not_to include("Warning") + expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0") end end end @@ -389,15 +392,14 @@ RSpec.describe "bundle install with gems on multiple sources" do build_gem "not_in_repo1", "1.0.0" end - gemfile <<-G + install_gemfile <<-G, :raise_on_error => false source "#{file_uri_for(gem_repo3)}" gem "not_in_repo1", :source => "#{file_uri_for(gem_repo1)}" G end it "does not install the gem" do - bundle :install, :raise_on_error => false - expect(err).to include("Could not find gem 'not_in_repo1'") + expect(err).to include("Could not find gem 'not_in_repo1") end end @@ -433,6 +435,92 @@ RSpec.describe "bundle install with gems on multiple sources" do end end + context "with a lockfile with aggregated rubygems sources" do + let(:aggregate_gem_section_lockfile) do + <<~L + GEM + remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo3)}/ + specs: + rack (0.9.1) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + rack! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + let(:split_gem_section_lockfile) do + <<~L + GEM + remote: #{file_uri_for(gem_repo1)}/ + specs: + + GEM + remote: #{file_uri_for(gem_repo3)}/ + specs: + rack (0.9.1) + + PLATFORMS + #{specific_local_platform} + + DEPENDENCIES + rack! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + before do + build_repo gem_repo3 do + build_gem "rack", "0.9.1" + end + + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo3)}" do + gem 'rack' + end + G + + lockfile aggregate_gem_section_lockfile + end + + it "installs a lockfile with separate rubygems source sections if not in frozen mode" do + bundle "install" + + expect(lockfile).to eq(split_gem_section_lockfile) + + expect(the_bundle).to include_gems("rack 0.9.1", :source => "remote3") + end + + it "installs the existing lockfile but prints a warning if in frozen mode", :bundler => "< 3" do + bundle "config set --local deployment true" + + bundle "install" + + expect(lockfile).to eq(aggregate_gem_section_lockfile) + + expect(the_bundle).to include_gems("rack 0.9.1", :source => "remote3") + end + + it "refuses to install the existing lockfile and prints an error if in frozen mode", :bundler => "3" do + bundle "config set --local deployment true" + + bundle "install", :raise_on_error =>false + + expect(lockfile).to eq(aggregate_gem_section_lockfile) + expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.") + expect(out).to be_empty + end + end + context "with a path gem in the same Gemfile" do before do build_lib "foo" @@ -457,14 +545,13 @@ RSpec.describe "bundle install with gems on multiple sources" do before do system_gems "rack-0.9.1" - gemfile <<-G + install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" gem "rack" # shoud come from repo1! G end it "installs the gems without any warning" do - bundle :install expect(err).not_to include("Warning") expect(the_bundle).to include_gems("rack 1.0.0") end @@ -615,16 +702,12 @@ RSpec.describe "bundle install with gems on multiple sources" do G end - it "keeps the old version", :bundler => "2" do - expect(the_bundle).to include_gems("rack 1.0.0") - end - - it "installs the higher version in the new repo", :bundler => "3" do + it "installs the higher version in the new repo" do expect(the_bundle).to include_gems("rack 1.2") end end - context "when a gem is available from multiple ambiguous sources", :bundler => "3" do + context "when a gem is available from multiple ambiguous sources" do it "raises, suggesting a source block" do build_repo4 do build_gem "depends_on_rack" do |s| diff --git a/spec/bundler/install/gems/flex_spec.rb b/spec/bundler/install/gems/flex_spec.rb index 7ab0ded26d..326ec51214 100644 --- a/spec/bundler/install/gems/flex_spec.rb +++ b/spec/bundler/install/gems/flex_spec.rb @@ -245,37 +245,7 @@ RSpec.describe "bundle flex_install" do end describe "when adding a new source" do - it "updates the lockfile", :bundler => "< 3" do - build_repo2 - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - gem "rack" - G - install_gemfile <<-G - source "#{file_uri_for(gem_repo1)}" - source "#{file_uri_for(gem_repo2)}" - gem "rack" - G - - lockfile_should_be <<-L - GEM - remote: #{file_uri_for(gem_repo1)}/ - remote: #{file_uri_for(gem_repo2)}/ - specs: - rack (1.0.0) - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - rack - - BUNDLED WITH - #{Bundler::VERSION} - L - end - - it "updates the lockfile", :bundler => "3" do + it "updates the lockfile" do build_repo2 install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" diff --git a/spec/bundler/lock/lockfile_spec.rb b/spec/bundler/lock/lockfile_spec.rb index d3591cd62a..639ccb87ea 100644 --- a/spec/bundler/lock/lockfile_spec.rb +++ b/spec/bundler/lock/lockfile_spec.rb @@ -318,40 +318,7 @@ RSpec.describe "the lockfile format" do G end - it "generates a lockfile without credentials for a configured source", :bundler => "< 3" do - bundle "config set http://localgemserver.test/ user:pass" - - install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true) - source "http://localgemserver.test/" do - - end - - source "http://user:pass@othergemserver.test/" do - gem "rack-obama", ">= 1.0" - end - G - - lockfile_should_be <<-G - GEM - remote: http://localgemserver.test/ - remote: http://user:pass@othergemserver.test/ - specs: - rack (1.0.0) - rack-obama (1.0) - rack - - PLATFORMS - #{lockfile_platforms} - - DEPENDENCIES - rack-obama (>= 1.0)! - - BUNDLED WITH - #{Bundler::VERSION} - G - end - - it "generates a lockfile without credentials for a configured source", :bundler => "3" do + it "generates a lockfile without credentials for a configured source" do bundle "config set http://localgemserver.test/ user:pass" install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true) diff --git a/spec/bundler/other/major_deprecation_spec.rb b/spec/bundler/other/major_deprecation_spec.rb index d061ca7064..cb85b6c9cb 100644 --- a/spec/bundler/other/major_deprecation_spec.rb +++ b/spec/bundler/other/major_deprecation_spec.rb @@ -17,7 +17,7 @@ RSpec.describe "major deprecations" do bundle "exec ruby -e #{source.dump}" end - it "is deprecated in favor of .unbundled_env", :bundler => "2" do + it "is deprecated in favor of .unbundled_env", :bundler => "< 3" do expect(deprecations).to include \ "`Bundler.clean_env` has been deprecated in favor of `Bundler.unbundled_env`. " \ "If you instead want the environment before bundler was originally loaded, use `Bundler.original_env` " \ @@ -33,7 +33,7 @@ RSpec.describe "major deprecations" do bundle "exec ruby -e #{source.dump}" end - it "is deprecated in favor of .unbundled_env", :bundler => "2" do + it "is deprecated in favor of .unbundled_env", :bundler => "< 3" do expect(deprecations).to include( "`Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. " \ "If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env` " \ @@ -50,7 +50,7 @@ RSpec.describe "major deprecations" do bundle "exec ruby -e #{source.dump}" end - it "is deprecated in favor of .unbundled_system", :bundler => "2" do + it "is deprecated in favor of .unbundled_system", :bundler => "< 3" do expect(deprecations).to include( "`Bundler.clean_system` has been deprecated in favor of `Bundler.unbundled_system`. " \ "If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system` " \ @@ -67,7 +67,7 @@ RSpec.describe "major deprecations" do bundle "exec ruby -e #{source.dump}" end - it "is deprecated in favor of .unbundled_exec", :bundler => "2" do + it "is deprecated in favor of .unbundled_exec", :bundler => "< 3" do expect(deprecations).to include( "`Bundler.clean_exec` has been deprecated in favor of `Bundler.unbundled_exec`. " \ "If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec` " \ @@ -84,7 +84,7 @@ RSpec.describe "major deprecations" do bundle "exec ruby -e #{source.dump}" end - it "is deprecated in favor of .load", :bundler => "2" do + it "is deprecated in favor of .load", :bundler => "< 3" do expect(deprecations).to include "Bundler.environment has been removed in favor of Bundler.load (called at -e:1)" end @@ -109,7 +109,7 @@ RSpec.describe "major deprecations" do bundle "check --path vendor/bundle", :raise_on_error => false end - it "should print a deprecation warning", :bundler => "2" do + it "should print a deprecation warning", :bundler => "< 3" do expect(deprecations).to include( "The `--path` flag is deprecated because it relies on being " \ "remembered across bundler invocations, which bundler will no " \ @@ -118,7 +118,7 @@ RSpec.describe "major deprecations" do ) end - pending "should fail with a helpful error", :bundler => "3" + pending "fails with a helpful error", :bundler => "3" end context "bundle check --path=" do @@ -131,7 +131,7 @@ RSpec.describe "major deprecations" do bundle "check --path=vendor/bundle", :raise_on_error => false end - it "should print a deprecation warning", :bundler => "2" do + it "should print a deprecation warning", :bundler => "< 3" do expect(deprecations).to include( "The `--path` flag is deprecated because it relies on being " \ "remembered across bundler invocations, which bundler will no " \ @@ -140,7 +140,7 @@ RSpec.describe "major deprecations" do ) end - pending "should fail with a helpful error", :bundler => "3" + pending "fails with a helpful error", :bundler => "3" end context "bundle cache --all" do @@ -153,7 +153,7 @@ RSpec.describe "major deprecations" do bundle "cache --all", :raise_on_error => false end - it "should print a deprecation warning", :bundler => "2" do + it "should print a deprecation warning", :bundler => "< 3" do expect(deprecations).to include( "The `--all` flag is deprecated because it relies on being " \ "remembered across bundler invocations, which bundler will no " \ @@ -162,7 +162,7 @@ RSpec.describe "major deprecations" do ) end - pending "should fail with a helpful error", :bundler => "3" + pending "fails with a helpful error", :bundler => "3" end describe "bundle config" do @@ -292,7 +292,7 @@ RSpec.describe "major deprecations" do G end - it "should output a deprecation warning", :bundler => "2" do + it "should output a deprecation warning", :bundler => "< 3" do expect(deprecations).to include("The --binstubs option will be removed in favor of `bundle binstubs --all`") end @@ -356,7 +356,7 @@ RSpec.describe "major deprecations" do bundle "install #{flag_name} #{value}" end - it "should print a deprecation warning", :bundler => "2" do + it "should print a deprecation warning", :bundler => "< 3" do expect(deprecations).to include( "The `#{flag_name}` flag is deprecated because it relies on " \ "being remembered across bundler invocations, which bundler " \ @@ -365,7 +365,7 @@ RSpec.describe "major deprecations" do ) end - pending "should fail with a helpful error", :bundler => "3" + pending "fails with a helpful error", :bundler => "3" end end end @@ -378,18 +378,58 @@ RSpec.describe "major deprecations" do G end - it "shows a deprecation", :bundler => "2" do + it "shows a deprecation", :bundler => "< 3" do expect(deprecations).to include( "Your Gemfile contains multiple primary sources. " \ "Using `source` more than once without a block is a security risk, and " \ "may result in installing unexpected gems. To resolve this warning, use " \ - "a block to indicate which gems should come from the secondary source. " \ - "To upgrade this warning to an error, run `bundle config set --local " \ - "disable_multisource true`." + "a block to indicate which gems should come from the secondary source." ) end - pending "should fail with a helpful error", :bundler => "3" + pending "fails with a helpful error", :bundler => "3" + end + + context "bundle install with a lockfile with a single rubygems section with multiple remotes in frozen mode" do + before do + build_repo gem_repo3 do + build_gem "rack", "0.9.1" + end + + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + source "#{file_uri_for(gem_repo3)}" do + gem 'rack' + end + G + + lockfile <<~L + GEM + remote: #{file_uri_for(gem_repo1)}/ + remote: #{file_uri_for(gem_repo3)}/ + specs: + rack (0.9.1) + + PLATFORMS + ruby + + DEPENDENCIES + rack! + + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle "config set --local deployment true" + end + + it "shows a deprecation", :bundler => "< 3" do + bundle "install" + + expect(deprecations).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. You should regenerate your lockfile in a non frozen environment.") + end + + pending "fails with a helpful error", :bundler => "3" end context "when Bundler.setup is run in a ruby script" do @@ -422,14 +462,14 @@ RSpec.describe "major deprecations" do RUBY end - it "should print a capistrano deprecation warning", :bundler => "2" do + it "should print a capistrano deprecation warning", :bundler => "< 3" do expect(deprecations).to include("Bundler no longer integrates " \ "with Capistrano, but Capistrano provides " \ "its own integration with Bundler via the " \ "capistrano-bundler gem. Use it instead.") end - pending "should fail with a helpful error", :bundler => "3" + pending "fails with a helpful error", :bundler => "3" end describe Bundler::Dsl do @@ -439,7 +479,7 @@ RSpec.describe "major deprecations" do end context "with github gems" do - it "does not warn about removal", :bundler => "2" do + it "does not warn about removal", :bundler => "< 3" do expect(Bundler.ui).not_to receive(:warn) subject.gem("sparks", :github => "indirect/sparks") github_uri = "https://github.com/indirect/sparks.git" @@ -461,7 +501,7 @@ The :github git source is deprecated, and will be removed in the future. Change end context "with bitbucket gems" do - it "does not warn about removal", :bundler => "2" do + it "does not warn about removal", :bundler => "< 3" do expect(Bundler.ui).not_to receive(:warn) subject.gem("not-really-a-gem", :bitbucket => "mcorp/flatlab-rails") end @@ -483,7 +523,7 @@ The :bitbucket git source is deprecated, and will be removed in the future. Add end context "with gist gems" do - it "does not warn about removal", :bundler => "2" do + it "does not warn about removal", :bundler => "< 3" do expect(Bundler.ui).not_to receive(:warn) subject.gem("not-really-a-gem", :gist => "1234") end @@ -514,7 +554,7 @@ The :gist git source is deprecated, and will be removed in the future. Add this bundle :show end - it "prints a deprecation warning recommending `bundle list`", :bundler => "2" do + it "prints a deprecation warning recommending `bundle list`", :bundler => "< 3" do expect(deprecations).to include("use `bundle list` instead of `bundle show`") end @@ -526,7 +566,7 @@ The :gist git source is deprecated, and will be removed in the future. Add this bundle "show --outdated" end - it "prints a deprecation warning informing about its removal", :bundler => "2" do + it "prints a deprecation warning informing about its removal", :bundler => "< 3" do expect(deprecations).to include("the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement") end @@ -538,7 +578,7 @@ The :gist git source is deprecated, and will be removed in the future. Add this bundle "show --verbose" end - it "prints a deprecation warning informing about its removal", :bundler => "2" do + it "prints a deprecation warning informing about its removal", :bundler => "< 3" do expect(deprecations).to include("the `--verbose` flag to `bundle show` was undocumented and will be removed without replacement") end @@ -550,7 +590,7 @@ The :gist git source is deprecated, and will be removed in the future. Add this bundle "show rack" end - it "prints a deprecation warning recommending `bundle info`", :bundler => "2" do + it "prints a deprecation warning recommending `bundle info`", :bundler => "< 3" do expect(deprecations).to include("use `bundle info rack` instead of `bundle show rack`") end @@ -562,7 +602,7 @@ The :gist git source is deprecated, and will be removed in the future. Add this bundle "show --paths" end - it "prints a deprecation warning recommending `bundle list`", :bundler => "2" do + it "prints a deprecation warning recommending `bundle list`", :bundler => "< 3" do expect(deprecations).to include("use `bundle list` instead of `bundle show --paths`") end @@ -574,7 +614,7 @@ The :gist git source is deprecated, and will be removed in the future. Add this bundle "show rack --paths" end - it "prints deprecation warning recommending `bundle info`", :bundler => "2" do + it "prints deprecation warning recommending `bundle info`", :bundler => "< 3" do expect(deprecations).to include("use `bundle info rack --path` instead of `bundle show rack --paths`") end @@ -587,7 +627,7 @@ The :gist git source is deprecated, and will be removed in the future. Add this bundle "console", :raise_on_error => false end - it "prints a deprecation warning", :bundler => "2" do + it "prints a deprecation warning", :bundler => "< 3" do expect(deprecations).to include \ "bundle console will be replaced by `bin/console` generated by `bundle gem <name>`" end @@ -603,7 +643,7 @@ The :gist git source is deprecated, and will be removed in the future. Add this bundle "viz" end - it "prints a deprecation warning", :bundler => "2" do + it "prints a deprecation warning", :bundler => "< 3" do expect(deprecations).to include "The `viz` command has been moved to the `bundle-viz` gem, see https://github.com/bundler/bundler-viz" end diff --git a/spec/bundler/resolver/platform_spec.rb b/spec/bundler/resolver/platform_spec.rb index 7169ba4b95..bc4081f8b5 100644 --- a/spec/bundler/resolver/platform_spec.rb +++ b/spec/bundler/resolver/platform_spec.rb @@ -28,6 +28,23 @@ RSpec.describe "Resolving platform craziness" do end end + it "resolves multiplatform gems with redundant platforms correctly" do + @index = build_index do + gem "zookeeper", "1.4.11" + gem "zookeeper", "1.4.11", "java" do + dep "slyphon-log4j", "= 1.2.15" + dep "slyphon-zookeeper_jar", "= 3.3.5" + end + gem "slyphon-log4j", "1.2.15" + gem "slyphon-zookeeper_jar", "3.3.5", "java" + end + + dep "zookeeper" + platforms "java", "ruby", "universal-java-11" + + should_resolve_as %w[zookeeper-1.4.11 zookeeper-1.4.11-java slyphon-log4j-1.2.15 slyphon-zookeeper_jar-3.3.5-java] + end + it "takes the latest ruby gem, even if an older platform specific version is available" do @index = build_index do gem "foo", "1.0.0" diff --git a/spec/bundler/runtime/platform_spec.rb b/spec/bundler/runtime/platform_spec.rb index f28b5ea16b..154d967e12 100644 --- a/spec/bundler/runtime/platform_spec.rb +++ b/spec/bundler/runtime/platform_spec.rb @@ -57,6 +57,89 @@ RSpec.describe "Bundler.setup with multi platform stuff" do expect(the_bundle).to include_gems "nokogiri 1.4.2" end + it "will keep both platforms when both ruby and a specific ruby platform are locked and the bundle is unlocked" do + build_repo4 do + build_gem "nokogiri", "1.11.1" do |s| + s.add_dependency "mini_portile2", "~> 2.5.0" + s.add_dependency "racc", "~> 1.4" + end + + build_gem "nokogiri", "1.11.1" do |s| + s.platform = Bundler.local_platform + s.add_dependency "racc", "~> 1.4" + end + + build_gem "mini_portile2", "2.5.0" + build_gem "racc", "1.5.2" + end + + good_lockfile = <<~L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + mini_portile2 (2.5.0) + nokogiri (1.11.1) + mini_portile2 (~> 2.5.0) + racc (~> 1.4) + nokogiri (1.11.1-#{Bundler.local_platform}) + racc (~> 1.4) + racc (1.5.2) + + PLATFORMS + ruby + #{Bundler.local_platform} + + DEPENDENCIES + nokogiri (~> 1.11) + + BUNDLED WITH + #{Bundler::VERSION} + L + + gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "nokogiri", "~> 1.11" + G + + lockfile good_lockfile + + bundle "update nokogiri" + + expect(lockfile).to eq(good_lockfile) + end + + it "will use the java platform if both generic java and generic ruby platforms are locked", :jruby do + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem "nokogiri" + G + + lockfile <<-G + GEM + remote: #{file_uri_for(gem_repo1)}/ + specs: + nokogiri (1.4.2) + nokogiri (1.4.2-java) + weakling (>= 0.0.3) + weakling (0.0.3) + + PLATFORMS + java + ruby + + DEPENDENCIES + nokogiri + + BUNDLED WITH + 2.1.4 + G + + bundle "install" + + expect(out).to include("Fetching nokogiri 1.4.2 (java)") + expect(the_bundle).to include_gems "nokogiri 1.4.2 JAVA" + end + it "will add the resolve for the current platform" do lockfile <<-G GEM diff --git a/spec/bundler/support/indexes.rb b/spec/bundler/support/indexes.rb index 45b68541f5..1f3c4ddaa6 100644 --- a/spec/bundler/support/indexes.rb +++ b/spec/bundler/support/indexes.rb @@ -30,7 +30,7 @@ module Spec args[1] ||= Bundler::GemVersionPromoter.new # gem_version_promoter args[2] ||= [] # additional_base_requirements args[3] ||= @platforms # platforms - Bundler::Resolver.resolve(deps, @index, source_requirements, *args) + Bundler::Resolver.resolve(deps, source_requirements, *args) end def should_resolve_as(specs) diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index 1c6d790b25..8b028d3495 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb @@ -1958,15 +1958,9 @@ class TestGem < Gem::TestCase io.write 'gem "a"' end - platform = Bundler::GemHelpers.generic_local_platform - if platform == Gem::Platform::RUBY - platform = '' - else - platform = " #{platform}" - end - expected = <<-EXPECTED -Could not find gem 'a#{platform}' in any of the gem sources listed in your Gemfile. +Could not find gem 'a' in locally installed gems. +The source does not contain any versions of 'a' You may need to `gem install -g` to install missing gems EXPECTED |