Commit 95640413 authored by James Edwards-Jones's avatar James Edwards-Jones

Gitlab::Git::Popen can lazily hand output to a block

This allows input to start processing immediately without waiting for the process to complete.
This also allows long or infinite inputs to be partially processed,
which will termiate the process when reading stops with SIGPIPE.
parent dfe6c539
...@@ -7,7 +7,7 @@ module Gitlab ...@@ -7,7 +7,7 @@ module Gitlab
module Popen module Popen
FAST_GIT_PROCESS_TIMEOUT = 15.seconds FAST_GIT_PROCESS_TIMEOUT = 15.seconds
def popen(cmd, path, vars = {}) def popen(cmd, path, vars = {}, lazy_block: nil)
unless cmd.is_a?(Array) unless cmd.is_a?(Array)
raise "System commands must be given as an array of strings" raise "System commands must be given as an array of strings"
end end
...@@ -22,7 +22,12 @@ module Gitlab ...@@ -22,7 +22,12 @@ module Gitlab
yield(stdin) if block_given? yield(stdin) if block_given?
stdin.close stdin.close
if lazy_block
return lazy_block.call(stdout.lazy)
else
@cmd_output << stdout.read @cmd_output << stdout.read
end
@cmd_output << stderr.read @cmd_output << stderr.read
@cmd_status = wait_thr.value.exitstatus @cmd_status = wait_thr.value.exitstatus
end end
......
...@@ -53,6 +53,23 @@ describe 'Gitlab::Git::Popen' do ...@@ -53,6 +53,23 @@ describe 'Gitlab::Git::Popen' do
it { expect(status).to be_zero } it { expect(status).to be_zero }
it { expect(output).to eq('hello') } it { expect(output).to eq('hello') }
end end
context 'with lazy block' do
it 'yields a lazy io' do
expect_lazy_io = lambda do |io|
expect(io).to be_a Enumerator::Lazy
expect(io.inspect).to include('#<IO:fd')
end
klass.new.popen(%w[ls], path, lazy_block: expect_lazy_io)
end
it "doesn't wait for process exit" do
Timeout.timeout(2) do
klass.new.popen(%w[yes], path, lazy_block: ->(io) {})
end
end
end
end end
context 'popen_with_timeout' do context 'popen_with_timeout' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment