right_popen 1.0.21 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -22,103 +22,195 @@
22
22
  #++
23
23
 
24
24
  module RightScale
25
- class Runner
26
- class RunnerStatus
27
- def initialize(command, options={}, &callback)
28
- options = {:force_yield=>nil, :timeout=>nil, :expect_timeout=>false}.merge(options)
29
- @output_text = ""
30
- @error_text = ""
31
- @status = nil
32
- @did_timeout = false
33
- @callback = callback
34
- @pid = nil
35
- @force_yield = options[:force_yield]
36
- EM.next_tick do
37
- @timeout = EM::Timer.new(options[:timeout] || 2) do
38
- puts "\n** Failed to run #{command.inspect}: Timeout" unless options[:expect_timeout]
39
- @did_timeout = true
40
- @callback.call(self) if options[:expect_timeout]
41
- end
25
+ module RightPopen
26
+ class Runner
27
+ class RunnerStatus
28
+ def initialize(command, options={}, &callback)
29
+ options = {:repeats=>1, :force_yield=>nil, :timeout=>nil, :expect_timeout=>false}.merge(options)
30
+
31
+ @command = command
32
+ @output_text = ""
33
+ @error_text = ""
34
+ @status = nil
35
+ @did_timeout = false
36
+ @callback = callback
37
+ @pid = nil
38
+ @force_yield = options[:force_yield]
39
+
40
+ @expect_timeout = options[:expect_timeout]
41
+ @expect_size_limit = options[:expect_size_limit]
42
42
  end
43
- end
44
43
 
45
- attr_accessor :output_text, :error_text, :status, :did_timeout, :pid
44
+ attr_accessor :output_text, :error_text, :status, :pid
45
+ attr_accessor :did_timeout, :did_size_limit
46
46
 
47
- def on_read_stdout(data)
48
- sleep @force_yield if @force_yield
49
- @output_text << data
50
- end
47
+ def on_read_stdout(data)
48
+ sleep @force_yield if @force_yield
49
+ @output_text << data
50
+ end
51
51
 
52
- def on_read_stderr(data)
53
- sleep @force_yield if @force_yield
54
- @error_text << data
55
- end
52
+ def on_read_stderr(data)
53
+ sleep @force_yield if @force_yield
54
+ @error_text << data
55
+ end
56
+
57
+ def on_pid(pid)
58
+ raise "PID already set!" unless @pid.nil?
59
+ @pid = pid
60
+ end
61
+
62
+ def on_timeout
63
+ puts "\n** Failed to run #{@command.inspect}: Timeout" unless @expect_timeout
64
+ @did_timeout = true
65
+ @callback.call(self) if @expect_timeout
66
+ end
67
+
68
+ def on_size_limit
69
+ puts "\n** Failed to run #{@command.inspect}: Size limit" unless @expect_size_limit
70
+ @did_size_limit = true
71
+ @callback.call(self) if @expect_size_limit
72
+ end
56
73
 
57
- def on_pid(pid)
58
- raise "PID already set!" unless @pid.nil?
59
- @pid = pid
74
+ def on_exit(status)
75
+ @status = status
76
+ @callback.call(self)
77
+ end
60
78
  end
61
79
 
62
- def on_exit(status)
63
- @timeout.cancel if @timeout
64
- @status = status
65
- @callback.call(self)
80
+ def initialize
81
+ @count = 0
82
+ @done = false
83
+ @last_exception = nil
84
+ @last_iteration = 0
66
85
  end
67
- end
68
86
 
69
- def initialize
70
- @count = 0
71
- @done = false
72
- @last_exception = nil
73
- @last_iteration = 0
74
- end
87
+ def run_right_popen3(synchronicity, command, runner_options={}, &callback)
88
+ runner_options = {
89
+ :repeats => 1,
90
+ :expect_timeout => false,
91
+ :expect_size_limit => false
92
+ }.merge(runner_options)
93
+ popen3_options = {
94
+ :input => runner_options[:input],
95
+ :environment => runner_options[:env],
96
+ :timeout_seconds => runner_options.has_key?(:timeout) ? runner_options[:timeout] : 2,
97
+ :size_limit_bytes => runner_options[:size_limit_bytes],
98
+ :watch_directory => runner_options[:watch_directory]
99
+ }
100
+ case synchronicity
101
+ when :sync
102
+ run_right_popen3_sync(command, runner_options, popen3_options, &callback)
103
+ when :async
104
+ run_right_popen3_async(command, runner_options, popen3_options, &callback)
105
+ else
106
+ raise "unknown synchronicity = #{synchronicity.inspect}"
107
+ end
108
+ end
75
109
 
76
- def do_right_popen(command, options={}, &callback)
77
- options = {:env=>nil, :input=>nil, :timeout=>nil, :force_yield=>nil, :expect_timeout=>false}.merge(options)
78
- status = RunnerStatus.new(command, options, &callback)
79
- RightScale.popen3(:command => command,
80
- :input => options[:input],
81
- :target => status,
82
- :environment => options[:env],
83
- :stdout_handler => :on_read_stdout,
84
- :stderr_handler => :on_read_stderr,
85
- :pid_handler => :on_pid,
86
- :exit_handler => :on_exit)
87
- status
88
- end
110
+ def run_right_popen3_sync(command, runner_options, popen3_options, &callback)
111
+ begin
112
+ @iterations = 0
113
+ @repeats = runner_options[:repeats]
114
+ @stats = []
115
+ while @iterations < @repeats
116
+ @iterations += 1
117
+ do_right_popen3_sync(command, runner_options, popen3_options) do |runner_status|
118
+ @stats << runner_status
119
+ callback.call(runner_status) if callback
120
+ if @repeats > 1
121
+ puts if 1 == (@iterations % 64)
122
+ print '+'
123
+ puts if @iterations == @repeats
124
+ end
125
+ end
126
+ end
127
+ @stats.uniq!
128
+ @stats.size < 2 ? @stats.first : @stats
129
+ rescue Exception => e
130
+ puts "\n** Failed: #{e.message} FROM\n#{e.backtrace.join("\n")}"
131
+ raise e
132
+ end
133
+ end
89
134
 
90
- def run_right_popen(command, options={}, &callback)
91
- options = {:repeats=>1, :env=>nil, :input=>nil, :timeout=>nil, :force_yield=>nil, :expect_timeout=>false}.merge(options)
92
- begin
93
- @iterations = 0
94
- @repeats = options[:repeats]
95
- @stats = []
96
- EM.run do
97
- EM.defer do
98
- do_right_popen(command, options) do |status|
99
- maybe_continue(status, command, options, &callback)
135
+ def run_right_popen3_async(command, runner_options, popen3_options, &callback)
136
+ begin
137
+ @iterations = 0
138
+ @repeats = runner_options[:repeats]
139
+ @stats = []
140
+ EM.run do
141
+ EM.defer do
142
+ begin
143
+ do_right_popen3_async(command, runner_options, popen3_options) do |runner_status|
144
+ maybe_continue_popen3_async(runner_status, command, runner_options, popen3_options, &callback)
145
+ end
146
+ rescue Exception => e
147
+ puts e.class, e.message, e.backtrace.join("\n")
148
+ EM.stop
149
+ end
100
150
  end
101
151
  end
152
+ @stats.uniq!
153
+ @stats.size < 2 ? @stats.first : @stats
154
+ rescue Exception => e
155
+ puts "\n** Failed: #{e.message} FROM\n#{e.backtrace.join("\n")}"
156
+ raise e
102
157
  end
103
- @stats.size < 2 ? @stats.first : @stats
104
- rescue Exception => e
105
- puts "\n** Failed: #{e.message} FROM\n#{e.backtrace.join("\n")}"
106
- raise e
107
158
  end
108
- end
109
159
 
