right_popen 1.0.11-x86-mswin32-60 → 1.0.17-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,14 +1,37 @@
1
1
  require 'rubygems'
2
+ require 'bundler'
2
3
  require 'fileutils'
3
4
  require 'rake'
4
5
  require 'rake/clean'
5
- require 'rake/testtask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/rdoctask'
8
+ require 'spec/rake/spectask'
6
9
  require 'rbconfig'
7
10
 
11
+ def list_spec_files
12
+ list = Dir['spec/**/*_spec.rb']
13
+ list.delete_if { |path| path.include?('/linux/') } if RUBY_PLATFORM =~ /mswin/
14
+ list
15
+ end
16
+
8
17
  include Config
9
18
 
19
+ Bundler::GemHelper.install_tasks
20
+
21
+ # == Gem == #
22
+
23
+ gemtask = Rake::GemPackageTask.new(Gem::Specification.load("right_popen.gemspec")) do |package|
24
+ package.package_dir = ENV['PACKAGE_DIR'] || 'pkg'
25
+ package.need_zip = true
26
+ package.need_tar = true
27
+ end
28
+
29
+ directory gemtask.package_dir
30
+
31
+ CLEAN.include(gemtask.package_dir)
32
+
10
33
  desc "Clean any build files for right_popen"
11
- task :clean do
34
+ task :win_clean do
12
35
  if RUBY_PLATFORM =~ /mswin/
13
36
  if File.exists?('ext/Makefile')
14
37
  Dir.chdir('ext') do
@@ -18,6 +41,7 @@ task :clean do
18
41
  rm 'lib/win32/right_popen.so' if File.file?('lib/win32/right_popen.so')
19
42
  end
20
43
  end
44
+ task :clean => :win_clean
21
45
 
22
46
  desc "Build right_popen (but don't install it)"
23
47
  task :build => [:clean] do
@@ -33,14 +57,25 @@ end
33
57
 
34
58
  desc "Build a binary gem"
35
59
  task :gem => [:build] do
36
- Dir["*.gem"].each { |gem| rm gem }
37
- ruby 'right_popen.gemspec'
60
+ if RUBY_PLATFORM =~ /mswin/
61
+ # the built .so file must appear under 'lib/win32' for the windows gem and
62
+ # the base gem task doesn't appear to handle this. this may be an issue with
63
+ # calculating the file list in the gemspec before the .so has actually been
64
+ # created. workaround is to invoke the gem build gemspec command line after
65
+ # the build step produces the .so file.
66
+ sh 'gem build right_popen.gemspec'
67
+ FileUtils::rm_rf('pkg')
68
+ FileUtils::mkdir_p('pkg')
69
+ Dir.glob('*.gem').each { |gem_path| FileUtils::mv(gem_path, File.join('pkg', File.basename((gem_path)))) }
70
+ end
38
71
  end
39
72
 
40
73
  desc 'Install the right_popen library as a gem'
41
74
  task :install_gem => [:gem] do
42
- file = Dir["*.gem"].first
43
- sh "gem install #{file}"
75
+ Dir.chdir(File.dirname(__FILE__)) do
76
+ file = Dir["pkg/*.gem"].first
77
+ sh "gem install #{file}"
78
+ end
44
79
  end
45
80
 
46
81
  desc 'Uninstalls and reinstalls the right_popen library as a gem'
@@ -49,7 +84,44 @@ task :reinstall_gem do
49
84
  sh "rake install_gem"
50
85
  end
51
86
 
52
- desc 'Runs all spec tests'
53
- task :spec do
54
- sh "spec spec/*_spec.rb"
87
+ # == Unit Tests == #
88
+
89
+ task :specs => :spec
90
+
91
+ desc "Run unit tests"
92
+ Spec::Rake::SpecTask.new do |t|
93
+ t.spec_files = list_spec_files
94
+ end
95
+
96
+ desc "Run unit tests with RCov"
97
+ Spec::Rake::SpecTask.new(:rcov) do |t|
98
+ t.spec_files = list_spec_files
99
+ t.rcov = true
100
+ end
101
+
102
+ desc "Print Specdoc for unit tests"
103
+ Spec::Rake::SpecTask.new(:doc) do |t|
104
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
105
+ t.spec_files = list_spec_files
106
+ end
107
+
108
+ # == Documentation == #
109
+
110
+ desc "Generate API documentation to doc/rdocs/index.html"
111
+ Rake::RDocTask.new do |rd|
112
+ rd.rdoc_dir = 'doc/rdocs'
113
+ rd.main = 'README.rdoc'
114
+ rd.rdoc_files.include 'README.rdoc', "lib/**/*.rb"
115
+
116
+ rd.options << '--inline-source'
117
+ rd.options << '--line-numbers'
118
+ rd.options << '--all'
119
+ rd.options << '--fileboxes'
120
+ rd.options << '--diagram'
121
+ end
122
+
123
+ # == Emacs integration == #
124
+ desc "Rebuild TAGS file"
125
+ task :tags do
126
+ sh "rtags -R lib spec"
55
127
  end
@@ -1457,7 +1457,8 @@ static VALUE right_popen_get_process_environment(VALUE vSelf)
1457
1457
  // 'RightPopen' module entry point
