command_runner_ng 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/command_runner.rb +27 -25
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 341dc1d0132412d53c1e5d258d7a6a03e96e3a4e
|
4
|
+
data.tar.gz: 94ac85a463daa4020bf069c47adba3a99fe4aebb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 175e6af549e49bf1269032c11f0881ca5b89f79706ba706f082cba51af96b1a1ef13bf04d5d7955d64c3057af39096c94be946350934c25b10e71cfc6b741aac
|
7
|
+
data.tar.gz: 5308811978a0c87a00e2aef3766b95fb733da28bcf32f58f327e65f1a58f5633f9b7143eddf4f5a1e9f3fc591bdcfb78a6286026a5e40b50123a9a01e20a42f9
|
data/lib/command_runner.rb
CHANGED
@@ -27,9 +27,8 @@ module CommandRunner
|
|
27
27
|
# to the caller of run.
|
28
28
|
#
|
29
29
|
def self.run(*args, timeout: nil)
|
30
|
-
#
|
30
|
+
# This could be tweakable through vararg opts
|
31
31
|
tick = 0.1
|
32
|
-
bufsize = 4096
|
33
32
|
|
34
33
|
now = Time.now
|
35
34
|
|
@@ -58,37 +57,19 @@ module CommandRunner
|
|
58
57
|
io = IO.popen(*args, :err=>[:child, :out])
|
59
58
|
data = ""
|
60
59
|
|
61
|
-
# Wait until stdout closes
|
62
|
-
while Time.now < deadline_sequence.first[:deadline] do
|
63
|
-
IO.select([io], nil, nil, tick)
|
64
|
-
begin
|
65
|
-
data << io.read_nonblock(bufsize)
|
66
|
-
rescue IO::WaitReadable
|
67
|
-
# Ignore: tick time reached without io
|
68
|
-
rescue EOFError
|
69
|
-
# Child closed stdout (probably dead, but not necessarily)
|
70
|
-
break
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
60
|
# Run through all deadlines until command completes.
|
75
61
|
# We could merge this block into the selecting block above,
|
76
62
|
# but splitting like this saves us a Process.wait syscall per iteration.
|
63
|
+
eof = false
|
77
64
|
deadline_sequence.each do |point|
|
78
65
|
while Time.now < point[:deadline]
|
79
66
|
if Process.wait(io.pid, Process::WNOHANG)
|
67
|
+
read_nonblock_safe!(io, data, tick)
|
80
68
|
result = {out: data, status: $?}
|
81
69
|
io.close
|
82
70
|
return result
|
83
|
-
|
84
|
-
|
85
|
-
begin
|
86
|
-
data << io.read_nonblock(bufsize)
|
87
|
-
rescue IO::WaitReadable
|
88
|
-
# Ignore: tick time reached without io
|
89
|
-
rescue EOFError
|
90
|
-
# Child closed stdout (probably dead, but not necessarily)
|
91
|
-
end
|
71
|
+
elsif !eof
|
72
|
+
eof = read_nonblock_safe!(io, data, tick)
|
92
73
|
end
|
93
74
|
end
|
94
75
|
|
@@ -116,12 +97,33 @@ module CommandRunner
|
|
116
97
|
end
|
117
98
|
end
|
118
99
|
|
119
|
-
# Either we didn't have a deadline, or none of the deadlines killed
|
100
|
+
# Either we didn't have a deadline, or none of the deadlines killed off the child.
|
120
101
|
Process.wait(io.pid)
|
102
|
+
read_nonblock_safe!(io, data, tick)
|
121
103
|
result = {out: data, status: $?}
|
122
104
|
io.close
|
123
105
|
|
124
106
|
result
|
125
107
|
end
|
126
108
|
|
109
|
+
private
|
110
|
+
|
111
|
+
# Read data async, appending to data_out,
|
112
|
+
# returning true on EOF, false otherwise
|
113
|
+
def self.read_nonblock_safe!(io, data_out, tick)
|
114
|
+
IO.select([io], nil, nil, tick)
|
115
|
+
begin
|
116
|
+
# Read all available data until EAGAIN or EOF
|
117
|
+
loop do
|
118
|
+
data_out << io.read_nonblock(4096)
|
119
|
+
end
|
120
|
+
rescue IO::WaitReadable
|
121
|
+
# Ignore: tick time reached without io
|
122
|
+
return false
|
123
|
+
rescue EOFError
|
124
|
+
# Child closed stdout (probably dead, but not necessarily)
|
125
|
+
return true
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
127
129
|
end
|