ffilewatch 0.6.0 → 0.6.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 211f6275bcf6037d2e6379dd206e268ebbf77362
4
- data.tar.gz: b329672228fc6ddd30802abae8803f550d7e84a1
3
+ metadata.gz: 07a481af51457dff387bdf3cb7d33fe0dbe056bd
4
+ data.tar.gz: 60d50fa77dba07d4faf31526e2aa56be0a4ff663
5
5
  SHA512:
6
- metadata.gz: f9d01a57ce62ab9737847fc61ca14e98f17656ec0d0f1c2db52d3024fd86f56d33f2bf30e13d20de272fff75d38db07c345244463def7bb894fdb2e87ce3f9d1
7
- data.tar.gz: 61084794c8ffdc1866c4c6b8cb23f94118a8ec92de05c6caffe6f0daa5238382890e71b848f729c3241fdb7e2b31b177f1eef270a521cc5e1994ca26929808ac
6
+ metadata.gz: 31810de1925838adb880afe3de1cd5ff465e87430f738f29d0ef9ea06b91d914e95b56a541ea97472a2b87f34bd92495b4670fc7baa4cc2d82208714b0b4c225
7
+ data.tar.gz: 59fcaef74a58f8e03d3b4035c093e5fc314ba3043be58aa7918422c965e6bcc21ae9e13456332809589181be44699649aab28c77b71d2979ff4bd6150ae9bbad
@@ -1,8 +1,5 @@
1
- require "filewatch/buftok"
1
+ require 'buftok'
2
2
  require "filewatch/watch"
3
- if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
4
- require "filewatch/winhelper"
5
- end
6
3
  require "logger"
7
4
  require "rbconfig"
8
5
 
@@ -21,8 +18,6 @@ module FileWatch
21
18
 
22
19
  public
23
20
  def initialize(opts={})
24
- @iswindows = ((RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/) != nil)
25
-
26
21
  if opts[:logger]
27
22
  @logger = opts[:logger]
28
23
  else
@@ -43,7 +38,7 @@ module FileWatch
43
38
  @sincedb_writing = false
44
39
  @statcache = {}
45
40
  @opts = {
46
- :eviction_interval => 60,
41
+ :eviction_interval => 300, # Let go of file handles after five minutes
47
42
  :sincedb_write_interval => 10,
48
43
  :stat_interval => 1,
49
44
  :discover_interval => 5,
@@ -81,7 +76,7 @@ module FileWatch
81
76
  @opts[:discover_interval]) do |event, path|
82
77
  case event
83
78
  when :create, :create_initial
84
- if @files.member?(path)
79
+ if @files[path].nil?
85
80
  @logger.debug("#{event} for #{path}: already exists in @files")
86
81
  next
87
82
  end
@@ -89,7 +84,7 @@ module FileWatch
89
84
  _read_file(path, &block)
90
85
  end
91
86
  when :modify
92
- if !@files.member?(path)
87
+ if @files[path].nil?
93
88
  @logger.debug(":modify for #{path}, does not exist in @files")
94
89
  if _open_file(path, event)
95
90
  _read_file(path, &block)
@@ -117,11 +112,7 @@ module FileWatch
117
112
  @logger.debug("_open_file: #{path}: opening")
118
113
  @locked[path] = true
119
114
  begin
120
- if @iswindows && defined? JRUBY_VERSION
121
- @files[path] = Java::RubyFileExt::getRubyFile(path)
122
- else
123
- @files[path] = File.open(path)
124
- end
115
+ @files[path] = File.open(path)
125
116
  rescue
126
117
  # don't emit this message too often. if a file that we can't
127
118
  # read is changing a lot, we'll try to open it more often,
@@ -148,12 +139,7 @@ module FileWatch
148
139
  # construct the inode key using the path which will be 'stable'
149
140
  inode = [path, stat.dev_major, stat.dev_minor]
150
141
  else