1458
1458
  void Init_right_popen()
1459
1459
  {
1460
- VALUE vModule = rb_define_module("RightPopen");
1460
+ VALUE vCompanyModule = rb_define_module("RightScale");
1461
+ VALUE vModule = rb_define_module_under(vCompanyModule, "RightPopen");
1461
1462
 
1462
1463
  rb_define_module_function(vModule, "popen4", (VALUE(*)(ANYARGS))right_popen_popen4, -1);
1463
1464
  rb_define_module_function(vModule, "async_read", (VALUE(*)(ANYARGS))right_popen_async_read, 1);
@@ -0,0 +1,28 @@
1
+ #-- -*- mode: ruby; encoding: utf-8 -*-
2
+ # Copyright: Copyright (c) 2011 RightScale, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # 'Software'), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ module RightScale
25
+ module RightPopen
26
+ VERSION = "1.0.17"
27
+ end
28
+ end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2009 RightScale Inc
2
+ # Copyright (c) 2009-2011 RightScale Inc
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -25,10 +25,13 @@ require 'rubygems'
25
25
  require 'eventmachine'
26
26
  require 'win32/process'
27
27
 
28
- require File.join(File.dirname(__FILE__), 'right_popen.so') # win32 native code
28
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'win32', 'right_popen.so')) # win32 native code
29
29
 
30
30
  module RightScale
31
31
 
32
+ # ensure uniqueness of handler to avoid confusion.
33
+ raise "#{StdInHandler.name} is already defined" if defined?(StdInHandler)
34
+
32
35
  # Eventmachine callback handler for stdin stream
33
36
  module StdInHandler
34
37
 
@@ -54,6 +57,9 @@ module RightScale
54
57
 
55
58
  end
56
59
 
60
+ # ensure uniqueness of handler to avoid confusion.
61
+ raise "#{StdOutHandler.name} is already defined" if defined?(StdOutHandler)
62
+
57
63
  # Provides an eventmachine callback handler for the stdout stream.
58
64
  module StdOutHandler
59
65
 
@@ -150,6 +156,9 @@ module RightScale
150
156
  end
151
157
  end
152
158
 
159
+ # ensure uniqueness of handler to avoid confusion.
160
+ raise "#{StdErrHandler.name} is already defined" if defined?(StdErrHandler)
161
+
153
162
  # Provides an eventmachine callback handler for the stderr stream.
154
163
  module StdErrHandler
155
164
 
@@ -197,7 +206,7 @@ module RightScale
197
206
  # and asynchronous I/O in the native Windows implementation.
198
207
  #
199
208
  # See RightScale.popen3
200
- def self.popen3_imp(options)
209
+ def self.popen3_imp(options, &block)
201
210
  raise "EventMachine reactor must be started" unless EM.reactor_running?
202
211
 
203
212
  # merge command string
@@ -244,6 +253,7 @@ module RightScale
244
253
  # for waiting for the process to terminate or closing streams as the
245
254
  # watched eventables will handle this automagically. notification will be
246
255
  # sent to the exit_handler on process termination.
256
+ true
247
257
  end
248
258
 
249
259
  protected
@@ -309,8 +319,11 @@ module RightScale
309
319
  # machine from registry supercedes process.
310
320
  merge_environment2(machine_environment_hash, result_environment_hash)
311
321
 
312
- # user environment from registry supercedes machine and process.
313
- merge_environment2(current_user_environment_hash, result_environment_hash)
322
+ # user environment from registry supercedes machine and process. the
323
+ # system account's (default user profile) registry values are not
324
+ # appropriate for merging, so skip it when we know we are the system.
325
+ current_user_name = (`whoami`.chomp rescue '')
326
+ merge_environment2(current_user_environment_hash, result_environment_hash) unless current_user_name == 'nt authority\system'
314
327
 
315
328
  # caller's environment supercedes all.
316
329
  merge_environment2(environment_hash, result_environment_hash)
data/lib/right_popen.rb CHANGED
@@ -26,9 +26,9 @@
26
26
  # It relies on EventMachine for most of its internal mechanisms.
27
27
 
28
28
  if RUBY_PLATFORM =~ /mswin/
29
- require File.expand_path(File.join(File.dirname(__FILE__), 'win32', 'right_popen'))
29
+ require File.expand_path(File.join(File.dirname(__FILE__), 'right_popen', 'win32', 'right_popen'))
30
30
  else
31
- require File.expand_path(File.join(File.dirname(__FILE__), 'linux', 'right_popen'))
31
+ require File.expand_path(File.join(File.dirname(__FILE__), 'right_popen', 'linux', 'right_popen'))
32
32
  end
33
33
 
34
34
  module RightScale
@@ -55,13 +55,12 @@ module RightScale
55
55
  # options[:exit_handler](String):: Exit handler method name, optional
56
56
  #
57
57
  # === Returns
58
- # true:: Always returns true
58
+ # true:: always true
59
59
  def self.popen3(options)
60
60
  raise "EventMachine reactor must be started" unless EM.reactor_running?
61
61
  raise "Missing command" unless options[:command]
