Bundler 在直接调用 .rb 文件时工作,在通过其他 ruby 脚本的 exec 调用时失败
Bundler works when .rb file called directly, fails when called via exec from other ruby script
我需要使用 Bundler + Gemfile 从另一个 ruby script1.rb 使用 Bundler + Gemfile 调用 ruby script2.rb。
我注意到 script2.rb 可用的宝石只有 script1.rb 的宝石。 script2.rb 独有的宝石在 script2.rb 被 script1.rb 调用时不可用。
当script2.rb直接从bashshell调用时,一切可用。
我确定这不是 ENV 问题,我在两个文件中使用 diff 和辅助代码对它们进行了比较,并进行了一些修改以使它们匹配。
File.open("script2_env.txt", 'wb') {|f| f.write(JSON.pretty_generate(ENV.to_h))}
为确保这不是 $LOAD_PATH 问题,我还确保它们匹配。
在由 script1.rb 调用的 script2.rb 中,我添加了以下行以匹配 script1 的 $LOAD_PATH :
$:.unshift "/usr/local/Cellar/rbenv/1.1.2/rbenv.d/exec/gem-rehash"
我对问题的理解是,当从 script1.rb 调用 script2.rb 时,Bundler 未正确初始化,可能是因为没有
eval "$(rbenv init -)"
正如我的 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'
结果是
/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>'
看来你需要在调用script2.rb
之前制作Dir.chdir "/Users/charbon/wip/script2/"
。
您正在从一个没有 Gemfile 的目录中调用 script2.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"
Dir.chdir "/Users/charbon/wip/script2/"
exec("script2.rb")
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"
总结并完成的回答:
Bundler 非常well documented:
Any Ruby code that opens a subshell (like system, backticks, or %x{}) will automatically use the current Bundler environment. If you need to shell out to a Ruby command that is not part of your current bundle, use the with_clean_env method with a block
第二种解决方案如Jay Dorsey : use the bundler/inline method
所评论
我已经测试了这两种方法,它们工作正常。
来自我对原问题的评论:
Bundler 支持 inline Gemfiles,它允许您直接在 ruby 脚本中指定所需的 gem(和来源!)。只要您在机器上安装了捆绑器,它就应该可以工作,从而使您可以隔离脚本依赖项。
Bundler 将处理安装和要求所需的 gem,允许您运行您的脚本
我需要使用 Bundler + Gemfile 从另一个 ruby script1.rb 使用 Bundler + Gemfile 调用 ruby script2.rb。
我注意到 script2.rb 可用的宝石只有 script1.rb 的宝石。 script2.rb 独有的宝石在 script2.rb 被 script1.rb 调用时不可用。 当script2.rb直接从bashshell调用时,一切可用。
我确定这不是 ENV 问题,我在两个文件中使用 diff 和辅助代码对它们进行了比较,并进行了一些修改以使它们匹配。
File.open("script2_env.txt", 'wb') {|f| f.write(JSON.pretty_generate(ENV.to_h))}
为确保这不是 $LOAD_PATH 问题,我还确保它们匹配。
在由 script1.rb 调用的 script2.rb 中,我添加了以下行以匹配 script1 的 $LOAD_PATH :
$:.unshift "/usr/local/Cellar/rbenv/1.1.2/rbenv.d/exec/gem-rehash"
我对问题的理解是,当从 script1.rb 调用 script2.rb 时,Bundler 未正确初始化,可能是因为没有
eval "$(rbenv init -)"
正如我的 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'
结果是
/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>'
看来你需要在调用script2.rb
之前制作Dir.chdir "/Users/charbon/wip/script2/"
。
您正在从一个没有 Gemfile 的目录中调用 script2.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"
Dir.chdir "/Users/charbon/wip/script2/"
exec("script2.rb")
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"
总结并完成
Bundler 非常well documented:
Any Ruby code that opens a subshell (like system, backticks, or %x{}) will automatically use the current Bundler environment. If you need to shell out to a Ruby command that is not part of your current bundle, use the with_clean_env method with a block
第二种解决方案如Jay Dorsey : use the bundler/inline method
所评论我已经测试了这两种方法,它们工作正常。
来自我对原问题的评论:
Bundler 支持 inline Gemfiles,它允许您直接在 ruby 脚本中指定所需的 gem(和来源!)。只要您在机器上安装了捆绑器,它就应该可以工作,从而使您可以隔离脚本依赖项。
Bundler 将处理安装和要求所需的 gem,允许您运行您的脚本