How to see the dependency tree just from Gemfile? - ruby

I am getting the following error when doing bundle install
Make sure that `gem install couchbase -v '1.3.3'` succeeds before bundling.
Now, i have not included this gem in the Gemfile, so it's coming from some dependency. How can i figure out which gem is dependent on this couchbase gem?
Since bundle install is failing and I don't have Gemfile.lock to figure out this dependency.

gem dependency (with no args) should show you all gems from current system with their dependencies.
bundle exec gem dependency will show you for the current Gemfile
Edit:
You can also do gem dependency -R (or just dep instead of dependency) if you want to find out which gems use specific (or all) gems.
For deeper dependencies I'd parse output (regex maybe?) of first gem dependencies, pick gem's names and call gem dep on each of them, but that's just a loose idea.

You can also use bundler to create a dependency graph.
Install graphviz:
gem install ruby-graphviz
and then:
bundle viz
Here are an example of a newly created Rails app:
You can also play with the options:
bundle help viz

Related

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.

Force Bundler to Use my Gem Source

I am running my own gem server with geminabox. This gem server hosts private forks of several public gems, as well as my own gems. I have a Gemfile with the sources listed like so:
source https://rubygems.org
source http://my/gem/server
When Bundler installs a bundle, I would like it to always use the version available on my gem server if it exists and satisfies the version requirements. I can't get this to work. Instead, bundler seems to pull from rubygems unless it can't find a gem with the same name there. This may be because the versions on rubygems are higher. However, bundler's documentation makes no mention of version numbers. This is how it describes source priority:
SOURCE PRIORITY
When attempting to locate a gem to satisfy a gem requirement, bundler uses the following priority order:
The source explicitly attached to the gem (using :path or :git)
For implicit gems (dependencies of explicit gems), any git or path repository otherwise declared. This results in bundler prioritizing the ActiveSupport gem from the Rails git repository over ones from rubygems.org
The sources specified via source, searching each source in your Gemfile from last added to first added.
Also, I know it is possible to explicitly list a source for each gem in the Gemfile. I would prefer to avoid this, since I have many of my own gems, and it is annoying to make explicit entries in the Gemfile for dependencies of dependencies (which you have to do, because bundler will not read the Gemfile of dependencies).
How can I achieve my goal?

Downloading dependencies for a private gem in vendor/cache

We have created a gem for internal use only which is not hosted on any server. It is distributed to teams as a gem file, who then add it to their "vendor/cache" folder, and use Bundler to add it as a dependency.
The gemspec file in the gem project stipulates the require dependencies for our internal gem, but is not downloading them when "Bundle install" is used. I assume this is because the list of dependencies is extracted from a call to the rubygems server rather than extracting from the Gem file itself?? If the dependencies are already in vendor/cache then all is fine.
Is there any way of instructing gem/bundler to get the list of dependencies from the gem itself rather than a server?
Is our only solution to create an internal Gem server?
bundle install looks for dependencies in a Gemfile and ignores the .gemspec.
According to Rails Engine documentation:
"Declare your gem's dependencies in clinkle_shared.gemspec. Bundler will treat runtime dependencies like base dependencies, and development dependencies will be added by default to the :development group.
Declare any dependencies that are still in development in a Gemfile instead of in your .gemspec. These might include edge Rails or gems from your path or Git. Remember to move these dependencies to your .gemspec before releasing your gem to rubygems.org."

Making a Ruby project that is not a gem (or some other kind)

I'm working on a project currently that I don't want to be a gem (or some other kind of project). How would I go about setting it up so that I can still have the same compatibility requirement abilities as a gem (e.g. Gemfile dependencies) but simultaneously not be a gem (or some other kind of project)?
You have to actually try to build a gem so this is easy!
to use bundler without Rails, a gem, whatever just create a directory
mkdir my-non-gem-project
cd my-non-gem-project
install bundler
gem install bundler
and initialize your Gemfile
bundle init
that will create a Gemfile for you and you can add to it and run bundle to install the dependencies from it
The simplest way to use bundler in your project would then be to open your main app file and add
require 'bundler/setup'
Bundler.require
This will require all of the gems you have in your Gemfile in the file this is added to. I am pretty sure that this file must be in the same directory as your Gemfile. More information here
Have fun with your Ruby project!

How to trace and check dependencies in bundled Ruby gems

Bundler will automatically install any dependencies for the specified gems, however it doesn't output which dependencies map to which gems in the standard output. That information is useful when one of the dependencies fails the installation.
Is there a way to set Bundler to be more verbose and inform about the dependencies while installing?
I am using Bundler 1.0.2
To see a visual representation of the dependency tree run bundle viz:
apt-get install graphviz && gem install ruby-graphviz && bundle viz
It will generate a PNG file of the tree.
A less exciting, but equally effective way is to just do:
gem dep
which will generate a Gemfile.lock style output with dependency information. You could pipe this output to less:
gem dep | less
Or, if you are searching for a failing dependency, you could grep it with some context. For instance, to find out where my failing Thin dependency was coming from (fails with JRuby), I did:
gem dep | grep -C 15 thin

Resources