62
62
  raise "Missing target" unless options[:target] || !options[:stdout_handler] && !options[:stderr_handler] && !options[:exit_handler] && !options[:pid_handler]
63
- RightScale.popen3_imp(options)
64
- true
63
+ return RightScale.popen3_imp(options)
65
64
  end
66
65
 
67
66
  end
Binary file
data/right_popen.gemspec CHANGED
@@ -1,16 +1,15 @@
1
- require 'rubygems'
2
-
3
- def is_windows?
4
- return RUBY_PLATFORM =~ /mswin/
5
- end
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require "right_popen/version"
6
3
 
7
4
  spec = Gem::Specification.new do |spec|
5
+ is_windows = RUBY_PLATFORM =~ /mswin/
6
+
8
7
  spec.name = 'right_popen'
9
- spec.version = '1.0.11'
8
+ spec.version = RightScale::RightPopen::VERSION
10
9
  spec.authors = ['Scott Messier', 'Raphael Simon', 'Graham Hughes']
11
10
  spec.email = 'scott@rightscale.com'
12
11
  spec.homepage = 'https://github.com/rightscale/right_popen'
13
- if is_windows?
12
+ if is_windows
14
13
  spec.platform = 'x86-mswin32-60'
15
14
  else
16
15
  spec.platform = Gem::Platform::RUBY
@@ -29,7 +28,7 @@ of its internal mechanisms. The Linux implementation is valid for any Linux
29
28
  platform but there is also a native implementation for Windows platforms.
30
29
  EOF
31
30
 
32
- if is_windows?
31
+ if is_windows
33
32
  extension_dir = "ext,"
34
33
  else
35
34
  extension_dir = ""
@@ -40,7 +39,7 @@ EOF
40
39
  item.include?("Makefile") || item.include?(".obj") || item.include?(".pdb") || item.include?(".def") || item.include?(".exp") || item.include?(".lib")
41
40
  end
42
41
  candidates = candidates.delete_if do |item|
43
- if is_windows?
42
+ if is_windows
44
43
  item.include?("/linux/")
45
44
  else
46
45
  item.include?("/win32/")
@@ -48,14 +47,12 @@ EOF
48
47
  end
49
48
  spec.files = candidates.sort!
50
49
 
51
- # Current implementation supports >= 0.12.10
52
- spec.add_runtime_dependency(%q<eventmachine>, [">= 0.12.10"])
53
- if is_windows?
50
+ # Current implementation supports >= 0.12.11
51
+ spec.add_runtime_dependency(%q<eventmachine>, [">= 0.12.11"])
52
+ if is_windows
54
53
  spec.add_runtime_dependency(%q<win32-process>, [">= 0.6.1"])
55
54
  end
56
- end
57
-
58
- if $PROGRAM_NAME == __FILE__
59
- Gem.manage_gems if Gem::RubyGemsVersion.to_f < 1.0
60
- Gem::Builder.new(spec).build
55
+ spec.add_development_dependency('rspec', "~> 1.3")
56
+ spec.add_development_dependency('rake', "~> 0.8.7")
57
+ spec.add_development_dependency('flexmock')
61
58
  end
@@ -0,0 +1,28 @@
1
+ #-- -*- mode: ruby; encoding: utf-8 -*-
2
+ # Copyright: Copyright (c) 2011 RightScale, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # 'Software'), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ fork {
25
+ sleep 30
26
+ puts "Done!"
27
+ }
28
+ exit 0
@@ -1,298 +1,230 @@
1
- require File.join(File.dirname(__FILE__), 'spec_helper')
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), 'runner'))
2
3
 
3
- describe 'RightScale::popen3' do
4
-
5
- module RightPopenSpec
6
- class Runner
7
- class RunnerStatus
8
- def initialize(command, block)
9
- @output_text = ""
10
- @error_text = ""
11
- @status = nil
12
- @did_timeout = false
13
- @callback = block
14
- @pid = nil
15
- EM.next_tick do
16
- @timeout = EM::Timer.new(2) do
17
- puts "\n** Failed to run #{command.inspect}: Timeout"
18
- @did_timeout = true
19
- @callback.call(self)
20
- end
21
- end
22
- end
23
-
24
- attr_accessor :output_text, :error_text, :status, :did_timeout, :pid
4
+ module RightScale
5
+ describe 'popen3' do
6
+ def is_windows?
7
+ return !!(RUBY_PLATFORM =~ /mswin/)
8
+ end
25
9
 
26
- def on_read_stdout(data)
27
- @output_text << data
28
- end
10
+ it 'should redirect output' do
11
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_output.rb'))}\" \"#{STANDARD_MESSAGE}\" \"#{ERROR_MESSAGE}\""
12
+ runner = Runner.new
13
+ status = runner.run_right_popen(command)
14
+ status.status.exitstatus.should == 0
15
+ status.output_text.should == STANDARD_MESSAGE + "\n"
16
+ status.error_text.should == ERROR_MESSAGE + "\n"
17
+ status.pid.should > 0
18
+ end
29
19
 
