childprocess 0.2.2 → 0.2.3
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.
- data/.travis.yml +4 -0
- data/README.md +2 -1
- data/lib/childprocess.rb +0 -4
- data/lib/childprocess/abstract_process.rb +12 -6
- data/lib/childprocess/errors.rb +1 -0
- data/lib/childprocess/jruby/process.rb +8 -4
- data/lib/childprocess/unix/process.rb +6 -0
- data/lib/childprocess/version.rb +1 -1
- data/lib/childprocess/windows/constants.rb +2 -0
- data/lib/childprocess/windows/functions.rb +39 -4
- data/lib/childprocess/windows/process.rb +4 -3
- data/spec/childprocess_spec.rb +44 -26
- metadata +7 -7
- data/lib/childprocess/ironruby.rb +0 -6
- data/lib/childprocess/ironruby/process.rb +0 -7
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -7,6 +7,8 @@ external programs running in the background on any Ruby / OS combination.
|
|
7
7
|
The code originated in the selenium-webdriver gem, but should prove useful as
|
8
8
|
a standalone library.
|
9
9
|
|
10
|
+
[](http://travis-ci.org/jarib/childprocess)
|
11
|
+
|
10
12
|
Usage
|
11
13
|
-----
|
12
14
|
```ruby
|
@@ -36,7 +38,6 @@ How the process is launched and killed depends on the platform:
|
|
36
38
|
* Unix : fork + exec
|
37
39
|
* Windows : CreateProcess and friends
|
38
40
|
* JRuby : java.lang.{Process,ProcessBuilder}
|
39
|
-
* IronRuby : System.Diagnostics.Process
|
40
41
|
|
41
42
|
Note on Patches/Pull Requests
|
42
43
|
-----------------------------
|
data/lib/childprocess.rb
CHANGED
@@ -7,16 +7,12 @@ module ChildProcess
|
|
7
7
|
autoload :Unix, 'childprocess/unix'
|
8
8
|
autoload :Windows, 'childprocess/windows'
|
9
9
|
autoload :JRuby, 'childprocess/jruby'
|
10
|
-
autoload :IronRuby, 'childprocess/ironruby'
|
11
10
|
|
12
11
|
class << self
|
13
|
-
|
14
12
|
def new(*args)
|
15
13
|
case platform
|
16
14
|
when :jruby
|
17
15
|
JRuby::Process.new(args)
|
18
|
-
when :ironruby
|
19
|
-
IronRuby::Process.new(args)
|
20
16
|
when :windows
|
21
17
|
Windows::Process.new(args)
|
22
18
|
when :macosx, :linux, :unix, :cygwin
|
@@ -14,6 +14,11 @@ module ChildProcess
|
|
14
14
|
#
|
15
15
|
attr_accessor :duplex
|
16
16
|
|
17
|
+
#
|
18
|
+
# Modify the child's environment variables
|
19
|
+
#
|
20
|
+
attr_reader :environment
|
21
|
+
|
17
22
|
#
|
18
23
|
# Create a new process with the given args.
|
19
24
|
#
|
@@ -22,12 +27,13 @@ module ChildProcess
|
|
22
27
|
#
|
23
28
|
|
24
29
|
def initialize(args)
|
25
|
-
@args
|
26
|
-
@started
|
27
|
-
@exit_code
|
28
|
-
@io
|
29
|
-
@detach
|
30
|
-
@duplex
|
30
|
+
@args = args
|
31
|
+
@started = false
|
32
|
+
@exit_code = nil
|
33
|
+
@io = nil
|
34
|
+
@detach = false
|
35
|
+
@duplex = false
|
36
|
+
@environment = {}
|
31
37
|
end
|
32
38
|
|
33
39
|
#
|
data/lib/childprocess/errors.rb
CHANGED
@@ -52,12 +52,11 @@ module ChildProcess
|
|
52
52
|
|
53
53
|
def launch_process(&blk)
|
54
54
|
pb = java.lang.ProcessBuilder.new(@args)
|
55
|
-
pb.directory(java.io.File.new(Dir.pwd))
|
56
|
-
env = pb.environment
|
57
|
-
ENV.each { |k,v| env.put(k, v) }
|
58
55
|
|
59
|
-
|
56
|
+
pb.directory java.io.File.new(Dir.pwd)
|
57
|
+
set_env pb.environment
|
60
58
|
|
59
|
+
@process = pb.start
|
61
60
|
setup_io
|
62
61
|
end
|
63
62
|
|
@@ -87,6 +86,11 @@ module ChildProcess
|
|
87
86
|
Thread.new { Redirector.new(input, output).run }
|
88
87
|
end
|
89
88
|
|
89
|
+
def set_env(env)
|
90
|
+
ENV.each { |k,v| env.put(k, v) } # not sure why this is needed
|
91
|
+
@environment.each { |k,v| env.put(k.to_s, v.to_s) }
|
92
|
+
end
|
93
|
+
|
90
94
|
end # Process
|
91
95
|
end # JRuby
|
92
96
|
end # ChildProcess
|
@@ -81,6 +81,8 @@ module ChildProcess
|
|
81
81
|
end
|
82
82
|
|
83
83
|
@pid = fork {
|
84
|
+
set_env
|
85
|
+
|
84
86
|
STDOUT.reopen(stdout || "/dev/null")
|
85
87
|
STDERR.reopen(stderr || "/dev/null")
|
86
88
|
|
@@ -100,6 +102,10 @@ module ChildProcess
|
|
100
102
|
::Process.detach(@pid) if detach?
|
101
103
|
end
|
102
104
|
|
105
|
+
def set_env
|
106
|
+
@environment.each { |k, v| ENV[k.to_s] = v.to_s }
|
107
|
+
end
|
108
|
+
|
103
109
|
end # Process
|
104
110
|
end # Unix
|
105
111
|
end # ChildProcess
|
data/lib/childprocess/version.rb
CHANGED
@@ -4,6 +4,7 @@ module ChildProcess
|
|
4
4
|
|
5
5
|
def self.create_proc(cmd, opts = {})
|
6
6
|
cmd_ptr = FFI::MemoryPointer.from_string cmd
|
7
|
+
env_ptr = environment_pointer_for(opts[:environment])
|
7
8
|
|
8
9
|
flags = 0
|
9
10
|
inherit = !!opts[:inherit]
|
@@ -25,7 +26,7 @@ module ChildProcess
|
|
25
26
|
if opts[:duplex]
|
26
27
|
read_pipe_ptr = FFI::MemoryPointer.new(:pointer)
|
27
28
|
write_pipe_ptr = FFI::MemoryPointer.new(:pointer)
|
28
|
-
sa
|
29
|
+
sa = SecurityAttributes.new(:inherit => true)
|
29
30
|
|
30
31
|
ok = create_pipe(read_pipe_ptr, write_pipe_ptr, sa, 0)
|
31
32
|
ok or raise Error, last_error_message
|
@@ -36,7 +37,19 @@ module ChildProcess
|
|
36
37
|
si[:hStdInput] = read_pipe
|
37
38
|
end
|
38
39
|
|
39
|
-
ok = create_process(
|
40
|
+
ok = create_process(
|
41
|
+
nil, # application name
|
42
|
+
cmd_ptr, # command line
|
43
|
+
nil, # process attributes
|
44
|
+
nil, # thread attributes
|
45
|
+
inherit, # inherit handles
|
46
|
+
flags, # creation flags
|
47
|
+
env_ptr, # environment
|
48
|
+
nil, # current directory
|
49
|
+
si, # startup info
|
50
|
+
pi # process info
|
51
|
+
)
|
52
|
+
|
40
53
|
ok or raise Error, last_error_message
|
41
54
|
|
42
55
|
close_handle pi[:hProcess]
|
@@ -60,13 +73,14 @@ module ChildProcess
|
|
60
73
|
nil, errnum, 0, buf, buf.size, nil
|
61
74
|
)
|
62
75
|
|
63
|
-
buf.read_string(size).strip
|
76
|
+
str = buf.read_string(size).strip
|
77
|
+
"#{str} (#{errnum})"
|
64
78
|
end
|
65
79
|
|
66
80
|
def self.handle_for(fd_or_io)
|
67
81
|
case fd_or_io
|
68
82
|
when IO
|
69
|
-
handle = get_osfhandle(
|
83
|
+
handle = get_osfhandle(fd_or_io.fileno)
|
70
84
|
when Fixnum
|
71
85
|
handle = get_osfhandle(fd_or_io)
|
72
86
|
else
|
@@ -113,6 +127,27 @@ module ChildProcess
|
|
113
127
|
close_handle proc
|
114
128
|
end
|
115
129
|
|
130
|
+
def self.environment_pointer_for(env)
|
131
|
+
return unless env.kind_of?(Hash) && env.any?
|
132
|
+
|
133
|
+
strings = ENV.map { |k,v| "#{k}=#{v}\0" }
|
134
|
+
env.each do |key, value|
|
135
|
+
if key.include?("=")
|
136
|
+
raise InvalidEnvironmentVariableName, key
|
137
|
+
end
|
138
|
+
|
139
|
+
strings << "#{key}=#{value}\0"
|
140
|
+
end
|
141
|
+
|
142
|
+
strings << "\0" # terminate the env block
|
143
|
+
env_str = strings.join
|
144
|
+
|
145
|
+
ptr = FFI::MemoryPointer.new(:long, env_str.bytesize)
|
146
|
+
ptr.write_bytes env_str, 0, env_str.bytesize
|
147
|
+
|
148
|
+
ptr
|
149
|
+
end
|
150
|
+
|
116
151
|
#
|
117
152
|
# BOOL WINAPI CreateProcess(
|
118
153
|
# __in_opt LPCTSTR lpApplicationName,
|
@@ -42,9 +42,10 @@ module ChildProcess
|
|
42
42
|
|
43
43
|
def launch_process
|
44
44
|
opts = {
|
45
|
-
:inherit
|
46
|
-
:detach
|
47
|
-
:duplex
|
45
|
+
:inherit => false,
|
46
|
+
:detach => detach?,
|
47
|
+
:duplex => duplex?,
|
48
|
+
:environment => (@environment unless @environment.empty?)
|
48
49
|
}
|
49
50
|
|
50
51
|
if @io
|
data/spec/childprocess_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require File.expand_path('../spec_helper', __FILE__)
|
2
4
|
|
3
5
|
describe ChildProcess do
|
@@ -49,6 +51,39 @@ describe ChildProcess do
|
|
49
51
|
end
|
50
52
|
end
|
51
53
|
|
54
|
+
it "can override env vars only for the current process" do
|
55
|
+
Tempfile.open("env-spec") do |file|
|
56
|
+
process = write_env(file.path)
|
57
|
+
process.environment['CHILD_ONLY'] = '1'
|
58
|
+
process.start
|
59
|
+
|
60
|
+
ENV['CHILD_ONLY'].should be_nil
|
61
|
+
|
62
|
+
process.poll_for_exit(EXIT_TIMEOUT)
|
63
|
+
file.rewind
|
64
|
+
|
65
|
+
child_env = eval(file.read)
|
66
|
+
child_env['CHILD_ONLY'].should == '1'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
it "inherits the parent's env vars also when some are overridden" do
|
71
|
+
Tempfile.open("env-spec") do |file|
|
72
|
+
with_env('INHERITED' => 'yes', 'CHILD_ONLY' => 'no') do
|
73
|
+
process = write_env(file.path)
|
74
|
+
process.environment['CHILD_ONLY'] = 'yes'
|
75
|
+
|
76
|
+
process.start
|
77
|
+
process.poll_for_exit(EXIT_TIMEOUT)
|
78
|
+
file.rewind
|
79
|
+
child_env = eval(file.read)
|
80
|
+
|
81
|
+
child_env['INHERITED'].should == 'yes'
|
82
|
+
child_env['CHILD_ONLY'].should == 'yes'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
52
87
|
it "passes arguments to the child" do
|
53
88
|
args = ["foo", "bar"]
|
54
89
|
|
@@ -137,32 +172,15 @@ describe ChildProcess do
|
|
137
172
|
end
|
138
173
|
|
139
174
|
it "preserves Dir.pwd in the child" do
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
begin
|
150
|
-
out = Tempfile.new("dir-spec-out")
|
151
|
-
|
152
|
-
process.io.stdout = out
|
153
|
-
process.io.stderr = out
|
154
|
-
|
155
|
-
process.start
|
156
|
-
process.poll_for_exit(EXIT_TIMEOUT)
|
157
|
-
|
158
|
-
out.rewind
|
159
|
-
out.read.should == "#{path}\n"
|
160
|
-
ensure
|
161
|
-
out.close
|
162
|
-
end
|
163
|
-
end
|
164
|
-
ensure
|
165
|
-
Dir.rmdir(path) if File.exist?(path)
|
175
|
+
Tempfile.open("dir-spec-out") do |file|
|
176
|
+
process = ruby("print Dir.pwd")
|
177
|
+
process.io.stdout = process.io.stderr = file
|
178
|
+
|
179
|
+
process.start
|
180
|
+
process.poll_for_exit(EXIT_TIMEOUT)
|
181
|
+
|
182
|
+
file.rewind
|
183
|
+
file.read.should == Dir.pwd
|
166
184
|
end
|
167
185
|
end
|
168
186
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: childprocess
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 3
|
10
|
+
version: 0.2.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jari Bakken
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-11-27 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: rspec
|
@@ -92,6 +92,7 @@ files:
|
|
92
92
|
- .document
|
93
93
|
- .gitignore
|
94
94
|
- .rspec
|
95
|
+
- .travis.yml
|
95
96
|
- Gemfile
|
96
97
|
- LICENSE
|
97
98
|
- README.md
|
@@ -101,8 +102,6 @@ files:
|
|
101
102
|
- lib/childprocess/abstract_io.rb
|
102
103
|
- lib/childprocess/abstract_process.rb
|
103
104
|
- lib/childprocess/errors.rb
|
104
|
-
- lib/childprocess/ironruby.rb
|
105
|
-
- lib/childprocess/ironruby/process.rb
|
106
105
|
- lib/childprocess/jruby.rb
|
107
106
|
- lib/childprocess/jruby/io.rb
|
108
107
|
- lib/childprocess/jruby/process.rb
|
@@ -155,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
154
|
requirements: []
|
156
155
|
|
157
156
|
rubyforge_project: childprocess
|
158
|
-
rubygems_version: 1.8.
|
157
|
+
rubygems_version: 1.8.10
|
159
158
|
signing_key:
|
160
159
|
specification_version: 3
|
161
160
|
summary: This gem aims at being a simple and reliable solution for controlling external programs running in the background on any Ruby / OS combination.
|
@@ -167,3 +166,4 @@ test_files:
|
|
167
166
|
- spec/spec_helper.rb
|
168
167
|
- spec/unix_spec.rb
|
169
168
|
- spec/windows_spec.rb
|
169
|
+
has_rdoc:
|