right_popen 1.0.4 → 1.0.5

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.
@@ -1,4 +1,4 @@
1
- #
1
+ #--
2
2
  # Copyright (c) 2009 RightScale Inc
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
@@ -19,7 +19,7 @@
19
19
  # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
20
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
21
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
- #
22
+ #++
23
23
 
24
24
  # RightScale.popen3 allows running external processes aynchronously
25
25
  # while still capturing their standard and error outputs.
@@ -99,33 +99,35 @@ module RightScale
99
99
  # Forks process to run given command asynchronously, hooking all three
100
100
  # standard streams of the child process.
101
101
  #
102
- # Streams the command's stdout and stderr to the given handlers. Time-
103
- # ordering of bytes sent to stdout and stderr is not preserved.
104
- #
105
- # Calls given exit handler upon command process termination, passing in the
106
- # resulting Process::Status.
107
- #
108
- # All handlers must be methods exposed by the given target.
109
- #
110
- # === Parameters
111
- # cmd(String):: command to execute, including any arguments.
112
- # target(Object):: object defining handler methods to be called.
113
- # stdout_handler(String):: token for stdout handler method name.
114
- # stderr_handler(String):: token for stderr handler method name.
115
- # exit_handler(String):: token for exit handler method name.
116
- #
117
- # === Returns
118
- # true:: Always returns true
119
- def self.popen3(cmd, target, stdout_handler = nil, stderr_handler = nil, exit_handler = nil)
120
- raise "EventMachine reactor must be started" unless EM.reactor_running?
102
+ # See RightScale.popen3
103
+ def self.popen3_imp(options)
104
+ cmd = options[:command].dup
121
105
  GC.start # To garbage collect open file descriptors from passed executions
122
106
  EM.next_tick do
123
107
  saved_stderr = $stderr.dup
124
108
  r, w = Socket::pair(Socket::AF_LOCAL, Socket::SOCK_STREAM, 0)#IO::pipe
125
109
 
126
110
  $stderr.reopen w
127
- c = EM.attach(r, StdErrHandler, target, stderr_handler, r) if stderr_handler
128
- EM.popen(cmd, StdOutHandler, target, stdout_handler, exit_handler, c, r, w)
111
+ c = EM.attach(r, StdErrHandler, options[:target], options[:stderr_handler], r) if options[:stderr_handler]
112
+
113
+ # Setup environment for child process
114
+ envs = {}
115
+ options[:environment].each { |k, v| envs[k.to_s] = v } if options[:environment]
116
+ unless envs.empty?
117
+ old_envs = {}
118
+ ENV.each { |k, v| old_envs[k] = v if envs.include?(k) }
119
+ envs.each { |k, v| ENV[k] = v }
120
+ end
121
+
122
+ # Launch child process
123
+ EM.popen(cmd, StdOutHandler, options[:target], options[:stdout_handler], options[:exit_handler], c, r, w)
124
+
125
+ # Restore environment variables
126
+ unless envs.empty?
127
+ envs.each { |k, _| ENV[k] = nil }
128
+ old_envs.each { |k, v| ENV[k] = v }
129
+ end
130
+
129
131
  # Do not close 'w', strange things happen otherwise
130
132
  # (command protocol socket gets closed during decommission)
131
133
  $stderr.reopen saved_stderr
data/lib/right_popen.rb CHANGED
@@ -1,4 +1,4 @@
1
- #
1
+ #--
2
2
  # Copyright (c) 2009 RightScale Inc
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
@@ -19,7 +19,7 @@
19
19
  # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
20
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
21
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
- #
22
+ #++
23
23
 
24
24
  # RightScale.popen3 allows running external processes aynchronously
25
25
  # while still capturing their standard and error outputs.
@@ -30,3 +30,36 @@ if RUBY_PLATFORM =~ /mswin/
30
30
  else
31
31
  require File.expand_path(File.join(File.dirname(__FILE__), 'linux', 'right_popen'))
32
32
  end
33
+
34
+ module RightScale
35
+
36
+ # Spawn process to run given command asynchronously, hooking all three
37
+ # standard streams of the child process.
38
+ #
39
+ # Streams the command's stdout and stderr to the given handlers. Time-
40
+ # ordering of bytes sent to stdout and stderr is not preserved.
41
+ #
42
+ # Calls given exit handler upon command process termination, passing in the
43
+ # resulting Process::Status.
44
+ #
45
+ # All handlers must be methods exposed by the given target.
46
+ #
47
+ # === Parameters
48
+ # options[:command](String):: Command to execute, including any arguments
49
+ # options[:environment](Hash):: Hash of environment variables values keyed by name
50
+ # options[:target](Object):: object defining handler methods to be called, optional (no handlers can be defined if not specified)
51
+ # options[:stdout_handler](String):: Stdout handler method name, optional
52
+ # options[:stderr_handler](String):: Stderr handler method name, optional
53
+ # options[:exit_handler](String):: Exit handler method name, optional
54
+ #
55
+ # === Returns
56
+ # true:: Always returns true
57
+ def self.popen3(options)
58
+ raise "EventMachine reactor must be started" unless EM.reactor_running?
59
+ raise "Missing command" unless options[:command]
60
+ raise "Missing target" unless options[:target] || !options[:stdout_handler] && !options[:stderr_handler] && !options[:exit_handler]
61
+ RightScale.popen3_imp(options)
62
+ true
63
+ end
64
+
65
+ end
data/right_popen.gemspec CHANGED
@@ -4,7 +4,7 @@ spec = Gem::Specification.new do |spec|
4
4
  is_windows = RUBY_PLATFORM =~ /mswin/