30
- def on_read_stderr(data)
31
- @error_text << data
32
- end
20
+ it 'should return the right status' do
21
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_status.rb'))}\" #{EXIT_STATUS}"
22
+ runner = Runner.new
23
+ status = runner.run_right_popen(command)
24
+ status.status.exitstatus.should == EXIT_STATUS
25
+ status.output_text.should == ''
26
+ status.error_text.should == ''
27
+ status.pid.should > 0
28
+ end
33
29
 
34
- def on_pid(pid)
35
- raise "PID already set!" unless @pid.nil?
36
- @pid = pid
30
+ it 'should correctly handle many small processes' do
31
+ pending 'Set environment variable TEST_STRESS to enable' unless ENV['TEST_STRESS']
32
+ TO_RUN = 100
33
+ command = is_windows? ? "cmd.exe /c exit 0" : "exit 0"
34
+ runner = Runner.new
35
+ @completed = 0
36
+ @started = 0
37
+ run_cmd = Proc.new do
38
+ runner.do_right_popen(command) do |status|
39
+ @completed += 1
40
+ status.status.exitstatus.should == 0
41
+ status.output_text.should == ''
42
+ status.error_text.should == ''
43
+ status.pid.should > 0
37
44
  end
38
-
39
- def on_exit(status)
40
- @timeout.cancel if @timeout
41
- @status = status
42
- @callback.call(self)
45
+ @started += 1
46
+ if @started < TO_RUN
47
+ EM.next_tick { run_cmd.call }
43
48
  end
44
49
  end
50
+ EM.run do
51
+ EM.next_tick { run_cmd.call }
45
52
 
46
- def initialize
47
- @count = 0
48
- @done = false
49
- @last_exception = nil
50
- @last_iteration = 0
51
- end
52
-
53
- def do_right_popen(command, env=nil, input=nil, &callback)
54
- status = RunnerStatus.new(command, callback)
55
- RightScale.popen3(:command => command,
56
- :input => input,
57
- :target => status,
58
- :environment => env,
59
- :stdout_handler => :on_read_stdout,
60
- :stderr_handler => :on_read_stderr,
61
- :pid_handler => :on_pid,
62
- :exit_handler => :on_exit)
63
- status
64
- end
65
-
66
- def run_right_popen(command, env=nil, input=nil, count=1)
67
- begin
68
- @iterations = 0
69
- EM.run do
70
- EM.next_tick do
71
- do_right_popen(command, env, input) do |status|
72
- maybe_continue(status)
73
- end
74
- end
53
+ EM::PeriodicTimer.new(1) do
54
+ if @completed >= TO_RUN
55
+ EM.stop
75
56
  end
76
- @status
77
- rescue Exception => e
78
- puts "\n** Failed: #{e.message} FROM\n#{e.backtrace.join("\n")}"
79
- raise e
80
- end
81
- end
82
-
83
- def maybe_continue(status)
84
- @iterations += 1
85
- if @iterations < @count
86
- do_right_popen(command, env, input) {|status| maybe_continue(status)}
87
- else
88
- @status = status
89
- EM.stop
90
57
  end
91
58
  end
92
59
  end
93
- end
94
60
 
95
- def is_windows?
96
- return !!(RUBY_PLATFORM =~ /mswin/)
97
- end
98
-
99
- it 'should redirect output' do
100
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_output.rb'))}\" \"#{STANDARD_MESSAGE}\" \"#{ERROR_MESSAGE}\""
101
- runner = RightPopenSpec::Runner.new
102
- status = runner.run_right_popen(command)
103
- status.status.exitstatus.should == 0
104
- status.output_text.should == STANDARD_MESSAGE + "\n"
105
- status.error_text.should == ERROR_MESSAGE + "\n"
106
- status.pid.should > 0
107
- end
108
-
109
- it 'should return the right status' do
110
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_status.rb'))}\" #{EXIT_STATUS}"
111
- runner = RightPopenSpec::Runner.new
112
- status = runner.run_right_popen(command)
113
- status.status.exitstatus.should == EXIT_STATUS
114
- status.output_text.should == ''
115
- status.error_text.should == ''
116
- status.pid.should > 0
117
- end
118
-
119
- it 'should correctly handle many small processes' do
120
- pending 'Set environment variable TEST_STRESS to enable' unless ENV['TEST_STRESS']
121
- TO_RUN = 100
122
- command = is_windows? ? "cmd.exe /c exit 0" : "exit 0"
123
- runner = RightPopenSpec::Runner.new
124
- @completed = 0
125
- @started = 0
126
- run_cmd = Proc.new do
127
- runner.do_right_popen(command) do |status|
128
- @completed += 1
129
- status.status.exitstatus.should == 0
130
- status.output_text.should == ''
131
- status.error_text.should == ''
132
- status.pid.should > 0
133
- end
134
- @started += 1
135
- if @started < TO_RUN
136
- EM.next_tick { run_cmd.call }
137
- end
138
- end
139
- EM.run do
140
- EM.next_tick { run_cmd.call }
61
+ it 'should preserve the integrity of stdout when stderr is unavailable' do
62
+ count = LARGE_OUTPUT_COUNTER
63
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_stdout_only.rb'))}\" #{count}"
64
+ runner = Runner.new
65
+ status = runner.run_right_popen(command)
66
+ status.status.exitstatus.should == 0
141
67
 
