How do I specify local .gem files in my Gemfile? - ruby

I have a couple of gem files which I install via gem install xx.gem. Can I tell Bundler to use them? Or do I have to specify the source path?

This isn't strictly an answer to your question about installing .gem packages, but you can specify all kinds of locations on a gem-by-gem basis by editing your Gemfile.
Specifying a :path attribute will install the gem from that path on your local machine.
gem "foreman", path: "/Users/pje/my_foreman_fork"
Alternately, specifying a :git attribute will install the gem from a remote git repository.
gem "foreman", git: "git://github.com/pje/foreman.git"
# ...or at a specific SHA-1 ref
gem "foreman", git: "git://github.com/pje/foreman.git", ref: "bf648a070c"
# ...or branch
gem "foreman", git: "git://github.com/pje/foreman.git", branch: "jruby"
# ...or tag
gem "foreman", git: "git://github.com/pje/foreman.git", tag: "v0.45.0"
(As #JHurrah mentioned in his comment.)

Seems bundler can't use .gem files out of the box. Pointing the :path to a directory containing .gem files doesn't work. Some people suggested to setup a local gem server (geminabox, stickler) for that purpose.
However, what I found to be much simpler is to use a local gem "server" from file system:
Just put your .gem files in a local directory, then use "gem generate_index" to make it a Gem repository
mkdir repo
mkdir repo/gems
cp *.gem repo/gems
cd repo
gem generate_index
Finally point bundler to this location by adding the following line to your Gemfile
source "file://path/to/repo"
If you update the gems in the repository, make sure to regenerate the index.

I would unpack your gem in the application vendor folder
gem unpack your.gem --target /path_to_app/vendor/gems/
Then add the path on the Gemfile to link unpacked gem.
gem 'your', '2.0.1', :path => 'vendor/gems/your'

By default Bundler will check your system first and if it can't find a gem it will use the sources specified in your Gemfile.

You can force bundler to use the gems you deploy using "bundle package" and "bundle install --local"
On your development machine:
bundle install
(Installs required gems and makes Gemfile.lock)
bundle package
(Caches the gems in vendor/cache)
On the server:
bundle install --local
(--local means "use the gems from vendor/cache")

Adding .gem to vendor/cache seems to work. No options required in Gemfile.

I found it easiest to run my own gem server using geminabox
See these simple instructions.

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.

How could I install Gems from git repositories?

I need to install gem form git repository. repository contains .gemspec file. In my gem file i have following code:
gem 'echo_server', :git => 'http://127.0.0.1/org/echo_server.git'
When i am running bundle install gems are installer in .bundeler and not showing in gem list.
my question is:
How the gem will be available in system, so that i can use in require ?
There are some similar SOQ but it does't help me.
It is not showing up when you type gem list because it is not being installed like a regular gem. You can require it like you would any other library because Bundler knows about it and will set it up for you. You should see it in your $LOAD_PATH:
$LOAD_PATH.grep(/nameofgem/)
See the Bundler documentation on this for more information.
If instead you want to install it as a regular gem from the Git repository, you can clone the repository and then build and install the generated gem. For example:
gem build echo_server.gemspec
gem install echo_server-X.Y.Z.gem
There is also specific_install.

Is it possible to bundle / install gems from a local cache?

I have bunch of gems on my computer that I want to use in a chef recipe.
I know it is possible to put them in a directory like /tmp/gems and just:
cd /tmp/gems
gem install *.gem
Is it possible to put all gems in one directory where I can install them with bundler without downloading them again?
cd /somedir/my_rails_project
bundle
I want to save bandwidth.
bundle install --local should be what you want. From the bundle-install manpage:
--local
Do not attempt to connect to rubygems.org, instead using just the
gems located in vendor/cache. Note that if a more appropriate
platform-specific gem exists on rubygems.org, this will bypass
the normal lookup.
You can add local directories to your Gemfile (example from the docs):
gem "nokogiri", :path => "~/sw/gems/nokogiri"
Alternatively, you can set up a local Git repository with the gems in it and write a Gemfile like this:
gem "gem1", :git => "file:///tmp/gems",
:branch => "gem1"
Use
bundle package
Locks and then caches the gems into ./vendor/cache.
The package command will copy the .gem files for your gems in the
bundle into ./vendor/cache. Afterward, when you run bundle install,
Bundler will use the gems in the cache in preference to the ones on
rubygems.org.
http://bundler.io/v1.6/bundle_package.html
You can use the BUNDLE_CACHE_PATH configuration key:
cache_path (BUNDLE_CACHE_PATH): The directory that bundler will place cached gems in when running bundle package, and that bundler will look in when installing gems. Defaults to vendor/bundle.
Source: https://bundler.io/v1.16/bundle_config.html#LIST-OF-AVAILABLE-KEYS
In GitLab CI, I defined this value in the environment of runners: "BUNDLE_CACHE_PATH=/cache-ci/bundle", this directory is mounted automatically in CI runners.
Then bundle install will install gems from the cache directory (once cache will be populated).
If you want to use a local cache for the purpose of speeding up bundle install on CI, for example when a docker container is used to run the tests, you could use --path. This will use gems in the given path unless they are not present, otherwise it will download them to that location.
This assumes the CI build can mount a persistent volume inside the docker container. So for example if the CI machine has a directory /var/cache/drone which can be mounted in the docker container as ./cache then you can do:
bundle install --without=development --quiet --path=cache

Using bundler with "--path vendor", why are gems specified with ":git" not locally vendored?

I'm using bundler and have a Gemfile that looks like this:
source 'http://rubygems.org'
gem 'sinatra', '1.3.1'
gem 'httparty'
# ...etc...
gem 'my_custom_gem', :git => 'git#github.com:me/my_custom_gem.git'
When I run bundle install it fetches the necessary gems, including my custom gem, and installs them in the system gem directory. So far, so good. However, an issue arises when I try to vendor them into a project-local directory. When I run
bundle install --path vendor
It creates the "vendor" directory in my project root and installs all the regular gems there. So I see directories like
vendor/ruby/1.8/gems/sinatra-1.3.1
vendor/ruby/1.8/gems/httparty-0.8.1
...etc...
But it does not vendor the gem specified with a 'git' parameter. I expect to see but do not see anything like
vendor/ruby/1.8/gems/my_custom_gem-1.0.0
It continues to use the system-installed version of this gem. Any explanation for this? Any clean way to get this custom gem vendored as well?
Not supported right now, hopefully coming in Bundler 1.1:
https://github.com/carlhuda/bundler/issues/67
For now you'll have to do:
cd vendor/ruby/1.8/gems/
git clone git://github.com/foo/foo.git
or similar

Bundling local gem (that I'm developing) does not seem to include lib directory (using rvm)

I'm trying to develop a gem locally, and have installed it with Bundler.
My Gemfile looks like this:
source "http://rubygems.org"
gemspec
And my gemspec is a standard gemspec file.
I can install the gem with 'bundle install' in the directory, and i see the local gem and all it's dependencies install:
bundle install
Using rack (1.3.4)
Using tilt (1.3.3)
Using sinatra (1.3.1)
Using {my gem} (0.0.2) from source at .
Using bundler (1.0.21)
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
However, when I do a 'gem list', my gem is not included in the list of gems - which is my guess as to why my bin directory does not appear in the path. Is there a way to test a local gem and include it in the list of installed gems using bundler, so that the bin directory properly works?
Easiest way to get rid of bundler: command not found: {your bin executable}:
git add bin/* # git-ls-files will now list your bin executables.
bundle install
# No git-commit necessary.
bundle exec <MY_BIN_EXECUTABLE>
gem list shows your system installed gems, not the gems in your Bundle (this are often the same but not always--as in this case). When you're using Bundler, you should always execute gem executables with bundle exec so that Bundler can set up the environment for you. So, if you have a binary called, for example, mygem, you should use bundle exec mygem.
See more info at Bundler's site or in the manpage.
[Edit]
Also be sure that your gemspec includes a bin directory! Common convention is to create a directory called bin at the same level as your lib directory, put your binaries in there, and then add this as the directory in your gemspec. If you don't do this, Bundler won't expose your binaries!
I had this problem too.
Make sure the executables and default_executable lines don't contain 'bin/'. Then:
git add add . # You can be more precice if you want.
git commit -m "My lousy commit message."
bundle install
bundle exec <binaryname>

Resources