summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Steiner <diego.steiner@renuo.ch>2016-09-27 14:07:35 +0200
committerDiego Steiner <diego.steiner@renuo.ch>2016-09-27 14:07:35 +0200
commitf809209b0c13a48a6da75692483bb51cf3ac0342 (patch)
tree37ca2dd297079ef5b91faefc423cd1b997d3991f
parent14c1a12b711878c7d7d7f360cb70c9398496b018 (diff)
parent121ada2a1842ebe9989f35567e2dd829ec06b7a1 (diff)
downloadbundler-f809209b0c13a48a6da75692483bb51cf3ac0342.tar.gz
Merge remote-tracking branch 'origin/master' into 4854-gemnotfound-error
-rw-r--r--.rubocop.yml3
-rw-r--r--.travis.yml36
-rw-r--r--CHANGELOG.md45
-rw-r--r--DEVELOPMENT.md2
-rw-r--r--Rakefile2
-rwxr-xr-xexe/bundle10
-rw-r--r--lib/bundler.rb17
-rw-r--r--lib/bundler/cli.rb27
-rw-r--r--lib/bundler/cli/binstubs.rb2
-rw-r--r--lib/bundler/cli/cache.rb2
-rw-r--r--lib/bundler/cli/check.rb2
-rw-r--r--lib/bundler/cli/doctor.rb36
-rw-r--r--lib/bundler/cli/gem.rb3
-rw-r--r--lib/bundler/cli/inject.rb2
-rw-r--r--lib/bundler/cli/install.rb4
-rw-r--r--lib/bundler/cli/lock.rb9
-rw-r--r--lib/bundler/cli/outdated.rb2
-rw-r--r--lib/bundler/cli/platform.rb2
-rw-r--r--lib/bundler/cli/show.rb2
-rw-r--r--lib/bundler/cli/update.rb6
-rw-r--r--lib/bundler/definition.rb113
-rw-r--r--lib/bundler/dependency.rb2
-rw-r--r--lib/bundler/deployment.rb2
-rw-r--r--lib/bundler/dsl.rb3
-rw-r--r--lib/bundler/endpoint_specification.rb2
-rw-r--r--lib/bundler/env.rb3
-rw-r--r--lib/bundler/errors.rb1
-rw-r--r--lib/bundler/feature_flag.rb27
-rw-r--r--lib/bundler/fetcher/compact_index.rb2
-rw-r--r--lib/bundler/fetcher/downloader.rb11
-rw-r--r--lib/bundler/gem_helpers.rb68
-rw-r--r--lib/bundler/inline.rb4
-rw-r--r--lib/bundler/installer.rb2
-rw-r--r--lib/bundler/lazy_specification.rb17
-rw-r--r--lib/bundler/lockfile_parser.rb2
-rw-r--r--lib/bundler/match_platform.rb3
-rw-r--r--lib/bundler/plugin.rb6
-rw-r--r--lib/bundler/postit_trampoline.rb19
-rw-r--r--lib/bundler/remote_specification.rb5
-rw-r--r--lib/bundler/resolver.rb102
-rw-r--r--lib/bundler/ruby_version.rb9
-rw-r--r--lib/bundler/rubygems_ext.rb15
-rw-r--r--lib/bundler/rubygems_gem_installer.rb48
-rw-r--r--lib/bundler/rubygems_integration.rb13
-rw-r--r--lib/bundler/runtime.rb3
-rw-r--r--lib/bundler/settings.rb25
-rw-r--r--lib/bundler/setup.rb2
-rw-r--r--lib/bundler/shared_helpers.rb3
-rw-r--r--lib/bundler/source.rb3
-rw-r--r--lib/bundler/source/git.rb2
-rw-r--r--lib/bundler/source/git/git_proxy.rb5
-rw-r--r--lib/bundler/source/path.rb7
-rw-r--r--lib/bundler/source/rubygems.rb3
-rw-r--r--lib/bundler/spec_set.rb41
-rw-r--r--lib/bundler/templates/newgem/README.md.tt2
-rw-r--r--lib/bundler/vendor/compact_index_client/lib/compact_index_client.rb29
-rw-r--r--lib/bundler/vendor/compact_index_client/lib/compact_index_client/updater.rb2
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb2
-rw-r--r--lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb10
-rw-r--r--lib/bundler/version.rb2
-rw-r--r--lib/bundler/yaml_serializer.rb2
-rw-r--r--man/bundle-config.ronn2
-rw-r--r--man/bundle-exec.ronn9
-rw-r--r--spec/bundler/definition_spec.rb69
-rw-r--r--spec/bundler/endpoint_specification_spec.rb13
-rw-r--r--spec/bundler/env_spec.rb9
-rw-r--r--spec/bundler/mirror_spec.rb10
-rw-r--r--spec/bundler/remote_specification_spec.rb22
-rw-r--r--spec/bundler/ruby_version_spec.rb8
-rw-r--r--spec/bundler/settings_spec.rb22
-rw-r--r--spec/bundler/source_spec.rb4
-rw-r--r--spec/bundler/yaml_serializer_spec.rb23
-rw-r--r--spec/commands/add_spec.rb86
-rw-r--r--spec/commands/doctor_spec.rb7
-rw-r--r--spec/commands/exec_spec.rb36
-rw-r--r--spec/commands/lock_spec.rb123
-rw-r--r--spec/commands/newgem_spec.rb29
-rw-r--r--spec/commands/update_spec.rb36
-rw-r--r--spec/install/gemfile/eval_gemfile_spec.rb18
-rw-r--r--spec/install/gemfile/specific_platform_spec.rb95
-rw-r--r--spec/install/gemfile_spec.rb29
-rw-r--r--spec/install/gems/compact_index_spec.rb43
-rw-r--r--spec/install/gems/resolving_spec.rb52
-rw-r--r--spec/install/gemspecs_spec.rb2
-rw-r--r--spec/install/path_spec.rb8
-rw-r--r--spec/other/major_deprecation_spec.rb16
-rw-r--r--spec/other/trampoline_spec.rb18
-rw-r--r--spec/realworld/edgecases_spec.rb12
-rw-r--r--spec/resolver/basic_spec.rb5
-rw-r--r--spec/resolver/platform_spec.rb2
-rw-r--r--spec/support/artifice/compact_index.rb11
-rw-r--r--spec/support/artifice/compact_index_concurrent_download.rb4
-rw-r--r--spec/support/artifice/compact_index_extra_api.rb4
-rw-r--r--spec/support/artifice/compact_index_wrong_gem_checksum.rb19
-rw-r--r--spec/support/builders.rb5
-rw-r--r--spec/support/helpers.rb6
-rw-r--r--spec/support/indexes.rb2
-rw-r--r--spec/support/matchers.rb6
-rw-r--r--spec/support/platforms.rb4
-rw-r--r--spec/support/rubygems_ext.rb17
-rw-r--r--spec/support/the_bundle.rb5
101 files changed, 1394 insertions, 333 deletions
diff --git a/.rubocop.yml b/.rubocop.yml
index cbce695fbd..b027d4cf54 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -119,6 +119,9 @@ Metrics/AbcSize:
Metrics/CyclomaticComplexity:
Enabled: false
+Metrics/ParameterLists:
+ Enabled: false
+
# It will be obvious which code is complex, Rubocop should only lint simple
# rules for us.
Metrics/PerceivedComplexity:
diff --git a/.travis.yml b/.travis.yml
index f8dd2dd7ca..04a0edc27a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,11 +13,6 @@ branches:
- /.+-stable$/
notifications:
- email:
- # andre
- - secure: "bCcvqJT7YrBawtkXXwHhT+jOFth7r2Qv/30PkkbhQxk6Jb3xambjCOJ3U6vJ\ngYmiL50exi5lUp3oc3SEbHN5t2CrZqOZDQ6o7P8EAmB5c0oH2RrYaFOkI5Gt\nul/jGH/96A9sj0aMwG7JfdMSfhqj1DUKAm2PnnbXPL853VfmT24="
- # terence
- - secure: "MQ8eA5Jb8YzEpAo58DRGfVJklAPcEbAulpBZnTxp0am6ldneDtJHbQk21w6R\nj5GsDHlzr/lMp/GHIimtUZ7rLohfND8fj/W7fs1Dkd4eN02/ERt98x3pHlqv\nvZgSnZ39uVYv+OcphraE24QaRaGWLhWZAMYQTVe/Yz50NyG8g1U="
slack:
on_success: change
on_failure: always
@@ -43,12 +38,16 @@ env:
# We need to know if changes to rubygems will break bundler on release
- RGV=master
# Test the latest rubygems release with all of our supported rubies
- - RGV=v2.6.4
- - RGV=v2.4.8
+ - RGV=v2.6.6
matrix:
include:
- # Ruby 2.2, Rubygems 2.4.5 and up (included by RGV above)
+ # Ruby 2.3, Rubygems 2.5.1 and up
+ - rvm: 2.2
+ env: RGV=v2.5.2
+ # Ruby 2.2, Rubygems 2.4.5 and up
+ - rvm: 2.2
+ env: RGV=v2.4.8
# Ruby 2.1, Rubygems 2.2.2 and up
- rvm: 2.1
env: RGV=v2.2.5
@@ -74,9 +73,12 @@ matrix:
env: RGV=v1.6.2
- rvm: 1.9.3
env: RGV=v1.5.3
+
# Ruby 1.8.7, Rubygems 1.3.6 and up
- rvm: 1.8.7
env: RGV=v2.2.5
+ # ALLOWED FAILURES
+ # since the great Travis image outage, frequent random segfaults :'(
- rvm: 1.8.7
env: RGV=v2.0.14
- rvm: 1.8.7
@@ -93,8 +95,6 @@ matrix:
env: RGV=v1.3.7
- rvm: 1.8.7
env: RGV=v1.3.6
-
- # ALLOWED FAILURES
# For no apparent reason, this often goes over the Travis limit
- rvm: 1.8.7
env: RGV=v2.1.11
@@ -104,5 +104,21 @@ matrix:
allow_failures:
- rvm: 1.8.7
+ env: RGV=v2.0.14
+ - rvm: 1.8.7
+ env: RGV=v1.8.29
+ - rvm: 1.8.7
+ env: RGV=v1.7.2
+ - rvm: 1.8.7
+ env: RGV=v1.6.2
+ - rvm: 1.8.7
+ env: RGV=v1.5.3
+ - rvm: 1.8.7
+ env: RGV=v1.4.2
+ - rvm: 1.8.7
+ env: RGV=v1.3.7
+ - rvm: 1.8.7
+ env: RGV=v1.3.6
+ - rvm: 1.8.7
env: RGV=v2.1.11
- rvm: ruby-head
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 22d1f1fb95..6961b52429 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,46 @@
+## 1.13.1 (2016-09-13)
+
+Bugfixes:
+
+ - ensure that `Gem::Source` is available, fixing several exceptions (#4944, @dekellum)
+ - ensure that dependency resolution works when multiple gems have the same dependency (#4961, @segiddins)
+
+## 1.13.0 (2016-09-05)
+
+This space deliberately left blank.
+
+## 1.13.0.rc.2 (2016-08-21)
+
+Features:
+
+ - add setting `exec_disable_load` to force `exec` to spawn a new Ruby process (@segiddins)
+ - add `doctor` command to help with issues like unlinked compiled gems (#4765, @mistydemeo)
+ - rework the `update` command, providing fine-grained control via flags (#4676, @chrismo)
+ - add URI to http response output in debug mode (#4808, @NickLaMuro)
+ - add manpage for `binstubs` command (#4847, @Zorbash)
+ - support `mirror` settings for sources by hostname, not only full URL (@opiethehokie)
+ - print gem installation errors after other install output (#4834, @segiddins)
+ - add `lock --remove-platform` flag to remove platforms from the lock (#4877, @segiddins)
+ - add `only_update_to_newer_versions` setting to prevent downgrades during `update` (@segiddins)
+ - expanded experimental plugin support to include hooks and sources (@asutoshpalai)
+
+Bugfixes:
+
+ - retry gem downloads (#4846, @jkeiser)
+ - improve the CompactIndex to handle capitalized legacy gems (#4867, @segiddins)
+ - re-use persistent HTTP connections for CompactIndex (@NickLaMuro)
+ - respect `required_ruby_version` when Gemfile contains `ruby` version (@indirect)
+ - allow `rake release` to sign git tags (#4743, @eagletmt)
+ - set process titles when using `#load` during `exec` (@yob)
+ - recognize JRuby shebangs for using `#load` during `exec` (@ojab)
+ - handle world-writable home directories (#4726, @allenzhao)
+ - support multi-platform gems via the `gemspec` Gemfile method (#4798, @segiddins)
+ - print dots correctly for CompactIndex fetcher (@NickLaMuro)
+ - set an `open_timeout` when requesting gem data via HTTP (@NickLaMuro)
+ - rename the BUNDLE\_ORIG\_ENV variable so it no longer shows up in `config` (@indirect)
+ - show help only when `-h` or `--help` is passed to Bundler, not to `exec` (#4801, @segiddins)
+ - handle symlinks to binstubs created by `--standalone` (#4782, @terinjokes)
+
## 1.13.0.rc.1 (2016-06-27)
Features:
@@ -5,7 +48,7 @@ Features:
- when `bundle config major_deprecations` or `BUNDLE_MAJOR_DEPRECATIONS` is set, deprecation warnings for bundler 2 will be printed (@segiddins)
- when running with `--verbose`, bundler will print the reason it is re-resolving a gemfile (@segiddins)
-Bug fixes:
+Bugfixes:
- fix support for running RubyGems 1.x on Ruby 2.3 (#4698, @segiddins)
- fix bundle exec'ing to a ruby file when gems are installed into a path (#4592, @chrismo)
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
index 8964b75c3d..ab95db363a 100644
--- a/DEVELOPMENT.md
+++ b/DEVELOPMENT.md
@@ -40,6 +40,8 @@ Bundler doesn't use a Gemfile to list development dependencies, because when we
The `BUNDLE_DISABLE_POSTIT` environment variable ensures that the version of Bundler in `/path/to/bundler/lib` will be used. Without that environment setting, Bundler will automatically download, install, and run the version of Bundler listed in `Gemfile.lock`. With that set up, you can test changes you've made to Bundler by running `dbundle`, without interfering with the regular `bundle` command.
+To dive into the code with Pry: `RUBYOPT=-rpry dbundle` to require pry and then run commands.
+
# Submitting Pull Requests
Before you submit a pull request, please remember to do the following:
diff --git a/Rakefile b/Rakefile
index 7c4a2eb0a4..cc7162a6ef 100644
--- a/Rakefile
+++ b/Rakefile
@@ -127,7 +127,7 @@ begin
rubyopt = ENV["RUBYOPT"]
# When editing this list, also edit .travis.yml!
branches = %w(master)
- releases = %w(v1.3.6 v1.3.7 v1.4.2 v1.5.3 v1.6.2 v1.7.2 v1.8.29 v2.0.14 v2.1.11 v2.2.5 v2.4.8 v2.6.4)
+ releases = %w(v1.3.6 v1.3.7 v1.4.2 v1.5.3 v1.6.2 v1.7.2 v1.8.29 v2.0.14 v2.1.11 v2.2.5 v2.4.8 v2.5.2 v2.6.6)
(branches + releases).each do |rg|
desc "Run specs with Rubygems #{rg}"
RSpec::Core::RakeTask.new(rg) do |t|
diff --git a/exe/bundle b/exe/bundle
index 51a9035d97..ec88ea7552 100755
--- a/exe/bundle
+++ b/exe/bundle
@@ -4,12 +4,10 @@
# Exit cleanly from an early interrupt
Signal.trap("INT") { exit 1 }
-unless ENV["BUNDLE_DISABLE_POSTIT"]
- update = "update".start_with?(ARGV.first || " ") && ARGV.find {|a| a.start_with?("--bundler") }
- update &&= update =~ /--bundler(?:=(.+))?/ && $1 || "> 0.a"
- ENV["BUNDLER_VERSION"] = update if update
- require "bundler/postit_trampoline"
-end
+update = "update".start_with?(ARGV.first || " ") && ARGV.find {|a| a.start_with?("--bundler") }
+update &&= update =~ /--bundler(?:=(.+))?/ && $1 || "> 0.a"
+ENV["BUNDLER_VERSION"] = update if update
+require "bundler/postit_trampoline"
require "bundler"
# Check if an older version of bundler is installed
diff --git a/lib/bundler.rb b/lib/bundler.rb
index 8b3f60d36a..f5bbd61f57 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -27,6 +27,7 @@ module Bundler
autoload :EndpointSpecification, "bundler/endpoint_specification"
autoload :Env, "bundler/env"
autoload :Fetcher, "bundler/fetcher"
+ autoload :FeatureFlag, "bundler/feature_flag"
autoload :GemHelper, "bundler/gem_helper"
autoload :GemHelpers, "bundler/gem_helpers"
autoload :GemVersionPromoter, "bundler/gem_version_promoter"
@@ -90,7 +91,7 @@ module Bundler
# Return if all groups are already loaded
return @setup if defined?(@setup) && @setup
- definition.validate_ruby!
+ definition.validate_runtime!
SharedHelpers.print_major_deprecations!
@@ -328,17 +329,23 @@ EOF
def sudo(str)
SUDO_MUTEX.synchronize do
prompt = "\n\n" + <<-PROMPT.gsub(/^ {6}/, "").strip + " "
- Your user account isn't allowed to install to the system Rubygems.
+ Your user account isn't allowed to install to the system RubyGems.
You can cancel this installation and run:
bundle install --path vendor/bundle
to install the gems into ./vendor/bundle/, or you can enter your password
- and install the bundled gems to Rubygems using sudo.
+ and install the bundled gems to RubyGems using sudo.
Password:
PROMPT
+ unless @prompted_for_sudo ||= system(%(sudo -k -p "#{prompt}" true))
+ raise SudoNotPermittedError,
+ "Bundler requires sudo access to install at the moment. " \
+ "Try installing again, granting Bundler sudo access when prompted, or installing into a different path."
+ end
+
`sudo -p "#{prompt}" #{str}`
end
end
@@ -389,6 +396,10 @@ EOF
@git_present = Bundler.which("git") || Bundler.which("git.exe")
end
+ def feature_flag
+ @feature_flag ||= FeatureFlag.new(VERSION)
+ end
+
def reset!
@root = nil
@settings = nil
diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb
index 75cceee80d..ee18767a73 100644
--- a/lib/bundler/cli.rb
+++ b/lib/bundler/cli.rb
@@ -92,7 +92,7 @@ module Bundler
end
def self.handle_no_command_error(command, has_namespace = $thor_runner)
- if Bundler.settings[:plugins] && Bundler::Plugin.command?(command)
+ if Bundler.feature_flag.plugins? && Bundler::Plugin.command?(command)
return Bundler::Plugin.exec_command(command, ARGV[1..-1])
end
@@ -184,11 +184,9 @@ module Bundler
map "i" => "install"
def install
require "bundler/cli/install"
- no_install = Bundler.settings[:no_install]
- Bundler.settings[:no_install] = false if no_install == true
- Install.new(options.dup).run
- ensure
- Bundler.settings[:no_install] = no_install unless no_install.nil?
+ Bundler.settings.temporary(:no_install => false) do
+ Install.new(options.dup).run
+ end
end
desc "update [OPTIONS]", "update the current environment"
@@ -255,7 +253,7 @@ module Bundler
"Overwrite existing binstubs if they exist"
method_option "path", :type => :string, :lazy_default => "bin", :banner =>
"Binstub destination directory (default bin)"
- method_option "standalone", :type => :array, :lazy_default => [], :banner =>
+ method_option "standalone", :type => :boolean, :banner =>
"Make binstubs that can work without the Bundler runtime"
def binstubs(*gems)
require "bundler/cli/binstubs"
@@ -437,12 +435,13 @@ module Bundler
desc "inject GEM VERSION ...", "Add the named gem(s), with version requirements, to the resolved Gemfile"
def inject(name, version, *gems)
+ SharedHelpers.major_deprecation "The `inject` command has been replaced by the `add` command"
require "bundler/cli/inject"
Inject.new(options, name, version, gems).run
end
desc "lock", "Creates a lockfile without installing"
- method_option "update", :type => :array, :lazy_default => [], :banner =>
+ method_option "update", :type => :array, :lazy_default => true, :banner =>
"ignore the existing lockfile, update all gems by default, or update list of given gems"
method_option "local", :type => :boolean, :default => false, :banner =>
"do not attempt to fetch remote gemspecs and use the local gem cache only"
@@ -466,16 +465,6 @@ module Bundler
Env.new.write($stdout)
end
- desc "add GEM [VERSION]", "Add the specified gem to the bottom of Gemfile"
- method_option "group", :type => :array, :aliases => "-g", :desc => "Specify groups to add the gem in"
- method_option "source", :type => :string, :aliases => "-s", :desc => "Specify the gem's source"
- method_option "pre", :type => :boolean, :aliases => "-p", :default => false, :desc => "Check for newer pre-release gems"
- method_option "timestamp", :type => :boolean, :aliases => "-t", :default => false, :desc => "Append timestamp to Gemfile"
- def add(name, version = nil, *gems)
- require "bundler/cli/inject"
- Inject.new(options, name, version, gems).run
- end
-
desc "doctor [OPTIONS]", "Checks the bundle for common problems"
long_desc <<-D
Doctor scans the OS dependencies of each of the gems requested in the Gemfile. If
@@ -491,7 +480,7 @@ module Bundler
Doctor.new(options).run
end
- if Bundler.settings[:plugins]
+ if Bundler.feature_flag.plugins?
require "bundler/cli/plugin"
desc "plugin SUBCOMMAND ...ARGS", "manage the bundler plugins"
subcommand "plugin", Plugin
diff --git a/lib/bundler/cli/binstubs.rb b/lib/bundler/cli/binstubs.rb
index f7a27b01bb..95103b7dd8 100644
--- a/lib/bundler/cli/binstubs.rb
+++ b/lib/bundler/cli/binstubs.rb
@@ -10,7 +10,7 @@ module Bundler
end
def run
- Bundler.definition.validate_ruby!
+ Bundler.definition.validate_runtime!
Bundler.settings[:bin] = options["path"] if options["path"]
Bundler.settings[:bin] = nil if options["path"] && options["path"].empty?
installer = Installer.new(Bundler.root, Bundler.definition)
diff --git a/lib/bundler/cli/cache.rb b/lib/bundler/cli/cache.rb
index c8c63e926c..5ba105a31d 100644
--- a/lib/bundler/cli/cache.rb
+++ b/lib/bundler/cli/cache.rb
@@ -7,7 +7,7 @@ module Bundler
end
def run
- Bundler.definition.validate_ruby!
+ Bundler.definition.validate_runtime!
Bundler.definition.resolve_with_cache!
setup_cache_all
Bundler.settings[:cache_all_platforms] = options["all-platforms"] if options.key?("all-platforms")
diff --git a/lib/bundler/cli/check.rb b/lib/bundler/cli/check.rb
index 738d40b622..3f504ff621 100644
--- a/lib/bundler/cli/check.rb
+++ b/lib/bundler/cli/check.rb
@@ -15,7 +15,7 @@ module Bundler
begin
definition = Bundler.definition
- definition.validate_ruby!
+ definition.validate_runtime!
not_installed = definition.missing_specs
rescue GemNotFound, VersionConflict
Bundler.ui.error "Bundler can't satisfy your Gemfile's dependencies."
diff --git a/lib/bundler/cli/doctor.rb b/lib/bundler/cli/doctor.rb
index 8fd862a1c2..728662024b 100644
--- a/lib/bundler/cli/doctor.rb
+++ b/lib/bundler/cli/doctor.rb
@@ -14,11 +14,11 @@ module Bundler
end
def otool_available?
- system("otool --version 2>&1 >#{Bundler::NULL}")
+ system("otool --version 2>#{Bundler::NULL} >#{Bundler::NULL}")
end
def ldd_available?
- !system("ldd --help 2>&1 >#{Bundler::NULL}").nil?
+ !system("ldd --help 2>#{Bundler::NULL} >#{Bundler::NULL}").nil?
end
def dylibs_darwin(path)
@@ -55,22 +55,18 @@ module Bundler
Dir.glob("#{spec.full_gem_path}/**/*.bundle")
end
+ def check!
+ require "bundler/cli/check"
+ Bundler::CLI::Check.new({}).run
+ end
+
def run
Bundler.ui.level = "error" if options[:quiet]
+ check!
+ definition = Bundler.definition
broken_links = {}
- begin
- definition = Bundler.definition
- definition.validate_ruby!
- not_installed = definition.missing_specs
- raise GemNotFound if not_installed.any?
- rescue GemNotFound
- Bundler.ui.warn "This bundle's gems must be installed to run this command."
- Bundler.ui.warn "Install missing gems with `bundle install`."
- exit 0
- end
-
definition.specs.each do |spec|
bundles_for_gem(spec).each do |bundle|
bad_paths = dylibs(bundle).select {|f| !File.exist?(f) }
@@ -82,13 +78,15 @@ module Bundler
end
if broken_links.any?
- Bundler.ui.error "The following gems are missing OS dependencies"
- broken_links.each do |spec, paths|
- paths.uniq.each do |path|
- Bundler.ui.error " * #{spec.name}: #{path}"
+ message = "The following gems are missing OS dependencies:"
+ broken_links.map do |spec, paths|
+ paths.uniq.map do |path|
+ "\n * #{spec.name}: #{path}"
end
- end
- exit 1
+ end.flatten.sort.each {|m| message += m }
+ raise ProductionError, message
+ else
+ Bundler.ui.info "No issues found with the installed bundle"
end
end
end
diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb
index 27f4262e30..4dc0dbdb6b 100644
--- a/lib/bundler/cli/gem.rb
+++ b/lib/bundler/cli/gem.rb
@@ -44,7 +44,8 @@ module Bundler
:test => options[:test],
:ext => options[:ext],
:exe => options[:exe],
- :bundler_version => bundler_dependency_version
+ :bundler_version => bundler_dependency_version,
+ :git_user_name => git_user_name.empty? ? "[USERNAME]" : git_user_name
}
ensure_safe_gem_name(name, constant_array)
diff --git a/lib/bundler/cli/inject.rb b/lib/bundler/cli/inject.rb
index 262514d587..9d1d08120a 100644
--- a/lib/bundler/cli/inject.rb
+++ b/lib/bundler/cli/inject.rb
@@ -31,7 +31,7 @@ module Bundler
Bundler.ui.confirm "Added to Gemfile:"
Bundler.ui.confirm added.map {|g| " #{g}" }.join("\n")
else
- Bundler.ui.confirm "All injected gems were already present in the Gemfile"
+ Bundler.ui.confirm "All gems were already present in the Gemfile"
end
end
diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb
index 5c7b8c5b0b..f1632c9ee2 100644
--- a/lib/bundler/cli/install.rb
+++ b/lib/bundler/cli/install.rb
@@ -63,10 +63,10 @@ module Bundler
# rubygems plugins sometimes hook into the gem install process
Gem.load_env_plugins if Gem.respond_to?(:load_env_plugins)
- Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.settings[:plugins]
+ Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins?
definition = Bundler.definition
- definition.validate_ruby!
+ definition.validate_runtime!
installer = Installer.install(Bundler.root, definition, options)
Bundler.load.cache if Bundler.app_cache.exist? && !options["no-cache"] && !Bundler.settings[:frozen]
diff --git a/lib/bundler/cli/lock.rb b/lib/bundler/cli/lock.rb
index a6a95f895c..d4256ad4b9 100644
--- a/lib/bundler/cli/lock.rb
+++ b/lib/bundler/cli/lock.rb
@@ -17,14 +17,11 @@ module Bundler
ui = Bundler.ui
Bundler.ui = UI::Silent.new if print
- gems = options[:update]
Bundler::Fetcher.disable_endpoint = options["full-index"]
- if gems && !gems.empty?
- definition = Bundler.definition(:gems => gems)
- else
- definition = Bundler.definition(true)
- end
+ update = options[:update]
+ update = { :gems => update } if update.is_a?(Array)
+ definition = Bundler.definition(update)
options["remove-platform"].each do |platform|
definition.remove_platform(platform)
diff --git a/lib/bundler/cli/outdated.rb b/lib/bundler/cli/outdated.rb
index 09b2d71453..de71075522 100644
--- a/lib/bundler/cli/outdated.rb
+++ b/lib/bundler/cli/outdated.rb
@@ -18,7 +18,7 @@ module Bundler
Bundler::CLI::Common.select_spec(gem_name)
end
- Bundler.definition.validate_ruby!
+ Bundler.definition.validate_runtime!
current_specs = Bundler.ui.silence { Bundler.load.specs }
current_dependencies = {}
Bundler.ui.silence { Bundler.load.dependencies.each {|dep| current_dependencies[dep.name] = dep } }
diff --git a/lib/bundler/cli/platform.rb b/lib/bundler/cli/platform.rb
index b5f906bfd9..9fdab0a53c 100644
--- a/lib/bundler/cli/platform.rb
+++ b/lib/bundler/cli/platform.rb
@@ -29,7 +29,7 @@ module Bundler
output << "Your Gemfile specifies a Ruby version requirement:\n* #{ruby_version}"
begin
- Bundler.definition.validate_ruby!
+ Bundler.definition.validate_runtime!
output << "Your current platform satisfies the Ruby version requirement."
rescue RubyVersionMismatch => e
output << e.message
diff --git a/lib/bundler/cli/show.rb b/lib/bundler/cli/show.rb
index d67b086dd1..77e845a603 100644
--- a/lib/bundler/cli/show.rb
+++ b/lib/bundler/cli/show.rb
@@ -13,7 +13,7 @@ module Bundler
def run
Bundler.ui.silence do
- Bundler.definition.validate_ruby!
+ Bundler.definition.validate_runtime!
Bundler.load.lock
end
diff --git a/lib/bundler/cli/update.rb b/lib/bundler/cli/update.rb
index 1c35659e0b..5aac47bd09 100644
--- a/lib/bundler/cli/update.rb
+++ b/lib/bundler/cli/update.rb
@@ -10,7 +10,7 @@ module Bundler
def run
Bundler.ui.level = "error" if options[:quiet]
- Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.settings[:plugins]
+ Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins?
sources = Array(options[:source])
groups = Array(options[:group]).map(&:to_sym)
@@ -40,7 +40,7 @@ module Bundler
end
patch_level = [:major, :minor, :patch].select {|v| options.keys.include?(v.to_s) }
- raise ProductionError, "Provide only one of the following options: #{patch_level.join(", ")}" unless patch_level.length <= 1
+ raise InvalidOption, "Provide only one of the following options: #{patch_level.join(", ")}" unless patch_level.length <= 1
Bundler.definition.gem_version_promoter.tap do |gvp|
gvp.level = patch_level.first || :major
gvp.strict = options[:strict]
@@ -57,7 +57,7 @@ module Bundler
# rubygems plugins sometimes hook into the gem install process
Gem.load_env_plugins if Gem.respond_to?(:load_env_plugins)
- Bundler.definition.validate_ruby!
+ Bundler.definition.validate_runtime!
Installer.install Bundler.root, Bundler.definition, opts
Bundler.load.cache if Bundler.app_cache.exist?
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb
index ee966e7164..12951cdf9c 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -62,6 +62,7 @@ module Bundler
@specs = nil
@ruby_version = ruby_version
+ @lockfile = lockfile
@lockfile_contents = String.new
@locked_bundler_version = nil
@locked_ruby_version = nil
@@ -69,7 +70,8 @@ module Bundler
if lockfile && File.exist?(lockfile)
@lockfile_contents = Bundler.read_file(lockfile)
@locked_gems = LockfileParser.new(@lockfile_contents)
- @platforms = @locked_gems.platforms
+ @locked_platforms = @locked_gems.platforms
+ @platforms = @locked_platforms.dup
@locked_bundler_version = @locked_gems.bundler_version
@locked_ruby_version = @locked_gems.ruby_version
@@ -90,28 +92,24 @@ module Bundler
@locked_deps = []
@locked_specs = SpecSet.new([])
@locked_sources = []
+ @locked_platforms = []
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
+ @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object
@ruby_version.diff(locked_ruby_version_object)
end
@unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version)
- @gem_version_promoter = create_gem_version_promoter
-
- current_platform = Bundler.rubygems.platforms.map {|p| generic(p) }.compact.last
- add_platform(current_platform)
+ add_current_platform unless Bundler.settings[:frozen]
@path_changes = converge_paths
eager_unlock = expand_dependencies(@unlock[:gems])
@unlock[:gems] = @locked_specs.for(eager_unlock).map(&:name)
+ @gem_version_promoter = create_gem_version_promoter
+
@source_changes = converge_sources
@dependency_changes = converge_dependencies
@local_changes = converge_locals
@@ -137,17 +135,15 @@ module Bundler
end
def create_gem_version_promoter
- locked_specs = begin
+ locked_specs =
if @unlocking && @locked_specs.empty? && !@lockfile_contents.empty?
# Definition uses an empty set of locked_specs to indicate all gems
# are unlocked, but GemVersionPromoter needs the locked_specs
# for conservative comparison.
- locked = Bundler::LockfileParser.new(@lockfile_contents)
- Bundler::SpecSet.new(locked.specs)
+ Bundler::SpecSet.new(@locked_gems.specs)
else
@locked_specs
end
- end
GemVersionPromoter.new(locked_specs, @unlock[:gems])
end
@@ -249,7 +245,7 @@ module Bundler
else
# Run a resolve against the locally available gems
Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}")
- last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, ruby_version, gem_version_promoter)
+ last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve)
end
end
end
@@ -264,6 +260,8 @@ module Bundler
dependency_names -= pinned_spec_names(source.specs)
dependency_names.concat(source.unmet_deps).uniq!
end
+ idx << Gem::Specification.new("ruby\0", RubyVersion.system.to_gem_version_with_patchlevel)
+ idx << Gem::Specification.new("rubygems\0", Gem::VERSION)
end
end
@@ -340,6 +338,18 @@ module Bundler
end
end
+ def locked_ruby_version_object
+ return unless @locked_ruby_version
+ @locked_ruby_version_object ||= begin
+ unless version = RubyVersion.from_string(@locked_ruby_version)
+ raise LockfileError, "The Ruby version #{@locked_ruby_version} from " \
+ "#{@lockfile} could not be parsed. " \
+ "Try running bundle update --ruby to resolve this."
+ end
+ version
+ end
+ end
+
def to_lock
out = String.new
@@ -403,6 +413,11 @@ module Bundler
deleted = []
changed = []
+ new_platforms = @platforms - @locked_platforms
+ deleted_platforms = @locked_platforms - @platforms
+ added.concat new_platforms.map {|p| "* platform: #{p}" }
+ deleted.concat deleted_platforms.map {|p| "* platform: #{p}" }
+
gemfile_sources = sources.lock_sources
new_sources = gemfile_sources - @locked_sources
@@ -451,6 +466,11 @@ module Bundler
raise ProductionError, msg if added.any? || deleted.any? || changed.any?
end
+ def validate_runtime!
+ validate_ruby!
+ validate_platforms!
+ end
+
def validate_ruby!
return unless ruby_version
@@ -476,6 +496,22 @@ module Bundler
end
end
+ # TODO: refactor this so that `match_platform` can be called with two platforms
+ DummyPlatform = Struct.new(:platform)
+ class DummyPlatform; include MatchPlatform; end
+ def validate_platforms!
+ return if @platforms.any? do |bundle_platform|
+ bundle_platform = DummyPlatform.new(bundle_platform)
+ Bundler.rubygems.platforms.any? do |local_platform|
+ bundle_platform.match_platform(local_platform)
+ end
+ end
+
+ raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \
+ "but your local platforms are #{Bundler.rubygems.platforms.map(&:to_s)}, and " \
+ "there's no compatible match between those two lists."
+ end
+
def add_platform(platform)
@new_platform ||= !@platforms.include?(platform)
@platforms |= [platform]
@@ -486,6 +522,12 @@ module Bundler
raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}"
end
+ def add_current_platform
+ current_platform = Bundler.rubygems.platforms.last
+ add_platform(current_platform) if Bundler.settings[:specific_platform]
+ add_platform(generic(current_platform))
+ end
+
attr_reader :sources
private :sources
@@ -728,8 +770,38 @@ module Bundler
@locked_specs.any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) }
end
+ # This list of dependencies is only used in #resolve, so it's OK to add
+ # the metadata dependencies here
def expanded_dependencies
- @expanded_dependencies ||= expand_dependencies(dependencies, @remote)
+ @expanded_dependencies ||= begin
+ ruby_versions = concat_ruby_version_requirements(@ruby_version)
+ if ruby_versions.empty? || !@ruby_version.exact?
+ concat_ruby_version_requirements(RubyVersion.system)
+ concat_ruby_version_requirements(locked_ruby_version_object) unless @unlock[:ruby]
+ end
+
+ metadata_dependencies = [
+ Dependency.new("ruby\0", ruby_versions),
+ Dependency.new("rubygems\0", Gem::VERSION),
+ ]
+ expand_dependencies(dependencies + metadata_dependencies, @remote)
+ end
+ end
+
+ def concat_ruby_version_requirements(ruby_version, ruby_versions = [])
+ return ruby_versions unless ruby_version
+ if ruby_version.patchlevel
+ ruby_versions << ruby_version.to_gem_version_with_patchlevel
+ else
+ ruby_versions.concat(ruby_version.versions.map do |version|
+ requirement = Gem::Requirement.new(version)
+ if requirement.exact?
+ "~> #{version}.0"
+ else
+ requirement
+ end
+ end)
+ end
end
def expand_dependencies(dependencies, remote = false)
@@ -812,5 +884,14 @@ module Bundler
requires
end
end
+
+ def additional_base_requirements_for_resolve
+ return [] unless @locked_gems && Bundler.settings[:only_update_to_newer_versions]
+ @locked_gems.specs.reduce({}) do |requirements, locked_spec|
+ dep = Gem::Dependency.new(locked_spec.name, ">= #{locked_spec.version}")
+ requirements[locked_spec.name] = DepProxy.new(dep, locked_spec.platform)
+ requirements
+ end.values
+ end
end
end
diff --git a/lib/bundler/dependency.rb b/lib/bundler/dependency.rb
index 1b1808b40a..66162d741a 100644
--- a/lib/bundler/dependency.rb
+++ b/lib/bundler/dependency.rb
@@ -52,7 +52,7 @@ module Bundler
:x64_mingw_20 => Gem::Platform::X64_MINGW,
:x64_mingw_21 => Gem::Platform::X64_MINGW,
:x64_mingw_22 => Gem::Platform::X64_MINGW,
- :x64_mingw_23 => Gem::Platform::X64_MINGW
+ :x64_mingw_23 => Gem::Platform::X64_MINGW,
}.freeze
REVERSE_PLATFORM_MAP = {}.tap do |reverse_platform_map|
diff --git a/lib/bundler/deployment.rb b/lib/bundler/deployment.rb
index 94f2fac620..a62fa232fb 100644
--- a/lib/bundler/deployment.rb
+++ b/lib/bundler/deployment.rb
@@ -15,7 +15,7 @@ module Bundler
else
context_name = "vlad"
role_default = "[:app]"
- error_type = ::Rake::CommandFailedError
+ error_type = ::Vlad::CommandFailedError
end
roles = context.fetch(:bundle_roles, false)
diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb
index b064c80d4c..428ccd4c2d 100644
--- a/lib/bundler/dsl.rb
+++ b/lib/bundler/dsl.rb
@@ -393,7 +393,8 @@ module Bundler
"as an option for #{command}, but it is invalid."
end
- message << " Valid options are: #{valid_keys.join(", ")}"
+ message << " Valid options are: #{valid_keys.join(", ")}."
+ message << " You may be able to resolve this by upgrading Bundler to the newest version."
raise InvalidOption, message
end
end
diff --git a/lib/bundler/endpoint_specification.rb b/lib/bundler/endpoint_specification.rb
index 69d05167e8..4f5377d3cc 100644
--- a/lib/bundler/endpoint_specification.rb
+++ b/lib/bundler/endpoint_specification.rb
@@ -113,6 +113,8 @@ module Bundler
@required_ruby_version = Gem::Requirement.new(v)
end
end
+ rescue => e
+ raise GemspecError, "There was an error parsing the metadata for the gem #{name} (#{version}): #{e.class}\n#{e}\nThe metadata was #{data.inspect}"
end
def build_dependency(name, requirements)
diff --git a/lib/bundler/env.rb b/lib/bundler/env.rb
index 75edbf2b88..74541681ef 100644
--- a/lib/bundler/env.rb
+++ b/lib/bundler/env.rb
@@ -20,6 +20,7 @@ module Bundler
out << " GEM_PATH #{ENV["GEM_PATH"]}\n" unless ENV["GEM_PATH"] == ENV["GEM_HOME"]
out << " RVM #{ENV["rvm_version"]}\n" if ENV["rvm_version"]
out << " Git #{git_version}\n"
+ out << " OpenSSL #{OpenSSL::OPENSSL_VERSION}\n" if defined?(OpenSSL::OPENSSL_VERSION)
%w(rubygems-bundler open_gem).each do |name|
specs = Bundler.rubygems.find_name(name)
out << " #{name} (#{specs.map(&:version).join(",")})\n" unless specs.empty?
@@ -33,6 +34,8 @@ module Bundler
end
end
+ return out unless SharedHelpers.in_bundle?
+
if print_gemfile
out << "\n#{Bundler.default_gemfile.relative_path_from(SharedHelpers.pwd)}\n\n"
out << " " << read_file(Bundler.default_gemfile).gsub(/\n/, "\n ") << "\n"
diff --git a/lib/bundler/errors.rb b/lib/bundler/errors.rb
index 7681ea73ae..dd5782fb3d 100644
--- a/lib/bundler/errors.rb
+++ b/lib/bundler/errors.rb
@@ -52,6 +52,7 @@ module Bundler
class CyclicDependencyError < BundlerError; status_code(21); end
class GemfileLockNotFound < BundlerError; status_code(22); end
class PluginError < BundlerError; status_code(29); end
+ class SudoNotPermittedError < BundlerError; status_code(30); end
class GemfileEvalError < GemfileError; end
class MarshalError < StandardError; end
diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb
new file mode 100644
index 0000000000..80bf2a5150
--- /dev/null
+++ b/lib/bundler/feature_flag.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+module Bundler
+ class FeatureFlag
+ def self.settings_flag(flag)
+ unless Bundler::Settings::BOOL_KEYS.include?(flag.to_s)
+ raise "Cannot use `#{flag}` as a settings feature flag since it isn't a bool key"
+ end
+ define_method("#{flag}?") { Bundler.settings[flag] }
+ end
+
+ (1..10).each {|v| define_method("bundler_#{v}_mode?") { major_version >= v } }
+
+ settings_flag :allow_offline_install
+ settings_flag :plugins
+
+ def initialize(bundler_version)
+ @bundler_version = Gem::Version.create(bundler_version)
+ end
+
+ def major_version
+ @bundler_version.segments.first
+ end
+ private :major_version
+
+ class << self; private :settings_flag; end
+ end
+end
diff --git a/lib/bundler/fetcher/compact_index.rb b/lib/bundler/fetcher/compact_index.rb
index fb77451822..9461368df5 100644
--- a/lib/bundler/fetcher/compact_index.rb
+++ b/lib/bundler/fetcher/compact_index.rb
@@ -110,7 +110,7 @@ module Bundler
begin
downloader.fetch(fetch_uri + path, headers)
rescue NetworkDownError => e
- raise unless Bundler.settings[:allow_offline_install] && headers["If-None-Match"]
+ raise unless Bundler.feature_flag.allow_offline_install? && headers["If-None-Match"]
Bundler.ui.warn "Using the cached data for the new index because of a network error: #{e}"
Net::HTTPNotModified.new(nil, nil, nil)
end
diff --git a/lib/bundler/fetcher/downloader.rb b/lib/bundler/fetcher/downloader.rb
index c8d714c05a..ee1aa1a972 100644
--- a/lib/bundler/fetcher/downloader.rb
+++ b/lib/bundler/fetcher/downloader.rb
@@ -38,6 +38,8 @@ module Bundler
end
def request(uri, options)
+ validate_uri_scheme!(uri)
+
Bundler.ui.debug "HTTP GET #{uri}"
req = Net::HTTP::Get.new uri.request_uri, options
if uri.user
@@ -61,6 +63,15 @@ module Bundler
raise HTTPError, "Network error while fetching #{URICredentialsFilter.credential_filtered_uri(uri)}"
end
end
+
+ private
+
+ def validate_uri_scheme!(uri)
+ return if uri.scheme =~ /\Ahttps?\z/
+ raise InvalidOption,
+ "The request uri `#{uri}` has an invalid scheme (`#{uri.scheme}`). " \
+ "Did you mean `http` or `https`?"
+ end
end
end
end
diff --git a/lib/bundler/gem_helpers.rb b/lib/bundler/gem_helpers.rb
index 5c824ffefc..6d926ce83f 100644
--- a/lib/bundler/gem_helpers.rb
+++ b/lib/bundler/gem_helpers.rb
@@ -28,5 +28,73 @@ module Bundler
generic(Gem::Platform.local)
end
module_function :generic_local_platform
+
+ def platform_specificity_match(spec_platform, user_platform)
+ spec_platform = Gem::Platform.new(spec_platform)
+ return PlatformMatch::EXACT_MATCH if spec_platform == user_platform
+ return PlatformMatch::WORST_MATCH if spec_platform.nil? || spec_platform == Gem::Platform::RUBY || user_platform == Gem::Platform::RUBY
+
+ PlatformMatch.new(
+ PlatformMatch.os_match(spec_platform, user_platform),
+ PlatformMatch.cpu_match(spec_platform, user_platform),
+ PlatformMatch.platform_version_match(spec_platform, user_platform)
+ )
+ end
+ module_function :platform_specificity_match
+
+ def select_best_platform_match(specs, platform)
+ specs.select {|spec| spec.match_platform(platform) }.
+ min_by {|spec| platform_specificity_match(spec.platform, platform) }
+ end
+ module_function :select_best_platform_match
+
+ PlatformMatch = Struct.new(:os_match, :cpu_match, :platform_version_match)
+ class PlatformMatch
+ def <=>(other)
+ return nil unless other.is_a?(PlatformMatch)
+
+ m = os_match <=> other.os_match
+ return m unless m.zero?
+
+ m = cpu_match <=> other.cpu_match
+ return m unless m.zero?
+
+ m = platform_version_match <=> other.platform_version_match
+ m
+ end
+
+ EXACT_MATCH = new(-1, -1, -1).freeze
+ WORST_MATCH = new(1_000_000, 1_000_000, 1_000_000).freeze
+
+ def self.os_match(spec_platform, user_platform)
+ if spec_platform.os == user_platform.os
+ 0
+ else
+ 1
+ end
+ end
+
+ def self.cpu_match(spec_platform, user_platform)
+ if spec_platform.cpu == user_platform.cpu
+ 0
+ elsif spec_platform.cpu == "arm" && user_platform.cpu.to_s.start_with?("arm")
+ 0
+ elsif spec_platform.cpu.nil? || spec_platform.cpu == "universal"
+ 1
+ else
+ 2
+ end
+ end
+
+ def self.platform_version_match(spec_platform, user_platform)
+ if spec_platform.version == user_platform.version
+ 0
+ elsif spec_platform.version.nil?
+ 1
+ else
+ 2
+ end
+ end
+ end
end
end
diff --git a/lib/bundler/inline.rb b/lib/bundler/inline.rb
index dcaf22944c..dec3be3e98 100644
--- a/lib/bundler/inline.rb
+++ b/lib/bundler/inline.rb
@@ -41,13 +41,13 @@ def gemfile(install = false, options = {}, &gemfile)
end
ENV["BUNDLE_GEMFILE"] ||= "Gemfile"
- Bundler::Plugin.gemfile_install(&gemfile) if Bundler.settings[:plugins]
+ Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins?
builder = Bundler::Dsl.new
builder.instance_eval(&gemfile)
definition = builder.to_definition(nil, true)
def definition.lock(*); end
- definition.validate_ruby!
+ definition.validate_runtime!
missing_specs = proc do
begin
diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb
index 528dee177e..824b1a45cd 100644
--- a/lib/bundler/installer.rb
+++ b/lib/bundler/installer.rb
@@ -207,7 +207,7 @@ module Bundler
end unless Bundler.bundle_path.exist?
rescue Errno::EEXIST
raise PathError, "Could not install to path `#{Bundler.settings[:path]}` " \
- "because of an invalid symlink. Remove the symlink so the directory can be created."
+ "because a file already exists at that path. Either remove or rename the file so the directory can be created."
end
def resolve_if_need(options)
diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb
index 36ff5c59ed..0b667f7dbe 100644
--- a/lib/bundler/lazy_specification.rb
+++ b/lib/bundler/lazy_specification.rb
@@ -6,6 +6,20 @@ require "bundler/match_platform"
module Bundler
class LazySpecification
Identifier = Struct.new(:name, :version, :source, :platform, :dependencies)
+ class Identifier
+ include Comparable
+ def <=>(other)
+ return unless other.is_a?(Identifier)
+ [name, version, platform_string] <=> [other.name, other.version, other.platform_string]
+ end
+
+ protected
+
+ def platform_string
+ platform_string = platform.to_s
+ platform_string == Index::RUBY ? Index::NULL : platform_string
+ end
+ end
include MatchPlatform
@@ -55,7 +69,8 @@ module Bundler
end
def __materialize__
- @specification = source.specs.search(Gem::Dependency.new(name, version)).last
+ search_object = Bundler.settings[:specific_platform] ? self : Dependency.new(name, version)
+ @specification = source.specs.search(search_object).last
end
def respond_to?(*args)
diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb
index 063a1887fa..51148ab614 100644
--- a/lib/bundler/lockfile_parser.rb
+++ b/lib/bundler/lockfile_parser.rb
@@ -92,7 +92,7 @@ module Bundler
end
end
@sources << @rubygems_aggregate
- @specs = @specs.values
+ @specs = @specs.values.sort_by(&:identifier)
warn_for_outdated_bundler_version
rescue ArgumentError => e
Bundler.ui.debug(e)
diff --git a/lib/bundler/match_platform.rb b/lib/bundler/match_platform.rb
index fed418b593..0a4e4c7e3a 100644
--- a/lib/bundler/match_platform.rb
+++ b/lib/bundler/match_platform.rb
@@ -8,7 +8,8 @@ module Bundler
def match_platform(p)
Gem::Platform::RUBY == platform ||
platform.nil? || p == platform ||
- generic(Gem::Platform.new(platform)) === p
+ generic(Gem::Platform.new(platform)) === p ||
+ Gem::Platform.new(platform) === p
end
end
end
diff --git a/lib/bundler/plugin.rb b/lib/bundler/plugin.rb
index 1f0297f29b..8fb4119323 100644
--- a/lib/bundler/plugin.rb
+++ b/lib/bundler/plugin.rb
@@ -62,7 +62,9 @@ module Bundler
save_plugins plugins, installed_specs, builder.inferred_plugins
rescue => e
- Bundler.ui.error "Failed to install plugin: #{e.message}\n #{e.backtrace[0]}"
+ unless e.is_a?(GemfileError)
+ Bundler.ui.error "Failed to install plugin: #{e.message}\n #{e.backtrace[0]}"
+ end
raise
end
@@ -158,7 +160,7 @@ module Bundler
#
# @param [String] event
def hook(event, *args, &arg_blk)
- return unless Bundler.settings[:plugins]
+ return unless Bundler.feature_flag.plugins?
plugins = index.hook_plugins(event)
return unless plugins.any?
diff --git a/lib/bundler/postit_trampoline.rb b/lib/bundler/postit_trampoline.rb
index dbb23aa4d9..2a22489954 100644
--- a/lib/bundler/postit_trampoline.rb
+++ b/lib/bundler/postit_trampoline.rb
@@ -1,13 +1,18 @@
# frozen_string_literal: true
-if ENV["BUNDLE_ENABLE_TRAMPOLINE"]
- module BundlerVendoredPostIt; end
- require "bundler/vendor/postit/lib/postit"
- require "rubygems"
+module BundlerVendoredPostIt; end
+require "bundler/vendor/postit/lib/postit"
+require "rubygems"
- environment = BundlerVendoredPostIt::PostIt::Environment.new([])
- version = Gem::Requirement.new(environment.bundler_version)
+environment = BundlerVendoredPostIt::PostIt::Environment.new([])
+version = Gem::Requirement.new(environment.bundler_version)
+if version.requirements.size == 1 && version.requirements.first.first == "=" # version.exact?
+ if version.requirements.first.last.segments.first >= 2
+ ENV["BUNDLE_ENABLE_TRAMPOLINE"] = "true"
+ end
+end
+if ENV["BUNDLE_ENABLE_TRAMPOLINE"] && !ENV["BUNDLE_DISABLE_POSTIT"]
installed_version =
if defined?(Bundler::VERSION)
Bundler::VERSION
@@ -65,4 +70,4 @@ You're running Bundler #{installed_version} but this project uses #{running_vers
abort "The running bundler (#{running_version}) does not match the required `#{version}`"
end
-end # unless ENV["BUNDLE_ENABLE_TRAMPOLINE"]
+end # if ENV["BUNDLE_ENABLE_TRAMPOLINE"] && !ENV["BUNDLE_DISABLE_POSTIT"]
diff --git a/lib/bundler/remote_specification.rb b/lib/bundler/remote_specification.rb
index 6a02897c63..112c7f97fe 100644
--- a/lib/bundler/remote_specification.rb
+++ b/lib/bundler/remote_specification.rb
@@ -81,5 +81,10 @@ module Bundler
def method_missing(method, *args, &blk)
_remote_specification.send(method, *args, &blk)
end
+
+ def respond_to?(method, include_all = false)
+ super || _remote_specification.respond_to?(method, include_all)
+ end
+ public :respond_to?
end
end
diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb
index 81537baf24..e636e1f815 100644
--- a/lib/bundler/resolver.rb
+++ b/lib/bundler/resolver.rb
@@ -66,48 +66,39 @@ module Bundler
end
end
- ALL = Bundler::Dependency::PLATFORM_MAP.values.uniq.freeze
-
class SpecGroup < Array
include GemHelpers
- attr_reader :activated, :required_by
+ attr_reader :activated
def initialize(a)
super
- @required_by = []
- @activated = []
+ @required_by = []
+ @activated_platforms = []
@dependencies = nil
- @specs = {}
-
- ALL.each do |p|
- @specs[p] = reverse.find {|s| s.match_platform(p) }
+ @specs = Hash.new do |specs, platform|
+ specs[platform] = select_best_platform_match(self, platform)
end
end
def initialize_copy(o)
super
- @required_by = o.required_by.dup
- @activated = o.activated.dup
+ @activated_platforms = o.activated.dup
end
def to_specs
- specs = {}
-
- @activated.each do |p|
+ @activated_platforms.map do |p|
next unless s = @specs[p]
- platform = generic(Gem::Platform.new(s.platform))
- next if specs[platform]
-
- lazy_spec = LazySpecification.new(name, version, platform, source)
+ lazy_spec = LazySpecification.new(name, version, s.platform, source)
lazy_spec.dependencies.replace s.dependencies
- specs[platform] = lazy_spec
- end
- specs.values
+ lazy_spec
+ end.compact
end
def activate_platform!(platform)
- @activated << platform if !@activated.include?(platform) && for?(platform, nil)
+ return unless for?(platform)
+ return if @activated_platforms.include?(platform)
+ @activated_platforms << platform
end
def name
@@ -122,17 +113,9 @@ module Bundler
@source ||= first.source
end
- def for?(platform, ruby_version)
+ def for?(platform)
spec = @specs[platform]
- return false unless spec
-
- return true if ruby_version.nil?
- # Only allow endpoint specifications since they won't hit the network to
- # fetch the full gemspec when calling required_ruby_version
- return true if !spec.is_a?(EndpointSpecification) && !spec.is_a?(Gem::Specification)
- return true if spec.required_ruby_version.nil?
-
- spec.required_ruby_version.satisfied_by?(ruby_version.to_gem_version_with_patchlevel)
+ !spec.nil?
end
def to_s
@@ -140,7 +123,11 @@ module Bundler
end
def dependencies_for_activated_platforms
- @activated.map {|p| __dependencies[p] }.flatten
+ dependencies = @activated_platforms.map {|p| __dependencies[p] }
+ metadata_dependencies = @activated_platforms.map do |platform|
+ metadata_dependencies(@specs[platform], platform)
+ end
+ dependencies.concat(metadata_dependencies).flatten
end
def platforms_for_dependency_named(dependency)
@@ -150,18 +137,31 @@ module Bundler
private
def __dependencies
- @dependencies ||= begin
- dependencies = {}
- ALL.each do |p|
- next unless spec = @specs[p]
- dependencies[p] = []
+ @dependencies = Hash.new do |dependencies, platform|
+ dependencies[platform] = []
+ if spec = @specs[platform]
spec.dependencies.each do |dep|
next if dep.type == :development
- dependencies[p] << DepProxy.new(dep, p)
+ dependencies[platform] << DepProxy.new(dep, platform)
end
end
- dependencies
+ dependencies[platform]
+ end
+ end
+
+ def metadata_dependencies(spec, platform)
+ return [] unless spec
+ # Only allow endpoint specifications since they won't hit the network to
+ # fetch the full gemspec when calling required_ruby_version
+ return [] if !spec.is_a?(EndpointSpecification) && !spec.is_a?(Gem::Specification)
+ dependencies = []
+ if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none?
+ dependencies << DepProxy.new(Gem::Dependency.new("ruby\0", spec.required_ruby_version), platform)
end
+ if !spec.required_rubygems_version.nil? && !spec.required_rubygems_version.none?
+ dependencies << DepProxy.new(Gem::Dependency.new("rubygems\0", spec.required_rubygems_version), platform)
+ end
+ dependencies
end
end
@@ -175,29 +175,34 @@ module Bundler
# ==== Returns
# <GemBundle>,nil:: If the list of dependencies can be resolved, a
# collection of gemspecs is returned. Otherwise, nil is returned.
- def self.resolve(requirements, index, source_requirements = {}, base = [], ruby_version = nil, gem_version_promoter = GemVersionPromoter.new)
+ def self.resolve(requirements, index, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [])
base = SpecSet.new(base) unless base.is_a?(SpecSet)
- resolver = new(index, source_requirements, base, ruby_version, gem_version_promoter)
+ resolver = new(index, source_requirements, base, gem_version_promoter, additional_base_requirements)
result = resolver.start(requirements)
SpecSet.new(result)
end
- def initialize(index, source_requirements, base, ruby_version, gem_version_promoter)
+ def initialize(index, source_requirements, base, gem_version_promoter, additional_base_requirements)
@index = index
@source_requirements = source_requirements
@base = base
@resolver = Molinillo::Resolver.new(self, self)
@search_for = {}
@base_dg = Molinillo::DependencyGraph.new
- @base.each {|ls| @base_dg.add_vertex(ls.name, Dependency.new(ls.name, ls.version), true) }
- @ruby_version = ruby_version
+ @base.each do |ls|
+ dep = Dependency.new(ls.name, ls.version)
+ @base_dg.add_vertex(ls.name, DepProxy.new(dep, ls.platform), true)
+ end
+ additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) }
@gem_version_promoter = gem_version_promoter
end
def start(requirements)
verify_gemfile_dependencies_are_found!(requirements)
dg = @resolver.resolve(requirements, @base_dg)
- dg.map(&:payload).map(&:to_specs).flatten
+ dg.map(&:payload).
+ reject {|sg| sg.name.end_with?("\0") }.
+ map(&:to_specs).flatten
rescue Molinillo::VersionConflict => e
raise VersionConflict.new(e.conflicts.keys.uniq, e.message)
rescue Molinillo::CircularDependencyError => e
@@ -278,7 +283,7 @@ module Bundler
@gem_version_promoter.sort_versions(dependency, spec_groups)
end
end
- search.select {|sg| sg.for?(platform, @ruby_version) }.each {|sg| sg.activate_platform!(platform) }
+ search.select {|sg| sg.for?(platform) }.each {|sg| sg.activate_platform!(platform) }
end
def index_for(dependency)
@@ -302,7 +307,8 @@ module Bundler
end
def requirement_satisfied_by?(requirement, activated, spec)
- requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec)
+ return false unless requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec)
+ spec.activate_platform!(requirement.__platform) || spec.for?(requirement.__platform)
end
def sort_dependencies(dependencies, activated, conflicts)
diff --git a/lib/bundler/ruby_version.rb b/lib/bundler/ruby_version.rb
index 9321f94c23..ebdefe63fc 100644
--- a/lib/bundler/ruby_version.rb
+++ b/lib/bundler/ruby_version.rb
@@ -23,8 +23,8 @@ module Bundler
@versions = Array(versions)
@gem_version = Gem::Requirement.create(@versions.first).requirements.first.last
- @input_engine = engine
- @engine = engine || "ruby"
+ @input_engine = engine && engine.to_s
+ @engine = engine && engine.to_s || "ruby"
@engine_versions = (engine_version && Array(engine_version)) || @versions
@engine_gem_version = Gem::Requirement.create(@engine_versions.first).requirements.first.last
@patchlevel = patchlevel
@@ -128,6 +128,11 @@ module Bundler
end
end
+ def exact?
+ return @exact if defined?(@exact)
+ @exact = versions.all? {|v| Gem::Requirement.create(v).exact? }
+ end
+
private
def matches?(requirements, version)
diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb
index fc8eadd186..53a153e560 100644
--- a/lib/bundler/rubygems_ext.rb
+++ b/lib/bundler/rubygems_ext.rb
@@ -8,6 +8,16 @@ end
require "rubygems"
require "rubygems/specification"
+
+begin
+ # Possible use in Gem::Specification#source below and require
+ # shouldn't be deferred.
+ require "rubygems/source"
+rescue LoadError
+ # Not available before Rubygems 2.0.0, ignore
+ nil
+end
+
require "bundler/match_platform"
module Gem
@@ -159,6 +169,11 @@ module Gem
def none?
@none ||= (to_s == ">= 0")
end unless allocate.respond_to?(:none?)
+
+ def exact?
+ return false unless @requirements.size == 1
+ @requirements[0][0] == "="
+ end unless allocate.respond_to?(:exact?)
end
class Platform
diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb
index e18f46268b..28ad988b94 100644
--- a/lib/bundler/rubygems_gem_installer.rb
+++ b/lib/bundler/rubygems_gem_installer.rb
@@ -12,5 +12,53 @@ module Bundler
def check_executable_overwrite(filename)
# Bundler needs to install gems regardless of binstub overwriting
end
+
+ def pre_install_checks
+ super && validate_bundler_checksum(options[:bundler_expected_checksum])
+ end
+
+ private
+
+ def validate_bundler_checksum(checksum)
+ return true if Bundler.settings[:disable_checksum_validation]
+ return true unless checksum
+ return true unless source = @package.instance_variable_get(:@gem)
+ return true unless source.respond_to?(:with_read_io)
+ digest = source.with_read_io do |io|
+ digest = Digest::SHA256.new
+ digest << io.read(16_384) until io.eof?
+ io.rewind
+ send(checksum_type(checksum), digest)
+ end
+ unless digest == checksum
+ raise SecurityError,
+ "The checksum for the downloaded `#{spec.full_name}.gem` did not match " \
+ "the checksum given by the API. This means that the contents of the " \
+ "gem appear to be different from what was uploaded, and could be an indicator of a security issue.\n" \
+ "(The expected SHA256 checksum was #{checksum.inspect}, but the checksum for the downloaded gem was #{digest.inspect}.)\n" \
+ "Bundler cannot continue installing #{spec.name} (#{spec.version})."
+ end
+ true
+ end
+
+ def checksum_type(checksum)
+ case checksum.length
+ when 64 then :hexdigest!
+ when 44 then :base64digest!
+ else raise InstallError, "The given checksum for #{spec.full_name} (#{checksum.inspect}) is not a valid SHA256 hexdigest nor base64digest"
+ end
+ end
+
+ def hexdigest!(digest)
+ digest.hexdigest!
+ end
+
+ def base64digest!(digest)
+ if digest.respond_to?(:base64digest!)
+ digest.base64digest!
+ else
+ [digest.digest!].pack("m0")
+ end
+ end
end
end
diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb
index c1bb6c7ab8..23ae95aa04 100644
--- a/lib/bundler/rubygems_integration.rb
+++ b/lib/bundler/rubygems_integration.rb
@@ -489,6 +489,7 @@ module Bundler
end
def redefine_method(klass, method, unbound_method = nil, &block)
+ visibility = method_visibility(klass, method)
begin
if (instance_method = klass.instance_method(method)) && method != :initialize
# doing this to ensure we also get private methods
@@ -501,8 +502,20 @@ module Bundler
@replaced_methods[[method, klass]] = instance_method
if unbound_method
klass.send(:define_method, method, unbound_method)
+ klass.send(visibility, method)
elsif block
klass.send(:define_method, method, &block)
+ klass.send(visibility, method)
+ end
+ end
+
+ def method_visibility(klass, method)
+ if klass.private_method_defined?(method)
+ :private
+ elsif klass.protected_method_defined?(method)
+ :protected
+ else
+ :public
end
end
diff --git a/lib/bundler/runtime.rb b/lib/bundler/runtime.rb
index fda499cf5a..45f445aec1 100644
--- a/lib/bundler/runtime.rb
+++ b/lib/bundler/runtime.rb
@@ -140,7 +140,8 @@ module Bundler
Bundler.ui.info "Updating files in #{Bundler.settings.app_cache_path}"
- specs.each do |spec|
+ specs_to_cache = Bundler.settings[:cache_all_platforms] ? @definition.resolve.materialized_for_all_platforms : specs
+ specs_to_cache.each do |spec|
next if spec.name == "bundler"
next if spec.source.is_a?(Source::Gemspec)
spec.source.send(:fetch_gem, spec) if Bundler.settings[:cache_all_platforms] && spec.source.respond_to?(:fetch_gem, true)
diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb
index 2a04805f92..db6a4ab6ad 100644
--- a/lib/bundler/settings.rb
+++ b/lib/bundler/settings.rb
@@ -6,6 +6,7 @@ module Bundler
BOOL_KEYS = %w(
allow_offline_install
cache_all
+ disable_checksum_validation
disable_exec_load
disable_local_branch_check
disable_shared_gems
@@ -16,6 +17,7 @@ module Bundler
major_deprecations
no_install
no_prune
+ only_update_to_newer_versions
plugins
silence_root_warning
).freeze
@@ -40,11 +42,18 @@ module Bundler
@local_config = load_config(local_config_file)
@global_config = load_config(global_config_file)
@cli_flags_given = false
+ @temporary = {}
end
def [](name)
key = key_for(name)
- value = (@local_config[key] || ENV[key] || @global_config[key] || DEFAULT_CONFIG[name])
+ value = @temporary.fetch(name) do
+ @local_config.fetch(key) do
+ ENV.fetch(key) do
+ @global_config.fetch(key) do
+ DEFAULT_CONFIG.fetch(name) do
+ nil
+ end end end end end
if value.nil?
nil
@@ -74,9 +83,19 @@ module Bundler
local_config_file || raise(GemfileNotFound, "Could not locate Gemfile")
set_key(key, value, @local_config, local_config_file)
end
-
alias_method :set_local, :[]=
+ def temporary(update)
+ existing = Hash[update.map {|k, _| [k, @temporary[k]] }]
+ @temporary.update(update)
+ return unless block_given?
+ begin
+ yield
+ ensure
+ existing.each {|k, v| v.nil? ? @temporary.delete(k) : @temporary[k] = v }
+ end
+ end
+
def delete(key)
@local_config.delete(key_for(key))
end
@@ -277,7 +296,7 @@ module Bundler
}xo
def load_config(config_file)
- return unless config_file
+ return {} unless config_file
SharedHelpers.filesystem_access(config_file, :read) do |file|
valid_file = file.exist? && !file.size.zero?
return {} if ignore_config? || !valid_file
diff --git a/lib/bundler/setup.rb b/lib/bundler/setup.rb
index 8b4b479778..4e213beed3 100644
--- a/lib/bundler/setup.rb
+++ b/lib/bundler/setup.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-require "bundler/postit_trampoline" unless ENV["BUNDLE_DISABLE_POSTIT"]
+require "bundler/postit_trampoline"
require "bundler/shared_helpers"
if Bundler::SharedHelpers.in_bundle?
diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb
index 69543356a2..ca4eafd623 100644
--- a/lib/bundler/shared_helpers.rb
+++ b/lib/bundler/shared_helpers.rb
@@ -224,7 +224,8 @@ module Bundler
def prints_major_deprecations?
require "bundler"
- return false unless Bundler.settings[:major_deprecations]
+ deprecation_release = Bundler::VERSION.split(".").drop(1).include?("99")
+ return false if !deprecation_release && !Bundler.settings[:major_deprecations]
require "bundler/deprecate"
return false if Bundler::Deprecate.skip
true
diff --git a/lib/bundler/source.rb b/lib/bundler/source.rb
index afa7d91838..9d65d4613b 100644
--- a/lib/bundler/source.rb
+++ b/lib/bundler/source.rb
@@ -14,12 +14,13 @@ module Bundler
def version_message(spec)
message = "#{spec.name} #{spec.version}"
+ message += " (#{spec.platform})" if spec.platform != Gem::Platform::RUBY && !spec.platform.nil?
if Bundler.locked_gems
locked_spec = Bundler.locked_gems.specs.find {|s| s.name == spec.name }
locked_spec_version = locked_spec.version if locked_spec
if locked_spec_version && spec.version != locked_spec_version
- message += " (#{Bundler.ui.add_color("was #{locked_spec_version}", :green)})"
+ message += Bundler.ui.add_color(" (was #{locked_spec_version})", :green)
end
end
diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb
index 60fb555f0a..d1757a4a93 100644
--- a/lib/bundler/source/git.rb
+++ b/lib/bundler/source/git.rb
@@ -292,7 +292,7 @@ module Bundler
def fetch
git_proxy.checkout
rescue GitError
- raise unless Bundler.settings[:allow_offline_install]
+ raise unless Bundler.feature_flag.allow_offline_install?
Bundler.ui.warn "Using cached git data because of network errors"
end
end
diff --git a/lib/bundler/source/git/git_proxy.rb b/lib/bundler/source/git/git_proxy.rb
index 4b76d18735..c44f00d7b1 100644
--- a/lib/bundler/source/git/git_proxy.rb
+++ b/lib/bundler/source/git/git_proxy.rb
@@ -224,6 +224,11 @@ module Bundler
raise GitError, "The git source #{uri} is not yet checked out. Please run `bundle install` before trying to start your application"
end
+ # TODO: Replace this with Open3 when upgrading to bundler 2
+ # Similar to #git_null, as Open3 is not cross-platform,
+ # a temporary way is to use Tempfile to capture the stderr.
+ # When replacing this using Open3, make sure git_null is
+ # also replaced by Open3, so stdout and stderr all got handled properly.
def capture_and_filter_stderr(uri)
return_value, captured_err = ""
backup_stderr = STDERR.dup
diff --git a/lib/bundler/source/path.rb b/lib/bundler/source/path.rb
index 69bb0c1af2..87a490446c 100644
--- a/lib/bundler/source/path.rb
+++ b/lib/bundler/source/path.rb
@@ -46,7 +46,7 @@ module Bundler
def to_lock
out = String.new("PATH\n")
- out << " remote: #{relative_path}\n"
+ out << " remote: #{lockfile_path}\n"
out << " glob: #{@glob}\n" unless @glob == DEFAULT_GLOB
out << " specs:\n"
end
@@ -129,6 +129,11 @@ module Bundler
"`#{somepath}`.\nThe error message was: #{e.message}."
end
+ def lockfile_path
+ return relative_path if path.absolute?
+ expand(path).relative_path_from(Bundler.root)
+ end
+
def app_cache_path(custom_path = nil)
@app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname)
end
diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb
index aedad7086d..89f7673eb8 100644
--- a/lib/bundler/source/rubygems.rb
+++ b/lib/bundler/source/rubygems.rb
@@ -140,7 +140,8 @@ module Bundler
:bin_dir => bin_path.to_s,
:ignore_dependencies => true,
:wrappers => true,
- :env_shebang => true
+ :env_shebang => true,
+ :bundler_expected_checksum => spec.respond_to?(:checksum) && spec.checksum
).install
end
spec.full_gem_path = installed_spec.full_gem_path
diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb
index f2ccac4742..fe31b17f0e 100644
--- a/lib/bundler/spec_set.rb
+++ b/lib/bundler/spec_set.rb
@@ -24,17 +24,9 @@ module Bundler
dep = deps.shift
next if handled[dep] || skip.include?(dep.name)
- spec = lookup[dep.name].find do |s|
- if match_current_platform
- Gem::Platform.match(s.platform)
- else
- s.match_platform(dep.__platform)
- end
- end
-
handled[dep] = true
- if spec
+ if spec = spec_for_dependency(dep, match_current_platform)
specs << spec
spec.dependencies.each do |d|
@@ -99,6 +91,20 @@ module Bundler
SpecSet.new(materialized.compact)
end
+ # Materialize for all the specs in the spec set, regardless of what platform they're for
+ # This is in contrast to how for does platform filtering (and specifically different from how `materialize` calls `for` only for the current platform)
+ # @return [Array<Gem::Specification>]
+ def materialized_for_all_platforms
+ names = @specs.map(&:name).uniq
+ @specs.map do |s|
+ next s unless s.is_a?(LazySpecification)
+ s.source.dependency_names = names if s.source.respond_to?(:dependency_names=)
+ spec = s.__materialize__
+ raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec
+ spec
+ end
+ end
+
def merge(set)
arr = sorted.dup
set.each do |s|
@@ -133,10 +139,7 @@ module Bundler
def lookup
@lookup ||= begin
lookup = Hash.new {|h, k| h[k] = [] }
- specs = @specs.sort_by do |s|
- s.platform.to_s == "ruby" ? "\0" : s.platform.to_s
- end
- specs.reverse_each do |s|
+ Index.sort_specs(@specs).reverse_each do |s|
lookup[s.name] << s
end
lookup
@@ -147,6 +150,18 @@ module Bundler
@specs.each {|s| yield s }
end
+ def spec_for_dependency(dep, match_current_platform)
+ if match_current_platform
+ Bundler.rubygems.platforms.reverse_each do |pl|
+ match = GemHelpers.select_best_platform_match(lookup[dep.name], pl)
+ return match if match
+ end
+ nil
+ else
+ GemHelpers.select_best_platform_match(lookup[dep.name], dep.__platform)
+ end
+ end
+
def tsort_each_child(s)
s.dependencies.sort_by(&:name).each do |d|
next if d.type == :development
diff --git a/lib/bundler/templates/newgem/README.md.tt b/lib/bundler/templates/newgem/README.md.tt
index 30c7b93609..ad8d88b6e4 100644
--- a/lib/bundler/templates/newgem/README.md.tt
+++ b/lib/bundler/templates/newgem/README.md.tt
@@ -32,7 +32,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
## Contributing
-Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/<%= config[:name] %>.<% if config[:coc] %> This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.<% end %>
+Bug reports and pull requests are welcome on GitHub at https://github.com/<%= config[:git_user_name] %>/<%= config[:name] %>.<% if config[:coc] %> This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.<% end %>
<% if config[:mit] %>
## License
diff --git a/lib/bundler/vendor/compact_index_client/lib/compact_index_client.rb b/lib/bundler/vendor/compact_index_client/lib/compact_index_client.rb
index 9ab2722f18..c063c6b4dc 100644
--- a/lib/bundler/vendor/compact_index_client/lib/compact_index_client.rb
+++ b/lib/bundler/vendor/compact_index_client/lib/compact_index_client.rb
@@ -3,6 +3,12 @@ require "pathname"
require "set"
class Bundler::CompactIndexClient
+ DEBUG_MUTEX = Mutex.new
+ def self.debug
+ return unless ENV["DEBUG_COMPACT_INDEX"]
+ DEBUG_MUTEX.synchronize { warn("[#{self}] #{yield}") }
+ end
+
class Error < StandardError; end
require "bundler/vendor/compact_index_client/lib/compact_index_client/cache"
@@ -28,17 +34,20 @@ class Bundler::CompactIndexClient
end
def names
+ Bundler::CompactIndexClient.debug { "/names" }
update(@cache.names_path, "names")
@cache.names
end
def versions
+ Bundler::CompactIndexClient.debug { "/versions" }
update(@cache.versions_path, "versions")
versions, @info_checksums_by_name = @cache.versions
versions
end
def dependencies(names)
+ Bundler::CompactIndexClient.debug { "dependencies(#{names})" }
in_parallel.call(names) do |name|
update_info(name)
@cache.dependencies(name).map {|d| d.unshift(name) }
@@ -46,11 +55,13 @@ class Bundler::CompactIndexClient
end
def spec(name, version, platform = nil)
+ Bundler::CompactIndexClient.debug { "spec(name = #{name}, version = #{version}, platform = #{platform})" }
update_info(name)
@cache.specific_dependency(name, version, platform)
end
def update_and_parse_checksums!
+ Bundler::CompactIndexClient.debug { "update_and_parse_checksums!" }
return @info_checksums_by_name if @parsed_checksums
update(@cache.versions_path, "versions")
@info_checksums_by_name = @cache.checksums
@@ -60,15 +71,27 @@ class Bundler::CompactIndexClient
private
def update(local_path, remote_path)
- return unless @endpoints.add?(remote_path)
+ Bundler::CompactIndexClient.debug { "update(#{local_path}, #{remote_path})" }
+ unless @endpoints.add?(remote_path)
+ Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" }
+ return
+ end
@updater.update(local_path, url(remote_path))
end
def update_info(name)
+ Bundler::CompactIndexClient.debug { "update_info(#{name})" }
path = @cache.info_path(name)
checksum = @updater.checksum_for_file(path)
- return unless existing = @info_checksums_by_name[name]
- return if checksum == existing
+ unless existing = @info_checksums_by_name[name]
+ Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since it is missing from versions" }
+ return
+ end
+ if checksum == existing
+ Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since the versions checksum matches the local checksum" }
+ return
+ end
+ Bundler::CompactIndexClient.debug { "updating info for #{name} since the versions checksum #{existing} != the local checksum #{checksum}" }
update(path, "info/#{name}")
end
diff --git a/lib/bundler/vendor/compact_index_client/lib/compact_index_client/updater.rb b/lib/bundler/vendor/compact_index_client/lib/compact_index_client/updater.rb
index 5c5ba41434..a410dd423c 100644
--- a/lib/bundler/vendor/compact_index_client/lib/compact_index_client/updater.rb
+++ b/lib/bundler/vendor/compact_index_client/lib/compact_index_client/updater.rb
@@ -50,7 +50,7 @@ class Bundler::CompactIndexClient
mode = response.is_a?(Net::HTTPPartialContent) ? "a" : "w"
local_temp_path.open(mode) {|f| f << content }
- response_etag = response["ETag"]
+ response_etag = response["ETag"].gsub(%r{\AW/}, "")
if etag_for(local_temp_path) == response_etag
FileUtils.mv(local_temp_path, local_path)
return
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb b/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb
index c44da1ce3e..f840e7ea30 100644
--- a/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module Bundler::Molinillo
# The version of Bundler::Molinillo.
- VERSION = '0.5.0'.freeze
+ VERSION = '0.5.1'.freeze
end
diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb b/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb
index 5707e890b7..1890d95a56 100644
--- a/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb
+++ b/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb
@@ -184,6 +184,8 @@ module Bundler::Molinillo
raise VersionConflict.new(c) unless state
activated.rewind_to(sliced_states.first || :initial_state) if sliced_states
state.conflicts = c
+ index = states.size - 1
+ @parent_of.reject! { |_, i| i >= index }
end
end
@@ -209,7 +211,10 @@ module Bundler::Molinillo
# @return [Object] the requirement that led to `requirement` being added
# to the list of requirements.
def parent_of(requirement)
- @parent_of[requirement]
+ return unless requirement
+ return unless index = @parent_of[requirement]
+ return unless parent_state = @states[index]
+ parent_state.requirement
end
# @return [Object] the requirement that led to a version of a possibility
@@ -418,7 +423,8 @@ module Bundler::Molinillo
debug(depth) { "Requiring nested dependencies (#{nested_dependencies.join(', ')})" }
nested_dependencies.each do |d|
activated.add_child_vertex(name_for(d), nil, [name_for(activated_spec)], d)
- @parent_of[d] = requirement
+ parent_index = states.size - 1
+ @parent_of[d] ||= parent_index
end
push_state_for_requirements(requirements + nested_dependencies, !nested_dependencies.empty?)
diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb
index bcee8f7201..2fcacc0f33 100644
--- a/lib/bundler/version.rb
+++ b/lib/bundler/version.rb
@@ -7,5 +7,5 @@ module Bundler
# We're doing this because we might write tests that deal
# with other versions of bundler and we are unsure how to
# handle this better.
- VERSION = "1.13.0.rc.1" unless defined?(::Bundler::VERSION)
+ VERSION = "1.13.1" unless defined?(::Bundler::VERSION)
end
diff --git a/lib/bundler/yaml_serializer.rb b/lib/bundler/yaml_serializer.rb
index dede8fd5fd..3c9eccafc2 100644
--- a/lib/bundler/yaml_serializer.rb
+++ b/lib/bundler/yaml_serializer.rb
@@ -52,7 +52,7 @@ module Bundler
stack = [res]
last_hash = nil
last_empty_key = nil
- str.split("\n").each do |line|
+ str.split(/\r?\n/).each do |line|
if match = HASH_REGEX.match(line)
indent, key, _, val = match.captures
key = convert_to_backward_compatible_key(key)
diff --git a/man/bundle-config.ronn b/man/bundle-config.ronn
index 3ea6d10973..dc701c584f 100644
--- a/man/bundle-config.ronn
+++ b/man/bundle-config.ronn
@@ -142,7 +142,7 @@ learn more about their operation in [bundle install(1)][bundle-install].
and key in PEM format.
* `cache_path` (`BUNDLE_CACHE_PATH`): The directory that bundler will place
cached gems in when running <code>bundle package</code>, and that bundler
- will look in when installing gems.
+ will look in when installing gems. Defaults to `vendor/bundle`.
* `disable_multisource` (`BUNDLE_DISABLE_MULTISOURCE`): When set, Gemfiles
containing multiple sources will produce errors instead of warnings. Use
`bundle config --delete disable_multisource` to unset.
diff --git a/man/bundle-exec.ronn b/man/bundle-exec.ronn
index ba6844c5c2..c9ab2309e4 100644
--- a/man/bundle-exec.ronn
+++ b/man/bundle-exec.ronn
@@ -63,6 +63,15 @@ It also modifies Rubygems:
making system executables work
* Add all gems in the bundle into Gem.loaded_specs
+### Loading
+
+By default, when attempting to `bundle exec` to a file with a ruby shebang,
+Bundler will `Kernel.load` that file instead of using `Kernel.exec`. For the
+vast majority of cases, this is a performance improvement. In a rare few cases,
+this could cause some subtle side-effects (such as dependence on the exact
+contents of `$0` or `__FILE__`) and the optimization can be disabled by enabling
+the `disable_exec_load` setting.
+
### Shelling out
Any Ruby code that opens a subshell (like `system`, backticks, or `%x{}`) will
diff --git a/spec/bundler/definition_spec.rb b/spec/bundler/definition_spec.rb
index c72f50f0d1..71e5bb00aa 100644
--- a/spec/bundler/definition_spec.rb
+++ b/spec/bundler/definition_spec.rb
@@ -137,7 +137,7 @@ describe Bundler::Definition do
describe "initialize" do
context "gem version promoter" do
context "with lockfile" do
- before :each do
+ before do
install_gemfile <<-G
source "file://#{gem_repo1}"
gem "foo"
@@ -159,6 +159,73 @@ describe Bundler::Definition do
end
end
+ context "shared dependent gems" do
+ before do
+ build_repo4 do
+ build_gem "isolated_owner", %w(1.0.1 1.0.2) do |s|
+ s.add_dependency "isolated_dep", "~> 2.0"
+ end
+ build_gem "isolated_dep", %w(2.0.1 2.0.2)
+
+ build_gem "shared_owner_a", %w(3.0.1 3.0.2) do |s|
+ s.add_dependency "shared_dep", "~> 5.0"
+ end
+ build_gem "shared_owner_b", %w(4.0.1 4.0.2) do |s|
+ s.add_dependency "shared_dep", "~> 5.0"
+ end
+ build_gem "shared_dep", %w(5.0.1 5.0.2)
+ end
+
+ gemfile <<-G
+ source "file://#{gem_repo4}"
+ gem 'isolated_owner'
+
+ gem 'shared_owner_a'
+ gem 'shared_owner_b'
+ G
+
+ lockfile <<-L
+ GEM
+ remote: file://#{gem_repo4}
+ specs:
+ isolated_dep (2.0.1)
+ isolated_owner (1.0.1)
+ isolated_dep (~> 2.0)
+ shared_dep (5.0.1)
+ shared_owner_a (3.0.1)
+ shared_dep (~> 5.0)
+ shared_owner_b (4.0.1)
+ shared_dep (~> 5.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ shared_owner_a
+ shared_owner_b
+ isolated_owner
+
+ BUNDLED WITH
+ 1.13.0
+ L
+ end
+
+ it "should unlock isolated and shared dependencies equally" do
+ # setup for these test costs about 3/4 of a second, much faster to just jam them all in here.
+ # the global before :each defeats any ability to have re-usable setup for many examples in a
+ # single context by wiping out the tmp dir and contents.
+
+ unlock_deps_test(%w(isolated_owner), %w(isolated_dep isolated_owner))
+ unlock_deps_test(%w(isolated_owner shared_owner_a), %w(isolated_dep isolated_owner shared_dep shared_owner_a))
+ end
+
+ def unlock_deps_test(passed_unlocked, expected_calculated)
+ definition = Bundler::Definition.new(bundled_app("Gemfile.lock"), [], Bundler::SourceList.new, :gems => passed_unlocked)
+ unlock_gems = definition.gem_version_promoter.unlock_gems
+ expect(unlock_gems.sort).to eq expected_calculated
+ end
+ end
+
def mock_source_list
Class.new do
def all_sources
diff --git a/spec/bundler/endpoint_specification_spec.rb b/spec/bundler/endpoint_specification_spec.rb
index 6718b24971..b1e71df39a 100644
--- a/spec/bundler/endpoint_specification_spec.rb
+++ b/spec/bundler/endpoint_specification_spec.rb
@@ -50,4 +50,17 @@ describe Bundler::EndpointSpecification do
end
end
end
+
+ describe "#parse_metadata" do
+ context "when the metadata has malformed requirements" do
+ let(:metadata) { { "rubygems" => ">\n" } }
+ it "raises a helpful error message" do
+ expect { subject }.to raise_error(
+ Bundler::GemspecError,
+ a_string_including("There was an error parsing the metadata for the gem foo (1.0.0)").
+ and(a_string_including('The metadata was {"rubygems"=>">\n"}'))
+ )
+ end
+ end
+ end
end
diff --git a/spec/bundler/env_spec.rb b/spec/bundler/env_spec.rb
index 73d1f1d7df..245073d9b8 100644
--- a/spec/bundler/env_spec.rb
+++ b/spec/bundler/env_spec.rb
@@ -15,6 +15,7 @@ describe Bundler::Env do
expect(out).to include(Gem::VERSION)
expect(out).to include(env.send(:ruby_version))
expect(out).to include(env.send(:git_version))
+ expect(out).to include(OpenSSL::OPENSSL_VERSION)
end
context "when there is a Gemfile and a lockfile and print_gemfile is true" do
@@ -48,6 +49,14 @@ describe Bundler::Env do
end
end
+ context "when there no Gemfile and print_gemfile is true" do
+ let(:output) { env.report(:print_gemfile => true) }
+
+ it "prints the environment" do
+ expect(output).to start_with("Environment")
+ end
+ end
+
context "when Gemfile contains a gemspec and print_gemspecs is true" do
let(:gemspec) do
<<-GEMSPEC.gsub(/^\s+/, "")
diff --git a/spec/bundler/mirror_spec.rb b/spec/bundler/mirror_spec.rb
index eb0ccf0bdf..6a81ef2af4 100644
--- a/spec/bundler/mirror_spec.rb
+++ b/spec/bundler/mirror_spec.rb
@@ -131,6 +131,16 @@ describe Bundler::Settings::Mirror do
end
end
end
+
+ describe "#==" do
+ it "returns true if uri and fallback timeout are the same" do
+ uri = "https://ruby.taobao.org"
+ mirror = Bundler::Settings::Mirror.new(uri, 1)
+ another_mirror = Bundler::Settings::Mirror.new(uri, 1)
+
+ expect(mirror == another_mirror).to be true
+ end
+ end
end
end
diff --git a/spec/bundler/remote_specification_spec.rb b/spec/bundler/remote_specification_spec.rb
index 6a8e9a6434..d958ca85eb 100644
--- a/spec/bundler/remote_specification_spec.rb
+++ b/spec/bundler/remote_specification_spec.rb
@@ -158,16 +158,30 @@ describe Bundler::RemoteSpecification do
describe "method missing" do
context "and is present in Gem::Specification" do
- let(:remote_spec) { double(:remote_spec) }
+ let(:remote_spec) { double(:remote_spec, :authors => "abcd") }
before do
- allow_any_instance_of(Gem::Specification).to receive(:respond_to?).and_return(true)
allow(subject).to receive(:_remote_specification).and_return(remote_spec)
+ expect(subject.methods.map(&:to_sym)).not_to include(:authors)
end
it "should send through to Gem::Specification" do
- expect(remote_spec).to receive(:send).with(:missing_method_call).once
- subject.missing_method_call
+ expect(subject.authors).to eq("abcd")
+ end
+ end
+ end
+
+ describe "respond to missing?" do
+ context "and is present in Gem::Specification" do
+ let(:remote_spec) { double(:remote_spec, :authors => "abcd") }
+
+ before do
+ allow(subject).to receive(:_remote_specification).and_return(remote_spec)
+ expect(subject.methods.map(&:to_sym)).not_to include(:authors)
+ end
+
+ it "should send through to Gem::Specification" do
+ expect(subject.respond_to?(:authors)).to be_truthy
end
end
end
diff --git a/spec/bundler/ruby_version_spec.rb b/spec/bundler/ruby_version_spec.rb
index abcd0303d0..e983c18484 100644
--- a/spec/bundler/ruby_version_spec.rb
+++ b/spec/bundler/ruby_version_spec.rb
@@ -35,6 +35,14 @@ describe "Bundler::RubyVersion and its subclasses" do
end
end
+ context "with engine in symbol" do
+ let(:engine) { :jruby }
+
+ it "should coerce engine to string" do
+ expect(subject.engine).to eq("jruby")
+ end
+ end
+
context "is called with multiple requirements" do
let(:version) { ["<= 2.0.0", "> 1.9.3"] }
let(:engine_version) { nil }
diff --git a/spec/bundler/settings_spec.rb b/spec/bundler/settings_spec.rb
index 0f7d2a0138..5a9d0cb08b 100644
--- a/spec/bundler/settings_spec.rb
+++ b/spec/bundler/settings_spec.rb
@@ -54,6 +54,16 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
describe "#[]" do
+ context "when the local config file is not found" do
+ subject(:settings) { described_class.new }
+
+ it "does not raise" do
+ expect do
+ subject["foo"]
+ end.not_to raise_error
+ end
+ end
+
context "when not set" do
context "when default value present" do
it "retrieves value" do
@@ -96,6 +106,18 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
end
+ describe "#temporary" do
+ it "reset after used" do
+ Bundler.settings[:no_install] = true
+
+ Bundler.settings.temporary(:no_install => false) do
+ expect(Bundler.settings[:no_install]).to eq false
+ end
+
+ expect(Bundler.settings[:no_install]).to eq true
+ end
+ end
+
describe "#set_global" do
context "when it's not possible to write to the file" do
it "raises an PermissionError with explanation" do
diff --git a/spec/bundler/source_spec.rb b/spec/bundler/source_spec.rb
index 25abd90c96..ea171d387c 100644
--- a/spec/bundler/source_spec.rb
+++ b/spec/bundler/source_spec.rb
@@ -22,7 +22,7 @@ describe Bundler::Source do
end
describe "#version_message" do
- let(:spec) { double(:spec, :name => "nokogiri", :version => ">= 1.6") }
+ let(:spec) { double(:spec, :name => "nokogiri", :version => ">= 1.6", :platform => rb) }
shared_examples_for "the lockfile specs are not relevant" do
it "should return a string with the spec name and version" do
@@ -61,7 +61,7 @@ describe Bundler::Source do
before { Bundler.ui = Bundler::UI::Shell.new }
it "should return a string with the spec name and version and locked spec version" do
- expect(subject.version_message(spec)).to eq("nokogiri >= 1.6 (\e[32mwas < 1.5\e[0m)")
+ expect(subject.version_message(spec)).to eq("nokogiri >= 1.6\e[32m (was < 1.5)\e[0m")
end
end
diff --git a/spec/bundler/yaml_serializer_spec.rb b/spec/bundler/yaml_serializer_spec.rb
index 0b3261336c..bf86d2a076 100644
--- a/spec/bundler/yaml_serializer_spec.rb
+++ b/spec/bundler/yaml_serializer_spec.rb
@@ -125,6 +125,29 @@ describe Bundler::YAMLSerializer do
expect(serializer.load(yaml)).to eq(hash)
end
+
+ it "handles windows-style CRLF line endings" do
+ yaml = strip_whitespace(<<-YAML).gsub("\n", "\r\n")
+ ---
+ nested_hash:
+ contains_array:
+ - "Why shouldn't you write with a broken pencil?"
+ - "Because it's pointless!"
+ - oh so silly
+ YAML
+
+ hash = {
+ "nested_hash" => {
+ "contains_array" => [
+ "Why shouldn't you write with a broken pencil?",
+ "Because it's pointless!",
+ "oh so silly",
+ ],
+ },
+ }
+
+ expect(serializer.load(yaml)).to eq(hash)
+ end
end
describe "against yaml lib" do
diff --git a/spec/commands/add_spec.rb b/spec/commands/add_spec.rb
deleted file mode 100644
index d6b9b46f94..0000000000
--- a/spec/commands/add_spec.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-# frozen_string_literal: true
-require "spec_helper"
-
-describe "bundle add" do
- before :each do
- build_repo2
-
- gemfile <<-G
- source "file://#{gem_repo2}"
- G
- end
-
- context "when version number is set" do
- it "adds gem with provided version" do
- bundle "add activesupport 2.3.5"
- expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 2.3.5'")
- end
-
- it "adds gem with provided version and version operator" do
- update_repo2 do
- build_gem "activesupport", "3.0.0"
- end
-
- bundle "add activesupport '> 2.3.5'"
- expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '> 2.3.5'")
- end
- end
-
- context "when version number is not set" do
- it "adds gem with last stable version" do
- bundle "add activesupport"
- expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 2.3.5'")
- end
-
- it "`--pre` flag adds the gem with the latest prerelease version" do
- update_repo2 do
- build_gem "activesupport", "3.0.0.beta"
- end
-
- bundle "add activesupport --pre"
- expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 3.0.0.beta'")
- end
-
- it "`--pre` flag adds the gem with the latest non-prerelease version if it is available" do
- update_repo2 do
- build_gem "activesupport", "3.0.0.beta"
- build_gem "activesupport", "3.0.0"
- end
-
- bundle "add activesupport --pre"
- expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 3.0.0'")
- end
- end
-
- context "when group is set" do
- it "adds the gem with the specified groups" do
- bundle "add activesupport --group development test"
- expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 2.3.5', :group => [:development, :test]")
- end
- end
-
- context "when source is set" do
- it "adds the gem with a specified source" do
- bundle "add activesupport --source file://#{gem_repo2}"
- expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 2.3.5', :source => 'file:\/\/#{gem_repo2}'")
- end
- end
-
- context "when multiple options are set" do
- before :each do
- update_repo2 do
- build_gem "activesupport", "3.0.0"
- end
- end
-
- it "adds the gem with a specified group and source" do
- bundle "add activesupport --group test --source file://#{gem_repo2}"
- expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 3.0.0', :group => [:test], :source => 'file:\/\/#{gem_repo2}'")
- end
-
- it "adds the gem with a specified version, group, and source" do
- bundle "add activesupport 2.3.5 --group development --source file://#{gem_repo2}"
- expect(bundled_app("Gemfile").read).to include("gem 'activesupport', '~> 2.3.5', :group => [:development], :source => 'file:\/\/#{gem_repo2}'")
- end
- end
-end
diff --git a/spec/commands/doctor_spec.rb b/spec/commands/doctor_spec.rb
index 236138a6c8..8debeb55e4 100644
--- a/spec/commands/doctor_spec.rb
+++ b/spec/commands/doctor_spec.rb
@@ -55,7 +55,10 @@ describe "bundle doctor" do
expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib"]
allow(File).to receive(:exist?).and_call_original
allow(File).to receive(:exist?).with("/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib").and_return(false)
- expect { doctor.run }.to raise_error SystemExit
- expect(@stdout.string).to include("libicui18n.57.1.dylib")
+ expect { doctor.run }.to raise_error Bundler::ProductionError, strip_whitespace(<<-E).strip
+ The following gems are missing OS dependencies:
+ * bundler: /usr/local/opt/icu4c/lib/libicui18n.57.1.dylib
+ * rack: /usr/local/opt/icu4c/lib/libicui18n.57.1.dylib
+ E
end
end
diff --git a/spec/commands/exec_spec.rb b/spec/commands/exec_spec.rb
index 3d861c0799..4d374cebdd 100644
--- a/spec/commands/exec_spec.rb
+++ b/spec/commands/exec_spec.rb
@@ -564,6 +564,42 @@ describe "bundle exec" do
it_behaves_like "it runs"
end
+ context "regarding $0 and __FILE__" do
+ let(:executable) { super() + <<-'RUBY' }
+
+ puts "$0: #{$0.inspect}"
+ puts "__FILE__: #{__FILE__.inspect}"
+ RUBY
+
+ let(:expected) { super() + <<-EOS.chomp }
+
+$0: #{path.to_s.inspect}
+__FILE__: #{path.to_s.inspect}
+ EOS
+
+ it_behaves_like "it runs"
+
+ context "when the path is relative" do
+ let(:path) { super().relative_path_from(bundled_app) }
+
+ if LessThanProc.with(RUBY_VERSION).call("1.9")
+ pending "relative paths have ./ __FILE__"
+ else
+ it_behaves_like "it runs"
+ end
+ end
+
+ context "when the path is relative with a leading ./" do
+ let(:path) { Pathname.new("./#{super().relative_path_from(Pathname.pwd)}") }
+
+ if LessThanProc.with(RUBY_VERSION).call("< 1.9")
+ pending "relative paths with ./ have absolute __FILE__"
+ else
+ it_behaves_like "it runs"
+ end
+ end
+ end
+
context "signals being trapped by bundler" do
let(:executable) { strip_whitespace <<-RUBY }
#{shebang}
diff --git a/spec/commands/lock_spec.rb b/spec/commands/lock_spec.rb
index 693c1a6fe0..5600434607 100644
--- a/spec/commands/lock_spec.rb
+++ b/spec/commands/lock_spec.rb
@@ -10,9 +10,11 @@ describe "bundle lock" do
strip_lockfile bundled_app(file).read
end
+ let(:repo) { gem_repo1 }
+
before :each do
gemfile <<-G
- source "file://#{gem_repo1}"
+ source "file://#{repo}"
gem "rails"
gem "with_license"
gem "foo"
@@ -20,7 +22,7 @@ describe "bundle lock" do
@lockfile = strip_lockfile <<-L
GEM
- remote: file:#{gem_repo1}/
+ remote: file:#{repo}/
specs:
actionmailer (2.3.2)
activesupport (= 2.3.2)
@@ -77,7 +79,7 @@ describe "bundle lock" do
it "writes a lockfile when there is an outdated lockfile using --update" do
lockfile @lockfile.gsub("2.3.2", "2.3.1")
- bundle "lock --update"
+ bundle! "lock --update"
expect(read_lockfile).to eq(@lockfile)
end
@@ -132,4 +134,119 @@ describe "bundle lock" do
bundle "lock --remove-platform #{local}"
expect(out).to include("Removing all platforms from the bundle is not allowed")
end
+
+ # from https://github.com/bundler/bundler/issues/4896
+ it "properly adds platforms when platform requirements come from different dependencies" do
+ build_repo4 do
+ build_gem "ffi", "1.9.14"
+ build_gem "ffi", "1.9.14" do |s|
+ s.platform = mingw
+ end
+
+ build_gem "gssapi", "0.1"
+ build_gem "gssapi", "0.2"
+ build_gem "gssapi", "0.3"
+ build_gem "gssapi", "1.2.0" do |s|
+ s.add_dependency "ffi", ">= 1.0.1"
+ end
+
+ build_gem "mixlib-shellout", "2.2.6"
+ build_gem "mixlib-shellout", "2.2.6" do |s|
+ s.platform = "universal-mingw32"
+ s.add_dependency "win32-process", "~> 0.8.2"
+ end
+
+ # we need all these versions to get the sorting the same as it would be
+ # pulling from rubygems.org
+ %w(0.8.3 0.8.2 0.8.1 0.8.0).each do |v|
+ build_gem "win32-process", v do |s|
+ s.add_dependency "ffi", ">= 1.0.0"
+ end
+ end
+ end
+
+ gemfile <<-G
+ source "file:#{gem_repo4}"
+
+ gem "mixlib-shellout"
+ gem "gssapi"
+ G
+
+ simulate_platform(mingw) { bundle! :lock }
+
+ expect(the_bundle.lockfile).to read_as(strip_whitespace(<<-G))
+ GEM
+ remote: file:#{gem_repo4}/
+ specs:
+ ffi (1.9.14-x86-mingw32)
+ gssapi (1.2.0)
+ ffi (>= 1.0.1)
+ mixlib-shellout (2.2.6-universal-mingw32)
+ win32-process (~> 0.8.2)
+ win32-process (0.8.3)
+ ffi (>= 1.0.0)
+
+ PLATFORMS
+ x86-mingw32
+
+ DEPENDENCIES
+ gssapi
+ mixlib-shellout
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ G
+
+ simulate_platform(rb) { bundle! :lock }
+
+ expect(the_bundle.lockfile).to read_as(strip_whitespace(<<-G))
+ GEM
+ remote: file:#{gem_repo4}/
+ specs:
+ ffi (1.9.14)
+ ffi (1.9.14-x86-mingw32)
+ gssapi (1.2.0)
+ ffi (>= 1.0.1)
+ mixlib-shellout (2.2.6)
+ mixlib-shellout (2.2.6-universal-mingw32)
+ win32-process (~> 0.8.2)
+ win32-process (0.8.3)
+ ffi (>= 1.0.0)
+
+ PLATFORMS
+ ruby
+ x86-mingw32
+
+ DEPENDENCIES
+ gssapi
+ mixlib-shellout
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ G
+ end
+
+ context "when an update is available" do
+ let(:repo) { gem_repo2 }
+
+ before do
+ lockfile(@lockfile)
+ build_repo2 do
+ build_gem "foo", "2.0"
+ end
+ end
+
+ it "does not implicitly update" do
+ bundle! "lock"
+
+ expect(read_lockfile).to eq(@lockfile)
+ end
+
+ it "accounts for changes in the gemfile" do
+ gemfile gemfile.gsub('"foo"', '"foo", "2.0"')
+ bundle! "lock"
+
+ expect(read_lockfile).to eq(@lockfile.sub("foo (1.0)", "foo (2.0)").sub(/foo$/, "foo (= 2.0)"))
+ end
+ end
end
diff --git a/spec/commands/newgem_spec.rb b/spec/commands/newgem_spec.rb
index cb3c48132a..6e80aa7a60 100644
--- a/spec/commands/newgem_spec.rb
+++ b/spec/commands/newgem_spec.rb
@@ -112,6 +112,35 @@ describe "bundle gem" do
end
end
+ context "README.md" do
+ let(:gem_name) { "test_gem" }
+ let(:generated_gem) { Bundler::GemHelper.new(bundled_app(gem_name).to_s) }
+
+ context "git config user.name present" do
+ before do
+ execute_bundle_gem(gem_name)
+ end
+
+ it "contribute URL set to git username" do
+ expect(bundled_app("test_gem/README.md").read).not_to include("[USERNAME]")
+ end
+ end
+
+ context "git config user.name is absent" do
+ before do
+ `git config --unset user.name`
+ reset!
+ in_app_root
+ bundle "gem #{gem_name}"
+ remove_push_guard(gem_name)
+ end
+
+ it "contribute URL set to [USERNAME]" do
+ expect(bundled_app("test_gem/README.md").read).to include("[USERNAME]")
+ end
+ end
+ end
+
it "generates a valid gemspec" do
system_gems ["rake-10.0.2"]
diff --git a/spec/commands/update_spec.rb b/spec/commands/update_spec.rb
index 19fbb8388c..8a9867d1e9 100644
--- a/spec/commands/update_spec.rb
+++ b/spec/commands/update_spec.rb
@@ -72,6 +72,42 @@ describe "bundle update" do
end
end
+ describe "when a possible resolve requires an older version of a locked gem" do
+ context "and only_update_to_newer_versions is set" do
+ before do
+ bundle! "config only_update_to_newer_versions true"
+ end
+ it "does not go to an older version" do
+ build_repo4 do
+ build_gem "a" do |s|
+ s.add_dependency "b"
+ s.add_dependency "c"
+ end
+ build_gem "b"
+ build_gem "c"
+ build_gem "c", "2.0"
+ end
+
+ install_gemfile! <<-G
+ source "file:#{gem_repo4}"
+ gem "a"
+ G
+
+ expect(the_bundle).to include_gems("a 1.0", "b 1.0", "c 2.0")
+
+ update_repo4 do
+ build_gem "b", "2.0" do |s|
+ s.add_dependency "c", "< 2"
+ end
+ end
+
+ bundle! "update"
+
+ expect(the_bundle).to include_gems("a 1.0", "b 1.0", "c 2.0")
+ end
+ end
+ end
+
describe "with --local option" do
it "doesn't hit repo2" do
FileUtils.rm_rf(gem_repo2)
diff --git a/spec/install/gemfile/eval_gemfile_spec.rb b/spec/install/gemfile/eval_gemfile_spec.rb
index 2660ac98c2..29f27550e4 100644
--- a/spec/install/gemfile/eval_gemfile_spec.rb
+++ b/spec/install/gemfile/eval_gemfile_spec.rb
@@ -26,6 +26,24 @@ describe "bundle install with gemfile that uses eval_gemfile" do
end
end
+ context "eval-ed Gemfile has relative-path gems" do
+ before do
+ build_lib("a", :path => "gems/a")
+ create_file "nested/Gemfile-nested", <<-G
+ gem "a", :path => "../gems/a"
+ G
+
+ gemfile <<-G
+ eval_gemfile "nested/Gemfile-nested"
+ G
+ end
+
+ it "installs the path gem" do
+ bundle! :install
+ expect(the_bundle).to include_gem("a 1.0")
+ end
+ end
+
context "Gemfile uses gemspec paths after eval-ing a Gemfile" do
before { create_file "other/Gemfile-other" }
diff --git a/spec/install/gemfile/specific_platform_spec.rb b/spec/install/gemfile/specific_platform_spec.rb
new file mode 100644
index 0000000000..3e12f94c86
--- /dev/null
+++ b/spec/install/gemfile/specific_platform_spec.rb
@@ -0,0 +1,95 @@
+# frozen_string_literal: true
+require "spec_helper"
+
+describe "bundle install with specific_platform enabled" do
+ before do
+ bundle "config specific_platform true"
+
+ build_repo2 do
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1")
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x86_64-linux" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x86-mingw32" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x86-linux" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x64-mingw32" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "universal-darwin" }
+
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.5") {|s| s.platform = "x86_64-linux" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.5") {|s| s.platform = "x86-linux" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.5") {|s| s.platform = "x64-mingw32" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.5") {|s| s.platform = "x86-mingw32" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.5")
+
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "universal-darwin" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "x86_64-linux" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "x86-mingw32" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "x86-linux" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "x64-mingw32" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.4")
+
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.3")
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.3") {|s| s.platform = "x86_64-linux" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.3") {|s| s.platform = "x86-mingw32" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.3") {|s| s.platform = "x86-linux" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.3") {|s| s.platform = "x64-mingw32" }
+ build_gem("google-protobuf", "3.0.0.alpha.5.0.3") {|s| s.platform = "universal-darwin" }
+
+ build_gem("google-protobuf", "3.0.0.alpha.4.0")
+ build_gem("google-protobuf", "3.0.0.alpha.3.1.pre")
+ build_gem("google-protobuf", "3.0.0.alpha.3")
+ build_gem("google-protobuf", "3.0.0.alpha.2.0")
+ build_gem("google-protobuf", "3.0.0.alpha.1.1")
+ build_gem("google-protobuf", "3.0.0.alpha.1.0")
+ end
+ end
+
+ let(:google_protobuf) { <<-G }
+ source "file:#{gem_repo2}"
+ gem "google-protobuf"
+ G
+
+ context "when on a darwin machine" do
+ before { simulate_platform "x86_64-darwin-15" }
+
+ it "locks to both the specific darwin platform and ruby" do
+ install_gemfile!(google_protobuf)
+ expect(the_bundle.locked_gems.platforms).to eq([pl("ruby"), pl("x86_64-darwin-15")])
+ expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin")
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w(
+ google-protobuf-3.0.0.alpha.5.0.5.1
+ google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin
+ ))
+ end
+
+ it "caches both the universal-darwin and ruby gems when --all-platforms is passed" do
+ gemfile(google_protobuf)
+ bundle! "package --all-platforms"
+ expect([cached_gem("google-protobuf-3.0.0.alpha.5.0.5.1"), cached_gem("google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin")]).
+ to all(exist)
+ end
+
+ context "when adding a platform via lock --add_platform" do
+ it "adds the foreign platform" do
+ install_gemfile!(google_protobuf)
+ bundle! "lock --add-platform=#{x64_mingw}"
+
+ expect(the_bundle.locked_gems.platforms).to eq([rb, x64_mingw, pl("x86_64-darwin-15")])
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w(
+ google-protobuf-3.0.0.alpha.5.0.5.1
+ google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin
+ google-protobuf-3.0.0.alpha.5.0.5.1-x64-mingw32
+ ))
+ end
+
+ it "falls back on plain ruby when that version doesnt have a platform-specific gem" do
+ install_gemfile!(google_protobuf)
+ bundle! "lock --add-platform=#{java}"
+
+ expect(the_bundle.locked_gems.platforms).to eq([java, rb, pl("x86_64-darwin-15")])
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w(
+ google-protobuf-3.0.0.alpha.5.0.5.1
+ google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin
+ ))
+ end
+ end
+ end
+end
diff --git a/spec/install/gemfile_spec.rb b/spec/install/gemfile_spec.rb
index 98abc30c86..03ae344987 100644
--- a/spec/install/gemfile_spec.rb
+++ b/spec/install/gemfile_spec.rb
@@ -66,4 +66,33 @@ describe "bundle install" do
expect(out).to match(/You passed :lib as an option for gem 'rack', but it is invalid/)
end
end
+
+ context "with engine specified in symbol" do
+ it "does not raise any error parsing Gemfile" do
+ simulate_ruby_version "2.3.0" do
+ simulate_ruby_engine "jruby", "9.1.2.0" do
+ install_gemfile! <<-G
+ source "https://rubygems.org"
+ ruby "2.3.0", :engine => :jruby, :engine_version => "9.1.2.0"
+ G
+
+ expect(out).to match(/Bundle complete!/)
+ end
+ end
+ end
+
+ it "installation succeeds" do
+ simulate_ruby_version "2.3.0" do
+ simulate_ruby_engine "jruby", "9.1.2.0" do
+ install_gemfile! <<-G
+ source "file://#{gem_repo1}"
+ ruby "2.3.0", :engine => :jruby, :engine_version => "9.1.2.0"
+ gem "rack"
+ G
+
+ expect(the_bundle).to include_gems "rack 1.0.0"
+ end
+ end
+ end
+ end
end
diff --git a/spec/install/gems/compact_index_spec.rb b/spec/install/gems/compact_index_spec.rb
index 0edd1d20e7..228d8ddcc9 100644
--- a/spec/install/gems/compact_index_spec.rb
+++ b/spec/install/gems/compact_index_spec.rb
@@ -695,4 +695,47 @@ The checksum of /versions does not match the checksum provided by the server! So
expect(File.read(versions)).to start_with("created_at")
expect(the_bundle).to include_gems "rack 1.0.0"
end
+
+ it "fails gracefully when the source URI has an invalid scheme" do
+ install_gemfile <<-G
+ source "htps://rubygems.org"
+ gem "rack"
+ G
+ expect(exitstatus).to eq(15) if exitstatus
+ expect(out).to end_with(<<-E.strip)
+ The request uri `htps://index.rubygems.org/versions` has an invalid scheme (`htps`). Did you mean `http` or `https`?
+ E
+ end
+
+ describe "checksum validation", :rubygems => ">= 2.3.0" do
+ it "raises when the checksum does not match" do
+ install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum"
+ source "#{source_uri}"
+ gem "rack"
+ G
+ expect(exitstatus).to eq(19) if exitstatus
+ expect(out).
+ to include("The checksum for the downloaded `rack-1.0.0.gem` did not match the checksum given by the API.").
+ and include("This means that the contents of the gem appear to be different from what was uploaded, and could be an indicator of a security issue.").
+ and match(/\(The expected SHA256 checksum was "#{"ab" * 22}", but the checksum for the downloaded gem was ".+?"\.\)/).
+ and include("Bundler cannot continue installing rack (1.0.0).")
+ end
+
+ it "raises when the checksum is the wrong length" do
+ install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum", :env => { "BUNDLER_SPEC_RACK_CHECKSUM" => "checksum!" }
+ source "#{source_uri}"
+ gem "rack"
+ G
+ expect(exitstatus).to eq(5) if exitstatus
+ expect(out).to include("The given checksum for rack-1.0.0 (\"checksum!\") is not a valid SHA256 hexdigest nor base64digest")
+ end
+
+ it "does not raise when disable_checksum_validation is set" do
+ bundle! "config disable_checksum_validation true"
+ install_gemfile! <<-G, :artifice => "compact_index_wrong_gem_checksum"
+ source "#{source_uri}"
+ gem "rack"
+ G
+ end
+ end
end
diff --git a/spec/install/gems/resolving_spec.rb b/spec/install/gems/resolving_spec.rb
index 816799c0f8..0204a222f9 100644
--- a/spec/install/gems/resolving_spec.rb
+++ b/spec/install/gems/resolving_spec.rb
@@ -119,20 +119,58 @@ describe "bundle install with install-time dependencies" do
end
context "allows no gems" do
- it "does not try to install those gems" do
+ before do
build_repo2 do
build_gem "require_ruby" do |s|
s.required_ruby_version = "> 9000"
end
end
+ end
- install_gemfile <<-G
- source "file://#{gem_repo2}"
- gem 'require_ruby'
- G
+ let(:ruby_requirement) { %("#{RUBY_VERSION}") }
+ let(:error_message_requirement) { "~> #{RUBY_VERSION}.0" }
+
+ shared_examples_for "ruby version conflicts" do
+ it "raises an error during resolution" do
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2 }
+ source "http://localgemserver.test/"
+ ruby #{ruby_requirement}
+ gem 'require_ruby'
+ G
+
+ expect(out).to_not include("Gem::InstallError: require_ruby requires Ruby version > 9000")
+
+ nice_error = strip_whitespace(<<-E).strip
+ Fetching gem metadata from http://localgemserver.test/.
+ Fetching version metadata from http://localgemserver.test/
+ Resolving dependencies...
+ Bundler could not find compatible versions for gem "ruby\0":
+ In Gemfile:
+ ruby\0 (#{error_message_requirement})
+
+ require_ruby was resolved to 1.0, which depends on
+ ruby\0 (> 9000)
+
+ Could not find gem 'ruby\0 (> 9000)', which is required by gem 'require_ruby', in any of the sources.
+ E
+ expect(out).to eq(nice_error)
+ end
+ end
+
+ it_behaves_like "ruby version conflicts"
+
+ describe "with a < requirement" do
+ let(:ruby_requirement) { %("< 5000") }
+ let(:error_message_requirement) { "< 5000" }
+
+ it_behaves_like "ruby version conflicts"
+ end
+
+ describe "with a compound requirement" do
+ let(:ruby_requirement) { %("< 5000", "> 0.1") }
+ let(:error_message_requirement) { "< 5000, > 0.1" }
- expect(out).to_not include("Gem::InstallError: require_ruby requires Ruby version > 9000")
- expect(out).to include("require_ruby-1.0 requires ruby version > 9000, which is incompatible with the current version, #{Bundler::RubyVersion.system}")
+ it_behaves_like "ruby version conflicts"
end
end
end
diff --git a/spec/install/gemspecs_spec.rb b/spec/install/gemspecs_spec.rb
index 3e6021b7e2..8f719bf601 100644
--- a/spec/install/gemspecs_spec.rb
+++ b/spec/install/gemspecs_spec.rb
@@ -50,7 +50,7 @@ describe "bundle install" do
context "when ruby version is specified in gemspec and gemfile" do
it "installs when patch level is not specified and the version matches" do
build_lib("foo", :path => bundled_app) do |s|
- s.required_ruby_version = RUBY_VERSION
+ s.required_ruby_version = "~> #{RUBY_VERSION}.0"
end
install_gemfile <<-G
diff --git a/spec/install/path_spec.rb b/spec/install/path_spec.rb
index 3d84fffd58..03c42f008c 100644
--- a/spec/install/path_spec.rb
+++ b/spec/install/path_spec.rb
@@ -130,21 +130,21 @@ describe "bundle install" do
end
end
- describe "to a dead symlink" do
+ describe "to a file" do
before do
in_app_root do
- `ln -s /tmp/idontexist bundle`
+ `touch /tmp/idontexist bundle`
end
end
- it "reports the symlink is dead" do
+ it "reports the file exists" do
gemfile <<-G
source "file://#{gem_repo1}"
gem "rack"
G
bundle "install --path bundle"
- expect(out).to match(/invalid symlink/)
+ expect(out).to match(/file already exists/)
end
end
end
diff --git a/spec/other/major_deprecation_spec.rb b/spec/other/major_deprecation_spec.rb
index c8a2633279..6505023d13 100644
--- a/spec/other/major_deprecation_spec.rb
+++ b/spec/other/major_deprecation_spec.rb
@@ -4,6 +4,22 @@ require "spec_helper"
describe "major deprecations" do
let(:warnings) { out } # change to err in 2.0
+ context "in a .99 version" do
+ before do
+ simulate_bundler_version "1.99.1"
+ bundle "config --delete major_deprecations"
+ end
+
+ it "prints major deprecations without being configured" do
+ ruby <<-R
+ require "bundler"
+ Bundler::SharedHelpers.major_deprecation(Bundler::VERSION)
+ R
+
+ expect(warnings).to have_major_deprecation("1.99.1")
+ end
+ end
+
before do
bundle "config major_deprecations true"
diff --git a/spec/other/trampoline_spec.rb b/spec/other/trampoline_spec.rb
index 2aac0a2c1d..9a8e0a4a5d 100644
--- a/spec/other/trampoline_spec.rb
+++ b/spec/other/trampoline_spec.rb
@@ -59,6 +59,24 @@ describe "bundler version trampolining" do
end
end
+ context "without BUNDLE_ENABLE_TRAMPOLINE" do
+ before { ENV["BUNDLE_ENABLE_TRAMPOLINE"] = nil }
+
+ context "when the version is >= 2" do
+ let(:version) { "2.7182818285" }
+ before do
+ simulate_bundler_version version do
+ install_gemfile! ""
+ end
+ end
+
+ it "trampolines automatically", :realworld => true do
+ bundle "--version"
+ expect(err).to include("Installing locked Bundler version #{version}...")
+ end
+ end
+ end
+
context "installing missing bundler versions", :realworld => true do
before do
ENV["BUNDLER_VERSION"] = "1.12.3"
diff --git a/spec/realworld/edgecases_spec.rb b/spec/realworld/edgecases_spec.rb
index 7a78a114b4..06e588044c 100644
--- a/spec/realworld/edgecases_spec.rb
+++ b/spec/realworld/edgecases_spec.rb
@@ -48,8 +48,16 @@ describe "real world edgecases", :realworld => true, :sometimes => true do
gem 'capybara', '~> 2.2.0'
gem 'rack-cache', '1.2.0' # last version that works on Ruby 1.9
G
- bundle :lock
- expect(lockfile).to include("rails (3.2.22.4)")
+ bundle! :lock
+ rails_version = ruby(<<-R)
+ require 'rubygems'
+ require 'bundler'
+ fetcher = Bundler::Fetcher.new(Bundler::Source::Rubygems::Remote.new(URI('https://rubygems.org')))
+ index = fetcher.specs(%w(rails), nil)
+ rails = index.search(Gem::Dependency.new("rails", "~> 3.0")).last
+ puts rails.version
+ R
+ expect(lockfile).to include("rails (#{rails_version})")
expect(lockfile).to include("capybara (2.2.1)")
end
diff --git a/spec/resolver/basic_spec.rb b/spec/resolver/basic_spec.rb
index b7b8b4c3b8..3e8883d1d4 100644
--- a/spec/resolver/basic_spec.rb
+++ b/spec/resolver/basic_spec.rb
@@ -92,15 +92,18 @@ describe "Resolving" do
gem "bar", "2.0.0" do |s|
s.required_ruby_version = "~> 2.0.0"
end
+
+ gem "ruby\0", "1.8.7"
end
dep "foo"
+ dep "ruby\0", "1.8.7"
deps = []
@deps.each do |d|
deps << Bundler::DepProxy.new(d, "ruby")
end
- should_resolve_and_include %w(foo-1.0.0 bar-1.0.0), [{}, [], Bundler::RubyVersion.new("1.8.7", nil, nil, nil)]
+ should_resolve_and_include %w(foo-1.0.0 bar-1.0.0), [{}, []]
end
context "conservative" do
diff --git a/spec/resolver/platform_spec.rb b/spec/resolver/platform_spec.rb
index d5f217684c..fa91eab9c2 100644
--- a/spec/resolver/platform_spec.rb
+++ b/spec/resolver/platform_spec.rb
@@ -50,7 +50,7 @@ describe "Resolving platform craziness" do
# mingw is _not_ hardcoded to add CPU x86 in rubygems
platforms "x86-mingw32"
dep "thin"
- should_resolve_as %w(thin-1.2.7-x86-mingw32)
+ should_resolve_as %w(thin-1.2.7-mingw32)
end
it "finds x64-mingw gems" do
diff --git a/spec/support/artifice/compact_index.rb b/spec/support/artifice/compact_index.rb
index 233c192a67..0afd7fc526 100644
--- a/spec/support/artifice/compact_index.rb
+++ b/spec/support/artifice/compact_index.rb
@@ -78,7 +78,12 @@ class CompactIndexAPI < Endpoint
reqs = d.requirement.requirements.map {|r| r.join(" ") }.join(", ")
CompactIndex::Dependency.new(d.name, reqs)
end
- CompactIndex::GemVersion.new(spec.version.version, spec.platform.to_s, nil, nil,
+ checksum = begin
+ Digest::SHA256.file("#{GEM_REPO}/gems/#{spec.original_name}.gem").base64digest
+ rescue
+ nil
+ end
+ CompactIndex::GemVersion.new(spec.version.version, spec.platform.to_s, checksum, nil,
deps, spec.required_ruby_version, spec.required_rubygems_version)
end
CompactIndex::Gem.new(name, gem_versions)
@@ -98,8 +103,8 @@ class CompactIndexAPI < Endpoint
file = tmp("versions.list")
file.delete if file.file?
file = CompactIndex::VersionsFile.new(file.to_s)
- file.update_with(gems)
- CompactIndex.versions(file, nil, {})
+ file.create(gems)
+ file.contents
end
end
diff --git a/spec/support/artifice/compact_index_concurrent_download.rb b/spec/support/artifice/compact_index_concurrent_download.rb
index 30a2171a30..b788a852cf 100644
--- a/spec/support/artifice/compact_index_concurrent_download.rb
+++ b/spec/support/artifice/compact_index_concurrent_download.rb
@@ -22,8 +22,8 @@ class CompactIndexConcurrentDownload < CompactIndexAPI
file = tmp("versions.list")
file.delete if file.file?
file = CompactIndex::VersionsFile.new(file.to_s)
- file.update_with(gems)
- CompactIndex.versions(file, nil, {})
+ file.create(gems)
+ file.contents
end
end
end
diff --git a/spec/support/artifice/compact_index_extra_api.rb b/spec/support/artifice/compact_index_extra_api.rb
index 063e5589d4..844a9ca9f2 100644
--- a/spec/support/artifice/compact_index_extra_api.rb
+++ b/spec/support/artifice/compact_index_extra_api.rb
@@ -15,8 +15,8 @@ class CompactIndexExtraApi < CompactIndexAPI
file = tmp("versions.list")
file.delete if file.file?
file = CompactIndex::VersionsFile.new(file.to_s)
- file.update_with(gems(gem_repo4))
- CompactIndex.versions(file, nil, {})
+ file.create(gems(gem_repo4))
+ file.contents
end
end
diff --git a/spec/support/artifice/compact_index_wrong_gem_checksum.rb b/spec/support/artifice/compact_index_wrong_gem_checksum.rb
new file mode 100644
index 0000000000..3a12a59ae7
--- /dev/null
+++ b/spec/support/artifice/compact_index_wrong_gem_checksum.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+require File.expand_path("../compact_index", __FILE__)
+
+Artifice.deactivate
+
+class CompactIndexWrongGemChecksum < CompactIndexAPI
+ get "/info/:name" do
+ etag_response do
+ name = params[:name]
+ gem = gems.find {|g| g.name == name }
+ checksum = ENV.fetch("BUNDLER_SPEC_#{name.upcase}_CHECKSUM") { "ab" * 22 }
+ versions = gem ? gem.versions : []
+ versions.each {|v| v.checksum = checksum }
+ CompactIndex.info(versions)
+ end
+ end
+end
+
+Artifice.activate_with(CompactIndexWrongGemChecksum)
diff --git a/spec/support/builders.rb b/spec/support/builders.rb
index 337234f14a..7436779d15 100644
--- a/spec/support/builders.rb
+++ b/spec/support/builders.rb
@@ -610,7 +610,10 @@ module Spec
end
def _default_files
- @_default_files ||= { "lib/#{name}.rb" => "#{Builders.constantize(name)} = '#{version}'" }
+ @_default_files ||= begin
+ platform_string = " #{@spec.platform}" unless @spec.platform == Gem::Platform::RUBY
+ { "lib/#{name}.rb" => "#{Builders.constantize(name)} = '#{version}#{platform_string}'" }
+ end
end
def _default_path
diff --git a/spec/support/helpers.rb b/spec/support/helpers.rb
index fe79604f30..b30c44d1cb 100644
--- a/spec/support/helpers.rb
+++ b/spec/support/helpers.rb
@@ -208,7 +208,11 @@ module Spec
end
def gemfile(*args)
- create_file("Gemfile", *args)
+ if args.empty?
+ File.open("Gemfile", "r", &:read)
+ else
+ create_file("Gemfile", *args)
+ end
end
def lockfile(*args)
diff --git a/spec/support/indexes.rb b/spec/support/indexes.rb
index 9a7879bc74..29780014fc 100644
--- a/spec/support/indexes.rb
+++ b/spec/support/indexes.rb
@@ -62,7 +62,7 @@ module Spec
s.level = opts.first
s.strict = opts.include?(:strict)
end
- should_resolve_and_include specs, [{}, @base, nil, search]
+ should_resolve_and_include specs, [{}, @base, search]
end
def an_awesome_index
diff --git a/spec/support/matchers.rb b/spec/support/matchers.rb
index 9476f18984..9248360639 100644
--- a/spec/support/matchers.rb
+++ b/spec/support/matchers.rb
@@ -110,15 +110,9 @@ module Spec
define_compound_matcher :read_as, [exist] do |file_contents|
diffable
- attr_reader :strip_whitespace
-
- chain :stripping_whitespace do
- @strip_whitespace = true
- end
match do |actual|
@actual = Bundler.read_file(actual)
- file_contents = strip_whitespace(file_contents) if strip_whitespace
values_match?(file_contents, @actual)
end
end
diff --git a/spec/support/platforms.rb b/spec/support/platforms.rb
index b1dedb05fa..a2a3afba00 100644
--- a/spec/support/platforms.rb
+++ b/spec/support/platforms.rb
@@ -11,6 +11,10 @@ module Spec
Gem::Platform.new("x86-darwin-10")
end
+ def x64_mac
+ Gem::Platform.new("x86_64-darwin-15")
+ end
+
def java
Gem::Platform.new([nil, "java", nil])
end
diff --git a/spec/support/rubygems_ext.rb b/spec/support/rubygems_ext.rb
index 4ddbc3312a..e2b8c6a45e 100644
--- a/spec/support/rubygems_ext.rb
+++ b/spec/support/rubygems_ext.rb
@@ -9,7 +9,8 @@ module Spec
# rack 2.x requires Ruby version >= 2.2.2.
# artifice doesn't support rack 2.x now.
"rack" => "< 2",
- "fakeweb artifice compact_index" => nil,
+ "fakeweb artifice" => nil,
+ "compact_index" => "~> 0.11.0",
"sinatra" => "1.2.7",
# Rake version has to be consistent for tests to pass
"rake" => "10.0.2",
@@ -36,7 +37,7 @@ module Spec
FileUtils.rm_rf(Path.base_system_gems)
FileUtils.mkdir_p(Path.base_system_gems)
puts "installing gems for the tests to use..."
- DEPS.sort {|a, _| a[1].nil? ? 1 : -1 }.each {|n, v| install_gem(n, v) }
+ install_gems(DEPS)
File.open(manifest_path, "w") {|f| f << manifest.join }
end
@@ -45,10 +46,14 @@ module Spec
Gem::DefaultUserInteraction.ui = Gem::SilentUI.new
end
- def self.install_gem(name, version = nil)
- cmd = "gem install #{name} --no-rdoc --no-ri"
- cmd += " --version '#{version}'" if version
- system(cmd) || raise("Installing gem #{name} for the tests to use failed!")
+ def self.install_gems(gems)
+ reqs, no_reqs = gems.partition {|_, req| !req.nil? && !req.split(" ").empty? }
+ no_reqs.map!(&:first)
+ reqs.map! {|name, req| "'#{name}:#{req}'" }
+ deps = reqs.concat(no_reqs).join(" ")
+ cmd = "gem install #{deps} --no-rdoc --no-ri"
+ puts cmd
+ system(cmd) || raise("Installing gems #{deps} for the tests to use failed!")
end
end
end
diff --git a/spec/support/the_bundle.rb b/spec/support/the_bundle.rb
index 86df9cd9c7..742d393425 100644
--- a/spec/support/the_bundle.rb
+++ b/spec/support/the_bundle.rb
@@ -27,5 +27,10 @@ module Spec
def lockfile
bundle_dir.join("Gemfile.lock")
end
+
+ def locked_gems
+ raise "Cannot read lockfile if it doesn't exist" unless locked?
+ Bundler::LockfileParser.new(lockfile.read)
+ end
end
end