5
5
 
6
6
  spec.name = 'right_popen'
7
- spec.version = '1.0.4'
7
+ spec.version = '1.0.5'
8
8
  spec.authors = ['Scott Messier', 'Raphael Simon']
9
9
  spec.email = 'scott@rightscale.com'
10
10
  spec.homepage = 'https://github.com/rightscale/right_popen'
data/spec/print_env.rb ADDED
@@ -0,0 +1 @@
1
+ ENV.each { |k, v| $stdout.puts "#{k}=#{v}\n" }
@@ -1,5 +1,4 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
- require 'right_popen'
3
2
 
4
3
  RUBY_CMD = 'ruby'
5
4
  STANDARD_MESSAGE = 'Standard message'
@@ -29,18 +28,23 @@ describe 'RightScale::popen3' do
29
28
 
30
29
  attr_reader :output_text, :error_text, :status
31
30
 
32
- def do_right_popen(command)
31
+ def do_right_popen(command, env=nil)
33
32
  @output_text = ''
34
33
  @error_text = ''
35
34
  @status = nil
36
- RightScale.popen3(command, self, :on_read_stdout, :on_read_stderr, :on_exit)
35
+ RightScale.popen3(:command => command,
36
+ :target => self,
37
+ :environment => env,
38
+ :stdout_handler => :on_read_stdout,
39
+ :stderr_handler => :on_read_stderr,
40
+ :exit_handler => :on_exit)
37
41
  end
38
42
 
39
- def run_right_popen(command, count = 1)
43
+ def run_right_popen(command, env=nil, count = 1)
40
44
  puts "#{count}>" if count > 1
41
45
  last_iteration = 0
42
46
  EM.next_tick do
43
- do_right_popen(command)
47
+ do_right_popen(command, env)
44
48
  end
45
49
  EM.run do
46
50
  timer = EM::PeriodicTimer.new(0.05) do
@@ -54,7 +58,7 @@ describe 'RightScale::popen3' do
54
58
  print '+'
55
59
  STDOUT.flush
56
60
  end
57
- do_right_popen(command)
61
+ do_right_popen(command, env)
58
62
  end
59
63
  else
60
64
  puts "<" if count > 1
@@ -162,11 +166,35 @@ describe 'RightScale::popen3' do
162
166
  end
163
167
  runner.error_text.should == results
164
168
  end
169
+
170
+ it 'should setup environment variables' do
171
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
172
+ runner = RightPopenSpec::Runner.new
173
+ runner.run_right_popen(command)
174
+ runner.status.exitstatus.should == 0
175
+ runner.output_text.should_not include('_test_')
176
+ runner.run_right_popen(command, :__test__ => '42')
177
+ runner.status.exitstatus.should == 0
178
+ runner.output_text.should match(/^__test__=42$/)
179
+ end
180
+
181
+ it 'should restore environment variables' do
182
+ ENV['__test__'] = '41'
183
+ old_envs = {}
184
+ ENV.each { |k, v| old_envs[k] = v }
185
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
186
+ runner = RightPopenSpec::Runner.new
187
+ runner.run_right_popen(command, :__test__ => '42')
188
+ runner.status.exitstatus.should == 0
189
+ runner.output_text.should match(/^__test__=42$/)
190
+ ENV.each { |k, v| old_envs[k].should == v }
191
+ old_envs.each { |k, v| ENV[k].should == v }
192
+ end
165
193
 
166
194
  it 'should run repeatedly without leaking resources' do
167
195
  command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_output.rb'))}\" \"#{STANDARD_MESSAGE}\" \"#{ERROR_MESSAGE}\""
168
196
  runner = RightPopenSpec::Runner.new
169
- runner.run_right_popen(command, REPEAT_TEST_COUNTER)
197
+ runner.run_right_popen(command, nil, REPEAT_TEST_COUNTER)
170
198
  runner.status.exitstatus.should == 0
171
199
  runner.output_text.should == STANDARD_MESSAGE + "\n"
172
200
  runner.error_text.should == ERROR_MESSAGE + "\n"
data/spec/spec_helper.rb CHANGED
@@ -1,2 +1,4 @@
1
1
  require 'rubygems'
2
- $:.push File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'spec'
3
+ require 'eventmachine'
4
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'right_popen')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: right_popen
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Messier
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2010-02-18 00:00:00 -08:00
13
+ date: 2010-02-19 00:00:00 -08:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -43,6 +43,7 @@ files:
43
43
  - lib/linux/right_popen.rb
44
44
  - lib/right_popen.rb
45
45
  - right_popen.gemspec
46
+ - spec/print_env.rb
46
47
  - spec/produce_mixed_output.rb
47
48
  - spec/produce_output.rb
48
49
  - spec/produce_status.rb