Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Process#spawn should call #to_io on non-IO file descriptor objects #2809

Merged
merged 3 commits into from
Dec 19, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions spec/ruby/core/process/spawn_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,52 @@ def child_pids(pid)

# redirection

context "redirects STDOUT to the IO returned by obj.to_io if out: obj" do
# When an instance of @wrapped_io_class is passed as a value for Process#spawn
# redirection (e.g. as the value for out: or err:), Process#spawn is
# expected to call #to_io to get the wrapped IO object.
#
@wrapped_io_class = Class.new do
def initialize(io)
@io = io
@to_io_called = false
end

def to_io
@to_io_called = true
@io
end

def to_io_called?
@to_io_called
end
end

it 'should not raise an error' do
out = @wrapped_io_class.new(STDOUT)
# Since 'exit' is a shell builtin, the quotes around 0 are necessary to
# force spawn to use a shell
-> { Process.wait Process.spawn('exit "0"', out: out) }.should_not raise_error
end

it 'should call #to_io to get the wrapped IO object' do
out = @wrapped_io_class.new(STDOUT)
# Since 'exit' is a shell builtin, the quotes around 0 are necessary to
# force spawn to use a shell
Process.wait Process.spawn('exit "0"', out: out)
out.to_io_called?.should == true
end

it 'should redirect stdout of the subprocess to the wrapped IO object' do
File.open(@name, 'w') do |file|
-> do
out = @wrapped_io_class.new(file)
Process.wait Process.spawn('echo "Hello World"', out: out)
end.should output_to_fd("Hello World\n", file)
end
end
end

it "redirects STDOUT to the given file descriptor if out: Integer" do
File.open(@name, 'w') do |file|
-> do
Expand Down
6 changes: 5 additions & 1 deletion src/main/ruby/truffleruby/core/truffle/process_operations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,11 @@ def convert_to_fd(obj, target)
open_file_for_child(obj[0], convert_file_mode(obj[1]), obj[2])
end
else
raise ArgumentError, "wrong exec redirect: #{obj.inspect}"
if obj.respond_to?(:to_io)
obj.to_io.fileno
else
raise ArgumentError, "wrong exec redirect: #{obj.inspect}"
end
end
end

Expand Down