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 +81 -9
- data/ext/win32/right_popen.c +2 -1
- data/lib/right_popen/version.rb +28 -0
- data/lib/{win32 → right_popen/win32}/right_popen.rb +18 -5
- data/lib/right_popen.rb +4 -5
- data/lib/win32/right_popen.so +0 -0
- data/right_popen.gemspec +14 -17
- data/spec/background.rb +28 -0
- data/spec/right_popen_spec.rb +185 -253
- data/spec/runner.rb +112 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/stdout.rb +28 -0
- metadata +90 -15
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/
|
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 :
|
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
|
-
|
37
|
-
|
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
|
-
|
43
|
-
|
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
|
-
|
53
|
-
|
54
|
-
|
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
|
data/ext/win32/right_popen.c
CHANGED
@@ -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
|
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
|
-
|
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::
|
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
|
data/lib/win32/right_popen.so
CHANGED
Binary file
|
data/right_popen.gemspec
CHANGED
@@ -1,16 +1,15 @@
|
|
1
|
-
|
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 =
|
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.
|
52
|
-
spec.add_runtime_dependency(%q<eventmachine>, [">= 0.12.
|
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
|
-
|
57
|
-
|
58
|
-
|
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
|
data/spec/background.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
|
+
fork {
|
25
|
+
sleep 30
|
26
|
+
puts "Done!"
|
27
|
+
}
|
28
|
+
exit 0
|
data/spec/right_popen_spec.rb
CHANGED
@@ -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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
40
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
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
|
-
|
143
|
-
|
144
|
-
|
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
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
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
|
-
|
174
|
-
|
175
|
-
|
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
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
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
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
100
|
+
results = ''
|
101
|
+
count.times do |i|
|
102
|
+
results << "stdout #{i}\n"
|
103
|
+
end
|
104
|
+
status.output_text.should == results
|
194
105
|
|
195
|
-
|
196
|
-
|
197
|
-
|
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
|
-
|
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 =
|
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
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
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
|
-
|
245
|
-
it 'should
|
246
|
-
command =
|
247
|
-
runner =
|
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 == "
|
184
|
+
status.output_text.should == "*\n"
|
251
185
|
status.pid.should > 0
|
252
186
|
end
|
253
187
|
|
254
|
-
it 'should
|
255
|
-
|
256
|
-
|
257
|
-
runner =
|
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
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
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
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
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
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
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
|
-
|
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:
|
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
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
26
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
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/
|
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.
|
172
|
+
rubygems_version: 1.3.7
|
98
173
|
signing_key:
|
99
174
|
specification_version: 3
|
100
175
|
summary: Provides a platform-independent popen implementation
|