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 ADDED
@@ -0,0 +1,4 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
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 = args
26
- @started = false
27
- @exit_code = nil
28
- @io = nil
29
- @detach = false
30
- @duplex = false
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
  #
@@ -2,4 +2,5 @@ module ChildProcess
2
2
  class Error < StandardError; end
3
3
  class TimeoutError < StandardError; end
4
4
  class SubclassResponsibility < StandardError; end
5
+ class InvalidEnvironmentVariableName < StandardError; end
5
6
  end
@@ -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
- @process = pb.start
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
@@ -1,3 +1,3 @@
1
1
  module ChildProcess
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.3"
3
3
  end
@@ -25,6 +25,8 @@ module ChildProcess::Windows
25
25
 
26
26
  DUPLICATE_SAME_ACCESS = 0x00000002
27
27
 
28
+ CREATE_UNICODE_ENVIRONMENT = 0x00000400
29
+
28
30
  module Lib
29
31
  enum :wait_status, [ :wait_object_0, 0,
30
32
  :wait_timeout, 0x102,
@@ -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 = SecurityAttributes.new(:inherit => true)
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(nil, cmd_ptr, nil, nil, inherit, flags, nil, nil, si, pi)
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(fd.fileno)
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 => false,
46
- :detach => detach?,
47
- :duplex => duplex?
45
+ :inherit => false,
46
+ :detach => detach?,
47
+ :duplex => duplex?,
48
+ :environment => (@environment unless @environment.empty?)
48
49
  }
49
50
 
50
51
  if @io
@@ -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
- require 'pathname'
141
- begin
142
- path = nil
143
- Tempfile.open("dir-spec") {|tf| path = tf.path }
144
- path = Pathname.new(path).realpath.to_s
145
- File.unlink(path)
146
- Dir.mkdir(path)
147
- Dir.chdir(path) do
148
- process = ruby("puts Dir.pwd")
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: 19
4
+ hash: 17
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 2
10
- version: 0.2.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-08-26 00:00:00 Z
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.9
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:
@@ -1,6 +0,0 @@
1
- module ChildProcess
2
- module IronRuby
3
- end
4
- end
5
-
6
- require "childprocess/ironruby/process"
@@ -1,7 +0,0 @@
1
- module ChildProcess
2
- module IronRuby
3
- class Process < AbstractProcess
4
-
5
- end # Process
6
- end # IronRuby
7
- end # ChildProcess