summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThe Bundler Bot <bot@bundler.io>2017-09-18 04:26:44 +0000
committerThe Bundler Bot <bot@bundler.io>2017-09-18 04:26:44 +0000
commite6cc7a24d5ca9da842aeefd23167be4d850c9aa5 (patch)
treeb4708edbae7386963b66f7cbe9d6d17d7f93c846
parent4fc8fe968ff61ece41f5a74ebc117f84cf22f827 (diff)
parentb3108fac3f9ec1a85554790b9401ade370392b75 (diff)
downloadbundler-e6cc7a24d5ca9da842aeefd23167be4d850c9aa5.tar.gz
Auto merge of #6024 - gwerbin:custom-user-bundle-dir, r=colby-swandale
Allow user to override ~/.bundle with environment variables ### What was the end-user problem that led to this PR? As in #4333, users wanted a way to make Bundler respect the XDG specification. ### What was your diagnosis of the problem? The directory `~/.bundle` was hard-coded and could not be configured. ### What is your fix for the problem, implemented in this PR? Allow users to configure `~/.bundle` and its relevant sub-directories by setting environment variables. The environment variables and their fallbacks are as follows: | variable | fallback if unset | |---|---| | `BUNDLE_USER_HOME` | `$HOME/.bundle` | | `BUNDLE_USER_CACHE` | `$BUNDLE_USER_HOME/cache` | | `BUNDLE_USER_CONFIG` | `$BUNDLE_USER_HOME/config` | | `BUNDLE_USER_PLUGIN` | `$BUNDLE_USER_HOME/plugin` | ### Why did you choose this fix out of the possible options? Unlike https://github.com/bundler/bundler/pull/5787, This solution is not specific to the XDG specification. Users have all kinds of setups, and this is a very general system for allowing them to configure their development machines however they need. It tries to keep all files created by Bundler in the same place (as per https://github.com/bundler/bundler/pull/5787#issuecomment-310154273), but allows the user to override that convention _if they really want to and they know what they are doing_. If they want to use XDG for everything, they can do it by explicitly setting the `BUNDLE_USER_*` variables to the equivalent `XDG_DATA_*`. If they just want to get `.bundle` out of their home directory, they can do it by setting `BUNDLE_USER_HOME` and don't have to mess with the more specific env variables if they don't want to. To me, this solution strikes the right balance between "fine-grained control for power users" and "simple, sane defaults for everyone else". Please let me know if my tests can be improved. My only Ruby experience so far has been writing Homebrew formulas and configuring Jekyll, so I'm sure I have a lot to learn.
-rw-r--r--lib/bundler.rb26
-rw-r--r--lib/bundler/plugin.rb6
-rw-r--r--lib/bundler/settings.rb2
-rw-r--r--spec/bundler/bundler_spec.rb58
4 files changed, 82 insertions, 10 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb
index 81c6a5b594..6c942baf59 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -193,8 +193,26 @@ module Bundler
raise e.exception("#{warning}\nBundler also failed to create a temporary home directory at `#{path}':\n#{e}")
end
- def user_bundle_path
- Pathname.new(user_home).join(".bundle")
+ def user_bundle_path(dir = "home")
+ env_var, fallback = case dir
+ when "home"
+ ["BUNDLE_USER_HOME", Pathname.new(user_home).join(".bundle")]
+ when "cache"
+ ["BUNDLE_USER_CACHE", user_bundle_path.join("cache")]
+ when "config"
+ ["BUNDLE_USER_CONFIG", user_bundle_path.join("config")]
+ when "plugin"
+ ["BUNDLE_USER_PLUGIN", user_bundle_path.join("plugin")]
+ else
+ raise BundlerError, "Unknown user path requested: #{dir}"
+ end
+ # `fallback` will already be a Pathname, but Pathname.new() is
+ # idempotent so it's OK
+ Pathname.new(ENV.fetch(env_var, fallback))
+ end
+
+ def user_cache
+ user_bundle_path("cache")
end
def home
@@ -209,10 +227,6 @@ module Bundler
bundle_path.join("specifications")
end
- def user_cache
- user_bundle_path.join("cache")
- end
-
def root
@root ||= begin
SharedHelpers.root
diff --git a/lib/bundler/plugin.rb b/lib/bundler/plugin.rb
index 99c9a867b0..7db159c593 100644
--- a/lib/bundler/plugin.rb
+++ b/lib/bundler/plugin.rb
@@ -80,8 +80,8 @@ module Bundler
# The directory root for all plugin related data
#
- # Points to root in app_config_path if ran in an app else points to the one
- # in user_bundle_path
+ # If run in an app, points to local root, in app_config_path
+ # Otherwise, points to global root, in Bundler.user_bundle_path("plugin")
def root
@root ||= if SharedHelpers.in_bundle?
local_root
@@ -96,7 +96,7 @@ module Bundler
# The global directory root for all plugin related data
def global_root
- Bundler.user_bundle_path.join("plugin")
+ Bundler.user_bundle_path("plugin")
end
# The cache directory for plugin stuffs
diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb
index d9daba43f6..75e2d4dff2 100644
--- a/lib/bundler/settings.rb
+++ b/lib/bundler/settings.rb
@@ -393,7 +393,7 @@ module Bundler
Pathname.new(ENV["BUNDLE_CONFIG"])
else
begin
- Bundler.user_bundle_path.join("config")
+ Bundler.user_bundle_path("config")
rescue PermissionError, GenericSystemCallError
nil
end
diff --git a/spec/bundler/bundler_spec.rb b/spec/bundler/bundler_spec.rb
index 19e3f0336f..94d4096cd3 100644
--- a/spec/bundler/bundler_spec.rb
+++ b/spec/bundler/bundler_spec.rb
@@ -227,4 +227,62 @@ EOF
expect(Bundler.tmp_home_path("USER", "")).to eq(Pathname("/TMP/bundler/home/USER"))
end
end
+
+ context "user cache dir" do
+ let(:home_path) { Pathname.new(ENV["HOME"]) }
+
+ let(:xdg_data_home) { home_path.join(".local") }
+ let(:xdg_cache_home) { home_path.join(".cache") }
+ let(:xdg_config_home) { home_path.join(".config") }
+
+ let(:bundle_user_home_default) { home_path.join(".bundle") }
+ let(:bundle_user_home_custom) { xdg_data_home.join("bundle") }
+
+ let(:bundle_user_cache_default) { bundle_user_home_default.join("cache") }
+ let(:bundle_user_cache_custom) { xdg_cache_home.join("bundle") }
+
+ let(:bundle_user_config_default) { bundle_user_home_default.join("config") }
+ let(:bundle_user_config_custom) { xdg_config_home.join("bundle") }
+
+ let(:bundle_user_plugin_default) { bundle_user_home_default.join("plugin") }
+ let(:bundle_user_plugin_custom) { xdg_data_home.join("bundle").join("plugin") }
+
+ describe "#user_bundle_path" do
+ before do
+ allow(Bundler.rubygems).to receive(:user_home).and_return(home_path)
+ end
+
+ it "should use the default home path" do
+ expect(Bundler.user_bundle_path).to eq(bundle_user_home_default)
+ expect(Bundler.user_bundle_path("home")).to eq(bundle_user_home_default)
+ expect(Bundler.user_bundle_path("cache")).to eq(bundle_user_cache_default)
+ expect(Bundler.user_cache).to eq(bundle_user_cache_default)
+ expect(Bundler.user_bundle_path("config")).to eq(bundle_user_config_default)
+ expect(Bundler.user_bundle_path("plugin")).to eq(bundle_user_plugin_default)
+ end
+
+ it "should use custom home path as root for other paths" do
+ ENV["BUNDLE_USER_HOME"] = bundle_user_home_custom.to_s
+ expect(Bundler.user_bundle_path).to eq(bundle_user_home_custom)
+ expect(Bundler.user_bundle_path("home")).to eq(bundle_user_home_custom)
+ expect(Bundler.user_bundle_path("cache")).to eq(bundle_user_home_custom.join("cache"))
+ expect(Bundler.user_cache).to eq(bundle_user_home_custom.join("cache"))
+ expect(Bundler.user_bundle_path("config")).to eq(bundle_user_home_custom.join("config"))
+ expect(Bundler.user_bundle_path("plugin")).to eq(bundle_user_home_custom.join("plugin"))
+ end
+
+ it "should use all custom paths, except home" do
+ ENV.delete("BUNDLE_USER_HOME")
+ ENV["BUNDLE_USER_CACHE"] = bundle_user_cache_custom.to_s
+ ENV["BUNDLE_USER_CONFIG"] = bundle_user_config_custom.to_s
+ ENV["BUNDLE_USER_PLUGIN"] = bundle_user_plugin_custom.to_s
+ expect(Bundler.user_bundle_path).to eq(bundle_user_home_default)
+ expect(Bundler.user_bundle_path("home")).to eq(bundle_user_home_default)
+ expect(Bundler.user_bundle_path("cache")).to eq(bundle_user_cache_custom)
+ expect(Bundler.user_cache).to eq(bundle_user_cache_custom)
+ expect(Bundler.user_bundle_path("config")).to eq(bundle_user_config_custom)
+ expect(Bundler.user_bundle_path("plugin")).to eq(bundle_user_plugin_custom)
+ end
+ end
+ end
end