142
- EM::PeriodicTimer.new(1) do
143
- if @completed >= TO_RUN
144
- EM.stop
145
- end
68
+ results = ''
69
+ count.times do |i|
70
+ results << "stdout #{i}\n"
146
71
  end
72
+ status.output_text.should == results
73
+ status.error_text.should == ''
74
+ status.pid.should > 0
147
75
  end
148
- end
149
-
150
- it 'should preserve the integrity of stdout when stderr is unavailable' do
151
- count = LARGE_OUTPUT_COUNTER
152
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_stdout_only.rb'))}\" #{count}"
153
- runner = RightPopenSpec::Runner.new
154
- status = runner.run_right_popen(command)
155
- status.status.exitstatus.should == 0
156
-
157
- results = ''
158
- count.times do |i|
159
- results << "stdout #{i}\n"
160
- end
161
- status.output_text.should == results
162
- status.error_text.should == ''
163
- status.pid.should > 0
164
- end
165
76
 
166
- it 'should preserve the integrity of stderr when stdout is unavailable' do
167
- count = LARGE_OUTPUT_COUNTER
168
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_stderr_only.rb'))}\" #{count}"
169
- runner = RightPopenSpec::Runner.new
170
- status = runner.run_right_popen(command)
171
- status.status.exitstatus.should == 0
77
+ it 'should preserve the integrity of stderr when stdout is unavailable' do
78
+ count = LARGE_OUTPUT_COUNTER
79
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_stderr_only.rb'))}\" #{count}"
80
+ runner = Runner.new
81
+ status = runner.run_right_popen(command)
82
+ status.status.exitstatus.should == 0
172
83
 
173
- results = ''
174
- count.times do |i|
175
- results << "stderr #{i}\n"
84
+ results = ''
85
+ count.times do |i|
86
+ results << "stderr #{i}\n"
87
+ end
88
+ status.error_text.should == results
89
+ status.output_text.should == ''
90
+ status.pid.should > 0
176
91
  end
177
- status.error_text.should == results
178
- status.output_text.should == ''
179
- status.pid.should > 0
180
- end
181
92
 
182
- it 'should preserve the integrity of stdout and stderr despite interleaving' do
183
- count = LARGE_OUTPUT_COUNTER
184
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_mixed_output.rb'))}\" #{count}"
185
- runner = RightPopenSpec::Runner.new
186
- status = runner.run_right_popen(command)
187
- status.status.exitstatus.should == 99
93
+ it 'should preserve the integrity of stdout and stderr despite interleaving' do
94
+ count = LARGE_OUTPUT_COUNTER
95
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_mixed_output.rb'))}\" #{count}"
96
+ runner = Runner.new
97
+ status = runner.run_right_popen(command)
98
+ status.status.exitstatus.should == 99
188
99
 
189
- results = ''
190
- count.times do |i|
191
- results << "stdout #{i}\n"
192
- end
193
- status.output_text.should == results
100
+ results = ''
101
+ count.times do |i|
102
+ results << "stdout #{i}\n"
103
+ end
104
+ status.output_text.should == results
194
105
 
195
- results = ''
196
- count.times do |i|
197
- (results << "stderr #{i}\n") if 0 == i % 10
106
+ results = ''
107
+ count.times do |i|
108
+ (results << "stderr #{i}\n") if 0 == i % 10
109
+ end
110
+ status.error_text.should == results
111
+ status.pid.should > 0
198
112
  end
199
- status.error_text.should == results
200
- status.pid.should > 0
201
- end
202
113
 
203
- it 'should setup environment variables' do
204
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
205
- runner = RightPopenSpec::Runner.new
206
- status = runner.run_right_popen(command)
207
- status.status.exitstatus.should == 0
208
- status.output_text.should_not include('_test_')
209
- status = runner.run_right_popen(command, :__test__ => '42')
210
- status.status.exitstatus.should == 0
211
- status.output_text.should match(/^__test__=42$/)
212
- status.pid.should > 0
213
- end
214
-
215
- it 'should restore environment variables' do
216
- begin
217
- ENV['__test__'] = '41'
218
- old_envs = {}
219
- ENV.each { |k, v| old_envs[k] = v }
114
+ it 'should setup environment variables' do
220
115
  command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
221
- runner = RightPopenSpec::Runner.new
116
+ runner = Runner.new
117
+ status = runner.run_right_popen(command)
118
+ status.status.exitstatus.should == 0
119
+ status.output_text.should_not include('_test_')
222
120
  status = runner.run_right_popen(command, :__test__ => '42')
223
121
  status.status.exitstatus.should == 0
224
122
  status.output_text.should match(/^__test__=42$/)
225
- ENV.each { |k, v| old_envs[k].should == v }
226
- old_envs.each { |k, v| ENV[k].should == v }
227
123
  status.pid.should > 0
228
- ensure
229
- ENV.delete('__test__')
230
124
  end
231
- end
232
125
 