110
- def maybe_continue(status, command, options, &callback)
111
- @iterations += 1
112
- @stats << status
113
- callback.call(status) if callback
114
- if @iterations < @repeats
115
- EM.defer do
116
- do_right_popen(command, options) do |status|
117
- maybe_continue(status, command, options, &callback)
160
+ def do_right_popen3(synchronicity, command, runner_options, popen3_options, &callback)
161
+ runner_status = RunnerStatus.new(command, runner_options, &callback)
162
+ popen3_options = {
163
+ :target => runner_status,
164
+ :stdout_handler => :on_read_stdout,
165
+ :stderr_handler => :on_read_stderr,
166
+ :pid_handler => :on_pid,
167
+ :timeout_handler => :on_timeout,
168
+ :size_limit_handler => :on_size_limit,
169
+ :exit_handler => :on_exit
170
+ }.merge(popen3_options)
171
+ case synchronicity
172
+ when :sync
173
+ result = ::RightScale::RightPopen.popen3_sync(command, popen3_options)
174
+ when :async
175
+ result = ::RightScale::RightPopen.popen3_async(command, popen3_options)
176
+ else
177
+ raise "Uknown synchronicity = #{synchronicity.inspect}"
178
+ end
179
+ result.should == true
180
+ true
181
+ end
182
+
183
+ def do_right_popen3_sync(command, runner_options, popen3_options, &callback)
184
+ do_right_popen3(:sync, command, runner_options, popen3_options, &callback)
185
+ end
186
+
187
+ def do_right_popen3_async(command, runner_options, popen3_options, &callback)
188
+ do_right_popen3(:async, command, runner_options, popen3_options, &callback)
189
+ end
190
+
191
+ def maybe_continue_popen3_async(runner_status, command, runner_options, popen3_options, &callback)
192
+ @iterations += 1
193
+ @stats << runner_status
194
+ callback.call(runner_status) if callback
195
+ if @iterations < @repeats
196
+ if @repeats > 1
197
+ puts if 1 == (@iterations % 64)
198
+ print '+'
199
+ puts if @iterations == @repeats
200
+ end
201
+ EM.defer do
202
+ begin
203
+ do_right_popen3_async(command, runner_options, popen3_options) do |runner_status2|
204
+ maybe_continue_popen3_async(runner_status2, command, runner_options, popen3_options, &callback)
205
+ end
206
+ rescue Exception => e
207
+ puts e.class, e.message, e.backtrace.join("\n")
208
+ EM.stop
209
+ end
118
210
  end
211
+ else
212
+ EM.stop
119
213
  end
120
- else
121
- EM.stop
122
214
  end
123
215
  end
124
216
  end
@@ -0,0 +1,35 @@
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
+ REPEATS = (ARGV[0] || '4').to_i
25
+
26
+ STDOUT.sync = true
27
+ STDERR.sync = true
28
+ REPEATS.times do |i|
29
+ STDOUT.puts "To sleep... #{i}"
30
+ STDERR.puts "Perchance to dream... #{i}"
31
+ sleep 1
32
+ end
33
+ STDOUT.puts "The sleeper must awaken."
34
+
35
+ exit 0
@@ -23,6 +23,6 @@
23
23
 
24
24
  $stderr.puts "Closing stdout"
25
25
  STDOUT.close
26
- sleep 3
26
+ sleep 15
27
27
  $stderr.puts "Exiting"
28
28
  exit 0
@@ -0,0 +1,34 @@
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
+ watched_dir = ARGV[0]
25
+
26
+ 10.times do |i|
27
+ path = ::File.join(watched_dir, "file#{i}.txt")
28
+ ::File.open(path, 'w') do |f|
29
+ f.write 'x' * 100
30
+ end
31
+ sleep 0.2
32
+ end
33
+
34
+ exit 0
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: right_popen
3
3
  version: !ruby/object:Gem::Version
4
- hash: 61
5
- prerelease: false
4
+ hash: 21
5
+ prerelease:
6
6
  segments:
7
7
  - 1
