在什么情况下会从父进程获取Ruby $LOAD_PATH?

4
在我的黄瓜场景中,如果我在目标Rails应用程序文件夹内调用rake db:schema:load,那么我会得到黄瓜进程的$LOAD_PATH,而不是Rails应用程序自己的Gemfile/load path。我认为这非常奇怪。
结果是我会得到以下错误:
no such file to load -- rails/all

我无法在我的cucumber场景之外重现它。

ruby -rubygems -e "system 'rake -T'"

正常工作 -> 'rake -T'具有基于应用程序自己的Gemfile的$LOAD_PATH; 不会生成上述错误。
有人能想到为什么子进程(通过system,exec,%x[...]或反引号调用的rake - T或rake db:schema:load或rails runner ...)会以父进程的$LOAD_PATH(从cucumber场景的Gemfile)开始,而不是其自己的$LOAD_PATH(来自Rails应用程序的Gemfile)吗?
2个回答

2
当你使用bundler时,无论是通过bundle exec还是require 'bundler/setup',它都会找到你的Gemfile,并将其位置存储在ENV["BUNDLE_GEMFILE"]中。然而,如果此值已经被设置,则bundler只会重复使用该值。这就是导致你的Rails应用程序使用cucumber进程的Gemfile的原因。
如果你想在不同的Gemfile上下文中执行某些操作,请先清除ENV["BUNDLE_GEMFILE"]。Bundler提供了一个有用的方法Bundler.with_clean_env(&blk),它可以在加载Bundler之前以其初始环境执行你的代码块。当然,你也可以手动清除它,比如使用system("env -u BUNDLE_GEMFILE rake sometask")

如果你正在进行“Bundler Inception”(多层Bundler调用),那么这绝对是正确的。请注意,Rails应用程序在config/boot.rb中设置了ENV['BUNDLE_GEMFILE'],即使使用Bundler.with_clean_env也无法捕获它。 - wuputah

0
父进程的环境变量(ENV)会传递给子shell。无论是cucumber本身,还是你运行cucumber的方式(例如bundle exec cucumber),你的场景或者加载场景的代码(例如应用程序,因此也包括bundler),都可能会影响你的ENV。像RUBYLIBGEM_PATHBUNDLE_GEMFILE这样的环境变量可能会对你的子shell Ruby进程可以加载/将如何行为产生重大影响。
尝试在你的场景中打印出ENV变量,并将其与使用ruby -rubygems -rpp -e "pp ENV"或在命令行上使用env时获得的结果进行比较。
值得一提的是,一个可能的替代方案是直接加载和调用rake任务,例如Rake::Task['db:schema:load'].invoke,而不使用子shell。不过这取决于你想要做什么。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接