151
- if @iswindows
152
- fileId = Winhelper.GetWindowsUniqueFileIdentifier(path)
153
- inode = [fileId, stat.dev_major, stat.dev_minor]
154
- else
155
- inode = [stat.ino.to_s, stat.dev_major, stat.dev_minor]
156
- end
142
+ inode = [stat.ino.to_s, stat.dev_major, stat.dev_minor]
157
143
  end
158
144
 
159
145
  @statcache[path] = inode
@@ -191,7 +177,7 @@ module FileWatch
191
177
  private
192
178
  def _read_file(path, &block)
193
179
  @locked[path] = true
194
- @buffers[path] ||= FileWatch::BufferedTokenizer.new
180
+ @buffers[path] ||= ::BufferedTokenizer.new
195
181
 
196
182
  changed = false
197
183
  loop do
@@ -319,20 +305,22 @@ module FileWatch
319
305
 
320
306
  private
321
307
  def _start_eviction
308
+ sleep_interval = 5
309
+ sleep_interval = 10 if @opts[:eviction_interval] >= 100
322
310
  @evict = Thread.new do
323
311
  loop do
324
312
  now = Time.now.to_i
325
313
  @changed.keys.each do |path|
326
314
  next if now - @changed[path] < @opts[:eviction_interval]
327
315
  next if @locked[path]
328
- next unless @files.include?(path)
316
+ next if @files[path].nil?
329
317
  @logger.debug(":evict for #{path}, deleted from @files")
330
318
  @files.delete(path).close
331
319
  @statcache.delete(path)
332
320
  @changed.delete(path)
333
321
  @locked.delete(path)
334
322
  end
335
- sleep 5
323
+ sleep sleep_interval
336
324
  end
337
325
  end
338
326
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffilewatch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Sissel
@@ -9,8 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-08-05 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2014-08-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: buftok
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
14
28
  description: Watch files and directories in ruby. Also supports tailing and glob file
15
29
  patterns.
16
30
  email:
@@ -22,10 +36,8 @@ extra_rdoc_files: []
22
36
  files:
23
37
  - bin/globtail
24
38
  - lib/JRubyFileExtension.jar
25
- - lib/filewatch/buftok.rb
26
39
  - lib/filewatch/tail.rb
27
40
  - lib/filewatch/watch.rb
28
- - lib/filewatch/winhelper.rb
29
41
  - test/filewatch/tail.rb
30
42
  - test/globtail/Makefile
31
43
  - test/globtail/framework.sh
