eventmachine-tail 0.1.20100506012705 → 0.2.20100516235116

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/bin/rtail CHANGED
@@ -2,31 +2,75 @@
2
2
  require "rubygems"
3
3
  require "eventmachine"
4
4
  require "eventmachine-tail"
5
+ require "optparse"
5
6
 
6
7
  class Reader < EventMachine::FileTail
7
- def initialize(path, startpos=-1)
8
+ def initialize(path, startpos=-1, with_filenames=true)
8
9
  super(path, startpos)
9
10
  @buffer = BufferedTokenizer.new
11
+ @with_filenames = with_filenames
10
12
  end
11
13
 
12
14
  def receive_data(data)
13
15
  @buffer.extract(data).each do |line|
14
- puts "#{path}: #{line}"
15
- end
16
- end
17
- end
16
+ if @with_filenames # global flag, see the '-n' option
17
+ puts "#{path}: #{line}"
18
+ else
19
+ puts line
20
+ end # if @with_filenames
21
+ end # buffer extract
22
+ end # def receive_data
23
+ end # class Reader
24
+
25
+ def pattern_to_regexp(pattern)
26
+ pattern.gsub!(".", "\\.") # fix literal .
27
+ pattern.gsub!("*", ".+") # * becomes .+
28
+ pattern.gsub!("?", ".") # ? becomes .
29
+ return Regexp.new(pattern)
30
+ end # def pattern_to_regexp
18
31
 
19
32
  def main(args)
33
+ with_filenames = true
34
+ globcheck_interval = 5
35
+ exclude_patterns = []
36
+
37
+ opts = OptionParser.new do |opts|
38
+ opts.banner = "Usage: #{$0} [options] <path_or_glob> [path_or_glob2] [...]"
39
+
40
+ opts.on("-n", "--no-filename",
41
+ "Supress prefixing of output with file names") do |x|
42
+ with_filenames = false
43
+ end # -n
44
+
45
+ opts.on("-i SECONDS", "--check-interval SECONDS",
46
+ "How frequently, in seconds, to check the glob patterns" \
47
+ "for new files") do |x|
48
+ globcheck_interval = x.to_f
49
+ end # -i SECONDS
50
+
51
+ opts.on("-x EXCLUDE", "--exclude EXCLUDE",
52
+ "A pattern to ignore. Wildcard/globs accepted." \
53
+ " Can be specified multiple times") do |pattern|
54
+ exclude_patterns << pattern_to_regexp(pattern)
55
+ end
56
+ end # OptionParser
57
+
58
+ opts.parse!(args)
59
+
20
60
  if args.length == 0
21
- puts "Usage: #{$0} <path_or_glob> [path_or_glob2] [...]"
61
+ puts opts.banner
22
62
  return 1
23
63
  end
24
64
 
25
65
  EventMachine.run do
26
66
  args.each do |path|
27
- EventMachine::FileGlobWatchTail.new(path, Reader)
28
- end
29
- end
67
+ EventMachine::FileGlobWatchTail.new(path, Reader,
68
+ interval = globcheck_interval,
69
+ exclude = exclude_patterns,
70
+ start_pos = -1,
71
+ with_filenames = with_filenames)
72
+ end # args.each
73
+ end # EventMachine.run
30
74
  end # def main
31
75
 
32
76
  exit(main(ARGV))
data/lib/em/filetail.rb CHANGED
@@ -43,6 +43,7 @@ class EventMachine::FileTail
43
43
  @logger.level = ($DEBUG and Logger::DEBUG or Logger::WARN)
44
44
  @logger.debug("Tailing #{path} starting at position #{startpos}")
45
45
 
46
+ @file = nil
46
47
  @fstat = File.stat(@path)
47
48
 
48
49
  if @fstat.directory?
@@ -62,7 +62,6 @@ class EventMachine::FileGlobWatch
62
62
 
63
63
  private
64
64
  def add(path)
65
- @logger.info "Watching #{path}"
66
65
  @files.add(path)
67
66
 
68
67
  # If EventMachine::watch_file fails, that's ok, I guess.
@@ -97,15 +96,26 @@ class EventMachine::FileGlobWatch
97
96
  end # class EventMachine::FileGlobWatch
98
97
 
99
98
  class EventMachine::FileGlobWatchTail < EventMachine::FileGlobWatch
100
- def initialize(path, handler=nil, interval=60, *args)
99
+ def initialize(path, handler=nil, interval=60, exclude=[], *args)
101
100
  super(path, interval)