233
- if is_windows?
234
- # FIX: this behavior is currently specific to Windows but should probably be
235
- # implemented for Linux.
236
- it 'should merge the PATH variable instead of overriding it' do
237
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
238
- runner = RightPopenSpec::Runner.new
239
- status = runner.run_right_popen(command, 'PATH' => "c:/bogus\\bin")
240
- status.status.exitstatus.should == 0
241
- status.output_text.should include('PATH=c:\\bogus\\bin;')
242
- status.pid.should > 0
126
+ it 'should restore environment variables' do
127
+ begin
128
+ ENV['__test__'] = '41'
129
+ old_envs = {}
130
+ ENV.each { |k, v| old_envs[k] = v }
131
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
132
+ runner = Runner.new
133
+ status = runner.run_right_popen(command, :__test__ => '42')
134
+ status.status.exitstatus.should == 0
135
+ status.output_text.should match(/^__test__=42$/)
136
+ ENV.each { |k, v| old_envs[k].should == v }
137
+ old_envs.each { |k, v| ENV[k].should == v }
138
+ status.pid.should > 0
139
+ ensure
140
+ ENV.delete('__test__')
141
+ end
142
+ end
143
+
144
+ if is_windows?
145
+ # FIX: this behavior is currently specific to Windows but should probably be
146
+ # implemented for Linux.
147
+ it 'should merge the PATH variable instead of overriding it' do
148
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
149
+ runner = Runner.new
150
+ status = runner.run_right_popen(command, 'PATH' => "c:/bogus\\bin")
151
+ status.status.exitstatus.should == 0
152
+ status.output_text.should include('c:\\bogus\\bin;')
153
+ status.pid.should > 0
154
+ end
155
+ else
156
+ it 'should allow running bash command lines starting with a built-in command' do
157
+ command = "for i in 1 2 3 4 5; do echo $i;done"
158
+ runner = Runner.new
159
+ status = runner.run_right_popen(command)
160
+ status.status.exitstatus.should == 0
161
+ status.output_text.should == "1\n2\n3\n4\n5\n"
162
+ status.pid.should > 0
163
+ end
164
+
165
+ it 'should support running background processes' do
166
+ command = "(sleep 20)&"
167
+ now = Time.now
168
+ runner = Runner.new
169
+ status = runner.run_right_popen(command)
170
+ finished = Time.now
171
+ (finished - now).should < 20
172
+ status.did_timeout.should be_false
173
+ status.status.exitstatus.should == 0
174
+ status.output_text.should == ""
175
+ status.pid.should > 0
176
+ end
243
177
  end
244
- else
245
- it 'should allow running bash command lines starting with a built-in command' do
246
- command = "for i in 1 2 3 4 5; do echo $i;done"
247
- runner = RightPopenSpec::Runner.new
178
+
179
+ it 'should support raw command arguments' do
180
+ command = is_windows? ? ["cmd.exe", "/c", "echo", "*"] : ["echo", "*"]
181
+ runner = Runner.new
248
182
  status = runner.run_right_popen(command)
249
183
  status.status.exitstatus.should == 0
250
- status.output_text.should == "1\n2\n3\n4\n5\n"
184
+ status.output_text.should == "*\n"
251
185
  status.pid.should > 0
252
186
  end
253
187
 
254
- it 'should support running background processes' do
255
- command = "(sleep 20)&"
256
- now = Time.now
257
- runner = RightPopenSpec::Runner.new
258
- status = runner.run_right_popen(command)
259
- finished = Time.now
260
- (finished - now).should < 20
261
- status.did_timeout.should be_false
188
+ it 'should run repeatedly without leaking resources' do
189
+ pending 'Set environment variable TEST_LEAK to enable' unless ENV['TEST_LEAK']
190
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_output.rb'))}\" \"#{STANDARD_MESSAGE}\" \"#{ERROR_MESSAGE}\""
191
+ runner = Runner.new
192
+ status = runner.run_right_popen(command, nil, nil, REPEAT_TEST_COUNTER)
262
193
  status.status.exitstatus.should == 0
263
- status.output_text.should == ""
194
+ status.output_text.should == STANDARD_MESSAGE + "\n"
195
+ status.error_text.should == ERROR_MESSAGE + "\n"
264
196
  status.pid.should > 0
265
197
  end
266
- end
267
198
 
268
- it 'should support raw command arguments' do
269
- command = is_windows? ? ["cmd.exe", "/c", "echo", "*"] : ["echo", "*"]
270
- runner = RightPopenSpec::Runner.new
271
- status = runner.run_right_popen(command)
272
- status.status.exitstatus.should == 0
273
- status.output_text.should == "*\n"
274
- status.pid.should > 0
275
- end
199
+ it 'should pass input to child process' do
200
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'increment.rb'))}\""
201
+ runner = Runner.new
202
+ status = runner.run_right_popen(command, nil, "42\n")
203
+ status.status.exitstatus.should == 0
204
+ status.output_text.should == "43\n"
205
+ status.error_text.should be_empty
206
+ status.pid.should > 0
207
+ end
276
208
 
