Module: Gitlab::Popen
Defined Under Namespace
Instance Method Summary collapse
-
#popen(cmd, path = nil, vars = {}, &block) ⇒ Object
Returns [stdout + stderr, status] status is either the exit code or the signal that killed the process.
- #popen_with_detail(cmd, path = nil, vars = {}) ⇒ Object
- #popen_with_streaming(cmd, path = nil, vars = {}, &block) ⇒ Object
Instance Method Details
#popen(cmd, path = nil, vars = {}, &block) ⇒ Object
Returns [stdout + stderr, status] status is either the exit code or the signal that killed the process
14 15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/gitlab/popen.rb', line 14 def popen(cmd, path = nil, vars = {}, &block) result = popen_with_detail(cmd, path, vars, &block) # Process#waitpid returns Process::Status, which holds a 16-bit value. # The higher-order 8 bits hold the exit() code (`exitstatus`). # The lower-order bits holds whether the process was terminated. # If the process didn't exit normally, `exitstatus` will be `nil`, # but we still want a non-zero code, even if the value is # platform-dependent. status = result.status&.exitstatus || result.status.to_i ["#{result.stdout}#{result.stderr}", status] end |
#popen_with_detail(cmd, path = nil, vars = {}) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/gitlab/popen.rb', line 49 def popen_with_detail(cmd, path = nil, vars = {}) vars, = prepare_popen_command(cmd, path, vars) cmd_stdout = '' cmd_stderr = '' cmd_status = nil start = Time.now.to_f Open3.popen3(vars, *cmd, ) do |stdin, stdout, stderr, wait_thr| # stderr and stdout pipes can block if stderr/stdout aren't drained: https://bugs.ruby-lang.org/issues/9082 # Mimic what Ruby does with capture3: https://github.com/ruby/ruby/blob/1ec544695fa02d714180ef9c34e755027b6a2103/lib/open3.rb#L257-L273 out_reader = Thread.new { stdout.read } err_reader = Thread.new { stderr.read } yield(stdin) if block_given? stdin.close cmd_stdout = out_reader.value cmd_stderr = err_reader.value cmd_status = wait_thr.value end Result.new(cmd, cmd_stdout, cmd_stderr, cmd_status, Time.now.to_f - start) end |
#popen_with_streaming(cmd, path = nil, vars = {}, &block) ⇒ Object
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/gitlab/popen.rb', line 28 def popen_with_streaming(cmd, path = nil, vars = {}, &block) vars, = prepare_popen_command(cmd, path, vars) cmd_status = nil block_mutex = Mutex.new if block Open3.popen3(vars, *cmd, ) do |stdin, stdout, stderr, wait_thr| stdin.close # Close stdin immediately since we're not using it for streaming stdout_thread = read_stream_in_thread(stdout, :stdout, block_mutex, &block) stderr_thread = read_stream_in_thread(stderr, :stderr, block_mutex, &block) stdout_thread.join stderr_thread.join cmd_status = wait_thr.value&.exitstatus || wait_thr.value.to_i end cmd_status end |