childprocess 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://secure.travis-ci.org/jarib/childprocess.png)](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:
|