summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThe Bundler Bot <bot@bundler.io>2017-07-25 03:33:50 +0000
committerThe Bundler Bot <bot@bundler.io>2017-07-25 03:33:50 +0000
commit219ea82fd4c84fcf047fc4cd957147600902288e (patch)
treec0feb454837dc0de5df6666a81d48fc657ad9d3b
parentc34f20a39b03d07f72089fa58bf5af24edd6b490 (diff)
parent65c05e88eaba044117e80aa40c8a8e7ffc8f6a27 (diff)
downloadbundler-219ea82fd4c84fcf047fc4cd957147600902288e.tar.gz
Auto merge of #5860 - bundler:seg-validate-settings, r=segiddins
Introduce the notion of settings validation & default install to ./.bundle Thanks so much for the contribution! To make reviewing this PR a bit easier, please fill out answers to the following questions. ### What was the end-user problem that led to this PR? The problem was... ### What was your diagnosis of the problem? My diagnosis was... ### What is your fix for the problem, implemented in this PR? My fix... ### Why did you choose this fix out of the possible options? I chose this fix because...
-rw-r--r--lib/bundler.rb28
-rw-r--r--lib/bundler/cli/check.rb5
-rw-r--r--lib/bundler/cli/clean.rb9
-rw-r--r--lib/bundler/cli/doctor.rb1
-rw-r--r--lib/bundler/cli/install.rb28
-rw-r--r--lib/bundler/cli/update.rb2
-rw-r--r--lib/bundler/endpoint_specification.rb1
-rw-r--r--lib/bundler/feature_flag.rb1
-rw-r--r--lib/bundler/installer.rb4
-rw-r--r--lib/bundler/resolver.rb4
-rw-r--r--lib/bundler/settings.rb94
-rw-r--r--lib/bundler/settings/validator.rb79
-rw-r--r--lib/bundler/source/git.rb4
-rw-r--r--lib/bundler/source/rubygems.rb2
-rw-r--r--man/bundle-config.ronn5
-rw-r--r--spec/bundler/bundler_spec.rb4
-rw-r--r--spec/bundler/settings/validator_spec.rb111
-rw-r--r--spec/cache/gems_spec.rb27
-rw-r--r--spec/commands/check_spec.rb8
-rw-r--r--spec/commands/clean_spec.rb29
-rw-r--r--spec/commands/doctor_spec.rb15
-rw-r--r--spec/commands/exec_spec.rb2
-rw-r--r--spec/commands/install_spec.rb20
-rw-r--r--spec/commands/newgem_spec.rb3
-rw-r--r--spec/commands/show_spec.rb6
-rw-r--r--spec/install/allow_offline_install_spec.rb2
-rw-r--r--spec/install/bundler_spec.rb20
-rw-r--r--spec/install/gemfile/gemspec_spec.rb21
-rw-r--r--spec/install/gemfile/git_spec.rb5
-rw-r--r--spec/install/gemfile/groups_spec.rb6
-rw-r--r--spec/install/gemfile/sources_spec.rb2
-rw-r--r--spec/install/gems/compact_index_spec.rb2
-rw-r--r--spec/install/gems/sudo_spec.rb3
-rw-r--r--spec/install/gemspecs_spec.rb4
-rw-r--r--spec/install/path_spec.rb4
-rw-r--r--spec/install/post_bundle_message_spec.rb26
-rw-r--r--spec/install/process_lock_spec.rb2
-rw-r--r--spec/other/platform_spec.rb26
-rw-r--r--spec/runtime/load_spec.rb17
-rw-r--r--spec/runtime/platform_spec.rb8
-rw-r--r--spec/runtime/require_spec.rb4
-rw-r--r--spec/runtime/setup_spec.rb10
-rw-r--r--spec/support/builders.rb15
-rw-r--r--spec/support/helpers.rb26
-rw-r--r--spec/support/path.rb6
-rw-r--r--spec/update/git_spec.rb4
46 files changed, 518 insertions, 187 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb
index d0ae913216..edef1620e8 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -75,7 +75,11 @@ module Bundler
# Returns absolute path of where gems are installed on the filesystem.
def bundle_path
- @bundle_path ||= Pathname.new(settings.path).expand_path(root)
+ @bundle_path ||= Pathname.new(configured_bundle_path.path).expand_path(root)
+ end
+
+ def configured_bundle_path
+ @configured_bundle_path ||= settings.path.tap(&:validate!)
end
# Returns absolute location of where binstubs are installed to.
@@ -329,6 +333,10 @@ EOF
Bundler.settings[:system_bindir] || Bundler.rubygems.gem_bindir
end
+ def use_system_gems?
+ configured_bundle_path.use_system_gems?
+ end
+
def requires_sudo?
return @requires_sudo if defined?(@requires_sudo_ran)
@@ -457,14 +465,16 @@ EOF
end
def reset_paths!
- @root = nil
- @settings = nil
+ @bin_path = nil
+ @bundle_path = nil
+ @configured = nil
+ @configured_bundle_path = nil
@definition = nil
- @setup = nil
@load = nil
@locked_gems = nil
- @bundle_path = nil
- @bin_path = nil
+ @root = nil
+ @settings = nil
+ @setup = nil
@user_home = nil
end
@@ -503,14 +513,14 @@ EOF
bundle_path
end
- def configure_gem_path(env = ENV, settings = self.settings)
+ def configure_gem_path(env = ENV)
blank_home = env["GEM_HOME"].nil? || env["GEM_HOME"].empty?
- if settings[:disable_shared_gems]
+ if !use_system_gems?
# this needs to be empty string to cause
# PathSupport.split_gem_path to only load up the
# Bundler --path setting as the GEM_PATH.
env["GEM_PATH"] = ""
- elsif blank_home || Bundler.rubygems.gem_dir != bundle_path.to_s
+ elsif blank_home
possibles = [Bundler.rubygems.gem_dir, Bundler.rubygems.gem_path]
paths = possibles.flatten.compact.uniq.reject(&:empty?)
env["GEM_PATH"] = paths.join(File::PATH_SEPARATOR)
diff --git a/lib/bundler/cli/check.rb b/lib/bundler/cli/check.rb
index c7367b2f42..e572787dc4 100644
--- a/lib/bundler/cli/check.rb
+++ b/lib/bundler/cli/check.rb
@@ -9,10 +9,7 @@ module Bundler
end
def run
- if path = options[:path]
- Bundler.settings.set_command_option :path, path
- Bundler.settings.set_command_option :disable_shared_gems, true
- end
+ Bundler.settings.set_command_option_if_given :path, options[:path]
begin
definition = Bundler.definition
diff --git a/lib/bundler/cli/clean.rb b/lib/bundler/cli/clean.rb
index 231127cf97..4a407fbae7 100644
--- a/lib/bundler/cli/clean.rb
+++ b/lib/bundler/cli/clean.rb
@@ -16,11 +16,10 @@ module Bundler
protected
def require_path_or_force
- if !Bundler.settings[:path] && !options[:force]
- raise InvalidOption, "Cleaning all the gems on your system is dangerous! " \
- "If you're sure you want to remove every system gem not in this " \
- "bundle, run `bundle clean --force`."
- end
+ return unless Bundler.use_system_gems? && !options[:force]
+ raise InvalidOption, "Cleaning all the gems on your system is dangerous! " \
+ "If you're sure you want to remove every system gem not in this " \
+ "bundle, run `bundle clean --force`."
end
end
end
diff --git a/lib/bundler/cli/doctor.rb b/lib/bundler/cli/doctor.rb
index ae27983240..7f28a5eb13 100644
--- a/lib/bundler/cli/doctor.rb
+++ b/lib/bundler/cli/doctor.rb
@@ -62,6 +62,7 @@ module Bundler
def run
Bundler.ui.level = "error" if options[:quiet]
+ Bundler.settings.validate!
check!
definition = Bundler.definition
diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb
index cc41cce7a6..771ff6f5dc 100644
--- a/lib/bundler/cli/install.rb
+++ b/lib/bundler/cli/install.rb
@@ -70,19 +70,19 @@ module Bundler
Bundler.ui.confirm "Bundle complete! #{dependencies_count_for(definition)}, #{gems_installed_for(definition)}."
Bundler::CLI::Common.output_without_groups_message
- if path = Bundler.settings[:path]
- absolute_path = File.expand_path(path)
- relative_path = absolute_path.sub(File.expand_path(".") + File::SEPARATOR, "." + File::SEPARATOR)
- Bundler.ui.confirm "Bundled gems are installed into #{relative_path}."
- else
+ if Bundler.use_system_gems?
Bundler.ui.confirm "Use `bundle info [gemname]` to see where a bundled gem is installed."
+ else
+ absolute_path = File.expand_path(Bundler.configured_bundle_path.base_path)
+ relative_path = absolute_path.sub(File.expand_path(".") + File::SEPARATOR, "." + File::SEPARATOR)
+ Bundler.ui.confirm "Bundled gems are installed into `#{relative_path}`"
end
Bundler::CLI::Common.output_post_install_messages installer.post_install_messages
warn_ambiguous_gems
- if Bundler.settings[:clean] && Bundler.settings[:path]
+ if Bundler.settings[:clean] && !Bundler.use_system_gems?
require "bundler/cli/clean"
Bundler::CLI::Clean.new(options).run
end
@@ -154,8 +154,8 @@ module Bundler
check_for_group_conflicts_in_cli_options
- Bundler.settings.set_command_option_if_given :with, options[:with]
- Bundler.settings.set_command_option_if_given :without, options[:without]
+ Bundler.settings.set_command_option :with, nil if options[:with] == []
+ Bundler.settings.set_command_option :without, nil if options[:without] == []
with = options.fetch(:with, [])
with |= Bundler.settings[:with].map(&:to_s)
@@ -189,11 +189,13 @@ module Bundler
Bundler.settings.set_command_option_if_given :clean, options["clean"]
- Bundler.settings.set_command_option :without, options[:without] unless Bundler.settings[:without] == options[:without]
- Bundler.settings.set_command_option :with, options[:with] unless Bundler.settings[:with] == options[:with]
-
- disable_shared_gems = Bundler.settings[:path] ? true : nil
- Bundler.settings.set_command_option :disable_shared_gems, disable_shared_gems unless Bundler.settings[:disable_shared_gems] == disable_shared_gems
+ unless Bundler.settings[:without] == options[:without] && Bundler.settings[:with] == options[:with]
+ # need to nil them out first to get around validation for backwards compatibility
+ Bundler.settings.set_command_option :without, nil
+ Bundler.settings.set_command_option :with, nil
+ Bundler.settings.set_command_option :without, options[:without] - options[:with]
+ Bundler.settings.set_command_option :with, options[:with]
+ end
options[:force] = options[:redownload]
end
diff --git a/lib/bundler/cli/update.rb b/lib/bundler/cli/update.rb
index c2391fa76d..fcf5397bf7 100644
--- a/lib/bundler/cli/update.rb
+++ b/lib/bundler/cli/update.rb
@@ -62,7 +62,7 @@ module Bundler
installer = Installer.install Bundler.root, Bundler.definition, opts
Bundler.load.cache if Bundler.app_cache.exist?
- if Bundler.settings[:clean] && Bundler.settings[:path]
+ if Bundler.settings[:clean] && !Bundler.use_system_gems?
require "bundler/cli/clean"
Bundler::CLI::Clean.new(options).run
end
diff --git a/lib/bundler/endpoint_specification.rb b/lib/bundler/endpoint_specification.rb
index 7231a1630e..8668c4ea7f 100644
--- a/lib/bundler/endpoint_specification.rb
+++ b/lib/bundler/endpoint_specification.rb
@@ -10,6 +10,7 @@ module Bundler
attr_accessor :source, :remote, :dependencies
def initialize(name, version, platform, dependencies, metadata = nil)
+ super()
@name = name
@version = Gem::Version.create version
@platform = platform
diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb
index 9956411a4b..67b89d89d3 100644
--- a/lib/bundler/feature_flag.rb
+++ b/lib/bundler/feature_flag.rb
@@ -47,6 +47,7 @@ module Bundler
settings_flag(:suppress_install_using_messages) { bundler_2_mode? }
settings_flag(:unlock_source_unlocks_spec) { !bundler_2_mode? }
settings_flag(:update_requires_all_flag) { bundler_2_mode? }
+ settings_flag(:default_install_uses_path) { bundler_2_mode? }
settings_option(:default_cli_command) { bundler_2_mode? ? :cli_help : :install }
diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb
index 9b648b0dd0..18debb72fe 100644
--- a/lib/bundler/installer.rb
+++ b/lib/bundler/installer.rb
@@ -155,7 +155,7 @@ module Bundler
# double-assignment to avoid warnings about variables that will be used by ERB
bin_path = Bundler.bin_path
unless path = Bundler.settings[:path]
- raise "Can't standalone without a path set"
+ raise "Can't standalone without an explicit path set"
end
standalone_path = standalone_path = Bundler.root.join(path).relative_path_from(bin_path)
template = File.read(File.expand_path("../templates/Executable.standalone", __FILE__))
@@ -260,7 +260,7 @@ module Bundler
Bundler.mkdir_p(p)
end unless Bundler.bundle_path.exist?
rescue Errno::EEXIST
- raise PathError, "Could not install to path `#{Bundler.settings[:path]}` " \
+ raise PathError, "Could not install to path `#{Bundler.bundle_path}` " \
"because a file already exists at that path. Either remove or rename the file so the directory can be created."
end
diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb
index aa512cb2e9..00cd0cad26 100644
--- a/lib/bundler/resolver.rb
+++ b/lib/bundler/resolver.rb
@@ -28,7 +28,7 @@ module Bundler
trees.reject! {|t| !maximal.include?(t.last) } if maximal
trees = trees.sort_by {|t| t.flatten.map(&:to_s) }
- trees.uniq! {|t| t.flatten.map {|dep| [dep.name, dep.requirement] } }
+ trees.uniq! {|t| t.flatten.map {|dep| [dep.name, dep.requirement.to_s] } }
o << trees.sort_by {|t| t.reverse.map(&:name) }.map do |tree|
t = String.new
@@ -453,7 +453,7 @@ module Bundler
message << if versions_with_platforms.any?
"The source contains '#{name}' at: #{formatted_versions_with_platforms(versions_with_platforms)}"
else
- "The source does not contain any versions of '#{requirement}'"
+ "The source does not contain any versions of '#{name}'"
end
else
message = "Could not find gem '#{requirement}' in any of the gem sources " \
diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb
index fa1483f804..15168b42e4 100644
--- a/lib/bundler/settings.rb
+++ b/lib/bundler/settings.rb
@@ -6,6 +6,7 @@ module Bundler
class Settings
autoload :Mirror, "bundler/mirror"
autoload :Mirrors, "bundler/mirror"
+ autoload :Validator, "bundler/settings/validator"
BOOL_KEYS = %w[
allow_bundler_dependency_conflicts
@@ -15,6 +16,7 @@ module Bundler
cache_all_platforms
cache_command_is_package
console_command
+ default_install_uses_path
deployment
deployment_means_frozen
disable_checksum_validation
@@ -37,6 +39,7 @@ module Bundler
no_install
no_prune
only_update_to_newer_versions
+ path.system
plugins
prefer_gems_rb
setup_makes_kernel_gem_public
@@ -205,21 +208,56 @@ module Bundler
locations
end
- # @local_config["BUNDLE_PATH"] should be prioritized over ENV["BUNDLE_PATH"]
+ # for legacy reasons, the ruby scope isnt appended when the setting comes from ENV or the global config,
+ # nor do we respect :disable_shared_gems
def path
key = key_for(:path)
path = ENV[key] || @global_config[key]
- return path if path && !@local_config.key?(key)
+ if path && !@temporary.key?(key) && !@local_config.key?(key)
+ return Path.new(path, false, false, false)
+ end
- if path = self[:path]
- "#{path}/#{Bundler.ruby_scope}"
- else
- Bundler.rubygems.gem_dir
+ system_path = self["path.system"] || (self[:disable_shared_gems] == false)
+ Path.new(self[:path], true, system_path, Bundler.feature_flag.default_install_uses_path?)
+ end
+
+ Path = Struct.new(:explicit_path, :append_ruby_scope, :system_path, :default_install_uses_path) do
+ def path
+ path = base_path
+ path = File.join(path, Bundler.ruby_scope) if append_ruby_scope && !use_system_gems?
+ path
+ end
+
+ def use_system_gems?
+ return true if system_path
+ return false if explicit_path
+ !default_install_uses_path
+ end
+
+ def base_path
+ path = explicit_path
+ path ||= ".bundle" unless use_system_gems?
+ path ||= Bundler.rubygems.gem_dir
+ path
+ end
+
+ def validate!
+ return unless explicit_path && system_path
+ path = Bundler.settings.pretty_values_for(:path)
+ path.unshift(nil, "path:") unless path.empty?
+ system_path = Bundler.settings.pretty_values_for("path.system")
+ system_path.unshift(nil, "path.system:") unless system_path.empty?
+ disable_shared_gems = Bundler.settings.pretty_values_for(:disable_shared_gems)
+ disable_shared_gems.unshift(nil, "disable_shared_gems:") unless disable_shared_gems.empty?
+ raise InvalidOption,
+ "Using a custom path while using system gems is unsupported.\n#{path.join("\n")}\n#{system_path.join("\n")}\n#{disable_shared_gems.join("\n")}"
end
end
def allow_sudo?
- !@local_config.key?(key_for(:path))
+ key = key_for(:path)
+ path_configured = @temporary.key?(key) || @local_config.key?(key)
+ !path_configured
end
def ignore_config?
@@ -230,7 +268,14 @@ module Bundler
@app_cache_path ||= self[:cache_path] || "vendor/cache"
end
- private
+ def validate!
+ all.each do |raw_key|
+ [@local_config, ENV, @global_config].each do |settings|
+ value = converted_value(settings[key_for(raw_key)], raw_key)
+ Validator.validate!(raw_key, value, settings.to_hash.dup)
+ end
+ end
+ end
def key_for(key)
key = Settings.normalize_uri(key).to_s if key.is_a?(String) && /https?:/ =~ key
@@ -238,6 +283,8 @@ module Bundler
"BUNDLE_#{key}"
end
+ private
+
def parent_setting_for(name)
split_specific_setting_for(name)[0]
end
@@ -282,24 +329,25 @@ module Bundler
array.join(":").tr(" ", ":")
end
- def set_key(key, value, hash, file)
- value = array_to_s(value) if is_array(key)
+ def set_key(raw_key, value, hash, file)
+ raw_key = raw_key.to_s
+ value = array_to_s(value) if is_array(raw_key)
- key = key_for(key)
+ key = key_for(raw_key)
- unless hash[key] == value
- hash[key] = value
- hash.delete(key) if value.nil?
- if file
- SharedHelpers.filesystem_access(file) do |p|
- FileUtils.mkdir_p(p.dirname)
- require "bundler/yaml_serializer"
- p.open("w") {|f| f.write(YAMLSerializer.dump(hash)) }
- end
- end
- end
+ return if hash[key] == value
+
+ hash[key] = value
+ hash.delete(key) if value.nil?
+
+ Validator.validate!(raw_key, converted_value(value, raw_key), hash)
- value
+ return unless file
+ SharedHelpers.filesystem_access(file) do |p|
+ FileUtils.mkdir_p(p.dirname)
+ require "bundler/yaml_serializer"
+ p.open("w") {|f| f.write(YAMLSerializer.dump(hash)) }
+ end
end
def converted_value(value, key)
diff --git a/lib/bundler/settings/validator.rb b/lib/bundler/settings/validator.rb
new file mode 100644
index 0000000000..9aa1627fb2
--- /dev/null
+++ b/lib/bundler/settings/validator.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+
+module Bundler
+ class Settings
+ class Validator
+ class Rule
+ attr_reader :description
+
+ def initialize(keys, description, &validate)
+ @keys = keys
+ @description = description
+ @validate = validate
+ end
+
+ def validate!(key, value, settings)
+ instance_exec(key, value, settings, &@validate)
+ end
+
+ def fail!(key, value, *reasons)
+ reasons.unshift @description
+ raise InvalidOption, "Setting `#{key}` to #{value.inspect} failed:\n#{reasons.map {|r| " - #{r}" }.join("\n")}"
+ end
+
+ def set(settings, key, value, *reasons)
+ hash_key = k(key)
+ return if settings[hash_key] == value
+ reasons.unshift @description
+ Bundler.ui.info "Setting `#{key}` to #{value.inspect}, since #{reasons.join(", ")}"
+ if value.nil?
+ settings.delete(hash_key)
+ else
+ settings[hash_key] = value
+ end
+ end
+
+ def k(key)
+ Bundler.settings.key_for(key)
+ end
+ end
+
+ def self.rules
+ @rules ||= Hash.new {|h, k| h[k] = [] }
+ end
+ private_class_method :rules
+
+ def self.rule(keys, description, &blk)
+ rule = Rule.new(keys, description, &blk)
+ keys.each {|k| rules[k] << rule }
+ end
+ private_class_method :rule
+
+ def self.validate!(key, value, settings)
+ rules_to_validate = rules[key]
+ rules_to_validate.each {|rule| rule.validate!(key, value, settings) }
+ end
+
+ rule %w[path path.system], "path and path.system are mutually exclusive" do |key, value, settings|
+ if key == "path" && value
+ set(settings, "path.system", nil)
+ elsif key == "path.system" && value
+ set(settings, :path, nil)
+ end
+ end
+
+ rule %w[with without], "a group cannot be in both `with` & `without` simultaneously" do |key, value, settings|
+ with = settings.fetch(k(:with), "").split(":").map(&:to_sym)
+ without = settings.fetch(k(:without), "").split(":").map(&:to_sym)
+
+ other_key = key == "with" ? :without : :with
+ other_setting = key == "with" ? without : with
+
+ conflicting = with & without
+ if conflicting.any?
+ fail!(key, value, "`#{other_key}` is current set to #{other_setting.inspect}", "the `#{conflicting.join("`, `")}` groups conflict")
+ end
+ end
+ end
+ end
+end
diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb
index 020cf74766..eb605771f4 100644
--- a/lib/bundler/source/git.rb
+++ b/lib/bundler/source/git.rb
@@ -172,13 +172,11 @@ module Bundler
print_using_message "Using #{version_message(spec)} from #{self}"
- if requires_checkout? && !@copied && !force
+ if (requires_checkout? && !@copied) || force
Bundler.ui.debug " * Checking out revision: #{ref}"
git_proxy.copy_to(install_path, submodules)
serialize_gemspecs_in(install_path)
@copied = true
- elsif force
- git_proxy.copy_to(install_path, submodules)
end
generate_bin_options = { :disable_extensions => !Bundler.rubygems.spec_missing_extensions?(spec), :build_args => options[:build_args] }
diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb
index 0ac45b3d70..511216a5c5 100644
--- a/lib/bundler/source/rubygems.rb
+++ b/lib/bundler/source/rubygems.rb
@@ -377,7 +377,6 @@ module Bundler
return false unless spec.remote
spec.fetch_platform
- Bundler.ui.confirm("Fetching #{version_message(spec)}")
download_path = requires_sudo? ? Bundler.tmp(spec.full_name) : rubygems_dir
gem_path = "#{rubygems_dir}/cache/#{spec.full_name}.gem"
@@ -443,6 +442,7 @@ module Bundler
end
else
uri = spec.remote.uri
+ Bundler.ui.confirm("Fetching #{version_message(spec)}")
Bundler.rubygems.download_gem(spec, uri, download_path)
cache_globally(spec, local_path)
end
diff --git a/man/bundle-config.ronn b/man/bundle-config.ronn
index 99746d57bb..dd315b9955 100644
--- a/man/bundle-config.ronn
+++ b/man/bundle-config.ronn
@@ -141,6 +141,9 @@ learn more about their operation in [bundle install(1)][bundle-install].
`bundle install`.
* `console` (`BUNDLE_CONSOLE`):
The console that `bundle console` starts. Defaults to `irb`.
+* `default_install_uses_path` (`BUNDLE_DEFAULT_INSTALL_USES_PATH`):
+ Whether a `bundle install` without an explicit `--path` argument defaults
+ to installing gems in `.bundle`.
* `deployment` (`BUNDLE_DEPLOYMENT`):
Disallow changes to the `Gemfile`. When the `Gemfile` is changed and the
lockfile has not been updated, running Bundler commands will be blocked.
@@ -205,6 +208,8 @@ learn more about their operation in [bundle install(1)][bundle-install].
of `$GEM_HOME` or `$GEM_PATH` values. Bundle gems not found in this location
will be installed by `bundle install`. Defaults to `Gem.dir`. When --deployment
is used, defaults to vendor/bundle.
+* `path.system` (`BUNDLE_PATH__SYSTEM`):
+ Whether Bundler will install gems into the default system path (`Gem.dir`).
* `plugins` (`BUNDLE_PLUGINS`):
Enable Bundler's experimental plugin system.
* `prefer_gems_rb` (`BUNDLE_PREFER_GEMS_RB`)
diff --git a/spec/bundler/bundler_spec.rb b/spec/bundler/bundler_spec.rb
index 882d368358..633aed12db 100644
--- a/spec/bundler/bundler_spec.rb
+++ b/spec/bundler/bundler_spec.rb
@@ -145,8 +145,8 @@ RSpec.describe Bundler do
context "disable_shared_gems" do
it "should unset GEM_PATH with empty string" do
env = {}
- settings = { :disable_shared_gems => true }
- Bundler.send(:configure_gem_path, env, settings)
+ expect(Bundler).to receive(:use_system_gems?).and_return(false)
+ Bundler.send(:configure_gem_path, env)
expect(env.keys).to include("GEM_PATH")
expect(env["GEM_PATH"]).to eq ""
end
diff --git a/spec/bundler/settings/validator_spec.rb b/spec/bundler/settings/validator_spec.rb
new file mode 100644
index 0000000000..e4ffd89435
--- /dev/null
+++ b/spec/bundler/settings/validator_spec.rb
@@ -0,0 +1,111 @@
+# frozen_string_literal: true
+
+RSpec.describe Bundler::Settings::Validator do
+ describe ".validate!" do
+ def validate!(key, value, settings)
+ transformed_key = Bundler.settings.key_for(key)
+ if value.nil?
+ settings.delete(transformed_key)
+ else
+ settings[transformed_key] = value
+ end
+ described_class.validate!(key, value, settings)
+ settings
+ end
+
+ it "path and path.system are mutually exclusive" do
+ expect(validate!("path", "bundle", {})).to eq("BUNDLE_PATH" => "bundle")
+ expect(validate!("path", "bundle", "BUNDLE_PATH__SYSTEM" => false)).to eq("BUNDLE_PATH" => "bundle")
+ expect(validate!("path", "bundle", "BUNDLE_PATH__SYSTEM" => true)).to eq("BUNDLE_PATH" => "bundle")
+ expect(validate!("path", nil, "BUNDLE_PATH__SYSTEM" => true)).to eq("BUNDLE_PATH__SYSTEM" => true)
+ expect(validate!("path", nil, "BUNDLE_PATH__SYSTEM" => false)).to eq("BUNDLE_PATH__SYSTEM" => false)
+ expect(validate!("path", nil, {})).to eq({})
+
+ expect(validate!("path.system", true, "BUNDLE_PATH" => "bundle")).to eq("BUNDLE_PATH__SYSTEM" => true)
+ expect(validate!("path.system", false, "BUNDLE_PATH" => "bundle")).to eq("BUNDLE_PATH" => "bundle", "BUNDLE_PATH__SYSTEM" => false)
+ expect(validate!("path.system", nil, "BUNDLE_PATH" => "bundle")).to eq("BUNDLE_PATH" => "bundle")
+ expect(validate!("path.system", true, {})).to eq("BUNDLE_PATH__SYSTEM" => true)
+ expect(validate!("path.system", false, {})).to eq("BUNDLE_PATH__SYSTEM" => false)
+ expect(validate!("path.system", nil, {})).to eq({})
+ end
+
+ it "a group cannot be in both `with` & `without` simultaneously" do
+ expect do
+ validate!("with", "", {})
+ validate!("with", nil, {})
+ validate!("with", "", "BUNDLE_WITHOUT" => "a")
+ validate!("with", nil, "BUNDLE_WITHOUT" => "a")
+ validate!("with", "b:c", "BUNDLE_WITHOUT" => "a")
+
+ validate!("without", "", {})
+ validate!("without", nil, {})
+ validate!("without", "", "BUNDLE_WITH" => "a")
+ validate!("without", nil, "BUNDLE_WITH" => "a")
+ validate!("without", "b:c", "BUNDLE_WITH" => "a")
+ end.not_to raise_error
+
+ expect { validate!("with", "b:c", "BUNDLE_WITHOUT" => "c:d") }.to raise_error Bundler::InvalidOption, strip_whitespace(<<-EOS).strip
+ Setting `with` to "b:c" failed:
+ - a group cannot be in both `with` & `without` simultaneously
+ - `without` is current set to [:c, :d]
+ - the `c` groups conflict
+ EOS
+
+ expect { validate!("without", "b:c", "BUNDLE_WITH" => "c:d") }.to raise_error Bundler::InvalidOption, strip_whitespace(<<-EOS).strip
+ Setting `without` to "b:c" failed:
+ - a group cannot be in both `with` & `without` simultaneously
+ - `with` is current set to [:c, :d]
+ - the `c` groups conflict
+ EOS
+ end
+ end
+
+ describe described_class::Rule do
+ let(:keys) { %w[key] }
+ let(:description) { "rule description" }
+ let(:validate) { proc { raise "validate called!" } }
+ subject(:rule) { described_class.new(keys, description, &validate) }
+
+ describe "#validate!" do
+ it "calls the block" do
+ expect { rule.validate!("key", nil, {}) }.to raise_error(RuntimeError, /validate called!/)
+ end
+ end
+
+ describe "#fail!" do
+ it "raises with a helpful message" do
+ expect { subject.fail!("key", "value", "reason1", "reason2") }.to raise_error Bundler::InvalidOption, strip_whitespace(<<-EOS).strip
+ Setting `key` to "value" failed:
+ - rule description
+ - reason1
+ - reason2
+ EOS
+ end
+ end
+
+ describe "#set" do
+ it "works when the value has not changed" do
+ allow(Bundler.ui).to receive(:info).never
+
+ subject.set({}, "key", nil)
+ subject.set({ "BUNDLE_KEY" => "value" }, "key", "value")
+ end
+
+ it "prints out when the value is changing" do
+ settings = {}
+
+ expect(Bundler.ui).to receive(:info).with("Setting `key` to \"value\", since rule description, reason1")
+ subject.set(settings, "key", "value", "reason1")
+ expect(settings).to eq("BUNDLE_KEY" => "value")
+
+ expect(Bundler.ui).to receive(:info).with("Setting `key` to \"value2\", since rule description, reason2")
+ subject.set(settings, "key", "value2", "reason2")
+ expect(settings).to eq("BUNDLE_KEY" => "value2")
+
+ expect(Bundler.ui).to receive(:info).with("Setting `key` to nil, since rule description, reason3")
+ subject.set(settings, "key", nil, "reason3")
+ expect(settings).to eq({})
+ end
+ end
+ end
+end
diff --git a/spec/cache/gems_spec.rb b/spec/cache/gems_spec.rb
index aef4c5f05a..4a0b953830 100644
--- a/spec/cache/gems_spec.rb
+++ b/spec/cache/gems_spec.rb
@@ -1,14 +1,14 @@
# frozen_string_literal: true
RSpec.describe "bundle cache" do
- describe "when there are only gemsources" do
+ shared_examples_for "when there are only gemsources" do
before :each do
gemfile <<-G
gem 'rack'
G
- system_gems "rack-1.0.0"
- bundle :cache
+ system_gems "rack-1.0.0", :path => :bundle_path
+ bundle! :cache
end
it "copies the .gem file to vendor/cache" do
@@ -27,7 +27,7 @@ RSpec.describe "bundle cache" do
end
it "uses the cache as a source when installing gems with --local" do
- system_gems []
+ system_gems [], :path => :bundle_path
bundle "install --local"
expect(the_bundle).to include_gems("rack 1.0.0")
@@ -46,7 +46,7 @@ RSpec.describe "bundle cache" do
end
it "does not reinstall gems from the cache if they exist in the bundle" do
- system_gems "rack-1.0.0"
+ system_gems "rack-1.0.0", :path => :bundle_path
gemfile <<-G
gem "rack"
@@ -56,7 +56,7 @@ RSpec.describe "bundle cache" do
s.write "lib/rack.rb", "RACK = 'FAIL'"
end
- bundle "install --local"
+ bundle! :install, :local => true
expect(the_bundle).to include_gems("rack 1.0.0")
end
@@ -73,6 +73,16 @@ RSpec.describe "bundle cache" do
end
end
+ context "using system gems" do
+ before { bundle! "config path.system true" }
+ it_behaves_like "when there are only gemsources"
+ end
+
+ context "installing into a local path" do
+ before { bundle! "config path ./.bundle" }
+ it_behaves_like "when there are only gemsources"
+ end
+
describe "when there is a built-in gem", :ruby => "2.0" do
before :each do
build_repo2 do
@@ -86,7 +96,8 @@ RSpec.describe "bundle cache" do
FileUtils.rm("#{system_gem_path}/cache/builtin_gem-1.0.2.gem")
end
- it "uses builtin gems" do
+ it "uses builtin gems when installing to system gems" do
+ bundle! "config path.system true"
install_gemfile %(gem 'builtin_gem', '1.0.2')
expect(the_bundle).to include_gems("builtin_gem 1.0.2")
end
@@ -118,6 +129,8 @@ RSpec.describe "bundle cache" do
end
it "errors if the builtin gem isn't available to cache" do
+ bundle! "config path.system true"
+
install_gemfile <<-G
gem 'builtin_gem', '1.0.2'
G
diff --git a/spec/commands/check_spec.rb b/spec/commands/check_spec.rb
index 3c25a8e8c8..f2af446fbf 100644
--- a/spec/commands/check_spec.rb
+++ b/spec/commands/check_spec.rb
@@ -137,8 +137,6 @@ RSpec.describe "bundle check" do
end
it "ignores missing gems restricted to other platforms" do
- system_gems "rack-1.0.0"
-
gemfile <<-G
source "file://#{gem_repo1}"
gem "rack"
@@ -147,6 +145,8 @@ RSpec.describe "bundle check" do
end
G
+ system_gems "rack-1.0.0", :path => :bundle_path
+
lockfile <<-G
GEM
remote: file:#{gem_repo1}/
@@ -168,8 +168,6 @@ RSpec.describe "bundle check" do
end
it "works with env conditionals" do
- system_gems "rack-1.0.0"
-
gemfile <<-G
source "file://#{gem_repo1}"
gem "rack"
@@ -178,6 +176,8 @@ RSpec.describe "bundle check" do
end
G
+ system_gems "rack-1.0.0", :path => :bundle_path
+
lockfile <<-G
GEM
remote: file:#{gem_repo1}/
diff --git a/spec/commands/clean_spec.rb b/spec/commands/clean_spec.rb
index e1febcbd4e..9be8f24fda 100644
--- a/spec/commands/clean_spec.rb
+++ b/spec/commands/clean_spec.rb
@@ -275,6 +275,7 @@ RSpec.describe "bundle clean" do
end
it "displays an error when used without --path" do
+ bundle! "config path.system true"
install_gemfile <<-G
source "file://#{gem_repo1}"
@@ -318,24 +319,27 @@ RSpec.describe "bundle clean" do
end
it "does not call clean automatically when using system gems" do
- gemfile <<-G
+ bundle! "config path.system true"
+
+ bundle! :config
+
+ install_gemfile! <<-G
source "file://#{gem_repo1}"
gem "thin"
gem "rack"
G
- bundle :install
- gemfile <<-G
+ bundle! "info thin"
+
+ install_gemfile! <<-G
source "file://#{gem_repo1}"
gem "rack"
G
- bundle :install
- sys_exec "gem list"
- expect(out).to include("rack (1.0.0)")
- expect(out).to include("thin (1.0)")
+ sys_exec! "gem list"
+ expect(out).to include("rack (1.0.0)").and include("thin (1.0)")
end
it "--clean should override the bundle setting on install", :bundler => "< 2" do
@@ -416,6 +420,8 @@ RSpec.describe "bundle clean" do
end
it "does not clean on bundle update when using --system" do
+ bundle! "config path.system true"
+
build_repo2
gemfile <<-G
@@ -435,6 +441,8 @@ RSpec.describe "bundle clean" do
end
it "cleans system gems when --force is used" do
+ bundle! "config path.system true"
+
gemfile <<-G
source "file://#{gem_repo1}"
@@ -458,8 +466,10 @@ RSpec.describe "bundle clean" do
end
describe "when missing permissions" do
+ before { ENV["BUNDLE_PATH__SYSTEM"] = "true" }
+ let(:system_cache_path) { system_gem_path("cache") }
after do
- FileUtils.chmod(0o755, default_bundle_path("cache"))
+ FileUtils.chmod(0o755, system_cache_path)
end
it "returns a helpful error message" do
gemfile <<-G
@@ -477,7 +487,6 @@ RSpec.describe "bundle clean" do
G
bundle :install
- system_cache_path = default_bundle_path("cache")
FileUtils.chmod(0o500, system_cache_path)
bundle :clean, :force => true
@@ -522,6 +531,8 @@ RSpec.describe "bundle clean" do
end
it "when using --force on system gems, it doesn't remove binaries" do
+ bundle! "config path.system true"
+
build_repo2
update_repo2 do
build_gem "bindir" do |s|
diff --git a/spec/commands/doctor_spec.rb b/spec/commands/doctor_spec.rb
index e1fa98b3d3..2572d4ff4d 100644
--- a/spec/commands/doctor_spec.rb
+++ b/spec/commands/doctor_spec.rb
@@ -17,45 +17,42 @@ RSpec.describe "bundle doctor" do
end
it "exits with no message if the installed gem has no C extensions" do
- gemfile <<-G
+ install_gemfile! <<-G
source "file://#{gem_repo1}"
gem "rack"
G
- bundle :install
- Bundler::CLI::Doctor.new({}).run
+ expect { Bundler::CLI::Doctor.new({}).run }.not_to raise_error
expect(@stdout.string).to be_empty
end
it "exits with no message if the installed gem's C extension dylib breakage is fine" do
- gemfile <<-G
+ install_gemfile! <<-G
source "file://#{gem_repo1}"
gem "rack"
G
- bundle :install
doctor = Bundler::CLI::Doctor.new({})
expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/rack/rack.bundle"]
expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/lib/libSystem.dylib"]
allow(File).to receive(:exist?).and_call_original
allow(File).to receive(:exist?).with("/usr/lib/libSystem.dylib").and_return(true)
- doctor.run
+ expect { doctor.run }.not_to(raise_error, @stdout.string)
expect(@stdout.string).to be_empty
end
it "exits with a message if one of the linked libraries is missing" do
- gemfile <<-G
+ install_gemfile! <<-G
source "file://#{gem_repo1}"
gem "rack"
G
- bundle :install
doctor = Bundler::CLI::Doctor.new({})
expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/rack/rack.bundle"]
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 Bundler::ProductionError, strip_whitespace(<<-E).strip
+ expect { doctor.run }.to raise_error(Bundler::ProductionError, strip_whitespace(<<-E).strip), @stdout.string
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
diff --git a/spec/commands/exec_spec.rb b/spec/commands/exec_spec.rb
index 8acc00fc91..bcc436d39b 100644
--- a/spec/commands/exec_spec.rb
+++ b/spec/commands/exec_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe "bundle exec" do
let(:system_gems_to_install) { %w[rack-1.0.0 rack-0.9.1] }
before :each do
- system_gems(system_gems_to_install)
+ system_gems(system_gems_to_install, :path => :bundle_path)
end
it "activates the correct gem" do
diff --git a/spec/commands/install_spec.rb b/spec/commands/install_spec.rb
index fd825a374f..46ec7105a0 100644
--- a/spec/commands/install_spec.rb
+++ b/spec/commands/install_spec.rb
@@ -29,13 +29,23 @@ RSpec.describe "bundle install with gem sources" do
expect(bundled_app("Gemfile.lock")).to exist
end
- it "does not create ./.bundle by default" do
+ it "does not create ./.bundle by default", :bundler => "< 2" do
gemfile <<-G
source "file://#{gem_repo1}"
gem "rack"
G
- bundle :install # can't use install_gemfile since it sets retry
+ bundle! :install # can't use install_gemfile since it sets retry
+ expect(bundled_app(".bundle")).not_to exist
+ end
+
+ it "does not create ./.bundle by default when installing to system gems" do
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "rack"
+ G
+
+ bundle! :install, :env => { "BUNDLE_PATH__SYSTEM" => true } # can't use install_gemfile since it sets retry
expect(bundled_app(".bundle")).not_to exist
end
@@ -166,7 +176,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "does not reinstall any gem that is already available locally" do
- system_gems "activesupport-2.3.2"
+ system_gems "activesupport-2.3.2", :path => :bundle_path
build_repo2 do
build_gem "activesupport", "2.3.2" do |s|
@@ -183,7 +193,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "works when the gemfile specifies gems that only exist in the system" do
- build_gem "foo", :to_system => true
+ build_gem "foo", :to_bundle => true
install_gemfile <<-G
source "file://#{gem_repo1}"
gem "rack"
@@ -194,7 +204,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "prioritizes local gems over remote gems" do
- build_gem "rack", "1.0.0", :to_system => true do |s|
+ build_gem "rack", "1.0.0", :to_bundle => true do |s|
s.add_dependency "activesupport", "2.3.5"
end
diff --git a/spec/commands/newgem_spec.rb b/spec/commands/newgem_spec.rb
index d08a0c0c6b..8543989ca2 100644
--- a/spec/commands/newgem_spec.rb
+++ b/spec/commands/newgem_spec.rb
@@ -191,8 +191,6 @@ RSpec.describe "bundle gem" do
end
it "generates a valid gemspec" do
- system_gems ["rake-10.0.2"]
-
in_app_root
bundle "gem newgem --bin"
@@ -214,6 +212,7 @@ RSpec.describe "bundle gem" do
end
Dir.chdir(bundled_app("newgem")) do
+ system_gems ["rake-10.0.2"], :path => :bundle_path
bundle! "exec rake build"
end
diff --git a/spec/commands/show_spec.rb b/spec/commands/show_spec.rb
index 56d8b50a10..9b2648bf75 100644
--- a/spec/commands/show_spec.rb
+++ b/spec/commands/show_spec.rb
@@ -31,12 +31,12 @@ RSpec.describe "bundle show" do
end
it "warns if path no longer exists on disk" do
- FileUtils.rm_rf("#{system_gem_path}/gems/rails-2.3.2")
+ FileUtils.rm_rf(default_bundle_path("gems", "rails-2.3.2"))
bundle "show rails"
- expect(out).to match(/has been deleted/i)
- expect(out).to include(default_bundle_path("gems", "rails-2.3.2").to_s)
+ expect(out).to match(/has been deleted/i).
+ and include(default_bundle_path("gems", "rails-2.3.2").to_s)
end
it "prints the path to the running bundler" do
diff --git a/spec/install/allow_offline_install_spec.rb b/spec/install/allow_offline_install_spec.rb
index 6ef4a95df9..6b335e23d5 100644
--- a/spec/install/allow_offline_install_spec.rb
+++ b/spec/install/allow_offline_install_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe "bundle install with :allow_offline_install" do
context "with cached data locally" do
it "will install from the compact index" do
- system_gems ["rack-1.0.0"]
+ system_gems ["rack-1.0.0"], :path => :bundle_path
install_gemfile! <<-G, :artifice => "compact_index"
source "http://testgemserver.local"
diff --git a/spec/install/bundler_spec.rb b/spec/install/bundler_spec.rb
index b59096e1ea..fd7d44d664 100644
--- a/spec/install/bundler_spec.rb
+++ b/spec/install/bundler_spec.rb
@@ -125,15 +125,29 @@ RSpec.describe "bundle install" do
expect(last_command.bundler_err).to include(nice_error)
end
- it "can install dependencies with newer bundler version" do
- install_gemfile <<-G
+ it "can install dependencies with newer bundler version with system gems" do
+ bundle! "config path.system true"
+ install_gemfile! <<-G
+ source "file://#{gem_repo2}"
+ gem "rails", "3.0"
+ G
+
+ simulate_bundler_version "99999999.99.1"
+
+ bundle! "check"
+ expect(out).to include("The Gemfile's dependencies are satisfied")
+ end
+
+ it "can install dependencies with newer bundler version with a local path" do
+ bundle! "config path .bundle"
+ install_gemfile! <<-G
source "file://#{gem_repo2}"
gem "rails", "3.0"
G
simulate_bundler_version "99999999.99.1"
- bundle "check"
+ bundle! "check"
expect(out).to include("The Gemfile's dependencies are satisfied")
end
diff --git a/spec/install/gemfile/gemspec_spec.rb b/spec/install/gemfile/gemspec_spec.rb
index 2585f7106f..6ab974ee41 100644
--- a/spec/install/gemfile/gemspec_spec.rb
+++ b/spec/install/gemfile/gemspec_spec.rb
@@ -2,8 +2,10 @@
RSpec.describe "bundle install from an existing gemspec" do
before(:each) do
- build_gem "bar", :to_system => true
- build_gem "bar-dev", :to_system => true
+ build_repo2 do
+ build_gem "bar"
+ build_gem "bar-dev"
+ end
end
it "should install runtime and development dependencies" do
@@ -39,8 +41,10 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "should handle a list of requirements" do
- build_gem "baz", "1.0", :to_system => true
- build_gem "baz", "1.1", :to_system => true
+ update_repo2 do
+ build_gem "baz", "1.0"
+ build_gem "baz", "1.1"
+ end
build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("Gemfile", "source :rubygems\ngemspec")
@@ -169,7 +173,7 @@ RSpec.describe "bundle install from an existing gemspec" do
s.add_dependency "platform_specific"
end
- install_gem "platform_specific-1.0-java"
+ system_gems "platform_specific-1.0-java", :path => :bundle_path, :keep_path => true
install_gemfile! <<-G
gemspec :path => '#{tmp.join("foo")}'
@@ -192,6 +196,7 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "allows the gemspec to activate other gems" do
+ ENV["BUNDLE_PATH__SYSTEM"] = "true"
# see https://github.com/bundler/bundler/issues/5409
#
# issue was caused by rubygems having an unresolved gem during a require,
@@ -216,10 +221,10 @@ RSpec.describe "bundle install from an existing gemspec" do
s.version = "1.0.0"
s.add_dependency "bar", "= 1.0.0"
end
- build_gem "deps", :to_system => true do |s|
+ build_gem "deps", :to_bundle => true do |s|
s.add_dependency "foo", "= 0.0.1"
end
- build_gem "foo", "0.0.1", :to_system => true
+ build_gem "foo", "0.0.1", :to_bundle => true
install_gemfile <<-G
source "file://#{gem_repo2}"
@@ -235,7 +240,7 @@ RSpec.describe "bundle install from an existing gemspec" do
s.version = "1.0.0"
s.add_dependency "bar", "= 1.0.0"
end
- build_repo2 do
+ update_repo2 do
build_gem "deps" do |s|
s.add_dependency "foo", "= 0.0.1"
end
diff --git a/spec/install/gemfile/git_spec.rb b/spec/install/gemfile/git_spec.rb
index 71ef3c856f..a3e69325cc 100644
--- a/spec/install/gemfile/git_spec.rb
+++ b/spec/install/gemfile/git_spec.rb
@@ -287,7 +287,7 @@ RSpec.describe "bundle install with git sources" do
# ensure we also git fetch after cloning
bundle! :update, :all => bundle_update_requires_all?
- Dir.chdir(Dir[system_gem_path("cache/bundler/git/foo-*")].first) do
+ Dir.chdir(Dir[default_bundle_path("cache/bundler/git/foo-*")].first) do
sys_exec("git ls-remote .")
end
@@ -893,6 +893,7 @@ RSpec.describe "bundle install with git sources" do
it "prints a friendly error if a file blocks the git repo" do
build_git "foo"
+ FileUtils.mkdir_p(default_bundle_path)
FileUtils.touch(default_bundle_path("bundler"))
install_gemfile <<-G
@@ -1118,7 +1119,7 @@ RSpec.describe "bundle install with git sources" do
run! <<-R
puts $:.grep(/ext/)
R
- expect(out).to eq(Pathname.glob(system_gem_path("bundler/gems/extensions/**/foo-1.0-*")).first.to_s)
+ expect(out).to eq(Pathname.glob(default_bundle_path("bundler/gems/extensions/**/foo-1.0-*")).first.to_s)
end
it "does not use old extension after ref changes" do
diff --git a/spec/install/gemfile/groups_spec.rb b/spec/install/gemfile/groups_spec.rb
index dc55f1d8d3..19c379e188 100644
--- a/spec/install/gemfile/groups_spec.rb
+++ b/spec/install/gemfile/groups_spec.rb
@@ -192,7 +192,7 @@ RSpec.describe "bundle install with groups" do
expect(the_bundle).not_to include_gems "thin 1.0"
end
- it "does remove groups from without when passed at with" do
+ it "does remove groups from without when passed at --with", :bundler => "< 2" do
bundle :install, forgotten_command_line_options(:without => "emo")
bundle :install, forgotten_command_line_options(:with => "emo")
expect(the_bundle).to include_gems "activesupport 2.3.5"
@@ -211,12 +211,12 @@ RSpec.describe "bundle install with groups" do
end
it "allows the BUNDLE_WITH setting to override BUNDLE_WITHOUT" do
- bundle! "config --local with debugging"
+ ENV["BUNDLE_WITH"] = "debugging"
bundle! :install
expect(the_bundle).to include_gem "thin 1.0"
- bundle! "config --local without debugging"
+ ENV["BUNDLE_WITHOUT"] = "debugging"
expect(the_bundle).to include_gem "thin 1.0"
bundle! :install
diff --git a/spec/install/gemfile/sources_spec.rb b/spec/install/gemfile/sources_spec.rb
index 6afe8bda59..0b837f87a1 100644
--- a/spec/install/gemfile/sources_spec.rb
+++ b/spec/install/gemfile/sources_spec.rb
@@ -394,7 +394,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "with an existing lockfile" do
before do
- system_gems "rack-0.9.1", "rack-1.0.0"
+ system_gems "rack-0.9.1", "rack-1.0.0", :path => :bundle_path
lockfile <<-L
GEM
diff --git a/spec/install/gems/compact_index_spec.rb b/spec/install/gems/compact_index_spec.rb
index 6dadbd9fca..273366c32f 100644
--- a/spec/install/gems/compact_index_spec.rb
+++ b/spec/install/gems/compact_index_spec.rb
@@ -830,7 +830,7 @@ The checksum of /versions does not match the checksum provided by the server! So
and include("The checksum for the downloaded `rack-1.0.0.gem` does not match the checksum given by the server.").
and include("This means the contents of the downloaded gem is different from what was uploaded to the server, and could be a potential security issue.").
and include("To resolve this issue:").
- and include("1. delete the downloaded gem located at: `#{system_gem_path}/gems/rack-1.0.0/rack-1.0.0.gem`").
+ and include("1. delete the downloaded gem located at: `#{default_bundle_path}/gems/rack-1.0.0/rack-1.0.0.gem`").
and include("2. run `bundle install`").
and include("If you wish to continue installing the downloaded gem, and are certain it does not pose a security issue despite the mismatching checksum, do the following:").
and include("1. run `bundle config disable_checksum_validation true` to turn off checksum verification").
diff --git a/spec/install/gems/sudo_spec.rb b/spec/install/gems/sudo_spec.rb
index afcc33cc74..ae94eee9c6 100644
--- a/spec/install/gems/sudo_spec.rb
+++ b/spec/install/gems/sudo_spec.rb
@@ -4,6 +4,7 @@ RSpec.describe "when using sudo", :sudo => true do
describe "and BUNDLE_PATH is writable" do
context "but BUNDLE_PATH/build_info is not writable" do
before do
+ bundle! "config path.system true"
subdir = system_gem_path("cache")
subdir.mkpath
sudo "chmod u-w #{subdir}"
@@ -24,6 +25,7 @@ RSpec.describe "when using sudo", :sudo => true do
describe "and GEM_HOME is owned by root" do
before :each do
+ bundle! "config path.system true"
chown_system_gems_to_root
end
@@ -127,6 +129,7 @@ RSpec.describe "when using sudo", :sudo => true do
describe "and GEM_HOME is not writable" do
it "installs" do
+ bundle! "config path.system true"
gem_home = tmp("sudo_gem_home")
sudo "mkdir -p #{gem_home}"
sudo "chmod ugo-w #{gem_home}"
diff --git a/spec/install/gemspecs_spec.rb b/spec/install/gemspecs_spec.rb
index a404a556b7..0c1ed99097 100644
--- a/spec/install/gemspecs_spec.rb
+++ b/spec/install/gemspecs_spec.rb
@@ -33,8 +33,8 @@ RSpec.describe "bundle install" do
gem 'rack'
G
- FileUtils.mkdir_p "#{tmp}/gems/system/specifications"
- File.open("#{tmp}/gems/system/specifications/rack-1.0.0.gemspec", "w+") do |f|
+ FileUtils.mkdir_p "#{default_bundle_path}/specifications"
+ File.open("#{default_bundle_path}/specifications/rack-1.0.0.gemspec", "w+") do |f|
spec = Gem::Specification.new do |s|
s.name = "rack"
s.version = "1.0.0"
diff --git a/spec/install/path_spec.rb b/spec/install/path_spec.rb
index f3e17845e3..fb356899a6 100644
--- a/spec/install/path_spec.rb
+++ b/spec/install/path_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe "bundle install" do
Dir.chdir(dir) do
bundle! :install, forgotten_command_line_options(:path => "vendor/bundle")
- expect(out).to include("installed into ./vendor/bundle")
+ expect(out).to include("installed into `./vendor/bundle`")
end
dir.rmtree
@@ -32,7 +32,7 @@ RSpec.describe "bundle install" do
it "prints a warning to let the user know what has happened with bundle --path vendor/bundle" do
bundle! :install, forgotten_command_line_options(:path => "vendor/bundle")
- expect(out).to include("gems are installed into ./vendor")
+ expect(out).to include("gems are installed into `./vendor/bundle`")
end
it "disallows --path vendor/bundle --system", :bundler => "< 2" do
diff --git a/spec/install/post_bundle_message_spec.rb b/spec/install/post_bundle_message_spec.rb
index 248ef2166a..a953847bac 100644
--- a/spec/install/post_bundle_message_spec.rb
+++ b/spec/install/post_bundle_message_spec.rb
@@ -13,11 +13,13 @@ RSpec.describe "post bundle message" do
G
end
- let(:bundle_show_message) { "Use `bundle info [gemname]` to see where a bundled gem is installed." }
- let(:bundle_deployment_message) { "Bundled gems are installed into ./vendor" }
- let(:bundle_complete_message) { "Bundle complete!" }
- let(:bundle_updated_message) { "Bundle updated!" }
- let(:installed_gems_stats) { "4 Gemfile dependencies, 5 gems now installed." }
+ let(:bundle_path) { "./.bundle" }
+ let(:bundle_show_system_message) { "Use `bundle info [gemname]` to see where a bundled gem is installed." }
+ let(:bundle_show_path_message) { "Bundled gems are installed into `#{bundle_path}`" }
+ let(:bundle_complete_message) { "Bundle complete!" }
+ let(:bundle_updated_message) { "Bundle updated!" }
+ let(:installed_gems_stats) { "4 Gemfile dependencies, 5 gems now installed." }
+ let(:bundle_show_message) { Bundler::VERSION.split(".").first.to_i < 2 ? bundle_show_system_message : bundle_show_path_message }
describe "for fresh bundle install" do
it "without any options" do
@@ -53,44 +55,46 @@ RSpec.describe "post bundle message" do
end
describe "with --path and" do
+ let(:bundle_path) { "./vendor" }
+
it "without any options" do
bundle! :install, forgotten_command_line_options(:path => "vendor")
- expect(out).to include(bundle_deployment_message)
+ expect(out).to include(bundle_show_path_message)
expect(out).to_not include("Gems in the group")
expect(out).to include(bundle_complete_message)
end
it "with --without one group" do
bundle! :install, forgotten_command_line_options(:without => "emo", :path => "vendor")
- expect(out).to include(bundle_deployment_message)
+ expect(out).to include(bundle_show_path_message)
expect(out).to include("Gems in the group emo were not installed")
expect(out).to include(bundle_complete_message)
end
it "with --without two groups" do
bundle! :install, forgotten_command_line_options(:without => "emo test", :path => "vendor")
- expect(out).to include(bundle_deployment_message)
+ expect(out).to include(bundle_show_path_message)
expect(out).to include("Gems in the groups emo and test were not installed")
expect(out).to include(bundle_complete_message)
end
it "with --without more groups" do
bundle! :install, forgotten_command_line_options(:without => "emo obama test", :path => "vendor")
- expect(out).to include(bundle_deployment_message)
+ expect(out).to include(bundle_show_path_message)
expect(out).to include("Gems in the groups emo, obama and test were not installed")
expect(out).to include(bundle_complete_message)
end
it "with an absolute --path inside the cwd" do
bundle! :install, forgotten_command_line_options(:path => bundled_app("cache"))
- expect(out).to include("Bundled gems are installed into ./cache")
+ expect(out).to include("Bundled gems are installed into `./cache`")
expect(out).to_not include("Gems in the group")
expect(out).to include(bundle_complete_message)
end
it "with an absolute --path outside the cwd" do
bundle! :install, forgotten_command_line_options(:path => tmp("not_bundled_app"))
- expect(out).to include("Bundled gems are installed into #{tmp("not_bundled_app")}")
+ expect(out).to include("Bundled gems are installed into `#{tmp("not_bundled_app")}`")
expect(out).to_not include("Gems in the group")
expect(out).to include(bundle_complete_message)
end
diff --git a/spec/install/process_lock_spec.rb b/spec/install/process_lock_spec.rb
index 113fd37934..02217f493b 100644
--- a/spec/install/process_lock_spec.rb
+++ b/spec/install/process_lock_spec.rb
@@ -2,6 +2,8 @@
RSpec.describe "process lock spec" do
describe "when an install operation is already holding a process lock" do
+ before { FileUtils.mkdir_p(default_bundle_path) }
+
it "will not run a second concurrent bundle install until the lock is released" do
thread = Thread.new do
Bundler::ProcessLock.lock(default_bundle_path) do
diff --git a/spec/other/platform_spec.rb b/spec/other/platform_spec.rb
index 7b0c71311f..63831c89b6 100644
--- a/spec/other/platform_spec.rb
+++ b/spec/other/platform_spec.rb
@@ -595,7 +595,7 @@ G
end
it "prints path if ruby version is correct" do
- gemfile <<-G
+ install_gemfile! <<-G
source "file://#{gem_repo1}"
gem "rails"
@@ -608,7 +608,7 @@ G
it "prints path if ruby version is correct for any engine" do
simulate_ruby_engine "jruby" do
- gemfile <<-G
+ install_gemfile! <<-G
source "file://#{gem_repo1}"
gem "rails"
@@ -676,11 +676,10 @@ G
context "bundle cache" do
before do
- gemfile <<-G
+ install_gemfile <<-G
+ source "file:#{gem_repo1}"
gem 'rack'
G
-
- system_gems "rack-1.0.0"
end
it "copies the .gem file to vendor/cache when ruby version matches" do
@@ -696,13 +695,14 @@ G
it "copies the .gem file to vendor/cache when ruby version matches for any engine" do
simulate_ruby_engine "jruby" do
- gemfile <<-G
+ install_gemfile! <<-G
+ source "file:#{gem_repo1}"
gem 'rack'
#{ruby_version_correct_engineless}
G
- bundle :cache
+ bundle! :cache
expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
end
@@ -757,11 +757,10 @@ G
context "bundle pack" do
before do
- gemfile <<-G
+ install_gemfile! <<-G
+ source "file:#{gem_repo1}"
gem 'rack'
G
-
- system_gems "rack-1.0.0"
end
it "copies the .gem file to vendor/cache when ruby version matches" do
@@ -777,7 +776,8 @@ G
it "copies the .gem file to vendor/cache when ruby version matches any engine" do
simulate_ruby_engine "jruby" do
- gemfile <<-G
+ install_gemfile! <<-G
+ source "file:#{gem_repo1}"
gem 'rack'
#{ruby_version_correct_engineless}
@@ -839,7 +839,7 @@ G
context "bundle exec" do
before do
ENV["BUNDLER_FORCE_TTY"] = "true"
- system_gems "rack-1.0.0", "rack-0.9.1"
+ system_gems "rack-1.0.0", "rack-0.9.1", :path => :bundle_path
end
it "activates the correct gem when ruby version matches" do
@@ -855,6 +855,7 @@ G
it "activates the correct gem when ruby version matches any engine" do
simulate_ruby_engine "jruby" do
+ system_gems "rack-1.0.0", "rack-0.9.1", :path => :bundle_path
gemfile <<-G
gem "rack", "0.9.1"
@@ -1179,6 +1180,7 @@ G
it "returns list of outdated gems when the ruby version matches for any engine" do
simulate_ruby_engine "jruby" do
+ bundle! :install
update_repo2 do
build_gem "activesupport", "3.0"
update_git "foo", :path => lib_path("foo")
diff --git a/spec/runtime/load_spec.rb b/spec/runtime/load_spec.rb
index 8f38e4fd04..b74dbde3f6 100644
--- a/spec/runtime/load_spec.rb
+++ b/spec/runtime/load_spec.rb
@@ -1,13 +1,9 @@
# frozen_string_literal: true
RSpec.describe "Bundler.load" do
- before :each do
- system_gems "rack-1.0.0"
- end
-
describe "with a gemfile" do
before(:each) do
- gemfile <<-G
+ install_gemfile! <<-G
source "file://#{gem_repo1}"
gem "rack"
G
@@ -35,6 +31,7 @@ RSpec.describe "Bundler.load" do
source "file://#{gem_repo1}"
gem "rack"
G
+ bundle! :install
end
it "provides a list of the env dependencies" do
@@ -76,13 +73,13 @@ RSpec.describe "Bundler.load" do
describe "when called twice" do
it "doesn't try to load the runtime twice" do
- system_gems "rack-1.0.0", "activesupport-2.3.5"
- gemfile <<-G
+ install_gemfile! <<-G
+ source "file:#{gem_repo1}"
gem "rack"
gem "activesupport", :group => :test
G
- ruby <<-RUBY
+ ruby! <<-RUBY
require "bundler"
Bundler.setup :default
Bundler.require :default
@@ -100,8 +97,8 @@ RSpec.describe "Bundler.load" do
describe "not hurting brittle rubygems" do
it "does not inject #source into the generated YAML of the gem specs" do
- system_gems "activerecord-2.3.2", "activesupport-2.3.2"
- gemfile <<-G
+ install_gemfile! <<-G
+ source "file:#{gem_repo1}"
gem "activerecord"
G
diff --git a/spec/runtime/platform_spec.rb b/spec/runtime/platform_spec.rb
index 5160d602e0..f38f733845 100644
--- a/spec/runtime/platform_spec.rb
+++ b/spec/runtime/platform_spec.rb
@@ -48,10 +48,8 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
nokogiri
G
- system_gems "nokogiri-1.4.2"
-
simulate_platform "x86-darwin-10"
- gemfile <<-G
+ install_gemfile! <<-G
source "file://#{gem_repo1}"
gem "nokogiri"
G
@@ -77,9 +75,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
simulate_platform "x86-darwin-100"
- system_gems "nokogiri-1.4.2", "platform_specific-1.0-x86-darwin-100"
-
- gemfile <<-G
+ install_gemfile! <<-G
source "file://#{gem_repo1}"
gem "nokogiri"
gem "platform_specific"
diff --git a/spec/runtime/require_spec.rb b/spec/runtime/require_spec.rb
index 5dcbba5d06..3eccd60fba 100644
--- a/spec/runtime/require_spec.rb
+++ b/spec/runtime/require_spec.rb
@@ -314,7 +314,7 @@ RSpec.describe "Bundler.require" do
describe "a gem with different requires for different envs" do
before(:each) do
- build_gem "multi_gem", :to_system => true do |s|
+ build_gem "multi_gem", :to_bundle => true do |s|
s.write "lib/one.rb", "puts 'ONE'"
s.write "lib/two.rb", "puts 'TWO'"
end
@@ -355,7 +355,7 @@ RSpec.describe "Bundler.require" do
describe "with busted gems" do
it "should be busted" do
- build_gem "busted_require", :to_system => true do |s|
+ build_gem "busted_require", :to_bundle => true do |s|
s.write "lib/busted_require.rb", "require 'no_such_file_omg'"
end
diff --git a/spec/runtime/setup_spec.rb b/spec/runtime/setup_spec.rb
index 3f95399c2b..0ea07c7b0a 100644
--- a/spec/runtime/setup_spec.rb
+++ b/spec/runtime/setup_spec.rb
@@ -116,7 +116,7 @@ RSpec.describe "Bundler.setup" do
tmp("rubygems/lib").to_s,
root.join("../lib").expand_path.to_s,
] - without_bundler_load_path
- lp.map! {|p| p.sub(/^#{system_gem_path}/, "") }
+ lp.map! {|p| p.sub(/^#{Regexp.union system_gem_path.to_s, default_bundle_path.to_s}/i, "") }
end
it "puts loaded gems after -I and RUBYLIB" do
@@ -787,7 +787,7 @@ end
G
run! "puts ENV['MANPATH']"
- expect(out).to eq("#{system_gem_path("gems/with_man-1.0/man")}:/foo")
+ expect(out).to eq("#{default_bundle_path("gems/with_man-1.0/man")}:/foo")
end
end
@@ -801,7 +801,7 @@ end
G
run! "puts ENV['MANPATH']"
- expect(out).to eq(system_gem_path("gems/with_man-1.0/man").to_s)
+ expect(out).to eq(default_bundle_path("gems/with_man-1.0/man").to_s)
end
end
end
@@ -995,6 +995,7 @@ end
describe "with system gems in the bundle" do
before :each do
+ bundle! "config path.system true"
system_gems "rack-1.0.0"
install_gemfile <<-G
@@ -1008,7 +1009,6 @@ end
run "puts Gem.path"
paths = out.split("\n")
expect(paths).to include(system_gem_path.to_s)
- expect(paths).to include(default_bundle_path.to_s)
end
end
@@ -1310,6 +1310,8 @@ end
end
end
+ default_gems.reject! {|g| exemptions.include?(g) }
+
install_gemfile! <<-G
source "file:#{gem_repo4}"
#{default_gems}.each do |g|
diff --git a/spec/support/builders.rb b/spec/support/builders.rb
index 6b15cffe5a..af91c5e6a7 100644
--- a/spec/support/builders.rb
+++ b/spec/support/builders.rb
@@ -718,18 +718,21 @@ module Spec
class GemBuilder < LibBuilder
def _build(opts)
lib_path = super(opts.merge(:path => @context.tmp(".tmp/#{@spec.full_name}"), :no_default => opts[:no_default]))
+ destination = opts[:path] || _default_path
Dir.chdir(lib_path) do
- destination = opts[:path] || _default_path
FileUtils.mkdir_p(destination)
@spec.authors = ["that guy"] if !@spec.authors || @spec.authors.empty?
Bundler.rubygems.build(@spec, opts[:skip_validation])
- if opts[:to_system]
- `gem install --ignore-dependencies --no-ri --no-rdoc #{@spec.full_name}.gem`
- else
- FileUtils.mv("#{@spec.full_name}.gem", opts[:path] || _default_path)
- end
+ end
+ gem_path = File.expand_path("#{@spec.full_name}.gem", lib_path)
+ if opts[:to_system]
+ @context.system_gems gem_path, :keep_path => true
+ elsif opts[:to_bundle]
+ @context.system_gems gem_path, :path => :bundle_path, :keep_path => true
+ else
+ FileUtils.mv(gem_path, destination)
end
end
diff --git a/spec/support/helpers.rb b/spec/support/helpers.rb
index 312e47d546..a0b46bfad7 100644
--- a/spec/support/helpers.rb
+++ b/spec/support/helpers.rb
@@ -360,16 +360,32 @@ module Spec
end
def system_gems(*gems)
+ opts = gems.last.is_a?(Hash) ? gems.last : {}
+ path = opts.fetch(:path, system_gem_path)
+ if path == :bundle_path
+ path = ruby!(<<-RUBY)
+ require "bundler"
+ begin
+ puts Bundler.bundle_path
+ rescue Bundler::GemfileNotFound
+ ENV["BUNDLE_GEMFILE"] = "Gemfile"
+ retry
+ end
+
+ RUBY
+ end
gems = gems.flatten
- FileUtils.rm_rf(system_gem_path)
- FileUtils.mkdir_p(system_gem_path)
+ unless opts[:keep_path]
+ FileUtils.rm_rf(path)
+ FileUtils.mkdir_p(path)
+ end
Gem.clear_paths
env_backup = ENV.to_hash
- ENV["GEM_HOME"] = system_gem_path.to_s
- ENV["GEM_PATH"] = system_gem_path.to_s
+ ENV["GEM_HOME"] = path.to_s
+ ENV["GEM_PATH"] = path.to_s
ENV["BUNDLER_ORIG_GEM_PATH"] = nil
install_gems(*gems)
@@ -423,7 +439,7 @@ module Spec
def simulate_new_machine
system_gems []
- FileUtils.rm_rf default_bundle_path
+ FileUtils.rm_rf system_gem_path
FileUtils.rm_rf bundled_app(".bundle")
end
diff --git a/spec/support/path.rb b/spec/support/path.rb
index cc9c5b3cad..54fc03c850 100644
--- a/spec/support/path.rb
+++ b/spec/support/path.rb
@@ -17,7 +17,11 @@ module Spec
end
def default_bundle_path(*path)
- system_gem_path(*path)
+ if Bundler::VERSION.split(".").first.to_i < 2
+ system_gem_path(*path)
+ else
+ bundled_app(*[".bundle", ENV.fetch("BUNDLER_SPEC_RUBY_ENGINE", Gem.ruby_engine), Gem::ConfigMap[:ruby_version], *path].compact)
+ end
end
def bundled_app(*path)
diff --git a/spec/update/git_spec.rb b/spec/update/git_spec.rb
index b8f98ade27..95b0a95976 100644
--- a/spec/update/git_spec.rb
+++ b/spec/update/git_spec.rb
@@ -56,7 +56,7 @@ RSpec.describe "bundle update" do
it "floats on master when updating all gems that are pinned to the source even if you have child dependencies" do
build_git "foo", :path => lib_path("foo")
- build_gem "bar", :to_system => true do |s|
+ build_gem "bar", :to_bundle => true do |s|
s.add_dependency "foo"
end
@@ -117,7 +117,7 @@ RSpec.describe "bundle update" do
describe "with submodules" do
before :each do
- build_gem "submodule", :to_system => true do |s|
+ build_gem "submodule", :to_bundle => true do |s|
s.write "lib/submodule.rb", "puts 'GEM'"
end