summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThe Bundler Bot <bot@bundler.io>2017-09-18 04:26:44 +0000
committerColby Swandale <me@colby.fyi>2018-10-09 22:26:41 +1100
commitaad374a88a5d7bd8a5d5a458294a9a411b323016 (patch)
tree1a2a7dd2e55438f09839d8709c2b3cc166ba98c3
parentaf1e58a61e4d8c65e0c44bebef26cca9806c619c (diff)
downloadbundler-aad374a88a5d7bd8a5d5a458294a9a411b323016.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. (cherry picked from commit e6cc7a24d5ca9da842aeefd23167be4d850c9aa5)
-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 829dc5d949..f44b7b6d78 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -195,8 +195,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
@@ -211,10 +229,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 0aa13ab784..53f9806b73 100644
--- a/lib/bundler/plugin.rb
+++ b/lib/bundler/plugin.rb
@@ -81,8 +81,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
@@ -97,7 +97,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 611c5a4ef9..fe68d510ff 100644
--- a/lib/bundler/settings.rb
+++ b/lib/bundler/settings.rb
@@ -395,7 +395,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 40dc094885..2b9051a974 100644
--- a/spec/bundler/bundler_spec.rb
+++ b/spec/bundler/bundler_spec.rb
@@ -306,4 +306,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