diff options
author | Tim Moore <tmoore@incrementalism.net> | 2014-07-06 18:35:31 +1000 |
---|---|---|
committer | Tim Moore <tmoore@incrementalism.net> | 2014-07-30 14:16:35 +1000 |
commit | ab78e7449ba1c1024de22ff798c6a32fb581abca (patch) | |
tree | 30e77a8e8f10b423874e6c713f1446d803bf8037 | |
parent | 9af2172e6dc6b29dc24f92a27b7a385faa952ba3 (diff) | |
download | bundler-ab78e7449ba1c1024de22ff798c6a32fb581abca.tar.gz |
Detect ambiguous gems.
-rw-r--r-- | lib/bundler/cli/install.rb | 9 | ||||
-rw-r--r-- | lib/bundler/index.rb | 18 | ||||
-rw-r--r-- | lib/bundler/installer.rb | 9 | ||||
-rw-r--r-- | lib/bundler/source/rubygems.rb | 12 | ||||
-rw-r--r-- | spec/install/gems/sources_spec.rb | 61 |
5 files changed, 88 insertions, 21 deletions
diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb index 2f5b490b83..64f4803a2c 100644 --- a/lib/bundler/cli/install.rb +++ b/lib/bundler/cli/install.rb @@ -93,6 +93,15 @@ module Bundler Bundler.ui.confirm "Post-install message from #{name}:" Bundler.ui.info msg end + Installer.ambiguous_gems.to_a.each do |name, installed_from_uri, *also_found_in_uris| + Bundler.ui.error "Warning: the gem '#{name}' was found in multiple sources." + Bundler.ui.error "Installed from: #{installed_from_uri}" + Bundler.ui.error "Also found in:" + also_found_in_uris.each { |uri| Bundler.ui.error " * #{uri}" } + Bundler.ui.error "You should add a source requirement to restrict this gem to your preferred source." + Bundler.ui.error "For example:" + Bundler.ui.error " gem '#{name}', :source => '#{installed_from_uri}'" + end if Bundler.settings[:clean] && Bundler.settings[:path] require "bundler/cli/clean" diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb index 493ac8fa52..5af7066845 100644 --- a/lib/bundler/index.rb +++ b/lib/bundler/index.rb @@ -10,13 +10,14 @@ module Bundler i end - attr_reader :specs, :sources - protected :specs + attr_reader :specs, :all_specs, :sources + protected :specs, :all_specs def initialize @sources = [] @cache = {} @specs = Hash.new { |h,k| h[k] = [] } + @all_specs = Hash.new { |h,k| h[k] = [] } end def initialize_copy(o) @@ -24,10 +25,14 @@ module Bundler @sources = @sources.dup @cache = {} @specs = Hash.new { |h,k| h[k] = [] } + @all_specs = Hash.new { |h,k| h[k] = [] } o.specs.each do |name, array| @specs[name] = array.dup end + o.all_specs.each do |name, array| + @all_specs[name] = array.dup + end end def inspect @@ -39,6 +44,14 @@ module Bundler true end + def search_all(name) + all_matches = @all_specs[name] + local_search(name) + @sources.each do |source| + all_matches.concat(source.search_all(name)) + end + all_matches + end + # Search this index's specs, and any source indexes that this index knows # about, returning all of the results. def search(query, base = nil) @@ -105,6 +118,7 @@ module Bundler return unless other other.each do |s| if (dupes = search_by_spec(s)) && dupes.any? + @all_specs[s.name] = [s] + dupes next unless override_dupes @specs[s.name] -= dupes end diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb index fe03b61508..ed743d40ca 100644 --- a/lib/bundler/installer.rb +++ b/lib/bundler/installer.rb @@ -5,7 +5,10 @@ require 'bundler/parallel_workers' module Bundler class Installer < Environment class << self - attr_accessor :post_install_messages + attr_accessor :post_install_messages, :ambiguous_gems + + Installer.post_install_messages = {} + Installer.ambiguous_gems = [] end # Begins the installation process for Bundler. @@ -75,10 +78,6 @@ module Bundler unless local options["local"] ? @definition.resolve_with_cache! : @definition.resolve_remotely! end - # Must install gems in the order that the resolver provides - # as dependencies might actually affect the installation of - # the gem. - Installer.post_install_messages = {} # the order that the resolver provides is significant, since # dependencies might actually affect the installation of a gem. diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index 5e708793d4..203473eda2 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -72,6 +72,12 @@ module Bundler # Download the gem to get the spec, because some specs that are returned # by rubygems.org are broken and wrong. if spec.source_uri + # Check for this spec from other sources + uris = [spec.source_uri] + uris += source_uris_for_spec(spec) + uris.uniq! + Installer.ambiguous_gems << [spec.name, *uris] if uris.length > 1 + s = Bundler.rubygems.spec_from_gem(fetch_gem(spec), Bundler.settings["trust-policy"]) spec.__swap__(s) end @@ -163,6 +169,12 @@ module Bundler true end + protected + + def source_uris_for_spec(spec) + specs.search_all(spec.name).map{|s| s.source_uri } + end + private def cached_gem(spec) diff --git a/spec/install/gems/sources_spec.rb b/spec/install/gems/sources_spec.rb index 946eb9d296..632a7ac3d7 100644 --- a/spec/install/gems/sources_spec.rb +++ b/spec/install/gems/sources_spec.rb @@ -4,24 +4,57 @@ describe "bundle install with gems on multiple sources" do # repo1 is built automatically before all of the specs run # it contains rack-obama 1.0.0 and rack 0.9.1 & 1.0.0 amongst other gems - it "searches gem sources from last to first" do - # Oh no! Someone evil is trying to hijack rack :( - # need this to be broken to check for correct source ordering - build_repo gem_repo3 do - build_gem "rack", "1.0.0" do |s| - s.write "lib/rack.rb", "RACK = 'FAIL'" + context "without source affinity" do + before do + # Oh no! Someone evil is trying to hijack rack :( + # need this to be broken to check for correct source ordering + build_repo gem_repo3 do + build_gem "rack", repo3_rack_version do |s| + s.write "lib/rack.rb", "RACK = 'FAIL'" + end end end - gemfile <<-G - source "file://#{gem_repo3}" - source "file://#{gem_repo1}" - gem "rack-obama" - gem "rack" - G + context "when the same version of the same gem is in multiple sources" do + let(:repo3_rack_version) { "1.0.0" } - bundle :install + before do + gemfile <<-G + source "file://#{gem_repo3}" + source "file://#{gem_repo1}" + gem "rack-obama" + gem "rack" + G + end + + it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first" do + bundle :install + + expect(out).to include("Warning: the gem 'rack' was found in multiple sources.") + expect(out).to include("Installed from: file:#{gem_repo1}") + should_be_installed("rack-obama 1.0.0", "rack 1.0.0") + end + end + + context "when different versions of the same gem are in multiple sources" do + let(:repo3_rack_version) { "1.2" } - should_be_installed("rack-obama 1.0.0", "rack 1.0.0") + before do + gemfile <<-G + source "file://#{gem_repo3}" + source "file://#{gem_repo1}" + gem "rack-obama" + gem "rack", "1.0.0" # force it to install the working version in repo1 + G + end + + it "warns about ambiguous gems, but installs anyway" do + bundle :install + + expect(out).to include("Warning: the gem 'rack' was found in multiple sources.") + expect(out).to include("Installed from: file:#{gem_repo1}") + should_be_installed("rack-obama 1.0.0", "rack 1.0.0") + end + end end end |