Skip to content

Commit

Permalink
Merge 5b08daa into d7d3ab6
Browse files Browse the repository at this point in the history
  • Loading branch information
jleeothon committed Mar 22, 2019
2 parents d7d3ab6 + 5b08daa commit afd38a8
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 62 deletions.
83 changes: 35 additions & 48 deletions lib/eksekuter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,71 +14,58 @@ def initialize logger: nil
@stdin_buffer = nil
end

def run *args, **opts, &block
env, cmd = separate_env_and_cmd(args)
# p opts
capture = opts.delete(:capture) || false
streams = get_out_err_streams(capture)

set_streams_in_opts streams, opts

params = { env: env, cmd: cmd, opts: opts, block: block }
# Wraps around Kernel#spawn so that the return value is an EksekResult.
# @return EksekResult
def run *args, **opts
env, cmd = split_env_and_cmd(args)
params = { env: env, cmd: cmd, opts: opts }
process_status = spawn_and_get_status(params)
assemble_result(params, process_status)
end

process_status = run_process(params, streams)
assemble_result(params, process_status, streams)
# Like Eksekuter#run but the :out and :err options are ignored; instead
# the output is attached to the EksekResult object returned.
# Returns an EksekResult object which getters :stdout and :stderr containing
# the corresponding output of the spawned process.
# @return EksekResult
def capture *args, **opts
env, cmd = split_env_and_cmd(args)
out_read, out_write = IO.pipe
err_read, err_write = IO.pipe
opts2 = opts.merge(out: out_write, err: err_write)
params = { env: env, cmd: cmd, opts: opts2 }
process_status = spawn_and_get_status(params)
out_write.close
err_write.close
assemble_result(params, process_status, out_read, err_read)
end

private

def separate_env_and_cmd args
env = args[0].is_a?(Hash) ? args.shift : {}
def split_env_and_cmd args
cmd_args = args.clone
env = cmd_args.first.is_a?(Hash) ? cmd_args.shift : {}
env = env.each_with_object({}) { |(k, v), o| o[k.to_s] = v }
cmd = args.size == 1 ? args.first : args
cmd = cmd_args.size == 1 ? cmd_args.first : cmd_args
[env, cmd]
end

def get_out_err_streams capture
if capture
out_readable, out_writable = IO.pipe
err_readable, err_writable = IO.pipe
return {
out: { readable: out_readable, writable: out_writable },
err: { readable: err_readable, writable: err_writable }
}
end

{
out: { readable: nil, writable: STDOUT },
err: { readable: nil, writable: STDERR }
}
end

def set_streams_in_opts streams, opts
opts[:out] = streams.fetch(:out).fetch(:writable) unless opts[:out]
opts[:err] = streams.fetch(:err).fetch(:writable) unless opts[:err]
end

def run_process params, streams
pid = spawn(params.fetch(:env), *params.fetch(:cmd), params.fetch(:opts))
close_streams streams
def spawn_and_get_status params
env = params.fetch(:env)
cmd = params.fetch(:cmd)
opts = params.fetch(:opts)
pid = spawn(env, *cmd, opts)
_, process_status = Process.wait2(pid)
process_status
end

def close_streams streams
out_writable = streams.fetch(:out).fetch(:writable)
err_writable = streams.fetch(:err).fetch(:writable)
out_writable&.close if out_writable != STDOUT
err_writable&.close if err_writable != STDERR
end

def assemble_result params, process_status, streams
def assemble_result params, process_status, out_stream = nil, err_stream = nil
EksekResult.new(
params.fetch(:env),
params.fetch(:cmd),
process_status.exitstatus,
streams.fetch(:out).fetch(:readable),
streams.fetch(:err).fetch(:readable),
out_stream,
err_stream,
)
end
end
2 changes: 1 addition & 1 deletion spec/eksek_result_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
RSpec.describe 'EksekResult#to_s' do
it 'returns the stdout' do
command = 'printf HelloStdout && printf HelloStderr >&2'
output = "The output was: #{Eksekuter.new.run(command, capture: true)}."
output = "The output was: #{Eksekuter.new.capture(command)}."
expect(output).to eq('The output was: HelloStdout.')
end
end
36 changes: 23 additions & 13 deletions spec/eksek_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,29 @@
end
end

RSpec.describe 'Eksekuter capturing options' do
RSpec.describe 'Eksekuter#capture' do
it 'captures the stdout and stderr separately' do
expect(Eksekuter.new.run('printf Hello', capture: true).stdout)
expect(Eksekuter.new.capture('printf Hello').stdout)
.to eq('Hello')
expect(Eksekuter.new.run('printf Hello >&2', capture: true).stderr)
expect(Eksekuter.new.capture('printf Hello >&2').stderr)
.to eq('Hello')
end
end

it 'outputs to stdout/stderr when disabling I/O capturing' do
expect { Eksekuter.new.run('printf Hello', capture: false) }
.to output('Hello').to_stdout_from_any_process
expect { Eksekuter.new.run('printf Hello >&2', capture: false) }
.to output('Hello').to_stderr_from_any_process
RSpec.describe 'Eksekuter with overridden output streams' do
it 'can write to a custom IO object' do
readable, writable = IO.pipe
Eksekuter.new.run('printf Hello', out: writable)
writable.close
expect(readable.read).to eq('Hello')
end

it 'can read from a custom IO object' do
readable, writable = IO.pipe
writable.write 'Hello'
writable.close
expect(Eksekuter.new.capture('read A; printf $A', in: readable).stdout)
.to eq('Hello')
end
end

Expand All @@ -49,27 +59,27 @@
readable, writable = IO.pipe
writable.write 'Hello'
writable.close
result = Eksekuter.new.run('read A; printf $A', in: readable, capture: true)
expect(result.stdout).to eq('Hello')
expect(Eksekuter.new.capture('read A; printf $A', in: readable).stdout)
.to eq('Hello')
end
end

RSpec.describe 'Kernel#spawn-style parameters' do
it 'accepts a Hash as an optional first parameter' do
result = Eksekuter.new
.run({ 'TEXT' => 'Hello' }, 'printf $TEXT', capture: true)
.capture({ 'TEXT' => 'Hello' }, 'printf $TEXT')
expect(result.stdout).to eq('Hello')
end

it 'stringifies the keys of the environment' do
result = Eksekuter.new
.run({ TEXT: 'Hello' }, 'printf $TEXT', capture: true)
.capture({ TEXT: 'Hello' }, 'printf $TEXT')
expect(result.stdout).to eq('Hello')
end

it 'accepts a variable-length parameter list as command' do
result = Eksekuter.new
.run('echo', 'Hello', 'World', capture: true)
.capture('echo', 'Hello', 'World')
expect(result.stdout).to eq("Hello World\n")
end
end

0 comments on commit afd38a8

Please sign in to comment.