lib/bundler/definition.rb in bundler-1.10.6 vs lib/bundler/definition.rb in bundler-1.11.0.pre.1

- old
+ new

@@ -17,18 +17,15 @@ # @return [Bundler::Definition] def self.build(gemfile, lockfile, unlock) unlock ||= {} gemfile = Pathname.new(gemfile).expand_path - unless gemfile.file? - raise GemfileNotFound, "#{gemfile} not found" - end + raise GemfileNotFound, "#{gemfile} not found" unless gemfile.file? Dsl.evaluate(gemfile, lockfile, unlock) end - # # How does the new system work? # # * Load information from Gemfile and Lockfile # * Invalidate stale locked specs @@ -60,11 +57,11 @@ @locked_bundler_version = nil if lockfile && File.exist?(lockfile) @lockfile_contents = Bundler.read_file(lockfile) locked = LockfileParser.new(@lockfile_contents) - @platforms = locked.platforms + @platforms = locked.platforms @locked_bundler_version = locked.bundler_version if unlock != true @locked_deps = locked.dependencies @locked_specs = SpecSet.new(locked.specs) @@ -84,17 +81,17 @@ end @unlock[:gems] ||= [] @unlock[:sources] ||= [] - current_platform = Bundler.rubygems.platforms.map { |p| generic(p) }.compact.last + current_platform = Bundler.rubygems.platforms.map {|p| generic(p) }.compact.last @new_platform = !@platforms.include?(current_platform) @platforms |= [current_platform] @path_changes = converge_paths eager_unlock = expand_dependencies(@unlock[:gems]) - @unlock[:gems] = @locked_specs.for(eager_unlock).map { |s| s.name } + @unlock[:gems] = @locked_specs.for(eager_unlock).map(&:name) @source_changes = converge_sources @dependency_changes = converge_dependencies @local_changes = converge_locals @@ -108,11 +105,11 @@ # 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 } + if ld = @locked_deps.find {|l| l.name == d.name } ld.instance_variable_set(:@type, d.type) end end end @@ -139,11 +136,11 @@ @specs ||= begin specs = resolve.materialize(Bundler.settings[:cache_all_platforms] ? dependencies : requested_dependencies) unless specs["bundler"].any? local = Bundler.settings[:frozen] ? rubygems_index : index - bundler = local.search(Gem::Dependency.new('bundler', VERSION)).last + bundler = local.search(Gem::Dependency.new("bundler", VERSION)).last specs["bundler"] = bundler if bundler end specs end @@ -168,22 +165,22 @@ end def requested_specs @requested_specs ||= begin groups = requested_groups - groups.map! { |g| g.to_sym } + groups.map!(&:to_sym) specs_for(groups) end end def current_dependencies - dependencies.reject { |d| !d.should_include? } + dependencies.reject {|d| !d.should_include? } end def specs_for(groups) - deps = dependencies.select { |d| (d.groups & groups).any? } - deps.delete_if { |d| !d.should_include? } + deps = dependencies.select {|d| (d.groups & groups).any? } + deps.delete_if {|d| !d.should_include? } specs.for(expand_dependencies(deps)) end # Resolve all the dependencies specified in Gemfile. It ensures that # dependencies that have been already resolved via locked file and are fresh @@ -195,18 +192,19 @@ last_resolve = converge_locked_specs if Bundler.settings[:frozen] || (!@unlocking && nothing_changed?) last_resolve else # Run a resolve against the locally available gems - last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve) + requested_ruby_version = ruby_version.version if ruby_version + last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, requested_ruby_version) end end end def index @index ||= Index.build do |idx| - dependency_names = @dependencies.map { |d| d.name } + dependency_names = @dependencies.map(&:name) sources.all_sources.each do |source| source.dependency_names = dependency_names.dup idx.add_source source.specs dependency_names -= pinned_spec_names(source.specs) @@ -236,11 +234,11 @@ def spec_git_paths sources.git_sources.map {|s| s.path.to_s } end def groups - dependencies.map { |d| d.groups }.flatten.uniq + dependencies.map(&:groups).flatten.uniq end def lock(file, preserve_bundled_with = false) contents = to_lock @@ -264,16 +262,13 @@ if Bundler.settings[:frozen] Bundler.ui.error "Cannot write a changed lockfile while frozen." return end - File.open(file, 'wb'){|f| f.puts(contents) } - rescue Errno::EACCES - raise Bundler::InstallError, - "There was an error while trying to write to Gemfile.lock. It is likely that \n" \ - "you need to allow write permissions for the file at path: \n" \ - "#{File.expand_path(file)}" + SharedHelpers.filesystem_access(file) do |p| + File.open(p, "wb") {|f| f.puts(contents) } + end end # Returns the version of Bundler that is creating or has created # Gemfile.lock. Used in #to_lock. def lock_version @@ -290,38 +285,36 @@ sources.lock_sources.each do |source| # Add the source header out << source.to_lock # Find all specs for this source resolve. - select { |s| source.can_lock?(s) }. + select {|s| source.can_lock?(s) }. # This needs to be sorted by full name so that # gems with the same name, but different platform # are ordered consistently - sort_by { |s| s.full_name }. + sort_by(&:full_name). each do |spec| - next if spec.name == 'bundler' + next if spec.name == "bundler" out << spec.to_lock end out << "\n" end out << "PLATFORMS\n" - platforms.map { |p| p.to_s }.sort.each do |p| + platforms.map(&:to_s).sort.each do |p| out << " #{p}\n" end out << "\n" out << "DEPENDENCIES\n" handled = [] - dependencies. - sort_by { |d| d.to_s }. - each do |dep| - next if handled.include?(dep.name) - out << dep.to_lock - handled << dep.name + dependencies.sort_by(&:to_s).each do |dep| + next if handled.include?(dep.name) + out << dep.to_lock + handled << dep.name end # Record the version of Bundler that was used to create the lockfile out << "\nBUNDLED WITH\n" out << " #{lock_version}\n" @@ -330,14 +323,14 @@ end def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false) msg = "You are trying to install in deployment mode after changing\n" \ "your Gemfile. Run `bundle install` elsewhere and add the\n" \ - "updated Gemfile.lock to version control." + "updated #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} to version control." unless explicit_flag - msg += "\n\nIf this is a development machine, remove the Gemfile " \ + msg += "\n\nIf this is a development machine, remove the #{Bundler.default_gemfile} " \ "freeze \nby running `bundle install --no-deployment`." end added = [] deleted = [] @@ -347,44 +340,41 @@ if @locked_sources != gemfile_sources new_sources = gemfile_sources - @locked_sources deleted_sources = @locked_sources - gemfile_sources if new_sources.any? - added.concat new_sources.map { |source| "* source: #{source}" } + added.concat new_sources.map {|source| "* source: #{source}" } end if deleted_sources.any? - deleted.concat deleted_sources.map { |source| "* source: #{source}" } + deleted.concat deleted_sources.map {|source| "* source: #{source}" } end end new_deps = @dependencies - @locked_deps deleted_deps = @locked_deps - @dependencies - if new_deps.any? - added.concat new_deps.map { |d| "* #{pretty_dep(d)}" } - end + 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)}" } + deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } end - both_sources = Hash.new { |h,k| h[k] = [] } - @dependencies.each { |d| both_sources[d.name][0] = d } - @locked_deps.each { |d| both_sources[d.name][1] = d.source } + both_sources = Hash.new {|h, k| h[k] = [] } + @dependencies.each {|d| both_sources[d.name][0] = d } + @locked_deps.each {|d| both_sources[d.name][1] = d.source } both_sources.each do |name, (dep, lock_source)| - if (dep.nil? && !lock_source.nil?) || (!dep.nil? && !lock_source.nil? && !lock_source.can_lock?(dep)) - gemfile_source_name = (dep && dep.source) || 'no specified source' - lockfile_source_name = lock_source || 'no specified source' - changed << "* #{name} from `#{gemfile_source_name}` to `#{lockfile_source_name}`" - end + next unless (dep.nil? && !lock_source.nil?) || (!dep.nil? && !lock_source.nil? && !lock_source.can_lock?(dep)) + gemfile_source_name = (dep && dep.source) || "no specified source" + lockfile_source_name = lock_source || "no specified source" + changed << "* #{name} from `#{gemfile_source_name}` to `#{lockfile_source_name}`" end - msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any? + msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any? msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any? - msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any? + msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any? msg << "\n" raise ProductionError, msg if added.any? || deleted.any? || changed.any? end @@ -393,39 +383,39 @@ if diff = ruby_version.diff(Bundler.ruby_version) problem, expected, actual = diff msg = case problem - when :engine - "Your Ruby engine is #{actual}, but your Gemfile specified #{expected}" - when :version - "Your Ruby version is #{actual}, but your Gemfile specified #{expected}" - when :engine_version - "Your #{Bundler.ruby_version.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}" - when :patchlevel - if !expected.is_a?(String) - "The Ruby patchlevel in your Gemfile must be a string" - else - "Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}" - end + when :engine + "Your Ruby engine is #{actual}, but your Gemfile specified #{expected}" + when :version + "Your Ruby version is #{actual}, but your Gemfile specified #{expected}" + when :engine_version + "Your #{Bundler.ruby_version.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}" + when :patchlevel + if !expected.is_a?(String) + "The Ruby patchlevel in your Gemfile must be a string" + else + "Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}" + end end raise RubyVersionMismatch, msg end end attr_reader :sources - private :sources + private :sources private def nothing_changed? !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes end def pretty_dep(dep, source = false) - msg = "#{dep.name}" + msg = "#{dep.name}" msg << " (#{dep.requirement})" unless dep.requirement == Gem::Requirement.default msg << " from the `#{dep.source}` source" if source && dep.source msg end @@ -444,33 +434,33 @@ !locked || unlocking || dependencies_for_source_changed?(locked) || source.specs != locked.specs 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 = @dependencies.select {|s| s.source == source } + locked_deps_for_source = @locked_deps.select {|s| s.source == source } deps_for_source != locked_deps_for_source 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 = [] - Bundler.settings.local_overrides.map do |k,v| - spec = @dependencies.find { |s| s.name == k } + Bundler.settings.local_overrides.map do |k, v| + spec = @dependencies.find {|s| s.name == k } source = spec && spec.source if source && source.respond_to?(:local_override!) source.unlock! if @unlock[:gems].include?(spec.name) - locals << [ source, source.local_override!(v) ] + locals << [source, source.local_override!(v)] end end locals.any? do |source, changed| - changed || specs_changed?(source) { |o| source.class == o.class && source.uri == o.uri } + changed || specs_changed?(source) {|o| source.class == o.class && source.uri == o.uri } end end def converge_paths sources.path_sources.any? do |source| @@ -482,26 +472,26 @@ def converge_sources changes = false # Get the Rubygems sources from the Gemfile.lock - locked_gem_sources = @locked_sources.select { |s| s.kind_of?(Source::Rubygems) } + locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } # Get the Rubygems remotes from the Gemfile actual_remotes = sources.rubygems_remotes # If there is a Rubygems source in both if !locked_gem_sources.empty? && !actual_remotes.empty? locked_gem_sources.each do |locked_gem| # Merge the remotes from the Gemfile into the Gemfile.lock - changes = changes | locked_gem.replace_remotes(actual_remotes) + changes |= locked_gem.replace_remotes(actual_remotes) end 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. - changes = changes | sources.replace_sources!(@locked_sources) + changes |= sources.replace_sources!(@locked_sources) sources.all_sources.each do |source| # 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 @@ -516,13 +506,11 @@ changes end def converge_dependencies (@dependencies + @locked_deps).each do |dep| - if dep.source - dep.source = sources.get(dep.source) - end + dep.source = sources.get(dep.source) if dep.source end Set.new(@dependencies) != Set.new(@locked_deps) end # Remove elements from the locked specs that are expired. This will most @@ -533,11 +521,14 @@ # Build a list of dependencies that are the same in the Gemfile # and Gemfile.lock. If the Gemfile modified a dependency, but # the gem in the Gemfile.lock still satisfies it, this is fine # too. - locked_deps_hash = @locked_deps.inject({}) { |hsh, dep| hsh[dep] = dep; hsh } + locked_deps_hash = @locked_deps.inject({}) do |hsh, dep| + hsh[dep] = dep + hsh + end @dependencies.each do |dep| locked_dep = locked_deps_hash[dep] if in_locked_deps?(dep, locked_dep) || satisfies_locked_spec?(dep) deps << dep @@ -545,23 +536,28 @@ @locked_specs.each do |s| @unlock[:gems] << s.name if s.source == dep.source end dep.source.unlock! if dep.source.respond_to?(:unlock!) - dep.source.specs.each { |s| @unlock[:gems] << s.name } + dep.source.specs.each {|s| @unlock[:gems] << s.name } end end converged = [] @locked_specs.each do |s| # Replace the locked dependency's source with the equivalent source from the Gemfile - dep = @dependencies.find { |d| s.satisfies?(d) } + dep = @dependencies.find {|d| s.satisfies?(d) } s.source = (dep && dep.source) || sources.get(s.source) # Don't add a spec to the list if its source is expired. For example, # if you change a Git gem to Rubygems. + next if s.source.nil? || @unlock[:sources].include?(s.source.name) + + # 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. # Path sources have special logic if s.source.instance_of?(Source::Path) @@ -569,11 +565,11 @@ # If the spec is no longer in the path source, unlock it. This # commonly happens if the version changed in the gemspec next unless other - deps2 = other.dependencies.select { |d| d.type != :development } + deps2 = other.dependencies.select {|d| d.type != :development } # If the dependencies of the path source have changed, unlock it next unless s.dependencies.sort == deps2.sort end converged << s @@ -585,12 +581,12 @@ # Now, we unlock any sources that do not have anymore gems pinned to it sources.all_sources.each do |source| next unless source.respond_to?(:unlock!) - unless resolve.any? { |s| s.source == source } - source.unlock! if !diff.empty? && diff.any? { |s| s.source == source } + unless resolve.any? {|s| s.source == source } + source.unlock! if !diff.empty? && diff.any? {|s| s.source == source } end end resolve end @@ -601,11 +597,11 @@ # that the Gemfile dep does. locked_dep && locked_dep.source && dep.source && locked_dep.source.include?(dep.source) end def satisfies_locked_spec?(dep) - @locked_specs.any? { |s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) } + @locked_specs.any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) } end def expanded_dependencies @expanded_dependencies ||= expand_dependencies(dependencies, @remote) end @@ -622,12 +618,12 @@ deps end def requested_dependencies groups = requested_groups - groups.map! { |g| g.to_sym } - dependencies.reject { |d| !d.should_include? || (d.groups & groups).empty? } + groups.map!(&:to_sym) + dependencies.reject {|d| !d.should_include? || (d.groups & groups).empty? } end def source_requirements # Load all specs from remote sources index @@ -644,11 +640,11 @@ end def pinned_spec_names(specs) names = [] specs.each do |s| - # TODO when two sources without blocks is an error, we can change + # TODO: when two sources without blocks is an error, we can change # this check to !s.source.is_a?(Source::LocalRubygems). For now, # we need to ask every Rubygems for every gem name. if s.source.is_a?(Source::Git) || s.source.is_a?(Source::Path) names << s.name end @@ -656,19 +652,18 @@ names.uniq! names end def requested_groups - self.groups - Bundler.settings.without - @optional_groups + Bundler.settings.with + groups - Bundler.settings.without - @optional_groups + Bundler.settings.with end def lockfiles_equal?(current, proposed, preserve_bundled_with) if preserve_bundled_with pattern = /\n\n#{LockfileParser::BUNDLED}\n\s+#{Gem::Version::VERSION_PATTERN}\n/ current.sub(pattern, "\n") == proposed.sub(pattern, "\n") else current == proposed end end - end end