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.
- checksums.yaml +7 -0
- data/lib/filewatch/tail.rb +43 -20
- data/lib/filewatch/watch.rb +19 -1
- data/lib/filewatch/winhelper.rb +70 -0
- metadata +16 -18
checksums.yaml
ADDED
@@ -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
|
data/lib/filewatch/tail.rb
CHANGED
@@ -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
|
-
@
|
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
|
-
|
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(
|
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
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
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
|
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
|
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(
|
213
|
-
rescue
|
214
|
-
@logger.
|
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
|
data/lib/filewatch/watch.rb
CHANGED
@@ -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
|
-
|
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
|
-
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:
|
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
|
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
|
-
|
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:
|
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:
|
70
|
-
MA==
|
71
|
-
none: false
|
69
|
+
version: '0'
|
72
70
|
requirements: []
|
73
|
-
rubyforge_project:
|
74
|
-
rubygems_version:
|
75
|
-
signing_key:
|
76
|
-
specification_version:
|
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: []
|