Module: PosixOpen4
- Defined in:
- lib/procreate/posix/open4.rb
Class Method Summary collapse
-
.background(argv, opts = {}) ⇒ Object
This is a rewritten version of Open4.background.
Class Method Details
.background(argv, opts = {}) ⇒ Object
This is a rewritten version of Open4.background. The reason for this is two-fold:
-
The existing function returns a thread that is extended to have a #pid method. This in turn waits on a queue, which will never have a pid pushed to it if there are any problems spawning. This version instead doesn’t create the separate background thread until after the popen4 has succeeded, meaning any exceptions related to spawn are thrown immediately and there is no need for a pid queue.
-
The existing spawn function calls flatten! on its argv parameter. This is because it was trying to support either splatted or not-splatted array, but that falls over for the 1-arg array form of Kernel#exec (eg, to launch a command that has spaces in its name, without using the shell.)
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/procreate/posix/open4.rb', line 23 def background argv, opts={} cmd = [argv].flatten.join(' ') getopt = getopts opts ignore_exit_failure = getopt[ 'ignore_exit_failure', getopt['quiet', false] ] ignore_exec_failure = getopt[ 'ignore_exec_failure', !getopt['raise', true] ] exitstatus = getopt[ %w( exitstatus exit_status status ) ] stdin = getopt[ %w( stdin in i 0 ) << 0 ] stdout = getopt[ %w( stdout out o 1 ) << 1 ] stderr = getopt[ %w( stderr err e 2 ) << 2 ] timeout = getopt[ %w( timeout spawn_timeout ) ] stdin_timeout = getopt[ %w( stdin_timeout ) ] stdout_timeout = getopt[ %w( stdout_timeout io_timeout ) ] stderr_timeout = getopt[ %w( stderr_timeout ) ] status = getopt[ %w( status ) ] cwd = getopt[ %w( cwd dir ) ] exitstatus = case exitstatus when TrueClass, FalseClass ignore_exit_failure = true if exitstatus [0] else [*(exitstatus || 0)].map{|i| Integer i} end stdin ||= '' if stdin_timeout stdout ||= '' if stdout_timeout stderr ||= '' if stderr_timeout started = false begin chdir(cwd) do pid, i, o, e = popen4(*argv) started = true thread = Thread.new do begin # the semantics of this timeout have been changed slightly, in # that it doesn't include the popen4 call itself anymore. i think # the intention however was for it to apply primarily to the # Process.waitpid Timeout::timeout timeout do te = ThreadEnsemble.new pid te.add_thread(i, stdin) do |i, stdin| relay stdin, i, stdin_timeout i.close rescue nil end te.add_thread(o, stdout) do |o, stdout| relay o, stdout, stdout_timeout end te.add_thread(e, stderr) do |o, stderr| relay e, stderr, stderr_timeout end te.run status = Process.waitpid2(pid).last unless ignore_exit_failure or (status.nil? and ignore_exec_failure) or exitstatus.include?(status.exitstatus) raise SpawnError.new(cmd, status) end status end ensure [i, o, e].each { |fd| fd.close unless fd.closed? } end end sc = class << thread; self; end sc.module_eval do define_method(:pid) { pid } define_method(:spawn_status) { value } define_method(:exitstatus) { spawn_status.exitstatus } end thread end rescue raise unless not started and ignore_exec_failure end end |