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.
This commit is contained in:
parent
dfe6c5390d
commit
95640413e6
2 changed files with 24 additions and 2 deletions
|
@ -7,7 +7,7 @@ module Gitlab
|
|||
module Popen
|
||||
FAST_GIT_PROCESS_TIMEOUT = 15.seconds
|
||||
|
||||
def popen(cmd, path, vars = {})
|
||||
def popen(cmd, path, vars = {}, lazy_block: nil)
|
||||
unless cmd.is_a?(Array)
|
||||
raise "System commands must be given as an array of strings"
|
||||
end
|
||||
|
@ -22,7 +22,12 @@ module Gitlab
|
|||
yield(stdin) if block_given?
|
||||
stdin.close
|
||||
|
||||
@cmd_output << stdout.read
|
||||
if lazy_block
|
||||
return lazy_block.call(stdout.lazy)
|
||||
else
|
||||
@cmd_output << stdout.read
|
||||
end
|
||||
|
||||
@cmd_output << stderr.read
|
||||
@cmd_status = wait_thr.value.exitstatus
|
||||
end
|
||||
|
|
|
@ -53,6 +53,23 @@ describe 'Gitlab::Git::Popen' do
|
|||
it { expect(status).to be_zero }
|
||||
it { expect(output).to eq('hello') }
|
||||
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
|
||||
|
||||
context 'popen_with_timeout' do
|
||||
|
|
Loading…
Reference in a new issue