Commit 0aa6d685 authored by Samuel E. Giddins's avatar Samuel E. Giddins

Merge pull request #3437 from CocoaPods/seg-popen3

[Executable] Use popen3 instead of open4 to execute commands
parents 3d184acc bea277d5
...@@ -17,6 +17,12 @@ To install release candidates run `[sudo] gem install cocoapods --pre` ...@@ -17,6 +17,12 @@ To install release candidates run `[sudo] gem install cocoapods --pre`
[Mason Glidden](https://github.com/mglidden) [Mason Glidden](https://github.com/mglidden)
[#1154](https://github.com/CocoaPods/CocoaPods/issues/1154) [#1154](https://github.com/CocoaPods/CocoaPods/issues/1154)
* Handle subprocesses leaking STDOUT/STDERR pipes by more strictly managing
process lifetime and not allowing I/O to block completion of the task.
[Samuel Giddins](https://github.com/segiddins)
[#3101](https://github.com/CocoaPods/CocoaPods/issues/3101)
## 0.37.0.beta.1 ## 0.37.0.beta.1
##### Enhancements ##### Enhancements
......
...@@ -77,7 +77,6 @@ PATH ...@@ -77,7 +77,6 @@ PATH
escape (~> 0.0.4) escape (~> 0.0.4)
molinillo (~> 0.2.3) molinillo (~> 0.2.3)
nap (~> 0.8) nap (~> 0.8)
open4 (~> 1.3)
xcodeproj (~> 0.24.0) xcodeproj (~> 0.24.0)
GEM GEM
...@@ -124,7 +123,6 @@ GEM ...@@ -124,7 +123,6 @@ GEM
nap (0.8.0) nap (0.8.0)
netrc (0.7.8) netrc (0.7.8)
notify (0.5.2) notify (0.5.2)
open4 (1.3.4)
parser (2.2.0.3) parser (2.2.0.3)
ast (>= 1.1, < 3.0) ast (>= 1.1, < 3.0)
powerpack (0.1.0) powerpack (0.1.0)
......
...@@ -38,7 +38,6 @@ Gem::Specification.new do |s| ...@@ -38,7 +38,6 @@ Gem::Specification.new do |s|
s.add_runtime_dependency 'colored', '~> 1.2' s.add_runtime_dependency 'colored', '~> 1.2'
s.add_runtime_dependency 'escape', '~> 0.0.4' s.add_runtime_dependency 'escape', '~> 0.0.4'
s.add_runtime_dependency 'open4', '~> 1.3'
s.add_runtime_dependency 'activesupport', '>= 3.2.15' s.add_runtime_dependency 'activesupport', '>= 3.2.15'
s.add_runtime_dependency 'nap', '~> 0.8' s.add_runtime_dependency 'nap', '~> 0.8'
......
...@@ -51,7 +51,6 @@ module Pod ...@@ -51,7 +51,6 @@ module Pod
bin = `which #{executable}`.strip bin = `which #{executable}`.strip
raise Informative, "Unable to locate the executable `#{executable}`" if bin.empty? raise Informative, "Unable to locate the executable `#{executable}`" if bin.empty?
require 'open4'
require 'shellwords' require 'shellwords'
command = command.map(&:to_s) command = command.map(&:to_s)
...@@ -64,8 +63,7 @@ module Pod ...@@ -64,8 +63,7 @@ module Pod
stdout, stderr = Indenter.new, Indenter.new stdout, stderr = Indenter.new, Indenter.new
end end
options = { :stdout => stdout, :stderr => stderr, :status => true } status = popen3(bin, command, stdout, stderr)
status = Open4.spawn(bin, command, options)
output = stdout.join("\n") + stderr.join("\n") output = stdout.join("\n") + stderr.join("\n")
unless status.success? unless status.success?
if raise_on_failure if raise_on_failure
...@@ -77,6 +75,27 @@ module Pod ...@@ -77,6 +75,27 @@ module Pod
output output
end end
private
def self.popen3(bin, command, stdout, stderr)
require 'open3'
Open3.popen3(bin, *command) do |i, o, e, t|
out_reader = Thread.new { while s = o.gets; stdout << s; end }
err_reader = Thread.new { while s = e.gets; stderr << s; end }
i.close
run_readers = lambda do
[out_reader, err_reader].each do |reader|
reader.run if reader.alive?
end
end
run_readers.call
t.value.tap { run_readers.call }
end
end
#-------------------------------------------------------------------------# #-------------------------------------------------------------------------#
# Helper class that allows to write to an {IO} instance taking into account # Helper class that allows to write to an {IO} instance taking into account
......
...@@ -16,8 +16,18 @@ module Pod ...@@ -16,8 +16,18 @@ module Pod
result = mock result = mock
result.stubs(:success?).returns(true) result.stubs(:success?).returns(true)
Open4.expects(:spawn).with('/Spa ces/are"/fun/false', [], :stdout => [], :stderr => [], :status => true).once.returns(result) Open3.expects(:popen3).with('/Spa ces/are"/fun/false').once.returns(result)
Executable.execute_command(cmd, [], true) Executable.execute_command(cmd, [], true)
end end
it "doesn't hang when the spawned process forks a zombie process with the same STDOUT and STDERR" do
cmd = ['-e', <<-RB]
Process.fork { Process.daemon(nil, true); sleep(2) }
puts 'out'
RB
Timeout.timeout(1) do
Executable.execute_command('ruby', cmd, true).should == "out\n"
end
end
end end
end end
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