102
101
  @handler = handler
103
102
  @args = args
103
+ @exclude = exclude
104
104
  end
105
105
 
106
106
  def file_found(path)
107
107
  begin
108
- EventMachine::file_tail(path, @handler)
108
+ @logger.info "#{self.class}: Trying #{path}"
109
+ @exclude.each do |exclude|
110
+ @logger.info "#{self.class}: Testing #{exclude} =~ #{path} == #{exclude.match(path) != nil}"
111
+ if exclude.match(path) != nil
112
+ file_excluded(path)
113
+ return
114
+ end
115
+ end
116
+ @logger.info "#{self.class}: Watching #{path}"
117
+
118
+ EventMachine::file_tail(path, @handler, *@args)
109
119
  rescue Errno::EACCES => e
110
120
  file_error(path, e)
111
121
  rescue Errno::EISDIR => e
@@ -113,13 +123,17 @@ class EventMachine::FileGlobWatchTail < EventMachine::FileGlobWatch
113
123
  end
114
124
  end
115
125
 
126
+ def file_excluded(path)
127
+ @logger.info "#{self.class}: Skipping path #{path} due to exclude rule"
128
+ end
129
+
116
130
  def file_removed(path)
117
131
  # Nothing to do
118
132
  end
119
133
 
120
134
  def file_error(path, e)
121
135
  $stderr.puts "#{e.class} while trying to tail #{path}"
122
- # Ignore by default
136
+ # otherwise, drop the error by default
123
137
  end
124
138
  end # class EventMachine::FileGlobWatchHandler
125
139
 
@@ -133,4 +147,14 @@ module EventMachine
133
147
  yield c if block_given?
134
148
  return c
135
149
  end
136
- end
150
+
151
+ def self.watch_glob(path, handler=nil, *args)
152
+ # This code mostly styled on what EventMachine does in many of it's other
153
+ # methods.
154
+ args = [path, *args]
155
+ klass = klass_from_handler(EventMachine::FileGlobWatch, handler, *args);
156
+ c = klass.new(*args)
157
+ yield c if block_given?
158
+ return c
159
+ end # def EventMachine::watch_glob
160
+ end # module EventMachine
@@ -6,6 +6,7 @@ require 'eventmachine-tail'
6
6
  require 'tempfile'
7
7
  require 'test/unit'
8
8
  require 'timeout'
9
+ require 'testcase_helpers.rb'
9
10
 
10
11
 
11
12
  # Generate some data
@@ -27,20 +28,13 @@ class Reader < EventMachine::FileTail
27
28
  expected = @data.shift
28
29
  @testobj.assert_equal(expected, line,
29
30
  "Expected '#{expected}' on line #{@lineno}, but got '#{line}'")
30
- if @data.length == 0
31
- EM.stop_event_loop
32
- end
31
+ @testobj.finish if @data.length == 0
33
32
  end # @buffer.extract
34
33
  end # def receive_data
35
34
  end # class Reader
36
35
 
37
36
  class TestFileTail < Test::Unit::TestCase
38
- def abort_after_timeout(seconds)
39
- EM::Timer.new(seconds) do
40
- EM.stop_event_loop
41
- flunk("Timeout (#{seconds} seconds) while running tests. Failing.")
42
- end
43
- end
37
+ include EventMachineTailTestHelpers
44
38
 
45
39
  # This test should run slow. We are trying to ensure that
46
40
  # our file_tail correctly reads data slowly fed into the file
