Bundler работает, когда файл .rb вызывается напрямую, происходит сбой при вызове через exec из другого скрипта ruby - PullRequest
4 голосов
/ 26 июня 2019

Мне нужно вызвать ruby ​​script2.rb с помощью Bundler + Gemfile из другого ruby ​​script1.rb с помощью Bundler + Gemfile.

Я заметил, что Gems доступны для script2.rbтолько те из script1.rb.Драгоценные камни, уникальные для script2.rb, недоступны, когда script2.rb вызывается script1.rb.Когда script2.rb вызывается напрямую из оболочки bash, все доступно.

Я убедился, что это не проблема ENV, я сравнил их, используя diff с вспомогательным кодом, как в обоих файлах, и сделал пару изменений длясделайте так, чтобы они совпадали.

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

Чтобы убедиться, что это не проблема $ LOAD_PATH, я также убедился, что они совпадают.

В script2.rb, который вызывается script1.rb,Я добавил следующую строку, чтобы соответствовать $ LOAD_PATH script1:

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

Мое понимание проблемы состоит в том, что каким-то образом Bundler не инициализируется должным образом, когда script2.rb вызывается из script1.rb, возможно, потому что естьнет

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>'

Ответы [ 4 ]

4 голосов
/ 03 июля 2019

Из моего комментария к исходному вопросу:

Bundler поддерживает встроенные Gemfiles , которые позволяют вам указывать необходимые гемы (и источники!) Непосредственно в вашем скрипте ruby.Пока у вас установлен упаковщик, он должен работать, позволяя вам сохранять изолированность ваших скриптов.

Bundler будет выполнять установку и требовать необходимые гемы, что позволит вам запустить ваш скрипт

4 голосов
/ 01 июля 2019

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"
4 голосов
/ 03 июля 2019

Подвести итог и завершить Марат Амеров ответ:

Bundler имеет это хорошо документированное :

Любой код Ruby, который открывает подоболочку (например, system, backticks или% x {}), будет автоматически использовать текущую среду Bundler. Если вам нужно добавить команду Ruby, которая не является частью вашего текущего пакета, используйте метод with_clean_env с блоком

Второе решение, как прокомментировал Jay Dorsey : используйте метод упаковщика / встроенный метод

Я проверил оба метода, и они отлично работают.

2 голосов
/ 30 июня 2019

Похоже, вам нужно набрать Dir.chdir "/Users/charbon/wip/script2/" перед вызовом script2.rb. Вы вызываете script2.rb из каталога, где для него нет Gemfile. Сценарий будет выглядеть так:

#!/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")
...