Why bundler doesn't use system gems? - ruby

Bundler version: 1.15.1. Ruby version: 2.3.1.
I have (from gem env):
- GEM PATHS:
- /var/lib/gems/2.3.0
- /root/.gem/ruby/2.3.0
- /usr/lib/x86_64-linux-gnu/rubygems-integration/2.3.0
- /usr/share/rubygems-integration/2.3.0
- /usr/share/rubygems-integration/all
With all the gems from Gemfile.lock present under /var/lib/gems/2.3.0. But bundler will not try to re-use these and instead will attempt to redownload every time.
My .bundle/config:
---
BUNDLE_PATH: "vendor/bundle"
BUNDLE_BIN: "vendor/bin"
BUNDLE_DISABLE_SHARED_GEMS: "true" <--- removing this config entry doesn't help
running bundle install just re-downloads the gems instead of saying 'Using' so takes a long time.
What are the settings that might cause this and how to make the bundler get gems from system path /var/lib/gems/2.3.0?
I have read the bundle and bundle install docs fully but can't see how I can make bundler use the system gems. Other than using source 'file:///var/lib/gems/2.3.0' after generating an index, but I would really like to avoid this and use a more elegant solution. Especially since it would probably cause the gems to be re-installed which takes even more time than re-download.

You have set BUNDLE_DISABLE_SHARED_GEMS to true. This setting instructs bundler to specifically ignore any system-installed gems. Instead, bundler downloads all required gems into your BUNDLE_PATH.
If you want to use system-installed gems if appropriate, remove the BUNDLE_DISABLE_SHARED_GEMS setting from your bundle config.

Related

Cleaning gems from older gem version

