chruby: A way to not set GEM_HOME if the installed ruby is under $HOME
I would like a way to tell chruby to not set $GEM_*
variables, as this is much safer (i.e., does not mix gems of different Ruby implementations) when e.g., developing TruffleRuby and executing two different Rubies without a chruby
in between (see https://github.com/postmodern/chruby/pull/410#issuecomment-515233038).
Currently I’m doing this by using a branch on my chruby fork, removing the code that sets GEM_HOME
, but that’s obviously not very convenient or maintainable, and I can’t easily advise other TruffleRuby developers to do the same. I’d much rather this was possible in chruby itself.
Actually, there is already a way to do this, by running everything as root
, but that’s obviously not very safe for my use-case.
So I’m thinking to just extend the check if (( UID != 0 )); then
to something like if (( UID != 0 )) && [ "$CHRUBY_SET_GEM_HOME" != "false" ]; then
.
We could also automatically just detect if $RUBY_ROOT
is under $HOME
and not set $GEM_*
vars in that case, but @postmodern had some concerns about that in https://github.com/postmodern/chruby/pull/410#issuecomment-515754740:
Furthermore, there is value in keeping user-installed gems separate from the ruby, in case you need to delete/re-install one or the other.
@postmodern @havenwood What do you think? I would like to have this available in chruby 1.0.0, I’m happy to make a PR.
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 21 (14 by maintainers)
As a compromise and to get the changes released faster, I am thinking of adding a separate
dev.sh
file which can be loaded along withchruby.sh
and that changes howGEM_HOME
/GEM_PATH
are set, in order to support testing rubies of the same version but with different configurations.As per @dentarg’s use case of wanting to switch between aarm64 and x86-64 on Apple Silicon, I could also add a
multi_arch.sh
file which takes into account the current architecture.Testing the same ruby version with different configurations or switching between aarch64 and x86-64 on specific hardware are niche use-cases vs. your more common Ruby app development. Providing opt-in solutions seems like a good compromise. Depending on whether these opt-in solutions become popular, they might become the default behavior in 1.0.0.
@eregon like we have discussed on multiple occasions, changing the path of the
GEM_HOME
is a breaking change and would cause chruby users to suddenly lose all of their installed gems after upgrading. Since chruby is widely used this would cause a great deal of confusion and frustration, so I decided to push that change back to 1.0.0 where we could safely break with backwards compatibility. Likewise, rubygems also has to maintain backwards compatibility and not change default behavior too much, otherwise that could possibly cause issues with downstream users and Linux distributions which expect gems to be installed into specific directories.I would have accepted #451, however I am very hesitant about adding additional bifurcating logic. I could envision scenarios where you are debugging an issue for a use and you need to determine if the gems are being installed into the correct location, so you then have to determine if the ruby’s gem directory is writable or not in order to determine if
chruby
is going to use the ruby’s gem dir or~/.gem/...
. This would likely result in more debugging, troubleshooting, and complexity.Since
chruby
is loaded into user’s shells, and because it has to run under Bash 3+ and Zsh, I have to be very cautious about changing any functionality and debate every change, especially those that might break or change default behavior for users. chruby also has an explicit policy of not accepting workaround fixes for upstream issues, which means I scrutinize issues and whether they could be better solved by rubygems or upstream Ruby. I also have to balance the needs of regular users vs the more exotic edge-cases which Ruby maintainers discover while testing Rubies. chruby is not an easy project to contribute to and requires a great deal of patience and compromising.I am now considering a different approach to handling
GEM_HOME
. Extracting the logic which setsGEM_HOME
andGEM_PATH
out as an additional function hook that could be overrode by additional opt-in configuration files much like howauto.sh
is implemented. Additionally, we could extract that logic entirely into an additionalgem_home.sh
file and make isolating gems in~/.gem/rubies/$ruby/
opt-in. This would provide an absolute bare minimum user experience of just switching the rubies, but not settingGEM_HOME
by default. This would work seamlessly for users who have all rubies installed into~/.rubies
; which means their ruby gem directories are writable by default. If theGEM_HOME
code is extracted entirely into an opt-ingems.sh
orgem_home.sh
file, and users have rubies installed into/opt/rubies
(such as myself) , those users would then need to decide if they want gem isolated in~/.gem/rubies/$ruby/
or allow rubygems to pick the gem installation directory for the user; this could potentially mean rubygems install gems of different/opt/rubies
rubies into~/.gem
, but maybe some users might want that? By moving the logic out into functions, this opens the door for customization and different opt-in configurations.Example Code
Sorry for not working on the 1.0.0 branch. I have been extremely busy over the last four-six years, with both commercial work (2014-2020) and other Open Source work (2020-2023). I will start working on 1.0.0 again; I just added relisting of rubies directories.
I have to disagree that multiple architechtures are niche use cases. there are searches for it all over the web since apple silicone and rosetta have become main staple development machines. it has become a necessity even for many
?? – I’m no truffleruby developer 😃 Just a developer doing things with Ruby.
I’ve been a devote and happy chruby user for 10 years (yes, since start almost), but sadly, I no longer recommend friends and co-workers to use the released version of chruby. I now recommend people using eregon’s branch. It would be great to change that.
I can verify that in my work on the YJIT team, and especially for speed.yjit.org, we have difficulties when shared dirs contain built native extensions. We handle this by deleting all gems in all shared directories on every build, as well as all built Ruby dirs we’ll be using for that build. In general, my experience is that Rubygems/Bundler/etc deal poorly with trying to match up specific built native extensions to specific Rubies. So for benchmarking we use a Big Hammer to handle the situation: we delete everything, so there is clearly nothing stale or inappropriately shared.
This problem isn’t unique to chruby, though we do have it when using chruby. We’re a hard case - we build a lot of prerelease Rubies that all have the same version string, so RUBY_VERSION checking does nothing for us. We’re prone to get crashes, slowdowns and other problems very regularly if we leave built gems sitting around. So we basically treat shared-across-multiple-Rubies gem dirs as a bug, and delete their contents when there’s reason to care.
To preempt the same question: we do indeed work around the problem, by deleting everything. We need a fresh gem install of all native extensions for every build regardless, so saving old copies wouldn’t do us any good. If we wanted shorter runs that didn’t take multiple hours, or to reuse the same prerelease Ruby for multiple runs, we’d work around it by fiddling with dirs like GEM_HOME every time we changed versions. But if we need to manually manage our gem-related env vars every time we switch Rubies, chruby becomes a much less valuable tool.
That would be nice. The defaults needs to change though, because the current GEM_HOME/GEM_PATH set by chruby are incorrect for all dev Rubies, and all non-CRuby. In other words, it only works for CRuby releases, in the case they are always built with the same flags (e.g., --enable-shared) and arch for a given release version on the same machine. It also fails for CRuby releases on platforms with multiple archs as said in https://github.com/postmodern/chruby/issues/422#issuecomment-1232791999 and https://github.com/postmodern/ruby-install/issues/413#issuecomment-1244762132.
For instance:
chruby
(and notably Shopify devs). I believe that’s one of the main reasons why https://github.com/ruby/ruby/pull/5474 was added. I know at least @byroot, @peterzhu2118, @noahgibbs, and the YJIT team were affected by this.TruffleRuby already spent significant amount of effort to workaround this chruby bug. Notably there is an ABI check when loading C extensions, so at least it fails early.
What workaround are you thinking of? I don’t think truffleruby can workaround chruby setting the GEM_HOME incorrectly. Whoever sets the GEM_HOME is responsible to set it correctly (or not set it), so that’s chruby, isn’t it?
Due to this, I’ve been forced to switch to @eregon’s fork of chruby that have #431: https://github.com/eregon/chruby/tree/do-no-set-gem-home
It was needed because I have a computer with Apple silicon (M2), and I want to be able run Ruby apps either on arm64 or x86_64 (“Intel”).
Using ruby-build it was very easy to install Rubies for different architectures to different directories (and configure your shell for it), but I can’t have them install native extensions (like for Nokogiri) to the same directory (
GEM_HOME
)As an example, before switching to the chruby fork (using chruby 0.3.9 installed from Homebrew), I did
bundle install
for my app on arm64 (ruby 2.7.6p219 (2022-04-12 revision c9c2245c0a) [arm64-darwin21]
), then I also didbundle install
for it on Intel (ruby 2.7.6p219 (2022-04-12 revision c9c2245c0a) [x86_64-darwin21]
). When I tried to run my tests on arm64 I got this back:I know chruby 1.0.0 will bring changes to
GEM_HOME
(https://github.com/postmodern/chruby/pull/419) but I don’t think using basename is enough, as it will be the same basename regardless of the architecture.