summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndré Arko <andre@arko.net>2013-07-29 10:35:25 -0700
committerAndré Arko <andre@arko.net>2013-07-29 10:35:25 -0700
commit6608516a379d6cd4bd2b35c8b913b6c284197e00 (patch)
tree1379403af7549ef9e9b7495b8115604153cb9c88
parent899a250984b4d248955a56948bd6e05423248df3 (diff)
parent5024238df342b791d3c19b1448c7a797615cc938 (diff)
downloadbundler-6608516a379d6cd4bd2b35c8b913b6c284197e00.tar.gz
Merge pull request #2564 from bundler/detect-cyclic-dependency
Raise user friendly errors in case of Cyclic Dependency
-rw-r--r--lib/bundler.rb31
-rw-r--r--lib/bundler/spec_set.rb17
-rw-r--r--spec/resolver/basic_spec.rb11
-rw-r--r--spec/support/indexes.rb18
4 files changed, 61 insertions, 16 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb
index 5ab56154ae..cfc645b75e 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -50,21 +50,22 @@ module Bundler
end
end
- class GemfileNotFound < BundlerError; status_code(10) ; end
- class GemNotFound < BundlerError; status_code(7) ; end
- class GemfileError < BundlerError; status_code(4) ; end
- class InstallError < BundlerError; status_code(5) ; end
- class InstallHookError < BundlerError; status_code(6) ; end
- class PathError < BundlerError; status_code(13) ; end
- class GitError < BundlerError; status_code(11) ; end
- class DeprecatedError < BundlerError; status_code(12) ; end
- class GemspecError < BundlerError; status_code(14) ; end
- class InvalidOption < BundlerError; status_code(15) ; end
- class ProductionError < BundlerError; status_code(16) ; end
- class HTTPError < BundlerError; status_code(17) ; end
- class RubyVersionMismatch < BundlerError; status_code(18) ; end
- class SecurityError < BundlerError; status_code(19) ; end
- class LockfileError < BundlerError; status_code(20) ; end
+ class GemfileNotFound < BundlerError; status_code(10) ; end
+ class GemNotFound < BundlerError; status_code(7) ; end
+ class GemfileError < BundlerError; status_code(4) ; end
+ class InstallError < BundlerError; status_code(5) ; end
+ class InstallHookError < BundlerError; status_code(6) ; end
+ class PathError < BundlerError; status_code(13) ; end
+ class GitError < BundlerError; status_code(11) ; end
+ class DeprecatedError < BundlerError; status_code(12) ; end
+ class GemspecError < BundlerError; status_code(14) ; end
+ class InvalidOption < BundlerError; status_code(15) ; end
+ class ProductionError < BundlerError; status_code(16) ; end
+ class HTTPError < BundlerError; status_code(17) ; end
+ class RubyVersionMismatch < BundlerError; status_code(18) ; end
+ class SecurityError < BundlerError; status_code(19) ; end
+ class LockfileError < BundlerError; status_code(20) ; end
+ class CyclicDependencyError < BundlerError; status_code(21) ; end
# Internal errors, should be rescued
class VersionConflict < BundlerError
diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb
index 2cdffdc83f..1746f6d0df 100644
--- a/lib/bundler/spec_set.rb
+++ b/lib/bundler/spec_set.rb
@@ -109,7 +109,22 @@ module Bundler
def sorted
rake = @specs.find { |s| s.name == 'rake' }
- @sorted ||= ([rake] + tsort).compact.uniq
+ begin
+ @sorted ||= ([rake] + tsort).compact.uniq
+ rescue TSort::Cyclic => error
+ cgems = extract_circular_gems(error)
+ raise CyclicDependencyError, "Your Gemfile requires gems that depend" \
+ " depend on each other, creating an infinite loop. Please remove" \
+ " either gem '#{cgems[1]}' or gem '#{cgems[0]}' and try again."
+ end
+ end
+
+ def extract_circular_gems(error)
+ if Bundler.current_ruby.mri? && Bundler.current_ruby.on_19?
+ error.message.scan(/(\w+) \([^)]/).flatten
+ else
+ error.message.scan(/@name="(.*?)"/).flatten
+ end
end
def lookup
diff --git a/spec/resolver/basic_spec.rb b/spec/resolver/basic_spec.rb
index d675f4435f..22dc2f0fbe 100644
--- a/spec/resolver/basic_spec.rb
+++ b/spec/resolver/basic_spec.rb
@@ -23,4 +23,15 @@ describe "Resolving" do
dep "my_app"
should_resolve_as %w(activemodel-3.2.11 builder-3.0.4 grape-0.2.6 my_app-1.0.0)
end
+
+ it "should throw error in case of circular dependencies" do
+ @index = a_circular_index
+ dep "circular_app"
+
+ got = resolve
+ expect {
+ got = got.map { |s| s.full_name }.sort
+ }.to raise_error(Bundler::CyclicDependencyError, /please remove either gem 'foo' or gem 'bar'/i)
+ end
+
end
diff --git a/spec/support/indexes.rb b/spec/support/indexes.rb
index 2ca67a637a..418f7f32db 100644
--- a/spec/support/indexes.rb
+++ b/spec/support/indexes.rb
@@ -130,5 +130,23 @@ module Spec
end
end
end
+
+ def a_circular_index
+ build_index do
+ gem "rack", "1.0.1"
+ gem("foo", '0.2.6') do
+ dep "bar", ">= 0"
+ end
+
+ gem("bar", "1.0.0") do
+ dep "foo", ">= 0"
+ end
+
+ gem("circular_app", '1.0.0') do
+ dep "foo", ">= 0"
+ dep "bar", ">= 0"
+ end
+ end
+ end
end
end