childprocess 0.5.3 → 0.5.4
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/.travis.yml +2 -2
- data/README.md +11 -0
- data/childprocess.gemspec +1 -1
- data/lib/childprocess/jruby/process.rb +7 -2
- data/lib/childprocess/version.rb +1 -1
- data/spec/abstract_io_spec.rb +2 -2
- data/spec/childprocess_spec.rb +25 -24
- data/spec/io_spec.rb +13 -13
- data/spec/jruby_spec.rb +2 -2
- data/spec/pid_behavior.rb +1 -1
- data/spec/spec_helper.rb +2 -2
- data/spec/unix_spec.rb +14 -14
- data/spec/windows_spec.rb +2 -2
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77e7009c5202bfecb17e331b56d15c79b92d33b0
|
4
|
+
data.tar.gz: 343d119d1130d05fe395d5ee2631aeb1a50866a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f84deda774210ec0d133c08095389c212770ed6afa58b37bddef82a7ca0513e76fcdcd3aaeb0ea4ca0e878329c160a7d9ba4770f19faceb472d9dbe9333cc45a
|
7
|
+
data.tar.gz: 7ded6c7fa7364c4c5fe423c7a06e671dce947e6290e62fb3d4be7d62554be1339e0e706159ee9fc4350c0a3a1fc4f5f608122c2c281780485793523d42dcfb5f
|
data/.travis.yml
CHANGED
@@ -6,8 +6,8 @@ rvm:
|
|
6
6
|
- 2.1.0
|
7
7
|
- ruby-head
|
8
8
|
env:
|
9
|
-
- CHILDPROCESS_POSIX_SPAWN=true
|
10
|
-
- CHILDPROCESS_POSIX_SPAWN=false
|
9
|
+
- CHILDPROCESS_POSIX_SPAWN=true CHILDPROCESS_UNSET=should-be-unset
|
10
|
+
- CHILDPROCESS_POSIX_SPAWN=false CHILDPROCESS_UNSET=should-be-unset
|
11
11
|
matrix:
|
12
12
|
allow_failures:
|
13
13
|
- rvm: rbx
|
data/README.md
CHANGED
@@ -142,6 +142,17 @@ process.detach = true
|
|
142
142
|
process.start
|
143
143
|
```
|
144
144
|
|
145
|
+
#### Invoking a shell
|
146
|
+
|
147
|
+
As opposed to `Kernel#system`, `Kernel#exec` et al., ChildProcess will not automatically execute your command in a shell (like `/bin/sh` or `cmd.exe`) depending on the arguments.
|
148
|
+
This means that if you try to execute e.g. gem executables (like `bundle` or `gem`) or Windows executables (with `.com` or `.bat` extensions) you may see a `ChildProcess::LaunchError`.
|
149
|
+
You can work around this by being explicit about what interpreter to invoke:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
ChildProcess.build("cmd.exe", "/c", "bundle")
|
153
|
+
ChildProcess.build("ruby", "-S", "bundle")
|
154
|
+
```
|
155
|
+
|
145
156
|
# Implementation
|
146
157
|
|
147
158
|
How the process is launched and killed depends on the platform:
|
data/childprocess.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.test_files = `git ls-files -- spec/*`.split("\n")
|
20
20
|
s.require_paths = ["lib"]
|
21
21
|
|
22
|
-
s.add_development_dependency "rspec", "
|
22
|
+
s.add_development_dependency "rspec", "~> 3.0.0"
|
23
23
|
s.add_development_dependency "yard", ">= 0"
|
24
24
|
s.add_development_dependency "rake", "~> 0.9.2"
|
25
25
|
s.add_development_dependency 'coveralls'
|
@@ -21,7 +21,8 @@ module ChildProcess
|
|
21
21
|
stop_pumps
|
22
22
|
|
23
23
|
true
|
24
|
-
rescue java.lang.IllegalThreadStateException
|
24
|
+
rescue java.lang.IllegalThreadStateException => ex
|
25
|
+
log(ex.class => ex.message)
|
25
26
|
false
|
26
27
|
ensure
|
27
28
|
log(:exit_code => @exit_code)
|
@@ -113,7 +114,11 @@ module ChildProcess
|
|
113
114
|
|
114
115
|
def set_env(env)
|
115
116
|
ENV.to_hash.merge(@environment).each do |k,v|
|
116
|
-
|
117
|
+
if v
|
118
|
+
env.put(k.to_s, v.to_s)
|
119
|
+
else
|
120
|
+
env.remove(k.to_s) if env.key?(k.to_s)
|
121
|
+
end
|
117
122
|
end
|
118
123
|
end
|
119
124
|
|
data/lib/childprocess/version.rb
CHANGED
data/spec/abstract_io_spec.rb
CHANGED
data/spec/childprocess_spec.rb
CHANGED
@@ -6,8 +6,8 @@ describe ChildProcess do
|
|
6
6
|
it "returns self when started" do
|
7
7
|
process = sleeping_ruby
|
8
8
|
|
9
|
-
process.start.
|
10
|
-
process.
|
9
|
+
expect(process.start).to eq process
|
10
|
+
expect(process).to be_alive
|
11
11
|
end
|
12
12
|
|
13
13
|
# We can't detect failure to execve() when using posix_spawn() on Linux
|
@@ -30,35 +30,35 @@ describe ChildProcess do
|
|
30
30
|
process = exit_with(1).start
|
31
31
|
process.wait
|
32
32
|
|
33
|
-
process.
|
33
|
+
expect(process).to be_crashed
|
34
34
|
end
|
35
35
|
|
36
36
|
it "knows if the process didn't crash" do
|
37
37
|
process = exit_with(0).start
|
38
38
|
process.wait
|
39
39
|
|
40
|
-
process.
|
40
|
+
expect(process).to_not be_crashed
|
41
41
|
end
|
42
42
|
|
43
43
|
it "can wait for a process to finish" do
|
44
44
|
process = exit_with(0).start
|
45
45
|
return_value = process.wait
|
46
46
|
|
47
|
-
process.
|
48
|
-
return_value.
|
47
|
+
expect(process).to_not be_alive
|
48
|
+
expect(return_value).to eq 0
|
49
49
|
end
|
50
50
|
|
51
51
|
it 'ignores #wait if process already finished' do
|
52
52
|
process = exit_with(0).start
|
53
53
|
sleep 0.01 until process.exited?
|
54
54
|
|
55
|
-
process.wait.
|
55
|
+
expect(process.wait).to eql 0
|
56
56
|
end
|
57
57
|
|
58
58
|
it "escalates if TERM is ignored" do
|
59
59
|
process = ignored('TERM').start
|
60
60
|
process.stop
|
61
|
-
process.
|
61
|
+
expect(process).to be_exited
|
62
62
|
end
|
63
63
|
|
64
64
|
it "accepts a timeout argument to #stop" do
|
@@ -74,7 +74,7 @@ describe ChildProcess do
|
|
74
74
|
end
|
75
75
|
|
76
76
|
child_env = eval rewind_and_read(file)
|
77
|
-
child_env['INHERITED'].
|
77
|
+
expect(child_env['INHERITED']).to eql 'yes'
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
@@ -84,12 +84,12 @@ describe ChildProcess do
|
|
84
84
|
process.environment['CHILD_ONLY'] = '1'
|
85
85
|
process.start
|
86
86
|
|
87
|
-
ENV['CHILD_ONLY'].
|
87
|
+
expect(ENV['CHILD_ONLY']).to be_nil
|
88
88
|
|
89
89
|
process.wait
|
90
90
|
|
91
91
|
child_env = eval rewind_and_read(file)
|
92
|
-
child_env['CHILD_ONLY'].
|
92
|
+
expect(child_env['CHILD_ONLY']).to eql '1'
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
@@ -104,8 +104,8 @@ describe ChildProcess do
|
|
104
104
|
|
105
105
|
child_env = eval rewind_and_read(file)
|
106
106
|
|
107
|
-
child_env['INHERITED'].
|
108
|
-
child_env['CHILD_ONLY'].
|
107
|
+
expect(child_env['INHERITED']).to eq 'yes'
|
108
|
+
expect(child_env['CHILD_ONLY']).to eq 'yes'
|
109
109
|
end
|
110
110
|
end
|
111
111
|
end
|
@@ -120,7 +120,7 @@ describe ChildProcess do
|
|
120
120
|
process.wait
|
121
121
|
|
122
122
|
child_env = eval rewind_and_read(file)
|
123
|
-
child_env.
|
123
|
+
expect(child_env).to_not have_key('CHILDPROCESS_UNSET')
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
@@ -132,12 +132,13 @@ describe ChildProcess do
|
|
132
132
|
process = write_argv(file.path, *args).start
|
133
133
|
process.wait
|
134
134
|
|
135
|
-
rewind_and_read(file).
|
135
|
+
expect(rewind_and_read(file)).to eql args.inspect
|
136
136
|
end
|
137
137
|
end
|
138
138
|
|
139
139
|
it "lets a detached child live on" do
|
140
140
|
pending "how do we spec this?"
|
141
|
+
fail
|
141
142
|
end
|
142
143
|
|
143
144
|
it "preserves Dir.pwd in the child" do
|
@@ -153,7 +154,7 @@ describe ChildProcess do
|
|
153
154
|
|
154
155
|
process.wait
|
155
156
|
|
156
|
-
rewind_and_read(file).
|
157
|
+
expect(rewind_and_read(file)).to eq expected_dir
|
157
158
|
end
|
158
159
|
end
|
159
160
|
|
@@ -164,7 +165,7 @@ describe ChildProcess do
|
|
164
165
|
process = write_argv(file.path, *args).start
|
165
166
|
process.wait
|
166
167
|
|
167
|
-
rewind_and_read(file).
|
168
|
+
expect(rewind_and_read(file)).to eq args.inspect
|
168
169
|
end
|
169
170
|
end
|
170
171
|
|
@@ -172,14 +173,14 @@ describe ChildProcess do
|
|
172
173
|
path = File.expand_path('foo bar')
|
173
174
|
|
174
175
|
with_executable_at(path) do |proc|
|
175
|
-
proc.start.
|
176
|
-
proc.
|
176
|
+
expect(proc.start).to eq proc
|
177
|
+
expect(proc).to be_alive
|
177
178
|
end
|
178
179
|
end
|
179
180
|
|
180
181
|
it "times out when polling for exit" do
|
181
182
|
process = sleeping_ruby.start
|
182
|
-
|
183
|
+
expect { process.poll_for_exit(0.1) }.to raise_error(ChildProcess::TimeoutError)
|
183
184
|
end
|
184
185
|
|
185
186
|
it "can change working directory" do
|
@@ -196,10 +197,10 @@ describe ChildProcess do
|
|
196
197
|
process.start
|
197
198
|
process.wait
|
198
199
|
|
199
|
-
rewind_and_read(file).
|
200
|
+
expect(rewind_and_read(file)).to eq dir
|
200
201
|
end
|
201
202
|
|
202
|
-
Dir.pwd.
|
203
|
+
expect(Dir.pwd).to eq orig_pwd
|
203
204
|
}
|
204
205
|
end
|
205
206
|
|
@@ -214,7 +215,7 @@ describe ChildProcess do
|
|
214
215
|
end
|
215
216
|
|
216
217
|
process.stop
|
217
|
-
wait_until(3) { alive?(pid).
|
218
|
+
wait_until(3) { expect(alive?(pid)).to eql(false) }
|
218
219
|
end
|
219
220
|
end
|
220
221
|
|
@@ -223,7 +224,7 @@ describe ChildProcess do
|
|
223
224
|
threads = []
|
224
225
|
|
225
226
|
threads << Thread.new { sleeping_ruby(1).start.wait }
|
226
|
-
threads << Thread.new(time) { (Time.now - time).
|
227
|
+
threads << Thread.new(time) { expect(Time.now - time).to be < 0.5 }
|
227
228
|
|
228
229
|
threads.each { |t| t.join }
|
229
230
|
end
|
data/spec/io_spec.rb
CHANGED
@@ -17,11 +17,11 @@ describe ChildProcess do
|
|
17
17
|
process.io.stderr = err
|
18
18
|
|
19
19
|
process.start
|
20
|
-
process.io.stdin.
|
20
|
+
expect(process.io.stdin).to be_nil
|
21
21
|
process.wait
|
22
22
|
|
23
|
-
rewind_and_read(out).
|
24
|
-
rewind_and_read(err).
|
23
|
+
expect(rewind_and_read(out)).to eq "0\n"
|
24
|
+
expect(rewind_and_read(err)).to eq "1\n"
|
25
25
|
ensure
|
26
26
|
out.close
|
27
27
|
err.close
|
@@ -44,7 +44,7 @@ describe ChildProcess do
|
|
44
44
|
process.start
|
45
45
|
process.wait
|
46
46
|
|
47
|
-
rewind_and_read(out).
|
47
|
+
expect(rewind_and_read(out)).to eq "0\n"
|
48
48
|
ensure
|
49
49
|
out.close
|
50
50
|
end
|
@@ -61,7 +61,7 @@ describe ChildProcess do
|
|
61
61
|
process.start
|
62
62
|
process.wait
|
63
63
|
|
64
|
-
rewind_and_read(out).
|
64
|
+
expect(rewind_and_read(out)).to eq "hello\n"
|
65
65
|
ensure
|
66
66
|
out.close
|
67
67
|
end
|
@@ -84,7 +84,7 @@ describe ChildProcess do
|
|
84
84
|
|
85
85
|
process.poll_for_exit(exit_timeout)
|
86
86
|
|
87
|
-
rewind_and_read(out).
|
87
|
+
expect(rewind_and_read(out)).to eq "hello world\n"
|
88
88
|
ensure
|
89
89
|
out.close
|
90
90
|
end
|
@@ -108,23 +108,23 @@ describe ChildProcess do
|
|
108
108
|
|
109
109
|
stdin.puts "hello"
|
110
110
|
stdin.flush
|
111
|
-
wait_until { rewind_and_read(out_receiver).
|
111
|
+
wait_until { expect(rewind_and_read(out_receiver)).to match(/\Ahello\r?\n\z/m) }
|
112
112
|
|
113
113
|
stdin.putc "n"
|
114
114
|
stdin.flush
|
115
|
-
wait_until { rewind_and_read(out_receiver).
|
115
|
+
wait_until { expect(rewind_and_read(out_receiver)).to match(/\Ahello\r?\nn\z/m) }
|
116
116
|
|
117
117
|
stdin.print "e"
|
118
118
|
stdin.flush
|
119
|
-
wait_until { rewind_and_read(out_receiver).
|
119
|
+
wait_until { expect(rewind_and_read(out_receiver)).to match(/\Ahello\r?\nne\z/m) }
|
120
120
|
|
121
121
|
stdin.printf "w"
|
122
122
|
stdin.flush
|
123
|
-
wait_until { rewind_and_read(out_receiver).
|
123
|
+
wait_until { expect(rewind_and_read(out_receiver)).to match(/\Ahello\r?\nnew\z/m) }
|
124
124
|
|
125
125
|
stdin.write "\nworld\n"
|
126
126
|
stdin.flush
|
127
|
-
wait_until { rewind_and_read(out_receiver).
|
127
|
+
wait_until { expect(rewind_and_read(out_receiver)).to match(/\Ahello\r?\nnew\r?\nworld\r?\n\z/m) }
|
128
128
|
|
129
129
|
stdin.close
|
130
130
|
process.poll_for_exit(exit_timeout)
|
@@ -168,7 +168,7 @@ describe ChildProcess do
|
|
168
168
|
out = stdout.read
|
169
169
|
err = stderr.read
|
170
170
|
|
171
|
-
[out, err].
|
171
|
+
expect([out, err]).to eq %w[stdout stderr]
|
172
172
|
end
|
173
173
|
|
174
174
|
it "can set close-on-exec when IO is inherited" do
|
@@ -199,7 +199,7 @@ describe ChildProcess do
|
|
199
199
|
process.start
|
200
200
|
process.wait
|
201
201
|
|
202
|
-
rewind_and_read(out).size.
|
202
|
+
expect(rewind_and_read(out).size).to eq 3000
|
203
203
|
ensure
|
204
204
|
out.close
|
205
205
|
end
|
data/spec/jruby_spec.rb
CHANGED
@@ -6,7 +6,7 @@ if ChildProcess.jruby? && !ChildProcess.windows?
|
|
6
6
|
let(:io) { ChildProcess::JRuby::IO.new }
|
7
7
|
|
8
8
|
it "raises an ArgumentError if given IO does not respond to :to_outputstream" do
|
9
|
-
|
9
|
+
expect { io.stdout = nil }.to raise_error(ArgumentError)
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -17,7 +17,7 @@ if ChildProcess.jruby? && !ChildProcess.windows?
|
|
17
17
|
it "raises an error when trying to access the child's pid" do
|
18
18
|
process = exit_with(0)
|
19
19
|
process.start
|
20
|
-
|
20
|
+
expect { process.pid }.to raise_error(NotImplementedError)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
data/spec/pid_behavior.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -128,9 +128,9 @@ module ChildProcessSpecHelper
|
|
128
128
|
def with_executable_at(path, &blk)
|
129
129
|
if ChildProcess.os == :windows
|
130
130
|
path << ".cmd"
|
131
|
-
content = "@echo foo"
|
131
|
+
content = "#{RUBY} -e 'sleep 10' \n @echo foo"
|
132
132
|
else
|
133
|
-
content = "#!/bin/sh\necho foo"
|
133
|
+
content = "#!/bin/sh\nsleep 10\necho foo"
|
134
134
|
end
|
135
135
|
|
136
136
|
File.open(path, 'w', 0744) { |io| io << content }
|
data/spec/unix_spec.rb
CHANGED
@@ -9,29 +9,29 @@ if ChildProcess.unix? && !ChildProcess.jruby? && !ChildProcess.posix_spawn?
|
|
9
9
|
it "handles ECHILD race condition where process dies between timeout and KILL" do
|
10
10
|
process = sleeping_ruby
|
11
11
|
|
12
|
-
process.
|
13
|
-
process.
|
14
|
-
process.
|
15
|
-
process.
|
12
|
+
allow(process).to receive(:fork).and_return('fakepid')
|
13
|
+
allow(process).to receive(:send_term)
|
14
|
+
allow(process).to receive(:poll_for_exit).and_raise(ChildProcess::TimeoutError)
|
15
|
+
allow(process).to receive(:send_kill).and_raise(Errno::ECHILD.new)
|
16
16
|
|
17
17
|
process.start
|
18
|
-
|
18
|
+
expect { process.stop }.not_to raise_error
|
19
19
|
|
20
|
-
process.
|
20
|
+
allow(process).to receive(:alive?).and_return(false)
|
21
21
|
end
|
22
22
|
|
23
23
|
it "handles ESRCH race condition where process dies between timeout and KILL" do
|
24
24
|
process = sleeping_ruby
|
25
25
|
|
26
|
-
process.
|
27
|
-
process.
|
28
|
-
process.
|
29
|
-
process.
|
26
|
+
allow(process).to receive(:fork).and_return('fakepid')
|
27
|
+
allow(process).to receive(:send_term)
|
28
|
+
allow(process).to receive(:poll_for_exit).and_raise(ChildProcess::TimeoutError)
|
29
|
+
allow(process).to receive(:send_kill).and_raise(Errno::ESRCH.new)
|
30
30
|
|
31
31
|
process.start
|
32
|
-
|
32
|
+
expect { process.stop }.not_to raise_error
|
33
33
|
|
34
|
-
process.
|
34
|
+
allow(process).to receive(:alive?).and_return(false)
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -39,14 +39,14 @@ if ChildProcess.unix? && !ChildProcess.jruby? && !ChildProcess.posix_spawn?
|
|
39
39
|
let(:io) { ChildProcess::Unix::IO.new }
|
40
40
|
|
41
41
|
it "raises an ArgumentError if given IO does not respond to :to_io" do
|
42
|
-
|
42
|
+
expect { io.stdout = nil }.to raise_error(ArgumentError, /to respond to :to_io/)
|
43
43
|
end
|
44
44
|
|
45
45
|
it "raises a TypeError if #to_io does not return an IO" do
|
46
46
|
fake_io = Object.new
|
47
47
|
def fake_io.to_io() StringIO.new end
|
48
48
|
|
49
|
-
|
49
|
+
expect { io.stdout = fake_io }.to raise_error(TypeError, /expected IO, got/)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
data/spec/windows_spec.rb
CHANGED
@@ -10,14 +10,14 @@ if ChildProcess.windows?
|
|
10
10
|
let(:io) { ChildProcess::Windows::IO.new }
|
11
11
|
|
12
12
|
it "raises an ArgumentError if given IO does not respond to :fileno" do
|
13
|
-
|
13
|
+
expect { io.stdout = nil }.to raise_error(ArgumentError, /must have :fileno or :to_io/)
|
14
14
|
end
|
15
15
|
|
16
16
|
it "raises an ArgumentError if the #to_io does not return an IO " do
|
17
17
|
fake_io = Object.new
|
18
18
|
def fake_io.to_io() StringIO.new end
|
19
19
|
|
20
|
-
|
20
|
+
expect { io.stdout = fake_io }.to raise_error(ArgumentError, /must have :fileno or :to_io/)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: childprocess
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jari Bakken
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 3.0.0
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 3.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: yard
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|