em-popen3 0.0.4
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.
- checksums.yaml +15 -0
- data/.gitignore +5 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/README +0 -0
- data/Rakefile +9 -0
- data/em-popen3.gemspec +19 -0
- data/lib/em-popen3.rb +1 -0
- data/lib/em-popen3/popen3.rb +97 -0
- data/lib/em-popen3/version.rb +5 -0
- data/spec/helper.rb +5 -0
- data/spec/popen3_spec.rb +55 -0
- metadata +82 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Njg3ZDUzYjJhNzc2YTQ2MzQ1ZmUwOWRkZTM5YTkzMjA3NmFhODlhYw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MjZhOWIyNTMyMzliZDQyOTIzMjliMTkxN2IzOWU2MmYwMTc3YjA2NQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YjNkZmEwNDU5MDk3Yjg4NWU3Y2ZjZTFmNjNhODFlOTYyYzJkNGU0OTdhNTk1
|
10
|
+
MTI5MGQ5MzA4OGU4M2I4YjQwMDdiYzNhYjQ0NTVkYzQ0Y2Q5NzM5NmFlYTg2
|
11
|
+
MjFmMGQ3MTNiMjFjNGZlYzk3ZmU5ZjdmMzJjNzBiNDMyNzczZjg=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YWExN2JlNzQ0YWZhYWM2MTNlZWU5MTgyZDc2MDRkNzk3YTcxNGU1NGYyYWYw
|
14
|
+
N2E3ODkxNTZhMGQ1ODA1ODA3ODg0ZmRhOGNlODI4NTc5MGJiZTJhZGU5OGRh
|
15
|
+
Nzk4ODY1Y2U3NTFiYmNhZWFhNjAwYjY4ODBlZDhmODdiM2Q5NTM=
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.3@em-popen3 --create
|
data/Gemfile
ADDED
data/README
ADDED
File without changes
|
data/Rakefile
ADDED
data/em-popen3.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
$:.push File.expand_path('../lib', __FILE__)
|
2
|
+
require 'em-popen3/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'em-popen3'
|
6
|
+
s.version = EventMachine::POpen3::VERSION
|
7
|
+
|
8
|
+
s.authors = ['stask']
|
9
|
+
s.email = ['stask@kontera.com']
|
10
|
+
s.summary = "Adds popen3 support to eventmachine"
|
11
|
+
s.description = s.summary
|
12
|
+
s.rubyforge_project = 'em-popen3'
|
13
|
+
|
14
|
+
s.add_dependency 'eventmachine', '>= 1.0.0.beta.4'
|
15
|
+
s.add_dependency 'rake'
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.require_paths = ['lib']
|
19
|
+
end
|
data/lib/em-popen3.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'em-popen3/popen3'
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# --
|
2
|
+
# Author:: stask
|
3
|
+
# inspired by http://pastebin.com/TLgVF8GZ
|
4
|
+
|
5
|
+
require 'open3'
|
6
|
+
|
7
|
+
module EventMachine
|
8
|
+
|
9
|
+
# EM::popen3 is used to launch given command and capture the stdin, stdout and stderr streams.
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
# EM.run do
|
13
|
+
# p = EM.popen3('ls', {
|
14
|
+
# :stdout => Proc.new { |data| puts "stdout: #{data}" },
|
15
|
+
# :stderr => Proc.new { |data| puts "stderr: #{data}" }
|
16
|
+
# })
|
17
|
+
# p.callback do
|
18
|
+
# puts "All good"
|
19
|
+
# end
|
20
|
+
# p.errback do |err_code|
|
21
|
+
# puts "Error: #{err_code}"
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# It returns a deferrable object
|
26
|
+
def self.popen3(cmd, stream_callbacks)
|
27
|
+
raise ArgumentError, "stream_callbacks must be specified" unless stream_callbacks
|
28
|
+
raise ArgumentError, ":stdout callback must be specified" unless stream_callbacks[:stdout].is_a?(Proc)
|
29
|
+
raise ArgumentError, ":stderr callback must be specified" unless stream_callbacks[:stderr].is_a?(Proc)
|
30
|
+
|
31
|
+
POpen3::Wrapper.new(cmd, stream_callbacks)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
module POpen3
|
36
|
+
|
37
|
+
class Wrapper
|
38
|
+
include EM::Deferrable
|
39
|
+
attr_accessor :pipes, :stream_callbacks
|
40
|
+
|
41
|
+
def initialize(cmd, stream_callbacks)
|
42
|
+
@pipes = {}
|
43
|
+
@stream_callbacks = stream_callbacks
|
44
|
+
@stdin, @stdout, @stderr, @wait_thr = Open3.popen3(cmd)
|
45
|
+
@stdin_conn = EM.attach(@stdin, Handler, self, :stdin)
|
46
|
+
@stdout_conn = EM.attach(@stdout, OutHandler, self, :stdout)
|
47
|
+
@stderr_conn = EM.attach(@stderr, OutHandler, self, :stderr)
|
48
|
+
end
|
49
|
+
|
50
|
+
def send_data(data)
|
51
|
+
pipes[:stdin].send_data(data) if pipes.has_key?(:stdin)
|
52
|
+
end
|
53
|
+
|
54
|
+
def kill(signal='TERM', wait=false)
|
55
|
+
Process.kill(signal, @wait_thr.pid)
|
56
|
+
val = @wait_thr.value if wait
|
57
|
+
@stdin_conn.close_connection
|
58
|
+
@stdout_conn.close_connection
|
59
|
+
@stderr_conn.close_connection
|
60
|
+
return val
|
61
|
+
end
|
62
|
+
|
63
|
+
def unbind(name)
|
64
|
+
pipes.delete(name)
|
65
|
+
remove_instance_variable("@"+name.to_s)
|
66
|
+
if pipes.empty?
|
67
|
+
err_code = @wait_thr.value
|
68
|
+
err_code == 0 ? succeed : fail(err_code)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class Handler < EM::Connection
|
74
|
+
def initialize(parent, name)
|
75
|
+
@parent = parent
|
76
|
+
@name = name
|
77
|
+
|
78
|
+
@parent.pipes[@name] = self
|
79
|
+
end
|
80
|
+
|
81
|
+
def unbind
|
82
|
+
begin
|
83
|
+
@io.close unless @io.closed?
|
84
|
+
rescue Exception => e
|
85
|
+
#don't care if the stream has been closed already
|
86
|
+
end
|
87
|
+
@parent.unbind(@name)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class OutHandler < Handler
|
92
|
+
def receive_data(data)
|
93
|
+
@parent.stream_callbacks[@name].call(data) if @parent.stream_callbacks.has_key?(@name)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/spec/helper.rb
ADDED
data/spec/popen3_spec.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
$:.push File.expand_path('../../lib', __FILE__)
|
2
|
+
$:.push File.expand_path('../', __FILE__)
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
describe EventMachine::POpen3 do
|
6
|
+
it "smokes" do
|
7
|
+
cmd = <<EOS
|
8
|
+
ruby -e "\\$stdout.sync = true; \\$stderr.sync=true; gets.to_i.times { |i| \\$stdout.puts i+1; \\$stderr.puts i+1; }"
|
9
|
+
EOS
|
10
|
+
stdout_capture = stderr_capture = ''
|
11
|
+
EM.run do
|
12
|
+
handler = EM.popen3(
|
13
|
+
cmd,
|
14
|
+
:stdout => Proc.new { |data| stdout_capture << data },
|
15
|
+
:stderr => Proc.new { |data| stderr_capture << data })
|
16
|
+
handler.callback do
|
17
|
+
5.times do |i|
|
18
|
+
stdout_capture.must_match(/^#{i+1}$/)
|
19
|
+
stderr_capture.must_match(/^#{i+1}$/)
|
20
|
+
end
|
21
|
+
EM.stop
|
22
|
+
end
|
23
|
+
handler.errback do |err_code|
|
24
|
+
assert(false, "Failed to run command: #{err_code}")
|
25
|
+
EM.stop
|
26
|
+
end
|
27
|
+
handler.send_data("5\n")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "can be killed" do
|
32
|
+
cmd = <<EOS
|
33
|
+
/bin/bash -l -c "trap \"echo TERM;echo 0\" SIGINT SIGTERM;sleep 10"
|
34
|
+
EOS
|
35
|
+
stdout_capture = stderr_capture = ''
|
36
|
+
EM.run do
|
37
|
+
handler = EM.popen3(
|
38
|
+
cmd,
|
39
|
+
:stdout => Proc.new { |data| stdout_capture << data },
|
40
|
+
:stderr => Proc.new { |data| stderr_capture << data }
|
41
|
+
)
|
42
|
+
handler.callback do
|
43
|
+
puts "stopped without error"
|
44
|
+
stdout_capture.must_match(/TERM/)
|
45
|
+
EM.stop
|
46
|
+
end
|
47
|
+
handler.errback do |err_code|
|
48
|
+
assert(false, "Failed to run command: #{err_code}")
|
49
|
+
EM.stop
|
50
|
+
end
|
51
|
+
EM.add_timer(1) { handler.kill('TERM', true) }
|
52
|
+
EM.add_timer(10) { assert(false, 'Failed to kill the damn thing'); EM.stop }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: em-popen3
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- stask
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-04-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: eventmachine
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.0.beta.4
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.0.beta.4
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Adds popen3 support to eventmachine
|
42
|
+
email:
|
43
|
+
- stask@kontera.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- .rvmrc
|
50
|
+
- Gemfile
|
51
|
+
- README
|
52
|
+
- Rakefile
|
53
|
+
- em-popen3.gemspec
|
54
|
+
- lib/em-popen3.rb
|
55
|
+
- lib/em-popen3/popen3.rb
|
56
|
+
- lib/em-popen3/version.rb
|
57
|
+
- spec/helper.rb
|
58
|
+
- spec/popen3_spec.rb
|
59
|
+
homepage:
|
60
|
+
licenses: []
|
61
|
+
metadata: {}
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
requirements: []
|
77
|
+
rubyforge_project: em-popen3
|
78
|
+
rubygems_version: 2.2.2
|
79
|
+
signing_key:
|
80
|
+
specification_version: 4
|
81
|
+
summary: Adds popen3 support to eventmachine
|
82
|
+
test_files: []
|