data/test/test_glob.rb ADDED
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ $:.unshift "#{File.dirname(__FILE__)}/../lib"
5
+ require 'eventmachine-tail'
6
+ require 'tempfile'
7
+ require 'test/unit'
8
+ require 'timeout'
9
+ require 'tmpdir'
10
+
11
+ require 'testcase_helpers'
12
+
13
+ class Watcher < EventMachine::FileGlobWatch
14
+ def initialize(path, interval, data, testobj)
15
+ super(path, interval)
16
+ @data = data
17
+ @testobj = testobj
18
+ end # def initialize
19
+
20
+ def file_found(path)
21
+ # Use .include? here because files aren't going to be found in any
22
+ # particular order.
23
+ @testobj.assert(@data.include?(path), "Expected #{path} in \n#{@data.join("\n")}")
24
+ @data.delete(path)
25
+ @testobj.finish if @data.length == 0
26
+ end
27
+
28
+ def file_removed(path)
29
+ @testobj.assert(@data.include?(path), "Expected #{path} in \n#{@data.join("\n")}")
30
+ @data.delete(path)
31
+ @testobj.finish if @data.length == 0
32
+ end
33
+ end # class Reader
34
+
35
+ class TestGlobWatcher < Test::Unit::TestCase
36
+ include EventMachineTailTestHelpers
37
+ SLEEPMAX = 2
38
+
39
+ def setup
40
+ @watchinterval = 0.2
41
+ @dir = Dir.mktmpdir
42
+ @data = []
43
+ @data << "#{@dir}/#{rand}"
44
+ @data << "#{@dir}/#{rand}"
45
+ @data << "#{@dir}/#{rand}"
46
+ @data << "#{@dir}/#{rand}"
47
+ @data << "#{@dir}/#{rand}"
48
+ @data << "#{@dir}/#{rand}"
49
+ @data << "#{@dir}/#{rand}"
50
+ @data << "#{@dir}/#{rand}.gz"
51
+ @data << "#{@dir}/#{rand}.gz"
52
+ @data << "#{@dir}/#{rand}.tar.gz"
53
+ end # def setup
54
+
55
+ def teardown
56
+ @data.each do |file|
57
+ #puts "Deleting #{file}"
58
+ File.delete(file) rescue nil
59
+ end
60
+ Dir.delete(@dir)
61
+ end # def teardown
62
+
63
+ def finish
64
+ EM.stop_event_loop
65
+ end
66
+
67
+ def test_glob_finds_existing_files
68
+ EM.run do
69
+ abort_after_timeout(SLEEPMAX * @data.length + 10)
70
+
71
+ @data.each do |path|
72
+ File.new(path, "w").close
73
+ end
74
+ EM::watch_glob("#{@dir}/*", Watcher, @watchinterval, @data.clone, self)
75
+ end # EM.run
76
+ end # def test_glob_finds_existing_files
77
+
78
+ # This test should run slow. We are trying to ensure that
79
+ # our file_tail correctly reads data slowly fed into the file
80
+ # as 'tail -f' would.
81
+ def test_glob_finds_newly_created_files_at_runtime
82
+ EM.run do
83
+ abort_after_timeout(SLEEPMAX * @data.length + 10)
84
+
85
+ EM::watch_glob("#{@dir}/*", Watcher, @watchinterval, @data.clone, self)
86
+ datacopy = @data.clone
87
+ timer = EM::PeriodicTimer.new(0.2) do
88
+ #puts "Creating: #{datacopy.first}"
89
+ File.new(datacopy.shift, "w")
90
+ sleep(rand * SLEEPMAX)
91
+ timer.cancel if datacopy.length == 0
92
+ end
93
+ end # EM.run
94
+ end # def test_glob_finds_newly_created_files_at_runtime
95
+ end # class TestGlobWatcher
96
+
@@ -0,0 +1,13 @@
1
+
2
+ module EventMachineTailTestHelpers
3
+ def abort_after_timeout(seconds)
4
+ EM::Timer.new(seconds) do
5
+ EM.stop_event_loop
6
+ flunk("Timeout (#{seconds} seconds) while running tests. Failing.")
7
+ end
8
+ end
9
+
10
+ def finish
11
+ EventMachine.stop_event_loop
12
+ end
13
+ end # module EventMachineTailTestHelpers
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- - 20100506012705
9
- version: 0.1.20100506012705
7
+ - 2
8
+ - 20100516235116
9
+ version: 0.2.20100516235116
10
10
  platform: ruby
11
11
  authors:
12
12
  - Jordan Sissel
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-05-06 00:00:00 -07:00
17
+ date: 2010-05-16 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -45,6 +45,8 @@ files:
45
45
  - samples/glob-tail.rb
46
46
  - samples/globwatch.rb
47
47
  - test/test_filetail.rb
48
+ - test/test_glob.rb
49
+ - test/testcase_helpers.rb
48
50
  - bin/rtail
49
51
  has_rdoc: true
50
52
  homepage: http://code.google.com/p/semicomplete/wiki/EventMachineTail
@@ -76,6 +78,6 @@ rubyforge_project:
76
78
  rubygems_version: 1.3.6
77
79
  signing_key:
78
80
  specification_version: 3
79
- summary: eventmachine tail - a file tail implementation
81
+ summary: eventmachine tail - a file tail implementation with glob support
80
82
  test_files: []
81
83