lib/bundler/definition.rb in bundler-1.1.rc.7 vs lib/bundler/definition.rb in bundler-1.1.rc.8
- old
+ new
@@ -1,6 +1,7 @@
require "digest/sha1"
+require "set"
module Bundler
class Definition
include GemHelpers
@@ -28,10 +29,12 @@
* If all fresh dependencies are satisfied by the locked
specs, then we can try to resolve locally.
=end
def initialize(lockfile, dependencies, sources, unlock)
+ @unlocking = unlock == true || !unlock.empty?
+
@dependencies, @sources, @unlock = dependencies, sources, unlock
@remote = false
@specs = nil
@lockfile_contents = ""
@@ -63,17 +66,51 @@
current_platform = Bundler.rubygems.platforms.map { |p| generic(p) }.compact.last
@new_platform = !@platforms.include?(current_platform)
@platforms |= [current_platform]
+ @path_changes = @sources.any? do |source|
+ next unless source.instance_of?(Source::Path)
+
+ locked = @locked_sources.find do |ls|
+ ls.class == source.class && ls.path == source.path
+ end
+
+ if locked
+ unlocking = locked.specs.any? do |spec|
+ @locked_specs.any? do |locked_spec|
+ locked_spec.source != locked
+ end
+ end
+ end
+
+ !locked || unlocking || source.specs != locked.specs
+ end
eager_unlock = expand_dependencies(@unlock[:gems])
@unlock[:gems] = @locked_specs.for(eager_unlock).map { |s| s.name }
- converge_sources
- converge_dependencies
+ @source_changes = converge_sources
+ @dependency_changes = converge_dependencies
+
+ fixup_dependency_types!
end
+ def fixup_dependency_types!
+ # XXX This is a temporary workaround for a bug when using rubygems 1.8.15
+ # where Gem::Dependency#== matches Gem::Dependency#type. As the lockfile
+ # doesn't carry a notion of the dependency type, if you use
+ # add_development_dependency in a gemspec that's loaded with the gemspec
+ # directive, the lockfile dependencies and resolved dependencies end up
+ # with a mismatch on #type.
+ # Test coverage to catch a regression on this is in gemspec_spec.rb
+ @dependencies.each do |d|
+ if ld = @locked_deps.find { |l| l.name == d.name }
+ ld.instance_variable_set(:@type, d.type)
+ end
+ end
+ end
+
def resolve_with_cache!
raise "Specs already loaded" if @specs
@sources.each { |s| s.cached! }
specs
end
@@ -135,11 +172,11 @@
specs.for(expand_dependencies(deps))
end
def resolve
@resolve ||= begin
- if Bundler.settings[:frozen]
+ if Bundler.settings[:frozen] || (!@unlocking && !@source_changes && !@dependency_changes && !@new_platform && !@path_changes)
@locked_specs
else
last_resolve = converge_locked_specs
# Record the specs available in each gem's source, so that those
@@ -157,24 +194,22 @@
end
end
def index
@index ||= Index.build do |idx|
- other_sources = @sources.find_all{|s| !s.is_a?(Bundler::Source::Rubygems) }
- rubygems_sources = @sources.find_all{|s| s.is_a?(Bundler::Source::Rubygems) }
-
dependency_names = @dependencies.dup || []
dependency_names.map! {|d| d.name }
- other_sources.each do |s|
- source_index = s.specs
- dependency_names += source_index.unmet_dependency_names
- idx.add_source source_index
- end
- rubygems_sources.each do |s|
- s.dependency_names = dependency_names.uniq if s.is_a?(Bundler::Source::Rubygems)
- idx.add_source s.specs
+ @sources.each do |s|
+ if s.is_a?(Bundler::Source::Rubygems)
+ s.dependency_names = dependency_names.uniq
+ idx.add_source s.specs
+ else
+ source_index = s.specs
+ dependency_names += source_index.unmet_dependency_names
+ idx.add_source source_index
+ end
end
end
end
# used when frozen is enabled so we can find the bundler
@@ -323,31 +358,53 @@
msg << " from the `#{dep.source}` source" if source && dep.source
msg
end
def converge_sources
+ changes = false
+
+ # Get the Rubygems source from the Gemfile.lock
locked_gem = @locked_sources.find { |s| Source::Rubygems === s }
+
+ # Get the Rubygems source from the Gemfile
actual_gem = @sources.find { |s| Source::Rubygems === s }
+ # If there is a Rubygems source in both
if locked_gem && actual_gem
- locked_gem.merge_remotes actual_gem
+ # Merge the remotes from the Gemfile into the Gemfile.lock
+ changes = changes | locked_gem.replace_remotes(actual_gem)
end
+ # Replace the sources from the Gemfile with the sources from the Gemfile.lock,
+ # if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent
+ # source in the Gemfile.lock, use the one from the Gemfile.
@sources.map! do |source|
@locked_sources.find { |s| s == source } || source
end
+ changes = changes | (Set.new(@sources) != Set.new(@locked_sources))
@sources.each do |source|
- source.unlock! if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name)
+ # If the source is unlockable and the current command allows an unlock of
+ # the source (for example, you are doing a `bundle update <foo>` of a git-pinned
+ # gem), unlock it. For git sources, this means to unlock the revision, which
+ # will cause the `ref` used to be the most recent for the branch (or master) if
+ # an explicit `ref` is not used.
+ if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name)
+ source.unlock!
+ changes = true
+ end
end
+
+ changes
end
def converge_dependencies
(@dependencies + @locked_deps).each do |dep|
if dep.source
dep.source = @sources.find { |s| dep.source == s }
end
end
+ Set.new(@dependencies) != Set.new(@locked_deps)
end
# Remove elements from the locked specs that are expired. This will most
# commonly happen if the Gemfile has changed since the lockfile was last
# generated