lib/bundler/definition.rb in bundler-1.12.6 vs lib/bundler/definition.rb in bundler-1.13.0.pre.1
- old
+ new
@@ -83,14 +83,21 @@
@locked_sources = []
end
@unlock[:gems] ||= []
@unlock[:sources] ||= []
+ @unlock[:ruby] ||= if @ruby_version && @locked_ruby_version
+ unless locked_ruby_version_object = RubyVersion.from_string(@locked_ruby_version)
+ raise LockfileError, "Failed to create a `RubyVersion` object from " \
+ "`#{@locked_ruby_version}` found in #{lockfile} -- try running `bundle update --ruby`."
+ end
+ @ruby_version.diff(locked_ruby_version_object)
+ end
+ @unlocking ||= @unlock[:ruby] || (!@locked_ruby_version ^ !@ruby_version)
current_platform = Bundler.rubygems.platforms.map {|p| generic(p) }.compact.last
- @new_platform = !@platforms.include?(current_platform)
- @platforms |= [current_platform]
+ add_platform(current_platform)
@path_changes = converge_paths
eager_unlock = expand_dependencies(@unlock[:gems])
@unlock[:gems] = @locked_specs.for(eager_unlock).map(&:name)
@@ -135,12 +142,21 @@
# 2. After that it tries and fetches gemspec of resolved dependencies
#
# @return [Bundler::SpecSet]
def specs
@specs ||= begin
- specs = resolve.materialize(Bundler.settings[:cache_all_platforms] ? dependencies : requested_dependencies)
-
+ begin
+ specs = resolve.materialize(Bundler.settings[:cache_all_platforms] ? dependencies : requested_dependencies)
+ rescue GemNotFound => e # Handle yanked gem
+ gem_name, gem_version = extract_gem_info(e)
+ locked_gem = @locked_specs[gem_name].last
+ raise if locked_gem.nil? || locked_gem.version.to_s != gem_version
+ raise GemNotFound, "Your bundle is locked to #{locked_gem}, but that version could not " \
+ "be found in any of the sources listed in your Gemfile. If you haven't changed sources, " \
+ "that means the author of #{locked_gem} has removed it. You'll need to update your bundle " \
+ "to a different version of #{locked_gem} that hasn't been removed in order to install."
+ end
unless specs["bundler"].any?
local = Bundler.settings[:frozen] ? rubygems_index : index
bundler = local.search(Gem::Dependency.new("bundler", VERSION)).last
specs["bundler"] = bundler if bundler
end
@@ -165,10 +181,16 @@
missing = []
resolve.materialize(requested_dependencies, missing)
missing
end
+ def missing_dependencies
+ missing = []
+ resolve.materialize(current_dependencies, missing)
+ missing
+ end
+
def requested_specs
@requested_specs ||= begin
groups = requested_groups
groups.map!(&:to_sym)
specs_for(groups)
@@ -192,13 +214,15 @@
# @return [SpecSet] resolved dependencies
def resolve
@resolve ||= begin
last_resolve = converge_locked_specs
if Bundler.settings[:frozen] || (!@unlocking && nothing_changed?)
+ Bundler.ui.debug("Found no changes, using resolution from the lockfile")
last_resolve
else
# Run a resolve against the locally available gems
+ Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies")
last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, ruby_version)
end
end
end
@@ -208,11 +232,11 @@
sources.all_sources.each do |source|
source.dependency_names = dependency_names.dup
idx.add_source source.specs
dependency_names -= pinned_spec_names(source.specs)
- dependency_names.push(*source.unmet_deps).uniq!
+ dependency_names.concat(source.unmet_deps).uniq!
end
end
end
# used when frozen is enabled so we can find the bundler
@@ -350,28 +374,34 @@
added = []
deleted = []
changed = []
gemfile_sources = sources.lock_sources
- if @locked_sources != gemfile_sources
- new_sources = gemfile_sources - @locked_sources
- deleted_sources = @locked_sources - gemfile_sources
+ new_sources = gemfile_sources - @locked_sources
+ deleted_sources = @locked_sources - gemfile_sources
+
+ new_deps = @dependencies - @locked_deps
+ deleted_deps = @locked_deps - @dependencies
+
+ # Check if it is possible that the source is only changed thing
+ if (new_deps.empty? && deleted_deps.empty?) && (!new_sources.empty? && !deleted_sources.empty?)
+ new_sources.reject! {|source| source.is_a_path? && source.path.exist? }
+ deleted_sources.reject! {|source| source.is_a_path? && source.path.exist? }
+ end
+
+ if @locked_sources != gemfile_sources
if new_sources.any?
added.concat new_sources.map {|source| "* source: #{source}" }
end
if deleted_sources.any?
deleted.concat deleted_sources.map {|source| "* source: #{source}" }
end
end
- new_deps = @dependencies - @locked_deps
- deleted_deps = @locked_deps - @dependencies
-
added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any?
-
if deleted_deps.any?
deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" }
end
both_sources = Hash.new {|h, k| h[k] = [] }
@@ -416,10 +446,15 @@
raise RubyVersionMismatch, msg
end
end
+ def add_platform(platform)
+ @new_platform ||= !@platforms.include?(platform)
+ @platforms |= [platform]
+ end
+
attr_reader :sources
private :sources
private
@@ -445,20 +480,27 @@
unlocking = @locked_specs.any? do |locked_spec|
locked_spec.source.class == locked.class && locked_spec.source != locked
end
end
- !locked || unlocking || dependencies_for_source_changed?(locked) || source.specs != locked.specs
+ !locked || unlocking || dependencies_for_source_changed?(source) || specs_for_source_changed?(source)
end
def dependencies_for_source_changed?(source)
deps_for_source = @dependencies.select {|s| s.source == source }
locked_deps_for_source = @locked_deps.select {|s| s.source == source }
- deps_for_source != locked_deps_for_source
+ Set.new(deps_for_source) != Set.new(locked_deps_for_source)
end
+ def specs_for_source_changed?(source)
+ locked_index = Index.new
+ locked_index.use(@locked_specs.select {|s| source.can_lock?(s) })
+
+ source.specs != locked_index
+ end
+
# Get all locals and override their matching sources.
# Return true if any of the locals changed (for example,
# they point to a new revision) or depend on new specs.
def converge_locals
locals = []
@@ -521,11 +563,19 @@
changes
end
def converge_dependencies
(@dependencies + @locked_deps).each do |dep|
- dep.source = sources.get(dep.source) if dep.source
+ locked_source = @locked_deps.select {|d| d.name == dep.name }.last
+ # This is to make sure that if bundler is installing in deployment mode and
+ # after locked_source and sources don't match, we still use locked_source.
+ if Bundler.settings[:frozen] && !locked_source.nil? &&
+ locked_source.respond_to?(:source) && locked_source.source.instance_of?(Source::Path) && locked_source.source.path.exist?
+ dep.source = locked_source.source
+ elsif dep.source
+ dep.source = sources.get(dep.source)
+ end
end
Set.new(@dependencies) != Set.new(@locked_deps)
end
# Remove elements from the locked specs that are expired. This will most
@@ -570,11 +620,11 @@
# XXX This is a backwards-compatibility fix to preserve the ability to
# unlock a single gem by passing its name via `--source`. See issue #3759
next if s.source.nil? || @unlock[:sources].include?(s.name)
# If the spec is from a path source and it doesn't exist anymore
- # then we just unlock it.
+ # then we unlock it.
# Path sources have special logic
if s.source.instance_of?(Source::Path)
other = s.source.specs[s].first
@@ -681,8 +731,14 @@
whitespace_cleanup = /\n{2,}/
current = current.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip
proposed = proposed.gsub(pattern, "\n").gsub(whitespace_cleanup, "\n\n").strip
end
current == proposed
+ end
+
+ def extract_gem_info(error)
+ # This method will extract the error message like "Could not find foo-1.2.3 in any of the sources"
+ # to an array. The first element will be the gem name (e.g. foo), the second will be the version number.
+ error.message.scan(/Could not find (\w+)-(\d+(?:\.\d+)+)/).flatten
end
end
end