filewatch 0.5.1 → 0.6.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: afac9c2d3c0a37891437ba7bb6a0f4bb8a4b68b0
4
+ data.tar.gz: d86fab5ae9f22ee5ba4c9552dec1feb8ea13b325
5
+ SHA512:
6
+ metadata.gz: 772e3c37641040f481778777e31bb19cf7a420fd04c27129a27363c5b32c97bce86077dc628a2e25f861432630d83275d36c106009b68c24cd8e3c6304e454bc
7
+ data.tar.gz: 4bddb7bcdf81c9dbfe015ee53bb387b0ba15625f0a2870fbf91bb0ee08cd9904e92c10cf620785daec7f008d464f59b99f335fd2db56f2ba6254a2e438330df1
@@ -1,6 +1,13 @@
1
1
  require "filewatch/buftok"
2
2
  require "filewatch/watch"
3
+ if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
4
+ require "filewatch/winhelper"
5
+ end
3
6
  require "logger"
7
+ require "rbconfig"
8
+
9
+ include Java if defined? JRUBY_VERSION
10
+ require "JRubyFileExtension.jar" if defined? JRUBY_VERSION
4
11
 
5
12
  module FileWatch
6
13
  class Tail
@@ -14,6 +21,8 @@ module FileWatch
14
21
 
15
22
  public
16
23
  def initialize(opts={})
24
+ @iswindows = ((RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/) != nil)
25
+
17
26
  if opts[:logger]
18
27
  @logger = opts[:logger]
19
28
  else
@@ -97,7 +106,11 @@ module FileWatch
97
106
  def _open_file(path, event)
98
107
  @logger.debug("_open_file: #{path}: opening")
99
108
  begin
100
- @files[path] = File.open(path)
109
+ if @iswindows && defined? JRUBY_VERSION
110
+ @files[path] = Java::RubyFileExt::getRubyFile(path)
111
+ else
112
+ @files[path] = File.open(path)
113
+ end
101
114
  rescue
102
115
  # don't emit this message too often. if a file that we can't
103
116
  # read is changing a lot, we'll try to open it more often,
@@ -114,7 +127,14 @@ module FileWatch
114
127
  end
115
128
 
116
129
  stat = File::Stat.new(path)
117
- inode = [stat.ino, stat.dev_major, stat.dev_minor]
130
+
131
+ if @iswindows
132
+ fileId = Winhelper.GetWindowsUniqueFileIdentifier(path)
133
+ inode = [fileId, stat.dev_major, stat.dev_minor]
134
+ else
135
+ inode = [stat.ino.to_s, stat.dev_major, stat.dev_minor]
136
+ end
137
+
118
138
  @statcache[path] = inode
119
139
 
120
140
  if @sincedb.member?(inode)
@@ -153,32 +173,28 @@ module FileWatch
153
173
  changed = false
154
174
  loop do
155
175
  begin
156
- data = @files[path].sysread(16394)
176
+ data = @files[path].sysread(32768)
157
177
  changed = true
158
178
  @buffers[path].extract(data).each do |line|
159
179
  yield(path, line)
160
180
  end
161
181
 
162
182
  @sincedb[@statcache[path]] = @files[path].pos
163
- write_sincedb_if_necessary
164
183
  rescue Errno::EWOULDBLOCK, Errno::EINTR, EOFError
165
184
  break
166
185
  end
167
186
  end
168
187
 
169
- write_sincedb_if_necessary
170
- end # def _read_file
171
-
172
- private
173
- def write_sincedb_if_necessary
174
- now = Time.now.to_i
175
- delta = now - @sincedb_last_write
176
- if delta >= @opts[:sincedb_write_interval]
177
- @logger.debug("writing sincedb (delta since last write = #{delta})")
178
- _sincedb_write
179
- @sincedb_last_write = now
188
+ if changed
189
+ now = Time.now.to_i
190
+ delta = now - @sincedb_last_write
191
+ if delta >= @opts[:sincedb_write_interval]
192
+ @logger.debug("writing sincedb (delta since last write = #{delta})")
193
+ _sincedb_write
194
+ @sincedb_last_write = now
195
+ end
180
196
  end
181
- end # def write_sincedb_if_necessary
197
+ end # def _read_file
182
198
 
183
199
  public
184
200
  def sincedb_write(reason=nil)
@@ -199,7 +215,7 @@ module FileWatch
199
215
  @logger.debug("_sincedb_open: reading from #{path}")
200
216
  db.each do |line|
201
217
  ino, dev_major, dev_minor, pos = line.split(" ", 4)
202
- inode = [ino.to_i, dev_major.to_i, dev_minor.to_i]
218
+ inode = [ino, dev_major.to_i, dev_minor.to_i]
203
219
  @logger.debug("_sincedb_open: setting #{inode.inspect} to #{pos.to_i}")
204
220
  @sincedb[inode] = pos.to_i
205
221
  end
@@ -208,10 +224,11 @@ module FileWatch
208
224
  private
209
225
  def _sincedb_write
210
226
  path = @opts[:sincedb_path]
227
+ tmp = "#{path}.new"
211
228
  begin
