filewatch 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []