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

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/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