212
- db = File.open(path, "w")
213
- rescue
214
- @logger.debug("_sincedb_write: #{path}: #{$!}")
229
+ db = File.open(tmp, "w")
230
+ rescue => e
231
+ @logger.warn("_sincedb_write failed: #{tmp}: #{e}")
215
232
  return
216
233
  end
217
234
 
@@ -219,6 +236,12 @@ module FileWatch
219
236
  db.puts([inode, pos].flatten.join(" "))
220
237
  end
221
238
  db.close
239
+
240
+ begin
241
+ File.rename(tmp, path)
242
+ rescue => e
243
+ @logger.warn("_sincedb_write rename/sync failed: #{tmp} -> #{path}: #{e}")
244
+ end
222
245
  end # def _sincedb_write
223
246
 
224
247
  public
@@ -1,4 +1,7 @@
1
1
  require "logger"
2
+ if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
3
+ require "filewatch/winhelper"
4
+ end
2
5
 
3
6
  module FileWatch
4
7
  class Watch
@@ -6,6 +9,7 @@ module FileWatch
6
9
 
7
10
  public
8
11
  def initialize(opts={})
12
+ @iswindows = ((RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/) != nil)
9
13
  if opts[:logger]
10
14
  @logger = opts[:logger]
11
15
  else
@@ -68,7 +72,13 @@ module FileWatch
68
72
  next
69
73
  end
70
74
 
71
- inode = [stat.ino, stat.dev_major, stat.dev_minor]
75
+ if @iswindows
76
+ fileId = Winhelper.GetWindowsUniqueFileIdentifier(path)
77
+ inode = [fileId, stat.dev_major, stat.dev_minor]
78
+ else
79
+ inode = [stat.ino.to_s, stat.dev_major, stat.dev_minor]
80
+ end
81
+
72
82
  if inode != @files[path][:inode]
73
83
  @logger.debug("#{path}: old inode was #{@files[path][:inode].inspect}, new is #{inode.inspect}")
74
84
  yield(:delete, path)
@@ -142,6 +152,14 @@ module FileWatch
142
152
  :inode => [stat.ino, stat.dev_major, stat.dev_minor],
143
153
  :create_sent => false,
144
154
  }
155
+
156
+ if @iswindows
157
+ fileId = Winhelper.GetWindowsUniqueFileIdentifier(path)
158
+ @files[file][:inode] = [fileId, stat.dev_major, stat.dev_minor]
159
+ else
160
+ @files[file][:inode] = [stat.ino.to_s, stat.dev_major, stat.dev_minor]
161
+ end
162
+
145
163
  if initial
146
164
  @files[file][:initial] = true
147
165
  end
@@ -0,0 +1,70 @@
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)
metadata CHANGED
@@ -1,18 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: filewatch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
5
- prerelease:
4
+ version: 0.6.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Jordan Sissel
9
8
  - Pete Fritchman
10
- autorequire:
9
+ autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2013-01-26 00:00:00.000000000 Z
12
+ date: 2015-01-13 00:00:00.000000000 Z
14
13
  dependencies: []
15
- description: Watch files and directories in ruby. Also supports tailing and glob file patterns.
14
+ description: Watch files and directories in ruby. Also supports tailing and glob file
15
+ patterns.
16
16
  email:
17
17
  - jls@semicomplete.com
18
18
  - petef@databits.net
@@ -21,9 +21,11 @@ executables:
21
21
  extensions: []
22
22
  extra_rdoc_files: []
23
23
  files:
24
+ - bin/globtail
24
25
  - lib/filewatch/buftok.rb
25
- - lib/filewatch/watch.rb
26
26
  - lib/filewatch/tail.rb
27
+ - lib/filewatch/watch.rb
28
+ - lib/filewatch/winhelper.rb
27
29
  - test/filewatch/tail.rb
28
30
  - test/globtail/Makefile
29
31
  - test/globtail/framework.sh
@@ -47,10 +49,10 @@ files:
47
49
  - test/globtail/test8.sh
48
50
  - test/globtail/test9.data
49
51
  - test/globtail/test9.sh
50
- - bin/globtail
51
52
  homepage: https://github.com/jordansissel/ruby-filewatch
52
53
  licenses: []
53
- post_install_message:
54
+ metadata: {}
55
+ post_install_message:
54
56
  rdoc_options: []
55
57
  require_paths:
56
58
  - lib
@@ -59,20 +61,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
59
61
  requirements:
60
62
  - - ">="
61
63
  - !ruby/object:Gem::Version
62
- version: !binary |-
63
- MA==
64
- none: false
64
+ version: '0'
65
65
  required_rubygems_version: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: !binary |-
70
- MA==
71
- none: false
69
+ version: '0'
72
70
  requirements: []
73
- rubyforge_project:
74
- rubygems_version: 1.8.24
75
- signing_key:
76
- specification_version: 3
71
+ rubyforge_project:
72
+ rubygems_version: 2.4.3
73
+ signing_key:
74
+ specification_version: 4
77
75
  summary: filewatch - file watching for ruby
78
76
  test_files: []