@@ -1,139 +0,0 @@
1
- # BufferedTokenizer - Statefully split input data by a specifiable token
2
- #
3
- # Authors:: Tony Arcieri, Martin Emde
4
- #
5
- #----------------------------------------------------------------------------
6
- #
7
- # Copyright (C) 2006-07 by Tony Arcieri and Martin Emde
8
- #
9
- # Distributed under the Ruby license (http://www.ruby-lang.org/en/LICENSE.txt)
10
- #
11
- #---------------------------------------------------------------------------
12
- #
13
-
14
- # (C)2006 Tony Arcieri, Martin Emde
15
- # Distributed under the Ruby license (http://www.ruby-lang.org/en/LICENSE.txt)
16
-
17
- # BufferedTokenizer takes a delimiter upon instantiation, or acts line-based
18
- # by default. It allows input to be spoon-fed from some outside source which
19
- # receives arbitrary length datagrams which may-or-may-not contain the token
20
- # by which entities are delimited.
21
- #
22
- # Commonly used to parse lines out of incoming data:
23
- #
24
- # module LineBufferedConnection
25
- # def receive_data(data)
26
- # (@buffer ||= BufferedTokenizer.new).extract(data).each do |line|
27
- # receive_line(line)
28
- # end
29
- # end
30
- # end
31
-
32
- module FileWatch; class BufferedTokenizer
33
- # New BufferedTokenizers will operate on lines delimited by "\n" by default
34
- # or allow you to specify any delimiter token you so choose, which will then
35
- # be used by String#split to tokenize the input data
36
- def initialize(delimiter = "\n", size_limit = nil)
37
- # Store the specified delimiter
38
- @delimiter = delimiter
39
-
40
- # Store the specified size limitation
41
- @size_limit = size_limit
42
-
43
- # The input buffer is stored as an array. This is by far the most efficient
44
- # approach given language constraints (in C a linked list would be a more
45
- # appropriate data structure). Segments of input data are stored in a list
46
- # which is only joined when a token is reached, substantially reducing the
47
- # number of objects required for the operation.
48
- @input = []
49
-
50
- # Size of the input buffer
51
- @input_size = 0
52
- end
53
-
54
- # Extract takes an arbitrary string of input data and returns an array of
55
- # tokenized entities, provided there were any available to extract. This
56
- # makes for easy processing of datagrams using a pattern like:
57
- #
58
- # tokenizer.extract(data).map { |entity| Decode(entity) }.each do ...
59
- def extract(data)
60
- # Extract token-delimited entities from the input string with the split command.
61
- # There's a bit of craftiness here with the -1 parameter. Normally split would
62
- # behave no differently regardless of if the token lies at the very end of the
63
- # input buffer or not (i.e. a literal edge case) Specifying -1 forces split to
64
- # return "" in this case, meaning that the last entry in the list represents a
65
- # new segment of data where the token has not been encountered
66
- entities = data.split @delimiter, -1
67
-
68
- # Check to see if the buffer has exceeded capacity, if we're imposing a limit
69
- if @size_limit
70
- raise 'input buffer full' if @input_size + entities.first.size > @size_limit
71
- @input_size += entities.first.size
72
- end
73
-
74
- # Move the first entry in the resulting array into the input buffer. It represents
75
- # the last segment of a token-delimited entity unless it's the only entry in the list.
76
- @input << entities.shift
77
-
78
- # If the resulting array from the split is empty, the token was not encountered
79
- # (not even at the end of the buffer). Since we've encountered no token-delimited
80
- # entities this go-around, return an empty array.
81
- return [] if entities.empty?
82
-
83
- # At this point, we've hit a token, or potentially multiple tokens. Now we can bring
84
- # together all the data we've buffered from earlier calls without hitting a token,
85
- # and add it to our list of discovered entities.
86
- entities.unshift @input.join
87
-
88
- =begin
89
- # Note added by FC, 10Jul07. This paragraph contains a regression. It breaks
90
- # empty tokens. Think of the empty line that delimits an HTTP header. It will have
91
- # two "\n" delimiters in a row, and this code mishandles the resulting empty token.
92
- # It someone figures out how to fix the problem, we can re-enable this code branch.
93
- # Multi-chara
94
- cter token support.
95
- # Split any tokens that were incomplete on the last iteration buf complete now.
96
- entities.map! do |e|
97
- e.split @delimiter, -1
98
- end
99
- # Flatten the resulting array. This has the side effect of removing the empty
100
- # entry at the end that was produced by passing -1 to split. Add it again if
101
- # necessary.
102
- if (entities[-1] == [])
103
- entities.flatten! << []
104
- else
105
- entities.flatten!
106
- end
107
- =end
108
-
109
- # Now that we've hit a token, joined the input buffer and added it to the entities
110
- # list, we can go ahead and clear the input buffer. All of the segments that were
111
- # stored before the join can now be garbage collected.
112
- @input.clear
113
-
114
- # The last entity in the list is not token delimited, however, thanks to the -1
115
- # passed to split. It represents the beginning of a new list of as-yet-untokenized
116
- # data, so we add it to the start of the list.
117
- @input << entities.pop
118
-
119
- # Set the new input buffer size, provided we're keeping track
120
- @input_size = @input.first.size if @size_limit
121
-
122
- # Now we're left with the list of extracted token-delimited entities we wanted
123
- # in the first place. Hooray!
124
- entities
125
- end
126
-
127
- # Flush the contents of the input buffer, i.e. return the input buffer even though
128
- # a token has not yet been encountered
129
- def flush
130
- buffer = @input.join
131
- @input.clear
132
- buffer
133
- end
134
-
135
- # Is the buffer empty?
136
- def empty?
137
- @input.empty?
138
- end
139
- end; end
@@ -1,70 +0,0 @@
1
- require "ffi"
2
-
3
- module Winhelper
4
- extend FFI::Library
5
-
6
- ffi_lib 'kernel32'
7
- ffi_convention :stdcall
8
- class FileTime < FFI::Struct
9
- layout :lowDateTime, :uint,
10
- :highDateTime, :uint
11
- end
12
-
13
- #http://msdn.microsoft.com/en-us/library/windows/desktop/aa363788(v=vs.85).aspx
14
- class FileInformation < FFI::Struct
15
- def initialize()
16
- createTime = FileTime.new
17
- lastAccessTime = FileTime.new
18
- lastWriteTime = FileTime.new
19
- end
20
-
21
- layout :fileAttributes, :uint, #DWORD dwFileAttributes;
22
- :createTime, FileTime, #FILETIME ftCreationTime;
23
- :lastAccessTime, FileTime, #FILETIME ftLastAccessTime;
24
- :lastWriteTime, FileTime, #FILETIME ftLastWriteTime;
25
- :volumeSerialNumber, :uint, #DWORD dwVolumeSerialNumber;
26
- :fileSizeHigh, :uint, #DWORD nFileSizeHigh;
27
- :fileSizeLow, :uint, #DWORD nFileSizeLow;
28
- :numberOfLinks, :uint, #DWORD nNumberOfLinks;
29
- :fileIndexHigh, :uint, #DWORD nFileIndexHigh;
30
- :fileIndexLow, :uint #DWORD nFileIndexLow;
31
- end
32
-
33
-
34
- #http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
35
- #HANDLE WINAPI CreateFile(_In_ LPCTSTR lpFileName,_In_ DWORD dwDesiredAccess,_In_ DWORD dwShareMode,
36
- # _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,_In_ DWORD dwCreationDisposition,
37
- # _In_ DWORD dwFlagsAndAttributes,_In_opt_ HANDLE hTemplateFile);
38
- attach_function :GetOpenFileHandle, :CreateFileA, [:pointer, :uint, :uint, :pointer, :uint, :uint, :pointer], :pointer
39
-
40
- #http://msdn.microsoft.com/en-us/library/windows/desktop/aa364952(v=vs.85).aspx
41
- #BOOL WINAPI GetFileInformationByHandle(_In_ HANDLE hFile,_Out_ LPBY_HANDLE_FILE_INFORMATION lpFileInformation);
42
- attach_function :GetFileInformationByHandle, [:pointer, :pointer], :int
43
-
44
- attach_function :CloseHandle, [:pointer], :int
45
-
46
-
47
- def self.GetWindowsUniqueFileIdentifier(path)
48
- handle = GetOpenFileHandle(path, 0, 7, nil, 3, 128, nil)
49
- fileInfo = Winhelper::FileInformation.new
50
- success = GetFileInformationByHandle(handle, fileInfo)
51
- CloseHandle(handle)
52
- if success == 1
53
- #args = [
54
- # fileInfo[:fileAttributes], fileInfo[:volumeSerialNumber], fileInfo[:fileSizeHigh], fileInfo[:fileSizeLow],
55
- # fileInfo[:numberOfLinks], fileInfo[:fileIndexHigh], fileInfo[:fileIndexLow]
56
- # ]
57
- #p "Information: %u %u %u %u %u %u %u " % args
58
- #this is only guaranteed on NTFS, for ReFS on windows 2012, GetFileInformationByHandleEx should be used with FILE_ID_INFO, which returns a 128 bit identifier
59
- return "#{fileInfo[:volumeSerialNumber]}-#{fileInfo[:fileIndexLow]}-#{fileInfo[:fileIndexHigh]}"
60
- else
61
- #p "cannot retrieve file information, returning path"
62
- return path;
63
- end
64
- end
65
- end
66
-
67
- #fileId = Winhelper.GetWindowsUniqueFileIdentifier('C:\inetpub\logs\LogFiles\W3SVC1\u_ex1fdsadfsadfasdf30612.log')
68
- #p "FileId: " + fileId
69
- #p "outside function, sleeping"
70
- #sleep(10)