277
- it 'should run repeatedly without leaking resources' do
278
- pending 'Set environment variable TEST_LEAK to enable' unless ENV['TEST_LEAK']
279
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_output.rb'))}\" \"#{STANDARD_MESSAGE}\" \"#{ERROR_MESSAGE}\""
280
- runner = RightPopenSpec::Runner.new
281
- status = runner.run_right_popen(command, nil, nil, REPEAT_TEST_COUNTER)
282
- status.status.exitstatus.should == 0
283
- status.output_text.should == STANDARD_MESSAGE + "\n"
284
- status.error_text.should == ERROR_MESSAGE + "\n"
285
- status.pid.should > 0
286
- end
209
+ it 'should handle child processes that close stdout but keep running' do
210
+ pending 'not implemented for windows' if is_windows?
211
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'stdout.rb'))}\""
212
+ runner = Runner.new
213
+ status = runner.run_right_popen(command, nil, nil)
214
+ status.did_timeout.should be_true
215
+ status.output_text.should be_empty
216
+ status.error_text.should == "Closing stdout\n"
217
+ end
287
218
 
288
- it 'should pass input to child process' do
289
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'increment.rb'))}\""
290
- runner = RightPopenSpec::Runner.new
291
- status = runner.run_right_popen(command, nil, "42\n")
292
- status.status.exitstatus.should == 0
293
- status.output_text.should == "43\n"
294
- status.error_text.should be_empty
295
- status.pid.should > 0
219
+ it 'should handle child processes that spawn long running background processes' do
220
+ pending 'not implemented for windows' if is_windows?
221
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'background.rb'))}\""
222
+ runner = Runner.new
223
+ status = runner.run_right_popen(command, nil, nil)
224
+ status.status.exitstatus.should == 0
225
+ status.did_timeout.should be_false
226
+ status.output_text.should be_empty
227
+ status.error_text.should be_empty
228
+ end
296
229
  end
297
-
298
230
  end
data/spec/runner.rb ADDED
@@ -0,0 +1,112 @@
1
+ #-- -*- mode: ruby; encoding: utf-8 -*-
2
+ # Copyright: Copyright (c) 2011 RightScale, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # 'Software'), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ module RightScale
25
+ class Runner
26
+ class RunnerStatus
27
+ def initialize(command, block)
28
+ @output_text = ""
29
+ @error_text = ""
30
+ @status = nil
31
+ @did_timeout = false
32
+ @callback = block
33
+ @pid = nil
34
+ EM.next_tick do
35
+ @timeout = EM::Timer.new(2) do
36
+ puts "\n** Failed to run #{command.inspect}: Timeout"
37
+ @did_timeout = true
38
+ @callback.call(self)
39
+ end
40
+ end
41
+ end
42
+
43
+ attr_accessor :output_text, :error_text, :status, :did_timeout, :pid
44
+
45
+ def on_read_stdout(data)
46
+ @output_text << data
47
+ end
48
+
49
+ def on_read_stderr(data)
50
+ @error_text << data
51
+ end
52
+
53
+ def on_pid(pid)
54
+ raise "PID already set!" unless @pid.nil?
55
+ @pid = pid
56
+ end
57
+
58
+ def on_exit(status)
59
+ @timeout.cancel if @timeout
60
+ @status = status
61
+ @callback.call(self)
62
+ end
63
+ end
64
+
65
+ def initialize
66
+ @count = 0
67
+ @done = false
68
+ @last_exception = nil
69
+ @last_iteration = 0
70
+ end
71
+
72
+ def do_right_popen(command, env=nil, input=nil, &callback)
73
+ status = RunnerStatus.new(command, callback)
74
+ RightScale.popen3(:command => command,
75
+ :input => input,
76
+ :target => status,
77
+ :environment => env,
78
+ :stdout_handler => :on_read_stdout,
79
+ :stderr_handler => :on_read_stderr,
80
+ :pid_handler => :on_pid,
81
+ :exit_handler => :on_exit)
82
+ status
83
+ end
84
+
85
+ def run_right_popen(command, env=nil, input=nil, count=1)
86
+ begin
87
+ @iterations = 0
88
+ EM.run do
89
+ EM.next_tick do
90
+ do_right_popen(command, env, input) do |status|
91
+ maybe_continue(status)
92
+ end
93
+ end
94
+ end
95
+ @status
96
+ rescue Exception => e
97
+ puts "\n** Failed: #{e.message} FROM\n#{e.backtrace.join("\n")}"
98
+ raise e
99
+ end
100
+ end
101
+
102
+ def maybe_continue(status)
103
+ @iterations += 1
104
+ if @iterations < @count
105
+ do_right_popen(command, env, input) {|status| maybe_continue(status)}
106
+ else
107
+ @status = status
108
+ EM.stop
109
+ end
110
+ end
111
+ end
112
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'rubygems'
2
+ require 'bundler/setup'
2
3
  require 'spec'
3
4
  require 'eventmachine'
5
+ require 'flexmock'
4
6
  require File.join(File.dirname(__FILE__), '..', 'lib', 'right_popen')
5
7
 
6
8
  RUBY_CMD = 'ruby'
@@ -18,3 +20,7 @@ REPEAT_TEST_COUNTER = 256
18
20
  def is_windows?
19
21
  return RUBY_PLATFORM =~ /mswin/
20
22
  end
