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."
Related
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.
I am working on a new Ruby Gem. I am familiar with using Bundler to manage gems:
source "https://rubygems.org"
gemspec
gem 'rspec-rails'
I am familiar with specifying dependencies in a gemspec file:
Gem::Specification.new do |s|
# ...
s.add_dependency "rails", "~> 4.1.5"
end
The Gemfile that was generated mentions that I should move my dependency declarations from my Gemfile to my gemspec when I'm ready to release.
# Declare any dependencies that are still in development here 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.
Why would I want to do this? Why should my gemspec care what gems I'm using in development? What purpose does development_dependency serve that Bundler doesn't already do for me?
To best answer your questions, we should first untangle the concepts of Bundler and Rubygems. I think a great explanation can be found here.
Why Would I Want to [move dependencies from Gemfile to .gemspec]?
Gemfile allows you to specify not only dependencies, but where the dependencies come from. This is useful when you are also working on the dependencies themselves and need to point to a Git repo (or something).
Once work on these dependencies is complete, Rubygem conventions dictate that you move the dependency declaration on these released gems into your .gemspec file. Adding a line gemspec tells Bundler to read from this conventional Rubygems location. If you are working on a gem, and you are not actively developing the gem's dependencies, then all dependencies should be declared in your .gemspec
Why should my gemspec care what gems I'm using in development?
From the docs for add_development_dependency:
Development dependencies aren't installed by default and aren't activated when a gem is required.
A popular example for this Rspec. You should generally declare Rspec as a development dependency for yourself, but not force everyone else to download it when they grab your gem.
Note that the comment you cited does not say "development dependencies", it says "dependencies that are in development". Dependencies that are in development commonly include cutting-edge versions of gems that you are installing directly from a Git repo. RubyGems cannot install gems from a Git repo; however, Bundler can. If you are installing cutting-edge versions of gems installed from a source that RubyGems cannot handle (such as a VCS repo), you should list them in your Gemfile instead of the .gemspec file.
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?
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!
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