diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 0e39cf710c6..e0b983730ca 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -167,8 +167,7 @@ def specs "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 + bundler = rubygems_index.search(Gem::Dependency.new("bundler", VERSION)).last specs["bundler"] = bundler if bundler end @@ -194,9 +193,9 @@ def missing_specs missing end - def missing_dependencies? + def missing_specs? missing = [] - resolve.materialize(current_dependencies, missing) + resolve.materialize(requested_dependencies, missing) return false if missing.empty? Bundler.ui.debug "The definition is missing #{missing.map(&:full_name)}" true @@ -594,6 +593,9 @@ def specs_for_source_changed?(source) # order here matters, since Index#== is checking source.specs.include?(locked_index) locked_index != source.specs + rescue PathError, GitError => e + Bundler.ui.debug "Assuming that #{source} has not changed since fetching its specs errored (#{e})" + false end # Get all locals and override their matching sources. @@ -771,7 +773,19 @@ def converge_locked_specs # Path sources have special logic if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec) - other = s.source.specs[s].first + other_sources_specs = begin + s.source.specs + rescue PathError, GitError + # if we won't need the source (according to the lockfile), + # don't error if the path/git source isn't available + next if @locked_specs. + for(requested_dependencies, [], false, true, false). + none? {|locked_spec| locked_spec.source == s.source } + + raise + end + + other = other_sources_specs[s].first # If the spec is no longer in the path source, unlock it. This # commonly happens if the version changed in the gemspec diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb index 7c13c0c8a93..8775fe2ed06 100644 --- a/lib/bundler/installer.rb +++ b/lib/bundler/installer.rb @@ -231,7 +231,7 @@ def create_bundle_path def resolve_if_needed(options) if !options["update"] && !options[:inline] && !options["force"] && Bundler.default_lockfile.file? - return if @definition.nothing_changed? && !@definition.missing_dependencies? + return if @definition.nothing_changed? && !@definition.missing_specs? end options["local"] ? @definition.resolve_with_cache! : @definition.resolve_remotely! diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index 96426335784..e68da87704e 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -76,7 +76,7 @@ def to_hash end def materialize(deps, missing_specs = nil) - materialized = self.for(deps, [], false, true, missing_specs).to_a + materialized = self.for(deps, [], false, true, !missing_specs).to_a deps = materialized.map(&:name).uniq materialized.map! do |s| next s unless s.is_a?(LazySpecification) diff --git a/spec/install/deploy_spec.rb b/spec/install/deploy_spec.rb index c6747764b11..032ff01b661 100644 --- a/spec/install/deploy_spec.rb +++ b/spec/install/deploy_spec.rb @@ -135,6 +135,35 @@ expect(out).not_to include("You have changed in the Gemfile") end + it "works if a path gem is missing but is in a without group" do + build_lib "path_gem" + install_gemfile! <<-G + source "file://#{gem_repo1}" + gem "rake" + gem "path_gem", :path => "#{lib_path("path_gem-1.0")}", :group => :development + G + expect(the_bundle).to include_gems "path_gem 1.0" + FileUtils.rm_r lib_path("path_gem-1.0") + + bundle! :install, :path => ".bundle", :without => "development", :deployment => true, :env => { :DEBUG => "1" } + run! "puts :WIN" + expect(out).to eq("WIN") + end + + it "explodes if a path gem is missing" do + build_lib "path_gem" + install_gemfile! <<-G + source "file://#{gem_repo1}" + gem "rake" + gem "path_gem", :path => "#{lib_path("path_gem-1.0")}", :group => :development + G + expect(the_bundle).to include_gems "path_gem 1.0" + FileUtils.rm_r lib_path("path_gem-1.0") + + bundle :install, :path => ".bundle", :deployment => true + expect(out).to include("The path `#{lib_path("path_gem-1.0")}` does not exist.") + end + it "can have --frozen set via an environment variable" do gemfile <<-G source "file://#{gem_repo1}" diff --git a/spec/install/gemfile/groups_spec.rb b/spec/install/gemfile/groups_spec.rb index a6b81d0911a..ed264d84391 100644 --- a/spec/install/gemfile/groups_spec.rb +++ b/spec/install/gemfile/groups_spec.rb @@ -363,8 +363,8 @@ it "does not hit the remote a second time" do FileUtils.rm_rf gem_repo2 - bundle "install --without rack" - expect(err).to lack_errors + bundle! "install --without rack" + expect(out).not_to include "Fetching" end end end diff --git a/spec/install/git_spec.rb b/spec/install/git_spec.rb index cd3b6e6a889..75d70747da9 100644 --- a/spec/install/git_spec.rb +++ b/spec/install/git_spec.rb @@ -36,8 +36,8 @@ expect(the_bundle).to include_gems "foo 2.0", :source => "git@#{lib_path("foo")}" end - it "should check out git repos that are missing but not being installed" do - build_git "foo" + it "should allows git repos that are missing but not being installed" do + revision = build_git("foo").ref_for("HEAD") gemfile <<-G gem "foo", :git => "file://#{lib_path("foo-1.0")}", :group => :development @@ -46,6 +46,7 @@ lockfile <<-L GIT remote: file://#{lib_path("foo-1.0")} + revision: #{revision} specs: foo (1.0) @@ -56,10 +57,9 @@ foo! L - bundle "install --path=vendor/bundle --without development" + bundle! "install --path=vendor/bundle --without development" expect(out).to include("Bundle complete!") - expect(vendored_gems("bundler/gems/foo-1.0-#{revision_for(lib_path("foo-1.0"))[0..11]}")).to be_directory end end end diff --git a/spec/quality_spec.rb b/spec/quality_spec.rb index c7b367ea877..43ee23a8ba4 100644 --- a/spec/quality_spec.rb +++ b/spec/quality_spec.rb @@ -78,7 +78,7 @@ def check_for_expendable_words(filename) File.readlines(filename).each_with_index do |line, number| next unless word_found = pattern.match(line) - failing_line_message << "#{filename} has '#{word_found}' on line #{number + 1}. Avoid using these kinds of weak modifiers." + failing_line_message << "#{filename}:#{number.succ} has '#{word_found}'. Avoid using these kinds of weak modifiers." end failing_line_message unless failing_line_message.empty? @@ -90,7 +90,7 @@ def check_for_specific_pronouns(filename) File.readlines(filename).each_with_index do |line, number| next unless word_found = specific_pronouns.match(line) - failing_line_message << "#{filename} has '#{word_found}' on line #{number + 1}. Use more generic pronouns in documentation." + failing_line_message << "#{filename}:#{number.succ} has '#{word_found}'. Use more generic pronouns in documentation." end failing_line_message unless failing_line_message.empty? @@ -107,7 +107,7 @@ def check_for_specific_pronouns(filename) it "has no malformed whitespace" do exempt = /\.gitmodules|\.marshal|fixtures|vendor|ssl_certs|LICENSE|vcr_cassettes/ error_messages = [] - Dir.chdir(File.expand_path("../..", __FILE__)) do + Dir.chdir(root) do `git ls-files -z`.split("\x0").each do |filename| next if filename =~ exempt error_messages << check_for_tab_characters(filename) @@ -118,9 +118,9 @@ def check_for_specific_pronouns(filename) end it "does not include any leftover debugging or development mechanisms" do - exempt = %r{quality_spec.rb|support/helpers|vcr_cassettes} + exempt = %r{quality_spec.rb|support/helpers|vcr_cassettes|\.md|\.ronn} error_messages = [] - Dir.chdir(File.expand_path("../", __FILE__)) do + Dir.chdir(root) do `git ls-files -z`.split("\x0").each do |filename| next if filename =~ exempt error_messages << check_for_debugging_mechanisms(filename) @@ -131,8 +131,8 @@ def check_for_specific_pronouns(filename) it "does not include any unresolved merge conflicts" do error_messages = [] - exempt = %r{lock/lockfile_spec|quality_spec|vcr_cassettes} - Dir.chdir(File.expand_path("../", __FILE__)) do + exempt = %r{lock/lockfile_spec|quality_spec|vcr_cassettes|\.ronn|lockfile_parser\.rb} + Dir.chdir(root) do `git ls-files -z`.split("\x0").each do |filename| next if filename =~ exempt error_messages << check_for_git_merge_conflicts(filename) @@ -144,8 +144,8 @@ def check_for_specific_pronouns(filename) it "maintains language quality of the documentation" do included = /ronn/ error_messages = [] - Dir.chdir(File.expand_path("../../man", __FILE__)) do - `git ls-files -z`.split("\x0").each do |filename| + Dir.chdir(root) do + `git ls-files -z -- man`.split("\x0").each do |filename| next unless filename =~ included error_messages << check_for_expendable_words(filename) error_messages << check_for_specific_pronouns(filename) @@ -157,8 +157,8 @@ def check_for_specific_pronouns(filename) it "maintains language quality of sentences used in source code" do error_messages = [] exempt = /vendor/ - Dir.chdir(File.expand_path("../../lib", __FILE__)) do - `git ls-files -z`.split("\x0").each do |filename| + Dir.chdir(root) do + `git ls-files -z -- lib`.split("\x0").each do |filename| next if filename =~ exempt error_messages << check_for_expendable_words(filename) error_messages << check_for_specific_pronouns(filename) @@ -180,14 +180,14 @@ def check_for_specific_pronouns(filename) Bundler::Settings::BOOL_KEYS.each {|k| all_settings[k] << "in Bundler::Settings::BOOL_KEYS" } Bundler::Settings::NUMBER_KEYS.each {|k| all_settings[k] << "in Bundler::Settings::NUMBER_KEYS" } - Dir.chdir(File.expand_path("../../lib", __FILE__)) do + Dir.chdir(root) do key_pattern = /([a-z\._-]+)/i - `git ls-files -z`.split("\x0").each do |filename| + `git ls-files -z -- lib`.split("\x0").each do |filename| File.readlines(filename).each_with_index do |line, number| - line.scan(/Bundler\.settings\[:#{key_pattern}\]/).flatten.each {|s| all_settings[s] << "referenced at `lib/#{filename}:#{number.succ}`" } + line.scan(/Bundler\.settings\[:#{key_pattern}\]/).flatten.each {|s| all_settings[s] << "referenced at `#{filename}:#{number.succ}`" } end end - documented_settings = File.read("../man/bundle-config.ronn").scan(/^\* `#{key_pattern}`/).flatten + documented_settings = File.read("man/bundle-config.ronn").scan(/^\* `#{key_pattern}`/).flatten end documented_settings.each {|s| all_settings.delete(s) } @@ -216,19 +216,19 @@ def check_for_specific_pronouns(filename) end it "does not contain any warnings" do - Dir.chdir(root.join("lib")) do + Dir.chdir(root) do exclusions = %w[ - bundler/capistrano.rb - bundler/gem_tasks.rb - bundler/vlad.rb - bundler/templates/gems.rb + lib/bundler/capistrano.rb + lib/bundler/gem_tasks.rb + lib/bundler/vlad.rb + lib/bundler/templates/gems.rb ] - lib_files = `git ls-files -z`.split("\x0").grep(/\.rb$/) - exclusions - lib_files.reject! {|f| f.start_with?("bundler/vendor") } + lib_files = `git ls-files -z -- lib`.split("\x0").grep(/\.rb$/) - exclusions + lib_files.reject! {|f| f.start_with?("lib/bundler/vendor") } lib_files.map! {|f| f.chomp(".rb") } - sys_exec!("ruby -w -I.") do |input, _, _| + sys_exec!("ruby -w -Ilib") do |input, _, _| lib_files.each do |f| - input.puts "require '#{f}'" + input.puts "require '#{f.sub(%r{\Alib/}, "")}'" end end