23
+
24
+ Spec::Runner.configure do |config|
25
+ config.mock_with :flexmock
26
+ end
data/spec/stdout.rb ADDED
@@ -0,0 +1,28 @@
1
+ #-- -*- mode: ruby; encoding: utf-8 -*-
2
+ # Copyright: Copyright (c) 2011 RightScale, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # 'Software'), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ $stderr.puts "Closing stdout"
25
+ STDOUT.close
26
+ sleep 3
27
+ $stderr.puts "Exiting"
28
+ exit 0
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: right_popen
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.11
4
+ hash: 53
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 17
10
+ version: 1.0.17
5
11
  platform: x86-mswin32-60
6
12
  authors:
7
13
  - Scott Messier
@@ -11,29 +17,86 @@ autorequire:
11
17
  bindir: bin
12
18
  cert_chain: []
13
19
 
14
- date: 2010-09-08 00:00:00 -07:00
20
+ date: 2011-09-21 00:00:00 -07:00
15
21
  default_executable:
16
22
  dependencies:
17
23
  - !ruby/object:Gem::Dependency
18
24
  name: eventmachine
19
- type: :runtime
20
- version_requirement:
21
- version_requirements: !ruby/object:Gem::Requirement
25
+ prerelease: false
26
+ requirement: &id001 !ruby/object:Gem::Requirement
27
+ none: false
22
28
  requirements:
23
29
  - - ">="
24
30
  - !ruby/object:Gem::Version
25
- version: 0.12.10
26
- version:
31
+ hash: 57
32
+ segments:
33
+ - 0
34
+ - 12
35
+ - 11
36
+ version: 0.12.11
37
+ type: :runtime
38
+ version_requirements: *id001
27
39
  - !ruby/object:Gem::Dependency
28
40
  name: win32-process
29
- type: :runtime
30
- version_requirement:
31
- version_requirements: !ruby/object:Gem::Requirement
41
+ prerelease: false
42
+ requirement: &id002 !ruby/object:Gem::Requirement
43
+ none: false
32
44
  requirements:
33
45
  - - ">="
34
46
  - !ruby/object:Gem::Version
47
+ hash: 5
48
+ segments:
49
+ - 0
50
+ - 6
51
+ - 1
35
52
  version: 0.6.1
36
- version:
53
+ type: :runtime
54
+ version_requirements: *id002
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ prerelease: false
58
+ requirement: &id003 !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ~>
62
+ - !ruby/object:Gem::Version
63
+ hash: 9
64
+ segments:
65
+ - 1
66
+ - 3
67
+ version: "1.3"
68
+ type: :development
69
+ version_requirements: *id003
70
+ - !ruby/object:Gem::Dependency
71
+ name: rake
72
+ prerelease: false
73
+ requirement: &id004 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ hash: 49
79
+ segments:
80
+ - 0
81
+ - 8
82
+ - 7
83
+ version: 0.8.7
84
+ type: :development
85
+ version_requirements: *id004
86
+ - !ruby/object:Gem::Dependency
87
+ name: flexmock
88
+ prerelease: false
89
+ requirement: &id005 !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ hash: 3
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ type: :development
99
+ version_requirements: *id005
37
100
  description: |
38
101
  RightPopen allows running external processes aynchronously while still
39
102
  capturing their standard and error outputs. It relies on EventMachine for most
@@ -55,9 +118,11 @@ files:
55
118
  - ext/win32/right_popen.c
56
119
  - ext/win32/right_popen.h
57
120
  - lib/right_popen.rb
58
- - lib/win32/right_popen.rb
121
+ - lib/right_popen/version.rb
122
+ - lib/right_popen/win32/right_popen.rb
59
123
  - lib/win32/right_popen.so
60
124
  - right_popen.gemspec
125
+ - spec/background.rb
61
126
  - spec/increment.rb
62
127
  - spec/print_env.rb
63
128
  - spec/produce_mixed_output.rb
@@ -66,7 +131,9 @@ files:
66
131
  - spec/produce_stderr_only.rb
67
132
  - spec/produce_stdout_only.rb
68
133
  - spec/right_popen_spec.rb
134
+ - spec/runner.rb
69
135
  - spec/spec_helper.rb
136
+ - spec/stdout.rb
70
137
  has_rdoc: true
71
138
  homepage: https://github.com/rightscale/right_popen
72
139
  licenses: []
@@ -80,21 +147,29 @@ rdoc_options:
80
147
  require_paths:
81
148
  - lib
82
149
  required_ruby_version: !ruby/object:Gem::Requirement
150
+ none: false
83
151
  requirements:
84
152
  - - ">="
85
153
  - !ruby/object:Gem::Version
154
+ hash: 59
155
+ segments:
156
+ - 1
157
+ - 8
158
+ - 6
86
159
  version: 1.8.6
87
- version:
88
160
  required_rubygems_version: !ruby/object:Gem::Requirement
161
+ none: false
89
162
  requirements:
90
163
  - - ">="
91
164
  - !ruby/object:Gem::Version
165
+ hash: 3
166
+ segments:
167
+ - 0
92
168
  version: "0"
93
- version:
94
169
  requirements: []
95
170
 
96
171
  rubyforge_project: right_popen
97
- rubygems_version: 1.3.5
172
+ rubygems_version: 1.3.7
98
173
  signing_key:
99
174
  specification_version: 3
100
175
  summary: Provides a platform-independent popen implementation