I want to set my Gemfile
to use all the exact versions from a working Gemfile.lock
.
What is the easiest way to do this?
I do not want to do it manually. Does bundler
do this out of the box. If not, is there a gem for this?
To clarify, I have a Gemfile
like this:
source 'https://rubygems.org'
gem 'pg'
gem 'puma'
gem 'rails'
I run bundle install
, and I get a Gemfile.lock
that works for me:
GEM
remote: https://rubygems.org/
specs:
pg (0.21.0)
puma (3.10.0)
rails (5.0.5)
actioncable (= 5.0.5)
actionmailer (= 5.0.5)
actionpack (= 5.0.5)
actionview (= 5.0.5)
activejob (= 5.0.5)
activemodel (= 5.0.5)
activerecord (= 5.0.5)
activesupport (= 5.0.5)
bundler (>= 1.3.0)
railties (= 5.0.5)
sprockets-rails (>= 2.0.0)
Now I want a command that updates my Gemfile
so that versions are specified:
source 'https://rubygems.org'
gem 'pg', '0.21.0'
gem 'puma', '3.10.0'
gem 'rails', '5.0.5'
If you are trying to reproduce your current Gemfile.lock
in the Gemfile
for another project, you can specify the exact version of your gems.
Let's assume that I have the following Gemfile
in my Rails App:
source 'https://rubygems.org'
gem 'pg', '~> 0.18'
gem 'puma', '~> 3.0'
gem 'rails', '~> 5.0.0', '>= 5.0.0.1'
It generates the following Gemfile.lock
:
GEM
remote: https://rubygems.org/
specs:
pg (0.21.0)
puma (3.10.0)
rails (5.0.5)
actioncable (= 5.0.5)
actionmailer (= 5.0.5)
actionpack (= 5.0.5)
actionview (= 5.0.5)
activejob (= 5.0.5)
activemodel (= 5.0.5)
activerecord (= 5.0.5)
activesupport (= 5.0.5)
bundler (>= 1.3.0)
railties (= 5.0.5)
sprockets-rails (>= 2.0.0)
If I want to reproduce exactly the same situation in a new project, I will create a Gemfile with exact versions:
source 'https://rubygems.org'
gem 'pg', '0.21.0'
gem 'puma', '3.10.0'
gem 'rails', '5.0.5'
and so on..
You can refer to bundler documentation
After you changed the focus of your question, it seems you are trying to create a Gemfile
from a Gemfile.lock
.
You could have a look at bundle --deployment. I saw several SO questions complaining about the output.
So, if it is not 100% satisfactory, you can use the Bundler::LockfileParser
and make your own script such as:
# test.rb
require 'bundler'
lockfile = Bundler::LockfileParser.new(Bundler.read_file('Gemfile.lock'))
specs = lockfile.specs
gems_hash = Hash.new.tap do |h|
specs.each do |s|
h[s.name] = {
spec: s,
dependencies: s.dependencies.map(&:name)
}
end
end
dependencies = gems_hash.keys && gems_hash.values.map { |h| h[:dependencies] }.flatten.uniq.sort
# Remove from the new Gemfile all gems installed as dependencies
dependencies.each { |dep| gems_hash.delete(dep) }
relevant_specs = gems_hash.values.map { |h| h[:spec] }
# I assume that by default you are installing from rubygems
puts "source 'https://rubygems.org'"
puts
relevant_specs.each do |s|
if s.source.to_s =~ /https:\/\/rubygems.org/
puts "gem '#{s.name}', '#{s.version}'" # eventually add "plaftform: :#{s.platform}"
# I consider as only alternative a git source.
elsif s.source.is_a?(Bundler::Source::Git)
uri = s.source.uri
branch = s.source.branch
ref = s.source.ref
puts
puts "git '#{uri}', branch: '#{branch}', ref: :#{ref} do"
puts " gem '#{s.name}'"
puts "end"
puts
end
end
puts
I created this gist for reading easily.
You can create then your Gemfile
by running:
$ ruby test.rb > Gemfile