Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bundler works when .rb file called directly, fails when called via exec from other ruby script

I need to call a ruby script2.rb using Bundler + Gemfile from another ruby script1.rb using Bundler + Gemfile.

I noticed that the Gems available to script2.rb are only those of script1.rb. The gems unique to script2.rb are not available when script2.rb is called by script1.rb. When script2.rb is called directly from the bash shell, everything is available.

I made sure it's not an ENV problem, I compared them using diff with helper code like so in both files and made a couple modifications to make them match.

File.open("script2_env.txt", 'wb') {|f| f.write(JSON.pretty_generate(ENV.to_h))}

To make sure it was not a $LOAD_PATH problem, I also made sure they match.

In script2.rb, which is called by script1.rb, I added the following line to match the $LOAD_PATH of script1 :

$:.unshift "/usr/local/Cellar/rbenv/1.1.2/rbenv.d/exec/gem-rehash"

My understanding of the problem is that somehow Bundler is not initialized properly when script2.rb is called from script1.rb, maybe because there is no

eval "$(rbenv init -)"

as there is in my bash_profile

script1/script1.rb :

#!/usr/bin/env ruby
cwd=Dir.pwd ; ourDir=File.dirname(__FILE__) ; Dir.chdir(ourDir)
require 'bundler' ;  Bundler.setup
require "awesome_print"
ap "in script1, we have awesome_print in our GemFile"
exec("/Users/charbon/wip/script2/script2.rb")

script1/Gemfile

source 'https://rubygems.org'
gem 'awesome_print'

script2.rb :

#!/usr/bin/env ruby
puts "we are now in script2.rb"
$:.unshift "/usr/local/Cellar/rbenv/1.1.2/rbenv.d/exec/gem-rehash"
cwd=Dir.pwd ; ourDir=File.dirname(__FILE__) ; Dir.chdir(ourDir)

#make ENV match to script1 ENV
ENV.delete('BUNDLER_ORIG_GEM_PATH') 
ENV['BUNDLE_GEMFILE']=ourDir+"/Gemfile"
ENV['RBENV_DIR']=ourDir

require 'bundler' ;
Bundler.setup
require 'awesome_print'

ap "in script2, we also have awesome_print in our GemFile"
puts "but we also have colored, which is not available, this throws an erro"
require "colored"

script2/Gemfile

source 'https://rubygems.org'
gem 'awesome_print'
gem 'colored'

The result is

 /Users/charbon/wip/script1/script1.rb 
"in script1, we have awesome_print in our GemFile"
we are now in script2.rb
ourDir is /Users/charbon/wip/script2
"in script2, we also have awesome_print in our GemFile"
but we also have colored, which is not available, this throws an error
/Users/charbon/wip/script2/script2.rb:19:in `require': cannot load such file -- colored (LoadError)
    from /Users/charbon/wip/script2/script2.rb:19:in `<main>'
like image 542
MichaelC Avatar asked Dec 08 '22 12:12

MichaelC


2 Answers

script1.rb

#!/usr/bin/env ruby
cwd=Dir.pwd ; ourDir=File.dirname(__FILE__) ; Dir.chdir(ourDir)
require 'bundler' ;  Bundler.setup
require "awesome_print"
ap "in script1, we have awesome_print in our GemFile"

Bundler.with_clean_env do
  Dir.chdir('/Users/charbon/wip/script2/script2.rb') do
    exec("./script2.rb")
  end 
end

script2.rb

#!/usr/bin/env ruby
puts "we are now in script2.rb"
cwd=Dir.pwd ; ourDir=File.dirname(__FILE__) ; Dir.chdir(ourDir)


require 'bundler' ;
Bundler.setup
require 'awesome_print'

ap "in script2, we also have awesome_print in our GemFile"
puts "but we also have colored, which is not available, this throws an erro"
require "colored"
like image 172
Marat Amerov Avatar answered Apr 20 '23 02:04

Marat Amerov


From my comment on the original question:

Bundler supports inline Gemfiles which allow you to specify your required gems (and sources!) directly in your ruby script. As long as you have bundler installed on the machine it should work, allowing you to keep your script dependencies isolated.

Bundler will handle installing & requiring the required gems, allowing you to run your script

like image 32
Jay Dorsey Avatar answered Apr 20 '23 02:04

Jay Dorsey