8
- - 0
9
- - 21
10
- version: 1.0.21
8
+ - 1
9
+ - 3
10
+ version: 1.1.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Scott Messier
@@ -17,26 +17,26 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2012-04-25 00:00:00 -07:00
21
- default_executable:
20
+ date: 2013-07-17 00:00:00 Z
22
21
  dependencies:
23
22
  - !ruby/object:Gem::Dependency
23
+ prerelease: false
24
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
25
  none: false
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- hash: 57
29
+ hash: 23
30
30
  segments:
31
+ - 1
31
32
  - 0
32
- - 12
33
- - 11
34
- version: 0.12.11
35
- type: :runtime
36
- name: eventmachine
37
- prerelease: false
33
+ - 0
34
+ version: 1.0.0
38
35
  version_requirements: *id001
36
+ name: eventmachine
37
+ type: :development
39
38
  - !ruby/object:Gem::Dependency
39
+ prerelease: false
40
40
  requirement: &id002 !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
@@ -47,11 +47,11 @@ dependencies:
47
47
  - 1
48
48
  - 3
49
49
  version: "1.3"
50
- type: :development
51
- name: rspec
52
- prerelease: false
53
50
  version_requirements: *id002
51
+ name: rspec
52
+ type: :development
54
53
  - !ruby/object:Gem::Dependency
54
+ prerelease: false
55
55
  requirement: &id003 !ruby/object:Gem::Requirement
56
56
  none: false
57
57
  requirements:
@@ -63,11 +63,11 @@ dependencies:
63
63
  - 8
64
64
  - 7
65
65
  version: 0.8.7
66
- type: :development
67
- name: rake
68
- prerelease: false
69
66
  version_requirements: *id003
67
+ name: rake
68
+ type: :development
70
69
  - !ruby/object:Gem::Dependency
70
+ prerelease: false
71
71
  requirement: &id004 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
@@ -77,10 +77,9 @@ dependencies:
77
77
  segments:
78
78
  - 0
79
79
  version: "0"
80
- type: :development
81
- name: flexmock
82
- prerelease: false
83
80
  version_requirements: *id004
81
+ name: flexmock
82
+ type: :development
84
83
  description: |
85
84
  RightPopen allows running external processes aynchronously while still
86
85
  capturing their standard and error outputs. It relies on EventMachine for most
@@ -100,9 +99,14 @@ files:
100
99
  - Rakefile
101
100
  - lib/right_popen.rb
102
101
  - lib/right_popen/linux/accumulator.rb
102
+ - lib/right_popen/linux/popen3_async.rb
103
+ - lib/right_popen/linux/popen3_sync.rb
103
104
  - lib/right_popen/linux/process.rb
104
- - lib/right_popen/linux/right_popen.rb
105
105
  - lib/right_popen/linux/utilities.rb
106
+ - lib/right_popen/process_base.rb
107
+ - lib/right_popen/process_status.rb
108
+ - lib/right_popen/safe_output_buffer.rb
109
+ - lib/right_popen/target_proxy.rb
106
110
  - lib/right_popen/version.rb
107
111
  - right_popen.gemspec
108
112
  - spec/background.rb
@@ -115,11 +119,13 @@ files:
115
119
  - spec/produce_stdout_only.rb
116
120
  - spec/right_popen/linux/accumulator_spec.rb
117
121
  - spec/right_popen/linux/utilities_spec.rb
122
+ - spec/right_popen/safe_output_buffer_spec.rb
118
123
  - spec/right_popen_spec.rb
119
124
  - spec/runner.rb
125
+ - spec/sleeper.rb
120
126
  - spec/spec_helper.rb
121
127
  - spec/stdout.rb
122
- has_rdoc: true
128
+ - spec/writer.rb
123
129
  homepage: https://github.com/rightscale/right_popen
124
130
  licenses: []
125
131
 
@@ -154,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
160
  requirements: []
155
161
 
156
162
  rubyforge_project: right_popen
157
- rubygems_version: 1.3.7
163
+ rubygems_version: 1.8.15
158
164
  signing_key:
159
165
  specification_version: 3
160
166
  summary: Provides a platform-independent popen implementation