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