shexecutor 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +25 -0
- data/lib/shexecutor/version.rb +1 -1
- data/lib/shexecutor.rb +32 -13
- data/spec/executor_spec.rb +13 -2
- 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: c90615e32be8148e01050f014d0bf7e107b403ad
|
4
|
+
data.tar.gz: 55607d1521893564995bea9da74153b084bd92ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 54788b1980134c365b3b4c8cfb20c0d73ad74b3283e398f86e2b24662c57fcc382978dec80dfe10f463cf730ab7bab1244475dd1a32c609988a70ed888204b9d
|
7
|
+
data.tar.gz: becd1258cd4c5c1a526f180a419503430d5549c4064df9078300ba102d4100fb9229df812b6ca5b79787ec4d94894d00eea7ff993ed7bbd6073de8474f991af9
|
data/README.md
CHANGED
@@ -20,6 +20,31 @@ For a full description of status, please see Process::Status
|
|
20
20
|
|
21
21
|
This gem is sponsored by Hetzner (Pty) Ltd - http://hetzner.co.za
|
22
22
|
|
23
|
+
## Initialization options:
|
24
|
+
|
25
|
+
Required / optional:
|
26
|
+
|
27
|
+
```
|
28
|
+
{
|
29
|
+
:application_path # Path of the command to run
|
30
|
+
:params # Parameters to pass the command
|
31
|
+
}
|
32
|
+
```
|
33
|
+
|
34
|
+
```
|
35
|
+
@@default_options = {
|
36
|
+
:timeout => -1, # Seconds after which to raise Timeout::Error if not completed
|
37
|
+
:protect_against_injection => true, # look for spaces in and tainted application path
|
38
|
+
:stdout_path => nil, # file to append stdout to
|
39
|
+
:stderr_path => nil, # file to append stderr to
|
40
|
+
:append_stdout_path => true, # if true, will append, otherwise will overwrite
|
41
|
+
:append_stderr_path => true, # if true, will append, otherwise will overwrite
|
42
|
+
:replace => false, # replace the running process with the command
|
43
|
+
:wait_for_completion => false, # block until the command completes
|
44
|
+
:timeout_sig_kill_retry => 500 # if timeout occurs, send TERM, and send signal 9 if still present after X ms
|
45
|
+
}
|
46
|
+
```
|
47
|
+
|
23
48
|
## Installation
|
24
49
|
|
25
50
|
Add this line to your application's Gemfile:
|
data/lib/shexecutor/version.rb
CHANGED
data/lib/shexecutor.rb
CHANGED
@@ -3,14 +3,15 @@ require 'open3'
|
|
3
3
|
|
4
4
|
module SHExecutor
|
5
5
|
@@default_options = {
|
6
|
-
:timeout => -1,
|
7
|
-
:protect_against_injection => true,
|
8
|
-
:stdout_path => nil,
|
9
|
-
:stderr_path => nil,
|
10
|
-
:append_stdout_path => true,
|
11
|
-
:append_stderr_path => true,
|
12
|
-
:replace => false,
|
13
|
-
:wait_for_completion => false
|
6
|
+
:timeout => -1, # Seconds after which to raise Timeout::Error if not completed
|
7
|
+
:protect_against_injection => true, # look for spaces in and tainted application path
|
8
|
+
:stdout_path => nil, # file to append stdout to
|
9
|
+
:stderr_path => nil, # file to append stderr to
|
10
|
+
:append_stdout_path => true, # if true, will append, otherwise will overwrite
|
11
|
+
:append_stderr_path => true, # if true, will append, otherwise will overwrite
|
12
|
+
:replace => false, # replace the running process with the command
|
13
|
+
:wait_for_completion => false, # block until the command completes
|
14
|
+
:timeout_sig_kill_retry => 500 # if timeout occurs, send TERM, and send signal 9 if still present after X ms
|
14
15
|
}
|
15
16
|
|
16
17
|
def self.default_options
|
@@ -127,9 +128,9 @@ module SHExecutor
|
|
127
128
|
def run_process(application_path, options = "")
|
128
129
|
data_out = StringIO.new
|
129
130
|
data_err = StringIO.new
|
130
|
-
t0 = nil
|
131
|
+
@t0 = nil
|
131
132
|
Open3::popen3(application_path, options) do |stdin, stdout, stderr, thr|
|
132
|
-
t0 = thr
|
133
|
+
@t0 = thr
|
133
134
|
# read srderr and stdout into buffers to prevent blocking
|
134
135
|
t1 = Thread.new do
|
135
136
|
IO.copy_stream(stdout, data_out)
|
@@ -151,7 +152,7 @@ module SHExecutor
|
|
151
152
|
t1.join if not should_timeout?
|
152
153
|
t2.join if not should_timeout?
|
153
154
|
end
|
154
|
-
return data_out, data_err, t0
|
155
|
+
return data_out, data_err, @t0
|
155
156
|
end
|
156
157
|
|
157
158
|
def block_process
|
@@ -170,17 +171,35 @@ module SHExecutor
|
|
170
171
|
@result.join
|
171
172
|
@result.value
|
172
173
|
rescue Timeout::Error => ex
|
174
|
+
kill_process(@t0.pid)
|
173
175
|
raise ex
|
174
176
|
end
|
175
177
|
end
|
176
178
|
|
179
|
+
def process?(pid)
|
180
|
+
begin
|
181
|
+
Process.getpgid(pid)
|
182
|
+
true
|
183
|
+
rescue Errno::ESRCH
|
184
|
+
false
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def kill_process(pid)
|
189
|
+
return if pid.nil?
|
190
|
+
Process.kill("TERM", pid)
|
191
|
+
count = 0
|
192
|
+
while (count < (@options[:timeout_sig_kill_retry]/100) and process?(pid)) do
|
193
|
+
sleep 0.1
|
194
|
+
end
|
195
|
+
Process.kill(9, pid) if process?(pid)
|
196
|
+
end
|
197
|
+
|
177
198
|
def fork_process
|
178
199
|
validate
|
179
200
|
@stdin_stream, @stdout_stream, @stderr_stream, @result = Open3::popen3(@options[:application_path], *@options[:params])
|
180
201
|
end
|
181
202
|
|
182
|
-
private
|
183
|
-
|
184
203
|
def should_timeout?
|
185
204
|
@options[:timeout] > 0
|
186
205
|
end
|
data/spec/executor_spec.rb
CHANGED
@@ -27,7 +27,8 @@ describe 'Executor' do
|
|
27
27
|
:append_stdout_path => false,
|
28
28
|
:append_stderr_path => false,
|
29
29
|
:replace => false,
|
30
|
-
:wait_for_completion => true
|
30
|
+
:wait_for_completion => true,
|
31
|
+
:timeout_sig_kill_retry => 500
|
31
32
|
}
|
32
33
|
@iut = SHExecutor::Executor.new(iut_options)
|
33
34
|
expect(@iut.options).to eq(iut_options)
|
@@ -207,7 +208,7 @@ describe 'Executor' do
|
|
207
208
|
end
|
208
209
|
|
209
210
|
context 'when asked to execute and block' do
|
210
|
-
it 'should raise a
|
211
|
+
it 'should raise a Timeout::Error if a timeout is specified and the process does not exit before' do
|
211
212
|
test_command = "/bin/sleep"
|
212
213
|
test_params = ["5"]
|
213
214
|
iut = SHExecutor::Executor.new({:timeout => 1, :wait_for_completion => true, :application_path => test_command, :params => test_params})
|
@@ -219,6 +220,16 @@ describe 'Executor' do
|
|
219
220
|
expect(after - before).to be < 2.1
|
220
221
|
end
|
221
222
|
|
223
|
+
it 'should kill the subprocess when a TimeoutError is raised' do
|
224
|
+
test_command = "/bin/sleep"
|
225
|
+
test_params = ["2"]
|
226
|
+
iut = SHExecutor::Executor.new({:timeout => 1, :wait_for_completion => true, :application_path => test_command, :params => test_params})
|
227
|
+
expect(Process).to receive(:kill)
|
228
|
+
expect {
|
229
|
+
iut.execute
|
230
|
+
}.to raise_error(Timeout::Error, "execution expired")
|
231
|
+
end
|
232
|
+
|
222
233
|
it 'should call run_process with the command and parameters specified' do
|
223
234
|
test_command = "/bin/ls"
|
224
235
|
test_params = ["/tmp/"]
|