linedump 0.1.0
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 +7 -0
- data/lib/linedump/consumer.rb +101 -0
- data/lib/linedump/stream_wrapper.rb +55 -0
- data/lib/linedump/version.rb +3 -0
- data/lib/linedump.rb +16 -0
- metadata +153 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0e4178abce450d405b7d4aaa896396dc7cb4adc2
|
4
|
+
data.tar.gz: 785a239c2e41e6ff3b0cd3d683fcdad1ef1489b8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6c43e82bc03b8109687e5a4c47f57b666a5da1598cf0854a4bb03e607f1e3c6e31874346f3d7bf9e9d720fa330ae42f1e67bbff43e57a063a4a4265c30374782
|
7
|
+
data.tar.gz: 3ddd976ec104f39325fd7208ae5cb87b45b7156276c31df3ef656b6565d7f7521fbd74096c7b7a4dbbe0276b4b4669b3d1844876da2e8a21f3cb5d59282cd453
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require "thwait"
|
2
|
+
require "linedump/stream_wrapper"
|
3
|
+
|
4
|
+
module Linedump
|
5
|
+
|
6
|
+
class Consumer
|
7
|
+
|
8
|
+
class StopSignal < Exception; end
|
9
|
+
|
10
|
+
class ReloadSignal < Exception; end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@streams = []
|
14
|
+
@lock = Mutex.new
|
15
|
+
@worker = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def register_stream(_stream, &_block)
|
19
|
+
# TODO: locking for non-GIL platforms
|
20
|
+
@streams << StreamWrapper.new(_stream, _block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def is_registered?(_stream)
|
24
|
+
not find_stream_wrapper(_stream).nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
def reload
|
28
|
+
@lock.synchronize do
|
29
|
+
if @worker and @worker.alive?
|
30
|
+
@worker.raise ReloadSignal # signal worker to reload streams
|
31
|
+
else
|
32
|
+
@worker = load_worker
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def stop
|
38
|
+
@lock.synchronize do
|
39
|
+
if @worker and @worker.alive?
|
40
|
+
@worker.raise StopSignal
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def load_worker
|
48
|
+
Thread.new do
|
49
|
+
looped = 0
|
50
|
+
begin
|
51
|
+
while @streams.count > 0
|
52
|
+
read_streams = load_monitored_streams
|
53
|
+
result = IO.select(read_streams, [], read_streams)
|
54
|
+
if result
|
55
|
+
process_ready_streams result[0]
|
56
|
+
discard_errored_streams result[2]
|
57
|
+
end
|
58
|
+
looped += 1
|
59
|
+
end
|
60
|
+
rescue ReloadSignal
|
61
|
+
retry
|
62
|
+
rescue StopSignal, SystemExit
|
63
|
+
# nothing
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def process_ready_streams(_streams)
|
69
|
+
_streams.each do |stream|
|
70
|
+
wrapper = find_stream_wrapper stream
|
71
|
+
if wrapper
|
72
|
+
wrapper.process_lines
|
73
|
+
remove_wrapper wrapper, :eof if wrapper.eof?
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def discard_errored_streams(_streams)
|
79
|
+
_streams.each do |stream|
|
80
|
+
wrapper = find_stream_wrapper stream
|
81
|
+
remove_wrapper wrapper, :error if wrapper
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def find_stream_wrapper(_stream)
|
86
|
+
@streams.find { |s| s.stream == _stream }
|
87
|
+
end
|
88
|
+
|
89
|
+
def remove_wrapper(_wrapper, _reason)
|
90
|
+
# TODO: locking for non-GIL platforms
|
91
|
+
@streams.delete _wrapper
|
92
|
+
end
|
93
|
+
|
94
|
+
def load_monitored_streams
|
95
|
+
# include stdin to prevent console enabled apps from locking
|
96
|
+
@streams.map(&:stream) << $stdin
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Linedump
|
2
|
+
|
3
|
+
class StreamWrapper
|
4
|
+
|
5
|
+
MAX_LENGTH = 2048
|
6
|
+
|
7
|
+
attr_reader :stream
|
8
|
+
|
9
|
+
def initialize(_stream, _block)
|
10
|
+
@stream = _stream
|
11
|
+
@block = _block
|
12
|
+
@buffer = []
|
13
|
+
@eof = false
|
14
|
+
end
|
15
|
+
|
16
|
+
def eof?
|
17
|
+
@eof
|
18
|
+
end
|
19
|
+
|
20
|
+
def process_lines
|
21
|
+
begin
|
22
|
+
loop do
|
23
|
+
chunk = @stream.read_nonblock(MAX_LENGTH)
|
24
|
+
process_chunk chunk
|
25
|
+
end
|
26
|
+
rescue IO::WaitReadable
|
27
|
+
# nothing, just stop looping
|
28
|
+
rescue EOFError, IOError
|
29
|
+
@eof = true
|
30
|
+
rescue Exception => exc
|
31
|
+
puts "Error in stream consumer: #{exc.class}" # TODO: not sure where to send this error
|
32
|
+
@eof = true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def process_chunk(_chunk)
|
39
|
+
index = _chunk.index $/
|
40
|
+
|
41
|
+
unless index.nil?
|
42
|
+
head = _chunk[0..index-1]
|
43
|
+
tail = _chunk[index+1..-1]
|
44
|
+
|
45
|
+
@block.call(@buffer.join + head)
|
46
|
+
@buffer.clear
|
47
|
+
|
48
|
+
process_chunk tail
|
49
|
+
else
|
50
|
+
@buffer << _chunk
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
data/lib/linedump.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "linedump/version"
|
2
|
+
require "linedump/consumer"
|
3
|
+
|
4
|
+
module Linedump
|
5
|
+
|
6
|
+
def self.consumer
|
7
|
+
@@consumer ||= Consumer.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.each_line(_stream, &_block)
|
11
|
+
consumer.register_stream _stream, &_block
|
12
|
+
consumer.reload
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: linedump
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ignacio Baixas
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-09-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.4'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.4'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec-nc
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.2'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: guard
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.11'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.11'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: guard-rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '4.5'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '4.5'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: terminal-notifier-guard
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.6'
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: 1.6.1
|
107
|
+
type: :development
|
108
|
+
prerelease: false
|
109
|
+
version_requirements: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - "~>"
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '1.6'
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 1.6.1
|
117
|
+
description: linedump allows you to register blocks to consume live output streams,
|
118
|
+
line by line.
|
119
|
+
email:
|
120
|
+
- ignacio@platan.us
|
121
|
+
executables: []
|
122
|
+
extensions: []
|
123
|
+
extra_rdoc_files: []
|
124
|
+
files:
|
125
|
+
- lib/linedump.rb
|
126
|
+
- lib/linedump/consumer.rb
|
127
|
+
- lib/linedump/stream_wrapper.rb
|
128
|
+
- lib/linedump/version.rb
|
129
|
+
homepage: https://github.com/platanus/linedump-gem
|
130
|
+
licenses:
|
131
|
+
- MIT
|
132
|
+
metadata: {}
|
133
|
+
post_install_message:
|
134
|
+
rdoc_options: []
|
135
|
+
require_paths:
|
136
|
+
- lib
|
137
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
requirements: []
|
148
|
+
rubyforge_project:
|
149
|
+
rubygems_version: 2.4.5
|
150
|
+
signing_key:
|
151
|
+
specification_version: 4
|
152
|
+
summary: Process output stream listener helper
|
153
|
+
test_files: []
|