I recently upgraded my distro (Ubuntu from 16.04 to 18.04), and I guess either on the upgrade or on the regular sudo update/upgrade calls gem was upgraded and I currently have the 2.7.6 version. I barely use Ruby lately, but just now I had to run a jekyll/bundle command which returned me that it had a bad interpreter (it was looking for ruby2.3 and it's currently installed on the 2.5 version).
My next step would be updating the jekyll and bundle gems (so they update the interpreter version), but to my surprise they aren't listed when I run gem list. They were obviously installed since there's a /usr/local/bin/jekyll executable and a /usr/local/bin/bundle one as well. But I think when gem was upgraded it started checking gems on a different folder (/var/lib/gems/2.5.0 I'm guessing) but jekyll/bundle apparently are in /var/lib/gems/2.3.0. I'd be fine just installing jekyll/bundle on the 2.5.0 version, but is there a way to remove all gem files from the older version since they are useless now?
I highly recommend you to use a ruby version manager like rvm or rbenv to manage different ruby versions installed on your system.
If you just want to remove the gems from your disk, you can find the location of each gem with the command bundle show $gem_name and delete the parent directory to delete all of them. You may need to delete the Gemfile.lock as well to reset the locked gem versions.
Here's what I recommend:
Use rbenv for multiple Ruby version management, no customizations needed
a ruby installer plugin is now included with rbenv
it also handles ruby executable shims automatically, don't need to rbenv rehash anymore
it loads really fast (rvm has a noticable load time on shell startup)
Use bundler to dynamically resolve gems at runtime (options below)
it's fast enough anyways
don't need a special gem solution, bundler comes included /w Ruby now
Options to invoke bundler dynamically (I recommend the last one):
use bundle exec in front of every ruby executable
variant: create alias be='bundle exec'
create bundle binstubs <LIST GEM EXECUTABLES YOU WANT> for each project
use bin/ in front of every ruby executable to call the binstubs
do #2 and then set up .git/safe
lets you manually allow PATH lookups to the bin/ folder while in that project root
don't need to type bin/ anymore
Now multiple gem versions will all be installed into the same Ruby version bucket, and you let bundler dynamically add the right versions to the load path before every startup.
Removing a Ruby version will also mean removing all the gems (and versions of those gems) installed for that Ruby version as well.
I'd like to thank both answers. I upvoted them because even though they're not a direct solution to my problem they give good directions to prevent it.
NOTE: These are the steps I took, which doesn't mean they are the correct way, so don't take more as a reference than a guide.
Here's what I did to clean up those old Ruby version gems:
First I needed to add an environment variable for gem to be able to find those obsolete gems, by running GEM_PATH=/var/lib/gems/2.3.0.
Then it's possible to get the contents and specification of the gems with gem contents name_of_gem and gem specification name_of_gem.
I individually uninstalled those gems that were obsolete with sudo GEM_PATH=/var/lib/gems/2.3.0 gem uninstall -i /var/lib/gems/2.3.0 name_of_gem. In my case I did a sudo install, so I needed sudo which also required me to set the environment variable again because of sudo's security policy. Also, I needed to manually set the install directory for some reason.
Some gems will have executables, and the uninstall will ask if you want to remove it. I wasn't able to get the gem uninstall to remove it because it claimed I didn't have write permission to /var/lib/gems/2.3.0/bin (which is weird because the EXECUTABLE DIRECTORY gem environment variable was /usr/local/bin). I asked gem not to remove the executables, wrote down their names and removed them manually from the EXECUTABLE DIRECTORY folder. You can also use which gem_executable_name to find out where it's located.
After uninstalling all the gems I believe it's safe to remove the /var/lib/gems/2.3.0 folder and its contents. Running gem contents on all of them only returned me files on this folder so I believe the only external files were the script/executables that were added to /usr/local/bin.

Can't install gem using Bundler's Rakefile install task when developing a custom gem

I'm developing a couple of private gems and I think I don't understand correctly the PATH/GEM_PATH and/or Bundler/RVM installation flow, would love if someone could chip in.
I have a repository with two gems (A & B for simplicity sake). I've developed the gems using the scaffolding + following the guidelines provided by this bundler tutorial.
Thanks to the Bundler project I have a few Rakefile tasks like rake build, rake install, rake install:local and rake release. Because of the private nature of these gems I can't release them to RubyGems (and we haven't looked into hosting our rubygems).
My machines are using RVM to manage ruby versions and Bundler version 1.15.1
What I want to do: Assuming a new machine/developer trying out the project, ideally we would cd into each of the subfolders (currently 2, gem A and gem B), run rake install and after that we should have the gems available system wide for the current user.
What is happening: The gems are built and work properly, but they are only available inside the subfolder of each gem i.e. gem A is only available inside the subfolder A and gem B is only available inside subfolder B.
What I've tried: So, after rake build/install/install:local a new .gem file is generated under pkg. I've tried to manually install the "compiled" file using gem install pkg/A.gem, gem install --local pkg/A.gem and gem install --local --user-install pkg/A.gem without success. (there are plenty of SO questions/answers about this)
I believe this has something to do with the PATH variables, but like I said before I don't fully understand the way they are managed. I get the following results from these commands:
# Our gem
> gem which A
/home/ubuntu/.rvm/gems/ruby-2.4.0/gems/A-0.1.8/lib/A.rb
# Pry, available globally
> gem which pry
/home/ubuntu/.rvm/gems/ruby-2.4.0/gems/pry-0.11.1/lib/pry.rb
I've been lost and frustrated for far too long now, any help is appreciated. Also open to hear suggestions of better private gem installation flows :)
Yes, it has something to do with your PATH variables. Your installation seems to be good.
I advise you to first affirm your gems installation path with:
echo $GEM_HOME
The double check your PATH to ensure its present and also confirm that the GEM home is also where the gem got installed into from the rake install
echo $PATH
If not, put it in your path and you should be fine with something like this:
echo PATH=$PATH:$GEM_HOME >> ~/.bashrc
source ~/.bashrc
Build your gem as per that guide you linked. You should end up with a gem file. Distribute this as you see fit (I use rsync/crontab to download newer gem versions but anything goes). User can install the gem as follows:
gem install --user-install /path/to/your/file.gem
This will install the gem in the user's ~/.gem/ruby/<version>/gems/<your-gem-name> directory.
Tried it with an empty gem (foodie, as in that example guide) and it works fine. But if you don't specify the --user-install parameter it will try to install in the system ruby dir (/usr/lib/ruby/gems...)

Bundler: using shared gem when it exists, rather than downloading from gem server

Say, I have Gemfile like following.
source "GEM_REPOSITORY"
gem 'gem_A'
# gem_A has no additional dependency
gem 'gem_B'
# gem_B depends on gem_B_1 and gem_B_2
When I run bundle install, I want Bundler to do the following.
If a gem already exists in "local system-wide gems", it copies the gem from local.
If a gem doesn't exist in local, it looks for GEM_REPOSITORY.
I looked for some related articles, and found some of likely-answers like
Ruby Bundler multiple sources in Gemfile
SOURCE PRIORITY
But none of the above looks like the answer for me.
Using source repository priority does't work. Because in the example above, if dependent gem (say, gem_B_1) exits in local but the target gem (gem_B) doesn't exist in local, it'll download both of above from the remote repository.
Are there any work around for doing this?
If not, don't you guys think it's necessary considering the cost of the implementation and the effect?
This is the current behavior.
When running gem install, directly or via bundle install, gem will first build a dependency graph with all the needed gems. If the gem is found locally it will use it, otherwise it will try to download it from the specified source.
If you want, try it yourself.
bundle gem gem_a
bundle gem gem_b
cd gem_a
vim gem_a.gemspec
add
spec.add_dependency 'multi_json', '~> 1.10.1'
or any dependency you want to the gem and run bundle install.
cd ../gem_b
vim Gemfile
and add
gem 'gem_a', path: '../gem_a'
then run
bundle install --verbose
you will see that the multi_json or whatever dependency of gem_a uses the local version and does not download anything.
This is of course also true for gems from remote sources.

rbenv clobbering my gem INSTALLATION DIRECTORY when using system

I want to use rbenv for setting ruby versions on a project per project basis. Otherwise, I want to use my default system ruby setup for everything else.
The problem I am having is the even though rbenv version returns system, gem command still uses the rbenv shim (.rbenv/shims/gem). So when I do gem environment my INSTALLATION DIRECTORY is '/Library/Ruby/Gems/1.8'. I would rather it remains ~/.gem/. I can see it still is that when I run /usr/bin/gem enviroment. I can't figure out where the rbenv shim gem is getting its settings from.
I've tried modifying my GEM_HOME both in my shell, and changing it in ~/.gemrc but that has no effect. I've been searching around with no luck. Hopefully someone here can help. Just some pointers to where the rbenv gem shim is pulling its values from would be helpful.
thanks
Since rbenv shims are pretty high in your PATH, their purpose is to intercept any invocation of ruby, gem, and similar, even if the currently selected Ruby version is "system". You shouldn't be worried about that.
Now, the default installation path for your system Ruby will always be /Library/Ruby/Gems/1.8. Here's my RBENV_VERSION=system gem env:
- GEM PATHS:
- /Library/Ruby/Gems/1.8
- /Users/mislav/.gem/ruby/1.8
- /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8
However, if you don't use sudo (and you shouldn't), gem install won't have write access to that directory, and will install the gems in the next writeable path, which is ~/.gem/ruby/1.8. That seems to be the behavior you want.

Bundler can't find Ruby gem that appears on website

I installed Bundler on a pre-Rails 3 application and am trying to use it to install gems. My Gemfile contains the following lines:
source :rubygems
[...]
gem "RubyInline", "3.8.1"
However, when I run bundle install I get this error:
Fetching source index for http://rubygems.org/
Could not find gem 'RubyInline', required by 'memcache-client (= 1.6.3)', in any of the sources
The gem appears on the rubygems website:
http://rubygems.org/gems/RubyInline
Why is it giving me an error then?
I'm afraid this resolved itself after changes to fix other issues, and I'm not sure what the fix was. The source of several other issues was wrong permissions on various gems/binaries.
This kind of issue for me seems to be resolved on occasion by applying
bundle update
before
bundle install
The effect is to resolve old dependencies from when the bundle was originally produced and hence a gem that has been superseded (or whatever) will no longer be in the Gemfile.

Resources