diff options
author | Matthew Draper <matthew@trebex.net> | 2017-09-04 02:25:26 +0930 |
---|---|---|
committer | Matthew Draper <matthew@trebex.net> | 2017-09-04 20:19:39 +0930 |
commit | 802ce8a2392d3f749e665d4f9e54790cf613aaf9 (patch) | |
tree | c918e029aabc60a84afe7714030e35e81dffc0ec /railties/test/isolation | |
parent | 07bac9ef93d98a1e31cd5b2ce2aabc1e57816604 (diff) | |
download | rails-802ce8a2392d3f749e665d4f9e54790cf613aaf9.tar.gz rails-802ce8a2392d3f749e665d4f9e54790cf613aaf9.tar.bz2 rails-802ce8a2392d3f749e665d4f9e54790cf613aaf9.zip |
Run in-app rails commands via fork+load where possible
While this avoids shell argument parsing, we still pass through
everything in our stack.
Diffstat (limited to 'railties/test/isolation')
-rw-r--r-- | railties/test/isolation/abstract_unit.rb | 84 |
1 files changed, 81 insertions, 3 deletions
diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index 90c366ba17..a4c6fc4e68 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -236,10 +236,88 @@ module TestHelpers end end - def script(script) - Dir.chdir(app_path) do - `#{Gem.ruby} #{app_path}/bin/rails #{script}` + # Invoke a bin/rails command inside the app + # + # allow_failures:: true to return normally if the command exits with + # a non-zero status. By default, this method will raise. + # stderr:: true to pass STDERR output straight to the "real" STDERR. + # By default, the STDERR and STDOUT of the process will be + # combined in the returned string. + # fork:: false to not use fork even when it's available. By default, + # when possible, the command is executed in a fork of the current + # process, avoiding the need to load core Rails libraries anew. + def rails(*args, allow_failure: false, stderr: false, fork: true) + args = args.flatten + + command = "bin/rails #{Shellwords.join args}#{' 2>&1' unless stderr}" + + # Don't fork if the environment has disabled it + fork = false if ENV["NO_FORK"] + + # Don't fork if the runtime isn't able to + fork = false if !Process.respond_to?(:fork) + + # Don't fork if we're re-invoking minitest + fork = false if args.first == "t" || args.grep(/\Atest(:|\z)/).any? + + if fork + out_read, out_write = IO.pipe + if stderr + err_read, err_write = IO.pipe + else + err_write = out_write + end + + pid = fork do + out_read.close + err_read.close if err_read + + $stdin.reopen(File::NULL, "r") + $stdout.reopen(out_write) + $stderr.reopen(err_write) + + at_exit do + case $! + when SystemExit + exit! $!.status + when nil + exit! 0 + else + err_write.puts "#{$!.class}: #{$!}" + exit! 1 + end + end + + Rails.instance_variable_set :@_env, nil + + $-v = $-w = false + Dir.chdir app_path unless Dir.pwd == app_path + + ARGV.replace(args) + load "./bin/rails" + + exit! 0 + end + + out_write.close + + if err_read + err_write.close + + $stderr.write err_read.read + end + + output = out_read.read + + Process.waitpid pid + + else + output = `cd #{app_path}; #{command}` end + + raise "rails command failed (#{$?.exitstatus}): #{command}\n#{output}" unless allow_failure || $?.success? + + output end def add_to_top_of_config(str) |